System Management code

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DataStructures.cpp Source File

DataStructures.cpp

00001 #include "DataStructures.h"
00002 #include "DefaultProfile.h"
00003 #include "IAP.h"
00004 
00005 #define HEADER_SECTOR           27                                                                  // Where the NV_Data header information is stored
00006 #define HEADER_PTR              (NV_Data*)((uint32_t*)(sector_start_adress[HEADER_SECTOR]))
00007 #define ID_MARKER               0x5a5a5a5a                                                          // Marker that identifies whether the flash was erased from programming a new .bin file
00008 #define FRAME_SECTOR            28                                                                  // First sector for freeze frame storage (swapspace)
00009 #define FRAME_PTR               (FreezeFrame*)((uint32_t*)(sector_start_adress[FRAME_SECTOR]))
00010 #define PROFILE_SECTOR          29                                                                  // The flash sector where profiles are stored, 29 is the last 32kB size sector in memory
00011 #define PROFILE_START_PTR       (Profile_checkSum*)((uint32_t*)(sector_start_adress[PROFILE_SECTOR]))        // Pointer to the first profile object in flash
00012 
00013 // OPERATING DATA OBJECTS
00014 FreezeFrame frame;                            // Current working object in RAM, contains both param and freeze frame
00015 OperatingInfo *op = &(frame.op.op);           // Handle to just the op section
00016 Profile *param = &(frame.param.param);        // Handle to just the param section
00017 TemporaryData tempData;                       // Temporary data object in RAM
00018 
00019 IAP iap;                                      // Access to In-Application-Programming --> flash memory programming routines
00020 Profile_checkSum copyBuffer[NUM_STORED_PROFILES];      // Scratch-space in RAM for saving profiles, since flash writes must erase the entire sector and only RAM is usable during flash write
00021 
00022 // Non-volatile data holder class
00023 class NV_Data
00024 {
00025 public:
00026     NV_Data() {
00027         id = ID_MARKER;
00028         frameStoredFlag = 0;
00029         usingProfile = 0;
00030     }
00031     int frameStoredFlag;
00032     int usingProfile;
00033     
00034     int id;
00035 };
00036 
00037 // Construct new freeze frames with empty OperatingInfo and default Profile
00038 FreezeFrame::FreezeFrame()
00039 {
00040     memcpy(&(this->param), &defaultProfile, sizeof(Profile));
00041     memset(&(this->op), 0, sizeof(OperatingInfo));
00042 }
00043 
00044 // Helper function to compute checksums using the BSD checksum algorithim for checking validity of flash contents
00045 // Arguments:  start location of the block, size in bytes     Returns:  checksum
00046 uint32_t checksum(const void* ptr, unsigned int size)
00047 {
00048     const char* start = (char*)(ptr);
00049     uint32_t checksum = 0;
00050     for (uint32_t i = 0; i < size; i++) {   // Skip last 4 bytes which holds the checksum itsel
00051         // BSD checksum algorithm
00052         checksum = (checksum >> 1) + ((checksum & 1) << 15);
00053         checksum += start[i];   // Accumulate
00054         checksum &= 0xffff;     // Time to 16 bits
00055     }
00056     return checksum;
00057 }
00058 
00059 // Helper function to streamline flash memory prep-erase-prep-write
00060 // Takes start pointer (RAM), size of object to copy, start pointer (flash), and sector number
00061 int flashWrite(void* start, int size, void* flash_start, int sector)
00062 {
00063     for (int i = 256; i <= 8192; i *= 2) {  // Count by powers of 2
00064         if (size <= i) {                    // Stop when oversize or equal
00065             size = i;
00066             break;
00067         }
00068     }
00069     if (size > 4096) return -1;           // Chunk too big to copy
00070     if (size == 2048) size = 4096;  // 2048 does not exist, next size up
00071 
00072     __disable_irq();                      // Flash operations are non-interruptable
00073 
00074     // Flash prepare, erase, prepare, write - (r == 0) means successful, non-zero = error code
00075     int r = iap.prepare(sector, sector);
00076     if (r == 0) {
00077         r = iap.erase(sector, sector);
00078         if (r == 0) {
00079             r = iap.prepare(sector, sector);
00080             if (r == 0) {
00081                 r = iap.write((char*)start, (char*)flash_start, size);
00082             }
00083         }
00084     }
00085     __enable_irq();     // Re-enable interrupts
00086     return r;           // 0 if success, otherwise see fault codes in LPC1768 User Manual
00087 }
00088 bool setProfile(int index)
00089 {
00090     bool passed = false;
00091     if (index == 0) passed = true;
00092     else if (index == -1) passed = true;
00093     else if (index <= NUM_STORED_PROFILES && index > 0) passed = true;
00094 
00095     if (!passed) return false;
00096     NV_Data temp;
00097     NV_Data* header = HEADER_PTR;
00098     
00099     __disable_irq();
00100     memcpy(&temp, header, sizeof(NV_Data));    // Atomic copy to RAM
00101     __enable_irq();
00102     
00103     temp.usingProfile = index;
00104 
00105     // Write it back to flash
00106     int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
00107     return (i == 0);
00108 }
00109 
00110 // Retrieve the index number of the currently active profile (last profile loaded/saved)
00111 int Profile::usingProfile()
00112 {
00113     NV_Data* header = HEADER_PTR;
00114     return header->usingProfile;
00115 }
00116 
00117 // Startup procedure run on chip reset to fetch last used profile
00118 bool Profile::loadStartUp()
00119 {
00120     // Check health of the header
00121     NV_Data *header = HEADER_PTR;
00122     bool passed=true;
00123     if (header->id != ID_MARKER) passed = false;
00124     if (header->usingProfile > NUM_STORED_PROFILES || header->usingProfile < -1) passed = false;
00125     if (header->frameStoredFlag != 0 && header->frameStoredFlag != ~0) passed = false;
00126 
00127     // Write a new, blank header    
00128     if (!passed) {
00129         NV_Data temp;
00130         int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
00131     }
00132     
00133     if (loadProfile(usingProfile())) {   // Try to fetch the profile that is currently marked
00134         return true;
00135     } else {                            // If fail, revert to default
00136         loadProfile(0);
00137         return false;
00138     }
00139 }
00140 
00141 // Attempt to copy profile from flash to RAM object as indicated by int index
00142 bool Profile::loadProfile(int index)
00143 {
00144     Profile *p;
00145     if (!getProfile(&p, index)) return false;
00146     
00147     __disable_irq();
00148     memcpy(param, p, sizeof(Profile));
00149     __enable_irq();
00150 
00151     if (setProfile(index)) return true;
00152     return false;                        // Bad sum, no copy was done
00153 }
00154 
00155 // Attempt to fetch the profile pointer only, no copy to RAM
00156 bool Profile::getProfile(Profile **ptr, int index)
00157 {
00158     Profile_checkSum *p;
00159 
00160     // If default profile requested
00161     if (index == 0) {
00162         *ptr = &defaultProfile;                 // Set pointer to default, return
00163         return true;
00164 
00165         // If freeze profile requested
00166     } else if (index == -1) {
00167         FreezeFrame *freeze;
00168         if (!FreezeFrame::getFrame(&freeze)) {  // Attempt to fetch frame
00169             *ptr = NULL;                        // Not available, set NULL
00170             return false;
00171         }
00172         p = &(freeze->param);
00173 
00174         // Profile from flash storage requested
00175     } else if (index <= NUM_STORED_PROFILES && index > 0) {
00176         p = PROFILE_START_PTR + (index - 1);  // Set a pointer to the profile
00177 
00178         // Bad command, invalid index
00179     } else {
00180         *ptr = NULL;
00181         return false;
00182     }
00183     // Validate contents by computing checksum
00184     if (p->BSDchecksum == checksum(&(p->param), sizeof(Profile))) {         // Check checksum
00185         *ptr = &(p->param);           // Fill out the pointer, checksum passed
00186         return true;
00187     }
00188     *ptr = NULL;
00189     return false;    // Bad checksum, ptr set to NULL
00190 }
00191 // Take the current RAM object contents and save it to flash at location given by index
00192 // Flash write requires the sector to be erased first, so the function will copy out and re-wrtie the profiles
00193 bool Profile::saveProfile(int index)
00194 {
00195     if (index > NUM_STORED_PROFILES || index <= 0) return false;            // Index invalid
00196     frame.param.BSDchecksum = checksum(param, sizeof(Profile));             // Add the checksum
00197 
00198     // Copy out all of the old profiles
00199     for (int i = 0; i < NUM_STORED_PROFILES; i++) {
00200         if (i == (index - 1)) {     // Exception, replace this slot with the RAM profile
00201             __disable_irq();
00202             memcpy(&copyBuffer[i], &(frame.param), sizeof(Profile_checkSum));
00203             __enable_irq();
00204             continue;               // Skip to next
00205         }
00206         __disable_irq();
00207         memcpy(&copyBuffer[i], PROFILE_START_PTR+i, sizeof(Profile_checkSum));   // Copy profile from flash to RAM
00208         __enable_irq();
00209     }
00210     int r = flashWrite(copyBuffer, sizeof(copyBuffer), sector_start_adress[PROFILE_SECTOR], PROFILE_SECTOR);
00211 
00212     if (r == 0) {
00213         return setProfile(index);
00214     }
00215     return false;
00216 }
00217 
00218 // Fetch pointer to the last written freeze frame object if available, do not copy contents to RAM
00219 bool FreezeFrame::getFrame(FreezeFrame **frame)
00220 {    
00221     if (FreezeFrame::getError() == false) {
00222         *frame = NULL;    // No frame available, return
00223         return false;
00224     }
00225     
00226     FreezeFrame* ptr = FRAME_PTR;                                                               // Set pointer to frame
00227     uint32_t checksumOp = checksum(&(ptr->op.op), sizeof(OperatingInfo));                       // Compute checksum for operatingInfo section
00228     uint32_t checksumParam = checksum(&(ptr->param.param), sizeof(Profile));                    // Compute checksum for profile section
00229 
00230     if (checksumOp == ptr->op.BSDchecksum && checksumParam == ptr->param.BSDchecksum) {         // Compare to stored checksum
00231         *frame = ptr;       // Checksum passed, pass out the ptr
00232         return true;
00233     }
00234     *frame = NULL;          // Checksum failed, write NULL
00235     return false;
00236 }
00237 
00238 // Copy contents of RAM to flash, usually called on error to record the internal state upon enetering fault conditions
00239 bool FreezeFrame::writeFrame()
00240 {
00241     // Compute and record the checksums
00242     frame.param.BSDchecksum = checksum(&(frame.param.param), sizeof(Profile));
00243     frame.op.BSDchecksum = checksum(&(frame.op.op), sizeof(OperatingInfo));
00244 
00245     int r = flashWrite(&frame, sizeof(FreezeFrame), sector_start_adress[FRAME_SECTOR], FRAME_SECTOR);
00246     if (r == 0) {
00247         // Set the error flag in the header
00248         NV_Data temp;
00249         NV_Data* header = HEADER_PTR;
00250         __disable_irq();
00251         memcpy(&temp, header, sizeof(NV_Data));
00252         __enable_irq();
00253         temp.frameStoredFlag = ~0;
00254         int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
00255         return (i == 0);
00256     }
00257     return false;                               // False if flash operations failed
00258 }
00259 
00260 // Get the non-volatile freeze Frame recorded flag that indicates whether a freeze frame is available
00261 bool FreezeFrame::getError()
00262 {
00263     NV_Data* header = HEADER_PTR;
00264     return header->frameStoredFlag;
00265 }
00266 // Clear the frame error, for ex. when the frame is read by user
00267 bool FreezeFrame::clearError()
00268 {
00269     NV_Data temp;
00270     NV_Data* header = HEADER_PTR;
00271     __disable_irq();
00272     memcpy(&temp, header, sizeof(NV_Data));
00273     __enable_irq();
00274     temp.frameStoredFlag = 0;
00275     int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
00276     return (i == 0);
00277 }