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 SettingsManager.h Source File

SettingsManager.h

00001 
00002 #ifndef _SettingsManager_h_
00003 #define _SettingsManager_h_
00004 
00005 #include "mbed.h"
00006 #include "SpiFlash25.h"
00007 
00008 
00009 #define PAGE_SIZE               256
00010 #define SECTOR_SIZE             64*1024
00011 #define MEM_SIZE                2*1024*1024
00012 
00013 
00014 class SettingsManager
00015 {
00016 public:
00017     static const size_t HOSTNAME_LENGTH = 128;
00018     
00019     static const uint32_t DefaultSignature = 0x130c8215;
00020 
00021     // This image appears at the top of the first two erasable sectors of the SPI flash.
00022 #pragma pack(push,1)
00023     struct SettingsImage
00024     {
00025         uint32_t m_valid; // Must be exactly 1 for valid; any other value (ffffffff, 0) are invalid.
00026         uint32_t m_signature; // arbitrary value, change if you want to force an update
00027         //char m_apn[HOSTNAME_LENGTH]; // For now, RadioManager hardcodes the ATT M2M APN; it's only a liability to make it changeable remotely, at this stage.
00028         char m_host1[HOSTNAME_LENGTH];
00029         uint32_t m_port1;
00030         char m_host2[HOSTNAME_LENGTH];
00031         uint32_t m_port2;
00032         int32_t m_sampleIntervalInSeconds;
00033         int32_t m_dischargeThreshold; // in mA
00034         int32_t m_chargeThreshold; // in mA
00035         int32_t m_currentHysteresis; // in mA
00036         int32_t m_serverSettingsUpdateSeconds; // seconds after which to ask server for updated settings -- usually the socket/radio will go down before this anyway
00037         uint32_t m_statusUpdateEvictionTime;
00038         uint32_t m_voltageFilterLengthInSamples;
00039         int32_t m_vspUpdateThreshold;
00040         int32_t m_vspJumpThreshold;
00041         int32_t m_voemUpdateThreshold;
00042         int32_t m_voemJumpThreshold;
00043         int32_t m_v3UpdateThreshold;
00044         int32_t m_v3JumpThreshold;
00045         int32_t m_v4UpdateThreshold;
00046         int32_t m_v4JumpThreshold;
00047         uint32_t m_currentFilterLengthInSamples;
00048         int32_t m_a1UpdateThreshold;
00049         int32_t m_a1JumpThreshold;
00050         int32_t m_a2UpdateThreshold;
00051         int32_t m_a2JumpThreshold;
00052         uint32_t m_temperatureFilterLengthInSamples;
00053         int32_t m_temperatureUpdateThreshold;
00054         int32_t m_temperatureJumpThreshold;
00055         int32_t m_useFilteredA1ForBatteryState;
00056         int32_t m_minimumEventSampleDuration;
00057         
00058         // NOTE: Must pad this struct (before m_checksum) to an integral number of u32's if it isn't already...
00059         // char m_pad[3];
00060         uint32_t m_mtime; // The time_t that the settings were written--so the manager can always take the most recent
00061         uint32_t m_checksum; // Sum of all 32-bit chunks preceding this, XOR'd by the XOR of all preceding u32's.  Always the last thing in the struct.
00062         
00063         bool matches(const SettingsImage& other) const
00064         {
00065             return 0 == memcmp(this, &other, sizeof(SettingsImage));
00066             /*
00067             // Keep this around; useful for debugging settings update problems
00068             int i;
00069             const char* otherBuffer = (const char*)&other;
00070             const char* buffer = (const char*)this;
00071             bool matched = true;
00072             for (i = 0; i < sizeof(SettingsImage)-2*sizeof(uint32_t); ++i)
00073             {
00074                 if (otherBuffer[i] != buffer[i])
00075                 {
00076                     printf("Buffer mismatch offset %d, %02X != %02X\r\n", i, buffer[i], otherBuffer[i]);
00077                     matched = false;
00078                 }
00079             }
00080             if (matched) printf("Everything matched.\r\n");
00081             return matched;
00082             */
00083         }
00084         
00085         
00086     };
00087 #pragma pack(pop)
00088 
00089     SettingsManager(SpiFlash25& flash) :
00090        m_flash(flash)
00091     {
00092         m_settings.m_signature = DefaultSignature;
00093     }
00094     
00095     /*
00096     const char* getAPN() const
00097     {
00098         return m_settings.m_apn;
00099     }
00100     */
00101     
00102     const char* getHost1() const
00103     {
00104         return m_settings.m_host1;
00105     }
00106     
00107     uint16_t getPort1() const
00108     {
00109         return (uint16_t)m_settings.m_port1;
00110     }
00111     
00112     const char* getHost2() const
00113     {
00114         return m_settings.m_host2;
00115     }
00116 
00117     uint16_t getPort2() const
00118     {
00119         return (uint16_t)m_settings.m_port2;
00120     }
00121     
00122     float getSampleIntervalInSeconds() const
00123     {
00124         return (float)m_settings.m_sampleIntervalInSeconds;
00125     }
00126     
00127     float getSettingsUpdateIntervalInSeconds() const
00128     {
00129         return (float)m_settings.m_serverSettingsUpdateSeconds;
00130     }
00131     
00132     float getDischargeThreshold() const
00133     {
00134         return (float)(m_settings.m_dischargeThreshold * 0.001);
00135     }
00136     
00137     float getChargeThreshold() const
00138     {
00139         return (float)(m_settings.m_chargeThreshold * 0.001);
00140     }
00141     
00142     float getCurrentHysteresis() const
00143     {
00144         return (float)(m_settings.m_currentHysteresis * 0.001);
00145     }
00146     
00147     uint32_t getStatusUpdateEvictionTime() const
00148     {
00149         return (uint32_t)(m_settings.m_statusUpdateEvictionTime);
00150     }
00151 
00152     uint32_t getVoltageFilterLengthInSamples() const
00153     {
00154         return (uint32_t)(m_settings.m_voltageFilterLengthInSamples);
00155     }
00156 
00157     float getVspUpdateThreshold() const
00158     {
00159         return (float)(m_settings.m_vspUpdateThreshold * 0.001);
00160     }
00161 
00162     float getVspJumpThreshold() const
00163     {
00164         return (float)(m_settings.m_vspJumpThreshold * 0.001);
00165     }
00166 
00167     float getVoemUpdateThreshold() const
00168     {
00169         return (float)(m_settings.m_voemUpdateThreshold * 0.001);
00170     }
00171 
00172     float getVoemJumpThreshold() const
00173     {
00174         return (float)(m_settings.m_voemJumpThreshold * 0.001);
00175     }
00176 
00177     float getV3UpdateThreshold() const
00178     {
00179         return (float)(m_settings.m_v3UpdateThreshold * 0.001);
00180     }
00181 
00182     float getV3JumpThreshold() const
00183     {
00184         return (float)(m_settings.m_v3JumpThreshold * 0.001);
00185     }
00186 
00187     float getV4UpdateThreshold() const
00188     {
00189         return (float)(m_settings.m_v4UpdateThreshold * 0.001);
00190     }
00191 
00192     float getV4JumpThreshold() const
00193     {
00194         return (float)(m_settings.m_v4JumpThreshold * 0.001);
00195     }
00196 
00197     uint32_t getCurrentFilterLengthInSamples() const
00198     {
00199         return (uint32_t)(m_settings.m_currentFilterLengthInSamples);
00200     }
00201 
00202     float getA1UpdateThreshold() const
00203     {
00204         return (float)(m_settings.m_a1UpdateThreshold * 0.001);
00205     }
00206 
00207     float getA1JumpThreshold() const
00208     {
00209         return (float)(m_settings.m_a1JumpThreshold * 0.001);
00210     }
00211 
00212     float getA2UpdateThreshold() const
00213     {
00214         return (float)(m_settings.m_a2UpdateThreshold * 0.001);
00215     }
00216 
00217     float getA2JumpThreshold() const
00218     {
00219         return (float)(m_settings.m_a2JumpThreshold * 0.001);
00220     }
00221 
00222     uint32_t getTemperatureFilterLengthInSamples() const
00223     {
00224         return (uint32_t)(m_settings.m_temperatureFilterLengthInSamples);
00225     }
00226 
00227     float getTemperatureUpdateThreshold() const
00228     {
00229         return (float)(m_settings.m_temperatureUpdateThreshold * 0.001);
00230     }
00231 
00232     float getTemperatureJumpThreshold() const
00233     {
00234         return (float)(m_settings.m_temperatureJumpThreshold * 0.001);
00235     }
00236     
00237     bool getUseFilteredA1ForBatteryState() const
00238     {
00239         return m_settings.m_useFilteredA1ForBatteryState != 0;
00240     }
00241     
00242     int32_t getMinimumEventSampleDuration() const
00243     {
00244         return m_settings.m_minimumEventSampleDuration;        
00245     }
00246 
00247     void loadDefaultSettings()
00248     {
00249         memset(&m_settings, 0, sizeof(m_settings));
00250         // Loads memory settings from hardcoded constants--don't use this unless the flash is toast
00251         m_settings.m_valid = 1;
00252         m_settings.m_signature = DefaultSignature;
00253         m_settings.m_mtime = 0; // default value, earliest possible value.
00254         //snprintf(m_settings.m_apn, HOSTNAME_LENGTH, "m2m.com.attz");
00255         memset(m_settings.m_host1, HOSTNAME_LENGTH, 0);
00256         snprintf(m_settings.m_host1, HOSTNAME_LENGTH, "iotdata1.idlereduction.com");
00257         m_settings.m_port1 = 4700;
00258         memset(m_settings.m_host2, HOSTNAME_LENGTH, 0);
00259         snprintf(m_settings.m_host2, HOSTNAME_LENGTH, "52.54.102.85"); // EC2 elastic IP
00260         m_settings.m_port2 = 4700;
00261         m_settings.m_sampleIntervalInSeconds = 60 * 60; // hourly reporting by default
00262         m_settings.m_dischargeThreshold = 2500; // mA
00263         m_settings.m_chargeThreshold = -2500; // mA
00264         m_settings.m_currentHysteresis = 250; // mA
00265         m_settings.m_serverSettingsUpdateSeconds = 60 * 60; // hourly updates for server settings by default
00266         m_settings.m_statusUpdateEvictionTime = 60*60; // at least report status hourly if no other reason
00267         m_settings.m_voltageFilterLengthInSamples = 100; // smooth exponentially over this many samples
00268         m_settings.m_vspUpdateThreshold = 50; // mV
00269         m_settings.m_vspJumpThreshold = 1000; // mV
00270         m_settings.m_voemUpdateThreshold = 50; // mV
00271         m_settings.m_voemJumpThreshold = 1000; // mV
00272         m_settings.m_v3UpdateThreshold = 50; // mV
00273         m_settings.m_v3JumpThreshold = 1000; // mV
00274         m_settings.m_v4UpdateThreshold = 50; // mV
00275         m_settings.m_v4JumpThreshold = 1000; // mV
00276         m_settings.m_currentFilterLengthInSamples = 0;
00277         m_settings.m_a1UpdateThreshold = 1000; // mA
00278         m_settings.m_a1JumpThreshold = 3000;
00279         m_settings.m_a2UpdateThreshold = 1000; // mA
00280         m_settings.m_a2JumpThreshold = 3000;
00281         m_settings.m_temperatureFilterLengthInSamples = 100;
00282         m_settings.m_temperatureUpdateThreshold = 2500; // thousands of degree
00283         m_settings.m_temperatureJumpThreshold = 2500;
00284         m_settings.m_useFilteredA1ForBatteryState = 0; //false
00285         m_settings.m_minimumEventSampleDuration = 5;
00286         _populateChecksum(m_settings);
00287     }
00288     
00289     void printSettings()
00290     {
00291         printf("                 dischargeThreshold: %d mA\r\n", m_settings.m_dischargeThreshold);
00292         printf("                    chargeThreshold: %d mA\r\n", m_settings.m_chargeThreshold);
00293         printf("                  currentHysteresis: %d mA\r\n", m_settings.m_currentHysteresis);
00294         printf("              regularSampleInterval: %d s\r\n", m_settings.m_sampleIntervalInSeconds);
00295         printf("              settingsCheckInterval: %d s\r\n", m_settings.m_serverSettingsUpdateSeconds);
00296         printf("                        primaryHost: '%s'\r\n", m_settings.m_host1);
00297         printf("                        primaryPort: %d\r\n", m_settings.m_port1);
00298         printf("                      secondaryHost: '%s'\r\n", m_settings.m_host2);
00299         printf("                      secondaryPort: %d\r\n", m_settings.m_port2);
00300         printf("           statusUpdateEvictionTime: %d s\r\n", m_settings.m_statusUpdateEvictionTime);
00301         printf("       voltageFilterLengthInSamples: %d\r\n", m_settings.m_voltageFilterLengthInSamples);
00302         printf("                 vspUpdateThreshold: %d mV\r\n", m_settings.m_vspUpdateThreshold);
00303         printf("                   vspJumpThreshold: %d mV\r\n", m_settings.m_vspJumpThreshold);
00304         printf("                voemUpdateThreshold: %d mV\r\n", m_settings.m_voemUpdateThreshold);
00305         printf("                  voemJumpThreshold: %d mV\r\n", m_settings.m_voemJumpThreshold);
00306         printf("                  v3UpdateThreshold: %d mV\r\n", m_settings.m_v3UpdateThreshold);
00307         printf("                    v3JumpThreshold: %d mV\r\n", m_settings.m_v3JumpThreshold);
00308         printf("                  v4UpdateThreshold: %d mV\r\n", m_settings.m_v4UpdateThreshold);
00309         printf("                    v4JumpThreshold: %d mV\r\n", m_settings.m_v4JumpThreshold);
00310         printf("       currentFilterLengthInSamples: %d\r\n", m_settings.m_currentFilterLengthInSamples);
00311         printf("                  a1UpdateThreshold: %d mA\r\n", m_settings.m_a1UpdateThreshold);
00312         printf("                    a1JumpThreshold: %d mA\r\n", m_settings.m_a1JumpThreshold);
00313         printf("                  a2UpdateThreshold: %d mA\r\n", m_settings.m_a2UpdateThreshold);
00314         printf("                    a2JumpThreshold: %d mA\r\n", m_settings.m_a2JumpThreshold);
00315         printf("   temperatureFilterLengthInSamples: %d s\r\n", m_settings.m_temperatureFilterLengthInSamples);
00316         printf("         temperatureUpdateThreshold: %d mDegC\r\n", m_settings.m_temperatureUpdateThreshold);
00317         printf("           temperatureJumpThreshold: %d mDegC\r\n", m_settings.m_temperatureJumpThreshold);
00318         printf("       useFilteredA1ForBatteryState: %d\r\n", m_settings.m_useFilteredA1ForBatteryState);
00319         printf("         minimumEventSampleDuration: %d\r\n", m_settings.m_minimumEventSampleDuration);
00320     }
00321 
00322     bool setAll(
00323         const char* primaryHost,
00324         uint16_t primaryPort,
00325         const char* secondaryHost,
00326         uint16_t secondaryPort,
00327         int32_t dischargeThreshold,     /* threshold in mV above which the stealth battery current is considered 'discharging' */
00328         int32_t chargeThreshold,        /* threshold below which the stealth battery current is considered 'charging' */
00329         int32_t currentHysteresis,      /* amount to ease the discharging/charging thresholds once already in that respective state */
00330         int32_t regularSampleInterval,  /* interval, in seconds, at which to send regularly-sampled data; 0 means "don't" */
00331         int32_t settingsCheckInterval,
00332         uint32_t statusUpdateEvictionTime,
00333         uint32_t voltageFilterLengthInSamples,
00334         int32_t vspUpdateThreshold,
00335         int32_t vspJumpThreshold,
00336         int32_t voemUpdateThreshold,
00337         int32_t voemJumpThreshold,
00338         int32_t v3UpdateThreshold,
00339         int32_t v3JumpThreshold,
00340         int32_t v4UpdateThreshold,
00341         int32_t v4JumpThreshold,
00342         uint32_t currentFilterLengthInSamples,
00343         int32_t a1UpdateThreshold,
00344         int32_t a1JumpThreshold,
00345         int32_t a2UpdateThreshold,
00346         int32_t a2JumpThreshold,
00347         uint32_t temperatureFilterLengthInSamples,
00348         int32_t temperatureUpdateThreshold,
00349         int32_t temperatureJumpThreshold,
00350         int32_t useFilteredA1ForBatteryState,
00351         int32_t minimumEventSampleDuration)
00352     {
00353         if (!primaryHost || strlen(primaryHost) >= HOSTNAME_LENGTH) return false;
00354         if (!secondaryHost || strlen(secondaryHost) >= HOSTNAME_LENGTH) return false;
00355         if (regularSampleInterval < 0) regularSampleInterval = 0;
00356         if (settingsCheckInterval < 20) settingsCheckInterval = 20; // min 20 sec between settings checks
00357         if (settingsCheckInterval > 24*60*60) settingsCheckInterval = 24*60*60; // max 1 day between settings check
00358         if (minimumEventSampleDuration < 0) minimumEventSampleDuration = 0;
00359          
00360         memset(m_settings.m_host1, 0, HOSTNAME_LENGTH);
00361         strncpy(m_settings.m_host1, primaryHost, HOSTNAME_LENGTH);
00362         m_settings.m_port1 = primaryPort;
00363         memset(m_settings.m_host2, 0, HOSTNAME_LENGTH);
00364         strncpy(m_settings.m_host2, secondaryHost, HOSTNAME_LENGTH);
00365         m_settings.m_port2 = secondaryPort;
00366         m_settings.m_dischargeThreshold = dischargeThreshold;
00367         m_settings.m_currentHysteresis = currentHysteresis;
00368         m_settings.m_chargeThreshold = chargeThreshold;
00369         m_settings.m_sampleIntervalInSeconds = regularSampleInterval;
00370         m_settings.m_serverSettingsUpdateSeconds = settingsCheckInterval;
00371         m_settings.m_statusUpdateEvictionTime = statusUpdateEvictionTime;
00372         m_settings.m_voltageFilterLengthInSamples = voltageFilterLengthInSamples;
00373         m_settings.m_vspUpdateThreshold = vspUpdateThreshold;
00374         m_settings.m_vspJumpThreshold = vspJumpThreshold;
00375         m_settings.m_voemUpdateThreshold = voemUpdateThreshold;
00376         m_settings.m_voemJumpThreshold = voemJumpThreshold;
00377         m_settings.m_v3UpdateThreshold = v3UpdateThreshold;
00378         m_settings.m_v3JumpThreshold = v3JumpThreshold;
00379         m_settings.m_v4UpdateThreshold = v4UpdateThreshold;
00380         m_settings.m_v4JumpThreshold = v4JumpThreshold;
00381         m_settings.m_currentFilterLengthInSamples = currentFilterLengthInSamples;
00382         m_settings.m_a1UpdateThreshold = a1UpdateThreshold;
00383         m_settings.m_a1JumpThreshold = a1JumpThreshold;
00384         m_settings.m_a2UpdateThreshold = a2UpdateThreshold;
00385         m_settings.m_a2JumpThreshold = a2JumpThreshold;
00386         m_settings.m_temperatureFilterLengthInSamples = temperatureFilterLengthInSamples;
00387         m_settings.m_temperatureUpdateThreshold = temperatureUpdateThreshold;
00388         m_settings.m_temperatureJumpThreshold = temperatureJumpThreshold;
00389         m_settings.m_useFilteredA1ForBatteryState = useFilteredA1ForBatteryState;
00390         m_settings.m_minimumEventSampleDuration = minimumEventSampleDuration;
00391         //printSettings();
00392         return true;
00393     }
00394    /* other settings you can think of here ... ? */
00395 
00396 
00397 
00398     bool loadSettingsFromFlash()
00399     {
00400         // Try to get settings from sector 0 and from sector 1.
00401         // If they're both valid, take the one with the newer mtime.
00402         // If neither is valid, return false.
00403         
00404         bool gotImage0 = false;
00405         SettingsImage image0;
00406         memset(&image0, 0, sizeof(SettingsImage));
00407         gotImage0 = _loadIfValid(0*SECTOR_SIZE, image0);
00408         
00409         bool gotImage1 = false;
00410         SettingsImage image1;
00411         memset(&image1, 0, sizeof(SettingsImage));
00412         gotImage1 = _loadIfValid(1*SECTOR_SIZE, image1);
00413         
00414         if (gotImage0 && !gotImage1)
00415         {
00416             m_settings = image0;
00417             printf("Loaded settings from sector 0 because sector 1 was bad\r\n");
00418         }
00419         else if (gotImage1 && !gotImage0)
00420         {
00421             m_settings = image1;
00422             printf("Loaded settings from sector 1 because sector 0 was bad\r\n");
00423         }
00424         else if (gotImage0 && gotImage1)
00425         {
00426             if (image0.m_mtime >= image1.m_mtime)
00427             {
00428                 printf("Loaded settings from sector 0\r\n");
00429                 m_settings = image0;
00430             }
00431             else
00432             {
00433                 printf("Loaded settings from sector 1\r\n");
00434                 m_settings = image1;
00435             }
00436         }
00437         
00438         return gotImage0 || gotImage1;
00439     }
00440         
00441     bool writeSettingsToFlash()
00442     {
00443         int mtime = SystemTimeKeeper::instance().walltime();
00444         
00445         // Compare to sector 0--if different, erase and write sector 0.
00446         SettingsImage image;
00447         memset(&image, 0, sizeof(SettingsImage));
00448         if (_load(0*SECTOR_SIZE, image))
00449         {
00450             if (!image.matches(m_settings) ||
00451                 !_checkChecksum(image))
00452             {
00453                 printf("Saving updated settings in sector 0.\r\n");
00454                 // Update the settings' mtime iff we're committed to rewriting flash
00455                 m_settings.m_mtime = mtime;
00456                 _populateChecksum(m_settings);
00457                 
00458                 m_flash.clear_sector(0*SECTOR_SIZE);
00459                 if (!m_flash.write(0*SECTOR_SIZE, sizeof(m_settings), (char*)&m_settings))
00460                 {
00461                    printf("Error writing settings to sector 0.\r\n");   
00462                 }
00463             }
00464             else
00465             {
00466                 //printf("Settings already written in sector 0.\r\n");
00467             }
00468         }
00469         else
00470         {
00471             printf("Couldn't validate settings in sector 0.\r\n");
00472         }
00473         
00474         // Compare to sector 1--if different, erase and write sector 1.
00475         memset(&image, 0, sizeof(SettingsImage));
00476         if (_load(1*SECTOR_SIZE, image))
00477         {
00478             if (!image.matches(m_settings) ||
00479                 !_checkChecksum(image))
00480             {
00481                 printf("Saving updated settings in sector 1.\r\n");
00482 
00483                 // Update the settings' mtime iff we're committed to rewriting flash
00484                 m_settings.m_mtime = mtime;
00485                 _populateChecksum(m_settings);
00486 
00487                 m_flash.clear_sector(1*SECTOR_SIZE);
00488                 if (!m_flash.write(1*SECTOR_SIZE, sizeof(m_settings), (char*)&m_settings))
00489                 {
00490                    printf("Error writing settings to sector 1.\r\n");   
00491                 }
00492             }
00493             else
00494             {
00495                 //printf("Settings already written in sector 1.\r\n");
00496             }
00497         }
00498         else
00499         {
00500             printf("Couldn't validate settings in sector 1.\r\n");
00501         }
00502         
00503         return true;
00504     }
00505     
00506     bool serviceSettingsInFlash()
00507     {
00508         // This really means do what writeSettingsToFlash() already does--make sure
00509         // the settings we *have* are actually in the flash, in duplicate.
00510         return writeSettingsToFlash();
00511     }
00512     
00513     void initializeSettings()
00514     {
00515         /*
00516         //Keep this around--nice to dump flash contents to hex...
00517         uint32_t buffer[64] = {0};
00518         int i;
00519         flash.read(0*SECTOR_SIZE, 64*4, (char*)&buffer);
00520         for (i = 0; i < 64; ++i)
00521         {
00522             printf(" %08x", buffer[i]);
00523             if (i % 8 == 7) printf("\r\n");
00524         }
00525         printf("\r\n");
00526         flash.read(1*SECTOR_SIZE, 64*4, (char*)&buffer);
00527         for (i = 0; i < 64; ++i)
00528         {
00529             printf(" %08x", buffer[i]);
00530             if (i % 8 == 7) printf("\r\n");
00531         }
00532         //printf("\r\n");
00533         */
00534         
00535         if (!loadSettingsFromFlash())
00536         {
00537             printf("No settings found in Flash; forced to load hard-coded default settings.\r\n");
00538             loadDefaultSettings();
00539         }
00540         if (!writeSettingsToFlash())
00541         {
00542             printf("Error writing settings to flash.\r\n");
00543         }
00544     }
00545     
00546 protected:
00547     bool _load(uint32_t offset, SettingsImage& image)
00548     {
00549         return m_flash.read(offset, sizeof(SettingsImage), (char*)&image);
00550     }
00551     
00552     bool _loadIfValid(uint32_t offset, SettingsImage& image)
00553     {
00554         SettingsImage tempImage;
00555         memset(&tempImage, 0, sizeof(SettingsImage));
00556         if (!_load(offset, tempImage)) return false;
00557         if (!_checkChecksum(tempImage)) return false;
00558         if (tempImage.m_valid != 1) return false;
00559         if (tempImage.m_signature != DefaultSignature) return false;
00560         image = tempImage;
00561         return true;
00562     }
00563 
00564     uint32_t _calculateChecksum(const SettingsImage& settings)
00565     {
00566         uint32_t* raw = (uint32_t*)&settings;
00567         uint32_t xorValue = 0;
00568         uint32_t sum = 0;
00569         while (raw < (uint32_t*)&settings.m_checksum)
00570         {
00571             sum += (*raw);
00572             xorValue ^= (*raw);
00573             ++raw;
00574         }
00575         uint32_t calculated = sum; // ^ xorValue;
00576         //printf("calculated = %08x\r\n", calculated);
00577         return calculated;
00578     }
00579 
00580     void _populateChecksum(SettingsImage& settings)
00581     {
00582         // Fill in the included settings.checksum is what it should be
00583         settings.m_checksum = _calculateChecksum(settings);
00584     }
00585     
00586     bool _checkChecksum(const SettingsImage& settings)
00587     {
00588         // See if the included settings.checksum is what it should be
00589         return settings.m_checksum == _calculateChecksum(settings);
00590     }
00591 
00592     SpiFlash25& m_flash;
00593     
00594     SettingsImage m_settings;
00595 };
00596 
00597 #endif //_SettingsManager_h_
00598