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:
parent
5571d5c7a3
commit
e2e4dbec39
@ -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
|
||||
|
3
pkg/tinyvcdiff/Makefile.dep
Normal file
3
pkg/tinyvcdiff/Makefile.dep
Normal file
@ -0,0 +1,3 @@
|
||||
ifneq (,$(filter mtd,$(USEMODULE)))
|
||||
USEMODULE += tinyvcdiff_mtd
|
||||
endif
|
@ -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
|
||||
|
3
pkg/tinyvcdiff/contrib/tinyvcdiff_mtd/Makefile
Normal file
3
pkg/tinyvcdiff/contrib/tinyvcdiff_mtd/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = tinyvcdiff_mtd
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
179
pkg/tinyvcdiff/contrib/tinyvcdiff_mtd/mtd.c
Normal file
179
pkg/tinyvcdiff/contrib/tinyvcdiff_mtd/mtd.c
Normal 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
|
||||
};
|
75
pkg/tinyvcdiff/include/vcdiff_mtd.h
Normal file
75
pkg/tinyvcdiff/include/vcdiff_mtd.h
Normal 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 */
|
||||
/** @} */
|
Loading…
Reference in New Issue
Block a user