]> git.defcon.no Git - rctxduino/blobdiff - source/RCTXDuino/RCTXDuino.pde
Cleaned up indentation and coding style ...
[rctxduino] / source / RCTXDuino / RCTXDuino.pde
index 0bc85626db0fc0992c86333e0fbb1029ae1a0151..d7144e7a6c70027fc86984605926ecbe0a64aa11 100644 (file)
@@ -1,7 +1,16 @@
-#include <LiquidCrystal.h>
+// No longer using HD44780-comaptible display,
+// Moving to a brand new world of dot-matrix display tech!
+// Using LCD library from http://code.google.com/p/pcd8544/
+#include <PCD8544.h>
+
 #include <TimerOne.h>
 #include <EEPROM.h>
 
+// Undefine this whenever a "release" or "flight-test" build is made.
+// Defining DEBUG sets some crazy values for things like battery warning,
+// and includes a whole bunch of debugging-related code ...
+#define DEBUG 1
+
 #define MAX_INPUTS 8
 
 // Update this _every_ time a change in datastructures that
@@ -66,8 +75,8 @@ volatile model_t model;
 unsigned char current_model; // Using uchar to spend a single byte of mem..
 
 // ----------------- Display related stuffs --------------------
-LiquidCrystal lcd( 12, 11, 10,     6,  7,  8,  9);
-// Parameters are: rs, rw, enable, d4, d5, d6, d7 pin numbers.
+PCD8544 lcd( 8,  9,   10, 11,    12);
+// Param:   sclk, sdin, dc, reset, sce
 
 // ----------------- PPM related stuffs ------------------------
 // The PPM generation is handled by Timer0 interrupts, and needs
@@ -83,10 +92,10 @@ volatile bool do_channel = true;        // Is next operation a channel or a sepa
 // The timing here (and/or in the ISR) needs to be tweaked to provide valid
 // RC PPM signals accepted by standard RC RX'es and the Microcopter...
 
-#define framelength  21500             // Max length of frame
-#define seplength      250             // Lenght of a channel separator
+#define framelength  21000             // Max length of frame
+#define seplength      300             // Lenght of a channel separator
 #define chmax         1600             // Max lenght of channel pulse
-#define chmin          480             // Min length of channel
+#define chmin          495             // Min length of channel
 #define chwidht  (chmax - chmin)// Useable time of channel pulse
 
 // ----------------- Menu/IU related stuffs --------------------
@@ -105,24 +114,32 @@ volatile bool do_channel = true;        // Is next operation a channel or a sepa
 
 // Voltage sense pin is connected to a 1/3'd voltage divider.
 #define BATTERY_CONV (10 * 3 * (5.0f/1024.0f))
+
+#ifdef DEBUG
+// The following values are for DEBUGGING ONLY!!
 #define BATTERY_LOW 92
+#define BATTERY_CRITICAL 0
+#else
+#define BATTERY_LOW 92
+#define BATTERY_CRITICAL 92
+#endif
 
 enum {
-  VALUES,
-  BATTERY,
-  TIMER,
-  CURMODEL,
-  MENU
+       VALUES,
+       BATTERY,
+       TIMER,
+       CURMODEL,
+       MENU
 } 
 displaystate;
 
 enum {
-  TOP,
-  INVERTS,
-  DUALRATES,
-  EXPOS, // Some radios have "drawn curves", i.e. loopup tables stored in external EEPROM ...
-  DEBUG,
-  SAVE
+       TOP,
+       INVERTS,
+       DUALRATES,
+       EXPOS, // Some radios have "drawn curves", i.e. loopup tables stored in external EEPROM ...
+       DEBUG_DUMP,
+       SAVE
 } 
 menu_mainstate;
 int menu_substate;
@@ -145,152 +162,154 @@ struct clock_timer_t
        boolean running;
 } clock_timer;
 
+#ifdef DEBUG
 // -----------------  DEBUG-STUFF --------------------
 unsigned long prev_loop_time;
 unsigned long avg_loop_time;
 unsigned long t;
-
+#endif
 
 // ---------- CODE! -----------------------------------
 
 // ---------- Arduino SETUP code ----------------------
 void setup(){
-  pinMode(13, OUTPUT);   // led
+       pinMode(13, OUTPUT);   // led
 
-  pinMode(2, OUTPUT);    // s0
-  pinMode(3, OUTPUT);    // s1
-  pinMode(4, OUTPUT);    // s2
-  pinMode(5, OUTPUT);    // e
+       pinMode(2, OUTPUT);    // s0
+       pinMode(3, OUTPUT);    // s1
+       pinMode(4, OUTPUT);    // s2
+       pinMode(5, OUTPUT);    // e
 
-  lcd.begin(16,2);
-  lcd.print("Starting....");
+       lcd.begin(84, 48);
+       lcd.print("Starting....");
 
-  Serial.begin(9600);
-  Serial.println("Starting....");
-  delay(500);
+#ifdef DEBUG  
+       Serial.begin(9600);
+       Serial.println("Starting....");
+#endif
   
-  model_defaults();
-  read_settings();
+       delay(500);
 
-  displaystate = VALUES;
-  
-  // Arduino believes all pins on Port C are Analog.
-  // In reality they are tri-purpose; ADC, Digital, Digital Interrupts
-  // Unfortunately the interrupt mode is unusable in this scenario, but digital I/O works :P
-  pinMode(A2, INPUT); 
-  digitalWrite(A2, HIGH);
-  scan_keys();
-  if ( !keys[KEY_UP])
-    calibrate();
-  
-  // Debugging: how long does the main loop take on avg...  
-  t = micros();
-  avg_loop_time = t;
-  prev_loop_time = t;    
+       model_defaults();
+       read_settings();
 
+       displaystate = VALUES;
   
-  // Initializing the stopwatch timer/clock values...
-  clock_timer = (clock_timer_t){0, 0, 0, false};
-
-  pinMode(A5, OUTPUT);  // PPM output pin  
-  do_channel = false;
-  set_timer( seplength );
-  Timer1.initialize(framelength);
-  Timer1.attachInterrupt(ISR_timer);  
+       // Arduino believes all pins on Port C are Analog.
+       // In reality they are tri-purpose; ADC, Digital, Digital Interrupts
+       // Unfortunately the interrupt mode is unusable in this scenario, but digital I/O works :P
+       pinMode(A2, INPUT); 
+       digitalWrite(A2, HIGH);
+       scan_keys();
+       if ( !keys[KEY_UP])
+               calibrate();
   
+#ifdef DEBUG
+       // Debugging: how long does the main loop take on avg...  
+       t = micros();
+       avg_loop_time = t;
+       prev_loop_time = t;    
+#endif
+
+       // Initializing the stopwatch timer/clock values...
+       clock_timer = (clock_timer_t){0, 0, 0, false};
+
+       pinMode(A5, OUTPUT);  // PPM output pin  
+       do_channel = false;
+       set_timer( seplength );
+       Timer1.initialize(framelength);
+       Timer1.attachInterrupt(ISR_timer);  
+
+       lcd.clear();
 }
 
 void model_defaults( void )
 {
-  // This function provides default values for model data
-  // that is not a result of stick input, or in other words:
-  // provides defautls for all user-configurable model options.
-  
-  // Remember to update this when a new option/element is added
-  // to the model_t struct (preferably before implementing the
-  // menu code that sets those options ...)
-
-  // This is used when a user wants a new, blank model, a reset
-  // of a configured model, and (most important) when EEPROM
-  // data format changes.
-  // NOTE: This means that stored model conficuration is reset
-  // to defaults when the EEPROM version/format changes.
-  model.channels = 8;
-  model.rev[0] = model.rev[1] = model.rev[2] = model.rev[3] = 
-  model.rev[4] = model.rev[5] = model.rev[6] = model.rev[7] = false;
-  model.dr[0] = model.dr[1] = model.dr[2] = model.dr[3] = 0;
-  model.dr[4] = model.dr[5] = model.dr[6] = model.dr[7] = 100;
-
+       // This function provides default values for model data
+       // that is not a result of stick input, or in other words:
+       // provides defautls for all user-configurable model options.
+
+       // Remember to update this when a new option/element is added
+       // to the model_t struct (preferably before implementing the
+       // menu code that sets those options ...)
+
+       // This is used when a user wants a new, blank model, a reset
+       // of a configured model, and (most important) when EEPROM
+       // data format changes.
+       // NOTE: This means that stored model conficuration is reset
+       // to defaults when the EEPROM version/format changes.
+       model.channels = 8;
+       model.rev[0] = model.rev[1] = model.rev[2] = model.rev[3] = 
+       model.rev[4] = model.rev[5] = model.rev[6] = model.rev[7] = false;
+       model.dr[0] = model.dr[1] = model.dr[2] = model.dr[3] = 0;
+       model.dr[4] = model.dr[5] = model.dr[6] = model.dr[7] = 100;
 }
 
 // ---------- Arduino main loop -----------------------
