1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-20 10:54:14 +01:00

Merge remote-tracking branch 'origin/amorale/02_os-stac_logfs-unittests' into next

Conflicts:
	flight/targets/RevoMini/Makefile
	flight/targets/Revolution/Makefile
This commit is contained in:
Alessio Morale 2013-03-23 15:13:05 +01:00
commit 1a38b7eb46
37 changed files with 2723 additions and 817 deletions

106
Makefile
View File

@ -31,6 +31,21 @@ $(foreach var, $(SANITIZE_GCC_VARS), $(eval $(call SANITIZE_VAR,$(var),disallowe
SANITIZE_DEPRECATED_VARS := USE_BOOTLOADER
$(foreach var, $(SANITIZE_DEPRECATED_VARS), $(eval $(call SANITIZE_VAR,$(var),deprecated)))
# Deal with unreasonable requests
# See: http://xkcd.com/149/
ifeq ($(MAKECMDGOALS),me a sandwich)
ifeq ($(shell whoami),root)
$(error Okay)
else
$(error What? Make it yourself)
endif
endif
# Make sure this isn't being run as root
ifeq ($(shell whoami),root)
$(error You should not be running this as root)
endif
# Decide on a verbosity level based on the V= parameter
export AT := @
@ -43,14 +58,17 @@ export V1 := $(AT)
else ifeq ($(V), 1)
endif
# Make sure we know a few things about the architecture before including
# the tools.mk to ensure that we download/install the right tools.
UNAME := $(shell uname)
ARCH := $(shell uname -m)
include $(ROOT_DIR)/make/tools.mk
# We almost need to consider autoconf/automake instead of this
# I don't know if windows supports uname :-(
QT_SPEC=win32-g++
UAVOBJGENERATOR="$(BUILD_DIR)/ground/uavobjgenerator/debug/uavobjgenerator.exe"
UNAME := $(shell uname)
ARCH := $(shell uname -m)
ifeq ($(UNAME), Linux)
QT_SPEC=linux-g++
UAVOBJGENERATOR="$(BUILD_DIR)/ground/uavobjgenerator/uavobjgenerator"
@ -98,6 +116,10 @@ help:
@echo " all_<board> - Build all available images for <board>"
@echo " all_<board>_clean - Remove all available images for <board>"
@echo
@echo " all_ut - Build all unit tests"
@echo " all_ut_tap - Run all unit tests and capture all TAP output to files"
@echo " all_ut_run - Run all unit tests and dump TAP output to console"
@echo
@echo " [Firmware]"
@echo " <board> - Build firmware for <board>"
@echo " supported boards are ($(ALL_BOARDS))"
@ -120,6 +142,10 @@ help:
@echo " [Unbrick a board]"
@echo " unbrick_<board> - Use the STM32's built in boot ROM to write a bootloader to <board>"
@echo " supported boards are ($(BL_BOARDS))"
@echo " [Unittests]"
@echo " ut_<test> - Build unit test <test>"
@echo " ut_<test>_tap - Run test and capture TAP output into a file"
@echo " ut_<test>_run - Run test and dump TAP output to console"
@echo
@echo " [Simulation]"
@echo " sim_osx - Build OpenPilot simulation firmware for OSX"
@ -167,10 +193,10 @@ $(BUILD_DIR):
##############################
ifeq ($(shell [ -d "$(QT_SDK_DIR)" ] && echo "exists"), exists)
QMAKE=$(QT_SDK_DIR)/Desktop/Qt/4.8.1/gcc/bin/qmake
QMAKE = $(QT_SDK_QMAKE_PATH)
else
# not installed, hope it's in the path...
QMAKE=qmake
QMAKE = qmake
endif
ifeq ($(shell [ -d "$(ARM_SDK_DIR)" ] && echo "exists"), exists)
@ -708,6 +734,78 @@ sim_osx_%: uavobjects_flight
$(V1) mkdir -p $(BUILD_DIR)/sim_osx
$(V1) $(MAKE) --no-print-directory \
-C $(ROOT_DIR)/flight/targets/Revolution --file=$(ROOT_DIR)/flight/targets/Revolution/Makefile.osx $*
##############################
#
# Unit Tests
#
##############################
ALL_UNITTESTS := logfs
UT_OUT_DIR := $(BUILD_DIR)/unit_tests
$(UT_OUT_DIR):
$(V1) mkdir -p $@
.PHONY: all_ut
all_ut: $(addsuffix _elf, $(addprefix ut_, $(ALL_UNITTESTS)))
.PHONY: all_ut_xml
all_ut_xml: $(addsuffix _xml, $(addprefix ut_, $(ALL_UNITTESTS)))
.PHONY: all_ut_run
all_ut_run: $(addsuffix _run, $(addprefix ut_, $(ALL_UNITTESTS)))
.PHONY: all_ut_clean
all_ut_clean:
$(V0) @echo " CLEAN $@"
$(V1) [ ! -d "$(UT_OUT_DIR)" ] || $(RM) -r "$(UT_OUT_DIR)"
# $(1) = Unit test name
define UT_TEMPLATE
.PHONY: ut_$(1)
ut_$(1): ut_$(1)_run
ut_$(1)_%: $$(UT_OUT_DIR)
$(V1) mkdir -p $(UT_OUT_DIR)/$(1)
$(V1) cd $(ROOT_DIR)/flight/tests/$(1) && \
$$(MAKE) -r --no-print-directory \
BUILD_TYPE=ut \
BOARD_SHORT_NAME=$(1) \
TCHAIN_PREFIX="" \
REMOVE_CMD="$(RM)" \
\
TARGET=$(1) \
OUTDIR="$(UT_OUT_DIR)/$(1)" \
\
PIOS=$(PIOS) \
OPUAVOBJ=$(OPUAVOBJ) \
OPUAVTALK=$(OPUAVTALK) \
FLIGHTLIB=$(FLIGHTLIB) \
\
GTEST_DIR=$(GTEST_DIR) \
\
$$*
.PHONY: ut_$(1)_clean
ut_$(1)_clean:
$(V0) @echo " CLEAN $(1)"
$(V1) [ ! -d "$(UT_OUT_DIR)/$(1)" ] || $(RM) -r "$(UT_OUT_DIR)/$(1)"
endef
# Expand the unittest rules
$(foreach ut, $(ALL_UNITTESTS), $(eval $(call UT_TEMPLATE,$(ut))))
# Disable parallel make when the all_ut_run target is requested otherwise the TAP
# output is interleaved with the rest of the make output.
ifneq ($(strip $(filter all_ut_run,$(MAKECMDGOALS))),)
.NOTPARALLEL:
$(info *NOTE* Parallel make disabled by all_ut_run target so we have sane console output)
endif
##############################
#
# Packaging components

View File

@ -48,7 +48,8 @@
*
*/
#include "pios.h"
#include "openpilot.h"
#include "flightstatus.h"
#include "hwsettings.h"
#include "manualcontrolcommand.h"

View File

@ -46,7 +46,8 @@
*
*/
#include "pios.h"
#include "openpilot.h"
#include "homelocation.h"
#include "magnetometer.h"
#include "magbias.h"

View File

@ -305,7 +305,7 @@ static void objectUpdatedCb(UAVObjEvent * ev)
} else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_FULLERASE) {
retval = -1;
#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS)
retval = PIOS_FLASHFS_Format();
retval = PIOS_FLASHFS_Format(0);
#endif
}
switch(retval) {

View File

@ -8,26 +8,28 @@
*
* @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
*
*****************************************************************************/
/*
* 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
*/
#include "pios.h"
#include "pios_flash_jedec_priv.h"
#define JEDEC_WRITE_ENABLE 0x06
#define JEDEC_WRITE_DISABLE 0x04
@ -47,8 +49,6 @@
#define JEDEC_STATUS_SEC 0x40
#define JEDEC_STATUS_SRP0 0x80
static uint8_t device_type;
enum pios_jedec_dev_magic {
PIOS_JEDEC_DEV_MAGIC = 0xcb55aa55,
};
@ -58,8 +58,11 @@ struct jedec_flash_dev {
uint32_t spi_id;
uint32_t slave_num;
bool claimed;
uint32_t device_type;
uint32_t capacity;
uint8_t manufacturer;
uint8_t memorytype;
uint8_t capacity;
const struct pios_flash_jedec_cfg * cfg;
#if defined(FLASH_FREERTOS)
xSemaphoreHandle transaction_lock;
@ -67,74 +70,96 @@ 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;
jedec_dev = (struct jedec_flash_dev *)pvPortMalloc(sizeof(*jedec_dev));
if (!jedec_dev) return (NULL);
jedec_dev->claimed = false;
jedec_dev->magic = PIOS_JEDEC_DEV_MAGIC;
struct jedec_flash_dev * flash_dev;
flash_dev = (struct jedec_flash_dev *)pvPortMalloc(sizeof(*flash_dev));
if (!flash_dev) return (NULL);
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(uintptr_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;
(void) PIOS_Flash_Jedec_ReadID(flash_dev);
if ((flash_dev->manufacturer != flash_dev->cfg->expect_manufacturer) ||
(flash_dev->memorytype != flash_dev->cfg->expect_memorytype) ||
(flash_dev->capacity != flash_dev->cfg->expect_capacity)) {
/* Mismatched device has been discovered */
return -1;
}
/* Give back a handle to this flash device */
*flash_id = (uintptr_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)
if (PIOS_SPI_ClaimBus(flash_dev->spi_id) < 0)
return -1;
if(PIOS_SPI_ClaimBus(flash_dev->spi_id) < 0)
return -1;
PIOS_SPI_RC_PinSet(flash_dev->spi_id, flash_dev->slave_num, 0);
flash_dev->claimed = true;
return 0;
}
/**
* @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 +170,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 +182,88 @@ 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->manufacturer = in[1];
flash_dev->memorytype = in[2];
flash_dev->capacity = in[3];
return flash_dev->manufacturer;
}
/**********************************
*
* 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(uintptr_t flash_id)
{
#if defined(FLASH_FREERTOS)
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
if (PIOS_Flash_Jedec_Validate(flash_dev) != 0)
return -1;
if(xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE)
return -1;
#if defined(PIOS_INCLUDE_FREERTOS)
if (xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE)
return -2;
#endif
return 0;
}
@ -210,61 +271,35 @@ 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(uintptr_t flash_id)
{
#if defined(FLASH_FREERTOS)
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
struct jedec_flash_dev * flash_dev = (struct jedec_flash_dev *)flash_id;
if (PIOS_Flash_Jedec_Validate(flash_dev) != 0)
return -1;
if(xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE)
return -1;
#if defined(PIOS_INCLUDE_FREERTOS)
if (xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE)
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;
}
PIOS_Flash_Jedec_ReleaseBus();
return in[1];
static int32_t PIOS_Flash_Jedec_StartTransaction(uintptr_t flash_id)
{
return 0;
}
/**
* @brief Read the status register from flash chip and return it
*/
int32_t PIOS_Flash_Jedec_ReadID()
static int32_t PIOS_Flash_Jedec_EndTransaction(uintptr_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;
}
PIOS_Flash_Jedec_ReleaseBus();
flash_dev->device_type = in[1];
flash_dev->capacity = in[3];
return in[1];
return 0;
}
#endif /* FLASH_USE_FREERTOS_LOCKS */
/**
* @brief Erase a sector on the flash chip
* @param[in] add Address of flash to erase
@ -272,29 +307,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(uintptr_t flash_id, uint32_t addr)
{
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
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 +344,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(uintptr_t flash_id)
{
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
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)
@ -339,7 +378,7 @@ int32_t PIOS_Flash_Jedec_EraseChip()
#endif
PIOS_LED_Toggle(PIOS_LED_HEARTBEAT);
}
return 0;
@ -356,8 +395,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(uintptr_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;
@ -365,48 +406,48 @@ int32_t PIOS_Flash_Jedec_WriteData(uint32_t addr, uint8_t * data, uint16_t len)
uint8_t out[4] = {JEDEC_PAGE_WRITE, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff};
/* Can only write one page at a time */
if(len > 0x100)
if (len > 0x100)
return -2;
/* Ensure number of bytes fits after starting address before end of page */
if(((addr & 0xff) + len) > 0x100)
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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,data,NULL,len,NULL) < 0) {
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();
while (PIOS_SPI_TransferByte(flash_dev->spi_id, JEDEC_READ_STATUS) & JEDEC_STATUS_BUSY);
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
#endif
return 0;
@ -422,49 +463,51 @@ 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(uintptr_t flash_id, uint32_t addr, struct pios_flash_chunk chunks[], uint32_t num)
{
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
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[4] = {JEDEC_PAGE_WRITE, (addr >> 16) & 0xff, (addr >> 8) & 0xff , addr & 0xff};
/* 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;
for (uint32_t i = 0; i < num; i++)
len += chunks[i].len;
if(len > 0x100)
if (len > 0x100)
return -2;
/* Ensure number of bytes fits after starting address before end of page */
if(((addr & 0xff) + len) > 0x100)
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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
PIOS_Flash_Jedec_ReleaseBus(flash_dev);
return -1;
}
for(uint32_t i = 0; i < num; i++) {
struct pios_flash_chunk * chunk = &p_chunk[i];
for (uint32_t i = 0; i < num; 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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,chunk->addr,NULL,chunk->len,NULL) < 0) {
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 +522,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(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len)
{
if(PIOS_Flash_Jedec_Validate(flash_dev) != 0)
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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,out,NULL,sizeof(out),NULL) < 0) {
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();
if (PIOS_SPI_TransferBlock(flash_dev->spi_id,NULL,data,len,NULL) < 0) {
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,
};

View File

@ -0,0 +1,1026 @@
/**
******************************************************************************
* @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 "pios_flashfs_logfs_priv.h"
#include <stdbool.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;
uintptr_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 {
/*
* The STM32F30X flash subsystem is only capable of
* writing words or halfwords. In this case we use halfwords.
* In addition to that it is only capable to write to erased
* cells (0xffff) or write a cell from anything to (0x0000).
* To cope with this, the F3 needs carefully crafted enum values.
* For this to work the underlying flash driver has to
* check each halfword if it has changed before writing.
*/
ARENA_STATE_ERASED = 0xFFFFFFFF,
ARENA_STATE_RESERVED = 0xE6E6FFFF,
ARENA_STATE_ACTIVE = 0xE6E66666,
ARENA_STATE_OBSOLETE = 0x00000000,
};
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 {
/*
* The STM32F30X flash subsystem is only capable of
* writing words or halfwords. In this case we use halfwords.
* In addition to that it is only capable to write to erased
* cells (0xffff) or write a cell from anything to (0x0000).
* To cope with this, the F3 needs carfully crafted enum values.
* For this to work the underlying flash driver has to
* check each halfword if it has changed before writing.
*/
SLOT_STATE_EMPTY = 0xFFFFFFFF,
SLOT_STATE_RESERVED = 0xFAFAFFFF,
SLOT_STATE_ACTIVE = 0xFAFAAAAA,
SLOT_STATE_OBSOLETE = 0x00000000,
};
struct slot_header {
enum slot_state state;
uint32_t obj_id;
uint16_t obj_inst_id;
uint16_t obj_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) - 1);
}
/*
* 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(uintptr_t * fs_id, const struct flashfs_logfs_cfg * cfg, const struct pios_flash_driver * driver, uintptr_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 = (uintptr_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.obj_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 obj_id, uint16_t obj_inst_id)
{
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->obj_id == obj_id &&
slot_hdr->obj_inst_id == obj_inst_id) {
/* 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 obj_id, uint16_t obj_inst_id)
{
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, obj_id, obj_inst_id)) {
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;
}
/* Object has been successfully obsoleted and is no longer active */
logfs.num_active_slots--;
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 obj_id, uint16_t obj_inst_id, uint16_t obj_size)
{
PIOS_Assert(slot_id);
PIOS_Assert(slot_hdr);
if (logfs.num_free_slots < 1) {
/* No free slots to allocate */
return -1;
}
if (obj_size > (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->obj_id = obj_id;
slot_hdr->obj_inst_id = obj_inst_id;
slot_hdr->obj_size = obj_size;
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 obj_id, uint16_t obj_inst_id, uint8_t * obj_data, uint16_t obj_size)
{
/* 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, obj_id, obj_inst_id, obj_size) != 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 (obj_size > 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(obj_size, page_remaining);
if (logfs.driver->write_data (logfs.flash_id,
slot_addr + slot_offset,
obj_data,
write_size) != 0) {
/* Failed to write the object data to the slot */
return -2;
}
/* Update our accounting */
obj_data += write_size;
slot_offset += write_size;
obj_size -= 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;
}
/**********************************
*
* Provide a PIOS_FLASHFS_* driver
*
*********************************/
#include "pios_flashfs.h" /* API for flash filesystem */
/**
* @brief Saves one object instance to the filesystem
* @param[in] fs_id The filesystem to use for this action
* @param[in] obj UAVObject ID of the object to save
* @param[in] obj_inst_id The instance number of the object being saved
* @param[in] obj_data Contents of the object being saved
* @param[in] obj_size Size of the object being saved
* @return 0 if success or error code
* @retval -1 if failed to start transaction
* @retval -2 if failure to delete any previous versions of the object
* @retval -3 if filesystem is entirely full and garbage collection won't help
* @retval -4 if garbage collection failed
* @retval -5 if filesystem is full even after garbage collection should have freed space
* @retval -6 if writing the new object to the filesystem failed
*/
int32_t PIOS_FLASHFS_ObjSave(uint32_t fs_id, uint32_t obj_id, uint16_t obj_inst_id, uint8_t * obj_data, uint16_t obj_size)
{
int8_t rc;
PIOS_Assert(obj_size <= (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 (obj_id, obj_inst_id) != 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(obj_id, obj_inst_id, obj_data, obj_size) != 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 from the filesystem
* @param[in] fs_id The filesystem to use for this action
* @param[in] obj UAVObject ID of the object to load
* @param[in] obj_inst_id The instance of the object to load
* @param[in] obj_data Buffer to hold the contents of the loaded object
* @param[in] obj_size Size of the object to be loaded
* @return 0 if success or error code
* @retval -1 if failed to start transaction
* @retval -2 if object not found in filesystem
* @retval -3 if object size in filesystem does not exactly match buffer size
* @retval -4 if reading the object data from flash fails
*/
int32_t PIOS_FLASHFS_ObjLoad(uint32_t fs_id, uint32_t obj_id, uint16_t obj_inst_id, uint8_t * obj_data, uint16_t obj_size)
{
int8_t rc;
PIOS_Assert(obj_size <= (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, obj_id, obj_inst_id) != 0) {
/* Object does not exist in fs */
rc = -2;
goto out_end_trans;
}
/* Sanity check what we've found */
if (slot_hdr.obj_size != obj_size) {
/* 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 */
if (obj_size > 0) {
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 *)obj_data,
obj_size) != 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 one instance of an object from the filesystem
* @param[in] fs_id The filesystem to use for this action
* @param[in] obj UAVObject ID of the object to delete
* @param[in] obj_inst_id The instance of the object to delete
* @return 0 if success or error code
* @retval -1 if failed to start transaction
* @retval -2 if failed to delete the object from the filesystem
*/
int32_t PIOS_FLASHFS_ObjDelete(uint32_t fs_id, uint32_t obj_id, uint16_t obj_inst_id)
{
int8_t rc;
if (logfs.driver->start_transaction(logfs.flash_id) != 0) {
rc = -1;
goto out_exit;
}
if (logfs_delete_object (obj_id, obj_inst_id) != 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;
}
/**
* @brief Erases all filesystem arenas and activate the first arena
* @param[in] fs_id The filesystem to use for this action
* @return 0 if success or error code
* @retval -1 if failed to start transaction
* @retval -2 if failed to erase all arenas
* @retval -3 if failed to activate arena 0
* @retval -4 if failed to mount arena 0
*/
int32_t PIOS_FLASHFS_Format(uint32_t fs_id)
{
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;
}
/**
* @}
* @}
*/

View File

@ -1,402 +0,0 @@
/**
******************************************************************************
*
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_FLASHFS_OBJLIST Object list based flash filesystem (low ram)
* @{
*
* @file pios_flashfs_objlist.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief A file system for storing UAVObject in flash chip
* @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
* (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"
// Private functions
static int32_t PIOS_FLASHFS_ClearObjectTableHeader();
static int32_t PIOS_FLASHFS_GetObjAddress(uint32_t objId, uint16_t instId);
static int32_t PIOS_FLASHFS_GetNewAddress(uint32_t objId, uint16_t instId);
// Private variables
static int32_t numObjects = -1;
// Private structures
// Header for objects in the file system table
struct objectHeader {
uint32_t objMagic;
uint32_t objId;
uint32_t instId;
uint32_t address;
} __attribute__((packed));;
struct fileHeader {
uint32_t id;
uint16_t instId;
uint16_t size;
} __attribute__((packed));
#define MAX_BADMAGIC 1000
static const struct flashfs_cfg * cfg;
/**
* @brief Initialize the flash object setting FS
* @return 0 if success, -1 if failure
*/
int32_t PIOS_FLASHFS_Init(const struct flashfs_cfg * new_cfg)
{
cfg = new_cfg;
// Check for valid object table or create one
uint32_t object_table_magic;
uint32_t magic_fail_count = 0;
bool magic_good = false;
while(!magic_good) {
if (PIOS_Flash_Jedec_ReadData(0, (uint8_t *)&object_table_magic, sizeof(object_table_magic)) != 0)
return -1;
if(object_table_magic != new_cfg->table_magic) {
if(magic_fail_count++ > MAX_BADMAGIC) {
if(PIOS_FLASHFS_Format() != 0)
return -1;
#if defined(PIOS_LED_HEARTBEAT)
PIOS_LED_Toggle(PIOS_LED_HEARTBEAT);
#endif /* PIOS_LED_HEARTBEAT */
magic_fail_count = 0;
magic_good = true;
} else {
PIOS_DELAY_WaituS(1000);
}
}
else {
magic_good = true;
}
}
int32_t addr = cfg->obj_table_start;
struct objectHeader header;
numObjects = 0;
// Loop through header area while objects detect to count how many saved
while(addr < cfg->obj_table_end) {
// Read the instance data
if (PIOS_Flash_Jedec_ReadData(addr, (uint8_t *)&header, sizeof(header)) != 0)
return -1;
// Counting number of valid headers
if(header.objMagic != cfg->obj_magic)
break;
numObjects++;
addr += sizeof(header);
}
return 0;
}
/**
* @brief Erase the whole flash chip and create the file system
* @return 0 if successful, -1 if not
*/
int32_t PIOS_FLASHFS_Format()
{
if(PIOS_Flash_Jedec_EraseChip() != 0)
return -1;
if(PIOS_FLASHFS_ClearObjectTableHeader() != 0)
return -1;
return 0;
}
/**
* @brief Erase the headers for all objects in the flash chip
* @return 0 if successful, -1 if not
*/
static int32_t PIOS_FLASHFS_ClearObjectTableHeader()
{
if(PIOS_Flash_Jedec_EraseSector(0) != 0)
return -1;
if (PIOS_Flash_Jedec_WriteData(0, (uint8_t *)&cfg->table_magic, sizeof(cfg->table_magic)) != 0)
return -1;
uint32_t object_table_magic;
PIOS_Flash_Jedec_ReadData(0, (uint8_t *)&object_table_magic, sizeof(object_table_magic));
if(object_table_magic != cfg->table_magic)
return -1;
return 0;
}
/**
* @brief Get the address of an object
* @param obj UAVObjHandle for that object
* @parma instId Instance id for that object
* @return address if successful, -1 if not found
*/
static int32_t PIOS_FLASHFS_GetObjAddress(uint32_t objId, uint16_t instId)
{
int32_t addr = cfg->obj_table_start;
struct objectHeader header;
// Loop through header area while objects detect to count how many saved
while(addr < cfg->obj_table_end) {
// Read the instance data
if (PIOS_Flash_Jedec_ReadData(addr, (uint8_t *) &header, sizeof(header)) != 0)
return -1;
if(header.objMagic != cfg->obj_magic)
break; // stop searching once hit first non-object header
else if (header.objId == objId && header.instId == instId)
break;
addr += sizeof(header);
}
if (header.objId == objId && header.instId == instId)
return header.address;
return -1;
}
/**
* @brief Returns an address for a new object and creates entry into object table
* @param[in] obj Object handle for object to be saved
* @param[in] instId The instance id of object to be saved
* @return 0 if success or error code
* @retval -1 Object not found
* @retval -2 No room in object table
* @retval -3 Unable to write entry into object table
* @retval -4 FS not initialized
* @retval -5
*/
int32_t PIOS_FLASHFS_GetNewAddress(uint32_t objId, uint16_t instId)
{
struct objectHeader header;
if(numObjects < 0)
return -4;
// Don't worry about max size of flash chip here, other code will catch that
header.objMagic = cfg->obj_magic;
header.objId = objId;
header.instId = instId;
header.address = cfg->obj_table_end + cfg->sector_size * numObjects;
int32_t addr = cfg->obj_table_start + sizeof(header) * numObjects;
// No room for this header in object table
if((addr + sizeof(header)) > cfg->obj_table_end)
return -2;
// Verify the address is within the chip
if((addr + cfg->sector_size) > cfg->chip_size)
return -5;
if(PIOS_Flash_Jedec_WriteData(addr, (uint8_t *) &header, sizeof(header)) != 0)
return -3;
// This numObejcts value must stay consistent or there will be a break in the table
// and later the table will have bad values in it
numObjects++;
return header.address;
}
/**
* @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
* @note This uses one sector on the flash chip per object so that no buffering in ram
* must be done when erasing the sector before a save
*/
int32_t PIOS_FLASHFS_ObjSave(UAVObjHandle obj, uint16_t instId, uint8_t * data)
{
uint32_t objId = UAVObjGetID(obj);
uint8_t crc = 0;
if(PIOS_Flash_Jedec_StartTransaction() != 0)
return -1;
int32_t addr = PIOS_FLASHFS_GetObjAddress(objId, instId);
// Object currently not saved
if(addr < 0)
addr = PIOS_FLASHFS_GetNewAddress(objId, instId);
// Could not allocate a sector
if(addr < 0) {
PIOS_Flash_Jedec_EndTransaction();
return -1;
}
struct fileHeader header = {
.id = objId,
.instId = instId,
.size = UAVObjGetNumBytes(obj)
};
// Update CRC
crc = PIOS_CRC_updateCRC(0, (uint8_t *) &header, sizeof(header));
crc = PIOS_CRC_updateCRC(crc, (uint8_t *) data, UAVObjGetNumBytes(obj));
if(PIOS_Flash_Jedec_EraseSector(addr) != 0) {
PIOS_Flash_Jedec_EndTransaction();
return -2;
}
struct pios_flash_chunk chunks[3] = {
{
.addr = (uint8_t *) &header,
.len = sizeof(header),
},
{
.addr = (uint8_t *) data,
.len = UAVObjGetNumBytes(obj)
},
{
.addr = (uint8_t *) &crc,
.len = sizeof(crc)
}
};
if(PIOS_Flash_Jedec_WriteChunks(addr, chunks, NELEMENTS(chunks)) != 0) {
PIOS_Flash_Jedec_EndTransaction();
return -1;
}
if(PIOS_Flash_Jedec_EndTransaction() != 0) {
PIOS_Flash_Jedec_EndTransaction();
return -1;
}
return 0;
}
/**
* @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
* @note This uses one sector on the flash chip per object so that no buffering in ram
* must be done when erasing the sector before a save
*/
int32_t PIOS_FLASHFS_ObjLoad(UAVObjHandle obj, uint16_t instId, uint8_t * data)
{
uint32_t objId = UAVObjGetID(obj);
uint16_t objSize = UAVObjGetNumBytes(obj);
uint8_t crc = 0;
uint8_t crcFlash = 0;
const uint8_t crc_read_step = 8;
uint8_t crc_read_buffer[crc_read_step];
if(PIOS_Flash_Jedec_StartTransaction() != 0)
return -1;
int32_t addr = PIOS_FLASHFS_GetObjAddress(objId, instId);
// Object currently not saved
if(addr < 0) {
PIOS_Flash_Jedec_EndTransaction();
return -1;
}
struct fileHeader header;
// Load header
// This information IS redundant with the object table id. Oh well. Better safe than sorry.
if(PIOS_Flash_Jedec_ReadData(addr, (uint8_t *) &header, sizeof(header)) != 0) {
PIOS_Flash_Jedec_EndTransaction();
return -2;
}
// Update CRC
crc = PIOS_CRC_updateCRC(0, (uint8_t *) &header, sizeof(header));
if((header.id != objId) || (header.instId != instId)) {
PIOS_Flash_Jedec_EndTransaction();
return -3;
}
// To avoid having to allocate the RAM for a copy of the object, we read by chunks
// and compute the CRC
for(uint32_t i = 0; i < objSize; i += crc_read_step) {
PIOS_Flash_Jedec_ReadData(addr + sizeof(header) + i, crc_read_buffer, crc_read_step);
uint8_t valid_bytes = ((i + crc_read_step) >= objSize) ? objSize - i : crc_read_step;
crc = PIOS_CRC_updateCRC(crc, crc_read_buffer, valid_bytes);
}
// Read CRC (written so will work when CRC changes to uint16)
if(PIOS_Flash_Jedec_ReadData(addr + sizeof(header) + objSize, (uint8_t *) &crcFlash, sizeof(crcFlash)) != 0) {
PIOS_Flash_Jedec_EndTransaction();
return -5;
}
if(crc != crcFlash) {
PIOS_Flash_Jedec_EndTransaction();
return -6;
}
// Read the instance data
if (PIOS_Flash_Jedec_ReadData(addr + sizeof(header), data, objSize) != 0) {
PIOS_Flash_Jedec_EndTransaction();
return -4;
}
if(PIOS_Flash_Jedec_EndTransaction() != 0)
return -1;
return 0;
}
/**
* @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)
{
uint32_t objId = UAVObjGetID(obj);
int32_t addr = PIOS_FLASHFS_GetObjAddress(objId, instId);
// Object currently not saved
if(addr < 0)
return -1;
if(PIOS_Flash_Jedec_EraseSector(addr) != 0)
return -2;
return 0;
}

View File

@ -31,6 +31,8 @@
/* Project Includes */
#include "pios.h"
#include "uavobjectmanager.h"
#if defined(PIOS_INCLUDE_GCSRCVR)
#include "pios_gcsrcvr_priv.h"

View File

@ -0,0 +1,337 @@
/**
******************************************************************************
* @file pios_flash_internal.c
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup
* @{
* @addtogroup
* @{
* @brief Provides a flash driver for the STM32 internal flash sectors
*****************************************************************************/
/*
* 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 "pios.h"
#if defined(PIOS_INCLUDE_FLASH_INTERNAL)
#include "stm32f4xx_flash.h"
#include "pios_flash_internal_priv.h"
#include "pios_flash.h"
#include <stdbool.h>
struct device_flash_sector {
uint32_t start;
uint32_t size;
uint16_t st_sector;
};
static struct device_flash_sector flash_sectors[] = {
[0] = {
.start = 0x08000000,
.size = 16 * 1024,
.st_sector = FLASH_Sector_0,
},
[1] = {
.start = 0x08004000,
.size = 16 * 1024,
.st_sector = FLASH_Sector_1,
},
[2] = {
.start = 0x08008000,
.size = 16 * 1024,
.st_sector = FLASH_Sector_2,
},
[3] = {
.start = 0x0800C000,
.size = 16 * 1024,
.st_sector = FLASH_Sector_3,
},
[4] = {
.start = 0x08010000,
.size = 64 * 1024,
.st_sector = FLASH_Sector_4,
},
[5] = {
.start = 0x08020000,
.size = 128 * 1024,
.st_sector = FLASH_Sector_5,
},
[6] = {
.start = 0x08040000,
.size = 128 * 1024,
.st_sector = FLASH_Sector_6,
},
[7] = {
.start = 0x08060000,
.size = 128 * 1024,
.st_sector = FLASH_Sector_7,
},
[8] = {
.start = 0x08080000,
.size = 128 * 1024,
.st_sector = FLASH_Sector_8,
},
[9] = {
.start = 0x080A0000,
.size = 128 * 1024,
.st_sector = FLASH_Sector_9,
},
[10] = {
.start = 0x080C0000,
.size = 128 * 1024,
.st_sector = FLASH_Sector_10,
},
[11] = {
.start = 0x080E0000,
.size = 128 * 1024,
.st_sector = FLASH_Sector_11,
},
};
static bool PIOS_Flash_Internal_GetSectorInfo(uint32_t address, uint8_t * sector_number, uint32_t *sector_start, uint32_t *sector_size)
{
for (uint8_t i = 0; i < NELEMENTS(flash_sectors); i++) {
struct device_flash_sector * sector = &flash_sectors[i];
if ((address >= sector->start) &&
(address < (sector->start + sector->size))) {
/* address lies within this sector */
*sector_number = sector->st_sector;
*sector_start = sector->start;
*sector_size = sector->size;
return (true);
}
}
return (false);
}
enum pios_internal_flash_dev_magic {
PIOS_INTERNAL_FLASH_DEV_MAGIC = 0x33445902,
};
struct pios_internal_flash_dev {
enum pios_internal_flash_dev_magic magic;
#if defined(PIOS_INCLUDE_FREERTOS)
xSemaphoreHandle transaction_lock;
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
};
static bool PIOS_Flash_Internal_Validate(struct pios_internal_flash_dev * flash_dev) {
return (flash_dev && (flash_dev->magic == PIOS_INTERNAL_FLASH_DEV_MAGIC));
}
#if defined(PIOS_INCLUDE_FREERTOS)
static struct pios_internal_flash_dev * PIOS_Flash_Internal_alloc(void)
{
struct pios_internal_flash_dev * flash_dev;
flash_dev = (struct pios_internal_flash_dev *)pvPortMalloc(sizeof(* flash_dev));
if (!flash_dev) return (NULL);
flash_dev->magic = PIOS_INTERNAL_FLASH_DEV_MAGIC;
return(flash_dev);
}
#else
static struct pios_internal_flash_dev pios_internal_flash_devs[PIOS_INTERNAL_FLASH_MAX_DEVS];
static uint8_t pios_internal_flash_num_devs;
static struct pios_internal_flash_dev * PIOS_Flash_Internal_alloc(void)
{
struct pios_internal_flash_dev * flash_dev;
if (pios_internal_flash_num_devs >= PIOS_INTERNAL_FLASH_MAX_DEVS) {
return (NULL);
}
flash_dev = &pios_internal_flash_devs[pios_internal_flash_num_devs++];
flash_dev->magic = PIOS_INTERNAL_FLASH_DEV_MAGIC;
return (flash_dev);
}
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
int32_t PIOS_Flash_Internal_Init(uintptr_t * flash_id, const struct pios_flash_internal_cfg * cfg)
{
struct pios_internal_flash_dev * flash_dev;
flash_dev = PIOS_Flash_Internal_alloc();
if (flash_dev == NULL)
return -1;
#if defined(PIOS_INCLUDE_FREERTOS)
flash_dev->transaction_lock = xSemaphoreCreateMutex();
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
*flash_id = (uintptr_t) flash_dev;
return 0;
}
/**********************************
*
* Provide a PIOS flash driver API
*
*********************************/
#include "pios_flash.h"
static int32_t PIOS_Flash_Internal_StartTransaction(uintptr_t flash_id)
{
struct pios_internal_flash_dev * flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev))
return -1;
#if defined(PIOS_INCLUDE_FREERTOS)
if (xSemaphoreTake(flash_dev->transaction_lock, portMAX_DELAY) != pdTRUE)
return -2;
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
/* Unlock the internal flash so we can write to it */
FLASH_Unlock();
return 0;
}
static int32_t PIOS_Flash_Internal_EndTransaction(uintptr_t flash_id)
{
struct pios_internal_flash_dev * flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev))
return -1;
#if defined(PIOS_INCLUDE_FREERTOS)
if (xSemaphoreGive(flash_dev->transaction_lock) != pdTRUE)
return -2;
#endif /* defined(PIOS_INCLUDE_FREERTOS) */
/* Lock the internal flash again so we can no longer write to it */
FLASH_Lock();
return 0;
}
static int32_t PIOS_Flash_Internal_EraseSector(uintptr_t flash_id, uint32_t addr)
{
struct pios_internal_flash_dev * flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev))
return -1;
uint8_t sector_number;
uint32_t sector_start;
uint32_t sector_size;
if (!PIOS_Flash_Internal_GetSectorInfo(addr,
&sector_number,
&sector_start,
&sector_size)) {
/* We're asking for an invalid flash address */
return -2;
}
if (FLASH_EraseSector(sector_number, VoltageRange_3) != FLASH_COMPLETE)
return -3;
return 0;
}
static int32_t PIOS_Flash_Internal_WriteData(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len)
{
PIOS_Assert(data);
struct pios_internal_flash_dev * flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev))
return -1;
uint8_t sector_number;
uint32_t sector_start;
uint32_t sector_size;
/* Ensure that the base address is in a valid sector */
if (!PIOS_Flash_Internal_GetSectorInfo(addr,
&sector_number,
&sector_start,
&sector_size)) {
/* We're asking for an invalid flash address */
return -2;
}
/* Ensure that the entire write occurs within the same sector */
if ((uintptr_t)addr + len > sector_start + sector_size) {
/* Write crosses the end of the sector */
return -3;
}
/* Write the data */
for (uint16_t i = 0; i < len; i++) {
FLASH_Status status;
/*
* This is inefficient. Should try to do word writes.
* Not sure if word writes need to be aligned though.
*/
status = FLASH_ProgramByte(addr + i, data[i]);
PIOS_Assert(status == FLASH_COMPLETE);
}
return 0;
}
static int32_t PIOS_Flash_Internal_ReadData(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len)
{
PIOS_Assert(data);
struct pios_internal_flash_dev * flash_dev = (struct pios_internal_flash_dev *)flash_id;
if (!PIOS_Flash_Internal_Validate(flash_dev))
return -1;
uint8_t sector_number;
uint32_t sector_start;
uint32_t sector_size;
/* Ensure that the base address is in a valid sector */
if (!PIOS_Flash_Internal_GetSectorInfo(addr,
&sector_number,
&sector_start,
&sector_size)) {
/* We're asking for an invalid flash address */
return -2;
}
/* Ensure that the entire read occurs within the same sector */
if ((uintptr_t)addr + len > sector_start + sector_size) {
/* Read crosses the end of the sector */
return -3;
}
/* Read the data into the buffer directly */
memcpy(data, (void *)addr, len);
return 0;
}
/* Provide a flash driver to external drivers */
const struct pios_flash_driver pios_internal_flash_driver = {
.start_transaction = PIOS_Flash_Internal_StartTransaction,
.end_transaction = PIOS_Flash_Internal_EndTransaction,
.erase_sector = PIOS_Flash_Internal_EraseSector,
.write_data = PIOS_Flash_Internal_WriteData,
.read_data = PIOS_Flash_Internal_ReadData,
};
#endif /* defined(PIOS_INCLUDE_FLASH_INTERNAL) */

