System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
DataStructures/DataStructures.cpp
- Committer:
- pspatel321
- Date:
- 2015-02-11
- Revision:
- 39:ddf38df9699e
- Parent:
- 38:8efacce315ae
File content as of revision 39:ddf38df9699e:
#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(©Buffer[i], &(frame.param), sizeof(Profile_checkSum)); __enable_irq(); continue; // Skip to next } __disable_irq(); memcpy(©Buffer[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); }