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);
}