View 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)(uintptr_t flash_id);
int32_t (*end_transaction)(uintptr_t flash_id);
int32_t (*erase_chip)(uintptr_t flash_id);
int32_t (*erase_sector)(uintptr_t flash_id, uint32_t addr);
int32_t (*write_data)(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len);
int32_t (*write_chunks)(uintptr_t flash_id, uint32_t addr, struct pios_flash_chunk chunks[], uint32_t num_chunks);
int32_t (*read_data)(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len);
};
#endif /* PIOS_FLASH_H_ */

View File

@ -0,0 +1,40 @@
/**
******************************************************************************
* @file pios_flash_internal_priv.h
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup
* @{
* @addtogroup
* @{
* @brief Provides a flash driver for the STM32 internal flash sectors
*****************************************************************************/
/*
* 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_INTERNAL_H_
#define PIOS_FLASH_INTERNAL_H_
#include "pios_flash.h" /* API definition for flash drivers */
extern const struct pios_flash_driver pios_internal_flash_driver;
struct pios_flash_internal_cfg {
;
};
extern int32_t PIOS_Flash_Internal_Init(uintptr_t * flash_id, const struct pios_flash_internal_cfg * cfg);
#endif /* PIOS_FLASH_INTERNAL_H_ */

View File

@ -6,45 +6,47 @@
* @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;
#define JEDEC_MANUFACTURER_ST 0x20
#define JEDEC_MANUFACTURER_MACRONIX 0xC2
#define JEDEC_MANUFACTURER_WINBOND 0xEF
struct pios_flash_jedec_cfg {
uint8_t expect_manufacturer;
uint8_t expect_memorytype;
uint8_t expect_capacity;
uint32_t sector_erase;
uint32_t chip_erase;
};
struct pios_flash_chunk {
uint8_t * addr;
uint32_t len;
};
int32_t PIOS_Flash_Jedec_Init(uintptr_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_ */

View File

@ -0,0 +1,37 @@
/**
******************************************************************************
* @file pios_flashfs.h
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_FLASHFS Flash Filesystem API Definition
* @{
* @brief Flash Filesystem 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_FLASHFS_H_
#define PIOS_FLASHFS_H_
#include <stdint.h>
int32_t PIOS_FLASHFS_Format(uint32_t fs_id);
int32_t PIOS_FLASHFS_ObjSave(uint32_t fs_id, uint32_t obj_id, uint16_t obj_inst_id, uint8_t * obj_data, uint16_t obj_size);
int32_t PIOS_FLASHFS_ObjLoad(uint32_t fs_id, uint32_t obj_id, uint16_t obj_inst_id, uint8_t * obj_data, uint16_t obj_size);
int32_t PIOS_FLASHFS_ObjDelete(uint32_t fs_id, uint32_t obj_id, uint16_t obj_inst_id);
#endif /* PIOS_FLASHFS_H_ */

View 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(uintptr_t * fs_id, const struct flashfs_logfs_cfg * cfg, const struct pios_flash_driver * driver, uintptr_t flash_id);
#endif /* PIOS_FLASHFS_LOGFS_PRIV_H_ */

View File

@ -1,47 +0,0 @@
/**
******************************************************************************
*
* @addtogroup PIOS PIOS Core hardware abstraction layer
* @{
* @addtogroup PIOS_FLASHFS_OBJLIST Object list based flash filesystem (low ram)
* @{
*
* @file pios_flashfs_objlist.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief A file system for storing UAVObject in flash chip
* @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
* (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"
struct flashfs_cfg {
uint32_t table_magic;
uint32_t obj_magic;
uint32_t obj_table_start;
uint32_t obj_table_end;
uint32_t sector_size;
uint32_t chip_size;
};
int32_t PIOS_FLASHFS_Init(const struct flashfs_cfg * cfg);
int32_t PIOS_FLASHFS_Format();
int32_t PIOS_FLASHFS_ObjSave(UAVObjHandle obj, uint16_t instId, uint8_t * data);
int32_t PIOS_FLASHFS_ObjLoad(UAVObjHandle obj, uint16_t instId, uint8_t * data);
int32_t PIOS_FLASHFS_ObjDelete(UAVObjHandle obj, uint16_t instId);

View File

@ -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)

View File

@ -1,26 +1,28 @@
#####
# Project: OpenPilot
#
#
# Makefile for OpenPilot project build PiOS and the AP.
#
# The OpenPilot Team, http://www.openpilot.org, Copyright (C) 2009.
#
#
# 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
#####
###############################################################################
# @file Makefile
# @author The OpenPilot Team, http://www.openpilot.org, Copyright (C) 2009.
# @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
# @addtogroup
# @{
# @addtogroup
# @{
# @brief Makefile to build firmware for the CopterControl board.
###############################################################################
#
# 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
#
WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST)))
TOP := $(realpath $(WHEREAMI)/../../../)
@ -259,7 +261,7 @@ SRC += $(PIOSCOMMON)/pios_usb_util.c
## PIOS Hardware (Common)
SRC += $(PIOSCOMMON)/pios_crc.c
SRC += $(PIOSCOMMON)/pios_flashfs_objlist.c
SRC += $(PIOSCOMMON)/pios_flashfs_logfs.c
SRC += $(PIOSCOMMON)/pios_flash_jedec.c
SRC += $(PIOSCOMMON)/pios_adxl345.c
SRC += $(PIOSCOMMON)/pios_mpu6000.c

View File

@ -1,15 +1,13 @@
/**
******************************************************************************
*****************************************************************************
* @file pios_board.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup OpenPilotSystem OpenPilot System
* @{
* @addtogroup OpenPilotCore OpenPilot Core
* @{
*
* @file pios_board.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief Defines board specific static initializers for hardware for the OpenPilot board.
* @see The GNU Public License (GPL) Version 3
*
* @brief Defines board specific static initializers for hardware for the CopterControl board.
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
@ -34,15 +32,15 @@
*
* NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE
*/
#include "board_hw_defs.c"
#include <pios.h>
#include <openpilot.h>
#include <uavobjectsinit.h>
#include <hwsettings.h>
#include <manualcontrolsettings.h>
#include <gcsreceiver.h>
#include "board_hw_defs.c"
/* One slot per selectable receiver group.
* eg. PWM, PPM, GCS, DSMMAINPORT, DSMFLEXIPORT, SBUS
@ -127,33 +125,6 @@ static const struct pios_mpu6000_cfg pios_mpu6000_cfg = {
};
#endif /* PIOS_INCLUDE_MPU6000 */
static const struct flashfs_cfg flashfs_w25x_cfg = {
.table_magic = 0x85FB3C35,
.obj_magic = 0x3015AE71,
.obj_table_start = 0x00000010,
.obj_table_end = 0x00001000,
.sector_size = 0x00001000,
.chip_size = 0x00080000,
};
static const struct pios_flash_jedec_cfg flash_w25x_cfg = {
.sector_erase = 0x20,
.chip_erase = 0x60
};
static const struct flashfs_cfg flashfs_m25p_cfg = {
.table_magic = 0x85FB3D35,
.obj_magic = 0x3015A371,
.obj_table_start = 0x00000010,
.obj_table_end = 0x00010000,
.sector_size = 0x00010000,
.chip_size = 0x00200000,
};
static const struct pios_flash_jedec_cfg flash_m25p_cfg = {
.sector_erase = 0xD8,
.chip_erase = 0xC7
};
#include <pios_board_info.h>
/**
* PIOS_Board_Init()
@ -194,14 +165,16 @@ void PIOS_Board_Init(void) {
#endif
uintptr_t flash_id;
uintptr_t fs_id;
switch(bdinfo->board_rev) {
case BOARD_REVISION_CC:
PIOS_Flash_Jedec_Init(pios_spi_flash_accel_id, 1, &flash_w25x_cfg);
PIOS_FLASHFS_Init(&flashfs_w25x_cfg);
PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_id, 1, &flash_w25x_cfg);
PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_w25x_cfg, &pios_jedec_flash_driver, flash_id);
break;
case BOARD_REVISION_CC3D:
PIOS_Flash_Jedec_Init(pios_spi_flash_accel_id, 0, &flash_m25p_cfg);
PIOS_FLASHFS_Init(&flashfs_m25p_cfg);
PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_accel_id, 0, &flash_m25p_cfg);
PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_m25p_cfg, &pios_jedec_flash_driver, flash_id);
break;
default:
PIOS_DEBUG_Assert(0);

View File

@ -148,7 +148,7 @@ SRC += $(PIOSCOMMON)/pios_rfm22b_rcvr.c
SRC += $(PIOSCOMMON)/pios_rcvr.c
SRC += $(PIOSCOMMON)/pios_sbus.c
SRC += $(PIOSCOMMON)/pios_flash_jedec.c
SRC += $(PIOSCOMMON)/pios_flashfs_objlist.c
SRC += $(PIOSCOMMON)/pios_flashfs_logfs.c
SRC += $(PIOSCOMMON)/printf-stdarg.c
SRC += $(PIOSCOMMON)/pios_usb_desc_hid_cdc.c
SRC += $(PIOSCOMMON)/pios_usb_desc_hid_only.c
@ -244,6 +244,7 @@ CFLAGS += -DSTACK_DIAGNOSTICS
CFLAGS += -DMIXERSTATUS_DIAGNOSTICS
CFLAGS += -DRATEDESIRED_DIAGNOSTICS
CFLAGS += -DI2C_WDG_STATS_DIAGNOSTICS
CFLAGS += -DDIAGNOSTICS
CFLAGS += -DDIAG_TASKS
# This is not the best place for these. Really should abstract out

View File

@ -1,15 +1,13 @@
/**
******************************************************************************
* @addtogroup Revolution Revolution configuration files
* @{
* @brief Configures the revolution board
* @{
*
* @file pios_board.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
* @brief Defines board specific static initializers for hardware for the Revolution board.
* @see The GNU Public License (GPL) Version 3
*
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup OpenPilotSystem OpenPilot System
* @{
* @addtogroup OpenPilotCore OpenPilot Core
* @{
* @brief Defines board specific static initializers for hardware for the revomini board.
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
@ -191,20 +189,6 @@ static const struct pios_mpu6000_cfg pios_mpu6000_cfg = {
};
#endif /* PIOS_INCLUDE_MPU6000 */
static const struct flashfs_cfg flashfs_m25p_cfg = {
.table_magic = 0x85FB3D35,
.obj_magic = 0x3015A371,
.obj_table_start = 0x00000010,
.obj_table_end = 0x00010000,
.sector_size = 0x00010000,
.chip_size = 0x00200000,
};
static const struct pios_flash_jedec_cfg flash_m25p_cfg = {
.sector_erase = 0xD8,
.chip_erase = 0xC7
};
/* One slot per selectable receiver group.
* eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS
* NOTE: No slot in this map for NONE.
@ -350,9 +334,11 @@ void PIOS_Board_Init(void) {
}
#if defined(PIOS_INCLUDE_FLASH)
/* Connect flash to the approrpiate interface and configure it */
PIOS_Flash_Jedec_Init(pios_spi_telem_flash_id, 1, &flash_m25p_cfg);
PIOS_FLASHFS_Init(&flashfs_m25p_cfg);
/* Connect flash to the appropriate interface and configure it */
uintptr_t flash_id;
PIOS_Flash_Jedec_Init(&flash_id, pios_spi_telem_flash_id, 1, &flash_m25p_cfg);
uintptr_t fs_id;
PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_m25p_cfg, &pios_jedec_flash_driver, flash_id);
#endif
/* Initialize UAVObject libraries */

