]> git.mxchange.org Git - flightgear.git/blobdiff - src/Network/atc610x.cxx
Updated adf property names.
[flightgear.git] / src / Network / atc610x.cxx
index c30a5ce2f09d60ca4d713e948b7b1943b7544d20..6e41ef7bc2a9b5d2448d46ec960253d14ecd9cc8 100644 (file)
 
 SG_USING_STD(string);
 
-#if defined( _MSC_VER ) || defined(__MINGW32__)
-#  define snprintf _snprintf
-#endif
-
 // Lock the ATC 610 hardware
 static int ATC610xLock( int fd ) {
     // rewind
@@ -185,6 +181,29 @@ static void ATC610xReadSwitches( int fd, unsigned char *switch_bytes ) {
 }
 
 
+// Turn a lamp on or off
+void ATC610xSetLamp( int fd, int channel, bool value ) {
+    // lamp channels 0-63 are written to LampPort0, channels 64-127
+    // are written to LampPort1
+
+    // bits 0-6 are the lamp address
+    // bit 7 is the value (on/off)
+
+    int result;
+
+    // Write the value
+    unsigned char buf[3];
+    buf[0] = channel;
+    buf[1] = value;
+    buf[2] = 0;
+    result = write( fd, buf, 2 );
+    if ( result != 2 ) {
+        SG_LOG( SG_IO, SG_ALERT,  "Write failed" );
+        exit( -1 );
+    }
+}
+
+
 // Open and initialize ATC 610x hardware
 bool FGATC610x::open() {
     if ( is_enabled() ) {
@@ -203,6 +222,7 @@ bool FGATC610x::open() {
 
     snprintf( lock_file, 256, "/proc/atc610x/board%d/lock", board );
     snprintf( analog_in_file, 256, "/proc/atc610x/board%d/analog_in", board );
+    snprintf( lamps_file, 256, "/proc/atc610x/board%d/lamps", board );
     snprintf( radios_file, 256, "/proc/atc610x/board%d/radios", board );
     snprintf( stepper_file, 256, "/proc/atc610x/board%d/steppers", board );
     snprintf( switches_file, 256, "/proc/atc610x/board%d/switches", board );
@@ -229,6 +249,15 @@ bool FGATC610x::open() {
        exit( -1 );
     }
 
+    lamps_fd = ::open( lamps_file, O_WRONLY );
+    if ( lamps_fd == -1 ) {
+       SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
+       char msg[256];
+       snprintf( msg, 256, "Error opening %s", lamps_file );
+       perror( msg );
+       exit( -1 );
+    }
+
     radios_fd = ::open( radios_file, O_RDWR );
     if ( radios_fd == -1 ) {
        SG_LOG( SG_IO, SG_ALERT, "errno = " << errno );
@@ -277,7 +306,7 @@ bool FGATC610x::open() {
 
     bool home = false;
     int timeout = 900;          // about 30 seconds
-    while ( ! home ) {
+    while ( ! home && timeout > 0 ) {
         if ( timeout % 150 == 0 ) {
             SG_LOG( SG_IO, SG_INFO, "waiting for compass = " << timeout );
         } else {
@@ -327,6 +356,14 @@ bool FGATC610x::open() {
 
     ATC610xRelease( lock_fd );
 
+    /////////////////////////////////////////////////////////////////////
+    // Blank the lamps
+    /////////////////////////////////////////////////////////////////////
+
+    for ( int i = 0; i < 128; ++i ) {
+        ATC610xSetLamp( lamps_fd, i, false );
+    }
+
     /////////////////////////////////////////////////////////////////////
     // Finished initing hardware
     /////////////////////////////////////////////////////////////////////
@@ -359,8 +396,20 @@ bool FGATC610x::open() {
     nav2_stby_freq
        = fgGetNode( "/radios/nav[1]/frequencies/standby-mhz", true );
 
-    adf_freq = fgGetNode( "/radios/adf/frequencies/selected-khz", true );
-    adf_stby_freq = fgGetNode( "/radios/adf/frequencies/standby-khz", true );
+    adf_on_off_vol = fgGetNode( "/radios/kr-87/on-off-volume", true );
+    adf_adf_btn = fgGetNode( "/radios/kr-87/adf-btn", true );
+    adf_bfo_btn = fgGetNode( "/radios/kr-87/bfo-btn", true );
+    adf_freq = fgGetNode( "/radios/kr-87/frequencies/selected-khz", true );
+    adf_stby_freq = fgGetNode( "/radios/kr-87/frequencies/standby-khz", true );
+    adf_stby_mode = fgGetNode( "/radios/kr-87/stby-mode", true );
+    adf_timer_mode = fgGetNode( "/radios/kr-87/timer-mode", true );
+    adf_count_mode = fgGetNode( "/radios/kr-87/count-mode", true );
+    adf_flight_timer = fgGetNode( "/radios/kr-87/flight-timer", true );
+    adf_elapsed_timer = fgGetNode( "/radios/kr-87/elapsed-timer", true );
+
+    inner = fgGetNode( "/radios/marker-beacon/inner", true );
+    middle = fgGetNode( "/radios/marker-beacon/middle", true );
+    outer = fgGetNode( "/radios/marker-beacon/outer", true );
 
     return true;
 }
@@ -423,7 +472,7 @@ bool FGATC610x::do_analog_in() {
 
     // adf volume
     tmp = (float)analog_in_data[26] / 1024.0f;
-    fgSetFloat( "/radios/adf/volume", tmp );
+    fgSetFloat( "/radios/kr-87/on-off-volume", tmp );
 
     // nav2 obs tuner
     tmp = (float)analog_in_data[29] * 360.0f / 1024.0f;
@@ -438,12 +487,61 @@ bool FGATC610x::do_analog_in() {
 }
 
 
+/////////////////////////////////////////////////////////////////////
+// Write the lights
+/////////////////////////////////////////////////////////////////////
+
+bool FGATC610x::do_lights( double dt ) {
+
+    // Marker beacons
+    ATC610xSetLamp( lamps_fd, 4, inner->getBoolValue() );
+    ATC610xSetLamp( lamps_fd, 5, middle->getBoolValue() );
+    ATC610xSetLamp( lamps_fd, 3, outer->getBoolValue() );
+
+    // ADF annunciators
+    if ( adf_on_off_vol->getDoubleValue() >= 0.01 ) {
+        ATC610xSetLamp( lamps_fd, 11, !adf_adf_btn->getBoolValue() ); // ANT
+        ATC610xSetLamp( lamps_fd, 12, adf_adf_btn->getBoolValue() ); // ADF
+        ATC610xSetLamp( lamps_fd, 13, adf_bfo_btn->getBoolValue() ); // BFO
+        ATC610xSetLamp( lamps_fd, 14, !adf_stby_mode->getBoolValue() ); // FRQ
+        ATC610xSetLamp( lamps_fd, 15, adf_stby_mode->getBoolValue() &&
+                        !adf_timer_mode->getBoolValue() ); // FLT
+
+        // ET needs to blink when we are in ET set countdown time
+        if ( adf_count_mode->getIntValue() < 2 ) {
+            ATC610xSetLamp( lamps_fd, 16, adf_stby_mode->getBoolValue() &&
+                            adf_timer_mode->getBoolValue() ); // ET
+        } else {
+            et_flash_time += dt;
+            if ( et_flash && et_flash_time > 0.5 ) {
+                et_flash = false;
+                et_flash_time -= 0.5;
+            } else if ( !et_flash && et_flash_time > 0.2 ) {
+                et_flash = true;
+                et_flash_time -= 0.2;
+            }
+            ATC610xSetLamp( lamps_fd, 16, et_flash ); // ET
+        }
+    } else {
+        ATC610xSetLamp( lamps_fd, 11, false ); // ANT
+        ATC610xSetLamp( lamps_fd, 12, false ); // ADF
+        ATC610xSetLamp( lamps_fd, 13, false ); // BFO
+        ATC610xSetLamp( lamps_fd, 14, false ); // FRQ
+        ATC610xSetLamp( lamps_fd, 15, false ); // FLT
+        ATC610xSetLamp( lamps_fd, 16, false ); // ET
+    }
+
+    return true;
+}
+
+
 /////////////////////////////////////////////////////////////////////
 // Read radio switches 
 /////////////////////////////////////////////////////////////////////
 
 bool FGATC610x::do_radio_switches() {
-    float freq, inc;
+    double freq, coarse_freq, fine_freq, value;
+    int diff;
 
     ATC610xReadRadios( radios_fd, radio_switch_data );
 
@@ -487,7 +585,7 @@ bool FGATC610x::do_radio_switches() {
     static int last_nav1_swap;
     if ( nav1_swap && (last_nav1_swap != nav1_swap) ) {
        float tmp = nav1_freq->getFloatValue();
-       fgSetFloat( "/radios/nav[0]/frequencies/selected-mhz",
+       fgSetFloat( "/radios/nav[0]/freqencies/selected-mhz",
                   nav1_stby_freq->getFloatValue() );
        fgSetFloat( "/radios/nav[0]/frequencies/standby-mhz", tmp );
     }
@@ -505,211 +603,289 @@ bool FGATC610x::do_radio_switches() {
     last_nav2_swap = nav2_swap;
 
     // Com1 Tuner
-    int com1_tuner_fine = (radio_switch_data[5] >> 4) & 0x0f;
-    int com1_tuner_course = radio_switch_data[5] & 0x0f;
-    // cout << "com1 = " << com1_tuner_fine << " " << com1_tuner_course << endl;
+    int com1_tuner_fine = ((radio_switch_data[5] >> 4) & 0x0f) - 1;
+    int com1_tuner_coarse = (radio_switch_data[5] & 0x0f) - 1;
     static int last_com1_tuner_fine = com1_tuner_fine;
-    static int last_com1_tuner_course = com1_tuner_course;
-    inc = 0.0;
+    static int last_com1_tuner_coarse = com1_tuner_coarse;
+
+    freq = com1_stby_freq->getFloatValue();
+    coarse_freq = (int)freq;
+    fine_freq = (int)((freq - coarse_freq) * 40 + 0.5);
+
     if ( com1_tuner_fine != last_com1_tuner_fine ) {
-       if ( com1_tuner_fine == 0x0c && last_com1_tuner_fine == 0x01 ) {
-           inc = -0.025;
-       } else if ( com1_tuner_fine == 0x01 && last_com1_tuner_fine == 0x0c ) {
-           inc = -0.025;
-       } else if ( com1_tuner_fine > last_com1_tuner_fine ) {
-           inc = 0.025;
-       } else {
-           inc = -0.025;
-       }
-    }
-    if ( com1_tuner_course != last_com1_tuner_course ) {
-       if ( com1_tuner_course == 0x0c && last_com1_tuner_course == 0x01 ) {
-           inc = -1.0;
-       } else if ( com1_tuner_course == 0x01
-                   && last_com1_tuner_course == 0x0c ) {
-           inc = -1.0;
-       } else if ( com1_tuner_course > last_com1_tuner_course ) {
-           inc = 1.0;
-       } else {
-           inc = -1.0;
-       }
+        diff = com1_tuner_fine - last_com1_tuner_fine;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( com1_tuner_fine < last_com1_tuner_fine ) {
+                // going up
+                diff = 12 - last_com1_tuner_fine + com1_tuner_fine;
+            } else {
+                // going down
+                diff = com1_tuner_fine - 12 - last_com1_tuner_fine;
+            }
+        }
+        fine_freq += diff;
+    }
+    while ( fine_freq >= 40.0 ) { fine_freq -= 40.0; }
+    while ( fine_freq < 0.0 )  { fine_freq += 40.0; }
+
+    if ( com1_tuner_coarse != last_com1_tuner_coarse ) {
+        diff = com1_tuner_coarse - last_com1_tuner_coarse;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( com1_tuner_coarse < last_com1_tuner_coarse ) {
+                // going up
+                diff = 12 - last_com1_tuner_coarse + com1_tuner_coarse;
+            } else {
+                // going down
+                diff = com1_tuner_coarse - 12 - last_com1_tuner_coarse;
+            }
+        }
+        coarse_freq += diff;
     }
+    if ( coarse_freq < 118.0 ) { coarse_freq += 19.0; }
+    if ( coarse_freq > 136.0 ) { coarse_freq -= 19.0; }
+
     last_com1_tuner_fine = com1_tuner_fine;
-    last_com1_tuner_course = com1_tuner_course;
+    last_com1_tuner_coarse = com1_tuner_coarse;
 
-    freq = com1_stby_freq->getFloatValue() + inc;
-    if ( freq < 0.0 ) {
-       freq = 140.0;
-    }
-    if ( freq > 140.0 ) {
-       freq = 0.0;
-    }
-    fgSetFloat( "/radios/comm[0]/frequencies/standby-mhz", freq );
+    fgSetFloat( "/radios/comm[0]/frequencies/standby-mhz", 
+                coarse_freq + fine_freq / 40.0 );
 
     // Com2 Tuner
-    int com2_tuner_fine = (radio_switch_data[13] >> 4) & 0x0f;
-    int com2_tuner_course = radio_switch_data[13] & 0x0f;
+    int com2_tuner_fine = ((radio_switch_data[13] >> 4) & 0x0f) - 1;
+    int com2_tuner_coarse = (radio_switch_data[13] & 0x0f) - 1;
     static int last_com2_tuner_fine = com2_tuner_fine;
-    static int last_com2_tuner_course = com2_tuner_course;
-    inc = 0.0;
+    static int last_com2_tuner_coarse = com2_tuner_coarse;
+
+    freq = com2_stby_freq->getFloatValue();
+    coarse_freq = (int)freq;
+    fine_freq = (int)((freq - coarse_freq) * 40 + 0.5);
+
     if ( com2_tuner_fine != last_com2_tuner_fine ) {
-       if ( com2_tuner_fine == 0x0c && last_com2_tuner_fine == 0x01 ) {
-           inc = -0.025;
-       } else if ( com2_tuner_fine == 0x01 && last_com2_tuner_fine == 0x0c ) {
-           inc = -0.025;
-       } else if ( com2_tuner_fine > last_com2_tuner_fine ) {
-           inc = 0.025;
-       } else {
-           inc = -0.025;
-       }
-    }
-    if ( com2_tuner_course != last_com2_tuner_course ) {
-       if ( com2_tuner_course == 0x0c && last_com2_tuner_course == 0x01 ) {
-           inc = -1.0;
-       } else if ( com2_tuner_course == 0x01
-                   && last_com2_tuner_course == 0x0c ) {
-           inc = -1.0;
-       } else if ( com2_tuner_course > last_com2_tuner_course ) {
-           inc = 1.0;
-       } else {
-           inc = -1.0;
-       }
+        diff = com2_tuner_fine - last_com2_tuner_fine;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( com2_tuner_fine < last_com2_tuner_fine ) {
+                // going up
+                diff = 12 - last_com2_tuner_fine + com2_tuner_fine;
+            } else {
+                // going down
+                diff = com2_tuner_fine - 12 - last_com2_tuner_fine;
+            }
+        }
+        fine_freq += diff;
+    }
+    while ( fine_freq >= 40.0 ) { fine_freq -= 40.0; }
+    while ( fine_freq < 0.0 )  { fine_freq += 40.0; }
+
+    if ( com2_tuner_coarse != last_com2_tuner_coarse ) {
+        diff = com2_tuner_coarse - last_com2_tuner_coarse;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( com2_tuner_coarse < last_com2_tuner_coarse ) {
+                // going up
+                diff = 12 - last_com2_tuner_coarse + com2_tuner_coarse;
+            } else {
+                // going down
+                diff = com2_tuner_coarse - 12 - last_com2_tuner_coarse;
+            }
+        }
+        coarse_freq += diff;
     }
+    if ( coarse_freq < 118.0 ) { coarse_freq += 19.0; }
+    if ( coarse_freq > 136.0 ) { coarse_freq -= 19.0; }
+
     last_com2_tuner_fine = com2_tuner_fine;
-    last_com2_tuner_course = com2_tuner_course;
+    last_com2_tuner_coarse = com2_tuner_coarse;
 
-    freq = com2_stby_freq->getFloatValue() + inc;
-    if ( freq < 0.0 ) {
-       freq = 140.0;
-    }
-    if ( freq > 140.0 ) {
-       freq = 0.0;
-    }
-    fgSetFloat( "/radios/comm[1]/frequencies/standby-mhz", freq );
+    fgSetFloat( "/radios/comm[1]/frequencies/standby-mhz",
+                coarse_freq + fine_freq / 40.0 );
 
     // Nav1 Tuner
-    int nav1_tuner_fine = (radio_switch_data[9] >> 4) & 0x0f;
-    int nav1_tuner_course = radio_switch_data[9] & 0x0f;
+    int nav1_tuner_fine = ((radio_switch_data[9] >> 4) & 0x0f) - 1;
+    int nav1_tuner_coarse = (radio_switch_data[9] & 0x0f) - 1;
     static int last_nav1_tuner_fine = nav1_tuner_fine;
-    static int last_nav1_tuner_course = nav1_tuner_course;
-    inc = 0.0;
+    static int last_nav1_tuner_coarse = nav1_tuner_coarse;
+
+    freq = nav1_stby_freq->getFloatValue();
+    coarse_freq = (int)freq;
+    fine_freq = (int)((freq - coarse_freq) * 20 + 0.5);
+
     if ( nav1_tuner_fine != last_nav1_tuner_fine ) {
-       if ( nav1_tuner_fine == 0x0c && last_nav1_tuner_fine == 0x01 ) {
-           inc = -0.05;
-       } else if ( nav1_tuner_fine == 0x01 && last_nav1_tuner_fine == 0x0c ) {
-           inc = -0.05;
-       } else if ( nav1_tuner_fine > last_nav1_tuner_fine ) {
-           inc = 0.05;
-       } else {
-           inc = -0.05;
-       }
-    }
-    if ( nav1_tuner_course != last_nav1_tuner_course ) {
-       if ( nav1_tuner_course == 0x0c && last_nav1_tuner_course == 0x01 ) {
-           inc = -1.0;
-       } else if ( nav1_tuner_course == 0x01
-                   && last_nav1_tuner_course == 0x0c ) {
-           inc = -1.0;
-       } else if ( nav1_tuner_course > last_nav1_tuner_course ) {
-           inc = 1.0;
-       } else {
-           inc = -1.0;
-       }
+        diff = nav1_tuner_fine - last_nav1_tuner_fine;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( nav1_tuner_fine < last_nav1_tuner_fine ) {
+                // going up
+                diff = 12 - last_nav1_tuner_fine + nav1_tuner_fine;
+            } else {
+                // going down
+                diff = nav1_tuner_fine - 12 - last_nav1_tuner_fine;
+            }
+        }
+        fine_freq += diff;
+    }
+    while ( fine_freq >= 20.0 ) { fine_freq -= 20.0; }
+    while ( fine_freq < 0.0 )  { fine_freq += 20.0; }
+
+    if ( nav1_tuner_coarse != last_nav1_tuner_coarse ) {
+        diff = nav1_tuner_coarse - last_nav1_tuner_coarse;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( nav1_tuner_coarse < last_nav1_tuner_coarse ) {
+                // going up
+                diff = 12 - last_nav1_tuner_coarse + nav1_tuner_coarse;
+            } else {
+                // going down
+                diff = nav1_tuner_coarse - 12 - last_nav1_tuner_coarse;
+            }
+        }
+        coarse_freq += diff;
     }
+    if ( coarse_freq < 108.0 ) { coarse_freq += 10.0; }
+    if ( coarse_freq > 117.0 ) { coarse_freq -= 10.0; }
+
     last_nav1_tuner_fine = nav1_tuner_fine;
-    last_nav1_tuner_course = nav1_tuner_course;
+    last_nav1_tuner_coarse = nav1_tuner_coarse;
 
-    freq = nav1_stby_freq->getFloatValue() + inc;
-    if ( freq < 108.0 ) {
-       freq = 117.95;
-    }
-    if ( freq > 117.95 ) {
-       freq = 108.0;
-    }
-    fgSetFloat( "/radios/nav[0]/frequencies/standby-mhz", freq );
+    fgSetFloat( "/radios/nav[0]/frequencies/standby-mhz",
+                coarse_freq + fine_freq / 20.0 );
 
     // Nav2 Tuner
-    int nav2_tuner_fine = (radio_switch_data[17] >> 4) & 0x0f;
-    int nav2_tuner_course = radio_switch_data[17] & 0x0f;
+    int nav2_tuner_fine = ((radio_switch_data[17] >> 4) & 0x0f) - 1;
+    int nav2_tuner_coarse = (radio_switch_data[17] & 0x0f) - 1;
     static int last_nav2_tuner_fine = nav2_tuner_fine;
-    static int last_nav2_tuner_course = nav2_tuner_course;
-    inc = 0.0;
+    static int last_nav2_tuner_coarse = nav2_tuner_coarse;
+
+    freq = nav2_stby_freq->getFloatValue();
+    coarse_freq = (int)freq;
+    fine_freq = (int)((freq - coarse_freq) * 20 + 0.5);
+
     if ( nav2_tuner_fine != last_nav2_tuner_fine ) {
-       if ( nav2_tuner_fine == 0x0c && last_nav2_tuner_fine == 0x01 ) {
-           inc = -0.05;
-       } else if ( nav2_tuner_fine == 0x01 && last_nav2_tuner_fine == 0x0c ) {
-           inc = -0.05;
-       } else if ( nav2_tuner_fine > last_nav2_tuner_fine ) {
-           inc = 0.05;
-       } else {
-           inc = -0.05;
-       }
-    }
-    if ( nav2_tuner_course != last_nav2_tuner_course ) {
-       if ( nav2_tuner_course == 0x0c && last_nav2_tuner_course == 0x01 ) {
-           inc = -1.0;
-       } else if ( nav2_tuner_course == 0x01
-                   && last_nav2_tuner_course == 0x0c ) {
-           inc = -1.0;
-       } else if ( nav2_tuner_course > last_nav2_tuner_course ) {
-           inc = 1.0;
-       } else {
-           inc = -1.0;
-       }
+        diff = nav2_tuner_fine - last_nav2_tuner_fine;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( nav2_tuner_fine < last_nav2_tuner_fine ) {
+                // going up
+                diff = 12 - last_nav2_tuner_fine + nav2_tuner_fine;
+            } else {
+                // going down
+                diff = nav2_tuner_fine - 12 - last_nav2_tuner_fine;
+            }
+        }
+        fine_freq += diff;
+    }
+    while ( fine_freq >= 20.0 ) { fine_freq -= 20.0; }
+    while ( fine_freq < 0.0 )  { fine_freq += 20.0; }
+
+    if ( nav2_tuner_coarse != last_nav2_tuner_coarse ) {
+        diff = nav2_tuner_coarse - last_nav2_tuner_coarse;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( nav2_tuner_coarse < last_nav2_tuner_coarse ) {
+                // going up
+                diff = 12 - last_nav2_tuner_coarse + nav2_tuner_coarse;
+            } else {
+                // going down
+                diff = nav2_tuner_coarse - 12 - last_nav2_tuner_coarse;
+            }
+        }
+        coarse_freq += diff;
     }
+    if ( coarse_freq < 108.0 ) { coarse_freq += 10.0; }
+    if ( coarse_freq > 117.0 ) { coarse_freq -= 10.0; }
+
     last_nav2_tuner_fine = nav2_tuner_fine;
-    last_nav2_tuner_course = nav2_tuner_course;
+    last_nav2_tuner_coarse = nav2_tuner_coarse;
 
-    freq = nav2_stby_freq->getFloatValue() + inc;
-    if ( freq < 108.0 ) {
-       freq = 117.95;
-    }
-    if ( freq > 117.95 ) {
-       freq = 108.0;
-    }
-    fgSetFloat( "/radios/nav[1]/frequencies/standby-mhz", freq );
+    fgSetFloat( "/radios/nav[1]/frequencies/standby-mhz", 
+                coarse_freq + fine_freq / 20.0);
 
     // ADF Tuner
-    int adf_tuner_fine = (radio_switch_data[21] >> 4) & 0x0f;
-    int adf_tuner_course = radio_switch_data[21] & 0x0f;
-    // cout << "adf = " << adf_tuner_fine << " " << adf_tuner_course << endl;
+    int adf_tuner_fine = ((radio_switch_data[21] >> 4) & 0x0f) - 1;
+    int adf_tuner_coarse = (radio_switch_data[21] & 0x0f) - 1;
     static int last_adf_tuner_fine = adf_tuner_fine;
-    static int last_adf_tuner_course = adf_tuner_course;
-    inc = 0.0;
+    static int last_adf_tuner_coarse = adf_tuner_coarse;
+
+    if ( adf_count_mode->getIntValue() == 2 ) {
+        // tune count down timer
+        value = adf_elapsed_timer->getDoubleValue();
+    } else {
+        // tune frequency
+        if ( adf_stby_mode->getIntValue() == 1 ) {
+            value = adf_freq->getFloatValue();
+        } else {
+            value = adf_stby_freq->getFloatValue();
+        }
+    }
+
     if ( adf_tuner_fine != last_adf_tuner_fine ) {
-       if ( adf_tuner_fine == 0x0c && last_adf_tuner_fine == 0x01 ) {
-           inc = -1.0;
-       } else if ( adf_tuner_fine == 0x01 && last_adf_tuner_fine == 0x0c ) {
-           inc = -1.0;
-       } else if ( adf_tuner_fine > last_adf_tuner_fine ) {
-           inc = 1.0;
-       } else {
-           inc = -1.0;
-       }
+        diff = adf_tuner_fine - last_adf_tuner_fine;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( adf_tuner_fine < last_adf_tuner_fine ) {
+                // going up
+                diff = 12 - last_adf_tuner_fine + adf_tuner_fine;
+            } else {
+                // going down
+                diff = adf_tuner_fine - 12 - last_adf_tuner_fine;
+            }
+        }
+        value += diff;
+    }
+
+    if ( adf_tuner_coarse != last_adf_tuner_coarse ) {
+        diff = adf_tuner_coarse - last_adf_tuner_coarse;
+        if ( abs(diff) > 4 ) {
+            // roll over
+            if ( adf_tuner_coarse < last_adf_tuner_coarse ) {
+                // going up
+                diff = 12 - last_adf_tuner_coarse + adf_tuner_coarse;
+            } else {
+                // going down
+                diff = adf_tuner_coarse - 12 - last_adf_tuner_coarse;
+            }
+        }
+        if ( adf_count_mode->getIntValue() == 2 ) {
+            value += 60 * diff;
+        } else {
+            value += 25 * diff;
+        }
     }
-    if ( adf_tuner_course != last_adf_tuner_course ) {
-       if ( adf_tuner_course == 0x0c && last_adf_tuner_course == 0x01 ) {
-           inc = -25.0;
-       } else if ( adf_tuner_course == 0x01
-                   && last_adf_tuner_course == 0x0c ) {
-           inc = -25.0;
-       } else if ( adf_tuner_course > last_adf_tuner_course ) {
-           inc = 25.0;
-       } else {
-           inc = -25.0;
-       }
+    if ( adf_count_mode->getIntValue() == 2 ) {
+        if ( value < 0 ) { value += 3600; }
+        if ( value > 3599 ) { value -= 3600; }
+    } else {
+        if ( value < 200 ) { value += 1600; }
+        if ( value > 1799 ) { value -= 1600; }
     }
     last_adf_tuner_fine = adf_tuner_fine;
-    last_adf_tuner_course = adf_tuner_course;
+    last_adf_tuner_coarse = adf_tuner_coarse;
 
-    freq = adf_freq->getFloatValue() + inc;
-    if ( freq < 100.0 ) {
-       freq = 1299;
-    }
-    if ( freq > 1299 ) {
-       freq = 100.0;
+    if ( adf_count_mode->getIntValue() == 2 ) {
+        fgSetFloat( "/radios/kr-87/elapsed-timer", value );
+    } else {
+        if ( adf_stby_mode->getIntValue() == 1 ) {
+            fgSetFloat( "/radios/kr-87/frequencies/selected-khz", value );
+        } else {
+            fgSetFloat( "/radios/kr-87/frequencies/standby-khz", value );
+        }
     }
-    fgSetFloat( "/radios/adf/frequencies/selected-khz", freq );
+
+    // ADF Modes 
+    fgSetInt( "/radios/kr-87/adf-btn", !(radio_switch_data[23] & 0x01) );
+    fgSetInt( "/radios/kr-87/bfo-btn", !(radio_switch_data[23] >> 1 & 0x01) );
+    fgSetInt( "/radios/kr-87/frq-btn", !(radio_switch_data[23] >> 2 & 0x01) );
+    fgSetInt( "/radios/kr-87/flt-et-btn", !(radio_switch_data[23] >> 3 & 0x01) );
+    fgSetInt( "/radios/kr-87/set-rst-btn", !(radio_switch_data[23] >> 4 & 0x01) );
+    /* cout << "adf = " << !(radio_switch_data[23] & 0x01)
+         << " bfo = " << !(radio_switch_data[23] >> 1 & 0x01)
+         << " stby = " << !(radio_switch_data[23] >> 2 & 0x01)
+         << " timer = " << !(radio_switch_data[23] >> 3 & 0x01)
+         << " set/rst = " << !(radio_switch_data[23] >> 4 & 0x01)
+         << endl; */
 
     return true;
 }
@@ -881,29 +1057,87 @@ bool FGATC610x::do_radio_display() {
     // the 0x00 in the upper nibble of the 6th byte of each display
     // turns on the decimal point
 
-    // ADF standby frequency
-    float adf_stby = adf_stby_freq->getFloatValue();
-    if ( fabs(adf_stby) > 999.99 ) {
-       adf_stby = 0.0;
-    }
-    sprintf(digits, "%03.0f", adf_stby);
-    for ( i = 0; i < 6; ++i ) {
-       digits[i] -= '0';
-    }
-    radio_display_data[30] = digits[2] << 4 | 0x0f;
-    radio_display_data[31] = digits[0] << 4 | digits[1];
+    // ADF standby frequency / timer
+    if ( adf_on_off_vol->getDoubleValue() >= 0.01 ) {
+        if ( adf_stby_mode->getIntValue() == 0 ) {
+            // frequency
+            float adf_stby = adf_stby_freq->getFloatValue();
+            if ( fabs(adf_stby) > 1799 ) {
+                adf_stby = 1799;
+            }
+            sprintf(digits, "%04.0f", adf_stby);
+            for ( i = 0; i < 6; ++i ) {
+                digits[i] -= '0';
+            }
+            radio_display_data[30] = digits[3] << 4 | 0x0f;
+            radio_display_data[31] = digits[1] << 4 | digits[2];
+            if ( digits[0] == 0 ) {
+                radio_display_data[32] = 0xff;
+            } else {
+                radio_display_data[32] = 0xf0 | digits[0];
+            }
+        } else {
+            // timer
+            double time;
+            int hours, min, sec;
+            if ( adf_timer_mode->getIntValue() == 0 ) {
+                time = adf_flight_timer->getDoubleValue();
+            } else {
+                time = adf_elapsed_timer->getDoubleValue();
+            }
+            // cout << time << endl;
+            hours = (int)(time / 3600.0);
+            time -= hours * 3600.00;
+            min = (int)(time / 60.0);
+            time -= min * 60.0;
+            sec = (int)time;
+            int big, small;
+            if ( hours > 0 ) {
+                big = hours;
+                if ( big > 99 ) {
+                    big = 99;
+                }
+                small = min;
+            } else {
+                big = min;
+                small = sec;
+            }
+            if ( big > 99 ) {
+                big = 99;
+            }
+            // cout << big << ":" << small << endl;
+            sprintf(digits, "%02d%02d", big, small);
+            for ( i = 0; i < 6; ++i ) {
+                digits[i] -= '0';
+            }
+            radio_display_data[30] = digits[3] << 4 | 0x0f;
+            radio_display_data[31] = digits[1] << 4 | digits[2];
+            radio_display_data[32] = 0xf0 | digits[0];
+        }
 
-    // ADF in use frequency
-    float adf = adf_freq->getFloatValue();
-    if ( fabs(adf) > 999.99 ) {
-       adf = 0.0;
-    }
-    sprintf(digits, "%03.0f", adf);
-    for ( i = 0; i < 6; ++i ) {
-       digits[i] -= '0';
+        // ADF in use frequency
+        float adf = adf_freq->getFloatValue();
+        if ( fabs(adf) > 1799 ) {
+            adf = 1799;
+        }
+        sprintf(digits, "%04.0f", adf);
+        for ( i = 0; i < 6; ++i ) {
+            digits[i] -= '0';
+        }
+        radio_display_data[33] = digits[2] << 4 | digits[3];
+        if ( digits[0] == 0 ) {
+            radio_display_data[34] = 0xf0 | digits[1];
+        } else {
+            radio_display_data[34] = digits[0] << 4 | digits[1];
+        }
+    } else {
+        radio_display_data[30] = 0xff;
+        radio_display_data[31] = 0xff;
+        radio_display_data[32] = 0xff;
+        radio_display_data[33] = 0xff;
+        radio_display_data[34] = 0xff;
     }
-    radio_display_data[33] = digits[1] << 4 | digits[2];
-    radio_display_data[34] = 0xf0 | digits[0];
+    
 
     ATC610xSetRadios( radios_fd, radio_display_data );
 
@@ -972,32 +1206,61 @@ bool FGATC610x::do_switches() {
     update_switch_matrix( board, switch_data, switch_matrix );
 
     // magnetos and starter switch
+    int magnetos = 0;
+    bool starter = false;
     if ( switch_matrix[board][3][1] == 1 ) {
-       fgSetInt( "/controls/magnetos[0]", 3 );
-       fgSetBool( "/controls/starter[0]", true );
+       magnetos = 3;
+       starter = true;
     } else if ( switch_matrix[board][2][1] == 1 ) {
-       fgSetInt( "/controls/magnetos[0]", 3 );
-       fgSetBool( "/controls/starter[0]", false );
+       magnetos = 3;
+       starter = false;
     } else if ( switch_matrix[board][1][1] == 1 ) {
-       fgSetInt( "/controls/magnetos[0]", 2 );
-       fgSetBool( "/controls/starter[0]", false );
+       magnetos = 2;
+       starter = false;
     } else if ( switch_matrix[board][0][1] == 1 ) {
-       fgSetInt( "/controls/magnetos[0]", 1 );
-       fgSetBool( "/controls/starter[0]", false );
+       magnetos = 1;
+       starter = false;
     } else {
-       fgSetInt( "/controls/magnetos[0]", 0 );
-       fgSetBool( "/controls/starter[0]", false );
+       magnetos = 0;
+       starter = false;
     }
 
     // flaps
+    float flaps = 0.0;
     if ( switch_matrix[board][6][3] == 1 ) {
-       fgSetFloat( "/controls/flaps", 1.0 );
+       flaps = 1.0;
     } else if ( switch_matrix[board][5][3] == 1 ) {
-       fgSetFloat( "/controls/flaps", 0.66 );
+       flaps = 2.0 / 3.0;
     } else if ( switch_matrix[board][4][3] == 1 ) {
-       fgSetFloat( "/controls/flaps", 0.33 );
+       flaps = 1.0 / 3.0;
     } else if ( switch_matrix[board][4][3] == 0 ) {
-       fgSetFloat( "/controls/flaps", 0.0 );
+       flaps = 0.0;
+    }
+
+    // do a bit of filtering on the magneto/starter switch and the
+    // flap lever because these are not well debounced in hardware
+    static int mag1, mag2, mag3;
+    mag3 = mag2;
+    mag2 = mag1;
+    mag1 = magnetos;
+    if ( mag1 == mag2 && mag2 == mag3 ) {
+        fgSetInt( "/controls/magnetos[0]", magnetos );
+    }
+
+    static bool start1, start2, start3;
+    start3 = start2;
+    start2 = start1;
+    start1 = starter;
+    if ( start1 == start2 && start2 == start3 ) {
+        fgSetBool( "/controls/starter[0]", starter );
+    }
+
+    static float flap1, flap2, flap3;
+    flap3 = flap2;
+    flap2 = flap1;
+    flap1 = flaps;
+    if ( flap1 == flap2 && flap2 == flap3 ) {
+        fgSetFloat( "/controls/flaps", flaps );
     }
 
     return true;
@@ -1005,11 +1268,17 @@ bool FGATC610x::do_switches() {
 
 
 bool FGATC610x::process() {
+    SGTimeStamp current;
+    current.stamp();
+
+    double dt = (double)(current - last_time_stamp) / 1000000;
+    last_time_stamp.stamp();
 
     // Lock the hardware, skip if it's not ready yet
     if ( ATC610xLock( lock_fd ) > 0 ) {
 
        do_analog_in();
+       do_lights( dt );
        do_radio_switches();
        do_radio_display();
        do_steppers();