mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-18 03:52:11 +01:00
logfs+flash: add log structured filesystem for PiOS
A new flash driver abstraction is also provided to allow for future support of other types of flash device under the filesystem. Conflicts: flight/PiOS/Common/pios_flash_jedec.c
This commit is contained in:
parent
20921e48ca
commit
5ef0988137
@ -8,6 +8,7 @@
|
||||
*
|
||||
* @file pios_flash_w25x.c
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
|
||||
* @brief Driver for talking to W25X flash chip (and most JEDEC chips)
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
@ -28,6 +29,7 @@
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "pios.h"
|
||||
#include "pios_flash_jedec_priv.h"
|
||||
|
||||
#define JEDEC_WRITE_ENABLE 0x06
|
||||
#define JEDEC_WRITE_DISABLE 0x04
|
||||
@ -67,58 +69,78 @@ struct jedec_flash_dev {
|
||||
enum pios_jedec_dev_magic magic;
|
||||
};
|
||||
|
||||
//! Global structure for this flash device
|
||||
struct jedec_flash_dev * flash_dev;
|
||||
|
||||
//! Private functions
|
||||
static int32_t PIOS_Flash_Jedec_Validate(struct jedec_flash_dev * dev);
|
||||
static int32_t PIOS_Flash_Jedec_Validate(struct jedec_flash_dev * flash_dev);
|
||||
static struct jedec_flash_dev * PIOS_Flash_Jedec_alloc(void);
|
||||
static int32_t PIOS_Flash_Jedec_ClaimBus();
|
||||
static int32_t PIOS_Flash_Jedec_ReleaseBus();
|
||||
static int32_t PIOS_Flash_Jedec_WriteEnable();
|
||||
static int32_t PIOS_Flash_Jedec_Busy() ;
|
||||
|
||||
static int32_t PIOS_Flash_Jedec_ReadID(struct jedec_flash_dev * flash_dev);
|
||||
static int32_t PIOS_Flash_Jedec_ReadStatus(struct jedec_flash_dev * flash_dev);
|
||||
static int32_t PIOS_Flash_Jedec_ClaimBus(struct jedec_flash_dev * flash_dev);
|
||||
static int32_t PIOS_Flash_Jedec_ReleaseBus(struct jedec_flash_dev * flash_dev);
|
||||
static int32_t PIOS_Flash_Jedec_WriteEnable(struct jedec_flash_dev * flash_dev);
|
||||
static int32_t PIOS_Flash_Jedec_Busy(struct jedec_flash_dev * flash_dev);
|
||||
|
||||
/**
|
||||
* @brief Allocate a new device
|
||||
*/
|
||||
static struct jedec_flash_dev * PIOS_Flash_Jedec_alloc(void)
|
||||
{
|
||||
struct jedec_flash_dev * jedec_dev;
|
||||
struct jedec_flash_dev * flash_dev;
|
||||
|
||||
jedec_dev = (struct jedec_flash_dev *)pvPortMalloc(sizeof(*jedec_dev));
|
||||
if (!jedec_dev) return (NULL);
|
||||
flash_dev = (struct jedec_flash_dev *)pvPortMalloc(sizeof(*flash_dev));
|
||||
if (!flash_dev) return (NULL);
|
||||
|
||||
jedec_dev->claimed = false;
|
||||
jedec_dev->magic = PIOS_JEDEC_DEV_MAGIC;
|
||||
flash_dev->claimed = false;
|
||||
flash_dev->magic = PIOS_JEDEC_DEV_MAGIC;
|
||||
#if defined(FLASH_FREERTOS)
|
||||
jedec_dev->transaction_lock = xSemaphoreCreateMutex();
|
||||
flash_dev->transaction_lock = xSemaphoreCreateMutex();
|
||||
#endif
|
||||
return(jedec_dev);
|
||||
return(flash_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validate the handle to the spi device
|
||||
*/
|
||||
static int32_t PIOS_Flash_Jedec_Validate(struct jedec_flash_dev * dev) {
|
||||
if (dev == NULL)
|
||||
static int32_t PIOS_Flash_Jedec_Validate(struct jedec_flash_dev * flash_dev) {
|
||||
if (flash_dev == NULL)
|
||||
return -1;
|
||||
if (dev->magic != PIOS_JEDEC_DEV_MAGIC)
|
||||
if (flash_dev->magic != PIOS_JEDEC_DEV_MAGIC)
|
||||
return -2;
|
||||
if (dev->spi_id == 0)
|
||||
if (flash_dev->spi_id == 0)
|
||||
return -3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the flash device and enable write access
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_Init(uint32_t * flash_id, uint32_t spi_id, uint32_t slave_num, const struct pios_flash_jedec_cfg * cfg)
|
||||
{
|
||||
struct jedec_flash_dev * flash_dev = PIOS_Flash_Jedec_alloc();
|
||||
if (flash_dev == NULL)
|
||||
return -1;
|
||||
|
||||
flash_dev->spi_id = spi_id;
|
||||
flash_dev->slave_num = slave_num;
|
||||
flash_dev->cfg = cfg;
|
||||
|
||||
device_type = PIOS_Flash_Jedec_ReadID(flash_dev);
|
||||
if (device_type == 0)
|
||||
return -1;
|
||||
|
||||
/* Give back a handle to this flash device */
|
||||
*flash_id = (uint32_t) flash_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Claim the SPI bus for flash use and assert CS pin
|
||||
* @return 0 for sucess, -1 for failure to get semaphore
|
||||
*/
|
||||
static int32_t PIOS_Flash_Jedec_ClaimBus()
|
||||
static int32_t PIOS_Flash_Jedec_ClaimBus(struct jedec_flash_dev * flash_dev)
|
||||
{
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_SPI_ClaimBus(flash_dev->spi_id) < 0)
|
||||
return -1;
|
||||
|
||||
@ -131,10 +153,8 @@ static int32_t PIOS_Flash_Jedec_ClaimBus()
|
||||
/**
|
||||
* @brief Release the SPI bus sempahore and ensure flash chip not using bus
|
||||
*/
|
||||
static int32_t PIOS_Flash_Jedec_ReleaseBus()
|
||||
static int32_t PIOS_Flash_Jedec_ReleaseBus(struct jedec_flash_dev * flash_dev)
|
||||
{
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
PIOS_SPI_RC_PinSet(flash_dev->spi_id, flash_dev->slave_num, 1);
|
||||
PIOS_SPI_ReleaseBus(flash_dev->spi_id);
|
||||
flash_dev->claimed = false;
|
||||
@ -145,9 +165,9 @@ static int32_t PIOS_Flash_Jedec_ReleaseBus()
|
||||
* @brief Returns if the flash chip is busy
|
||||
* @returns -1 for failure, 0 for not busy, 1 for busy
|
||||
*/
|
||||
static int32_t PIOS_Flash_Jedec_Busy()
|
||||
static int32_t PIOS_Flash_Jedec_Busy(struct jedec_flash_dev * flash_dev)
|
||||
{
|
||||
int32_t status = PIOS_Flash_Jedec_ReadStatus();
|
||||
int32_t status = PIOS_Flash_Jedec_ReadStatus(flash_dev);
|
||||
if (status < 0)
|
||||
return -1;
|
||||
return status & JEDEC_STATUS_BUSY;
|
||||
@ -157,52 +177,87 @@ static int32_t PIOS_Flash_Jedec_Busy()
|
||||
* @brief Execute the write enable instruction and returns the status
|
||||
* @returns 0 if successful, -1 if unable to claim bus
|
||||
*/
|
||||
static int32_t PIOS_Flash_Jedec_WriteEnable()
|
||||
static int32_t PIOS_Flash_Jedec_WriteEnable(struct jedec_flash_dev * flash_dev)
|
||||
{
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
uint8_t out[] = {JEDEC_WRITE_ENABLE};
|
||||
if(PIOS_Flash_Jedec_ClaimBus() != 0)
|
||||
return -1;
|
||||
PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL);
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read the status register from flash chip and return it
|
||||
*/
|
||||
static int32_t PIOS_Flash_Jedec_ReadStatus(struct jedec_flash_dev * flash_dev)
|
||||
{
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) < 0)
|
||||
return -1;
|
||||
|
||||
uint8_t out[2] = {JEDEC_READ_STATUS, 0};
|
||||
uint8_t in[2] = {0,0};
|
||||
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,in,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -2;
|
||||
}
|
||||
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
return in[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the flash device and enable write access
|
||||
* @brief Read the status register from flash chip and return it
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_Init(uint32_t spi_id, uint32_t slave_num, const struct pios_flash_jedec_cfg * cfg)
|
||||
static int32_t PIOS_Flash_Jedec_ReadID(struct jedec_flash_dev * flash_dev)
|
||||
{
|
||||
flash_dev = PIOS_Flash_Jedec_alloc();
|
||||
if(flash_dev == NULL)
|
||||
return -1;
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) < 0)
|
||||
return -2;
|
||||
|
||||
flash_dev->spi_id = spi_id;
|
||||
flash_dev->slave_num = slave_num;
|
||||
flash_dev->cfg = cfg;
|
||||
uint8_t out[] = {JEDEC_DEVICE_ID, 0, 0, 0};
|
||||
uint8_t in[4];
|
||||
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,in,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -3;
|
||||
}
|
||||
|
||||
device_type = PIOS_Flash_Jedec_ReadID();
|
||||
if(device_type == 0)
|
||||
return -1;
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
return 0;
|
||||
flash_dev->device_type = in[1];
|
||||
flash_dev->capacity = in[3];
|
||||
|
||||
return in[1];
|
||||
}
|
||||
|
||||
/**********************************
|
||||
*
|
||||
* Provide a PIOS flash driver API
|
||||
*
|
||||
*********************************/
|
||||
#include "pios_flash.h"
|
||||
|
||||
#if FLASH_USE_FREERTOS_LOCKS
|
||||
|
||||
/**
|
||||
* @brief Grab the semaphore to perform a transaction
|
||||
* @return 0 for success, -1 for timeout
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_StartTransaction()
|
||||
static int32_t PIOS_Flash_Jedec_StartTransaction(uint32_t flash_id)
|
||||
{
|
||||
#if defined(FLASH_FREERTOS)
|
||||
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
|
||||
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
if(xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE)
|
||||
return -1;
|
||||
return -2;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -210,60 +265,34 @@ int32_t PIOS_Flash_Jedec_StartTransaction()
|
||||
* @brief Release the semaphore to perform a transaction
|
||||
* @return 0 for success, -1 for timeout
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_EndTransaction()
|
||||
static int32_t PIOS_Flash_Jedec_EndTransaction(uint32_t flash_id)
|
||||
{
|
||||
#if defined(FLASH_FREERTOS)
|
||||
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
|
||||
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
#if defined(PIOS_INCLUDE_FREERTOS)
|
||||
if(xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE)
|
||||
return -1;
|
||||
return -2;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the status register from flash chip and return it
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_ReadStatus()
|
||||
{
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
#else /* FLASH_USE_FREERTOS_LOCKS */
|
||||
|
||||
uint8_t out[2] = {JEDEC_READ_STATUS, 0};
|
||||
uint8_t in[2] = {0,0};
|
||||
if(PIOS_Flash_Jedec_ClaimBus() < 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,in,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
return -2;
|
||||
static int32_t PIOS_Flash_Jedec_StartTransaction(uint32_t flash_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
return in[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the status register from flash chip and return it
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_ReadID()
|
||||
static int32_t PIOS_Flash_Jedec_EndTransaction(uint32_t flash_id)
|
||||
{
|
||||
uint8_t out[] = {JEDEC_DEVICE_ID, 0, 0, 0};
|
||||
uint8_t in[4];
|
||||
if (PIOS_Flash_Jedec_ClaimBus() < 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,in,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
return -2;
|
||||
return 0;
|
||||
}
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
|
||||
flash_dev->device_type = in[1];
|
||||
flash_dev->capacity = in[3];
|
||||
return in[1];
|
||||
}
|
||||
#endif /* FLASH_USE_FREERTOS_LOCKS */
|
||||
|
||||
/**
|
||||
* @brief Erase a sector on the flash chip
|
||||
@ -272,29 +301,31 @@ int32_t PIOS_Flash_Jedec_ReadID()
|
||||
* @retval -1 if unable to claim bus
|
||||
* @retval
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_EraseSector(uint32_t addr)
|
||||
static int32_t PIOS_Flash_Jedec_EraseSector(uint32_t flash_id, uint32_t addr)
|
||||
{
|
||||
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
|
||||
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
uint8_t ret;
|
||||
uint8_t out[] = {flash_dev->cfg->sector_erase, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff};
|
||||
|
||||
if((ret = PIOS_Flash_Jedec_WriteEnable()) != 0)
|
||||
if ((ret = PIOS_Flash_Jedec_WriteEnable(flash_dev)) != 0)
|
||||
return ret;
|
||||
|
||||
if(PIOS_Flash_Jedec_ClaimBus() != 0)
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -2;
|
||||
}
|
||||
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
// Keep polling when bus is busy too
|
||||
while(PIOS_Flash_Jedec_Busy() != 0) {
|
||||
while (PIOS_Flash_Jedec_Busy(flash_dev) != 0) {
|
||||
#if defined(FLASH_FREERTOS)
|
||||
vTaskDelay(1);
|
||||
#endif
|
||||
@ -307,30 +338,32 @@ int32_t PIOS_Flash_Jedec_EraseSector(uint32_t addr)
|
||||
* @brief Execute the whole chip
|
||||
* @returns 0 if successful, -1 if unable to claim bus
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_EraseChip()
|
||||
static int32_t PIOS_Flash_Jedec_EraseChip(uint32_t flash_id)
|
||||
{
|
||||
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
|
||||
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
uint8_t ret;
|
||||
uint8_t out[] = {flash_dev->cfg->chip_erase};
|
||||
|
||||
if((ret = PIOS_Flash_Jedec_WriteEnable()) != 0)
|
||||
if ((ret = PIOS_Flash_Jedec_WriteEnable(flash_dev)) != 0)
|
||||
return ret;
|
||||
|
||||
if(PIOS_Flash_Jedec_ClaimBus() != 0)
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -2;
|
||||
}
|
||||
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
// Keep polling when bus is busy too
|
||||
int i = 0;
|
||||
while(PIOS_Flash_Jedec_Busy() != 0) {
|
||||
while (PIOS_Flash_Jedec_Busy(flash_dev) != 0) {
|
||||
#if defined(FLASH_FREERTOS)
|
||||
vTaskDelay(1);
|
||||
if ((i++) % 100 == 0)
|
||||
@ -356,8 +389,10 @@ int32_t PIOS_Flash_Jedec_EraseChip()
|
||||
* @retval -2 Size exceeds 256 bytes
|
||||
* @retval -3 Length to write would wrap around page boundary
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_WriteData(uint32_t addr, uint8_t * data, uint16_t len)
|
||||
static int32_t PIOS_Flash_Jedec_WriteData(uint32_t flash_id, uint32_t addr, uint8_t * data, uint16_t len)
|
||||
{
|
||||
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
|
||||
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
@ -372,41 +407,41 @@ int32_t PIOS_Flash_Jedec_WriteData(uint32_t addr, uint8_t * data, uint16_t len)
|
||||
if(((addr & 0xff) + len) > 0x100)
|
||||
return -3;
|
||||
|
||||
if((ret = PIOS_Flash_Jedec_WriteEnable()) != 0)
|
||||
if ((ret = PIOS_Flash_Jedec_WriteEnable(flash_dev)) != 0)
|
||||
return ret;
|
||||
|
||||
/* Execute write page command and clock in address. Keep CS asserted */
|
||||
if(PIOS_Flash_Jedec_ClaimBus() != 0)
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Clock out data to flash */
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,data,NULL,len,NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
// Keep polling when bus is busy too
|
||||
#if defined(FLASH_FREERTOS)
|
||||
while(PIOS_Flash_Jedec_Busy() != 0) {
|
||||
while (PIOS_Flash_Jedec_Busy(flash_dev) != 0) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
#else
|
||||
|
||||
// Query status this way to prevent accel chip locking us out
|
||||
if(PIOS_Flash_Jedec_ClaimBus() < 0)
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) < 0)
|
||||
return -1;
|
||||
|
||||
PIOS_SPI_TransferByte(flash_dev->spi_id, JEDEC_READ_STATUS);
|
||||
while(PIOS_SPI_TransferByte(flash_dev->spi_id, JEDEC_READ_STATUS) & JEDEC_STATUS_BUSY);
|
||||
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
@ -422,8 +457,10 @@ int32_t PIOS_Flash_Jedec_WriteData(uint32_t addr, uint8_t * data, uint16_t len)
|
||||
* @retval -2 Size exceeds 256 bytes
|
||||
* @retval -3 Length to write would wrap around page boundary
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_WriteChunks(uint32_t addr, struct pios_flash_chunk * p_chunk, uint32_t num)
|
||||
static int32_t PIOS_Flash_Jedec_WriteChunks(uint32_t flash_id, uint32_t addr, struct pios_flash_chunk chunks[], uint32_t num)
|
||||
{
|
||||
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
|
||||
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
@ -433,7 +470,7 @@ int32_t PIOS_Flash_Jedec_WriteChunks(uint32_t addr, struct pios_flash_chunk * p_
|
||||
/* Can only write one page at a time */
|
||||
uint32_t len = 0;
|
||||
for(uint32_t i = 0; i < num; i++)
|
||||
len += p_chunk[i].len;
|
||||
len += chunks[i].len;
|
||||
|
||||
if(len > 0x100)
|
||||
return -2;
|
||||
@ -442,29 +479,29 @@ int32_t PIOS_Flash_Jedec_WriteChunks(uint32_t addr, struct pios_flash_chunk * p_
|
||||
if(((addr & 0xff) + len) > 0x100)
|
||||
return -3;
|
||||
|
||||
if((ret = PIOS_Flash_Jedec_WriteEnable()) != 0)
|
||||
if ((ret = PIOS_Flash_Jedec_WriteEnable(flash_dev)) != 0)
|
||||
return ret;
|
||||
|
||||
/* Execute write page command and clock in address. Keep CS asserted */
|
||||
if(PIOS_Flash_Jedec_ClaimBus() != 0)
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < num; i++) {
|
||||
struct pios_flash_chunk * chunk = &p_chunk[i];
|
||||
struct pios_flash_chunk * chunk = &chunks[i];
|
||||
|
||||
/* Clock out data to flash */
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,chunk->addr,NULL,chunk->len,NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
// Skip checking for busy with this to get OS running again fast
|
||||
|
||||
@ -479,29 +516,43 @@ int32_t PIOS_Flash_Jedec_WriteChunks(uint32_t addr, struct pios_flash_chunk * p_
|
||||
* @return Zero if success or error code
|
||||
* @retval -1 Unable to claim SPI bus
|
||||
*/
|
||||
int32_t PIOS_Flash_Jedec_ReadData(uint32_t addr, uint8_t * data, uint16_t len)
|
||||
static int32_t PIOS_Flash_Jedec_ReadData(uint32_t flash_id, uint32_t addr, uint8_t * data, uint16_t len)
|
||||
{
|
||||
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
|
||||
|
||||
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
|
||||
return -1;
|
||||
|
||||
if(PIOS_Flash_Jedec_ClaimBus() == -1)
|
||||
if (PIOS_Flash_Jedec_ClaimBus(flash_dev) == -1)
|
||||
return -1;
|
||||
|
||||
/* Execute read command and clock in address. Keep CS asserted */
|
||||
uint8_t out[] = {JEDEC_READ_DATA, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff};
|
||||
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Copy the transfer data to the buffer */
|
||||
if(PIOS_SPI_TransferBlock(flash_dev->spi_id,NULL,data,len,NULL) < 0) {
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
return -3;
|
||||
}
|
||||
|
||||
PIOS_Flash_Jedec_ReleaseBus();
|
||||
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Provide a flash driver to external drivers */
|
||||
const struct pios_flash_driver pios_jedec_flash_driver = {
|
||||
.start_transaction = PIOS_Flash_Jedec_StartTransaction,
|
||||
.end_transaction = PIOS_Flash_Jedec_EndTransaction,
|
||||
.erase_chip = PIOS_Flash_Jedec_EraseChip,
|
||||
.erase_sector = PIOS_Flash_Jedec_EraseSector,
|
||||
.write_chunks = PIOS_Flash_Jedec_WriteChunks,
|
||||
.write_data = PIOS_Flash_Jedec_WriteData,
|
||||
.read_data = PIOS_Flash_Jedec_ReadData,
|
||||
};
|
||||
|
||||
|
990
flight/PiOS/Common/pios_flashfs_logfs.c
Normal file
990
flight/PiOS/Common/pios_flashfs_logfs.c
Normal file
@ -0,0 +1,990 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file pios_flashfs_logfs.c
|
||||
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_FLASHFS Flash Filesystem Function
|
||||
* @{
|
||||
* @brief Log Structured Filesystem for internal or external NOR Flash
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "openpilot.h"
|
||||
#include "uavobjectmanager.h" /* UAVObjHandle, UAVObj* */
|
||||
|
||||
#include "pios_flashfs.h" /* API for flash filesystem */
|
||||
#include "pios_flashfs_logfs_priv.h"
|
||||
|
||||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
/*
|
||||
* Filesystem state data tracked in RAM
|
||||
*/
|
||||
|
||||
struct logfs_state {
|
||||
const struct flashfs_logfs_cfg * cfg;
|
||||
bool mounted;
|
||||
uint8_t active_arena_id;
|
||||
|
||||
/* NOTE: num_active_slots + num_free_slots will not typically add
|
||||
* up to the number of slots in the arena since some of the
|
||||
* slots will be obsolete or otherwise invalidated
|
||||
*/
|
||||
uint16_t num_free_slots; /* slots in free state */
|
||||
uint16_t num_active_slots; /* slots in active state */
|
||||
|
||||
/* Underlying flash driver glue */
|
||||
const struct pios_flash_driver * driver;
|
||||
uint32_t flash_id;
|
||||
};
|
||||
|
||||
static struct logfs_state logfs;
|
||||
|
||||
/*
|
||||
* Internal Utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Return the offset in flash of a particular slot within an arena
|
||||
* @return address of the requested slot
|
||||
*/
|
||||
static uintptr_t logfs_get_addr(uint8_t arena_id, uint16_t slot_id)
|
||||
{
|
||||
PIOS_Assert(arena_id < (logfs.cfg->total_fs_size / logfs.cfg->arena_size));
|
||||
PIOS_Assert(slot_id < (logfs.cfg->arena_size / logfs.cfg->slot_size));
|
||||
|
||||
return (logfs.cfg->start_offset +
|
||||
(arena_id * logfs.cfg->arena_size) +
|
||||
(slot_id * logfs.cfg->slot_size));
|
||||
}
|
||||
|
||||
/*
|
||||
* The bits within these enum values must progress ONLY
|
||||
* from 1 -> 0 so that we can write later ones on top
|
||||
* of earlier ones in NOR flash without an erase cycle.
|
||||
*/
|
||||
enum arena_state {
|
||||
ARENA_STATE_ERASED = 0xEEEEEEEE,
|
||||
ARENA_STATE_RESERVED = 0xE6E6E6E6,
|
||||
ARENA_STATE_ACTIVE = 0x66666666,
|
||||
ARENA_STATE_OBSOLETE = 0x44444444,
|
||||
};
|
||||
|
||||
struct arena_header {
|
||||
uint32_t magic;
|
||||
enum arena_state state;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/****************************************
|
||||
* Arena life-cycle transition functions
|
||||
****************************************/
|
||||
|
||||
/**
|
||||
* @brief Erases all sectors within the given arena and sets arena to erased state.
|
||||
* @return 0 if success, < 0 on failure
|
||||
* @note Must be called while holding the flash transaction lock
|
||||
*/
|
||||
static int32_t logfs_erase_arena(uint8_t arena_id)
|
||||
{
|
||||
uintptr_t arena_addr = logfs_get_addr (arena_id, 0);
|
||||
|
||||
/* Erase all of the sectors in the arena */
|
||||
for (uint8_t sector_id = 0;
|
||||
sector_id < (logfs.cfg->arena_size / logfs.cfg->sector_size);
|
||||
sector_id++) {
|
||||
if (logfs.driver->erase_sector(logfs.flash_id,
|
||||
arena_addr + (sector_id * logfs.cfg->sector_size))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark this arena as fully erased */
|
||||
struct arena_header arena_hdr = {
|
||||
.magic = logfs.cfg->fs_magic,
|
||||
.state = ARENA_STATE_ERASED,
|
||||
};
|
||||
|
||||
if (logfs.driver->write_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof(arena_hdr)) != 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Arena is ready to be activated */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks the given arena as reserved so it can be filled.
|
||||
* @return 0 if success, < 0 on failure
|
||||
* @note Arena must have been previously erased before calling this
|
||||
* @note Must be called while holding the flash transaction lock
|
||||
*/
|
||||
static int32_t logfs_reserve_arena (uint8_t arena_id)
|
||||
{
|
||||
uintptr_t arena_addr = logfs_get_addr (arena_id, 0);
|
||||
|
||||
/* Read in the current arena header */
|
||||
struct arena_header arena_hdr;
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof(arena_hdr)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (arena_hdr.state != ARENA_STATE_ERASED) {
|
||||
/* Arena was not erased, can't reserve it */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Set the arena state to reserved */
|
||||
arena_hdr.state = ARENA_STATE_RESERVED;
|
||||
|
||||
/* Write the arena header back to flash */
|
||||
if (logfs.driver->write_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof(arena_hdr)) != 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Arena is ready to be filled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases all arenas available to this filesystem instance
|
||||
* @return 0 if success, < 0 on failure
|
||||
* @note Must be called while holding the flash transaction lock
|
||||
*/
|
||||
static int32_t logfs_erase_all_arenas()
|
||||
{
|
||||
uint16_t num_arenas = logfs.cfg->total_fs_size / logfs.cfg->arena_size;
|
||||
|
||||
for (uint16_t arena = 0; arena < num_arenas; arena++) {
|
||||
if (logfs_erase_arena(arena) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks the given arena as active so it can be mounted.
|
||||
* @return 0 if success, < 0 on failure
|
||||
* @note Arena must have been previously erased or reserved before calling this
|
||||
* @note Must be called while holding the flash transaction lock
|
||||
*/
|
||||
static int32_t logfs_activate_arena(uint8_t arena_id)
|
||||
{
|
||||
uintptr_t arena_addr = logfs_get_addr(arena_id, 0);
|
||||
|
||||
/* Make sure this arena has been previously erased */
|
||||
struct arena_header arena_hdr;
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof (arena_hdr)) != 0) {
|
||||
/* Failed to read arena header */
|
||||
return -1;
|
||||
}
|
||||
if ((arena_hdr.state != ARENA_STATE_RESERVED) &&
|
||||
(arena_hdr.state != ARENA_STATE_ERASED)) {
|
||||
/* Arena was not erased or reserved, can't activate it */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Mark this arena as active */
|
||||
arena_hdr.state = ARENA_STATE_ACTIVE;
|
||||
if (logfs.driver->write_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof(arena_hdr)) != 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* The arena is now activated and the log may be mounted */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks the given arena as obsolete.
|
||||
* @return 0 if success, < 0 on failure
|
||||
* @note Arena must have been previously active before calling this
|
||||
* @note Must be called while holding the flash transaction lock
|
||||
*/
|
||||
static int32_t logfs_obsolete_arena(uint8_t arena_id)
|
||||
{
|
||||
uintptr_t arena_addr = logfs_get_addr (arena_id, 0);
|
||||
|
||||
/* We shouldn't be retiring the currently active arena */
|
||||
PIOS_Assert(!logfs.mounted);
|
||||
|
||||
/* Make sure this arena was previously active */
|
||||
struct arena_header arena_hdr;
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof (arena_hdr)) != 0) {
|
||||
/* Failed to read arena header */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (arena_hdr.state != ARENA_STATE_ACTIVE) {
|
||||
/* Arena was not previously active, can't obsolete it */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Mark this arena as obsolete */
|
||||
arena_hdr.state = ARENA_STATE_OBSOLETE;
|
||||
if (logfs.driver->write_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof(arena_hdr)) != 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Arena is now obsoleted */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find the first active arena in flash
|
||||
* @return arena_id (>=0) of first active arena
|
||||
* @return -1 if no active arena is found
|
||||
* @return -2 if failed to read arena header
|
||||
* @note Must be called while holding the flash transaction lock
|
||||
*/
|
||||
static int32_t logfs_find_active_arena()
|
||||
{
|
||||
/* Search for the lowest numbered active arena */
|
||||
for (uint8_t arena_id = 0;
|
||||
arena_id < logfs.cfg->total_fs_size / logfs.cfg->arena_size;
|
||||
arena_id++) {
|
||||
uintptr_t arena_addr = logfs_get_addr (arena_id, 0);
|
||||
/* Load the arena header */
|
||||
struct arena_header arena_hdr;
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
arena_addr,
|
||||
(uint8_t *)&arena_hdr,
|
||||
sizeof (arena_hdr)) != 0) {
|
||||
return -2;
|
||||
}
|
||||
if ((arena_hdr.state == ARENA_STATE_ACTIVE) &&
|
||||
(arena_hdr.magic == logfs.cfg->fs_magic)) {
|
||||
/* This is the first active arena */
|
||||
return arena_id;
|
||||
}
|
||||
}
|
||||
|
||||
/* Didn't find an active arena */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The bits within these enum values must progress ONLY
|
||||
* from 1 -> 0 so that we can write later ones on top
|
||||
* of earlier ones in NOR flash without an erase cycle.
|
||||
*/
|
||||
enum slot_state {
|
||||
SLOT_STATE_EMPTY = 0xFFFFFFFF,
|
||||
SLOT_STATE_RESERVED = 0xFAFAFAFA,
|
||||
SLOT_STATE_ACTIVE = 0xAAAAAAAA,
|
||||
SLOT_STATE_OBSOLETE = 0x88888888,
|
||||
};
|
||||
|
||||
struct slot_header {
|
||||
enum slot_state state;
|
||||
uint32_t objid;
|
||||
uint16_t instid;
|
||||
uint16_t size;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* NOTE: Must be called while holding the flash transaction lock */
|
||||
static int32_t logfs_raw_copy_bytes (uintptr_t src_addr, uint16_t src_size, uintptr_t dst_addr)
|
||||
{
|
||||
#define RAW_COPY_BLOCK_SIZE 16
|
||||
uint8_t data_block[RAW_COPY_BLOCK_SIZE];
|
||||
|
||||
while (src_size) {
|
||||
uint16_t blk_size;
|
||||
if (src_size >= RAW_COPY_BLOCK_SIZE) {
|
||||
/* Copy a full block */
|
||||
blk_size = RAW_COPY_BLOCK_SIZE;
|
||||
} else {
|
||||
/* Copy the remainder */
|
||||
blk_size = src_size;
|
||||
}
|
||||
|
||||
/* Read a block of data from source */
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
src_addr,
|
||||
data_block,
|
||||
blk_size) != 0) {
|
||||
/* Failed to read next chunk from source */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write a block of data to destination */
|
||||
if (logfs.driver->write_data(logfs.flash_id,
|
||||
dst_addr,
|
||||
data_block,
|
||||
blk_size) != 0) {
|
||||
/* Failed to write chunk to destination */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Update the src/dst pointers */
|
||||
src_size -= blk_size;
|
||||
src_addr += blk_size;
|
||||
dst_addr += blk_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the entire filesystem full?
|
||||
* true = all slots in the arena are in the ACTIVE state (ie. garbage collection won't free anything)
|
||||
* false = some slots in the arena are either currently free or could be free'd by garbage collection
|
||||
*/
|
||||
static bool logfs_fs_is_full(void)
|
||||
{
|
||||
return (logfs.num_active_slots == (logfs.cfg->arena_size / logfs.cfg->slot_size));
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the log full?
|
||||
* true = there are no unwritten slots left in the log (garbage collection may or may not help)
|
||||
* false = there are still some entirely unused slots left in the log
|
||||
*/
|
||||
static bool logfs_log_is_full(void)
|
||||
{
|
||||
return (logfs.num_free_slots == 0);
|
||||
}
|
||||
|
||||
static int32_t logfs_unmount_log(void)
|
||||
{
|
||||
PIOS_Assert (logfs.mounted);
|
||||
|
||||
logfs.num_active_slots = 0;
|
||||
logfs.num_free_slots = 0;
|
||||
logfs.mounted = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t logfs_mount_log(uint8_t arena_id)
|
||||
{
|
||||
PIOS_Assert (!logfs.mounted);
|
||||
|
||||
logfs.num_active_slots = 0;
|
||||
logfs.num_free_slots = 0;
|
||||
logfs.active_arena_id = arena_id;
|
||||
|
||||
/* Scan the log to find out how full it is */
|
||||
for (uint16_t slot_id = 1;
|
||||
slot_id < (logfs.cfg->arena_size / logfs.cfg->slot_size);
|
||||
slot_id++) {
|
||||
struct slot_header slot_hdr;
|
||||
uintptr_t slot_addr = logfs_get_addr (logfs.active_arena_id, slot_id);
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
slot_addr,
|
||||
(uint8_t *)&slot_hdr,
|
||||
sizeof (slot_hdr)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty slots must be in a continguous block at the
|
||||
* end of the arena.
|
||||
*/
|
||||
PIOS_Assert (slot_hdr.state == SLOT_STATE_EMPTY ||
|
||||
logfs.num_free_slots == 0);
|
||||
|
||||
switch (slot_hdr.state) {
|
||||
case SLOT_STATE_EMPTY:
|
||||
logfs.num_free_slots++;
|
||||
break;
|
||||
case SLOT_STATE_ACTIVE:
|
||||
logfs.num_active_slots++;
|
||||
break;
|
||||
case SLOT_STATE_RESERVED:
|
||||
case SLOT_STATE_OBSOLETE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan is complete, mark the arena mounted */
|
||||
logfs.active_arena_id = arena_id;
|
||||
logfs.mounted = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the flash object setting FS
|
||||
* @return 0 if success, -1 if failure
|
||||
*/
|
||||
int32_t PIOS_FLASHFS_Logfs_Init(uint32_t * fs_id, const struct flashfs_logfs_cfg * cfg, const struct pios_flash_driver * driver, uint32_t flash_id)
|
||||
{
|
||||
PIOS_Assert(cfg);
|
||||
PIOS_Assert(fs_id);
|
||||
PIOS_Assert(driver);
|
||||
|
||||
/* We must have at least 2 arenas for garbage collection to work */
|
||||
PIOS_Assert((cfg->total_fs_size / cfg->arena_size > 1));
|
||||
|
||||
/* Make sure the underlying flash driver provides the minimal set of required methods */
|
||||
PIOS_Assert(driver->start_transaction);
|
||||
PIOS_Assert(driver->end_transaction);
|
||||
PIOS_Assert(driver->erase_sector);
|
||||
PIOS_Assert(driver->write_data);
|
||||
PIOS_Assert(driver->read_data);
|
||||
|
||||
/* Bind configuration parameters to this filesystem instance */
|
||||
logfs.cfg = cfg; /* filesystem configuration */
|
||||
logfs.driver = driver; /* lower-level flash driver */
|
||||
logfs.flash_id = flash_id; /* lower-level flash device id */
|
||||
logfs.mounted = false;
|
||||
|
||||
int8_t rc;
|
||||
|
||||
if (logfs.driver->start_transaction(logfs.flash_id) != 0) {
|
||||
rc = -1;
|
||||
goto out_exit;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
int32_t arena_id;
|
||||
for (uint8_t try = 0; !found && try < 2; try++) {
|
||||
/* Find the active arena */
|
||||
arena_id = logfs_find_active_arena();
|
||||
if (arena_id >= 0) {
|
||||
/* Found the active arena */
|
||||
found = true;
|
||||
break;
|
||||
} else {
|
||||
/* No active arena found, erase and activate arena 0 */
|
||||
if (logfs_erase_arena(0) != 0)
|
||||
break;
|
||||
if (logfs_activate_arena(0) != 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* Still no active arena, something is broken */
|
||||
rc = -2;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* We've found an active arena, mount it */
|
||||
if (logfs_mount_log(arena_id) != 0) {
|
||||
/* Failed to mount the log, something is broken */
|
||||
rc = -3;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Log has been mounted */
|
||||
rc = 0;
|
||||
|
||||
*fs_id = (uint32_t) &logfs;
|
||||
|
||||
out_end_trans:
|
||||
logfs.driver->end_transaction(logfs.flash_id);
|
||||
|
||||
out_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* NOTE: Must be called while holding the flash transaction lock */
|
||||
static int32_t logfs_garbage_collect (void) {
|
||||
PIOS_Assert (logfs.mounted);
|
||||
|
||||
/* Source arena is the active arena */
|
||||
uint8_t src_arena_id = logfs.active_arena_id;
|
||||
|
||||
/* Compute destination arena */
|
||||
uint8_t dst_arena_id = (logfs.active_arena_id + 1) % (logfs.cfg->total_fs_size / logfs.cfg->arena_size);
|
||||
|
||||
/* Erase destination arena */
|
||||
if (logfs_erase_arena (dst_arena_id) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reserve the destination arena so we can start filling it */
|
||||
if (logfs_reserve_arena (dst_arena_id) != 0) {
|
||||
/* Unable to reserve the arena */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Copy active slots from active arena to destination arena */
|
||||
uint16_t dst_slot_id = 1;
|
||||
for (uint16_t src_slot_id = 1;
|
||||
src_slot_id < (logfs.cfg->arena_size / logfs.cfg->slot_size);
|
||||
src_slot_id++) {
|
||||
struct slot_header slot_hdr;
|
||||
uintptr_t src_addr = logfs_get_addr (src_arena_id, src_slot_id);
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
src_addr,
|
||||
(uint8_t *)&slot_hdr,
|
||||
sizeof (slot_hdr)) != 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (slot_hdr.state == SLOT_STATE_ACTIVE) {
|
||||
uintptr_t dst_addr = logfs_get_addr (dst_arena_id, dst_slot_id);
|
||||
if (logfs_raw_copy_bytes(src_addr,
|
||||
sizeof(slot_hdr) + slot_hdr.size,
|
||||
dst_addr) != 0) {
|
||||
/* Failed to copy all bytes */
|
||||
return -4;
|
||||
}
|
||||
dst_slot_id++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Activate the destination arena */
|
||||
if (logfs_activate_arena (dst_arena_id) != 0) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Unmount the source arena */
|
||||
if (logfs_unmount_log () != 0) {
|
||||
return -6;
|
||||
}
|
||||
|
||||
/* Obsolete the source arena */
|
||||
if (logfs_obsolete_arena (src_arena_id) != 0) {
|
||||
return -7;
|
||||
}
|
||||
|
||||
/* Mount the new arena */
|
||||
if (logfs_mount_log (dst_arena_id) != 0) {
|
||||
return -8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NOTE: Must be called while holding the flash transaction lock */
|
||||
static int16_t logfs_object_find_next (struct slot_header * slot_hdr, uint16_t * curr_slot, uint32_t objid, uint16_t instid)
|
||||
{
|
||||
PIOS_Assert(slot_hdr);
|
||||
PIOS_Assert(curr_slot);
|
||||
|
||||
/* First slot in the arena is reserved for arena header, skip it. */
|
||||
if (*curr_slot == 0) *curr_slot = 1;
|
||||
|
||||
for (uint16_t slot_id = *curr_slot;
|
||||
slot_id < (logfs.cfg->arena_size / logfs.cfg->slot_size);
|
||||
slot_id++) {
|
||||
uintptr_t slot_addr = logfs_get_addr (logfs.active_arena_id, slot_id);
|
||||
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
slot_addr,
|
||||
(uint8_t *)slot_hdr,
|
||||
sizeof (*slot_hdr)) != 0) {
|
||||
return -2;
|
||||
}
|
||||
if (slot_hdr->state == SLOT_STATE_EMPTY) {
|
||||
/* We hit the end of the log */
|
||||
break;
|
||||
}
|
||||
if (slot_hdr->state == SLOT_STATE_ACTIVE &&
|
||||
slot_hdr->objid == objid &&
|
||||
slot_hdr->instid == instid) {
|
||||
/* Found what we were looking for */
|
||||
*curr_slot = slot_id;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* No matching entry was found */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* NOTE: Must be called while holding the flash transaction lock */
|
||||
/* OPTIMIZE: could trust that there is at most one active version of every object and terminate the search when we find one */
|
||||
static int8_t logfs_delete_object (uint32_t objid, uint16_t instid)
|
||||
{
|
||||
int8_t rc;
|
||||
|
||||
bool more = true;
|
||||
uint16_t curr_slot_id = 0;
|
||||
do {
|
||||
struct slot_header slot_hdr;
|
||||
switch (logfs_object_find_next (&slot_hdr, &curr_slot_id, objid, instid)) {
|
||||
case 0:
|
||||
/* Found a matching slot. Obsolete it. */
|
||||
slot_hdr.state = SLOT_STATE_OBSOLETE;
|
||||
uintptr_t slot_addr = logfs_get_addr (logfs.active_arena_id, curr_slot_id);
|
||||
|
||||
if (logfs.driver->write_data(logfs.flash_id,
|
||||
slot_addr,
|
||||
(uint8_t *)&slot_hdr,
|
||||
sizeof(slot_hdr)) != 0) {
|
||||
rc = -2;
|
||||
goto out_exit;
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
/* Search completed, object not found */
|
||||
more = false;
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
/* Error occurred during search */
|
||||
rc = -1;
|
||||
goto out_exit;
|
||||
}
|
||||
} while (more);
|
||||
|
||||
out_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* NOTE: Must be called while holding the flash transaction lock */
|
||||
static int8_t logfs_reserve_free_slot (uint16_t * slot_id, struct slot_header * slot_hdr, uint32_t objid, uint16_t instid, uint16_t objsize)
|
||||
{
|
||||
PIOS_Assert(slot_id);
|
||||
PIOS_Assert(slot_hdr);
|
||||
|
||||
if (logfs.num_free_slots < 1) {
|
||||
/* No free slots to allocate */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (objsize > (logfs.cfg->slot_size - sizeof (slot_hdr))) {
|
||||
/* This object is too big for the slot */
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint16_t candidate_slot_id = (logfs.cfg->arena_size / logfs.cfg->slot_size) - logfs.num_free_slots;
|
||||
PIOS_Assert(candidate_slot_id > 0);
|
||||
|
||||
uintptr_t slot_addr = logfs_get_addr (logfs.active_arena_id, candidate_slot_id);
|
||||
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
slot_addr,
|
||||
(uint8_t *)slot_hdr,
|
||||
sizeof (*slot_hdr)) != 0) {
|
||||
/* Failed to read slot header for candidate slot */
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (slot_hdr->state != SLOT_STATE_EMPTY) {
|
||||
/* Candidate slot isn't empty! Something is broken. */
|
||||
PIOS_DEBUG_Assert(0);
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Mark this slot as RESERVED */
|
||||
slot_hdr->state = SLOT_STATE_RESERVED;
|
||||
slot_hdr->objid = objid;
|
||||
slot_hdr->instid = instid;
|
||||
slot_hdr->size = objsize;
|
||||
|
||||
if (logfs.driver->write_data(logfs.flash_id,
|
||||
slot_addr,
|
||||
(uint8_t *)slot_hdr,
|
||||
sizeof(*slot_hdr)) != 0) {
|
||||
/* Failed to write the slot header */
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* FIXME: If the header write (above) failed, may have partially written data, thus corrupting that slot but we would have missed decrementing this counter */
|
||||
logfs.num_free_slots--;
|
||||
|
||||
*slot_id = candidate_slot_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NOTE: Must be called while holding the flash transaction lock */
|
||||
static int8_t logfs_append_to_log (uint32_t objid, uint16_t instid, uint8_t * data, uint16_t data_len)
|
||||
{
|
||||
/* Reserve a free slot for our new object */
|
||||
uint16_t free_slot_id;
|
||||
struct slot_header slot_hdr;
|
||||
if (logfs_reserve_free_slot (&free_slot_id, &slot_hdr, objid, instid, data_len) != 0) {
|
||||
/* Failed to reserve a free slot */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Compute slot address */
|
||||
uintptr_t slot_addr = logfs_get_addr (logfs.active_arena_id, free_slot_id);
|
||||
|
||||
/* Write the data into the reserved slot, starting after the slot header */
|
||||
uintptr_t slot_offset = sizeof(slot_hdr);
|
||||
while (data_len > 0) {
|
||||
/* Individual writes must fit entirely within a single page buffer. */
|
||||
uint16_t page_remaining = logfs.cfg->page_size - (slot_offset % logfs.cfg->page_size);
|
||||
uint16_t write_size = MIN(data_len, page_remaining);
|
||||
if (logfs.driver->write_data (logfs.flash_id,
|
||||
slot_addr + slot_offset,
|
||||
data,
|
||||
write_size) != 0) {
|
||||
/* Failed to write the object data to the slot */
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Update our accounting */
|
||||
data += write_size;
|
||||
slot_offset += write_size;
|
||||
data_len -= write_size;
|
||||
}
|
||||
|
||||
/* Mark this slot active in one atomic step */
|
||||
slot_hdr.state = SLOT_STATE_ACTIVE;
|
||||
if (logfs.driver->write_data (logfs.flash_id,
|
||||
slot_addr,
|
||||
(uint8_t *)&slot_hdr,
|
||||
sizeof(slot_hdr)) != 0) {
|
||||
/* Failed to mark the slot active */
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Object has been successfully written to the slot */
|
||||
logfs.num_active_slots++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Saves one object instance per sector
|
||||
* @param[in] obj UAVObjHandle the object to save
|
||||
* @param[in] instId The instance of the object to save
|
||||
* @return 0 if success or -1 if failure
|
||||
*/
|
||||
int32_t PIOS_FLASHFS_ObjSave(UAVObjHandle obj, uint16_t instid, uint8_t * data)
|
||||
{
|
||||
int8_t rc;
|
||||
|
||||
uint32_t objid = UAVObjGetID(obj);
|
||||
uint16_t objsize = UAVObjGetNumBytes(obj);
|
||||
|
||||
PIOS_Assert(objsize <= (logfs.cfg->slot_size - sizeof(struct slot_header)));
|
||||
|
||||
if (logfs.driver->start_transaction(logfs.flash_id) != 0) {
|
||||
rc = -1;
|
||||
goto out_exit;
|
||||
}
|
||||
|
||||
if (logfs_delete_object (objid, instid) != 0) {
|
||||
rc = -2;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/*
|
||||
* All old versions of this object + instance have been invalidated.
|
||||
* Write the new object.
|
||||
*/
|
||||
|
||||
/* Check if the arena is entirely full. */
|
||||
if (logfs_fs_is_full()) {
|
||||
/* Note: Filesystem Full means we're full of *active* records so gc won't help at all. */
|
||||
rc = -3;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Is garbage collection required? */
|
||||
if (logfs_log_is_full()) {
|
||||
/* Note: Log Full means the log is full but may contain obsolete slots so gc may free some space */
|
||||
if (logfs_garbage_collect() != 0) {
|
||||
rc = -4;
|
||||
goto out_end_trans;
|
||||
}
|
||||
/* Check one more time just to be sure we actually free'd some space */
|
||||
if (logfs_log_is_full()) {
|
||||
/*
|
||||
* Log is still full even after gc!
|
||||
* NOTE: This should not happen since the filesystem wasn't full
|
||||
* when we checked above so gc should have helped.
|
||||
*/
|
||||
PIOS_DEBUG_Assert(0);
|
||||
rc = -5;
|
||||
goto out_end_trans;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have room for our new object. Append it to the log. */
|
||||
if (logfs_append_to_log(objid, instid, data, objsize) != 0) {
|
||||
/* Error during append */
|
||||
rc = -6;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Object successfully written to the log */
|
||||
rc = 0;
|
||||
|
||||
out_end_trans:
|
||||
logfs.driver->end_transaction(logfs.flash_id);
|
||||
|
||||
out_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load one object instance per sector
|
||||
* @param[in] obj UAVObjHandle the object to save
|
||||
* @param[in] instId The instance of the object to save
|
||||
* @return 0 if success or error code
|
||||
* @retval -1 if object not in file table
|
||||
* @retval -2 if unable to retrieve object header
|
||||
* @retval -3 if loaded data instId or objId don't match
|
||||
* @retval -4 if unable to retrieve instance data
|
||||
* @retval -5 if unable to read CRC
|
||||
* @retval -6 if CRC doesn't match
|
||||
*/
|
||||
int32_t PIOS_FLASHFS_ObjLoad(UAVObjHandle obj, uint16_t instid, uint8_t * data)
|
||||
{
|
||||
int8_t rc;
|
||||
|
||||
uint32_t objid = UAVObjGetID(obj);
|
||||
uint16_t objsize = UAVObjGetNumBytes(obj);
|
||||
|
||||
PIOS_Assert(objsize <= (logfs.cfg->slot_size - sizeof(struct slot_header)));
|
||||
|
||||
if (logfs.driver->start_transaction(logfs.flash_id) != 0) {
|
||||
rc = -1;
|
||||
goto out_exit;
|
||||
}
|
||||
|
||||
/* Find the object in the log */
|
||||
uint16_t slot_id = 0;
|
||||
struct slot_header slot_hdr;
|
||||
if (logfs_object_find_next (&slot_hdr, &slot_id, objid, instid) != 0) {
|
||||
/* Object does not exist in fs */
|
||||
rc = -2;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Sanity check what we've found */
|
||||
if (slot_hdr.size != objsize) {
|
||||
/* Object sizes don't match. Not safe to copy contents. */
|
||||
rc = -3;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Read the contents of the object from the log */
|
||||
uintptr_t slot_addr = logfs_get_addr (logfs.active_arena_id, slot_id);
|
||||
if (logfs.driver->read_data(logfs.flash_id,
|
||||
slot_addr + sizeof(slot_hdr),
|
||||
(uint8_t *)data,
|
||||
objsize) != 0) {
|
||||
/* Failed to read object data from the log */
|
||||
rc = -4;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Object successfully loaded */
|
||||
rc = 0;
|
||||
|
||||
out_end_trans:
|
||||
logfs.driver->end_transaction(logfs.flash_id);
|
||||
|
||||
out_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete object from flash
|
||||
* @param[in] obj UAVObjHandle the object to save
|
||||
* @param[in] instId The instance of the object to save
|
||||
* @return 0 if success or error code
|
||||
* @retval -1 if object not in file table
|
||||
* @retval -2 Erase failed
|
||||
* @note To avoid buffering the file table (1k ram!) the entry in the file table
|
||||
* remains but destination sector is erased. This will make the load fail as the
|
||||
* file header won't match the object. At next save it goes back there.
|
||||
*/
|
||||
int32_t PIOS_FLASHFS_ObjDelete(UAVObjHandle obj, uint16_t instid)
|
||||
{
|
||||
int8_t rc;
|
||||
|
||||
uint32_t objid = UAVObjGetID(obj);
|
||||
uint16_t objsize = UAVObjGetNumBytes(obj);
|
||||
|
||||
PIOS_Assert(objsize <= (logfs.cfg->slot_size - sizeof(struct slot_header)));
|
||||
|
||||
if (logfs.driver->start_transaction(logfs.flash_id) != 0) {
|
||||
rc = -1;
|
||||
goto out_exit;
|
||||
}
|
||||
|
||||
if (logfs_delete_object (objid, instid) != 0) {
|
||||
rc = -2;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Object successfully deleted from the log */
|
||||
rc = 0;
|
||||
|
||||
out_end_trans:
|
||||
logfs.driver->end_transaction(logfs.flash_id);
|
||||
|
||||
out_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int32_t PIOS_FLASHFS_Format()
|
||||
{
|
||||
int32_t rc;
|
||||
|
||||
if (logfs.mounted) {
|
||||
logfs_unmount_log();
|
||||
}
|
||||
|
||||
if (logfs.driver->start_transaction(logfs.flash_id) != 0) {
|
||||
rc = -1;
|
||||
goto out_exit;
|
||||
}
|
||||
|
||||
if (logfs_erase_all_arenas() != 0) {
|
||||
rc = -2;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Reinitialize arena 0 */
|
||||
if (logfs_activate_arena(0) != 0) {
|
||||
rc = -3;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Mount arena 0 */
|
||||
if (logfs_mount_log(0) != 0) {
|
||||
rc = -4;
|
||||
goto out_end_trans;
|
||||
}
|
||||
|
||||
/* Chip erased and log remounted successfully */
|
||||
rc = 0;
|
||||
|
||||
out_end_trans:
|
||||
logfs.driver->end_transaction(logfs.flash_id);
|
||||
|
||||
out_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
47
flight/PiOS/inc/pios_flash.h
Normal file
47
flight/PiOS/inc/pios_flash.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file pios_flash.h
|
||||
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_FLASH Flash Driver API Definition
|
||||
* @{
|
||||
* @brief Flash Driver API Definition
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_FLASH_H_
|
||||
#define PIOS_FLASH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct pios_flash_chunk {
|
||||
uint8_t * addr;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
struct pios_flash_driver {
|
||||
int32_t (*start_transaction)(uint32_t flash_id);
|
||||
int32_t (*end_transaction)(uint32_t flash_id);
|
||||
int32_t (*erase_chip)(uint32_t flash_id);
|
||||
int32_t (*erase_sector)(uint32_t flash_id, uint32_t addr);
|
||||
int32_t (*write_data)(uint32_t flash_id, uint32_t addr, uint8_t * data, uint16_t len);
|
||||
int32_t (*write_chunks)(uint32_t flash_id, uint32_t addr, struct pios_flash_chunk chunks[], uint32_t num_chunks);
|
||||
int32_t (*read_data)(uint32_t flash_id, uint32_t addr, uint8_t * data, uint16_t len);
|
||||
};
|
||||
|
||||
#endif /* PIOS_FLASH_H_ */
|
@ -6,45 +6,40 @@
|
||||
* @addtogroup PIOS_FLASH Flash device handler
|
||||
* @{
|
||||
*
|
||||
* @file pios_flash_w25x.h
|
||||
* @file pios_flash_jedec_priv.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @brief Driver for talking to W25X flash chip (and most JEDEC chips)
|
||||
* @brief Driver for talking to most JEDEC flash chips
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
*
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_FLASH_JEDEC_H_
|
||||
#define PIOS_FLASH_JEDEC_H_
|
||||
|
||||
#include "pios_flash.h" /* API definition for flash drivers */
|
||||
|
||||
extern const struct pios_flash_driver pios_jedec_flash_driver;
|
||||
|
||||
struct pios_flash_jedec_cfg {
|
||||
uint32_t sector_erase;
|
||||
uint32_t chip_erase;
|
||||
};
|
||||
|
||||
struct pios_flash_chunk {
|
||||
uint8_t * addr;
|
||||
uint32_t len;
|
||||
};
|
||||
int32_t PIOS_Flash_Jedec_Init(uint32_t * flash_id, uint32_t spi_id, uint32_t slave_num, const struct pios_flash_jedec_cfg * cfg);
|
||||
|
||||
int32_t PIOS_Flash_Jedec_Init(uint32_t spi_id, uint32_t slave_num, const struct pios_flash_jedec_cfg * cfg);
|
||||
int32_t PIOS_Flash_Jedec_ReadStatus();
|
||||
int32_t PIOS_Flash_Jedec_ReadID();
|
||||
int32_t PIOS_Flash_Jedec_EraseChip();
|
||||
int32_t PIOS_Flash_Jedec_EraseSector(uint32_t add);
|
||||
int32_t PIOS_Flash_Jedec_WriteData(uint32_t addr, uint8_t * data, uint16_t len);
|
||||
int32_t PIOS_Flash_Jedec_ReadData(uint32_t addr, uint8_t * data, uint16_t len);
|
||||
int32_t PIOS_Flash_Jedec_WriteChunks(uint32_t addr, struct pios_flash_chunk * p_chunk, uint32_t num);
|
||||
int32_t PIOS_Flash_Jedec_StartTransaction();
|
||||
int32_t PIOS_Flash_Jedec_EndTransaction();
|
||||
#endif /* PIOS_FLASH_JEDEC_H_ */
|
46
flight/PiOS/inc/pios_flashfs_logfs_priv.h
Normal file
46
flight/PiOS/inc/pios_flashfs_logfs_priv.h
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file pios_flashfs_logfs_priv.h
|
||||
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_FLASHFS Flash Filesystem Function
|
||||
* @{
|
||||
* @brief Log Structured Filesystem for internal or external NOR Flash
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_FLASHFS_LOGFS_PRIV_H_
|
||||
#define PIOS_FLASHFS_LOGFS_PRIV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "pios_flash.h" /* struct pios_flash_driver */
|
||||
|
||||
struct flashfs_logfs_cfg {
|
||||
uint32_t fs_magic;
|
||||
uint32_t total_fs_size; /* Total size of all generations of the filesystem */
|
||||
uint32_t arena_size; /* Max size of one generation of the filesystem */
|
||||
uint32_t slot_size; /* Max size of a "file" */
|
||||
|
||||
uint32_t start_offset; /* Offset into flash where this filesystem starts */
|
||||
uint32_t sector_size; /* Size of a flash erase block */
|
||||
uint32_t page_size; /* Maximum flash burst write size */
|
||||
};
|
||||
|
||||
int32_t PIOS_FLASHFS_Logfs_Init(uint32_t * fs_id, const struct flashfs_logfs_cfg * cfg, const struct pios_flash_driver * driver, uint32_t flash_id);
|
||||
|
||||
#endif /* PIOS_FLASHFS_LOGFS_PRIV_H_ */
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
* @file pios.h
|
||||
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
||||
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
|
||||
* @brief Main PiOS header.
|
||||
* - Central header for the project.
|
||||
* @see The GNU Public License (GPL) Version 3
|
||||
@ -156,8 +157,8 @@
|
||||
#endif
|
||||
|
||||
#if defined(PIOS_INCLUDE_FLASH)
|
||||
#include <pios_flash_jedec.h>
|
||||
#include <pios_flashfs_objlist.h>
|
||||
#include <pios_flash.h>
|
||||
#include <pios_flashfs.h>
|
||||
#endif
|
||||
|
||||
#if defined(PIOS_INCLUDE_BL_HELPER)
|
||||
|
Loading…
x
Reference in New Issue
Block a user