View File

@ -163,7 +163,7 @@ SRC += $(PIOSCOMMON)/pios_com.c
SRC += $(PIOSCOMMON)/pios_rcvr.c
SRC += $(PIOSCOMMON)/pios_sbus.c
SRC += $(PIOSCOMMON)/pios_flash_jedec.c
SRC += $(PIOSCOMMON)/pios_flashfs_objlist.c
SRC += $(PIOSCOMMON)/pios_flashfs_logfs.c
SRC += $(PIOSCOMMON)/printf-stdarg.c
SRC += $(PIOSCOMMON)/pios_usb_desc_hid_cdc.c
SRC += $(PIOSCOMMON)/pios_usb_desc_hid_only.c

View File

@ -1,15 +1,13 @@
/**
******************************************************************************
* @addtogroup Revolution Revolution configuration files
* @{
* @brief Configures the revolution board
* @{
*
*****************************************************************************
* @file pios_board.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
* @brief Defines board specific static initializers for hardware for the Revolution board.
* @see The GNU Public License (GPL) Version 3
*
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup OpenPilotSystem OpenPilot System
* @{
* @addtogroup OpenPilotCore OpenPilot Core
* @{
* @brief Defines board specific static initializers for hardware for the revolution board.
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
@ -34,14 +32,14 @@
*
* NOTE: THIS IS THE ONLY PLACE THAT SHOULD EVER INCLUDE THIS FILE
*/
#include "board_hw_defs.c"
#include <pios.h>
#include <openpilot.h>
#include <uavobjectsinit.h>
#include "hwsettings.h"
#include "manualcontrolsettings.h"
#include "board_hw_defs.c"
/**
* Sensor configurations
*/
@ -274,21 +272,6 @@ static const struct pios_l3gd20_cfg pios_l3gd20_cfg = {
};
#endif /* PIOS_INCLUDE_L3GD20 */
static const struct flashfs_cfg flashfs_m25p_cfg = {
.table_magic = 0x85FB3D35,
.obj_magic = 0x3015A371,
.obj_table_start = 0x00000010,
.obj_table_end = 0x00010000,
.sector_size = 0x00010000,
.chip_size = 0x00200000,
};
static const struct pios_flash_jedec_cfg flash_m25p_cfg = {
.sector_erase = 0xD8,
.chip_erase = 0xC7
};
/* One slot per selectable receiver group.
* eg. PWM, PPM, GCS, SPEKTRUM1, SPEKTRUM2, SBUS
* NOTE: No slot in this map for NONE.
@ -401,11 +384,16 @@ void PIOS_Board_Init(void) {
if (PIOS_SPI_Init(&pios_spi_flash_id, &pios_spi_flash_cfg)) {
PIOS_DEBUG_Assert(0);
}
PIOS_Flash_Jedec_Init(pios_spi_flash_id, 0, &flash_m25p_cfg);
/* Connect flash to the appropriate interface and configure it */
uintptr_t flash_id;
PIOS_Flash_Jedec_Init(&flash_id, pios_spi_flash_id, 0, &flash_m25p_cfg);
#else
PIOS_Flash_Jedec_Init(pios_spi_accel_id, 1, &flash_m25p_cfg);
/* Connect flash to the appropriate interface and configure it */
uintptr_t flash_id;
PIOS_Flash_Jedec_Init(&flash_id, pios_spi_accel_id, 1, &flash_m25p_cfg);
#endif
PIOS_FLASHFS_Init(&flashfs_m25p_cfg);
uintptr_t fs_id;
PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_m25p_cfg, &pios_jedec_flash_driver, flash_id);
/* Initialize UAVObject libraries */
EventDispatcherInitialize();

