1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

pkg/tinyvcdiff: add MTD driver

This commit is contained in:
Jue 2022-03-11 11:38:28 +01:00 committed by Juergen Fitschen
parent 5571d5c7a3
commit e2e4dbec39
6 changed files with 282 additions and 0 deletions

View File

@ -19,4 +19,21 @@ config TINYVCDIFF_BUFFER_SIZE
the underlying MTD or VFS backend. But a size of just 1 byte would
work, too.
menuconfig MODULE_TINYVCDIFF_MTD
bool "MTD Backend"
depends on MODULE_MTD
default y
help
Use a MTD device as VCDIFF target or source.
if MODULE_TINYVCDIFF_MTD
config TINYVCDIFF_MTD_WRITE_SIZE
int "Write size"
default 4
help
Alignment and minimum size for MTD write access.
endif # MODULE_TINYVCDIFF_MTD
endif # PACKAGE_TINYVCDIFF

View File

@ -0,0 +1,3 @@
ifneq (,$(filter mtd,$(USEMODULE)))
USEMODULE += tinyvcdiff_mtd
endif

View File

@ -8,3 +8,8 @@ ifneq ($(DEVELHELP),1)
endif
INCLUDES += -I$(PKGDIRBASE)/tinyvcdiff/include
INCLUDES += -I$(RIOTPKG)/tinyvcdiff/include
ifneq (,$(filter tinyvcdiff_mtd,$(USEMODULE)))
DIRS += $(RIOTPKG)/tinyvcdiff/contrib/tinyvcdiff_mtd
endif

View File

