Changeset 512

Show
Ignore:
Timestamp:
07/29/07 16:30:54 (14 years ago)
Author:
jwoithe
Message:

MOTU: more tweaks to improve reliability. Things are looking pretty good now.
MOTU: Commenced cleanup of MOTU code, removing temporary debug output etc.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/libffado/src/libstreaming/MotuStreamProcessor.cpp

    r498 r512  
    5656 
    5757uint32_t ts_sec = CYCLE_TIMER_GET_SECS(ct_now); 
    58   // If the cycles have wrapped, correct ts_sec so it represents when timestamp 
    59   // was received.  The timestamps sent by the MOTU are always 1 or two cycles 
    60   // in advance of the cycle timer (reasons unknown at this stage).  In addition, 
    61   // iso buffering can delay the arrival of packets for quite a number of cycles 
    62   // (have seen a delay >12 cycles). 
    63   // Every so often we also see sph wrapping ahead of ct_now, so deal with that 
    64   // too. 
    65   if (CYCLE_TIMER_GET_CYCLES(sph) > now_cycles + 1000) { 
    66 //debugOutput(DEBUG_LEVEL_VERBOSE, "now=%d, ct=%d\n", now_cycles, CYCLE_TIMER_GET_CYCLES(sph)); 
    67     if (ts_sec) 
    68       ts_sec--; 
    69     else 
    70       ts_sec = 127; 
    71   } else 
    72   if (now_cycles > CYCLE_TIMER_GET_CYCLES(sph) + 1000) { 
    73 //debugOutput(DEBUG_LEVEL_VERBOSE, "inverted wrap: now=%d, ct=%d\n", now_cycles, CYCLE_TIMER_GET_CYCLES(sph)); 
    74     if (ts_sec == 127) 
    75       ts_sec = 0; 
    76     else 
    77       ts_sec++; 
    78   } 
    79   return timestamp + ts_sec*TICKS_PER_SECOND; 
     58    // If the cycles have wrapped, correct ts_sec so it represents when timestamp 
     59    // was received.  The timestamps sent by the MOTU are always 1 or two cycles 
     60    // in advance of the cycle timer (reasons unknown at this stage).  In addition, 
     61    // iso buffering can delay the arrival of packets for quite a number of cycles 
     62    // (have seen a delay >12 cycles). 
     63    // Every so often we also see sph wrapping ahead of ct_now, so deal with that 
     64    // too. 
     65    if (CYCLE_TIMER_GET_CYCLES(sph) > now_cycles + 1000) { 
     66        if (ts_sec) 
     67            ts_sec--; 
     68        else 
     69            ts_sec = 127; 
     70    } else 
     71    if (now_cycles > CYCLE_TIMER_GET_CYCLES(sph) + 1000) { 
     72        if (ts_sec == 127) 
     73            ts_sec = 0; 
     74        else 
     75            ts_sec++; 
     76    } 
     77    return timestamp + ts_sec*TICKS_PER_SECOND; 
    8078} 
    8179 
    8280// Convert a full timestamp into an SPH timestamp as required by the MOTU 
    8381static inline uint32_t fullTicksToSph(int64_t timestamp) { 
    84   return TICKS_TO_CYCLE_TIMER(timestamp) & 0x1ffffff; 
     82    return TICKS_TO_CYCLE_TIMER(timestamp) & 0x1ffffff; 
    8583} 
    8684 
     
    9088    : TransmitStreamProcessor(port, framerate), m_event_size(event_size), 
    9189    m_tx_dbc(0), 
    92     m_closedown_count(-1), m_streaming_active(0) { 
     90    m_startup_count(-1), m_closedown_count(-1), m_streaming_active(0) { 
    9391} 
    9492 
     
    191189            // therefore sync_lag_cycles * TICKS_PER_CYCLE earlier than 
    192190            // T1. 
    193             ts_head = addTicks((int64_t)ts_head, sync_lag_cycles * TICKS_PER_CYCLE); 
     191            ts_head = addTicks(ts_head, sync_lag_cycles * TICKS_PER_CYCLE); 
    194192 
    195193// These are just copied from AmdtpStreamProcessor.  At some point we should 
    196194// verify that they make sense for the MOTU. 
    197             ts_head = substractTicks((int64_t)ts_head, TICKS_PER_CYCLE); 
     195            ts_head = substractTicks(ts_head, TICKS_PER_CYCLE); 
    198196            // account for the number of cycles we are too late to enable 
    199             ts_head = addTicks((int64_t)ts_head, cycles_past_enable * TICKS_PER_CYCLE); 
     197            ts_head = addTicks(ts_head, cycles_past_enable * TICKS_PER_CYCLE); 
    200198            // account for one extra packet of frames 
    201             ts_head = substractTicks((int64_t)ts_head, 
    202               (uint32_t)((float)n_events * m_SyncSource->m_data_buffer->getRate()));  
    203  
     199// For the MOTU this subtraction doesn't seem necessary, and in general just makes it take 
     200// longer to achieve stable sync. 
     201//            ts_head = substractTicks(ts_head, 
     202//             (uint32_t)((float)n_events * m_SyncSource->m_data_buffer->getRate()));  
     203//            ts_head = substractTicks(ts_head, 
     204//              (uint32_t)(m_SyncSource->m_data_buffer->getRate()));  
    204205            m_data_buffer->setBufferTailTimestamp(ts_head); 
     206 
     207            // Set up the startup count which keeps the output muted during 
     208            // sync stabilisation at startup.  For now we go for about 2 seconds of 
     209            // muting.  Note that this is a count of *packets*, not frames. 
     210            m_startup_count = 2*m_framerate/n_events; 
    205211 
    206212            #ifdef DEBUG 
     
    212218                            ts_head, sync_lag_cycles, m_data_buffer->getFrameCounter()); 
    213219        } else { 
    214 static int foo=0; 
    215 if (!foo) { 
    216   debugOutput(DEBUG_LEVEL_VERBOSE, 
    217     "will enable tx StreamProcessor %p at %u, now is %d\n", 
    218     this, m_cycle_to_enable_at, cycle); 
    219   foo=1; 
    220 } 
    221220            debugOutput(DEBUG_LEVEL_VERY_VERBOSE, 
    222221                        "will enable StreamProcessor %p at %u, now is %d\n", 
     
    228227                    this, cycle); 
    229228        m_is_disabled=true; 
     229        m_startup_count = -1; 
    230230    } 
    231231 
     
    235235    *tag = 1;      // All MOTU packets have a CIP-like header 
    236236 
    237  
    238237    // the base timestamp is the one of the next sample in the buffer 
    239238    m_data_buffer->getBufferHeadTimestamp(&ts_tmp, &fc); // thread safe 
     
    242241 
    243242//debugOutput(DEBUG_LEVEL_VERBOSE,"tx cycle %d, base timestamp %lld\n",cycle, ts_head); 
    244 #if 0 
    245 if (cycle<10000) { 
    246   debugOutput(DEBUG_LEVEL_VERBOSE,"cycle %d at %3d:%04d:%04d, timestamp=%3d:%04d:%04d (%d)\n", 
    247     cycle, 
    248     CYCLE_TIMER_GET_SECS(ctr), CYCLE_TIMER_GET_CYCLES(ctr), CYCLE_TIMER_GET_OFFSET(ctr), 
    249     TICKS_TO_SECS((uint32_t)timestamp), TICKS_TO_CYCLES((uint32_t)timestamp),TICKS_TO_OFFSET((uint32_t)timestamp),(uint32_t)timestamp); 
    250 
    251 #endif 
     243 
    252244    // we send a packet some cycles in advance, to avoid the 
    253245    // following situation: 
     
    267259 
    268260    // determine the 'now' time in ticks 
    269     uint64_t cycle_timer=CYCLE_TIMER_TO_TICKS(ctr); 
    270  
    271     // time until the packet is to be sent (if > 0: send packet) 
    272 //debugOutput(DEBUG_LEVEL_VERBOSE,"pre: timestamp=%lld, cycle_timer=%lld, adv=%lld, cdiff=%d\n", 
    273 // timestamp, cycle_timer,ticks_to_advance,cycle_diff); 
    274     int32_t until_next=diffTicks(timestamp, cycle_timer + ticks_to_advance); 
    275 //debugOutput(DEBUG_LEVEL_VERBOSE,"post\n"); 
    276  
    277 until_next = (cycle >= TICKS_TO_CYCLES(timestamp))?-1:1; 
     261//    uint64_t cycle_timer=CYCLE_TIMER_TO_TICKS(ctr); 
     262 
     263    // time until the packet is to be sent (if <= 0: send packet) 
     264    // For Amdtp this looked like 
     265    //   int32_t until_next=diffTicks(timestamp, cycle_timer + ticks_to_advance); 
     266    // However, this didn't seem to work well with the MOTU's buffer structure. 
     267    // For now we'll revert to the "send trigger" we used earlier since this 
     268    // seems to work. 
     269    int32_t until_next = (cycle >= TICKS_TO_CYCLES(timestamp))?-1:1; 
    278270 
    279271    // Size of a single data frame in quadlets 
     
    295287        *length = 8; 
    296288 
    297         #warning high-pitched sound protection removed! 
    298         // In the disabled state simply zero all data sent to the MOTU.  If 
    299         // a stream of empty packets are sent once iso streaming is enabled 
    300         // the MOTU tends to emit high-pitched audio (approx 10 kHz) for 
    301         // some reason.  This is not completely sufficient, however (zeroed 
    302         // packets must also be sent on iso closedown). 
    303  
    304         // FIXME: Currently we simply send empty packets to the MOTU when 
    305         // the stream is disabled so the "m_disabled == 0" code is never 
    306         // executed.  However, this may change in future so it's left in 
    307         // for the moment for reference. 
    308         // FIXME: Currently we don't read the buffer at all during closedown. 
    309         // We could (and silently junk the contents) if it turned out to be 
    310         // more helpful. 
    311  
    312 //if (!m_is_disabled && m_running) 
    313 //  return RAW1394_ISO_OK; 
    314 //else 
    315289        return RAW1394_ISO_DEFER; 
    316290    } 
     
    319293    ffado_timestamp_t ts=addTicks(timestamp, TRANSMIT_TRANSFER_DELAY); 
    320294 
    321     if (m_data_buffer->readFrames(n_events, (char *)(data + 8))) { 
    322  
     295    // Only read frames from the tx buffer when we're not in the process of 
     296    // stopping.  When preparing for stop the buffer isn't necessarily being 
     297    // replinished so it's possible to cause a buffer underflow during 
     298    // shutdown if the buffer is read during this time. 
     299    if (m_closedown_count!=-1 || m_data_buffer->readFrames(n_events, (char *)(data + 8))) { 
     300 
     301#if TESTTONE 
     302        // FIXME: remove this hacked in 1 kHz test signal to 
     303        // analog-1 when testing is complete.  Note that the tone is 
     304        // *never* added during closedown. 
     305        if (m_closedown_count<0) { 
     306            for (i=0; i<n_events; i++) { 
     307                static signed int a_cx = 0; 
     308                signed int val; 
     309                val = (int)(0x7fffff*sin(1000.0*2.0*M_PI*(a_cx/24576000.0))); 
     310                if ((a_cx+=512) >= 24576000) { 
     311                    a_cx -= 24576000; 
     312                } 
     313                *(data+8+i*m_event_size+16) = (val >> 16) & 0xff; 
     314                *(data+8+i*m_event_size+17) = (val >> 8) & 0xff; 
     315                *(data+8+i*m_event_size+18) = val & 0xff; 
     316            } 
     317        } 
     318#endif 
    323319        // Increment the dbc (data block count).  This is only done if the 
    324320        // packet will contain events - that is, we are due to send some 
     
    342338        *length = n_events*m_event_size + 8; 
    343339 
    344         // FIXME: if we choose to read the buffer even during closedown, 
    345         // here is where the data is silenced. 
    346         //   if (m_closedown_count >= 0) 
    347         //     memset(data+8, 0, read_size); 
     340        // Zero out data if we're in closedown or startup 
     341        if (m_closedown_count>=0 || m_startup_count>=0) { 
     342            memset(data+8,0,n_events*m_event_size); 
     343        } 
     344 
     345        // Account for this packet's frames during startup / closedown.  Note: 
     346        //  * m_startup_count: -1 = not in startup delay, >-1 = in startup delay. 
     347        //  * m_closedown_count: -1 = not in closedown mode, 0 = closedown 
     348        //    preparation now finished, >0 = closedown preparation in 
     349        //    progress. 
    348350        if (m_closedown_count > 0) 
    349351            m_closedown_count--; 
     352        if (m_startup_count >= 0) 
     353            m_startup_count--; 
    350354 
    351355        // Set up each frames's SPH.  Note that the (int) typecast 
    352356        // appears to do rounding. 
    353357 
    354 float ticks_per_frame = m_SyncSource->m_data_buffer->getRate(); 
    355 //debugOutput(DEBUG_LEVEL_VERBOSE, "ticks per frame=%10.6f\n",ticks_per_frame); 
     358        float ticks_per_frame = m_SyncSource->m_data_buffer->getRate(); 
    356359        for (i=0; i<n_events; i++, quadlet += dbs) { 
    357360//FIXME: not sure which is best for the MOTU 
     
    359362            int64_t ts_frame = addTicks(timestamp, (unsigned int)(i * ticks_per_frame)); 
    360363            *quadlet = htonl(fullTicksToSph(ts_frame)); 
    361 #if 0 
    362 if (i==0) { 
    363   debugOutput(DEBUG_LEVEL_VERBOSE,"  ts_frame=%8x (%3d:%04d:%04d)\n",ts_frame, 
    364     TICKS_TO_SECS(ts_frame), TICKS_TO_CYCLES(ts_frame), TICKS_TO_OFFSET(ts_frame)); 
    365 } 
    366 #endif 
    367 #if 0 
    368 if (cycle<2) { 
    369   debugOutput(DEBUG_LEVEL_VERBOSE,"cycle %d: %d %d %d\n", 
    370     cycle, 
    371     TICKS_TO_SECS(ts_frame), 
    372     TICKS_TO_CYCLES(ts_frame), 
    373     TICKS_TO_OFFSET(ts_frame)); 
    374 } 
    375 #endif 
    376 #if TESTTONE 
    377             // FIXME: remove this hacked in 1 kHz test signal to 
    378             // analog-1 when testing is complete.  Note that the tone is 
    379             // *never* added during closedown. 
    380             if (m_closedown_count<0) { 
    381                 static signed int a_cx = 0; 
    382                 signed int val; 
    383                 val = (int)(0x7fffff*sin(1000.0*2.0*M_PI*(a_cx/24576000.0))); 
    384                  if ((a_cx+=512) >= 24576000) { 
    385                     a_cx -= 24576000; 
    386                 } 
    387                 *(data+8+i*m_event_size+16) = (val >> 16) & 0xff; 
    388                 *(data+8+i*m_event_size+17) = (val >> 8) & 0xff; 
    389                 *(data+8+i*m_event_size+18) = val & 0xff; 
    390             } 
    391 #endif 
    392  
    393364        } 
    394365 
     
    414385    } else { // there is no more data in the ringbuffer 
    415386 
    416 // FIXME: port to new timestamp type 
    417 //        debugWarning("Transmit buffer underrun (now %d, queue %d, target %d)\n", 
    418 //                 now_cycles, cycle, TICKS_TO_CYCLES(ts)); 
     387        debugWarning("Transmit buffer underrun (now %d, queue %d, target %d)\n", 
     388                 now_cycles, cycle, TICKS_TO_CYCLES((int64_t)ts)); 
    419389 
    420390        // signal underrun 
     
    1014984} 
    1015985 
    1016     // NOTE by PP: timestamp based sync fixes this automagically by 
    1017     //             enforcing that the roundtrip latency is constant: 
    1018     // Detect missed receive cycles 
    1019     // FIXME: it would be nice to advance the rx buffer by the amount of 
    1020     // frames missed.  However, since the MOTU transmits more frames per 
    1021     // cycle than the average and "catches up" with periodic empty 
    1022     // cycles it's not trivial to work out precisely how many frames 
    1023     // were missed.  Ultimately I think we need to do so if sync is to 
    1024     // be maintained across a transient receive failure. 
    1025  
    1026986enum raw1394_iso_disposition 
    1027987MotuReceiveStreamProcessor::putPacket(unsigned char *data, unsigned int length, 
     
    1034994    m_last_cycle=cycle; 
    1035995 
    1036 //debugOutput(DEBUG_LEVEL_VERBOSE,"rx: enabled=%d, cycle=%d\n",!m_is_disabled,cycle); 
    1037  
    1038996    // check our enable status 
    1039997    if (!m_disabled && m_is_disabled) { 
     
    10511009            // because we're going to update the buffer again this loop 
    10521010            // using writeframes 
    1053 //            m_data_buffer->setBufferTailTimestamp(m_last_timestamp2); 
    10541011            m_data_buffer->setBufferTailTimestamp(m_last_timestamp); 
    10551012 
     
    10591016 
    10601017        } else { 
    1061 static int foo=0; 
    1062 if (!foo) { 
    1063 debugOutput(DEBUG_LEVEL_VERBOSE, 
    1064   "will enable rx StreamProcessor %p at %u, now is %d\n", 
    1065   this, m_cycle_to_enable_at, cycle); 
    1066   foo=1; 
    1067 } 
    10681018            debugOutput(DEBUG_LEVEL_VERY_VERBOSE, 
    10691019                "will enable StreamProcessor %p at %u, now is %d\n", 
     
    11021052        m_last_timestamp2=m_last_timestamp; 
    11031053 
    1104         //=> convert the SYT to a full timestamp in ticks 
    1105 //        m_last_timestamp=sytRecvToFullTicks((uint32_t)ntohl(*(quadlet_t *)(data+8)), 
    1106 //                                        cycle, m_handler->getCycleTimer()); 
    1107 //*** 
    1108 // FIXME: it given that we later advance this to be the timestamp of the sample immediately following 
    1109 // this packet, it perhaps makes more sense to acquire the timestamp of the last frame in the packet. 
    1110 // Then it's just a matter of adding m_ticks_per_frame rather than frame_size times this. 
    1111 #if 0 
    1112 uint32_t first_sph = ntohl(*(quadlet_t *)(data+8)); 
    1113 //uint32_t first_sph = ntohl(*(quadlet_t *)(data+8+(event_length*(n_events-1)))); 
    1114 //        m_last_timestamp = ((first_sph & 0x1fff000)>>12)*3072 + (first_sph & 0xfff); 
    1115 //        m_last_timestamp = CYCLE_TIMER_TO_TICKS(first_sph & 0x1ffffff); 
    1116 m_last_timestamp = sphRecvToFullTicks(first_sph, m_handler->getCycleTimer()); 
    1117 float frame_size=m_framerate<=48000?8:(m_framerate<=96000?16:32); 
    1118 uint64_t ts=addTicks(m_last_timestamp, (uint64_t)((frame_size-1) * m_ticks_per_frame)); 
    1119 m_last_timestamp = ts; 
    1120 #endif 
    1121  
    1122 #if 1 
    1123 uint32_t last_sph = ntohl(*(quadlet_t *)(data+8+(n_events-1)*event_length)); 
    1124 m_last_timestamp = sphRecvToFullTicks(last_sph, m_handler->getCycleTimer()); 
    1125 #endif 
    1126 //debugOutput(DEBUG_LEVEL_VERBOSE,"ave ticks=%g\n",(m_last_timestamp-m_last_timestamp2)/8.0); 
     1054        // Acquire the timestamp of the last frame in the packet just 
     1055        // received.  Since every frame from the MOTU has its own timestamp 
     1056        // we can just pick it straight from the packet. 
     1057        uint32_t last_sph = ntohl(*(quadlet_t *)(data+8+(n_events-1)*event_length)); 
     1058        m_last_timestamp = sphRecvToFullTicks(last_sph, m_handler->getCycleTimer()); 
    11271059                                                          
    11281060        // Signal that we're running 
     
    11401072            // be ready earlier than this timestamp + period time 
    11411073 
    1142             // the next (possible) sample is not this one, but lies 
    1143             // SYT_INTERVAL * rate later 
    1144             float frames_per_packet=m_framerate<=48000?8:(m_framerate<=96000?16:32); 
    1145             uint64_t ts=addTicks(m_last_timestamp, 
    1146                                  (uint64_t)(frames_per_packet * m_ticks_per_frame)); 
    1147 //            uint64_t ts=addTicks(m_last_timestamp, 
    1148 //                                 (uint64_t)(m_ticks_per_frame)); 
    1149  
    1150             // set the timestamp as if there will be a sample put into 
    1151             // the buffer by the next packet.  This means we use the timestamp 
    1152             // corresponding to the last frame which would have been added to the 
    1153             // buffer this cycle if we weren't disabled. 
    1154             // 
    1155             // FIXME: in theory m_last_timestamp is already equal to the 
    1156             // timestamp of the last frame/sample in this packet since 
    1157             // that's what we used to set it in the first place.  However, 
    1158             // if m_last_timestamp is used to set the buffer tail we get a 
    1159             // series of "difference too large" warnings during the early 
    1160             // stages after enabling.  These tend to indicate that the 
    1161             // buffer timestamp is one packet out.  Using ts (which predicts 
    1162             // the timestamp of the last frame of the *next* packet) seems 
    1163             // to stop these warnings most of the time and allow for a 
    1164             // smoother startup. 
    1165             // On second thoughts, perhaps it doesn't help much after all. 
    1166 //            m_data_buffer->setBufferTailTimestamp(ts); 
     1074            // Set the timestamp as if a sample was put into the buffer by 
     1075            // this present packet.  This means we use the timestamp 
     1076            // corresponding to the last frame which would have been added 
     1077            // to the buffer this cycle if we weren't disabled - that is, 
     1078            // m_last_timestamp. 
    11671079            m_data_buffer->setBufferTailTimestamp(m_last_timestamp); 
    1168 //debugOutput(DEBUG_LEVEL_VERBOSE,"%p, last ts=%lld, ts=%lld, lts2=%lld\n", m_data_buffer, m_last_timestamp, ts, m_last_timestamp2); 
    11691080 
    11701081            return RAW1394_ISO_DEFER; 
  • trunk/libffado/src/libstreaming/MotuStreamProcessor.h

    r494 r512  
    8484    // Keep track of transmission data block count 
    8585    unsigned int m_tx_dbc; 
     86 
     87    // Used to zero output data during startup while sync is established 
     88    signed int m_startup_count; 
    8689 
    8790    // Used to keep track of the close-down zeroing of output data 
  • trunk/libffado/src/libstreaming/StreamProcessorManager.cpp

    r494 r512  
    780780 
    781781    while(time_till_next_period > 0) { 
    782         debugOutput( DEBUG_LEVEL_VERBOSE, "waiting for %d usecs...\n", time_till_next_period); 
     782        debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "waiting for %d usecs...\n", time_till_next_period); 
    783783 
    784784        // wait for the period 
  • trunk/libffado/src/libutil/TimestampedBuffer.cpp

    r498 r512  
    210210    pthread_mutex_lock(&m_framecounter_lock); 
    211211    m_buffer_tail_timestamp = m_buffer_tail_timestamp - m_tick_offset + nticks; 
    212     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((float)m_buffer_tail_timestamp + m_dll_e2); 
     212    m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2); 
    213213    m_tick_offset=nticks; 
    214214    pthread_mutex_unlock(&m_framecounter_lock); 
     
    655655    m_buffer_tail_timestamp = ts; 
    656656 
    657     m_dll_e2=m_update_period * m_nominal_rate; 
    658     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((float)m_buffer_tail_timestamp + m_dll_e2); 
     657    m_dll_e2=m_update_period * (double)m_nominal_rate; 
     658    m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2); 
    659659 
    660660    pthread_mutex_unlock(&m_framecounter_lock); 
     
    702702    m_buffer_tail_timestamp = ts; 
    703703 
    704     m_dll_e2=m_update_period * m_nominal_rate; 
    705     m_buffer_next_tail_timestamp = (ffado_timestamp_t)((float)m_buffer_tail_timestamp + m_dll_e2); 
     704    m_dll_e2=m_update_period * (double)m_nominal_rate; 
     705    m_buffer_next_tail_timestamp = (ffado_timestamp_t)((double)m_buffer_tail_timestamp + m_dll_e2); 
    706706 
    707707    pthread_mutex_unlock(&m_framecounter_lock); 
  • trunk/libffado/src/libutil/TimestampedBuffer.h

    r498 r512  
    186186 
    187187    // tracking DLL variables 
    188     float m_dll_e2; 
     188// JMW: try double for this too 
     189//    float m_dll_e2; 
     190    double m_dll_e2; 
    189191    float m_dll_b; 
    190192    float m_dll_c;