View File

@ -772,7 +772,7 @@ int32_t UAVObjSave(UAVObjHandle obj_handle, uint16_t instId)
if (instId != 0)
return -1;
if (PIOS_FLASHFS_ObjSave(obj_handle, instId, (uint8_t*) MetaDataPtr((struct UAVOMeta *)obj_handle)) != 0)
if (PIOS_FLASHFS_ObjSave(0, UAVObjGetID(obj_handle), instId, (uint8_t*) MetaDataPtr((struct UAVOMeta *)obj_handle), UAVObjGetNumBytes(obj_handle)) != 0)
return -1;
} else {
InstanceHandle instEntry = getInstance( (struct UAVOData *)obj_handle, instId);
@ -783,7 +783,7 @@ int32_t UAVObjSave(UAVObjHandle obj_handle, uint16_t instId)
if (InstanceData(instEntry) == NULL)
return -1;
if (PIOS_FLASHFS_ObjSave(obj_handle, instId, InstanceData(instEntry)) != 0)
if (PIOS_FLASHFS_ObjSave(0, UAVObjGetID(obj_handle), instId, InstanceData(instEntry), UAVObjGetNumBytes(obj_handle)) != 0)
return -1;
}
#endif
@ -927,7 +927,7 @@ int32_t UAVObjLoad(UAVObjHandle obj_handle, uint16_t instId)
return -1;
// Fire event on success
if (PIOS_FLASHFS_ObjLoad(obj_handle, instId, (uint8_t*) MetaDataPtr((struct UAVOMeta *)obj_handle)) == 0)
if (PIOS_FLASHFS_ObjLoad(0, UAVObjGetID(obj_handle), instId, (uint8_t*) MetaDataPtr((struct UAVOMeta *)obj_handle), UAVObjGetNumBytes(obj_handle)) == 0)
sendEvent((struct UAVOBase*)obj_handle, instId, EV_UNPACKED);
else
return -1;
@ -939,7 +939,7 @@ int32_t UAVObjLoad(UAVObjHandle obj_handle, uint16_t instId)
return -1;
// Fire event on success
if (PIOS_FLASHFS_ObjLoad(obj_handle, instId, InstanceData(instEntry)) == 0)
if (PIOS_FLASHFS_ObjLoad(0, UAVObjGetID(obj_handle), instId, InstanceData(instEntry), UAVObjGetNumBytes(obj_handle)) == 0)
sendEvent((struct UAVOBase*)obj_handle, instId, EV_UNPACKED);
else
return -1;
@ -997,7 +997,7 @@ int32_t UAVObjDelete(UAVObjHandle obj_handle, uint16_t instId)
{
PIOS_Assert(obj_handle);
#if defined(PIOS_INCLUDE_FLASH_SECTOR_SETTINGS)
PIOS_FLASHFS_ObjDelete(obj_handle, instId);
PIOS_FLASHFS_ObjDelete(0, UAVObjGetID(obj_handle), instId);
#endif
#if defined(PIOS_INCLUDE_SDCARD)
uint8_t filename[14];

View File

@ -1,15 +1,13 @@
/**
******************************************************************************
* @file board_hw_defs.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup OpenPilotSystem OpenPilot System
* @{
* @addtogroup OpenPilotCore OpenPilot Core
* @{
*
* @file board_hw_defs.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief Defines board specific static initializers for hardware for the OpenPilot board.
* @see The GNU Public License (GPL) Version 3
*
* @brief Defines board specific static initializers for hardware for the CopterControl board.
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
@ -401,6 +399,52 @@ void PIOS_SPI_flash_accel_irq_handler(void)
#endif /* PIOS_INCLUDE_SPI */
#if defined(PIOS_INCLUDE_FLASH)
#include "pios_flashfs_logfs_priv.h"
#include "pios_flash_jedec_priv.h"
static const struct flashfs_logfs_cfg flashfs_w25x_cfg = {
.fs_magic = 0x99abcdef,
.total_fs_size = 0x00080000, /* 512K bytes (128 sectors = entire chip) */
.arena_size = 0x00010000, /* 256 * slot size */
.slot_size = 0x00000100, /* 256 bytes */
.start_offset = 0, /* start at the beginning of the chip */
.sector_size = 0x00001000, /* 4K bytes */
.page_size = 0x00000100, /* 256 bytes */
};
static const struct pios_flash_jedec_cfg flash_w25x_cfg = {
.expect_manufacturer = JEDEC_MANUFACTURER_WINBOND,
.expect_memorytype = 0x30,
.expect_capacity = 0x13,
.sector_erase = 0x20,
.chip_erase = 0x60
};
static const struct flashfs_logfs_cfg flashfs_m25p_cfg = {
.fs_magic = 0x99abceef,
.total_fs_size = 0x00200000, /* 2M bytes (32 sectors = entire chip) */
.arena_size = 0x00010000, /* 256 * slot size */
.slot_size = 0x00000100, /* 256 bytes */
.start_offset = 0, /* start at the beginning of the chip */
.sector_size = 0x00010000, /* 64K bytes */
.page_size = 0x00000100, /* 256 bytes */
};
static const struct pios_flash_jedec_cfg flash_m25p_cfg = {
.expect_manufacturer = JEDEC_MANUFACTURER_ST,
.expect_memorytype = 0x20,
.expect_capacity = 0x15,
.sector_erase = 0xD8,
.chip_erase = 0xC7,
};
#include "pios_flash.h"
#endif /* PIOS_INCLUDE_FLASH */
/*
* ADC system
*/

View File

@ -1,15 +1,13 @@
/**
******************************************************************************
* @file board_hw_defs.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup OpenPilotSystem OpenPilot System
* @{
* @addtogroup OpenPilotCore OpenPilot Core
* @{
*
* @file board_hw_defs.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief Defines board specific static initializers for hardware for the OpenPilot board.
* @see The GNU Public License (GPL) Version 3
*
* @brief Defines board specific static initializers for hardware for the Revolution board.
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
@ -449,6 +447,31 @@ void PIOS_SPI_flash_irq_handler(void)
#endif /* PIOS_INCLUDE_SPI */
#if defined(PIOS_INCLUDE_FLASH)
#include "pios_flashfs_logfs_priv.h"
#include "pios_flash_jedec_priv.h"
static const struct flashfs_logfs_cfg flashfs_m25p_cfg = {
.fs_magic = 0x99abceef,
.total_fs_size = 0x00200000, /* 2M bytes (32 sectors = entire chip) */
.arena_size = 0x00010000, /* 256 * slot size */
.slot_size = 0x00000100, /* 256 bytes */
.start_offset = 0, /* start at the beginning of the chip */
.sector_size = 0x00010000, /* 64K bytes */
.page_size = 0x00000100, /* 256 bytes */
};
static const struct pios_flash_jedec_cfg flash_m25p_cfg = {
.expect_manufacturer = JEDEC_MANUFACTURER_ST,
.expect_memorytype = 0x20,
.expect_capacity = 0x15,
.sector_erase = 0xD8,
.chip_erase = 0xC7,
};
#endif /* PIOS_INCLUDE_FLASH */
#if defined(PIOS_OVERO_SPI)
/* SPI3 Interface
* - Used for flash communications

View File

@ -1,15 +1,13 @@
/**
******************************************************************************
* @file board_hw_defs.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
* @addtogroup OpenPilotSystem OpenPilot System
* @{
* @addtogroup OpenPilotCore OpenPilot Core
* @{
*
* @file board_hw_defs.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
* @brief Defines board specific static initializers for hardware for the OpenPilot board.
* @see The GNU Public License (GPL) Version 3
*
* @brief Defines board specific static initializers for hardware for the RevoMini board.
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
@ -554,6 +552,31 @@ const struct pios_rfm22b_cfg * PIOS_BOARD_HW_DEFS_GetRfm22Cfg (uint32_t board_re
#endif /* PIOS_INCLUDE_SPI */
#if defined(PIOS_INCLUDE_FLASH)
#include "pios_flashfs_logfs_priv.h"
#include "pios_flash_jedec_priv.h"
static const struct flashfs_logfs_cfg flashfs_m25p_cfg = {
.fs_magic = 0x99abceef,
.total_fs_size = 0x00200000, /* 2M bytes (32 sectors = entire chip) */
.arena_size = 0x00010000, /* 256 * slot size */
.slot_size = 0x00000100, /* 256 bytes */
.start_offset = 0, /* start at the beginning of the chip */
.sector_size = 0x00010000, /* 64K bytes */
.page_size = 0x00000100, /* 256 bytes */
};
static const struct pios_flash_jedec_cfg flash_m25p_cfg = {
.expect_manufacturer = JEDEC_MANUFACTURER_ST,
.expect_memorytype = 0x20,
.expect_capacity = 0x15,
.sector_erase = 0xD8,
.chip_erase = 0xC7,
};
#endif /* PIOS_INCLUDE_FLASH */
#include <pios_usart_priv.h>
#ifdef PIOS_INCLUDE_COM_TELEM

View File

@ -0,0 +1,43 @@
###############################################################################
# @file Makefile
# @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
# @addtogroup
# @{
# @addtogroup
# @{
# @brief Makefile for unit test
###############################################################################
#
# 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
#
WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST)))
TOP := $(realpath $(WHEREAMI)/../../../)
include $(TOP)/make/firmware-defs.mk
EXTRAINCDIRS += $(PIOS)/inc
CFLAGS += -O0
CFLAGS += -Wall -Werror
CFLAGS += -g
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) -I.
CFLAGS += "-DFLASH_IMAGE_FILE=\"$(OUTDIR)/theflash.bin\""
CONLYFLAGS += -std=gnu99
SRC := $(PIOS)/Common/pios_flashfs_logfs.c
include $(TOP)/make/unittest.mk

View File

@ -0,0 +1,5 @@
#include <stdbool.h>
#define PIOS_Assert(x) if (!(x)) { while (1) ; }
#define PIOS_DEBUG_Assert(x) PIOS_Assert(x)

View File

@ -0,0 +1,4 @@
#if defined(PIOS_INCLUDE_FLASH)
#include <pios_flash.h>
#include <pios_flashfs.h>
#endif

View File

@ -0,0 +1 @@
#define PIOS_INCLUDE_FLASH

View File

@ -0,0 +1,159 @@
#include <stdlib.h> /* abort */
#include <stdio.h> /* fopen/fread/fwrite/fseek */
#include <assert.h> /* assert */
#include <string.h> /* memset */
#include <stdbool.h>
#include "pios_flash_ut_priv.h"
enum flash_ut_magic {
FLASH_UT_MAGIC = 0x321dabc1,
};
struct flash_ut_dev {
enum flash_ut_magic magic;
const struct pios_flash_ut_cfg * cfg;
bool transaction_in_progress;
FILE * flash_file;
};
static struct flash_ut_dev * PIOS_Flash_UT_Alloc(void)
{
struct flash_ut_dev * flash_dev = malloc(sizeof(struct flash_ut_dev));
flash_dev->magic = FLASH_UT_MAGIC;
return flash_dev;
}
int32_t PIOS_Flash_UT_Init(uintptr_t * flash_id, const struct pios_flash_ut_cfg * cfg)
{
/* Check inputs */
assert(flash_id);
assert(cfg);
assert(cfg->size_of_flash);
assert(cfg->size_of_sector);
assert((cfg->size_of_flash % cfg->size_of_sector) == 0);
struct flash_ut_dev * flash_dev = PIOS_Flash_UT_Alloc();
assert(flash_dev);
flash_dev->cfg = cfg;
flash_dev->transaction_in_progress = false;
flash_dev->flash_file = fopen (FLASH_IMAGE_FILE, "rb+");
if (flash_dev->flash_file == NULL) {
return -1;
}
if (fseek (flash_dev->flash_file, flash_dev->cfg->size_of_flash, SEEK_SET) != 0) {
return -2;
}
*flash_id = (uintptr_t)flash_dev;
return 0;
}
/**********************************
*
* Provide a PIOS flash driver API
*
*********************************/
#include "pios_flash.h"
static int32_t PIOS_Flash_UT_StartTransaction(uintptr_t flash_id)
{
struct flash_ut_dev * flash_dev = (struct flash_ut_dev *)flash_id;
assert(!flash_dev->transaction_in_progress);
flash_dev->transaction_in_progress = true;
return 0;
}
static int32_t PIOS_Flash_UT_EndTransaction(uintptr_t flash_id)
{
struct flash_ut_dev * flash_dev = (struct flash_ut_dev *)flash_id;
assert(flash_dev->transaction_in_progress);
flash_dev->transaction_in_progress = false;
return 0;
}
static int32_t PIOS_Flash_UT_EraseSector(uintptr_t flash_id, uint32_t addr)
{
struct flash_ut_dev * flash_dev = (struct flash_ut_dev *)flash_id;
assert(flash_dev->transaction_in_progress);
if (fseek (flash_dev->flash_file, addr, SEEK_SET) != 0) {
assert(0);
}
unsigned char * buf = malloc(flash_dev->cfg->size_of_sector);
assert (buf);
memset((void *)buf, 0xFF, flash_dev->cfg->size_of_sector);
size_t s;
s = fwrite (buf, 1, flash_dev->cfg->size_of_sector, flash_dev->flash_file);
assert (s == flash_dev->cfg->size_of_sector);
return 0;
}
static int32_t PIOS_Flash_UT_WriteData(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len)
{
/* Check inputs */
assert(data);
struct flash_ut_dev * flash_dev = (struct flash_ut_dev *)flash_id;
assert(flash_dev->transaction_in_progress);
if (fseek (flash_dev->flash_file, addr, SEEK_SET) != 0) {
assert(0);
}
size_t s;
s = fwrite (data, 1, len, flash_dev->flash_file);
assert (s == len);
return 0;
}
static int32_t PIOS_Flash_UT_ReadData(uintptr_t flash_id, uint32_t addr, uint8_t * data, uint16_t len)
{
/* Check inputs */
assert(data);
struct flash_ut_dev * flash_dev = (struct flash_ut_dev *)flash_id;
assert(flash_dev->transaction_in_progress);
if (fseek (flash_dev->flash_file, addr, SEEK_SET) != 0) {
assert(0);
}
size_t s;
s = fread (data, 1, len, flash_dev->flash_file);
assert (s == len);
return 0;
}
/* Provide a flash driver to external drivers */
const struct pios_flash_driver pios_ut_flash_driver = {
.start_transaction = PIOS_Flash_UT_StartTransaction,
.end_transaction = PIOS_Flash_UT_EndTransaction,
.erase_sector = PIOS_Flash_UT_EraseSector,
.write_data = PIOS_Flash_UT_WriteData,
.read_data = PIOS_Flash_UT_ReadData,
};

