This is a test of the ability to publish code

Dependencies:   mbed SpiFlash25 mtsas

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 
00003 #include "SystemTimeKeeper.h"
00004 #include "RadioManager.h"
00005 #include "StealthPowerSampler.h"
00006 #include "Logo.h"
00007 #include "SampleBacklog.h"
00008 #include "StatusUpdateBacklog.h"
00009 #include "PICManager.h"
00010 #include "RadarSocketManager.h"
00011 #include "SecondTimer.h"
00012 #include "SystemSerialNumber.h"
00013 #include "StatusUpdateManager.h"
00014 #include "SettingsManager.h"
00015 #include "WatchdogManager.h"
00016 
00017 #define HOSTNAME_LENGTH 128
00018 
00019 // This line controls the regulator's battery charger.
00020 // BC_NCE = 0 enables the battery charger
00021 // BC_NCE = 1 disables the battery charger
00022 DigitalOut bc_nce(PB_2);
00023 
00024 // Declare all the firmware subcomponents/objects globally here
00025 SpiFlash25 flash(SPI_MOSI, SPI_MISO, SPI_SCK, SPI_CS1);
00026 SettingsManager settingsManager(flash);
00027 Ticker picTicker;
00028 RadioManager radioManager;
00029 SystemTimeKeeper systemTime;
00030 Serial dbg(USBTX, USBRX);
00031 Ticker main1HzTicker;
00032 StealthPowerSampler intervalSampler;
00033 StealthPowerSampler eventSampler;
00034 StatusUpdateManager updateManager;
00035 SampleBacklog sampleBacklog;
00036 StatusUpdateBacklog statusUpdateBacklog;
00037 RadarSocketManager radarSocketManager(radioManager);
00038 PICManager picManager(&intervalSampler, &eventSampler, &sampleBacklog);
00039 SecondTimer timeSinceSettingsCheck;
00040 
00041 
00042 void picUpdateServiceCallback()
00043 {
00044     picManager.servicePIC();
00045     updateManager.service(statusUpdateBacklog);
00046 }
00047 
00048 
00049 void main1HzCallback()
00050 {
00051     // This gets called exactly once a second and is where we take data samples.
00052     // NOTE: We are in a Ticker callback (ISR) Context, so BE CAREFUL!
00053     systemTime.advance();
00054 
00055     int64_t now = systemTime.uptime();
00056     
00057     // Make sure all samplers know the range of time they've measured even if
00058     // we don't have data for them
00059     intervalSampler.sampleTime(now);
00060     eventSampler.sampleTime(now);
00061     
00062     if (intervalSampler.intervalIsComplete())
00063     {
00064         printf("Interval sample rollover.\r\n");
00065         
00066         if (intervalSampler.isWorthSending())
00067         {
00068             StealthPowerSample sample;
00069             intervalSampler.populateSample(sample);
00070             sample.m_trigger = StealthPowerSample::TriggerInterval;
00071             sampleBacklog.push(sample);
00072         }
00073         intervalSampler.reset(now);
00074     }
00075 }
00076 
00077 
00078 const int64_t MinimumValidTime = 1459007487; // 3/26/2016.
00079 
00080 void synchronizeTimeToCellular()
00081 {
00082     // Query the radio for the exact wall time
00083     int64_t currentRadioTime = radioManager.getTime();
00084 
00085     // If we got a valid time (after 3/26/2016, and not -1 (error))
00086     if (currentRadioTime >= MinimumValidTime && currentRadioTime != -1) {
00087         __disable_irq();
00088         int delta = abs(systemTime.walltime() - currentRadioTime);
00089         // Because the phase of the update Ticker is unaligned with this update,
00090         // leave 1s of slack between the two and only update the system
00091         // time if they get more than 1s apart.
00092         if (delta > 1) {
00093             printf("Resynchronized to wall time = %lld\r\n", currentRadioTime);
00094             systemTime.setWalltime(currentRadioTime);
00095         }
00096         __enable_irq();
00097     }
00098 }
00099 
00100 bool flushQueuesToAPI()
00101 {
00102     // Push all the explicit status-update events
00103     int sentItemsCount = 0;
00104     radar_result_t result = RADAR_OK;
00105     StealthPowerStatusUpdate update;
00106     __disable_irq();
00107     while (statusUpdateBacklog.peek(update) && update.m_atTimestamp >= MinimumValidTime) {
00108         __enable_irq();
00109         result = Radar_PublishStatus(
00110                      (time_t)update.m_atTimestamp,
00111                      update.m_picState,
00112                      update.m_picK,
00113                      update.m_batteryState,
00114                      update.m_error,
00115                      update.m_message.c_str(),
00116                      update.m_Vsp,
00117                      update.m_Voem,
00118                      update.m_V3,
00119                      update.m_V4,
00120                      update.m_A1,
00121                      update.m_A2,
00122                      update.m_temperature);
00123 
00124         __disable_irq();
00125         if (result == RADAR_OK) {
00126             // Only once it's transmitted do we remove it from queue.
00127             statusUpdateBacklog.shift_if(update);
00128             ++sentItemsCount;
00129         }
00130         if (result != RADAR_OK) {
00131             __enable_irq();
00132             return false;
00133         }
00134     }
00135     __enable_irq();
00136     if (sentItemsCount > 0) printf("Transmitted %d event(s).\r\n", sentItemsCount);
00137 
00138     // And the interval/trigger samples:
00139     sentItemsCount = 0;
00140     StealthPowerSample sample;
00141     __disable_irq();
00142     while (sampleBacklog.peek(sample) && sample.m_beginTimestamp >= MinimumValidTime) {
00143         __enable_irq();
00144         
00145         int triggerType = RADAR_TRIGGER_INTERVAL;
00146         if (sample.m_trigger == StealthPowerSample::TriggerDischarge) triggerType = RADAR_TRIGGER_BATTERY_DISCHARGE;
00147         if (sample.m_trigger == StealthPowerSample::TriggerCharge) triggerType = RADAR_TRIGGER_BATTERY_CHARGE;
00148         
00149         printf("SENDING SAMPLE, sample.m_Vsp is %f\r\n", sample.m_Vsp);
00150         result = Radar_PublishSample(
00151                      triggerType,
00152                      (time_t)sample.m_beginTimestamp,
00153                      (time_t)sample.m_endTimestamp,
00154                      sample.m_Vsp * 1000.0F,
00155                      sample.m_Vsp_min * 1000.0F,
00156                      sample.m_Vsp_max * 1000.0F,
00157                      sample.m_Voem * 1000.0F,
00158                      sample.m_Voem_min * 1000.0F,
00159                      sample.m_Voem_max * 1000.0F,
00160                      sample.m_V3 * 1000.0F,
00161                      sample.m_V3_min * 1000.0F,
00162                      sample.m_V3_max * 1000.0F,
00163                      sample.m_V4 * 1000.0F,
00164                      sample.m_V4_min * 1000.0F,
00165                      sample.m_V4_max * 1000.0F,
00166                      sample.m_A1 * 1000.0F,
00167                      sample.m_A1_min * 1000.0F,
00168                      sample.m_A1_max * 1000.0F,
00169                      sample.m_A2 * 1000.0F,
00170                      sample.m_A2_min * 1000.0F,
00171                      sample.m_A2_max * 1000.0F,
00172                      sample.m_temperatureAvg * 1000.0F,
00173                      sample.m_temperatureMin * 1000.0F,
00174                      sample.m_temperatureMax * 1000.0F,
00175                      sample.m_sampleCount,
00176                      sample.m_dischargeCount,
00177                      sample.m_chargeCount);
00178         __disable_irq();
00179         if (result == RADAR_OK) {
00180             // Only once it's transmitted do we remove it from queue.
00181             sampleBacklog.shift_if(sample);
00182             ++sentItemsCount;
00183         }
00184         if (result != RADAR_OK) {
00185             __enable_irq();
00186             return false;
00187         }
00188     }
00189     __enable_irq();
00190     if (sentItemsCount > 0) printf("Transmitted %d sample(s).\r\n", sentItemsCount);
00191 
00192     return true;
00193 }
00194 
00195 
00196 bool applySettingsToSubsystems()
00197 {
00198     // Copy the settings from the settings manager into all the subystems that
00199     // should be affected by them.  This should be invoked after every 
00200     // GetTelemetrySettings() call, or whenever any settings are changed or
00201     // loaded (e.g. at boot).
00202     bool success = true;
00203 
00204     success = success && radarSocketManager.setServers(
00205         settingsManager.getHost1(),
00206         settingsManager.getPort1(),
00207         settingsManager.getHost2(),
00208         settingsManager.getPort2());
00209     
00210     success = success && intervalSampler.setSampleInterval(
00211         settingsManager.getSampleIntervalInSeconds());
00212 
00213     success = success && picManager.setThresholds(
00214         settingsManager.getDischargeThreshold(),
00215         settingsManager.getChargeThreshold(),
00216         settingsManager.getCurrentHysteresis(),
00217         settingsManager.getUseFilteredA1ForBatteryState(),
00218         settingsManager.getMinimumEventSampleDuration());
00219 
00220     success = success && updateManager.setSettings(
00221         settingsManager.getStatusUpdateEvictionTime(),
00222         settingsManager.getVoltageFilterLengthInSamples(),
00223         settingsManager.getVspUpdateThreshold(),
00224         settingsManager.getVspJumpThreshold(),
00225         settingsManager.getVoemUpdateThreshold(),
00226         settingsManager.getVoemJumpThreshold(),
00227         settingsManager.getV3UpdateThreshold(),
00228         settingsManager.getV3JumpThreshold(),
00229         settingsManager.getV4UpdateThreshold(),
00230         settingsManager.getV4JumpThreshold(),
00231         settingsManager.getCurrentFilterLengthInSamples(),
00232         settingsManager.getA1UpdateThreshold(),
00233         settingsManager.getA1JumpThreshold(),
00234         settingsManager.getA2UpdateThreshold(),
00235         settingsManager.getA2JumpThreshold(),
00236         settingsManager.getTemperatureFilterLengthInSamples(),
00237         settingsManager.getTemperatureUpdateThreshold(),
00238         settingsManager.getTemperatureJumpThreshold());
00239 
00240     // No need to do anything for settingsCheckInterval--settingsManager
00241     // is the final recipient of that information already.
00242 
00243     return success;
00244 }
00245 
00246 
00247 bool updateSettingsFromServer()
00248 {
00249     int32_t dischargeThreshold = 0;
00250     int32_t chargeThreshold = 0;
00251     int32_t currentHysteresis = 0;
00252     int32_t regularSampleInterval = -1;
00253     int32_t settingsCheckInterval = -1;
00254     hostname_t primaryHost = "";
00255     uint32_t primaryPort = 0;
00256     hostname_t secondaryHost = "";
00257     uint32_t secondaryPort = 0;
00258     uint32_t statusUpdateEvictionTime = 0;
00259     uint32_t voltageFilterLengthInSamples = 0;
00260     int32_t vspUpdateThreshold = 0;
00261     int32_t vspJumpThreshold = 0;
00262     int32_t voemUpdateThreshold = 0;
00263     int32_t voemJumpThreshold = 0;
00264     int32_t v3UpdateThreshold = 0;
00265     int32_t v3JumpThreshold = 0;
00266     int32_t v4UpdateThreshold = 0;
00267     int32_t v4JumpThreshold = 0;
00268     uint32_t currentFilterLengthInSamples = 0;
00269     int32_t a1UpdateThreshold = 0;
00270     int32_t a1JumpThreshold = 0;
00271     int32_t a2UpdateThreshold = 0;
00272     int32_t a2JumpThreshold = 0;
00273     uint32_t temperatureFilterLengthInSamples = 0;
00274     int32_t temperatureUpdateThreshold = 0;
00275     int32_t temperatureJumpThreshold = 0;
00276     int32_t useFilteredA1ForBatteryState = 0;
00277     int32_t minimumEventSampleDuration = 0;
00278     
00279 
00280     radar_result_t result = Radar_GetTelemetrySettings(
00281         &dischargeThreshold,
00282         &chargeThreshold,
00283         &currentHysteresis,
00284         &regularSampleInterval,
00285         &settingsCheckInterval,
00286         primaryHost,
00287         &primaryPort,
00288         secondaryHost,
00289         &secondaryPort,
00290         &statusUpdateEvictionTime,
00291         &voltageFilterLengthInSamples,
00292         &vspUpdateThreshold,
00293         &vspJumpThreshold,
00294         &voemUpdateThreshold,
00295         &voemJumpThreshold,
00296         &v3UpdateThreshold,
00297         &v3JumpThreshold,
00298         &v4UpdateThreshold,
00299         &v4JumpThreshold,
00300         &currentFilterLengthInSamples,
00301         &a1UpdateThreshold,
00302         &a1JumpThreshold,
00303         &a2UpdateThreshold,
00304         &a2JumpThreshold,
00305         &temperatureFilterLengthInSamples,
00306         &temperatureUpdateThreshold,
00307         &temperatureJumpThreshold,
00308         &useFilteredA1ForBatteryState,
00309         &minimumEventSampleDuration);
00310 
00311     printf("Radar_GetTelemetrySettings result = %d\r\n", result); // TODO: Cleanup
00312     if (result == RADAR_OK)
00313     {
00314         printf("Retrieved latest settings.\r\n");
00315         settingsManager.setAll(
00316             primaryHost,
00317             primaryPort,
00318             secondaryHost,
00319             secondaryPort,
00320             dischargeThreshold,
00321             chargeThreshold,
00322             currentHysteresis,
00323             regularSampleInterval,
00324             settingsCheckInterval,
00325             statusUpdateEvictionTime,
00326             voltageFilterLengthInSamples,
00327             vspUpdateThreshold,
00328             vspJumpThreshold,
00329             voemUpdateThreshold,
00330             voemJumpThreshold,
00331             v3UpdateThreshold,
00332             v3JumpThreshold,
00333             v4UpdateThreshold,
00334             v4JumpThreshold,
00335             currentFilterLengthInSamples,
00336             a1UpdateThreshold,
00337             a1JumpThreshold,
00338             a2UpdateThreshold,
00339             a2JumpThreshold,
00340             temperatureFilterLengthInSamples,
00341             temperatureUpdateThreshold,
00342             temperatureJumpThreshold,
00343             useFilteredA1ForBatteryState,
00344             minimumEventSampleDuration);
00345 
00346         printf("Latest Settings:\r\n");
00347         settingsManager.printSettings();
00348 
00349         return applySettingsToSubsystems();
00350     }
00351     else
00352     {
00353         printf("FAILED to retrieve settings!\r\n");
00354     }
00355     return false;
00356 }
00357 
00358 
00359 
00360 int main()
00361 {
00362     // Initial boot delay fixes issue with occasional loss of first lines of
00363     // console output.
00364     wait_ms(1000);
00365     
00366     // All the demos do this to disable the (modem) battery charger.
00367     bc_nce = 1;
00368 
00369     // Radio state management
00370     bool isRadioConnected = false;
00371     bool isCommunicationConnected = false;
00372     bool haveReasonToContactServer = false;
00373     bool everGotSettingsFromServer = false;
00374 
00375     // For debugging:
00376     //mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL);
00377     
00378     // For normal use:
00379     mts::MTSLog::setLogLevel(mts::MTSLog::WARNING_LEVEL);
00380 
00381     //*********************************
00382     dbg.baud(115200);
00383     printf("Initializing Serial Console - OK\r\n"); fflush(stdout);
00384     printStealthPowerLogo();
00385     
00386     //*********************************
00387     printf("Initializing System Watchdog Timer - OK\r\n"); fflush(stdout);
00388     WatchdogManager::Initialize();
00389 
00390     //*********************************
00391     printf("Initializing Serial Number: "); fflush(stdout);
00392     printf("%s", getSystemSerialNumber());
00393     printf(" - OK\r\n");
00394 
00395     //*********************************
00396     printf("Initializing Settings: "); fflush(stdout);
00397     settingsManager.initializeSettings();
00398     printf("- OK\r\n");
00399     settingsManager.printSettings();
00400     
00401     //*********************************
00402     printf("Applying Settings: "); fflush(stdout);
00403     if (applySettingsToSubsystems())
00404     {
00405         printf("- OK\r\n");
00406     }
00407     else
00408     {
00409         printf("- ERROR\r\n");   
00410     }
00411 
00412     //*********************************
00413     printf("Initializing Real Time Clock"); fflush(stdout);
00414     systemTime.reset();
00415     printf(" - OK\r\n");
00416     
00417     //*********************************
00418     printf("Initializing Sample Engine"); fflush(stdout);
00419     intervalSampler.reset(systemTime.uptime());
00420     eventSampler.reset(systemTime.uptime());
00421     main1HzTicker.attach(main1HzCallback, 1.0);
00422     printf(" - OK\r\n");
00423 
00424     //*********************************
00425     printf("Initializing PIC Communications"); fflush(stdout);
00426     
00427     if (picManager.initialize())
00428         printf(" - OK\r\n");
00429     else
00430         printf(" - FAILED (will keep trying)\r\n");
00431     // Service the PIC uart rapidly--most of the time there won't be anything to do.
00432     picTicker.attach(picUpdateServiceCallback, 0.1);
00433    
00434     //*********************************
00435     // Radio Init is last, because it may block if no signal; don't want to hold off
00436     // sampling engine on a blocking radio call
00437     printf("Initializing Radio"); fflush(stdout);
00438     //wait_us(50);
00439     radioManager.initialize();
00440     radioManager.connect();
00441     if (radioManager.hasEverConnected())
00442         printf(" - OK\r\n");
00443     else
00444         printf(" - FAILED (but will keep trying)\r\n");
00445 
00446     //*********************************
00447     printf("Entering Main Loop\r\n");
00448     while(1)
00449     {
00450         // ---------------------------------------------------------------------------------------------
00451         // (0) Feed the pseudo-hardware watchdog ticker loop
00452         WatchdogManager::Feed();
00453         
00454         // ---------------------------------------------------------------------------------------------
00455         // (1) Make sure the radio is connected if it possibly can be.  (Not necessarily the socket.)
00456         isRadioConnected = false;
00457 
00458         // If connected, ensure time-sync to cellular network wall time.
00459         if (radioManager.isConnected()) {
00460             isRadioConnected = true;
00461             synchronizeTimeToCellular();
00462         }
00463         else
00464         {
00465             printf("Connecting radio\r\n");
00466             isRadioConnected = radioManager.connect();
00467             if (isRadioConnected)
00468             {
00469                 printf("Radio connected.\r\n");
00470             }
00471             else
00472             {
00473                 printf("Radio failed to connect.\r\n");
00474             }
00475         }
00476 
00477         // ---------------------------------------------------------------------------------------------
00478         // (2) Then, make sure that if we have a valid wall-time, all samples that were timestamped
00479         //     with system uptime are translated to wall-time.
00480         if (systemTime.hasWalltime())
00481         {
00482             __disable_irq();
00483             sampleBacklog.retroactivelyTimestampSamples(systemTime.uptime(), systemTime.walltimeDelta());
00484             statusUpdateBacklog.retroactivelyTimestampSamples(systemTime.uptime(), systemTime.walltimeDelta());
00485             __enable_irq();
00486         }
00487 
00488         // ---------------------------------------------------------------------------------------------
00489         // (3) Determine if there's a pressing need to contact the server right now--if not, don't waste
00490         //     bandwidth connecting and hello'ing a socket we don't have anything to say on.
00491         haveReasonToContactServer = (sampleBacklog.backlog() > 0) ||
00492                                    (statusUpdateBacklog.backlog() > 0) ||
00493                                    (timeSinceSettingsCheck.read() >= settingsManager.getSettingsUpdateIntervalInSeconds()) ||
00494                                    (!everGotSettingsFromServer);
00495 
00496         // ---------------------------------------------------------------------------------------------
00497         // (4) Make sure we're connected via TCP to the server if we can be, and need to be, assuming the
00498         //     radio is successfully connected.
00499         if (haveReasonToContactServer)
00500         {
00501             // First, if there's any reason to try connecting, that's a reason to start the radio watchdog.
00502             // This basically means "I better have some luck with the radio/server within X amount of time
00503             // or we'll hard reboot the radio."
00504             radioManager.resumeWatchdog();
00505             
00506             isCommunicationConnected = false;
00507             if (isRadioConnected)
00508             {
00509                 if (!radarSocketManager.isConnected())
00510                 {
00511                     printf("Connecting Stealth Radar API TCP socket\r\n");
00512                     if (radarSocketManager.connect()) { //(re-)connect to configured server
00513                         printf("Connected socket; sending Hello()\r\n");
00514                         radar_result_t result = Radar_Hello(
00515                                                     0x00010000,  // build 01.0.0
00516                                                     (time_t)systemTime.uptime(), // useful for detecting reboots
00517                                                     (time_t)systemTime.walltime(),
00518                                                     getSystemSerialNumber());
00519                         if (result != RADAR_OK)
00520                         {
00521                             printf("Error from Radar_Hello, shutting down socket.\r\n");
00522                             radarSocketManager.disconnect();
00523                             isCommunicationConnected = false;
00524                         }
00525                         else
00526                         {
00527                             printf("Connected Stealth Radar API TCP socket.\r\n");
00528                             isCommunicationConnected = true;
00529                         }
00530                     }
00531                     else
00532                     {
00533                         printf("Failed to connect Stealth Radar API TCP socket!\r\n");
00534                         radarSocketManager.disconnect();
00535                         isCommunicationConnected = false; // just being explicit about this
00536                     }
00537                 }
00538                 else
00539                 {
00540                     isCommunicationConnected = true;
00541                 }
00542             }
00543             else
00544             {
00545                 printf("Radar socket not connected because radio not connected.\r\n");
00546                 // Radio not connected
00547                 radarSocketManager.disconnect();
00548                 isCommunicationConnected = false;
00549             }
00550         }
00551 
00552         // ---------------------------------------------------------------------------------------------
00553         // (5) If the communication socket is established, dump as much queued data ASAP to the
00554         //     server as possible
00555         if (isCommunicationConnected)
00556         {
00557             if (!flushQueuesToAPI())
00558             {
00559                 printf("Problem transmitting sample/status updates to the server; destroying Radar API TCP Socket.\r\n");
00560                 radarSocketManager.disconnect();
00561                 isCommunicationConnected = false;
00562             }
00563             
00564             // Always get settings at the beginning of a connection
00565             if (timeSinceSettingsCheck.read() >= settingsManager.getSettingsUpdateIntervalInSeconds() || !everGotSettingsFromServer)
00566             {
00567                 if (updateSettingsFromServer())
00568                 {
00569                     // Reset the timer that watches how long it's been since we've asked for settings
00570                     timeSinceSettingsCheck.stop();
00571                     timeSinceSettingsCheck.reset();
00572                     timeSinceSettingsCheck.start();
00573                     everGotSettingsFromServer = true;
00574                 }
00575                 else
00576                 {
00577                     printf("Problem getting settings from the server.\r\n");
00578                     radarSocketManager.disconnect();
00579                     isCommunicationConnected = false;
00580                 }
00581             }
00582         }
00583 
00584         // ---------------------------------------------------------------------------------------------
00585         // (6) If we are *not* connected to the server due to radio or tcp problems, *and* there
00586         //     is any backlog of samples not sent yet, back them up to flash in case of power loss.
00587         if (!isCommunicationConnected)
00588         {
00589             /*if (sampleBacklog.backlog() > 0)
00590             {
00591                 printf("Backing up queued sample data to flash.\r\n");
00592             }
00593             if (statusUpdateBacklog.backlog() > 0)
00594             {
00595                 printf("Backing up queued status-update events to flash.\r\n");
00596             }*/           
00597             // Backup any wall-timestamped samples to flash since there's no connection right now and
00598             // power could go away at any moment.
00599             
00600             // Note -- we dropped this feature due to the complexity of dealing with 64KB sectors
00601             // on the SPI flash, but this is where you'd ideally keep everything backed up.
00602         }
00603 
00604         // ---------------------------------------------------------------------------------------------
00605         // (7) Make sure the latest setting are stored in the flash, in duplicate
00606         if (!settingsManager.serviceSettingsInFlash())
00607         {
00608             printf("Error updating settings in flash!\r\n");
00609         }
00610 
00611         // ---------------------------------------------------------------------------------------------
00612         // (8) Finally, spit out debug state and throttle the main loop rate (too fast seems to aggravate
00613         //     the modem, which is already touchy...)
00614         printf("MAIN: t = %d, radio = %d, socket = %d, samplebacklog = %d, updatebacklog = %d, radio wdt = %d\r\n",
00615             (int)SystemTimeKeeper::instance().walltime(),
00616             isRadioConnected,
00617             isCommunicationConnected,
00618             sampleBacklog.backlog(),
00619             statusUpdateBacklog.backlog(),
00620             radioManager.watchdogValue());
00621   
00622         // ---------------------------------------------------------------------------------------------
00623         // (7) Radio watchdog -- if we haven't had success using the radio in
00624         //     more than a couple hours, reboot the radio; it may be hosed.
00625         if (!radioManager.serviceWatchdog())
00626         {
00627             printf("Error handling radio watchdog!\r\n");
00628         }
00629 
00630         wait(2.0);
00631     }
00632 }