@ -0,0 +1,3 @@
MODULE = tinyvcdiff_mtd
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,179 @@
/*
* Copyright (C) 2022 Juergen Fitschen
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include "vcdiff_mtd.h"
#include "assert.h"
#include <string.h>
#define ENABLE_DEBUG 0
#include "debug.h"
static int _erase (void *dev, size_t offset, size_t len)
{
int rc;
vcdiff_mtd_t *mtd = dev;
size_t addr = offset + len;
size_t page = addr / mtd->dev->page_size;
size_t sector = page / mtd->dev->pages_per_sector;
size_t cnt = sector - mtd->next_erase_sector + 1;
/* early exit if all sectors are already in the erased state */
if (cnt == 0) {
return 0;
}
/* erase sectors */
rc = mtd_erase_sector(mtd->dev, mtd->next_erase_sector, cnt);
if (rc != 0) {
return rc;
}
mtd->next_erase_sector += cnt;
return 0;
}
static int _read (void *dev, uint8_t *dest, size_t offset, size_t len)
{
vcdiff_mtd_t *mtd = dev;
/* mtd_read_page will take care of calculation the right page */
int rc = mtd_read_page(mtd->dev, dest, 0, offset, len);
return rc;
}
static int _align_write (vcdiff_mtd_t *mtd, uint8_t **src, size_t *len)
{
size_t alignment_offset;
size_t copy_len;
alignment_offset = mtd->offset % CONFIG_TINYVCDIFF_MTD_WRITE_SIZE;
if (alignment_offset == 0) {
/* we are already aligned */
return 0;
}
/* check how many bytes have to be copied to be aligned */
copy_len = CONFIG_TINYVCDIFF_MTD_WRITE_SIZE - alignment_offset;
if (copy_len > *len) {
copy_len = *len;
}
/* copy unaligned bytes to the write buffer */
memcpy(&mtd->write_buffer[alignment_offset], *src, copy_len);
alignment_offset += copy_len;
mtd->offset += copy_len;
*len -= copy_len;
*src += copy_len;
DEBUG("_align_write: buffered %zuB for alignment\n", copy_len);
if (alignment_offset < CONFIG_TINYVCDIFF_MTD_WRITE_SIZE) {
/* we haven't collected enough bytes, yet */
return 0;
}
assert(alignment_offset == CONFIG_TINYVCDIFF_MTD_WRITE_SIZE);
DEBUG("_align_write: write buffered data\n");
/* write buffer to mtd
* mtd_read_page will take care of calculation the right page
* it's safe to call mtd_read_page_raw: the erase driver already
* prepared the sector for writing */
return mtd_write_page_raw(mtd->dev, mtd->write_buffer, 0,
mtd->offset - alignment_offset,
CONFIG_TINYVCDIFF_MTD_WRITE_SIZE);
}
static int _write (void *dev, uint8_t *src, size_t offset, size_t len)
{
int rc;
size_t to_copy;
vcdiff_mtd_t *mtd = dev;
assert(offset == mtd->offset);
DEBUG("_write: 0x%zx + %zuB\n", mtd->offset, len);
/* align writes */
rc = _align_write(dev, &src, &len);
if (rc < 0) {
/* an error occurred */
return rc;
} else if (len == 0) {
/* no bytes are left */
return 0;
}
assert((mtd->offset % CONFIG_TINYVCDIFF_MTD_WRITE_SIZE) == 0);
/* copy all aligned data */
to_copy = (len / CONFIG_TINYVCDIFF_MTD_WRITE_SIZE) * CONFIG_TINYVCDIFF_MTD_WRITE_SIZE;
rc = mtd_write_page_raw(mtd->dev, src, 0, mtd->offset, to_copy);
if (rc < 0) {
return rc;
}
mtd->offset += to_copy;
len -= to_copy;
src += to_copy;
if (len == 0) {
/* no bytes are left */
return 0;
}
assert(len < CONFIG_TINYVCDIFF_MTD_WRITE_SIZE);
/* copy remaining bytes into write_buffer */
memcpy(mtd->write_buffer, src, len);
mtd->offset += len;
DEBUG("_write: buffered %zuB for alignment\n", len);
return rc;
}
static int _flush (void *dev)
{
vcdiff_mtd_t *mtd = dev;
int rc;
uint8_t buf[CONFIG_TINYVCDIFF_MTD_WRITE_SIZE];
size_t alignment_offset;
alignment_offset = mtd->offset % CONFIG_TINYVCDIFF_MTD_WRITE_SIZE;
if (alignment_offset == 0) {
/* we are already aligned -> no bytes are left in the buffer */
return 0;
}
DEBUG("_flush: write last %zuB\n", alignment_offset);
/* get present bytes from MTD to pad alignment */
rc = mtd_read_page(mtd->dev, buf, 0, mtd->offset - alignment_offset,
CONFIG_TINYVCDIFF_MTD_WRITE_SIZE);
if (rc < 0) {
return rc;
}
/* pad write buffer */
memcpy(&mtd->write_buffer[alignment_offset], &buf[alignment_offset],
CONFIG_TINYVCDIFF_MTD_WRITE_SIZE - alignment_offset);
/* write last buffer */
rc = mtd_write_page_raw(mtd->dev, mtd->write_buffer, 0,
mtd->offset - alignment_offset,
CONFIG_TINYVCDIFF_MTD_WRITE_SIZE);
return rc;
}
const vcdiff_driver_t vcdiff_mtd_driver = {
.erase = _erase,
.read = _read,
.write = _write,
.flush = _flush
};

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2022 Juergen Fitschen
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
*
* @file
* @ingroup pkg_tinyvcdiff
*
* @author Juergen Fitschen <me@jue.yt>
*/
#ifndef VCDIFF_MTD_H
#define VCDIFF_MTD_H
#include "vcdiff.h"
#include "mtd.h"
#ifndef CONFIG_TINYVCDIFF_MTD_WRITE_SIZE
/**
* @brief Alignment and minimum size for MTD write access
*/
#define CONFIG_TINYVCDIFF_MTD_WRITE_SIZE 4
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Driver for accessing MTD devices
*/
extern const vcdiff_driver_t vcdiff_mtd_driver;
/**
* @brief Context for the underlying MTD device
*/
typedef struct {
/**
* @brief Instance of the backing MTD device
*/
mtd_dev_t *dev;
/**
* @brief Number of the next sector that must be erased
*/
size_t next_erase_sector;
/**
* @brief Buffer for aligned writes
*/
uint8_t write_buffer[CONFIG_TINYVCDIFF_MTD_WRITE_SIZE];
/**
* @brief Current offset on the MTD device
*/
size_t offset;
} vcdiff_mtd_t;
/**
* @brief Initializes vcdiff_mtd_t
*/
#define VCDIFF_MTD_INIT(DEV) { .dev = DEV }
#ifdef __cplusplus
}
#endif
#endif /* VCDIFF_MTD_H */
/** @} */