View File

@ -0,0 +1,14 @@
#include <stdint.h>
struct pios_flash_ut_cfg {
uint32_t size_of_flash;
uint32_t size_of_sector;
};
int32_t PIOS_Flash_UT_Init(uintptr_t * flash_id, const struct pios_flash_ut_cfg * cfg);
extern const struct pios_flash_driver pios_ut_flash_driver;
#if !defined(FLASH_IMAGE_FILE)
#define FLASH_IMAGE_FILE "theflash.bin"
#endif

View File

@ -0,0 +1,259 @@
#include "gtest/gtest.h"
#include <stdio.h> /* printf */
#include <stdlib.h> /* abort */
#include <string.h> /* memset */
extern "C" {
#include "pios_flash.h" /* PIOS_FLASH_* API */
#include "pios_flash_ut_priv.h"
extern struct pios_flash_ut_cfg flash_config;
#include "pios_flashfs_logfs_priv.h"
extern struct flashfs_logfs_cfg flashfs_config;
#include "pios_flashfs.h" /* PIOS_FLASHFS_* */
}
#define OBJ0_ID 0xAA55AA55
#define OBJ1_ID 0x12345678
#define OBJ1_SIZE 76
#define OBJ2_ID 0xABCDEFAB
#define OBJ2_SIZE 123
#define OBJ3_ID 0x99999999
#define OBJ3_SIZE (256 - 12) // leave room for the slot header
// To use a test fixture, derive a class from testing::Test.
class LogfsTestRaw : public testing::Test {
protected:
virtual void SetUp() {
/* create an empty, appropriately sized flash filesystem */
FILE * theflash = fopen(FLASH_IMAGE_FILE, "wb");
uint8_t sector[flash_config.size_of_sector];
memset(sector, 0xFF, sizeof(sector));
for (uint32_t i = 0; i < flash_config.size_of_flash / flash_config.size_of_sector; i++) {
fwrite(sector, sizeof(sector), 1, theflash);
}
fclose(theflash);
/* Set up obj1 */
for (uint32_t i = 0; i < sizeof(obj1); i++) {
obj1[i] = 0x10 + (i % 10);
}
/* Set up a second version of obj1 with different data */
for (uint32_t i = 0; i < sizeof(obj1_alt); i++) {
obj1_alt[i] = 0xA0 + (i % 10);
}
/* Set up obj2 */
for (uint32_t i = 0; i < sizeof(obj2); i++) {
obj2[i] = 0x20 + (i % 10);
}
/* Set up obj3 */
for (uint32_t i = 0; i < sizeof(obj3); i++) {
obj3[i] = 0x30 + (i % 10);
}
}
virtual void TearDown() {
unlink("theflash.bin");
}
unsigned char obj1[OBJ1_SIZE];
unsigned char obj1_alt[OBJ1_SIZE];
unsigned char obj2[OBJ2_SIZE];
unsigned char obj3[OBJ3_SIZE];
};
TEST_F(LogfsTestRaw, FlashInit) {
uintptr_t flash_id;
EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id, &flash_config));
}
TEST_F(LogfsTestRaw, LogfsInit) {
uintptr_t flash_id;
EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id, &flash_config));
uintptr_t fs_id;
EXPECT_EQ(0, PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_config, &pios_ut_flash_driver, flash_id));
}
class LogfsTestCooked : public LogfsTestRaw {
protected:
virtual void SetUp() {
/* First, we need to set up the super fixture (LogfsTestRaw) */
LogfsTestRaw::SetUp();
/* Init the flash and the flashfs so we don't need to repeat this in every test */
uintptr_t flash_id;
EXPECT_EQ(0, PIOS_Flash_UT_Init(&flash_id, &flash_config));
EXPECT_EQ(0, PIOS_FLASHFS_Logfs_Init(&fs_id, &flashfs_config, &pios_ut_flash_driver, flash_id));
}
uintptr_t fs_id;
};
TEST_F(LogfsTestCooked, LogfsFormat) {
EXPECT_EQ(0, PIOS_FLASHFS_Format(fs_id));
}
TEST_F(LogfsTestCooked, WriteOne) {
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
}
TEST_F(LogfsTestCooked, WriteVerifyOne) {
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
unsigned char obj1_check[OBJ1_SIZE];
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
}
TEST_F(LogfsTestCooked, WriteVerifyDeleteVerifyOne) {
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
unsigned char obj1_check[OBJ1_SIZE];
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
EXPECT_EQ(0, PIOS_FLASHFS_ObjDelete(fs_id, OBJ1_ID, 0));
EXPECT_EQ(-2, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
}
TEST_F(LogfsTestCooked, WriteTwoVerifyOneA) {
/* Write obj1 then obj2 */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
/* Read back obj1 */
unsigned char obj1_check[OBJ1_SIZE];
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
}
TEST_F(LogfsTestCooked, WriteTwoVerifyOneB) {
/* Write obj2 then obj1 */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
/* Read back obj1 */
unsigned char obj1_check[OBJ1_SIZE];
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
}
TEST_F(LogfsTestCooked, WriteZeroSize) {
/* Write a zero length object */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ0_ID, 0, NULL, 0));
}
TEST_F(LogfsTestCooked, WriteVerifyZeroLength) {
/* Write a zero length object */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ0_ID, 0, NULL, 0));
/* Read back a zero length object -- effectively an existence check */
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ0_ID, 0, NULL, 0));
}
TEST_F(LogfsTestCooked, WriteMaxSize) {
/* Write a zero length object */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ3_ID, 0, obj3, sizeof(obj3)));
}
TEST_F(LogfsTestCooked, ReadNonexistent) {
/* Read back a zero length object -- basically an existence check */
unsigned char obj1_check[OBJ1_SIZE];
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(-2, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
}
TEST_F(LogfsTestCooked, WriteVerifyMultiInstance) {
/* Write instance zero */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
/* Write a non-zero instance ID */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 123, obj1_alt, sizeof(obj1_alt)));
unsigned char obj1_check[OBJ1_SIZE];
/* Read back instance 123 */
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 123, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1_alt, obj1_check, sizeof(obj1_alt)));
/* Read back instance 0 */
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
}
TEST_F(LogfsTestCooked, FillFilesystemAndGarbageCollect) {
/* Fill up the entire filesystem with multiple instances of obj1 */
for (uint32_t i = 0; i < (flashfs_config.arena_size / flashfs_config.slot_size) - 1; i++) {
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, i, obj1, sizeof(obj1)));
}
/* Should fail to add a new object since the filesystem is full */
EXPECT_EQ(-3, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
/* Now save a new version of an existing object which should trigger gc and succeed */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1_alt, sizeof(obj1_alt)));
/* Read back one of the original obj1 instances */
unsigned char obj1_check[OBJ1_SIZE];
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 1, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
/* Read back the new version of obj1 written after gc */
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1_alt, obj1_check, sizeof(obj1_alt)));
}
TEST_F(LogfsTestCooked, WriteManyVerify) {
for (uint32_t i = 0; i < 10000; i++) {
/* Write a collection of objects */
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ0_ID, 0, NULL, 0));
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 0, obj1, sizeof(obj1)));
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ1_ID, 123, obj1_alt, sizeof(obj1_alt)));
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ2_ID, 0, obj2, sizeof(obj2)));
EXPECT_EQ(0, PIOS_FLASHFS_ObjSave(fs_id, OBJ3_ID, 0, obj3, sizeof(obj3)));
}
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ0_ID, 0, NULL, 0));
unsigned char obj1_check[OBJ1_SIZE];
memset(obj1_check, 0, sizeof(obj1_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 0, obj1_check, sizeof(obj1_check)));
EXPECT_EQ(0, memcmp(obj1, obj1_check, sizeof(obj1)));
unsigned char obj1_alt_check[OBJ1_SIZE];
memset(obj1_alt_check, 0, sizeof(obj1_alt_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ1_ID, 123, obj1_alt_check, sizeof(obj1_alt_check)));
EXPECT_EQ(0, memcmp(obj1_alt, obj1_alt_check, sizeof(obj1_alt)));
unsigned char obj2_check[OBJ2_SIZE];
memset(obj2_check, 0, sizeof(obj2_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ2_ID, 0, obj2_check, sizeof(obj2_check)));
EXPECT_EQ(0, memcmp(obj2, obj2_check, sizeof(obj2)));
unsigned char obj3_check[OBJ3_SIZE];
memset(obj3_check, 0, sizeof(obj3_check));
EXPECT_EQ(0, PIOS_FLASHFS_ObjLoad(fs_id, OBJ3_ID, 0, obj3_check, sizeof(obj3_check)));
EXPECT_EQ(0, memcmp(obj3, obj3_check, sizeof(obj3)));
}

