Commit a2ec2372 authored by Theodor-Adrian Stana's avatar Theodor-Adrian Stana

Store settings to flash

parent 1e7f7e98
/**************************************************************************//**
* @file eeprom_emulation.c
* @brief EEPROM Emulation Demo Application functions
* @author Silicon Labs
* @version 1.10
******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
* obligation to support this Software. Silicon Labs is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Silicon Labs will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
******************************************************************************/
#include <stdlib.h>
#include "em_msc.h"
#include "em_assert.h"
#include "eeprom_emulation.h"
/*******************************************************************************
************************** GLOBAL VARIABLES *******************************
******************************************************************************/
/* Variables to keep track of what pages are active and receiving. */
static int activePageNumber = -1;
static int receivingPageNumber = -1;
static bool initialized = false;
/* Array of all pages allocated to the eeprom */
static EE_Page_TypeDef pages[MAX_NUMBER_OF_PAGES];
static int16_t numberOfVariablesDeclared = 0;
static int16_t numberOfActiveVariables = 0;
static int16_t numberOfPagesAllocated;
/*******************************************************************************
************************** LOCAL FUNCTIONS ********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Checks if all the bits in the page are 1's.
*
* @param[in]
* Pointer to the page that is to be validated.
*
* @return
* Returns the result of the check.
*
* @verbatim
* true - All bits in the page are 1's.
* false - One or more bits in the page are 0's.
* @endverbatim
*******************************************************************************/
static bool EE_validateIfErased(EE_Page_TypeDef *page)
{
uint32_t *address = page->startAddress;
/* Iterate through all the words of the page, and validate that all bits are set. */
while (address <= page->endAddress)
{
if (*address != 0xFFFFFFFF)
{
/* 0 bit detected */
return false;
}
address++;
}
/* All bits are 1's. */
return true;
}
/***************************************************************************//**
* @brief
* Writes the desired data to the specified page.
*
* @param[in] page
* Pointer to the page to write variable to.
*
* @param[in] virtualAddress
* The virtual address of the variable to be written.
*
* @param[in] writeData
* The data to be associated with the given virtual address.
*
* @return
* Returns whether the write has been a success or not. In normal operation
* a failed write indicates that the currently active page is full.
******************************************************************************/
static bool EE_WriteToPage(EE_Page_TypeDef *page, uint16_t virtualAddress, uint16_t writeData)
{
/* Start at the second word. The fist one is reserved for status and erase count. */
uint32_t *address = page->startAddress + 1;
uint32_t virtualAddressAndData;
/* Iterate through the page from the beginning, and stop at the fist empty word. */
while (address <= page->endAddress)
{
/* Empty word found. */
if (*address == 0xFFFFFFFF)
{
/* The virtual address and data is combined to a full word. */
virtualAddressAndData = ((uint32_t)(virtualAddress << 16) & 0xFFFF0000) | (uint32_t)(writeData);
/* Make sure that the write to flash is a success. */
if (MSC_WriteWord(address, &virtualAddressAndData, SIZE_OF_VARIABLE) != mscReturnOk)
{
/* Write failed. Halt for debug trace, if enabled. */
EFM_ASSERT(0);
return false;
}
/* Data written successfully. */
return true;
}
else
{
address++;
}
}
/* Reached the end of the page without finding any empty words. */
return false;
}
/***************************************************************************//**
* @brief
* Erase all pages allocated to the eeprom emulator, and force page 0 to be
* the active page.
*
* @return
* Returns true if the format was successful.
******************************************************************************/
bool EE_Format(uint32_t numberOfPages)
{
uint32_t eraseCount = 0xFF000001;
int i;
msc_Return_TypeDef retStatus;
/* Make the number of pages allocated accessible throughout the file. */
numberOfPagesAllocated = numberOfPages;
/* Initialize the address of each page */
for (i = 0; i < numberOfPagesAllocated; i++)
{
pages[i].startAddress = (uint32_t *)(FLASH_SIZE - i * PAGE_SIZE - PAGE_SIZE);
pages[i].endAddress = (uint32_t *)(FLASH_SIZE - i * PAGE_SIZE - 4);
}
/* Erase all pages allocated to the eeprom emulator*/
for (i = numberOfPagesAllocated - 1; i >= 0; i--)
{
/* Validate if the page is already erased, and erase it if not. */
if (!EE_validateIfErased(&pages[i]))
{
/* Erase the page, and return the status if the erase operation is unsuccessful. */
retStatus = MSC_ErasePage(pages[i].startAddress);
if (retStatus != mscReturnOk) {
return false;
}
}
}
/* Page 0 is the active page. */
activePageNumber = 0;
/* There should be no receiving page. */
receivingPageNumber = -1;
/* Write erase count of 1 to the page 0 head. */
retStatus = MSC_WriteWord(pages[activePageNumber].startAddress, &eraseCount, 4);
if (retStatus != mscReturnOk) {
return false;
}
/* Set page status active to page 0. */
retStatus = EE_setPageStatusActive(&pages[activePageNumber]);
if ( retStatus != mscReturnOk ) {
return false;
}
/** Successfully formatted pages */
return true;
}
/***************************************************************************//**
* @brief
* Transfers the most recently written value of each variable, from the active
* to a new receiving page.
*
* @param[in] var
* Pointer to a variable whose data will be written to the first free word of
* the receiving page. If var is a null pointer, this operation will be
* skipped.
*
* @param[in] writeData
* Data to be associated with var's virtual address, if var is not a null
* pointer.
*
* @return
* Returns the status of the last flash operation.
******************************************************************************/
static msc_Return_TypeDef EE_TransferPage(EE_Variable_TypeDef *var, uint16_t writeData)
{
msc_Return_TypeDef retStatus;
uint32_t *activeAddress;
uint32_t *receivingAddress;
bool newVariable;
uint32_t eraseCount;
/* If there is no receiving page predefined, set it to cycle through all allocated pages. */
if (receivingPageNumber == -1)
{
receivingPageNumber = activePageNumber + 1;
if (receivingPageNumber >= numberOfPagesAllocated) {
receivingPageNumber = 0;
}
/* Check if the new receiving page really is erased. */
if (!EE_validateIfErased(&pages[receivingPageNumber]))
{
/* If this page is not truly erased, it means that it has been written to
* from outside this API, this could be an address conflict. */
EFM_ASSERT(0);
MSC_ErasePage(pages[receivingPageNumber].startAddress);
}
}
/* Set the status of the receiving page */
EE_setPageStatusReceiving(&pages[receivingPageNumber]);
/* If a variable was specified, write it to the receiving page */
if (var != NULL)
{
EE_WriteToPage(&pages[receivingPageNumber], var->virtualAddress, writeData);
}
/* Start at the last word. */
activeAddress = pages[activePageNumber].endAddress;
/* Iterate through all words in the active page. Each time a new virtual
* address is found, write it and it's data to the receiving page */
while (activeAddress > pages[activePageNumber].startAddress)
{
/* 0x0000 and 0xFFFF are not valid virtual addresses. */
if ((uint16_t)(*activeAddress >> 16) == 0x0000 || (uint16_t)(*activeAddress >> 16) == 0xFFFF)
{
newVariable = false;
}
/* Omit when transfer is initiated from inside the EE_Init() function. */
else if (var != NULL && (uint16_t)(*activeAddress >> 16) > numberOfVariablesDeclared)
{
/* A virtual address outside the virtual address space, defined by the
* number of variables declared, are considered garbage. */
newVariable = false;
}
else
{
receivingAddress = pages[receivingPageNumber].startAddress + 1;
/* Start at the beginning of the receiving page. Check if the variable is
* already transfered. */
while (receivingAddress <= pages[receivingPageNumber].endAddress)
{
/* Variable found, and is therefore already transferred. */
if ((uint16_t)(*activeAddress >> 16) == (uint16_t)(*receivingAddress >> 16))
{
newVariable = false;
break;
}
/* Empty word found. All transferred variables are checked. */
else if (*receivingAddress == 0xFFFFFFFF)
{
newVariable = true;
break;
}
receivingAddress++;
}
}
if (newVariable)
{
/* Write the new variable to the receiving page. */
EE_WriteToPage(&pages[receivingPageNumber], (uint16_t)(*activeAddress >> 16), (uint16_t)(*activeAddress));
}
activeAddress--;
}
/* Update erase count */
eraseCount = EE_GetEraseCount();
/* If a new page cycle is started, increment the erase count. */
if (receivingPageNumber == 0)
eraseCount++;
/* Set the first byte, in this way the page status is not altered when the erase count is written. */
eraseCount = eraseCount | 0xFF000000;
/* Write the erase count obtained to the active page head. */
retStatus = MSC_WriteWord(pages[receivingPageNumber].startAddress, &eraseCount, 4);
if (retStatus != mscReturnOk) {
return retStatus;
}
/* Erase the old active page. */
retStatus = MSC_ErasePage(pages[activePageNumber].startAddress);
if (retStatus != mscReturnOk) {
return retStatus;
}
/* Set the receiving page to be the new active page. */
retStatus = EE_setPageStatusActive(&pages[receivingPageNumber]);
if (retStatus != mscReturnOk) {
return retStatus;
}
activePageNumber = receivingPageNumber;
receivingPageNumber = -1;
return mscReturnOk;
}
/*******************************************************************************
************************** GLOBAL FUNCTIONS *******************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Should be run once before any other eeprom emulator functions are called.
* It restores the pages to a known good state in case of page status
* corruption after a power loss or another unwanted system reset.
*
* @param[in] numberOfPages
* Number of pages to be allocated to the eeprom emulator for the entire
* lifetime of the application. Must be 2 or greater.
*
* @note
* When choosing the number of pages to assign to the eeprom emulator, it is
* highly recommended to have a good insight into how much data that will be
* written to the eeprom emulator during the application lifetime. Using an
* estimate of this data, and the maximum number of rewrite cycles the flash
* is guaranteed to endure, it should be easy to get a good idea of how many
* pages that are needed to keep flash wear within the recommended level
* throughout the application lifetime.
* It should also be noted that it is critical to have control over what
* areas of the flash that is in use by other parts of the application, to
* avoid possible conflicts and hard-to-find bugs.
*
* @return
* Returns true if the initialization was successful.
******************************************************************************/
bool EE_Init(uint32_t numberOfPages)
{
/* Make sure that the eeprom emulator is only initialized once. More that one
* initialization may result in undefined behavior. */
EFM_ASSERT(!initialized);
initialized = true;
/* Number of pages must be at least 2. */
if (numberOfPages < 2) {
numberOfPages = DEFAULT_NUMBER_OF_PAGES;
}
/* Make the number of pages allocated accessible throughout the file. */
numberOfPagesAllocated = numberOfPages;
/* Initialize the address of each page */
uint32_t i;
for (i = 0; i < numberOfPages; i++)
{
pages[i].startAddress = (uint32_t *)(FLASH_SIZE - i * PAGE_SIZE - PAGE_SIZE);
pages[i].endAddress = (uint32_t *)(FLASH_SIZE - i * PAGE_SIZE - 4);
}
/* Check status of each page */
for (i = 0; i < numberOfPages; i++)
{
switch (EE_getPageStatus(&pages[i]))
{
case eePageStatusActive:
if (activePageNumber == -1)
{
activePageNumber = i;
}
else
{
/* More than one active page found. This is an invalid system state. */
return false;
}
break;
case eePageStatusReceiving:
if (receivingPageNumber == -1)
{
receivingPageNumber = i;
}
else
{
/* More than one receiving page foudn. This is an invalid system state. */
return false;
}
break;
case eePageStatusErased:
/* Validate if the page is really erased, and erase it if not. */
if (!EE_validateIfErased(&pages[i]))
{
MSC_ErasePage(pages[i].startAddress);
}
break;
default:
/* Undefined page status, erase page. */
MSC_ErasePage(pages[i].startAddress);
break;
}
}
/* No receiving or active page found. This is an invalid system state. */
if (receivingPageNumber == -1 && activePageNumber == -1)
{
return false;
}
/* One active page only. All good. */
if (receivingPageNumber == -1)
{
return true;
}
/* One receiving page only. */
else if (activePageNumber == -1)
{
/* Set current receiving page as active. */
activePageNumber = receivingPageNumber;
receivingPageNumber = -1;
EE_setPageStatusActive(&pages[receivingPageNumber]);
}
/* Found exactly one active and one receiving page. */
else
{
/* Transfer variables from active to receiving page. */
EE_TransferPage(NULL, NULL);
}
/* Initialization completed successfully */
return true;
}
/***************************************************************************//**
* @brief
* Read the latest data associated with the given variable.
*
* @note
* If attempting to read from an undeclared variable, or a variable that has
* no valid value written to it, a null value will be returned.
*
* @param[in] var
* Pointer to the variable with the virtual address to look for.
*
* @param[out] readData
* Pointer to the memory area to write the read data to.
*
* @return
* Returns whether the variable given was found or not.
******************************************************************************/
bool EE_Read(EE_Variable_TypeDef *var, uint16_t *readData)
{
/* Make sure that the eeprom emulator is initialized. */
EFM_ASSERT(initialized);
uint32_t *address;
address = (pages[activePageNumber].endAddress);
/* 0x0000 and 0xFFFF are illegal addresses. */
if (var->virtualAddress != 0x0000 && var->virtualAddress != 0xFFFF)
{
/* Iterate through the active page, starting from the end. */
while (address > pages[activePageNumber].startAddress)
{
/* Check if the stored virtual address matches the one wanted. */
if ((uint16_t)(*address >> 16) == var->virtualAddress)
{
/* Correct virtual address found, return the corresponding data. */
*readData = (uint16_t)(*address);
return true;
}
address--;
}
}
/* Variable not found, return null value. */
*readData = 0x0000;
return false;
}
/***************************************************************************//**
* @brief
* Writes the desired data, together with the given variable's virtual address
* to the emulated eeprom memory.
*
* @param[in] var
* Pointer to the variable to associate data with.
*
* @param[in] writeData
* The 16 bit data to write to the flash memory. Any 16 bit data can be sent,
* as long as it is casted to a uint16_t type.
******************************************************************************/
void EE_Write(EE_Variable_TypeDef *var, uint16_t writeData)
{
/* Make sure that the eeprom emulator is initialized. */
EFM_ASSERT(initialized);
/* Make sure that the virtual address is declared and valid. */
EFM_ASSERT(var->virtualAddress <= numberOfVariablesDeclared);
uint16_t readData;
/* Check whether the variable already has a value associated to it. */
if (EE_Read(var, &readData))
{
/* Do not write if data is duplicate. */
if (readData == writeData)
{
return;
}
}
/* Write to flash. */
if (!EE_WriteToPage(&pages[activePageNumber], var->virtualAddress, writeData))
{
/* The write was not successful, which indicates that the active page is full. */
EE_TransferPage(var, writeData);
}
}
/***************************************************************************//**
* @brief
* If the variable no longer is needed, it can be deleted to free flash space.
*
* @note
* The function writes 0x0000 to the virtual address field of all previous
* versions of the input variable. All stored data with virtual address 0x0000
* is marked as garbage, which will be collected on the next page transfer.
*
* @param[in] var
* Pointer to the variable to be deleted from the emulated eeprom.
*******************************************************************************/
void EE_DeleteVariable(EE_Variable_TypeDef *var)
{
/* If the eeprom emulator is not initialized, this function has no meaning. */
if (!initialized)
{
/* Halt for debug trace. */
EFM_ASSERT(0);
return;
}
uint32_t deleteData = 0x0000FFFF;
uint32_t *address = (pages[activePageNumber].endAddress);
/* Keep track if we actually removed a variable */
bool varDeleted = false;
/* Iterate through the active page from the end. */
while (address > pages[activePageNumber].startAddress)
{
/* Write the virtual address 0x0000 to all instances of the chosen variable.
* Since 0x0000 is not a valid virtual address, the variable will not
* transferred to a new page on the next page transfer. */
if ((uint16_t)(*address >> 16) == var->virtualAddress)
{
MSC_WriteWord(address, &deleteData, sizeof deleteData);
varDeleted = true;
}
address--;
}
if (varDeleted) {
numberOfActiveVariables--;
}
}
/***************************************************************************//**
* @brief
* Assign a virtual address to a new variable.
*
* @note
* All variables that is to be used in an application, should be declared
* prior to any write operations to ensure that all variables are transfered
* correctly whenever a page is full. The virtual addresses are assigned to
* the variables according to the order of declaration. This means that in
* case of a system reset, all variables must be declared in the same order on
* each startup to retain its previous virtual address.
*
* @param[in] var
* Pointer to variable to be assigned a virtual address.
* @return
* Returns whether the declaration was successful.
*******************************************************************************/
bool EE_DeclareVariable(EE_Variable_TypeDef *var)
{
if ( numberOfActiveVariables < MAX_ACTIVE_VARIABLES ) {
/* The virtual addresses are assigned according to the order of declaration. */
var->virtualAddress = ++numberOfVariablesDeclared;
numberOfActiveVariables++;
return true;
} else {
return false;
}
}
/***************************************************************************//**
* @brief
* Returns the number of times all pages has been erased.
*
* @note
* The erase count is the number of cycles where all the pages has been
* erased. The value is always written to the 24 LSB of the first word on the
* active page. The value is incremented each time data is transferred to
* page 0.
*
* @return
* Returns the number of complete erase cycles endured.
******************************************************************************/
uint32_t EE_GetEraseCount(void)
{
/* Make sure that there is an active page */
EFM_ASSERT(activePageNumber != -1);
uint32_t eraseCount;
/* The number of erase cycles is the 24 LSB of the first word of the active page. */
eraseCount = (*(pages[activePageNumber].startAddress) & 0x00FFFFFF);
/* if the page has never been erased, return 0. */
if (eraseCount == 0xFFFFFF) {
return 0;
}
return eraseCount;
}
/**************************************************************************//**
* @file eeprom_emulation.h
* @brief EEPROM Emulation Demo Application header file
* @author Silicon Labs
* @version 1.10
******************************************************************************
* @section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
* obligation to support this Software. Silicon Labs is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Silicon Labs will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
******************************************************************************/
#ifndef __EE_H
#define __EE_H
#include <stdbool.h>
#include "em_device.h"
#include "em_msc.h"
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
****************************** DEFINES ************************************
******************************************************************************/
#if defined (_EFM32_GECKO_FAMILY) || defined(_EFM32_TINY_FAMILY)
#define PAGE_SIZE 0x200
#elif defined(_EFM32_GIANT_FAMILY)
#define PAGE_SIZE ((FLASH_SIZE >= 0x80000) ? 0x1000 : 0x800)
#else
#pragma error "Unknown page size"
#endif
#define DEFAULT_NUMBER_OF_PAGES 2
#define MAX_NUMBER_OF_PAGES (FLASH_SIZE/PAGE_SIZE)
#define SIZE_OF_DATA 2 /* 2 bytes */
#define SIZE_OF_VIRTUAL_ADDRESS 2 /* 2 bytes */
#define SIZE_OF_VARIABLE (SIZE_OF_DATA + SIZE_OF_VIRTUAL_ADDRESS) /* 4 bytes */
#define MAX_ACTIVE_VARIABLES (PAGE_SIZE / SIZE_OF_VARIABLE)
#define PAGE_STATUS_ERASED 0xFF
#define PAGE_STATUS_RECEIVING 0xAA
#define PAGE_STATUS_ACTIVE 0x00
/*******************************************************************************
*************************** GLOBAL VARIABLES ******************************
******************************************************************************/
/* Since the data to be written to flash must be read from ram, the data used to
* set the pages' status, is explicitly written to the ram beforehand. */
static uint32_t pageStatusActiveValue = ((uint32_t) PAGE_STATUS_ACTIVE << 24) | 0x00FFFFFF;
static uint32_t pageStatusReceivingValue = ((uint32_t) PAGE_STATUS_RECEIVING << 24) | 0x00FFFFFF;
/*******************************************************************************
******************************* ENUMS *************************************
******************************************************************************/
typedef enum
{
eePageStatusErased = PAGE_STATUS_ERASED,
eePageStatusReceiving = PAGE_STATUS_RECEIVING,
eePageStatusActive = PAGE_STATUS_ACTIVE,
} EE_PageStatus_TypeDef;
/*******************************************************************************
****************************** STRUCTS ************************************
******************************************************************************/
typedef struct
{
/* Each variable is assigned a unique virtual address automatically when first
* written to, or when using the declare function. */
uint16_t virtualAddress;
} EE_Variable_TypeDef;
typedef struct
{
uint32_t *startAddress;
uint32_t *endAddress;
} EE_Page_TypeDef;
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
bool EE_Init(uint32_t);
bool EE_Format(uint32_t);
bool EE_Read(EE_Variable_TypeDef *var, uint16_t *readData);
void EE_Write(EE_Variable_TypeDef *var, uint16_t writeData);
bool EE_DeclareVariable(EE_Variable_TypeDef *var);
void EE_DeleteVariable(EE_Variable_TypeDef *var);
uint32_t EE_GetEraseCount(void);
/***************************************************************************//**
* @brief
* Returns the page status of the given page.
*
* @param[in] page
* Pointer to the page whose status to be returned.
*
* @return
* Returns the status of the given page.
******************************************************************************/
__STATIC_INLINE EE_PageStatus_TypeDef EE_getPageStatus(EE_Page_TypeDef *page)
{
return (EE_PageStatus_TypeDef)((*(page->startAddress) >> 24) & 0xFF);
}
/***************************************************************************//**
* @brief
* Sets status of the given page to active.
*
* @param[in] page
* Pointer to the page whose status to be altered.
*
* @return
* Returns the status of the flash operation.
******************************************************************************/
__STATIC_INLINE msc_Return_TypeDef EE_setPageStatusActive(EE_Page_TypeDef *page)
{
return MSC_WriteWord(page->startAddress, &pageStatusActiveValue, SIZE_OF_VARIABLE);
}
/***************************************************************************//**
* @brief
* Sets status of the given page to receiving.
*
* @param[in] page
* Pointer to the page whose status to be altered.
*
* @return
* Returns the status of the flash operation.
******************************************************************************/
__STATIC_INLINE msc_Return_TypeDef EE_setPageStatusReceiving(EE_Page_TypeDef *page)
{
return MSC_WriteWord(page->startAddress, &pageStatusReceivingValue, SIZE_OF_VARIABLE);
}
#ifdef __cplusplus
}
#endif
#endif /* __EE_H */
......@@ -144,6 +144,7 @@ C_SRC += \
../common/emlib/src/em_timer.c \
../common/emlib/src/em_usart.c \
../common/emlib/src/em_leuart.c \
../common/emlib/src/em_msc.c \
../common/emdrv/sleep/src/sleep.c \
../common/drivers/dmactrl.c \
../common/drivers/lcd.c \
......@@ -172,6 +173,7 @@ C_SRC += \
../common/gfx/gfx.c \
../common/gfx/ui.c \
../common/sincos.c \
../common/eeprom_emulation.c \
../common/usb/src/em_usbd.c \
../common/usb/src/em_usbdch9.c \
../common/usb/src/em_usbhal.c \
......
......@@ -27,31 +27,77 @@
#include <task.h>
setting_t setting_gps_on = { "GPS on", 1, 2 };
setting_t setting_coord_style = { "Coord style", 1, 3 };
setting_t setting_gps_sets_time = { "GPS sets time", 1, 2 };
#include <eeprom_emulation.h>
setting_t setting_gps_on = { "GPS on", 1, 2, 0 };
setting_t setting_coord_style = { "Coord style", 1, 3, 0 };
setting_t setting_gps_sets_time = { "GPS sets time", 1, 2, 0 };
/* Settings with nrvals == 0 do not wrap around, they are set externally */
setting_t setting_gmt_ofs_hr = { "GMT offset hours" , 0, 0 };
setting_t setting_gmt_ofs_min = { "GMT offset minutes", 0, 0 };
setting_t setting_gmt_ofs_hr = { "GMT ofs hrs", 0, 0, 0 };
setting_t setting_gmt_ofs_min = { "GMT ofs mins", 0, 0, 0 };
static EE_Variable_TypeDef gps_on, coord_style, gps_sets_time,
gmt_ofs_hr, gmt_ofs_min;
void setting_init()
{
/* Start adding virtual addresses to allocated variables */
EE_DeclareVariable(&gps_on);
EE_DeclareVariable(&coord_style);
EE_DeclareVariable(&gps_sets_time);
EE_DeclareVariable(&gmt_ofs_hr);
EE_DeclareVariable(&gmt_ofs_min);
/*
* Place these virtual addresses to the RAM-stored structs, so we can pass
* them to setting_apply() when called
*/
setting_gps_on.fladdr = gps_on.virtualAddress;
setting_coord_style.fladdr = coord_style.virtualAddress;
setting_gps_sets_time.fladdr = gps_sets_time.virtualAddress;
setting_gmt_ofs_hr.fladdr = gmt_ofs_hr.virtualAddress;
setting_gmt_ofs_min.fladdr = gmt_ofs_min.virtualAddress;
/*
* EE_Init() fails if the virtual addresses are not found in the flash. If
* it fails, we write the default setting values. Otherwise, we apply the
* settings in the flash to the setting values in RAM
*/
if (!EE_Init(2)) {
EE_Format(2);
EE_Write(&gps_on, setting_gps_on.val);
EE_Write(&coord_style, setting_coord_style.val);
EE_Write(&gps_sets_time, setting_gps_sets_time.val);
EE_Write(&gmt_ofs_hr, setting_gmt_ofs_hr.val);
EE_Write(&gmt_ofs_min, setting_gmt_ofs_min.val);
} else {
EE_Read(&gps_on, &setting_gps_on.val);
EE_Read(&coord_style, &setting_coord_style.val);
EE_Read(&gps_sets_time, &setting_gps_sets_time.val);
EE_Read(&gmt_ofs_hr, &setting_gmt_ofs_hr.val);
EE_Read(&gmt_ofs_min, &setting_gmt_ofs_min.val);
}
}
void setting_change(setting_t *setting)
{
int v = setting->val;
char s[16];
v++;
v %= setting->nrvals;
sprintf(s, ": %d", v);
setting_apply(setting, v);
}
void setting_apply(setting_t *setting, int val)
{
EE_Variable_TypeDef eevar;
eevar.virtualAddress = setting->fladdr;
taskENTER_CRITICAL();
setting->val = val;
EE_Write(&eevar, val);
taskEXIT_CRITICAL();
}
......
......@@ -30,10 +30,13 @@
#include "application.h"
#include <stdint.h>
typedef struct setting {
char name[16];
int val;
int nrvals;
uint16_t val; // uint16_t to comply to eeprom_emulation code
uint16_t nrvals;
uint16_t fladdr;
} setting_t;
extern application set_time;
......@@ -47,6 +50,7 @@ extern setting_t setting_gmt_ofs_hr;
extern setting_t setting_gmt_ofs_min;
extern setting_t setting_gps_sets_time;
void setting_init();
void setting_change(setting_t *setting);
void setting_apply(setting_t *setting, int val);
int setting_get(setting_t *setting);
......
......@@ -27,6 +27,7 @@
#include <em_chip.h>
#include <em_gpio.h>
#include <em_cmu.h>
#include <em_msc.h>
#include <sleep.h>
#include <drivers/i2cdrv.h>
......@@ -40,6 +41,7 @@
#include <gfx/ui.h>
#include <apps/app_list.h>
#include "settings/settings.h"
#include "battery_task.h"
#include "blight_task.h"
#include "state.h"
......@@ -55,13 +57,16 @@ int main(void)
CHIP_Init();
// Enable clocks
//CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO);
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO);
CMU_ClockEnable(cmuClock_HFPER, true);
CMU_ClockEnable(cmuClock_GPIO, true);
I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT;
I2CDRV_Init(&i2cInit);
MSC_Init();
setting_init();
#ifdef DEBUG
usbdbg_init();
#endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment