Skip to content

Commit

Permalink
config: Load config from embedded fat12 file system
Browse files Browse the repository at this point in the history
  • Loading branch information
pengi committed May 31, 2020
1 parent 3af1bab commit c7a6a74
Show file tree
Hide file tree
Showing 19 changed files with 343 additions and 216 deletions.
77 changes: 53 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ st-flash --reset --format ihex write build/nodeflight-stm32f722.hex

Loading a layer1 config: (currently hardcoded for stm32f722ze memory map, for layer1 config, see below)
```
./tools/flash_config.sh test_l1conf.txt
./tools/flash_config.sh config_int.dmg
```

## Building blocks
Expand Down Expand Up @@ -82,7 +82,8 @@ The configuration is stored as text, and is intended to be updated without updat

Each line contains an instruction:
- `per <tag> <configuration>` - peripheral, defines a template for the peripheral configuration.
- `mod <type> <configuration>` - Load a module
- `mod <name> <type> <configuration>` - Load a module. Modules names are optional, and can be skipped by `-`
- `inc <file>` - Add file to a configuration read queue. Files are loaded one at a time, and is read in order.

Example:

Expand All @@ -97,45 +98,73 @@ Note that the `per` line just creates the template for the interface, but doesn'

## Configuration storage

Configuration is layered, where each layer is loaded in sequence. A previous layer may enable access to lower layers.
Configuration is stored in files in a mapped file system. While configuration loads, more file systems may be mounted and gives access to more configuration.

Functionality placed in different layers are not enforced. The layered structure is just a recommendation and best practice.
On the internal storage, extra configuration files may be provided to load on board sensors for easy use.

For smaller embedded control systems, it may for example be suitable to put all configuration in layer 1, where no sd card is available.
For smaller systems, without access to SD card, it is possible to store all configuration in the on-board file system

### Layer 1 - onboard flash
## Boot sequence

Stored in a flash page a string
1. NodeFlight mounts internal flash storage as `/int`
2. The configuration `/int/boot.cfg` is loaded
3. `/int/boot.cfg` Configure and mount an external storage, preferably as `/ext`
4. `/int/boot.cfg` adds an external configuration file as config source, preferrably `/ext/boot.cfg`
5. `/ext/boot.cfg` includes application specific configration files needed

Intended to store `per` lines for on board interfaces, and create instances necessary for accessing layer 2, for example SD card drivers.
## Best practice

Example (may not be supported yet):
```
per spi_mpu6000 spi4 pin_e02 pin_e05 pin_e06 pin_e04 pin_e01
per spi_sdcard spi1 pin_a05 pin_a06 pin_a07 pin_a04 pin_d08
mod sdcard spi_sdcard
mod config_file layer2.txt
On board flash is not intended to be updated by the end user, but by the board developer. A common practice between board manufacturers and application developers needs to be established.

Therefore, the following convention is used for configuration files:

### `/int/boot.cfg`
Bare minimum for configuration of external flash and load `/ext/boot.cfg`. May also start of necessary interfaces for system functionality, for example fan control, or possibly debug IO in a development environment.

Example:
```
# Setup SD card interface
per sdcard_cs gpio_a15 pin_a15
per sdcard_spi spi1 pin_a05 pin_a07 pin_a06 dma_none dma_none
mod ext sdcard sdcard_spi sdcard_cs
### Layer 2 - user config loader
# Load external configuration
Stored preferably on an SD card, but can vary dependent on board.
inc /ext/boot.cfg
```

Stores user interface configuration and hardware mapping. modules for I/O are instanced.
### `/int/defaults.cfg`
Include `per` lines mapping peripherals to pins, without instancing. Should be possible to include to simplify loading of modules, without significant overhead, and without occupying resources, even though multiple `per` lines may use the same. No `mod` lines is allowed.

Intended to load application/regulator configuration
Those lines acts as defaults, and can be overridden by application configuration.

Example:
```
mod gyro_mpu6000 spi_mpu6000 ...
mod config_file layer3.txt
```
# mpu6500 interface
per mpu6500_cs gpio_d04 pin_d04
per mpu6500_int gpio_c00 pin_c00
per mpu6500_spi spi2 pin_d03 pin_c03 pin_c02 dma_none dma_none
### Layer 3 - control logic
# uart2 full duplex
per uart2_full uart2 pin_d05 pin_d06 dma_1_6 dma_1_5
# uart2 half duplex
per uart2_half uart2 pin_none pin_d06 dma_1_6 dma_1_5
```

Calculation blocks, which interfaces the I/O blocks provided by layer 2, or each other.
### `/ext/boot.cfg`
Loader for application configuration. Intended to load necessary configuration, to opt-in or opt-out of using the defaults. To load files containing glue to connect hardware to control logic, and load control logic models. Intended to only contain `inc` statements.

No hardware dependent interfaces should be placed in layer 3, to enable re-use between different boards.
Example:
```
inc /int/defaults.cfg
inc /ext/control-loop.cfg
inc /ext/sensors.cfg
inc /ext/telemetry.cfg
inc /ext/glue.cfg
```

# To be designed

Expand Down
Binary file added config_int.dmg
Binary file not shown.
Binary file added fs_int.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion make/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ TARGET_fatfs_INCLUDES = \
vendor/fatfs

TARGET_fatfs_SOURCES = \
integration/fatfs/diskio.c \
integration/fatfs/ffsystem.c \
vendor/fatfs/ff.c \
vendor/fatfs/ffunicode.c

TARGET_core_SOURCES = \
core/config.c \
core/disk_access.c \
core/disk_int.c \
core/module.c \
core/interface.c \
core/peripheral.c \
Expand Down
32 changes: 20 additions & 12 deletions src/core/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
#include "lib/strops.h"
#include "lib/map.h"

#include "ff.h"

#include "vendor/tinyprintf/tinyprintf.h"

#define LINEBUF_SIZE 256
#define LINEBUF_NUM_ARGS 32

extern const char __l1conf_start[];

static char cf_linebuf[LINEBUF_SIZE];
static map_t *cf_peripherals;

Expand Down Expand Up @@ -63,6 +63,8 @@ static int cf_process_line(
/* TODO: Error handling */
return -1;
}
} else if (0 == strops_cmp("inc", argv[0])) {
/* Ignore for now, enqueue file name later */
} else {
/* TODO: Error handling */
return -1;
Expand All @@ -71,22 +73,28 @@ static int cf_process_line(
}

int cf_init(
void)
const char *path)
{
const char *cur = __l1conf_start;
FIL f;
FRESULT res;

cf_peripherals = map_create();

while (*cur != '\0') {
if (0 == strops_line_copy(cf_linebuf, LINEBUF_SIZE, &cur)) {
char *argv[LINEBUF_NUM_ARGS];
int argc = strops_split_argv(cf_linebuf, argv);
if (cf_process_line(argc, argv) < 0) {
/* TODO: Error handling */
return -1;
}
res = f_open(&f, path, FA_READ);
if (res != FR_OK) {
return -1;
}

/* Read every line and display it */
while (f_gets(cf_linebuf, sizeof(cf_linebuf), &f)) {
char *argv[LINEBUF_NUM_ARGS];
int argc = strops_split_argv(cf_linebuf, argv);
if (cf_process_line(argc, argv) < 0) {
f_close(&f);
return -1;
}
}
f_close(&f);

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#pragma once

int cf_init(
void);
const char *path);

char *const *cf_get_pp_config(
const char *tag);
110 changes: 99 additions & 11 deletions src/core/disk_access.c
Original file line number Diff line number Diff line change
@@ -1,35 +1,123 @@
/*
* NodeFlight - platform for embedded control systems
* Copyright (C) 2020 Max Sikström
*
* 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, see <https://www.gnu.org/licenses/>.
*/

#include "disk_access.h"

disk_access_t *disk_access[FF_VOLUMES];
#include "ff.h"

#define DEBUG 0

#if DEBUG
#include "vendor/tinyprintf/tinyprintf.h"
#define PRINTF(...) tfp_printf(__VA_ARGS__)
#else
#define PRINTF(...) do {} while(0)
#endif

static disk_access_t *disk_access[FF_VOLUMES];
static int disks_mounted = 0;

static FATFS *disk_fs[FF_VOLUMES];

/* Mount names */
const char *VolumeStr[FF_VOLUMES] = {
"not_mounted_a", "not_mounted_b", "not_mounted_c", "not_mounted_d"
};

void disk_access_init(
void)
{
int i;
disks_mounted = 0;
for (i = 0; i < FF_VOLUMES; i++) {
disk_access[i] = NULL;
disk_fs[i] = NULL;
}
}

int disk_access_register(
int disk_id,
disk_access_t *dacc)
{
if (disk_id < 0 || disk_id >= FF_VOLUMES) {
char id_string[3] = "0:";
if (disks_mounted >= FF_VOLUMES) {
return -1;
}
if (disk_access[disk_id] != NULL) {
int disk_id = disks_mounted++;
disk_access[disk_id] = dacc;
VolumeStr[disk_id] = dacc->name;

/* Allocate FATFS */
disk_fs[disk_id] = pvPortMalloc(sizeof(FATFS));
if (disk_fs[disk_id] == NULL) {
return -1;
}

/* Mount via disk id */
id_string[0] = '0' + disk_id;
if (FR_OK != f_mount(disk_fs[disk_id], id_string, 0)) {
return -1;
}
disk_access[disk_id] = dacc;
return 0;
}

disk_access_t *disk_access_get(
int disk_id)
/*
* diskio interface for fatfs
*/

DSTATUS disk_initialize (
BYTE pdrv)
{
PRINTF("disk_initialize(%u)\n", pdrv);
return disk_access[pdrv]->initialize(disk_access[pdrv]->storage);
}

DSTATUS disk_status (
BYTE pdrv)
{
if (disk_id < 0 || disk_id >= FF_VOLUMES) {
return NULL;
}
return disk_access[disk_id];
PRINTF("disk_status(%u)\n", pdrv);
return disk_access[pdrv]->status(disk_access[pdrv]->storage);
}

DRESULT disk_read (
BYTE pdrv,
BYTE *buff,
LBA_t sector,
UINT count)
{
PRINTF("disk_read(%u, %p, %lu, %u)\n", pdrv, buff, sector, count);
return disk_access[pdrv]->read(disk_access[pdrv]->storage, buff, sector, count);
}

DRESULT disk_write (
BYTE pdrv,
const BYTE *buff,
LBA_t sector,
UINT count)
{
PRINTF("disk_write(%u, %p, %lu, %u)\n", pdrv, buff, sector, count);
return disk_access[pdrv]->write(disk_access[pdrv]->storage, buff, sector, count);
}

DRESULT disk_ioctl (
BYTE pdrv,
BYTE cmd,
void *buff)
{
PRINTF("disk_ioctl(%u, %u, %p)\n", pdrv, cmd, buff);
return disk_access[pdrv]->ioctl(disk_access[pdrv]->storage, cmd, buff);
}
6 changes: 2 additions & 4 deletions src/core/disk_access.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ typedef struct disk_access_s disk_access_t;
#include "diskio.h"

struct disk_access_s {
const char *name;

DSTATUS (*initialize)(
void *storage);

Expand Down Expand Up @@ -56,8 +58,4 @@ void disk_access_init(
void);

int disk_access_register(
int disk_id,
disk_access_t *dacc);

disk_access_t *disk_access_get(
int disk_id);
Loading

0 comments on commit c7a6a74

Please sign in to comment.