View File

@ -0,0 +1,26 @@
/*
* These need to be defined in a .c file so that we can use
* designated initializer syntax which c++ doesn't support (yet).
*/
#include "pios_flash_ut_priv.h"
const struct pios_flash_ut_cfg flash_config = {
.size_of_flash = 0x00200000,
.size_of_sector = 0x00010000,
};
#include "pios_flashfs_logfs_priv.h"
const struct flashfs_logfs_cfg flashfs_config = {
.fs_magic = 0x89abceef,
.total_fs_size = 0x00200000, /* 2M bytes (32 sectors = entire chip) */
.arena_size = 0x00010000, /* 256 * slot size */
.slot_size = 0x00000100, /* 256 bytes */
.start_offset = 0, /* start at the beginning of the chip */
.sector_size = 0x00010000, /* 64K bytes */
.page_size = 0x00000100, /* 256 bytes */
};

View File

@ -3,7 +3,7 @@ TCHAIN_PREFIX ?= arm-none-eabi-
# Define toolchain component names.
CC = $(TCHAIN_PREFIX)gcc
CPP = $(TCHAIN_PREFIX)g++
CXX = $(TCHAIN_PREFIX)g++
AR = $(TCHAIN_PREFIX)ar
OBJCOPY = $(TCHAIN_PREFIX)objcopy
OBJDUMP = $(TCHAIN_PREFIX)objdump
@ -44,8 +44,8 @@ MSG_ARCHIVING = ${quote} AR $(MSG_EXTRA) ${quote}
MSG_LINKING = ${quote} LD $(MSG_EXTRA) ${quote}
MSG_COMPILING = ${quote} CC ${MSG_EXTRA} ${quote}
MSG_COMPILING_ARM = ${quote} CC-ARM $(MSG_EXTRA) ${quote}
MSG_COMPILINGCPP = ${quote} CXX $(MSG_EXTRA) ${quote}
MSG_COMPILINGCPP_ARM = ${quote} CXX-ARM $(MSG_EXTRA) ${quote}
MSG_COMPILINGCXX = ${quote} CXX $(MSG_EXTRA) ${quote}
MSG_COMPILINGCXX_ARM = ${quote} CXX-ARM $(MSG_EXTRA) ${quote}
MSG_ASSEMBLING = ${quote} AS $(MSG_EXTRA) ${quote}
MSG_ASSEMBLING_ARM = ${quote} AS-ARM $(MSG_EXTRA) ${quote}
MSG_CLEANING = ${quote} CLEAN $(MSG_EXTRA) ${quote}
@ -171,17 +171,17 @@ $(OUTDIR)/$(notdir $(basename $(1))).o : $(1)
endef
# Compile: create object files from C++ source files.
define COMPILE_CPP_TEMPLATE
define COMPILE_CXX_TEMPLATE
$(OUTDIR)/$(notdir $(basename $(1))).o : $(1)
@echo $(MSG_COMPILINGCPP) $$(call toprel, $$<)
$(V1) $(CC) -c $(THUMB) $$(CFLAGS) $$(CPPFLAGS) $$< -o $$@
@echo $(MSG_COMPILINGCXX) $$(call toprel, $$<)
$(V1) $(CXX) -c $(THUMB) $$(CFLAGS) $$(CPPFLAGS) $$(CXXFLAGS) $$< -o $$@
endef
# Compile: create object files from C++ source files. ARM-only
define COMPILE_CPP_ARM_TEMPLATE
define COMPILE_CXX_ARM_TEMPLATE
$(OUTDIR)/$(notdir $(basename $(1))).o : $(1)
@echo $(MSG_COMPILINGCPP_ARM) $$(call toprel, $$<)
$(V1) $(CC) -c $$(CFLAGS) $$(CPPFLAGS) $$< -o $$@
@echo $(MSG_COMPILINGCXX_ARM) $$(call toprel, $$<)
$(V1) $(CPP) -c $$(CFLAGS) $$(CPPFLAGS) $$(CXXFLAGS) $$< -o $$@
endef
# Archive: create ar library file from object files.
@ -219,6 +219,17 @@ $(1): $(2) $(3)
$(V1) $(CC) $(THUMB) $$(CFLAGS) $(2) $(3) --output $$@ $$(LDFLAGS)
endef
# Link: create ELF output file from object files.
# $1 = elf file to produce
# $2 = list of object files that make up the elf file
define LINK_CXX_TEMPLATE
.SECONDARY : $(1)
.PRECIOUS : $(2)
$(1): $(2)
@echo $(MSG_LINKING) $$(call toprel, $$@)
$(V1) $(CXX) $(THUMB) $$(CFLAGS) $(2) --output $$@ $$(LDFLAGS)
endef
# Compile: create assembler files from C source files. ARM/Thumb
define PARTIAL_COMPILE_TEMPLATE
$($(1):.c=.s) : %.s : %.c

