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:
commit
1a38b7eb46
106
Makefile
106
Makefile
@ -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
|
||||
|
@ -48,7 +48,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pios.h"
|
||||
#include "openpilot.h"
|
||||
|
||||
#include "flightstatus.h"
|
||||
#include "hwsettings.h"
|
||||
#include "manualcontrolcommand.h"
|
||||
|
@ -46,7 +46,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "pios.h"
|
||||
#include "openpilot.h"
|
||||
|
||||
#include "homelocation.h"
|
||||
#include "magnetometer.h"
|
||||
#include "magbias.h"
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
1026
flight/PiOS/Common/pios_flashfs_logfs.c
Normal file
1026
flight/PiOS/Common/pios_flashfs_logfs.c
Normal 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
@ -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;
|
||||
}
|
@ -31,6 +31,8 @@
|
||||
/* Project Includes */
|
||||
#include "pios.h"
|
||||
|
||||
#include "uavobjectmanager.h"
|
||||
|
||||
#if defined(PIOS_INCLUDE_GCSRCVR)
|
||||
|
||||
#include "pios_gcsrcvr_priv.h"
|
||||
|
337
flight/PiOS/STM32F4xx/pios_flash_internal.c
Normal file
337
flight/PiOS/STM32F4xx/pios_flash_internal.c
Normal 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,
|
||||
§or_number,
|
||||
§or_start,
|
||||
§or_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,
|
||||
§or_number,
|
||||
§or_start,
|
||||
§or_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,
|
||||
§or_number,
|
||||
§or_start,
|
||||
§or_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) */
|
47
flight/PiOS/inc/pios_flash.h
Normal file
47
flight/PiOS/inc/pios_flash.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file pios_flash.h
|
||||
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_FLASH Flash Driver API Definition
|
||||
* @{
|
||||
* @brief Flash Driver API Definition
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_FLASH_H_
|
||||
#define PIOS_FLASH_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct pios_flash_chunk {
|
||||
uint8_t * addr;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
struct pios_flash_driver {
|
||||
int32_t (*start_transaction)(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_ */
|
40
flight/PiOS/inc/pios_flash_internal_priv.h
Normal file
40
flight/PiOS/inc/pios_flash_internal_priv.h
Normal 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_ */
|
@ -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_ */
|
37
flight/PiOS/inc/pios_flashfs.h
Normal file
37
flight/PiOS/inc/pios_flashfs.h
Normal 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_ */
|
46
flight/PiOS/inc/pios_flashfs_logfs_priv.h
Normal file
46
flight/PiOS/inc/pios_flashfs_logfs_priv.h
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file pios_flashfs_logfs_priv.h
|
||||
* @author PhoenixPilot, http://github.com/PhoenixPilot, Copyright (C) 2012
|
||||
* @addtogroup PIOS PIOS Core hardware abstraction layer
|
||||
* @{
|
||||
* @addtogroup PIOS_FLASHFS Flash Filesystem Function
|
||||
* @{
|
||||
* @brief Log Structured Filesystem for internal or external NOR Flash
|
||||
*****************************************************************************/
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef PIOS_FLASHFS_LOGFS_PRIV_H_
|
||||
#define PIOS_FLASHFS_LOGFS_PRIV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "pios_flash.h" /* struct pios_flash_driver */
|
||||
|
||||
struct flashfs_logfs_cfg {
|
||||
uint32_t fs_magic;
|
||||
uint32_t total_fs_size; /* Total size of all generations of the filesystem */
|
||||
uint32_t arena_size; /* Max size of one generation of the filesystem */
|
||||
uint32_t slot_size; /* Max size of a "file" */
|
||||
|
||||
uint32_t start_offset; /* Offset into flash where this filesystem starts */
|
||||
uint32_t sector_size; /* Size of a flash erase block */
|
||||
uint32_t page_size; /* Maximum flash burst write size */
|
||||
};
|
||||
|
||||
int32_t PIOS_FLASHFS_Logfs_Init(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_ */
|
@ -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);
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
43
flight/tests/logfs/Makefile
Normal file
43
flight/tests/logfs/Makefile
Normal 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
|
5
flight/tests/logfs/openpilot.h
Normal file
5
flight/tests/logfs/openpilot.h
Normal file
@ -0,0 +1,5 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#define PIOS_Assert(x) if (!(x)) { while (1) ; }
|
||||
|
||||
#define PIOS_DEBUG_Assert(x) PIOS_Assert(x)
|
4
flight/tests/logfs/pios.h
Normal file
4
flight/tests/logfs/pios.h
Normal file
@ -0,0 +1,4 @@
|
||||
#if defined(PIOS_INCLUDE_FLASH)
|
||||
#include <pios_flash.h>
|
||||
#include <pios_flashfs.h>
|
||||
#endif
|
1
flight/tests/logfs/pios_config.h
Normal file
1
flight/tests/logfs/pios_config.h
Normal file
@ -0,0 +1 @@
|
||||
#define PIOS_INCLUDE_FLASH
|
159
flight/tests/logfs/pios_flash_ut.c
Normal file
159
flight/tests/logfs/pios_flash_ut.c
Normal 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,
|
||||
};
|
||||
|
14
flight/tests/logfs/pios_flash_ut_priv.h
Normal file
14
flight/tests/logfs/pios_flash_ut_priv.h
Normal 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
|
259
flight/tests/logfs/unittest.cpp
Normal file
259
flight/tests/logfs/unittest.cpp
Normal 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)));
|
||||
}
|
26
flight/tests/logfs/unittest_init.c
Normal file
26
flight/tests/logfs/unittest_init.c
Normal 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 */
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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
73
make/unittest.mk
Normal 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) $<
|
Loading…
x
Reference in New Issue
Block a user