Penn Electric Racing / Mbed 2 deprecated SystemManagement

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Revision:
38:8efacce315ae
diff -r 2207b58b9a7f -r 8efacce315ae DataStructures/DataStructures.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DataStructures/DataStructures.cpp	Sat Feb 07 08:54:51 2015 +0000
@@ -0,0 +1,277 @@
+#include "DataStructures.h"
+#include "DefaultProfile.h"
+#include "IAP.h"
+
+#define HEADER_SECTOR           27                                                                  // Where the NV_Data header information is stored
+#define HEADER_PTR              (NV_Data*)((uint32_t*)(sector_start_adress[HEADER_SECTOR]))
+#define ID_MARKER               0x5a5a5a5a                                                          // Marker that identifies whether the flash was erased from programming a new .bin file
+#define FRAME_SECTOR            28                                                                  // First sector for freeze frame storage (swapspace)
+#define FRAME_PTR               (FreezeFrame*)((uint32_t*)(sector_start_adress[FRAME_SECTOR]))
+#define PROFILE_SECTOR          29                                                                  // The flash sector where profiles are stored, 29 is the last 32kB size sector in memory
+#define PROFILE_START_PTR       (Profile_checkSum*)((uint32_t*)(sector_start_adress[PROFILE_SECTOR]))        // Pointer to the first profile object in flash
+
+// OPERATING DATA OBJECTS
+FreezeFrame frame;                            // Current working object in RAM, contains both param and freeze frame
+OperatingInfo *op = &(frame.op.op);           // Handle to just the op section
+Profile *param = &(frame.param.param);        // Handle to just the param section
+TemporaryData tempData;                       // Temporary data object in RAM
+
+IAP iap;                                      // Access to In-Application-Programming --> flash memory programming routines
+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
+
+// Non-volatile data holder class
+class NV_Data
+{
+public:
+    NV_Data() {
+        id = ID_MARKER;
+        frameStoredFlag = 0;
+        usingProfile = 0;
+    }
+    int frameStoredFlag;
+    int usingProfile;
+    
+    int id;
+};
+
+// Construct new freeze frames with empty OperatingInfo and default Profile
+FreezeFrame::FreezeFrame()
+{
+    memcpy(&(this->param), &defaultProfile, sizeof(Profile));
+    memset(&(this->op), 0, sizeof(OperatingInfo));
+}
+
+// Helper function to compute checksums using the BSD checksum algorithim for checking validity of flash contents
+// Arguments:  start location of the block, size in bytes     Returns:  checksum
+uint32_t checksum(const void* ptr, unsigned int size)
+{
+    const char* start = (char*)(ptr);
+    uint32_t checksum = 0;
+    for (uint32_t i = 0; i < size; i++) {   // Skip last 4 bytes which holds the checksum itsel
+        // BSD checksum algorithm
+        checksum = (checksum >> 1) + ((checksum & 1) << 15);
+        checksum += start[i];   // Accumulate
+        checksum &= 0xffff;     // Time to 16 bits
+    }
+    return checksum;
+}
+
+// Helper function to streamline flash memory prep-erase-prep-write
+// Takes start pointer (RAM), size of object to copy, start pointer (flash), and sector number
+int flashWrite(void* start, int size, void* flash_start, int sector)
+{
+    for (int i = 256; i <= 8192; i *= 2) {  // Count by powers of 2
+        if (size <= i) {                    // Stop when oversize or equal
+            size = i;
+            break;
+        }
+    }
+    if (size > 4096) return -1;           // Chunk too big to copy
+    if (size == 2048) size = 4096;  // 2048 does not exist, next size up
+
+    __disable_irq();                      // Flash operations are non-interruptable
+
+    // Flash prepare, erase, prepare, write - (r == 0) means successful, non-zero = error code
+    int r = iap.prepare(sector, sector);
+    if (r == 0) {
+        r = iap.erase(sector, sector);
+        if (r == 0) {
+            r = iap.prepare(sector, sector);
+            if (r == 0) {
+                r = iap.write((char*)start, (char*)flash_start, size);
+            }
+        }
+    }
+    __enable_irq();     // Re-enable interrupts
+    return r;           // 0 if success, otherwise see fault codes in LPC1768 User Manual
+}
+bool setProfile(int index)
+{
+    bool passed = false;
+    if (index == 0) passed = true;
+    else if (index == -1) passed = true;
+    else if (index <= NUM_STORED_PROFILES && index > 0) passed = true;
+
+    if (!passed) return false;
+    NV_Data temp;
+    NV_Data* header = HEADER_PTR;
+    
+    __disable_irq();
+    memcpy(&temp, header, sizeof(NV_Data));    // Atomic copy to RAM
+    __enable_irq();
+    
+    temp.usingProfile = index;
+
+    // Write it back to flash
+    int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
+    return (i == 0);
+}
+
+// Retrieve the index number of the currently active profile (last profile loaded/saved)
+int Profile::usingProfile()
+{
+    NV_Data* header = HEADER_PTR;
+    return header->usingProfile;
+}
+
+// Startup procedure run on chip reset to fetch last used profile
+bool Profile::loadStartUp()
+{
+    // Check health of the header
+    NV_Data *header = HEADER_PTR;
+    bool passed=true;
+    if (header->id != ID_MARKER) passed = false;
+    if (header->usingProfile > NUM_STORED_PROFILES || header->usingProfile < -1) passed = false;
+    if (header->frameStoredFlag != 0 && header->frameStoredFlag != ~0) passed = false;
+
+    // Write a new, blank header    
+    if (!passed) {
+        NV_Data temp;
+        int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
+    }
+    
+    if (loadProfile(usingProfile())) {   // Try to fetch the profile that is currently marked
+        return true;
+    } else {                            // If fail, revert to default
+        loadProfile(0);
+        return false;
+    }
+}
+
+// Attempt to copy profile from flash to RAM object as indicated by int index
+bool Profile::loadProfile(int index)
+{
+    Profile *p;
+    if (!getProfile(&p, index)) return false;
+    
+    __disable_irq();
+    memcpy(param, p, sizeof(Profile));
+    __enable_irq();
+
+    if (setProfile(index)) return true;
+    return false;                        // Bad sum, no copy was done
+}
+
+// Attempt to fetch the profile pointer only, no copy to RAM
+bool Profile::getProfile(Profile **ptr, int index)
+{
+    Profile_checkSum *p;
+
+    // If default profile requested
+    if (index == 0) {
+        *ptr = &defaultProfile;                 // Set pointer to default, return
+        return true;
+
+        // If freeze profile requested
+    } else if (index == -1) {
+        FreezeFrame *freeze;
+        if (!FreezeFrame::getFrame(&freeze)) {  // Attempt to fetch frame
+            *ptr = NULL;                        // Not available, set NULL
+            return false;
+        }
+        p = &(freeze->param);
+
+        // Profile from flash storage requested
+    } else if (index <= NUM_STORED_PROFILES && index > 0) {
+        p = PROFILE_START_PTR + (index - 1);  // Set a pointer to the profile
+
+        // Bad command, invalid index
+    } else {
+        *ptr = NULL;
+        return false;
+    }
+    // Validate contents by computing checksum
+    if (p->BSDchecksum == checksum(&(p->param), sizeof(Profile))) {         // Check checksum
+        *ptr = &(p->param);           // Fill out the pointer, checksum passed
+        return true;
+    }
+    *ptr = NULL;
+    return false;    // Bad checksum, ptr set to NULL
+}
+// Take the current RAM object contents and save it to flash at location given by index
+// Flash write requires the sector to be erased first, so the function will copy out and re-wrtie the profiles
+bool Profile::saveProfile(int index)
+{
+    if (index > NUM_STORED_PROFILES || index <= 0) return false;            // Index invalid
+    frame.param.BSDchecksum = checksum(param, sizeof(Profile));             // Add the checksum
+
+    // Copy out all of the old profiles
+    for (int i = 0; i < NUM_STORED_PROFILES; i++) {
+        if (i == (index - 1)) {     // Exception, replace this slot with the RAM profile
+            __disable_irq();
+            memcpy(&copyBuffer[i], &(frame.param), sizeof(Profile_checkSum));
+            __enable_irq();
+            continue;               // Skip to next
+        }
+        __disable_irq();
+        memcpy(&copyBuffer[i], PROFILE_START_PTR+i, sizeof(Profile_checkSum));   // Copy profile from flash to RAM
+        __enable_irq();
+    }
+    int r = flashWrite(copyBuffer, sizeof(copyBuffer), sector_start_adress[PROFILE_SECTOR], PROFILE_SECTOR);
+
+    if (r == 0) {
+        return setProfile(index);
+    }
+    return false;
+}
+
+// Fetch pointer to the last written freeze frame object if available, do not copy contents to RAM
+bool FreezeFrame::getFrame(FreezeFrame **frame)
+{    
+    if (FreezeFrame::getError() == false) {
+        *frame = NULL;    // No frame available, return
+        return false;
+    }
+    
+    FreezeFrame* ptr = FRAME_PTR;                                                               // Set pointer to frame
+    uint32_t checksumOp = checksum(&(ptr->op.op), sizeof(OperatingInfo));                       // Compute checksum for operatingInfo section
+    uint32_t checksumParam = checksum(&(ptr->param.param), sizeof(Profile));                    // Compute checksum for profile section
+
+    if (checksumOp == ptr->op.BSDchecksum && checksumParam == ptr->param.BSDchecksum) {         // Compare to stored checksum
+        *frame = ptr;       // Checksum passed, pass out the ptr
+        return true;
+    }
+    *frame = NULL;          // Checksum failed, write NULL
+    return false;
+}
+
+// Copy contents of RAM to flash, usually called on error to record the internal state upon enetering fault conditions
+bool FreezeFrame::writeFrame()
+{
+    // Compute and record the checksums
+    frame.param.BSDchecksum = checksum(&(frame.param.param), sizeof(Profile));
+    frame.op.BSDchecksum = checksum(&(frame.op.op), sizeof(OperatingInfo));
+
+    int r = flashWrite(&frame, sizeof(FreezeFrame), sector_start_adress[FRAME_SECTOR], FRAME_SECTOR);
+    if (r == 0) {
+        // Set the error flag in the header
+        NV_Data temp;
+        NV_Data* header = HEADER_PTR;
+        __disable_irq();
+        memcpy(&temp, header, sizeof(NV_Data));
+        __enable_irq();
+        temp.frameStoredFlag = ~0;
+        int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
+        return (i == 0);
+    }
+    return false;                               // False if flash operations failed
+}
+
+// Get the non-volatile freeze Frame recorded flag that indicates whether a freeze frame is available
+bool FreezeFrame::getError()
+{
+    NV_Data* header = HEADER_PTR;
+    return header->frameStoredFlag;
+}
+// Clear the frame error, for ex. when the frame is read by user
+bool FreezeFrame::clearError()
+{
+    NV_Data temp;
+    NV_Data* header = HEADER_PTR;
+    __disable_irq();
+    memcpy(&temp, header, sizeof(NV_Data));
+    __enable_irq();
+    temp.frameStoredFlag = 0;
+    int i = flashWrite(&temp, sizeof(NV_Data), sector_start_adress[HEADER_SECTOR], HEADER_SECTOR);
+    return (i == 0);
+}