Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Diff: DataStructures/DataStructures.cpp
- Revision:
- 38:8efacce315ae
--- /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(©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);
+}