View File

@ -14,10 +14,12 @@ QT_SDK_DIR := $(TOOLS_DIR)/qtsdk-v1.2.1
# Choose the appropriate installer based on host architecture
ifneq (,$(filter $(ARCH), x86_64 amd64))
# 64-bit
QT_SDK_QMAKE_PATH := $(QT_SDK_DIR)/Desktop/Qt/4.8.1/gcc/bin/qmake
qt_sdk_install: QT_SDK_FILE := QtSdk-offline-linux-x86_64-v1.2.1.run
qt_sdk_install: QT_SDK_URL := http://www.developer.nokia.com/dp?uri=http://sw.nokia.com/id/14b2039c-0e1f-4774-a4f2-9aa60b6d5313/Qt_SDK_Lin64_offline
else
# 32-bit
QT_SDK_QMAKE_PATH := $(QT_SDK_DIR)/Desktop/Qt/4.8.1/gcc/bin/qmake
qt_sdk_install: QT_SDK_URL := http://www.developer.nokia.com/dp?uri=http://sw.nokia.com/id/8ea74da4-fec1-4277-8b26-c58cc82e204b/Qt_SDK_Lin32_offline
qt_sdk_install: QT_SDK_FILE := QtSdk-offline-linux-x86-v1.2.1.run
endif
@ -316,3 +318,26 @@ android_sdk_update:
$(V0) @echo " UPDATE $(ANDROID_SDK_DIR)"
$(ANDROID_SDK_DIR)/tools/android update sdk --no-ui -t platform-tools,android-16,addon-google_apis-google-16
# Set up Google Test (gtest) tools
GTEST_DIR := $(TOOLS_DIR)/gtest-1.6.0
.PHONY: gtest_install
gtest_install: | $(DL_DIR) $(TOOLS_DIR)
gtest_install: GTEST_URL := http://googletest.googlecode.com/files/gtest-1.6.0.zip
gtest_install: GTEST_FILE := $(notdir $(GTEST_URL))
gtest_install: gtest_clean
# download the file unconditionally since google code gives back 404
# for HTTP HEAD requests which are used when using the wget -N option
$(V1) [ ! -f "$(DL_DIR)/$(GTEST_FILE)" ] || $(RM) -f "$(DL_DIR)/$(GTEST_FILE)"
$(V1) wget -P "$(DL_DIR)" --trust-server-name "$(GTEST_URL)"
# extract the source
$(V1) [ ! -d "$(GTEST_DIR)" ] || $(RM) -rf "$(GTEST_DIR)"
$(V1) mkdir -p "$(GTEST_DIR)"
$(V1) unzip -q -d "$(TOOLS_DIR)" "$(DL_DIR)/$(GTEST_FILE)"
.PHONY: gtest_clean
gtest_clean:
$(V0) @echo " CLEAN $(GTEST_DIR)"
$(V1) [ ! -d "$(GTEST_DIR)" ] || $(RM) -rf "$(GTEST_DIR)"

73
make/unittest.mk Normal file
View File

@ -0,0 +1,73 @@
###############################################################################
# @file unittest.mk
# @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
# @addtogroup
# @{
# @addtogroup
# @{
# @brief Makefile template for unit tests
###############################################################################
#
# 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
#
# Flags passed to the preprocessor.
CPPFLAGS += -I$(GTEST_DIR)/include
# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra
# Google Test needs the pthread library
LDFLAGS += -lpthread
#################################
#
# Template to build the user test
#
#################################
# Need to disable THUMB mode for unit tests
override THUMB :=
EXTRAINCDIRS += .
ALLSRC := $(SRC) $(wildcard ./*.c)
ALLCPPSRC := $(wildcard ./*.cpp) $(GTEST_DIR)/src/gtest_main.cc
ALLSRCBASE := $(notdir $(basename $(ALLSRC) $(ALLCPPSRC)))
ALLOBJ := $(addprefix $(OUTDIR)/, $(addsuffix .o, $(ALLSRCBASE)))
$(foreach src,$(ALLSRC),$(eval $(call COMPILE_C_TEMPLATE,$(src))))
$(foreach src,$(ALLCPPSRC),$(eval $(call COMPILE_CXX_TEMPLATE,$(src))))
# Specific extensions to CPPFLAGS only for the google test library
$(OUTDIR)/gtest-all.o : CPPFLAGS += -I$(GTEST_DIR)
$(eval $(call COMPILE_CXX_TEMPLATE, $(GTEST_DIR)/src/gtest-all.cc))
$(eval $(call LINK_CXX_TEMPLATE,$(OUTDIR)/$(TARGET).elf,$(ALLOBJ) $(OUTDIR)/gtest-all.o))
.PHONY: elf
elf: $(OUTDIR)/$(TARGET).elf
.PHONY: xml
xml: $(OUTDIR)/test-reports/$(TARGET).xml
$(OUTDIR)/test-reports/$(TARGET).xml: $(OUTDIR)/$(TARGET).elf
$(V0) @echo " TEST XML $(MSG_EXTRA) $(call toprel, $@)"
$(V1) $< --gtest_output=xml:$@ > /dev/null
.PHONY: run
run: $(OUTDIR)/$(TARGET).elf
$(V0) @echo " TEST RUN $(MSG_EXTRA) $(call toprel, $<)"
$(V1) $<