-void loop () {
+void loop ()
+{  
+       process_inputs();
+
+       // Wasting a full I/O pin on battery status monitoring!
+       battery_val = analogRead(1) * BATTERY_CONV;
+       if ( battery_val < BATTERY_LOW ) 
+               digitalWrite(13, 1); // Simulate alarm :P
+
+       if ( battery_val < BATTERY_CRITICAL )
+               displaystate = BATTERY;
+
+       if ( millis() - last > UI_INTERVAL ) 
+       { 
+               last = millis(); 
+               ui_handler(); 
+       }
   
-  // Determine if the UI needs to run...
-  boolean disp;
-  if ( millis() - last > UI_INTERVAL ) { 
-    last = millis(); 
-    disp = true; 
-  }
-  else disp = false;
-
-  process_inputs();
-
-  // Wasting a full I/O pin on battery status monitoring!
-  battery_val = analogRead(1) * BATTERY_CONV;
-  if ( battery_val < BATTERY_LOW ) {
-    digitalWrite(13, 1); // Simulate alarm :P
-    displaystate = BATTERY;
-  }
-
-  if ( disp )
-  {
-    ui_handler(); 
-  }
-  if ( displaystate != MENU )
-  {
-    // Debugging: how long does the main loop take on avg,
-    // when not handling the UI...
-    t = micros();
-    avg_loop_time = ( t - prev_loop_time + avg_loop_time ) / 2;
-    prev_loop_time = t;    
-  }
-
-  // Whoa! Slow down partner! Let everything settle down before proceeding.
-  delay(5);
+#ifdef DEBUG
+       if ( displaystate != MENU )
+       {
+               // Debugging: how long does the main loop take on avg,
+               // when not handling the UI...
+               t = micros();
+               avg_loop_time = ( t - prev_loop_time + avg_loop_time ) / 2;
+               prev_loop_time = t;    
+       }
+#endif
+
+       // Whoa! Slow down partner! Let everything settle down before proceeding.
+       delay(5);
 }
 
 // ----- Simple support functions used by more complex functions ----
 
 void set_ppm_output( bool state )
 {
-  digitalWrite(A5, state); // Hard coded PPM output
+       digitalWrite(A5, state); // Hard coded PPM output
 }
 
 void set_timer(long time)
 {
-  Timer1.detachInterrupt();
-  Timer1.attachInterrupt(ISR_timer, time);  
+       Timer1.detachInterrupt();
+       Timer1.attachInterrupt(ISR_timer, time);  
 }
 
 boolean check_key( int key)
 {
-  return ( !keys[key] && prev_keys[key] );
+       return ( !keys[key] && prev_keys[key] );
 }
 
 void mplx_select(int pin)
 {
-  digitalWrite(5, 1);
-  delayMicroseconds(24);
+       digitalWrite(5, 1);
+       delayMicroseconds(24);
 
-  digitalWrite(2, bitRead(pin,0));  // Arduino alias for non-modifying bitshift operation
-  digitalWrite(3, bitRead(pin,1));  // us used to extract individual bits from the int (0..7)
-  digitalWrite(4, bitRead(pin,2));  // Select the appropriate input by setting s1,s2,s3 and e
-  digitalWrite(5, 0);               // on the 4051 multiplexer.
+       digitalWrite(2, bitRead(pin,0));  // Arduino alias for non-modifying bitshift operation
+       digitalWrite(3, bitRead(pin,1));  // us used to extract individual bits from the int (0..7)
+       digitalWrite(4, bitRead(pin,2));  // Select the appropriate input by setting s1,s2,s3 and e
+       digitalWrite(5, 0);               // on the 4051 multiplexer.
 
-  // May need to slow the following read down to be able to
-  // get fully reliable values from the 4051 multiplex.
-  delayMicroseconds(24);
+       // May need to slow the following read down to be able to
+       // get fully reliable values from the 4051 multiplex.
+       delayMicroseconds(24);
 
 }
 
@@ -298,411 +317,426 @@ void mplx_select(int pin)
 
 void calibrate()
 {
-  int i, adc_in;
-  int num_calibrations = 200;
-
-  lcd.clear();
-  lcd.print("Move controls to");
-  lcd.setCursor(0,1);
-  lcd.print("their extremes..");
-  Serial.print("Calibration. Move all controls to their extremes.");
-
-  for (i=0; i<MAX_INPUTS; i++) {
-    input_cal.min[i] = 1024;
-       input_cal.center[i] = 512;
-    input_cal.max[i] = 0;
-  }
-
-  while ( num_calibrations-- )
-  {
-    for (i=0; i<MAX_INPUTS; i++) {
-      mplx_select(i);
-      adc_in = analogRead(0);
-
-      // Naive min/max calibration
-      if ( adc_in < input_cal.min[i] ) {
-        input_cal.min[i] = adc_in;
-      }
-      if ( adc_in > input_cal.max[i] ) {
-        input_cal.max[i] = adc_in;
-      }
-      delay(10);
-    }
-  }
-
-  // TODO: WILL need to do center-point calibration after min-max...
-
-  lcd.clear();
-  lcd.print("Saving to EEPROM");
-  write_calibration();
-  lcd.setCursor(0 , 1);
-  lcd.print("Done calibrating");
-  
-  Serial.print("Done calibrating");
-  delay(2000);  
+       int i, adc_in;
+       int num_calibrations = 200;
+
+       lcd.clear();
+       lcd.print("Move controls to");
+       lcd.setCursor(0,1);
+       lcd.print("their extremes..");
+       Serial.print("Calibration. Move all controls to their extremes.");
+
+       for (i=0; i<MAX_INPUTS; i++)
+       {
+               input_cal.min[i] = 1024;
+               input_cal.center[i] = 512;
+               input_cal.max[i] = 0;
+       }
+
+       while ( num_calibrations-- )
+       {
+               for (i=0; i<MAX_INPUTS; i++) 
+               {
+                       mplx_select(i);
+                       adc_in = analogRead(0);
+
+                       // Naive min/max calibration
+                       if ( adc_in < input_cal.min[i] )
+                               input_cal.min[i] = adc_in;
+
+                       if ( adc_in > input_cal.max[i] )
+                               input_cal.max[i] = adc_in;
+
+                       delay(10);
+               }
+       }
+
+       // TODO: WILL need to do center-point calibration after min-max...
+
+       lcd.clear();
+       lcd.print("Saving to EEPROM");
+       write_calibration();
+       lcd.setCursor(0 , 1);
+       lcd.print("Done calibrating");
+
+       Serial.print("Done calibrating");
+       delay(2000);  
 }
 
 void write_calibration(void)
 {
-  int i;
-  unsigned char v;
-  const byte *p;
-  
-  // Set p to be a pointer to the start of the input calibration struct.
-  p = (const byte*)(const void*)&input_cal;
-  
-  // Iterate through the bytes of the struct...
-  for (i = 0; i < sizeof(input_cal_t); i++)
-  {
-    // Get a byte of data from the struct...
-       v = (unsigned char) *p;
-       // write it to EEPROM
-       EEPROM.write( EE_BASE_ADDR + i, v);
-       // and move the pointer to the next byte in the struct.
-       *p++;
-  }
+       int i;
+       unsigned char v;
+       const byte *p;
+
+       // Set p to be a pointer to the start of the input calibration struct.
+       p = (const byte*)(const void*)&input_cal;
+
+       // Iterate through the bytes of the struct...
+       for (i = 0; i < sizeof(input_cal_t); i++)
+       {
+               // Get a byte of data from the struct...
+               v = (unsigned char) *p;
+               // write it to EEPROM
+               EEPROM.write( EE_BASE_ADDR + i, v);
+               // and move the pointer to the next byte in the struct.
+               *p++;
+       }
 }
 
 void read_settings(void)
 {
-  int i;
-  unsigned char v;
-  byte *p;
-
-  v = EEPROM.read(0);
-  if ( v != EEPROM_VERSION )
-  {
-       // All models have been reset. Set the current model to 0
-       current_model = 0;
-       EEPROM.write(1, current_model);
-
-       calibrate();
-       model_defaults();
-       // The following does not yet work...
-       for ( i = 0; i < MAX_MODELS; i++)
-               write_model_settings(i);
+       int i;
+       unsigned char v;
+       byte *p;
+
+       v = EEPROM.read(0);
+       if ( v != EEPROM_VERSION )
+       {
+               // All models have been reset. Set the current model to 0
+               current_model = 0;
+               EEPROM.write(1, current_model);
+
+               calibrate();
+               model_defaults();
+               // The following does not yet work...
+               for ( i = 0; i < MAX_MODELS; i++)
+                       write_model_settings(i);
+
+
+               // After saving calibration data and model defaults,
+               // update the saved version-identifier to the current ver.
+               EEPROM.write(0, EEPROM_VERSION);
+       }
 
-       
-       // After saving calibration data and model defaults,
-       // update the saved version-identifier to the current ver.
-       EEPROM.write(0, EEPROM_VERSION);
-  }
-
-  // Read calibration values from EEPROM.
-  // This uses simple pointer-arithmetic and byte-by-byte
-  // to put bytes read from EEPROM to the data-struct.
-  p = (byte*)(void*)&input_cal;
-  for (i = 0; i < sizeof(input_cal_t); i++)
+       // Read calibration values from EEPROM.
+       // This uses simple pointer-arithmetic and byte-by-byte
+       // to put bytes read from EEPROM to the data-struct.
+       p = (byte*)(void*)&input_cal;
+       for (i = 0; i < sizeof(input_cal_t); i++)
                *p++ = EEPROM.read( EE_BASE_ADDR + i);
 
-  // Get the previously selected model from EEPROM.
-  current_model = EEPROM.read(1);
-  read_model_settings( current_model );
+       // Get the previously selected model from EEPROM.
+       current_model = EEPROM.read(1);
+       read_model_settings( current_model );
 }
 
 void read_model_settings(unsigned char mod_no)
 {
-  int model_address;
-  int i;
-  unsigned char v;
-  byte *p;
+       int model_address;
+       int i;
+       unsigned char v;
+       byte *p;
 
-  // Calculate the EEPROM start adress for the given model (mod_no)
-  model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
+       // Calculate the EEPROM start adress for the given model (mod_no)
+       model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
 
-  // Do not try to write the model to EEPROM if it won't fit.
-  if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
-  {
-       lcd.clear();
-       lcd.print("Aborting READ");
-    lcd.setCursor(0 , 1);
-    lcd.print("Invalid location");
-    delay(2000);  
-       return;
-  }
-  
-  lcd.clear();
-  lcd.print("Reading model ");
-  lcd.print( (int)mod_no );
+       // Do not try to write the model to EEPROM if it won't fit.
+       if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
+       {
+               lcd.clear();
+               lcd.print("Aborting READ");
+               lcd.setCursor(0 , 1);
+               lcd.print("Invalid location");
+               delay(2000);  
+               return;
+       }
   
-  // Pointer to the start of the model_t data struct,
-  // used for byte-by-byte reading of data...
-  p = (byte*)(void*)&model;
-  for (i = 0; i < sizeof(model_t); i++)
+       lcd.clear();
+       lcd.print("Reading model ");
+       lcd.print( (int)mod_no );
+
+       // Pointer to the start of the model_t data struct,
+       // used for byte-by-byte reading of data...
+       p = (byte*)(void*)&model;
+       for (i = 0; i < sizeof(model_t); i++)
                *p++ = EEPROM.read( model_address++ );
 
-  serial_dump_model();
+#ifdef DEBUG
+       serial_dump_model();
+#endif
 
-  lcd.setCursor(0 , 1);
-  lcd.print("... Loaded.");
-  delay(1000);    
+       lcd.setCursor(0 , 1);
+       lcd.print("... Loaded.");
+       delay(1000);    
 }
 
 void write_model_settings(unsigned char mod_no)
 {
-  int model_address;
-  int i;
-  unsigned char v;
-  byte *p;
+       int model_address;
+       int i;
+       unsigned char v;
+       byte *p;
 
-  // Calculate the EEPROM start adress for the given model (mod_no)
-  model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
+       // Calculate the EEPROM start adress for the given model (mod_no)
+       model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
+
+       // Do not try to write the model to EEPROM if it won't fit.
+       if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
+       {
+               lcd.clear();
+               lcd.print("Aborting SAVE");
+               lcd.setCursor(0 , 1);
+               lcd.print("No room for data");
+               delay(2000);  
+               return;
+       }
   
-  // Do not try to write the model to EEPROM if it won't fit.
-  if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
-  {
        lcd.clear();
-       lcd.print("Aborting SAVE");
-    lcd.setCursor(0 , 1);
-    lcd.print("No room for data");
-    delay(2000);  
-       return;
-  }
-  
-  lcd.clear();
-  lcd.print("Saving model ");
-  lcd.print( (int)mod_no);
+       lcd.print("Saving model ");
+       lcd.print( (int)mod_no);
   
-  // Pointer to the start of the model_t data struct,
-  // used for byte-by-byte reading of data...
-  p = (byte*)(void*)&model;
-  
-  // Write/serialize the model data struct to EEPROM...
-  for (i = 0; i < sizeof(model_t); i++)
+       // Pointer to the start of the model_t data struct,
+       // used for byte-by-byte reading of data...
+       p = (byte*)(void*)&model;
+
+       // Write/serialize the model data struct to EEPROM...
+       for (i = 0; i < sizeof(model_t); i++)
                EEPROM.write( model_address++, *p++);
                
-  lcd.setCursor(0 , 1);
-  lcd.print(".. done saving.");
-  delay(200);    
+       lcd.setCursor(0 , 1);
+       lcd.print(".. done saving.");
+       delay(200);    
 }
 
+#ifdef DEBUG
 void serial_dump_model ( void )
 {
-  int i;
-  int model_address;
-  // Calculate the EEPROM start adress for the given model (mod_no)
-  model_address = EE_MDL_BASE_ADDR + (current_model * sizeof(model_t));
-  Serial.print("Current model:    ");
-  Serial.println( (int)current_model );
-  Serial.print("Models base addr: ");
-  Serial.println( EE_MDL_BASE_ADDR );
-  Serial.print("Model no:         ");
-  Serial.println( current_model, 10 );
-  Serial.print("Size of struct:   ");
-  Serial.println( sizeof( model_t) );
-  Serial.print("Model address:    ");
-  Serial.println( model_address );
-  Serial.print("End of model:     ");
-  Serial.println( model_address + sizeof(model_t) );
-
-  Serial.println();
-  
-  Serial.print("Channel reversions: ");
-  for ( i = 0; i<8; i++)
-  {
-       Serial.print(i);
-       Serial.print("=");
-       Serial.print(model.rev[i], 10);
-       Serial.print(" ");
-  }
-  Serial.println();
-  
-  Serial.print("DR1 inp 0: ");
-  Serial.println(model.dr[0]);
-  Serial.print("DR1 inp 1: ");
-  Serial.println(model.dr[1]);
-  Serial.print("DR1 LO val: ");
-  Serial.println(model.dr[4]);
-  Serial.print("DR1 HI val: ");
-  Serial.println(model.dr[5]);
-  Serial.print("DR2 inp 0: ");
-  Serial.println(model.dr[2]);
-  Serial.print("DR2 inp 1: ");
-  Serial.println(model.dr[3]);
-  Serial.print("DR2 LO val: ");
-  Serial.println(model.dr[6]);
-  Serial.print("DR2 HI val: ");
-  Serial.println(model.dr[7]);
+       int i;
+       int model_address;
+       // Calculate the EEPROM start adress for the given model (mod_no)
+       model_address = EE_MDL_BASE_ADDR + (current_model * sizeof(model_t));
+       Serial.print("Current model:    ");
+       Serial.println( (int)current_model );
+       Serial.print("Models base addr: ");
+       Serial.println( EE_MDL_BASE_ADDR );
+       Serial.print("Model no:         ");
+       Serial.println( current_model, 10 );
+       Serial.print("Size of struct:   ");
+       Serial.println( sizeof( model_t) );
+       Serial.print("Model address:    ");
+       Serial.println( model_address );
+       Serial.print("End of model:     ");
+       Serial.println( model_address + sizeof(model_t) );
+
+       Serial.println();
+
+       Serial.print("Channel reversions: ");
+       for ( i = 0; i<8; i++)
+       {
+               Serial.print(i);
+               Serial.print("=");
+               Serial.print(model.rev[i], 10);
+               Serial.print(" ");
+       }
+       Serial.println();
+
+       Serial.print("DR1 inp 0: ");
+       Serial.println(model.dr[0]);
+       Serial.print("DR1 inp 1: ");
+       Serial.println(model.dr[1]);
+       Serial.print("DR1 LO val: ");
+       Serial.println(model.dr[4]);
+       Serial.print("DR1 HI val: ");
+       Serial.println(model.dr[5]);
+       Serial.print("DR2 inp 0: ");
+       Serial.println(model.dr[2]);
+       Serial.print("DR2 inp 1: ");
+       Serial.println(model.dr[3]);
+       Serial.print("DR2 LO val: ");
+       Serial.println(model.dr[6]);
+       Serial.print("DR2 HI val: ");
+       Serial.println(model.dr[7]);
   
-  for (i=0; i<MAX_INPUTS; i++) {
-    Serial.print("Input #");
-    Serial.print(i);
-    Serial.print(" pct: ");
-    Serial.print(model.stick[i]);
-    Serial.print(" min: ");
-    Serial.print(input_cal.min[i]);
-    Serial.print(" max: ");
-    Serial.print(input_cal.max[i]);
-    Serial.println();
-  }  
+       for (i=0; i<MAX_INPUTS; i++) 
+       {
+               Serial.print("Input #");
+               Serial.print(i);
+               Serial.print(" pct: ");
+               Serial.print(model.stick[i]);
+               Serial.print(" min: ");
+               Serial.print(input_cal.min[i]);
+               Serial.print(" max: ");
+               Serial.print(input_cal.max[i]);
+               Serial.println();
+       }  
 }
+#endif
 
 void scan_keys ( void )
 {
-  boolean key_in;
-
-  // To get more inputs, another 4051 analog multiplexer is used,
-  // but this time it is used for digital inputs. 8 digital inputs
-  // on one input line, as long as proper debouncing and filtering
-  // is done in hardware :P
-  for (int i=0; i<=7; i++) {
-    // To be able to detect that a key has changed state, preserve the previous..
-    prev_keys[i] = keys[i];
-
-    // Select and read input.
-    mplx_select(i);
-    keys[i] = digitalRead(A2);
-    delay(2);
-  }
+       boolean key_in;
+
+       // To get more inputs, another 4051 analog multiplexer is used,
+       // but this time it is used for digital inputs. 8 digital inputs
+       // on one input line, as long as proper debouncing and filtering
+       // is done in hardware :P
+       for (int i=0; i<=7; i++)
+       {
+               // To be able to detect that a key has changed state, preserve the previous..
+               prev_keys[i] = keys[i];
+
+               // Select and read input.
+               mplx_select(i);
+               keys[i] = digitalRead(A2);
+               delay(2);
+       }
 }
 
 
 void process_inputs(void )
 {
-  int current_input, adc_in, fact;
-  float min, max;
+       int current_input, adc_in, fact;
+       float min, max;
 
-  for (current_input=0; current_input<MAX_INPUTS; current_input++) {
+       for (current_input=0; current_input<MAX_INPUTS; current_input++) 
+       {
 
-    mplx_select(current_input);
-    adc_in = analogRead(0);
+               mplx_select(current_input);
+               adc_in = analogRead(0);
 
-       model.raw[current_input] = adc_in;
-       // New format on stick values
-       // The calculations happen around the center point, the values
-       // need to arrive at 0...100 of the range "center-to-edge",
-       // and must end up as negative on the ... negative side of center.
-       
-    if ( adc_in < input_cal.center[current_input] )
-    {
-                       // The stick is on the negative side, so the range is
-                       // from the lowest possible value to center, and we must
-                       // make this a negative percentage value.
-            max = input_cal.min[current_input];
-            min = input_cal.center[current_input];
-                       fact = -100;
-    } 
-    else 
-    {
-                       // The stick is at center, or on the positive side.
-                       // Thus, the range is from center to max, and
-                       // we need positive percentages.
-            min = input_cal.center[current_input];
-            max = input_cal.max[current_input];
-                       fact = 100;
-    }
-       // Calculate the percentage that the current stick position is at
-       // in the given range, referenced to or from center, depending :P
-    model.stick[current_input] =  fact * ((float)adc_in - min ) / (max - min);
-       
-       // If this input is configured to be reversed, simply do a sign-flip :D
-    if ( model.rev[current_input] ) model.stick[current_input] *= -1;
-
-    // Dual-rate calculation :D
-    // This is very repetitive code. It should be fast, but it may waste code-space.
-    float dr_val;
-    // Test to see if dualrate-switch #1 applies to channel...
-    if ( ( current_input == ( model.dr[0]-1) ) || ( current_input == ( model.dr[1]-1) ) )
-    {
-            if ( !keys[KEY_DR1] )
-                    dr_val = ((float)model.dr[4])/100.0; 
-            else
-                    dr_val = ((float)model.dr[5])/100.0;
-
-            model.stick[current_input] *= dr_val; 
-    }
-    else
-    // Test to see if dualrate-switch #1 applies to channel...
-    if ( ( current_input == ( model.dr[2]-1) ) || ( current_input == ( model.dr[3]-1) ) )
-    {
-            if ( !keys[KEY_DR1] )
-                    dr_val = ((float)model.dr[6])/100.0; 
-            else
-                    dr_val = ((float)model.dr[7])/100.0;
-
-            model.stick[current_input] *= dr_val; 
-    }
-  }
+               model.raw[current_input] = adc_in;
+               // New format on stick values
+               // The calculations happen around the center point, the values
+               // need to arrive at 0...100 of the range "center-to-edge",
+               // and must end up as negative on the ... negative side of center.
+               
+               if ( adc_in < input_cal.center[current_input] )
+               {
+                               // The stick is on the negative side, so the range is
+                               // from the lowest possible value to center, and we must
+                               // make this a negative percentage value.
+                               max = input_cal.min[current_input];
+                               min = input_cal.center[current_input];
+                               fact = -100;
+               
+               else 
+               {
+                               // The stick is at center, or on the positive side.
+                               // Thus, the range is from center to max, and
+                               // we need positive percentages.
+                               min = input_cal.center[current_input];
+                               max = input_cal.max[current_input];
+                               fact = 100;
+               }
+               // Calculate the percentage that the current stick position is at
+               // in the given range, referenced to or from center, depending :P
+               model.stick[current_input] =  fact * ((float)adc_in - min ) / (max - min);
+               
+               // If this input is configured to be reversed, simply do a sign-flip :D
+               if ( model.rev[current_input] ) model.stick[current_input] *= -1;
+
+               // Dual-rate calculation :D
+               // This is very repetitive code. It should be fast, but it may waste code-space.
+               float dr_val;
+               // Test to see if dualrate-switch #1 applies to channel...
+               if ( ( current_input == ( model.dr[0]-1) ) || ( current_input == ( model.dr[1]-1) ) )
+               {
+                               if ( !keys[KEY_DR1] )
+                                               dr_val = ((float)model.dr[4])/100.0; 
+                               else
+                                               dr_val = ((float)model.dr[5])/100.0;
+
+                               model.stick[current_input] *= dr_val; 
+               }
+               else
+               // Test to see if dualrate-switch #1 applies to channel...
+               if ( ( current_input == ( model.dr[2]-1) ) || ( current_input == ( model.dr[3]-1) ) )
+               {
+                               if ( !keys[KEY_DR2] )
+                                               dr_val = ((float)model.dr[6])/100.0; 
+                               else
+                                               dr_val = ((float)model.dr[7])/100.0;
+
+                               model.stick[current_input] *= dr_val; 
+               }
+       }
 }
 
 
 void ISR_timer(void)
 {
-  Timer1.stop(); // Make sure we do not run twice while working :P
-
-  if ( !do_channel )
-  {
-    set_ppm_output( LOW );
-    sum += seplength;
-    do_channel = true;
-    set_timer(seplength);
-    return;
-  }
-
-  if ( cchannel >= model.channels )
-  {
-    set_ppm_output( HIGH );
-    long framesep = framelength - sum;
-
-    sum = 0;
-    do_channel = false;
-    cchannel = 0;
-    set_timer ( framesep );
-    return;
-  }  
-
-  if ( do_channel )
-  {
-    set_ppm_output( HIGH );
-
-       // New format on stick values
-    // model.stick contains percentages, -100% to 100% in float. To make the timer-handling
-    // here as simple as possible. We want to calc the channel value as a  "ratio-value",
-    // a float in the range 0..1.0. So, by moving the lower bound to 0, then cutting the
-    // range in half, and finally dividing by 100, we should get the ratio value.
-    // Some loss of presicion occurs, perhaps the algo' should be reconsidered :P
-    long next_timer = (( chwidht * ((model.stick[cchannel]+100)/200) ) + chmin);
-    // Do sanity-check of next_timer compared to chmax and chmin...
-    while ( chmax < next_timer ) next_timer--;
-    while ( next_timer < chmin ) next_timer++;
-       
-       // Update the sum of elapsed time
-    sum += next_timer;
-
-    // Done with channel separator and value,
-    // prepare for next channel...
-    cchannel++;
-    do_channel = false;
-    set_timer ( next_timer );
-    return;
-  }
+       Timer1.stop(); // Make sure we do not run twice while working :P
+
+       if ( !do_channel )
+       {
+               set_ppm_output( LOW );
+               sum += seplength;
+               do_channel = true;
+               set_timer(seplength);
+               return;
+       }
+
+       if ( cchannel >= model.channels )
+       {
+               set_ppm_output( HIGH );
+               long framesep = framelength - sum;
+
+               sum = 0;
+               do_channel = false;
+               cchannel = 0;
+               set_timer ( framesep );
+               return;
+       }  
+
+       if ( do_channel )
+       {
+               set_ppm_output( HIGH );
+
+               // New format on stick values
+               // model.stick contains percentages, -100% to 100% in float. To make the timer-handling
+               // here as simple as possible. We want to calc the channel value as a  "ratio-value",
+               // a float in the range 0..1.0. So, by moving the lower bound to 0, then cutting the
+               // range in half, and finally dividing by 100, we should get the ratio value.
+               // Some loss of presicion occurs, perhaps the algo' should be reconsidered :P
+               long next_timer = (( chwidht * ((model.stick[cchannel]+100)/200) ) + chmin);
+               
+               // Do sanity-check of next_timer compared to chmax and chmin...
+               while ( chmax < next_timer ) next_timer--;
+               while ( next_timer < chmin ) next_timer++;
+
+               // Update the sum of elapsed time
+               sum += next_timer;
+
+               // Done with channel separator and value,
+               // prepare for next channel...
+               cchannel++;
+               do_channel = false;
+               set_timer ( next_timer );
+               return;
+       }
 }
 
+
+#ifdef DEBUG
 void serial_debug()
 {
-  int current_input;
-  for (current_input=0; current_input<MAX_INPUTS; current_input++) {
-
-    Serial.print("Input #");
-    Serial.print(current_input);
-    Serial.print(" pct: ");
-    Serial.print(model.stick[current_input]);
-    Serial.print(" raw value: ");
-    Serial.print(model.raw[current_input]);
-    Serial.print(" min: ");
-    Serial.print(input_cal.min[current_input]);
-    Serial.print(" max: ");
-    Serial.print(input_cal.max[current_input]);
-    Serial.println();
-  }
-  Serial.print("Battery level is: ");
-  Serial.println(battery_val);
-
-  Serial.print("Average loop time:");
-  Serial.println(avg_loop_time);
-
-  Serial.println();
+       int current_input;
+       for (current_input=0; current_input<MAX_INPUTS; current_input++) 
+       {
+               Serial.print("Input #");
+               Serial.print(current_input);
+               Serial.print(" pct: ");
+               Serial.print(model.stick[current_input]);
+               Serial.print(" raw value: ");
+               Serial.print(model.raw[current_input]);
+               Serial.print(" min: ");
+               Serial.print(input_cal.min[current_input]);
+               Serial.print(" max: ");
+               Serial.print(input_cal.max[current_input]);
+               Serial.println();
+       }
+       Serial.print("Battery level is: ");
+       Serial.println(battery_val);
+
+       Serial.print("Average loop time:");
+       Serial.println(avg_loop_time);
+
+       Serial.print("Free RAM:");
+       Serial.print( FreeRam() );
+       Serial.println();
 }
+#endif
 
 void dr_inputselect( int no, int in )
 {
@@ -712,7 +746,10 @@ void dr_inputselect( int no, int in )
        lcd.setCursor(0 , 0);
        lcd.print("D/R switch ");
        lcd.print( no + 1 );
-       lcd.print("    ");
+       //lcd.print("    ");
+       
+       lcd.setCursor(0 , 1);
+       lcd.print("              ");
        lcd.setCursor(0 , 1);
        lcd.print("Input ");
        lcd.print(in+1);
@@ -748,7 +785,10 @@ void dr_value()
        lcd.setCursor(0 , 0);
        lcd.print("D/R switch ");
        lcd.print( menu_substate - 3 );
-       lcd.print("    ");
+
+
+       lcd.setCursor(0 , 1);
+       lcd.print("              ");
        lcd.setCursor(0 , 1);
        lcd.print( state ? "HI" : "LO" );
        lcd.print(" Value :");
@@ -768,79 +808,102 @@ void dr_value()
 }
 void ui_handler()
 {
-  int row; 
-  int col;
-  scan_keys();
-
-  if ( displaystate != MENU )
-  {
-       menu_substate = 0;
-    if ( check_key(KEY_UP) && displaystate == VALUES  ) { 
-      displaystate = BATTERY; 
-      return; 
-    }
-    else if ( check_key(KEY_UP) && displaystate == BATTERY ) { 
-      displaystate = TIMER; 
-      return; 
-    }
-    else if ( check_key(KEY_UP) && displaystate == TIMER ) { 
-      displaystate = CURMODEL; 
-      return; 
-    }
-    else if ( check_key(KEY_UP) && displaystate == CURMODEL ) { 
-      displaystate = VALUES; 
-      return; 
-    }
-
-    else if ( check_key(KEY_DOWN) ) { 
-      displaystate = MENU; 
-      return; 
-    }
-  }
-
-  digitalWrite(13, digitalRead(13) ^ 1 );
-
-  switch ( displaystate )
-  {
-    case VALUES:
-      int current_input;
-      for (current_input=0; current_input<MAX_INPUTS; current_input++) {
-        // In channel value display, do a simple calc
-        // of the LCD row & column location. With 8 channels
-        // we can fit eight channels as percentage values on
-        // a simple 16x2 display...
-        if ( current_input < 4 )
-        {
-          col = current_input * 4; 
-          row = 0;
-        } 
-        else 
-        {
-          col = (current_input-4) * 4;      
-          row = 1;
-        }
-        // Overwriting the needed positions with
-        // blanks cause less display-flicker than
-        // actually clearing the display...
-        lcd.setCursor(col, row);
-        lcd.print("    ");
-        lcd.setCursor(col, row);
-        // Display uses percents, while PPM uses ratio....
-               // New format on stick values
-               lcd.print( (int)model.stick[current_input] );
-      }
-      break;
+       int row; 
+       int col;
+       scan_keys();
 
+       if ( check_key( KEY_UP) || check_key(KEY_DOWN))
+               lcd.clear();
 
-    case BATTERY:    
-      lcd.clear();
-      lcd.print("Battery level: ");
-      lcd.setCursor(0 , 1);
-      lcd.print( (float)battery_val/10);
-      lcd.print("V");
-      if ( battery_val < BATTERY_LOW ) lcd.print(" - WARNING");
-      else lcd.print(" - OK");
+       if ( displaystate != MENU )
+       {
+               menu_substate = 0;
+               if ( check_key(KEY_UP) && displaystate == VALUES  ) { 
+                       displaystate = BATTERY; 
+                       return; 
+               }
+               else if ( check_key(KEY_UP) && displaystate == BATTERY ) { 
+                       displaystate = TIMER; 
+                       return; 
+               }
+               else if ( check_key(KEY_UP) && displaystate == TIMER ) { 
+                       displaystate = CURMODEL; 
+                       return; 
+               }
+               else if ( check_key(KEY_UP) && displaystate == CURMODEL ) { 
+                       displaystate = VALUES; 
+                       return; 
+               }
+
+               else if ( check_key(KEY_DOWN) ) { 
+                       displaystate = MENU; 
+                       return; 
+               }
+       }
+               
+       digitalWrite(13, digitalRead(13) ^ 1 );
+
+       switch ( displaystate )
+       {
+       case VALUES:
+               int current_input;
+
+               row = 0; col = 0;
+               lcd.setCursor(col, row);
+               lcd.print("            ");
+               lcd.setCursor(col, row);
+
+               lcd.print("S1:");
+               lcd.print( keys[KEY_DR1] ? "On " : "Off" );
+               lcd.print(" S2:");
+               lcd.print( keys[KEY_DR2] ? "On " : "Off" );
+
+               row = 2; col = 0;
+               for (current_input=0; current_input<MAX_INPUTS; current_input++) {
+                       if (row == 6)
+                       {
+                               row = 2;
+                               col = 40;
+                       }
+
+                       // Overwriting the needed positions with
+                       // blanks cause less display-flicker than
+                       // actually clearing the display...
+                       lcd.setCursor(col, row);
+                       lcd.print("      ");
+                       lcd.setCursor(col, row);
+                       
+                       char mod_indicator = NULL;
+                       if (( keys[KEY_DR1] ) && (( model.dr[0] == current_input+1) || ( model.dr[1] == current_input+1)))
+                               mod_indicator = '/';
+                       if (( keys[KEY_DR2] ) && (( model.dr[2] == current_input+1) || ( model.dr[3] == current_input+1)))
+                               if (mod_indicator) mod_indicator = '|';
+                               else mod_indicator = '\\';
+                       
+                       if ( mod_indicator) lcd.print(mod_indicator);
+                       else lcd.print(" ");
+                       
+                       lcd.print( current_input+1);
+                       lcd.print(":");
+                       // Display uses percents, while PPM uses ratio....
+                       // New format on stick values
+                       lcd.print( (int)model.stick[current_input] );
+
+                       row++;
+               }
       break;
+
+    case BATTERY:    
+               lcd.setCursor(0 , 0);
+               lcd.print("Battery level: ");
+               lcd.setCursor(0 , 1);
+               lcd.print( "            ");
+               lcd.setCursor(0 , 1);
+               lcd.print( (float)battery_val/10);
+               lcd.print("V");
+               if ( battery_val < BATTERY_LOW ) lcd.print(" - WARNING");
+               else lcd.print(" - OK");
+               break;
       
     
 
@@ -850,10 +913,12 @@ void ui_handler()
                int minutes;
                int seconds;
                
-               lcd.clear();
+        lcd.setCursor(0 , 0);
                lcd.print("Timer: ");
                lcd.print( clock_timer.running ? "Running" : "Stopped" );
                lcd.setCursor(5 , 1);
+               lcd.print("         ");
+               lcd.setCursor(5 , 1);
                if ( clock_timer.running )
                {
                        clock_timer.value = millis() - (clock_timer.start + clock_timer.init);
@@ -862,7 +927,8 @@ void ui_handler()
                clock_timer.value = clock_timer.value % 3600000;
                minutes = ( clock_timer.value / 1000 ) / 60;
                seconds = ( clock_timer.value / 1000 ) % 60;
-               if ( hours ) {
+               if ( hours ) 
+               {
                        lcd.print(hours);
                        lcd.print(":");
                }
@@ -872,21 +938,29 @@ void ui_handler()
                if ( seconds < 10 ) lcd.print("0");
                lcd.print( seconds );
                
-        if ( check_key(KEY_INC) ) { 
+        if ( check_key(KEY_INC) )
+               {
                        if ( !clock_timer.running && !clock_timer.start )
                        {
                                clock_timer.start = millis();
                                clock_timer.value = 0;
                                clock_timer.running = true;
-                       } else if ( !clock_timer.running && clock_timer.start ) {
+                       } 
+                       else if ( !clock_timer.running && clock_timer.start ) 
+                       {
                                clock_timer.start = millis() - clock_timer.value;
                                clock_timer.running = true;
-                       } else if ( clock_timer.running ) {
+                       } 
+                       else if ( clock_timer.running ) 
                                clock_timer.running = false;
-                       }
+                       
                        return; 
-        } else if ( check_key(KEY_DEC) ) { 
-                       if ( !clock_timer.running && clock_timer.start ) {
+                       
+        }
+               else if ( check_key(KEY_DEC) ) 
+               {
+                       if ( !clock_timer.running && clock_timer.start )
+                       {
                                clock_timer.value = 0;
                                clock_timer.start = 0;
                                clock_timer.init = 0;
@@ -895,92 +969,113 @@ void ui_handler()
         }
                break;
 
-
                
        case CURMODEL:    
-      lcd.clear();
-      lcd.print("Model #: ");
-         lcd.print( (int)current_model );
-      lcd.setCursor(0 , 1);
-      lcd.print("NAME (not impl)");
-      break;
+               lcd.setCursor(0 , 0);
+               lcd.print("Model #: ");
+               lcd.print( (int)current_model );
+               lcd.setCursor(0 , 1);
+               lcd.print("NAME (not impl)");
+               break;
 
 
          
     case MENU:
-      lcd.clear();
-      switch ( menu_mainstate )
-      {
-        case TOP:
-          lcd.print("In MENU mode!");
-          lcd.setCursor(0 , 1);
-          lcd.print("Esc UP. Scrl DN.");
-          menu_substate = 0;
-          if ( check_key(KEY_UP) ) { 
-            displaystate = VALUES; 
-            return; 
-          }
-          else if ( check_key(KEY_DOWN) ) { 
-            menu_mainstate = INVERTS; 
-            return; 
-          }
-          break;
+               lcd.setCursor(0 , 0);
+               switch ( menu_mainstate )
+               {
+               case TOP:
+                       lcd.setCursor(0 , 0);
+                       lcd.print("In MENU mode!");
+                       lcd.setCursor(0 , 1);
+                       lcd.print("UP to quit.");
+                       lcd.setCursor(0 , 2);
+                       lcd.print("DOWN to scroll");
+
+                       menu_substate = 0;
+                       if ( check_key(KEY_UP) )
+                       {
+                               displaystate = VALUES; 
+                               lcd.clear();
+                               return; 
+                       }
+                       else if ( check_key(KEY_DOWN) ) 
+                       {
+                               lcd.clear();
+                               menu_mainstate = INVERTS; 
+                               return; 
+                       }
+                       break;
     
     
-        case INVERTS:
-          if ( menu_substate >= model.channels ) menu_substate = 0;
-          if ( menu_substate < 0) menu_substate = (model.channels - 1);
-          lcd.print("Channel invert");
-          lcd.setCursor(0 , 1);
-          lcd.print("Ch ");
-          lcd.print(menu_substate+1);
-          lcd.print( (model.rev[menu_substate] ?  ": Invert" : ": Normal"));
-
-          if ( check_key(KEY_UP) ) { 
-            menu_mainstate = TOP; 
-            return; 
-          }
-          else if ( check_key(KEY_DOWN) ) { 
-            menu_mainstate = DUALRATES; 
-            return; 
-          }
-
-          if ( check_key(KEY_RIGHT) ) { 
-            menu_substate++; 
-            return; 
-          }
-          else if ( check_key(KEY_LEFT) ) { 
-            menu_substate--; 
-            return; 
-          }
-          else if ( check_key(KEY_INC) || check_key(KEY_DEC) ) { 
-            model.rev[menu_substate] ^= 1; 
-            return; 
-          }
-          break;
+               case INVERTS:
+                       if ( menu_substate >= model.channels ) menu_substate = 0;
+                       if ( menu_substate < 0) menu_substate = (model.channels - 1);
+                       lcd.print("Channel invert");
+                       lcd.setCursor(0 , 1);
+                       lcd.print("Ch ");
+                       lcd.print(menu_substate+1);
+                       lcd.print( (model.rev[menu_substate] ?  ": Invert" : ": Normal"));
+
+                       if ( check_key(KEY_UP) )
+                       {
+                               menu_mainstate = TOP; 
+                               lcd.clear();
+                               return; 
+                       }
+                       else if ( check_key(KEY_DOWN) )
+                       {
+                               menu_mainstate = DUALRATES; 
+                               lcd.clear();
+                               return; 
+                       }
+
+                       if ( check_key(KEY_RIGHT) )
+                       {
+                               menu_substate++; 
+                               return; 
+                       }
+                       else if ( check_key(KEY_LEFT) )
+                       {
+                               menu_substate--; 
+                               return; 
+                       }
+                       else if ( check_key(KEY_INC) || check_key(KEY_DEC) )
+                       {
+                               model.rev[menu_substate] ^= 1; 
+                               return; 
+                       }
+                       break;
           
         case DUALRATES:
-          if ( menu_substate > 5 ) menu_substate = 0;
-          if ( menu_substate < 0) menu_substate = 5;
+                       if ( menu_substate > 5 ) menu_substate = 0;
+                       if ( menu_substate < 0) menu_substate = 5;
                
-          if ( check_key(KEY_UP) ) { 
-            menu_mainstate = INVERTS; 
-            return; 
-          }          
-          if ( check_key(KEY_DOWN) ) {
-            menu_mainstate = EXPOS;
-            return;
-          }
-          if ( check_key(KEY_RIGHT) ) { 
-            menu_substate++; 
-            return; 
-          }
-          else if ( check_key(KEY_LEFT) ) { 
-            menu_substate--; 
-            return; 
-          }
-          switch (menu_substate)
-                 {
+                       if ( check_key(KEY_UP) )
+                       {
+                               menu_mainstate = INVERTS; 
+                               lcd.clear();
+                               return; 
+                       }          
+                       if ( check_key(KEY_DOWN) )
+                       {
+                               menu_mainstate = EXPOS;
+                               lcd.clear();
+                               return;
+                       }
+                       if ( check_key(KEY_RIGHT) )
+                       {
+                               menu_substate++; 
+                               return; 
+                       }
+                       else if ( check_key(KEY_LEFT) )
+                       {
+                               menu_substate--; 
+                               return; 
+                       }
+                       
+                       switch (menu_substate)
+                       {
                        case 0:
                                dr_inputselect(0, 0);
                                return;
@@ -1000,66 +1095,115 @@ void ui_handler()
                        default:
                                menu_substate = 0;
                                break;
-                 }               
-          break;
+                       }                 
+                       break;
         
         case EXPOS:
-                   //________________
-          lcd.print("Input expo curve");
-          lcd.setCursor(0 , 1);
-          lcd.print("Not implemented");
-          // Possible, if input values are mapped to +/- 100 rather than 0..1 ..
-          // plot ( x*(1 - 1.0*cos (x/(20*PI)) )) 0 to 100
-          // Run in wolfram to see result, adjust the 1.0 factor to inc/red effect.
-          // Problem: -100 to 100 is terribly bad presicion, esp. considering that
-          // the values started as 0...1024, and we have 1000usec to "spend" on channels.
-                 
-                 // NEW IDEA provided my ivarf @ hig: use bezier curves og hermite curves!
-                 // Looks like a promising idea, but the implementation is still a bitt off
-                 // on the time-horizon :P
-          if ( check_key(KEY_UP ) ) { 
-            menu_mainstate = DUALRATES; 
-            return; 
-          }          
-          if ( check_key(KEY_DOWN ) ) {
-            menu_mainstate = DEBUG;
-            return;
-          }
-          break;
-          
-        case DEBUG:
-          lcd.setCursor(0 , 0);
-          lcd.print("Dumping debug to");
-          lcd.setCursor(0 , 1);
-          lcd.print("serial port 0");
-          serial_debug();          
-          if ( check_key(KEY_UP ) ) { 
-            // FIXME: Remember to update the "Scroll up" state!
-            menu_mainstate = EXPOS; 
-            return; 
-          } else if ( check_key(KEY_DOWN ) ) {
-            menu_mainstate = SAVE;
-            return;
-          }
-          break;
-    
-        default:
-          lcd.print("Not implemented");
-          lcd.setCursor(0 , 1);
-          lcd.print("Press DOWN...");
-          if ( check_key(KEY_DOWN ) ) menu_mainstate = TOP;
-      }
-      break;
-      
-      
-    default:
-      // Invalid
-      return;
-  }
+                                     //________________
+                       lcd.print("Input expo curve");
+                       lcd.setCursor(0 , 1);
+                       lcd.print("Not implemented");
+                       // Possible, if input values are mapped to +/- 100 rather than 0..1 ..
+                       // plot ( x*(1 - 1.0*cos (x/(20*PI)) )) 0 to 100
+                       // Run in wolfram to see result, adjust the 1.0 factor to inc/red effect.
+                       // Problem: -100 to 100 is terribly bad presicion, esp. considering that
+                       // the values started as 0...1024, and we have 1000usec to "spend" on channels.
+
+                       // NEW IDEA provided my ivarf @ hig: use bezier curves og hermite curves!
+                       // Looks like a promising idea, but the implementation is still a bitt off
+                       // on the time-horizon :P
+                       if ( check_key(KEY_UP ) )
+                       {
+                               menu_mainstate = DUALRATES; 
+                               lcd.clear();
+                               return; 
+                       }          
+#ifdef DEBUG          
+                       if ( check_key(KEY_DOWN ) )
+                       {
+                               menu_mainstate = DEBUG_DUMP;
+                               lcd.clear();
+                               return;
+                       }
+#else
+                       if ( check_key(KEY_DOWN ) )
+                       {
+                               menu_mainstate = TOP;
+                               lcd.clear();
+                               return;
+                       }
 
-  return;
+#endif
+                       break;
+
+#ifdef DEBUG          
+               case DEBUG_DUMP:
+                       lcd.setCursor(0 , 0);
+                       lcd.print("Dumping debug to");
+                       lcd.setCursor(0 , 1);
+                       lcd.print("serial port 0");
+                       serial_debug();          
+                       if ( check_key(KEY_UP ) ) 
+                       {
+                               // FIXME: Remember to update the "Scroll up" state!
+                               menu_mainstate = EXPOS; 
+                               lcd.clear();
+                               return; 
+                       } else if ( check_key(KEY_DOWN ) )
+                       {
+                               menu_mainstate = SAVE;
+                               lcd.clear();
+                               return;
+                       }
+                       break;
+#endif    
+               default:
+                       lcd.print("Not implemented");
+                       lcd.setCursor(0 , 1);
+                       lcd.print("Press DOWN...");
+                       if ( check_key(KEY_DOWN ) ) menu_mainstate = TOP;
+                       
+               } // End of settings menu / MENU
+               break;
+
+
+       default:
+                 // Invalid
+                 return;
+       } // End of main UI switch
+       return;
 }
 
+#ifdef DEBUG
+/* The following code is taken from the 
+   Arduino FAT16 Library by William Greiman 
+   The code may or may-not survive in the long run,
+   depending on what licensing-terms we decide on.
+   The license will be open source, but the FAT16lib
+   is GPL v3, and I (fishy) am personally not so sure about that... 
+   
+   On the other hand... This code is a very "intuitive approach",
+   so contacting the author may give us the option of relicencing just this bit...
+*/
+static int FreeRam(void) {
+       extern int  __bss_end;
+       extern int* __brkval;
+       int free_memory;
+       if (reinterpret_cast<int>(__brkval) == 0) 
+       {
+               // if no heap use from end of bss section
+               free_memory = reinterpret_cast<int>(&free_memory)
+                                               - reinterpret_cast<int>(&__bss_end);
+       }
+       else 
+       {
+               // use from top of stack to heap
+               free_memory = reinterpret_cast<int>(&free_memory)
+                                               - reinterpret_cast<int>(__brkval);
+       }
+       return free_memory;
+}
+#endif