Quellcode durchsuchen

1.补充提交缺失文件

libo vor 2 Jahren
Ursprung
Commit
70d4b97497

+ 587 - 0
lib/lib_ringfs/lib_ringfs.c

@@ -0,0 +1,587 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+/**
+ * @defgroup ringfs_impl RingFS implementation
+ * @details
+ *
+ * @{
+ */
+
+
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "lib_ringfs.h"
+
+/**
+ * @defgroup sector
+ * @{
+ */
+#if 0
+enum sector_status {
+    SECTOR_ERASED     = 0xFFFFFFFF, /**< Default state after NOR flash erase. */
+    SECTOR_FREE       = 0xFFFFFF00, /**< Sector erased. */
+    SECTOR_IN_USE     = 0xFFFF0000, /**< Sector contains valid data. */
+    SECTOR_ERASING    = 0xFF000000, /**< Sector should be erased. */
+    SECTOR_FORMATTING = 0x00000000, /**< The entire partition is being formatted. */
+};
+#else
+#define    SECTOR_ERASED     		0xFFFFFFFF /**< Default state after NOR flash erase. */
+#define    SECTOR_FREE       		0xFFFFFF00 /**< Sector erased. */
+#define    SECTOR_IN_USE     		0xFFFF0000 /**< Sector contains valid data. */
+#define    SECTOR_ERASING    		0xFF000000 /**< Sector should be erased. */
+#define    SECTOR_FORMATTING 		0x00000000 /**< The entire partition is being formatted. */
+#endif
+struct sector_header {
+    uint32_t status;
+    uint32_t version;
+};
+
+static int _sector_address(struct ringfs *fs, int sector_offset)
+{
+    return (fs->flash->sector_offset + sector_offset) * fs->flash->sector_size;
+}
+
+static int _sector_get_status(struct ringfs *fs, int sector, uint32_t *status)
+{
+    return fs->flash->read(fs->flash,
+            _sector_address(fs, sector) + offsetof(struct sector_header, status),
+            status, sizeof(*status));
+}
+
+static int _sector_set_status(struct ringfs *fs, int sector, uint32_t status)
+{
+    return fs->flash->program(fs->flash,
+            _sector_address(fs, sector) + offsetof(struct sector_header, status),
+            &status, sizeof(status));
+}
+
+static int _sector_free(struct ringfs *fs, int sector)
+{
+    int sector_addr = _sector_address(fs, sector);
+    _sector_set_status(fs, sector, SECTOR_ERASING);
+    fs->flash->sector_erase(fs->flash, sector_addr);
+    fs->flash->program(fs->flash,
+            sector_addr + offsetof(struct sector_header, version),
+            &fs->version, sizeof(fs->version));
+    _sector_set_status(fs, sector, SECTOR_FREE);
+    return 0;
+}
+
+/**
+ * @}
+ * @defgroup slot
+ * @{
+ */
+#if  0
+enum slot_status {
+    SLOT_ERASED   = 0xFFFFFFFF, /**< Default state after NOR flash erase. */
+    SLOT_RESERVED = 0xFFFFFF00, /**< Write started but not yet committed. */
+    SLOT_VALID    = 0xFFFF0000, /**< Write committed, slot contains valid data. */
+    SLOT_GARBAGE  = 0xFF000000, /**< Slot contents discarded and no longer valid. */
+};
+#else
+#define        SLOT_ERASED			0xFFFFFFFF	/**< Default state after NOR flash erase. */
+#define        SLOT_RESERVED		0xFFFFFF00	/**< Write started but not yet committed. */
+#define        SLOT_VALID				0xFFFF0000	/**< Write committed, slot contains valid data. */
+#define        SLOT_GARBAGE			0xFF000000	/**< Slot contents discarded and no longer valid. */
+#endif
+struct slot_header {
+    uint32_t status;
+};
+
+static int _slot_address(struct ringfs *fs, struct ringfs_loc *loc)
+{
+    return _sector_address(fs, loc->sector) +
+           sizeof(struct sector_header) +
+           (sizeof(struct slot_header) + fs->object_size) * loc->slot;
+}
+
+static int _slot_get_status(struct ringfs *fs, struct ringfs_loc *loc, uint32_t *status)
+{
+    return fs->flash->read(fs->flash,
+            _slot_address(fs, loc) + offsetof(struct slot_header, status),
+            status, sizeof(*status));
+}
+
+static int _slot_set_status(struct ringfs *fs, struct ringfs_loc *loc, uint32_t status)
+{
+    return fs->flash->program(fs->flash, 
+            _slot_address(fs, loc) + offsetof(struct slot_header, status),
+            &status, sizeof(status));
+}
+
+/**
+ * @}
+ * @defgroup loc
+ * @{
+ */
+
+static bool _loc_equal(struct ringfs_loc *a, struct ringfs_loc *b)
+{
+    return (a->sector == b->sector) && (a->slot == b->slot);
+}
+
+/** Advance a location to the beginning of the next sector. */
+static void _loc_advance_sector(struct ringfs *fs, struct ringfs_loc *loc)
+{
+    loc->slot = 0;
+    loc->sector++;
+    if (loc->sector >= fs->flash->sector_count)
+        loc->sector = 0;
+}
+
+/** Advance a location to the next slot, advancing the sector too if needed. */
+static void _loc_advance_slot(struct ringfs *fs, struct ringfs_loc *loc)
+{
+    loc->slot++;
+    if (loc->slot >= fs->slots_per_sector)
+        _loc_advance_sector(fs, loc);
+}
+
+/** Back a location to the ending of the pre sector. */
+static void _loc_back_sector(struct ringfs *fs, struct ringfs_loc *loc)
+{
+    loc->slot = fs->slots_per_sector - 1;
+    loc->sector--;
+    if (loc->sector < 0)
+        loc->sector = fs->flash->sector_count - 1;
+}
+
+/** Back a location to the next slot, backing the sector too if needed. */
+static void _loc_back_slot(struct ringfs *fs, struct ringfs_loc *loc)
+{
+    loc->slot--;
+    if (loc->slot < 0)
+        _loc_back_sector(fs, loc);
+}
+
+/**
+ * @}
+ */
+
+/* And here we go. */
+
+int ringfs_init(struct ringfs *fs, struct ringfs_flash_partition *flash, uint32_t version, int object_size)
+{
+    /* Copy arguments to instance. */
+    fs->flash 			= flash;
+    fs->version 		= version;
+    fs->object_size = object_size;
+
+    /* Precalculate commonly used values. */
+    fs->slots_per_sector = (fs->flash->sector_size - sizeof(struct sector_header)) /
+                           (sizeof(struct slot_header) + fs->object_size);
+
+    return 0;
+}
+
+int ringfs_format(struct ringfs *fs)
+{
+    /* Mark all sectors to prevent half-erased filesystems. */
+    for (int sector=0; sector<fs->flash->sector_count; sector++)
+        _sector_set_status(fs, sector, SECTOR_FORMATTING);
+
+    /* Erase, update version, mark as free. */
+    for (int sector=0; sector<fs->flash->sector_count; sector++)
+        _sector_free(fs, sector);
+
+    /* Start reading & writing at the first sector. */
+    fs->read.sector = 0;
+    fs->read.slot = 0;
+    fs->write.sector = 0;
+    fs->write.slot = 0;
+    fs->cursor.sector = 0;
+    fs->cursor.slot = 0;
+
+    return 0;
+}
+
+int ringfs_scan(struct ringfs *fs)
+{
+    uint32_t previous_sector_status = SECTOR_FREE;
+    /* The read sector is the first IN_USE sector *after* a FREE sector
+     * (or the first one). */
+    int read_sector = 0;
+    /* The write sector is the last IN_USE sector *before* a FREE sector
+     * (or the last one). */
+    int write_sector = fs->flash->sector_count - 1;
+    /* There must be at least one FREE sector available at all times. */
+    bool free_seen = false;
+    /* If there's no IN_USE sector, we start at the first one. */
+    bool used_seen = false;
+
+    /* Iterate over sectors. */
+    for (int sector=0; sector<fs->flash->sector_count; sector++) {
+        int addr = _sector_address(fs, sector);
+
+        /* Read sector header. */
+        struct sector_header header;
+        fs->flash->read(fs->flash, addr, &header, sizeof(header));
+
+        /* Detect partially-formatted partitions. */
+        if (header.status == SECTOR_FORMATTING) {
+            printf("ringfs_scan: partially formatted partition\r\n");
+            return -1;
+        }
+
+        /* Detect and fix partially erased sectors. */
+        if (header.status == SECTOR_ERASING || header.status == SECTOR_ERASED) {
+            _sector_free(fs, addr);
+            header.status = SECTOR_FREE;
+        }
+
+        /* Detect corrupted sectors. */
+        if (header.status != SECTOR_FREE && header.status != SECTOR_IN_USE) {
+            printf("ringfs_scan: corrupted sector %d\r\n", sector);
+            return -1;
+        }
+
+        /* Detect obsolete versions. We can't do this earlier because the version
+         * could have been invalid due to a partial erase. */
+        if (header.version != fs->version) {
+            printf("ringfs_scan: incompatible version 0x%08"PRIx32"\r\n", header.version);
+            return -1;
+        }
+
+        /* Record the presence of a FREE sector. */
+        if (header.status == SECTOR_FREE)
+            free_seen = true;
+
+        /* Record the presence of a IN_USE sector. */
+        if (header.status == SECTOR_IN_USE)
+            used_seen = true;
+
+        /* Update read & write sectors according to the above rules. */
+        if (header.status == SECTOR_IN_USE && previous_sector_status == SECTOR_FREE)
+            read_sector = sector;
+        if (header.status == SECTOR_FREE && previous_sector_status == SECTOR_IN_USE)
+            write_sector = sector-1;
+
+        previous_sector_status = header.status;
+    }
+
+    /* Detect the lack of a FREE sector. */
+    if (!free_seen) {
+        printf("ringfs_scan: invariant violated: no FREE sector found\r\n");
+        return -1;
+    }
+
+    /* Start writing at the first sector if the filesystem is empty. */
+    if (!used_seen) {
+        write_sector = 0;
+    }
+
+    /* Scan the write sector and skip all occupied slots at the beginning. */
+    fs->write.sector = write_sector;
+    fs->write.slot = 0;
+    while (fs->write.sector == write_sector) {
+        uint32_t status;
+        _slot_get_status(fs, &fs->write, &status);
+        if (status == SLOT_ERASED)
+            break;
+
+        _loc_advance_slot(fs, &fs->write);
+    }
+    /* If the sector was full, we're at the beginning of a FREE sector now. */
+
+    /* Position the read head at the start of the first IN_USE sector, then skip
+     * over garbage/invalid slots until something of value is found or we reach
+     * the write head which means there's no data. */
+    fs->read.sector = read_sector;
+    fs->read.slot = 0;
+    while (!_loc_equal(&fs->read, &fs->write)) {
+        uint32_t status;
+        _slot_get_status(fs, &fs->read, &status);
+        if (status == SLOT_VALID)
+            break;
+
+        _loc_advance_slot(fs, &fs->read);
+    }
+
+    /* Move the read cursor to the read head position. */
+    fs->cursor = fs->read;
+
+    return 0;
+}
+
+int ringfs_capacity(struct ringfs *fs)
+{
+    return fs->slots_per_sector * (fs->flash->sector_count - 1);
+}
+
+int ringfs_count_estimate(struct ringfs *fs)
+{
+    int sector_diff = (fs->write.sector - fs->read.sector + fs->flash->sector_count) %
+        fs->flash->sector_count;
+
+    return sector_diff * fs->slots_per_sector + fs->write.slot - fs->read.slot;
+}
+
+int ringfs_count_exact(struct ringfs *fs)
+{
+    int count = 0;
+
+    /* Use a temporary loc for iteration. */
+    struct ringfs_loc loc = fs->read;
+    while (!_loc_equal(&loc, &fs->write)) {
+        uint32_t status;
+        _slot_get_status(fs, &loc, &status);
+        
+        if (status == SLOT_VALID)
+            count++;
+
+        _loc_advance_slot(fs, &loc);
+    }
+
+    return count;
+}
+
+int ringfs_append(struct ringfs *fs, const void *object)
+{
+    uint32_t status;
+
+    /*
+     * There are three sectors involved in appending a value:
+     * - the sector where the append happens: it has to be writable
+     * - the next sector: it must be free (invariant)
+     * - the next-next sector: read & cursor heads are moved there if needed
+     */
+
+    /* Make sure the next sector is free. */
+    int next_sector = (fs->write.sector+1) % fs->flash->sector_count;
+    _sector_get_status(fs, next_sector, &status);
+    if (status != SECTOR_FREE) {
+        /* Next sector must be freed. But first... */
+
+        /* Move the read & cursor heads out of the way. */
+        if (fs->read.sector == next_sector)
+            _loc_advance_sector(fs, &fs->read);
+        if (fs->cursor.sector == next_sector)
+            _loc_advance_sector(fs, &fs->cursor);
+
+        /* Free the next sector. */
+        _sector_free(fs, next_sector);
+    }
+
+    /* Now we can make sure the current write sector is writable. */
+    _sector_get_status(fs, fs->write.sector, &status);
+    if (status == SECTOR_FREE) {
+        /* Free sector. Mark as used. */
+        _sector_set_status(fs, fs->write.sector, SECTOR_IN_USE);
+    } else if (status != SECTOR_IN_USE) {
+        printf("ringfs_append: corrupted filesystem\r\n");
+        return -1;
+    }
+
+    /* Preallocate slot. */
+    _slot_set_status(fs, &fs->write, SLOT_RESERVED);
+
+    /* Write object. */
+    fs->flash->program(fs->flash,
+            _slot_address(fs, &fs->write) + sizeof(struct slot_header),
+            object, fs->object_size);
+
+    /* Commit write. */
+    _slot_set_status(fs, &fs->write, SLOT_VALID);
+
+    /* Advance the write head. */
+    _loc_advance_slot(fs, &fs->write);
+
+    return 0;
+}
+
+int ringfs_fetch(struct ringfs *fs, void *object)
+{
+    /* Advance forward in search of a valid slot. */
+    while (!_loc_equal(&fs->cursor, &fs->write)) {
+        uint32_t status;
+
+        _slot_get_status(fs, &fs->cursor, &status);
+
+        if (status == SLOT_VALID) {
+            fs->flash->read(fs->flash,
+                    _slot_address(fs, &fs->cursor) + sizeof(struct slot_header),
+                    object, fs->object_size);
+            _loc_advance_slot(fs, &fs->cursor);
+            return 0;
+        }
+
+        _loc_advance_slot(fs, &fs->cursor);
+    }
+
+    return -1;
+}
+
+int ringfs_pop(struct ringfs *fs, void *object)
+{
+		fs->cursor = fs->write;
+    /* Advance forward in search of a valid slot. */
+		/*向前搜索有效的数据单元*/
+   return ringfs_del(fs, object);
+}
+
+int ringfs_del(struct ringfs *fs, void *object)
+{
+    /* Advance forward in search of a valid slot. */
+    while (!_loc_equal(&fs->cursor, &fs->read)) {
+        uint32_t status;
+							
+				_loc_back_slot(fs, &fs->cursor);
+
+			
+        _slot_get_status(fs, &fs->cursor, &status);
+
+        if (status == SLOT_VALID) {
+            fs->flash->read(fs->flash,
+                    _slot_address(fs, &fs->cursor) + sizeof(struct slot_header),
+                    object, fs->object_size);
+										
+						_slot_set_status(fs, &fs->cursor, SLOT_GARBAGE);
+										
+						//boly modify 20221124				
+            //_loc_back_slot(fs, &fs->cursor);
+						//end boly										
+            return 0;
+        }     
+
+    }
+		
+		ringfs_check(fs);
+		
+    return -1;
+}
+
+int ringfs_discard(struct ringfs *fs)
+{
+    while (!_loc_equal(&fs->read, &fs->cursor)) {
+        _slot_set_status(fs, &fs->read, SLOT_GARBAGE);
+        _loc_advance_slot(fs, &fs->read);
+    }
+
+    return 0;
+}
+
+int ringfs_item_discard(struct ringfs *fs)
+{
+        _slot_set_status(fs, &fs->read, SLOT_GARBAGE);
+        _loc_advance_slot(fs, &fs->read);
+
+    return 0;
+}
+
+int ringfs_end(struct ringfs *fs)
+{
+    fs->cursor = fs->write;
+    return 0;
+}
+
+
+int ringfs_rewind(struct ringfs *fs)
+{
+    fs->cursor = fs->read;
+    return 0;
+}
+
+int ringfs_check(struct ringfs *fs)
+{
+		uint32_t status;
+	
+	  if(_loc_equal(&fs->write, &fs->read))	//检查读写位置是否一致
+		{
+			return -1;
+		}
+		
+    _slot_get_status(fs, &fs->read, &status);				
+	  if (status != SLOT_GARBAGE)						//检查读取位置是否可用
+		{
+			return -1;
+		}
+			
+		if(_loc_equal(&fs->read, &fs->cursor)	)//检查当前位置与读取位置是否一致
+		{
+			_loc_advance_slot(fs, &fs->read);
+			fs->cursor = fs->read;				
+		}
+		else			
+		{
+			_loc_advance_slot(fs, &fs->read);
+		}			
+	
+    return 0;
+}
+
+
+void ringfs_dump(FILE *stream, struct ringfs *fs)
+{
+    const char *description;
+
+    fprintf(stream, "RingFS read: {%d,%d} cursor: {%d,%d} write: {%d,%d}\n",
+            fs->read.sector, fs->read.slot,
+            fs->cursor.sector, fs->cursor.slot,
+            fs->write.sector, fs->write.slot);
+
+    for (int sector=0; sector<fs->flash->sector_count; sector++) {
+        int addr = _sector_address(fs, sector);
+
+        /* Read sector header. */
+        struct sector_header header;
+        fs->flash->read(fs->flash, addr, &header, sizeof(header));
+
+        switch (header.status) {
+            case SECTOR_ERASED: description = "ERASED"; break;
+            case SECTOR_FREE: description = "FREE"; break;
+            case SECTOR_IN_USE: description = "IN_USE"; break;
+            case SECTOR_ERASING: description = "ERASING"; break;
+            case SECTOR_FORMATTING: description = "FORMATTING"; break;
+            default: description = "UNKNOWN"; break;
+        }
+
+        fprintf(stream, "[%04d] [v=0x%08"PRIx32"] [%-10s] ",
+                sector, header.version, description);
+
+        for (int slot=0; slot<fs->slots_per_sector; slot++) {
+            struct ringfs_loc loc = { sector, slot };
+            uint32_t status;
+            _slot_get_status(fs, &loc, &status);
+
+            switch (status) {
+                case SLOT_ERASED: description = "E"; break;
+                case SLOT_RESERVED: description = "R"; break;
+                case SLOT_VALID: description = "V"; break;
+                case SLOT_GARBAGE: description = "G"; break;
+                default: description = "?"; break;
+            }
+
+            fprintf(stream, "%s", description);
+        }
+
+        fprintf(stream, "\n");
+    }
+
+    fflush(stream);
+}
+
+void ringfs_assert_failed(int8_t* func, int8_t* file, uint32_t line)
+{
+// User can add his own implementation to report the file name and line number,
+// ex: printf(“Wrong parameters value: file %s on line %d\r\n”, file, line) /
+// Infinite loop */
+	while (1){
+	};
+};
+
+
+/**
+ * @}
+ */
+
+/* vim: set ts=4 sw=4 et: */

+ 246 - 0
lib/lib_ringfs/lib_ringfs.h

@@ -0,0 +1,246 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+#ifndef RINGFS_H
+#define RINGFS_H
+
+/**
+ * @defgroup ringfs_api RingFS API
+ * @{
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stddef.h>
+//#include <unistd.h>
+typedef size_t ssize_t;
+
+#ifndef NDEBUG
+#define RFS_ASSERT(x)	((void)(x))
+#else /* debugging enabled */
+void ringfs_assert_failed(int8_t* func, int8_t* file, uint32_t line);
+#define RFS_ASSERT(e)       ((e) ? (void)0 : ringfs_assert_failed(#e, __FILE__, __LINE__))	
+#endif	/* NDEBUG */
+
+/**
+ * Flash memory+parition descriptor.
+ */
+struct ringfs_flash_partition
+{
+    int sector_size;            /**< Sector size, in bytes. */
+    int sector_offset;          /**< Partition offset, in sectors. */
+    int sector_count;           /**< Partition size, in sectors. */
+
+    /**
+     * Erase a sector.
+     * @param address Any address inside the sector.
+     * @returns Zero on success, -1 on failure.
+		 * 擦除扇区。
+		 * @param address扇区内的任何地址。
+		 * @return 成功时为零,失败时为-1。
+     */
+    int (*sector_erase)(struct ringfs_flash_partition *flash, int address);
+    /**
+     * Program flash memory bits by toggling them from 1 to 0.
+     * @param address Start address, in bytes.
+     * @param data Data to program.
+     * @param size Size of data.
+     * @returns size on success, -1 on failure.
+     */
+    ssize_t (*program)(struct ringfs_flash_partition *flash, int address, const void *data, size_t size);
+    /**
+     * Read flash memory.
+     * @param address Start address, in bytes.
+     * @param data Buffer to store read data.
+     * @param size Size of data.
+     * @returns size on success, -1 on failure.
+     */
+    ssize_t (*read)(struct ringfs_flash_partition *flash, int address, void *data, size_t size);
+};
+
+/** @private */
+struct ringfs_loc {
+    int sector;
+    int slot;
+};
+
+/**
+ * RingFS instance. Should be initialized with ringfs_init() befure use.
+ * Structure fields should not be accessed directly.
+	*RingFS实例。应在使用前使用ringfs_init()初始化。
+	*不应直接访问结构字段。
+ * */
+struct ringfs {
+    /* Constant values, set once at ringfs_init(). */
+    struct ringfs_flash_partition *flash;
+    uint32_t version;
+    int object_size;
+    /* Cached values. */
+    int slots_per_sector;
+
+    /* Read/write pointers. Modified as needed. */
+    struct ringfs_loc read;
+    struct ringfs_loc write;
+    struct ringfs_loc cursor;
+};
+
+/**
+ * Initialize a RingFS instance. Must be called before the instance can be used
+ * with the other ringfs_* functions.
+ * 初始化RingFS实例。必须在使用实例之前调用
+ * 与其他ringfs_*函数一起使用。
+ * @param fs RingFS instance to be initialized.
+ * @param flash Flash memory interface. Must be implemented externally.
+ * @param version Object version. Should be incremented whenever the object's
+ *                semantics or size change in a backwards-incompatible way.
+ * @param object_size Size of one stored object, in bytes.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_init(struct ringfs *fs, struct ringfs_flash_partition *flash, uint32_t version, int object_size);
+
+/**
+ * Format the flash memory.
+ * 格式化FLASH 存储器。
+ *
+ * @param fs Initialized RingFS instance.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_format(struct ringfs *fs);
+
+/**
+ * Scan the flash memory for a valid filesystem.
+ * 扫描FLASH 存储器以获取有效的文件系统
+ *
+ * @param fs Initialized RingFS instance.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_scan(struct ringfs *fs);
+
+/**
+ * Calculate maximum RingFS capacity.
+ * 计算RingFS最大容量。
+ *
+ * @param fs Initialized RingFS instance.
+ * @returns Maximum capacity on success, -1 on failure.
+ */
+int ringfs_capacity(struct ringfs *fs);
+
+/**
+ * Calculate approximate object count.
+ * Runs in O(1).
+ * 计算近似对象数。
+ * 在O(1)中运行。
+ *
+ * @param fs Initialized RingFS instance.
+ * @returns Estimated object count on success, -1 on failure.
+ */
+int ringfs_count_estimate(struct ringfs *fs);
+
+/**
+ * Calculate exact object count.
+ * Runs in O(n).
+ * 计算确切的对象数量。
+ * 以O(n)运行。
+ * 
+ * @param fs Initialized RingFS instance.
+ * @returns Exact object count on success, -1 on failure.
+ */
+int ringfs_count_exact(struct ringfs *fs);
+
+/**
+ * Append an object at the end of the ring. Deletes oldest objects as needed.
+ * 在RingFS末端附加一个对象。根据需要删除最旧的对象。
+ * @param fs Initialized RingFS instance.
+ * @param object Object to be stored.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_append(struct ringfs *fs, const void *object);
+/**
+ *  Deletes newest objects.
+ *  根据删除最新可用的对象。
+ * @param fs Initialized RingFS instance.
+ * @param object Object to be stored.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_pop(struct ringfs *fs, void *object);
+/**
+ *  Deletes cur valid objects.
+ *  根据当前向前删除可用的对象。
+ * @param fs Initialized RingFS instance.
+ * @param object Object to be stored.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_del(struct ringfs *fs, void *object);
+/**
+ *  Deletes newest objects.
+ *  根据删除最新可用的对象。
+ * @param fs Initialized RingFS instance.
+ * @param object Object to be stored.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_pop(struct ringfs *fs, void *object);
+
+/**
+ * Fetch next object from the ring, oldest-first. Advances read cursor.
+ * 从RingFS中取出下一个对象,先取出最旧的。前进读取光标。
+ *
+ * @param fs Initialized RingFS instance.
+ * @param object Buffer to store retrieved object.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_fetch(struct ringfs *fs, void *object);
+
+/**
+ * Discard all fetched objects up to the read cursor.
+ * 丢弃到读取光标为止的所有提取对象。
+ *
+ * @param fs Initialized RingFS instance.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_discard(struct ringfs *fs);
+
+int ringfs_item_discard(struct ringfs *fs);
+
+/**
+ * Rewind the read cursor back to the oldest object.
+ * 将读取光标回退到最旧的对象。
+ * @param fs Initialized RingFS instance.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_rewind(struct ringfs *fs);
+
+/**
+ * Rewind the read cursor advance to the newest object.
+ * 将读取光标前进到最新的对象。
+ * @param fs Initialized RingFS instance.
+ * @returns Zero on success, -1 on failure.
+ */
+int ringfs_end(struct ringfs *fs);
+
+/**
+ * Dump filesystem metadata. For debugging purposes.
+ * 转储文件系统元数据。用于调试目的。
+ * @param stream File stream to write to.
+ * @param fs Initialized RingFS instance.
+ */
+void ringfs_dump(FILE *stream, struct ringfs *fs);
+
+/**
+ * 修正读取位置。
+ * @param stream File stream to write to.
+ * @param fs Initialized RingFS instance.
+ */
+int ringfs_check(struct ringfs *fs);
+
+/**
+ * @}
+ */
+
+#endif
+
+/* vim: set ts=4 sw=4 et: */

+ 177 - 0
lib/lib_ringfs/lib_ringfs_func.c

@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+#include <stdio.h>
+#include "lib_ringfs.h"
+#include "lib_ringfs_func.h"
+#include "lib_ringfs_ram.h"
+#include "lib_ringfs_w25q.h"
+#include "func_spi_w25qxx.h"
+#include "obj_hal_w25qxx.h"
+#include "obj_soft_w25qxx.h"
+
+/* Flash implementation & ops. */
+
+/* Data record format. */
+struct log_entry {
+    int level;
+    char message[16];
+};
+#define LOG_ENTRY_VERSION 1
+
+
+struct ringfs rfs_obj;
+
+
+int lib_ringfs_push(void *object, size_t size)
+{
+	if(ringfs_append(&rfs_obj, object) == 0)
+	{
+		ringfs_end(&rfs_obj);
+		return size;
+	}
+	return 0;
+}
+
+int lib_ringfs_pop(void *object, size_t size)
+{
+	if(ringfs_del(&rfs_obj, (void *)object) == 0)
+	{
+		return size;
+	}
+	
+	return 0;
+}
+
+
+uint32_t lib_ringfs_obj_cnt_estimate(void)
+{
+	return (uint32_t)ringfs_count_estimate(&rfs_obj);
+}
+
+uint32_t lib_ringfs_obj_cnt_exact(void)
+{
+	return (uint32_t)ringfs_count_exact(&rfs_obj);
+}
+
+/* Let's roll! */
+int lib_ringfs_init(int object_size)
+{
+    /* Initialize your Flash driver before using the filesystem. */
+	
+#if USE_LIB_RINGFS_RAM==1	
+    init_flash_driver_ram();
+		/* Always call ringfs_init first. */
+    ringfs_init(&rfs_obj, &rfs_disk_ram, LOG_ENTRY_VERSION, object_size);
+   
+#elif USE_LIB_RINGFS_W25Q==1
+	
+		init_flash_driver_w25q();
+	
+		/* Always call ringfs_init first. */
+    ringfs_init(&rfs_obj, &rfs_disk_w25q, LOG_ENTRY_VERSION, object_size);
+#endif
+	
+
+	
+    /* Scan and/or format before any data operations. */
+    printf("# scanning for filesystem...\n");
+    if (ringfs_scan(&rfs_obj) == 0) {
+        printf("# found existing filesystem, usage: %d/%d\n",
+                ringfs_count_estimate(&rfs_obj),
+                ringfs_capacity(&rfs_obj));
+    } else {
+        printf("# no valid filesystem found, formatting.\n");
+        ringfs_format(&rfs_obj);
+    }
+	//把光标位置移动到写入位置;	
+	ringfs_end(&rfs_obj);
+		
+	return 0;
+
+}
+
+
+int lib_ringfs_log_test(void)
+{
+		static uint32_t obj_idx = 0;
+	
+		int obj_cnt = ringfs_count_exact(&rfs_obj);
+
+		printf("\n\n\n# ringfs has %d objects\n", obj_cnt);
+    /* Append data using ringfs_append. Oldest data is removed as needed. */
+    printf("# inserting some objects\n");
+    ringfs_append(&rfs_obj, &(struct log_entry) { obj_idx++, "foo" });
+    ringfs_append(&rfs_obj, &(struct log_entry) { obj_idx++, "bar" });
+    ringfs_append(&rfs_obj, &(struct log_entry) { obj_idx++, "baz" });
+    ringfs_append(&rfs_obj, &(struct log_entry) { obj_idx++, "xyzzy" });
+    ringfs_append(&rfs_obj, &(struct log_entry) { obj_idx++, "test" });
+    ringfs_append(&rfs_obj, &(struct log_entry) { obj_idx++, "hello" });
+
+    /* Objects are retrieved using ringfs_fetch. They are not physically removed
+     * until you call ringfs_discard. This is useful, for example, when transmitting
+     * queued objects over the network: you don't physically remove the objects
+     * from the ring buffer until you receive an ACK. */
+    printf("# reading 2 objects\n");
+    for (int i=0; i<2; i++) {
+        struct log_entry entry;
+        RFS_ASSERT(ringfs_fetch(&rfs_obj, &entry) == 0);
+        printf("## level=%d message=%.16s\n", entry.level, entry.message);
+    }
+		if(0)
+		{
+			printf("# discarding read objects\n");
+			ringfs_discard(&rfs_obj);			
+		}
+
+    printf("# rewinding read head back\n");
+    ringfs_rewind(&rfs_obj);
+		
+    /* If you decide you can't remove the objects yet, just call ringfs_rewind() and
+     * they will be available again for subsequent reads. */
+    printf("# reading 2 objects\n");
+    for (int i=0; i<2; i++) {
+        struct log_entry entry;
+        if(ringfs_fetch(&rfs_obj, &entry) == 0)
+				{
+					printf("## level=%d message=%.16s\n", entry.level, entry.message);
+				}        
+    }
+
+		
+		printf("# popping 2 objects\n");
+		for (int i=0; i<2; i++) {
+        struct log_entry entry;
+        RFS_ASSERT(ringfs_pop(&rfs_obj, &entry) == 0);
+        printf("## level=%d message=%.16s\n", entry.level, entry.message);
+    }
+    /* ...and here they are again. */
+    printf("# reading 2 objects\n");
+    for (int i=0; i<2; i++) {
+        struct log_entry entry;
+				
+        if(ringfs_fetch(&rfs_obj, &entry) == 0)
+				{
+					printf("## level=%d message=%.16s\n", entry.level, entry.message);
+				}   
+    }
+		return 0;
+}
+
+void lib_ringfs_test(void const *argument)
+{
+		//UNUSED(argument);
+	
+		lib_ringfs_init(sizeof(struct log_entry));
+		while(1)
+		{
+			lib_ringfs_log_test();
+		};
+    //return 0;
+}
+/* vim: set ts=4 sw=4 et: */

+ 30 - 0
lib/lib_ringfs/lib_ringfs_func.h

@@ -0,0 +1,30 @@
+/*********************************************************
+//file		:lib_ringfs_func.h
+//author	:libo
+//date		:2022/10/28
+//version	:V1.0
+//brief		:GSP HAL层GPIO接口H文件
+*********************************************************/
+#ifndef LIB_RINGFS_FUNC_H
+#define LIB_RINGFS_FUNC_H
+
+/* Includes----------------------------------------------------------------------------------*/
+#define   USE_LIB_RINGFS_W25Q 	1
+#include <inttypes.h>
+
+/* Public macro------------------------------------------------------------------------------*/
+
+/* Public define-----------------------------------------------------------------------------*/
+
+/* Public typedef----------------------------------------------------------------------------*/
+
+/* public function---------------------------------------------------------------------------*/
+int 	lib_ringfs_init(int object_size);
+void 	lib_ringfs_test(void const *argument);			//文件操作主函数
+int32_t  lib_ringfs_push(void *object, size_t size);
+int32_t  lib_ringfs_pop(void *object, size_t size);
+uint32_t lib_ringfs_obj_cnt_estimate(void);
+uint32_t lib_ringfs_obj_cnt_exact(void);
+#endif    /*********LIB_RINGFS_FUNC_H****************/
+/******************************the end of file************************************************/
+

+ 105 - 0
lib/lib_ringfs/tests/flashsim.c

@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+#include "flashsim.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#ifdef FLASHSIM_LOG
+#define logprintf(args...) printf(args)
+#else
+#define logprintf(args...) do {} while (0)
+#endif
+
+struct flashsim {
+    int size;
+    int sector_size;
+
+    FILE *fh;
+};
+
+struct flashsim *flashsim_open(const char *name, int size, int sector_size)
+{
+    struct flashsim *sim = malloc(sizeof(struct flashsim));
+
+    sim->size = size;
+    sim->sector_size = sector_size;
+    sim->fh = fopen(name, "w+");
+    assert(sim->fh != NULL);
+    assert(ftruncate(fileno(sim->fh), size) == 0);
+
+    return sim;
+}
+
+void flashsim_close(struct flashsim *sim)
+{
+    fclose(sim->fh);
+    free(sim);
+}
+
+void flashsim_sector_erase(struct flashsim *sim, int addr)
+{
+    int sector_start = addr - (addr % sim->sector_size);
+    logprintf("flashsim_erase  (0x%08x) * erasing sector at 0x%08x\n", addr, sector_start);
+
+    void *empty = malloc(sim->sector_size);
+    memset(empty, 0xff, sim->sector_size);
+
+    assert(fseek(sim->fh, sector_start, SEEK_SET) == 0);
+    assert(fwrite(empty, 1, sim->sector_size, sim->fh) == (size_t) sim->sector_size);
+
+    free(empty);
+}
+
+void flashsim_read(struct flashsim *sim, int addr, uint8_t *buf, int len)
+{
+    assert(fseek(sim->fh, addr, SEEK_SET) == 0);
+    assert(fread(buf, 1, len, sim->fh) == (size_t) len);
+
+    logprintf("flashsim_read   (0x%08x) = %d bytes [ ", addr, len);
+    for (int i=0; i<len; i++) {
+        logprintf("%02x ", buf[i]);
+        if (i == 15) {
+            logprintf("... ");
+            break;
+        }
+    }
+    logprintf("]\n");
+}
+
+void flashsim_program(struct flashsim *sim, int addr, const uint8_t *buf, int len)
+{
+    logprintf("flashsim_program(0x%08x) + %d bytes [ ", addr, len);
+    for (int i=0; i<len; i++) {
+        logprintf("%02x ", buf[i]);
+        if (i == 15) {
+            logprintf("... ");
+            break;
+        }
+    }
+    logprintf("]\n");
+
+    uint8_t *data = malloc(len);
+
+    assert(fseek(sim->fh, addr, SEEK_SET) == 0);
+    assert(fread(data, 1, len, sim->fh) == (size_t) len);
+
+    for (int i=0; i<(int) len; i++)
+        data[i] &= buf[i];
+
+    assert(fseek(sim->fh, addr, SEEK_SET) == 0);
+    assert(fwrite(data, 1, len, sim->fh) == (size_t) len);
+
+    free(data);
+}
+
+/* vim: set ts=4 sw=4 et: */

+ 26 - 0
lib/lib_ringfs/tests/flashsim.h

@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+#ifndef FLASHSIM_H
+#define FLASHSIM_H
+
+#include <stdint.h>
+#include <unistd.h>
+
+struct flashsim;
+
+struct flashsim *flashsim_open(const char *name, int size, int sector_size);
+void flashsim_close(struct flashsim *sim);
+
+void flashsim_sector_erase(struct flashsim *sim, int addr);
+void flashsim_read(struct flashsim *sim, int addr, uint8_t *buf, int len);
+void flashsim_program(struct flashsim *sim, int addr, const uint8_t *buf, int len);
+
+#endif
+
+/* vim: set ts=4 sw=4 et: */

+ 89 - 0
lib/lib_ringfs/tests/fuzzer.py

@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import random
+
+from pyflashsim import FlashSim
+from pyringfs import RingFSFlashPartition, RingFS
+
+
+def compare(a, b):
+    if a != b:
+        print ">>> %s != %s" % (a, b)
+    return a == b
+
+
+class FuzzRun(object):
+
+    def __init__(self, name, version, object_size, sector_size, total_sectors, sector_offset, sector_count):
+
+        print "FuzzRun[%s]: v=%08x os=%d ss=%d ts=%d so=%d sc=%d" % (name, version, object_size, sector_size,
+                total_sectors, sector_offset, sector_count)
+
+        sim = FlashSim(name, total_sectors*sector_size, sector_size)
+
+        def op_sector_erase(flash, address):
+            sim.sector_erase(address)
+            return 0
+
+        def op_program(flash, address, data):
+            sim.program(address, data)
+            return len(data)
+
+        def op_read(flash, address, size):
+            return sim.read(address, size)
+
+        self.version = version
+        self.object_size = object_size
+
+        self.flash = RingFSFlashPartition(sector_size, sector_offset, sector_count,
+                op_sector_erase, op_program, op_read)
+        self.fs = RingFS(self.flash, self.version, self.object_size)
+
+    def run(self):
+
+        self.fs.format()
+        self.fs.dump()
+
+        def do_append():
+            self.fs.append('x'*self.object_size)
+
+        def do_fetch():
+            self.fs.fetch()
+
+        def do_rewind():
+            self.fs.rewind()
+
+        def do_discard():
+            self.fs.discard()
+
+        for i in xrange(1000):
+            fun = random.choice([do_append]*100 + [do_fetch]*100 + [do_rewind]*10 + [do_discard]*10)
+            print i, fun.__name__
+            fun()
+
+            # consistency check
+            newfs = RingFS(self.flash, self.version, self.object_size)
+            try:
+                assert newfs.scan() == 0
+                assert compare(newfs.ringfs.read.sector, self.fs.ringfs.read.sector)
+                assert compare(newfs.ringfs.read.slot, self.fs.ringfs.read.slot)
+                assert compare(newfs.ringfs.write.sector, self.fs.ringfs.write.sector)
+                assert compare(newfs.ringfs.write.slot, self.fs.ringfs.write.slot)
+            except AssertionError:
+                print "self.fs:"
+                self.fs.dump()
+                print "newfs:"
+                newfs.dump()
+                raise
+
+
+sector_size = random.randint(16, 256)
+total_sectors = random.randint(2, 8)
+sector_offset = random.randint(0, total_sectors-2)
+sector_count = random.randint(2, total_sectors-sector_offset)
+version = random.randint(0, 0xffffffff)
+object_size = random.randint(1, sector_size-8)
+
+f = FuzzRun('tests/fuzzer.sim', version, object_size, sector_size, total_sectors, sector_offset, sector_count)
+f.run()

+ 213 - 0
lib/lib_ringfs/tests/lib_ringfs_ram.c

@@ -0,0 +1,213 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+#if USE_LIB_RINGFS_RAM==1
+
+#include "lib_ringfs_func.h"
+#include "lib_ringfs.h"
+#include "lib_ringfs_ram.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#ifdef FLASHSIM_LOG
+#define logprintf(args...) printf(args)
+#else
+#define logprintf(args...) do {} while (0)
+#endif
+	
+	
+#define FLASH_RAM_SECTOR_SIZE       128
+#define FLASH_RAM_TOTAL_SECTORS     16
+#define FLASH_RAM_PARTITION_OFFSET  4
+#define FLASH_RAM_PARTITION_SIZE    8
+	
+
+uint8_t ram_buf[FLASH_RAM_TOTAL_SECTORS][FLASH_RAM_SECTOR_SIZE] = {0};	
+	
+struct rfs_dev_ram {
+    int size;
+    int sector_size;
+	
+		uint8_t* buf;
+    //FILE *fh;
+};
+
+struct rfs_dev_ram rfs_dev_ram_obj = {0};
+
+struct rfs_dev_ram *ramHandle = 0;
+
+
+void init_flash_driver_ram(void)
+{
+    ramHandle = rfs_dev_ram_open("example.ram",
+            FLASH_RAM_TOTAL_SECTORS*FLASH_RAM_SECTOR_SIZE,
+            FLASH_RAM_SECTOR_SIZE);
+}
+
+static int op_sector_erase(struct ringfs_flash_partition *flash, int address)
+{
+    (void) flash;
+    rfs_dev_ram_sector_erase(ramHandle, address);
+    return 0;
+}
+
+static ssize_t op_program(struct ringfs_flash_partition *flash, int address, const void *data, size_t size)
+{
+    (void) flash;
+    rfs_dev_ram_program(ramHandle, address, data, size);
+    return size;
+}
+
+static ssize_t op_read(struct ringfs_flash_partition *flash, int address, void *data, size_t size)
+{
+    (void) flash;
+    rfs_dev_ram_read(ramHandle, address, data, size);
+    return size;
+}
+
+struct ringfs_flash_partition rfs_disk_ram = {
+    .sector_size 		= FLASH_RAM_SECTOR_SIZE,
+    .sector_offset 	= FLASH_RAM_PARTITION_OFFSET,
+    .sector_count 	= FLASH_RAM_PARTITION_SIZE,
+
+    .sector_erase 	= op_sector_erase,
+    .program 				= op_program,
+    .read 					= op_read,
+};
+
+
+struct rfs_dev_ram *rfs_dev_ram_open(const char *name, int size, int sector_size)
+{
+    struct rfs_dev_ram *ram = &rfs_dev_ram_obj;
+		ram = &rfs_dev_ram_obj;
+	
+    ram->size = size;
+    ram->sector_size = sector_size;
+#if 0	
+    //ram->fh = fopen(name, "w+");
+    //assert_param(ram->fh != NULL);
+    //assert_param(ftruncate(fileno(ram->fh), size) == 0);
+#else
+		ram->buf = &ram_buf[0][0];
+#endif
+    return ram;
+}
+
+void rfs_dev_ram_close(struct rfs_dev_ram *ram)
+{
+    //fclose(ram->fh);
+    //free(ram);
+		memset(ram_buf, 0x00, sizeof(ram_buf));
+}
+
+void rfs_dev_ram_sector_erase(struct rfs_dev_ram *ram, int addr)
+{
+    int sector_start = addr - (addr % ram->sector_size);
+    logprintf("rfs_dev_ram_erase  (0x%08x) * erasing sector at 0x%08x\n", addr, sector_start);
+#if 0
+    void *empty = malloc(ram->sector_size);
+    assert_param(fseek(ram->fh, sector_start, SEEK_SET) == 0);
+    assert_param(fwrite(empty, 1, ram->sector_size, ram->fh) == (size_t) ram->sector_size);
+
+    free(empty);
+#else
+    memset(ram->buf+sector_start, 0xff, ram->sector_size);
+#endif 	
+}
+
+void rfs_dev_ram_read(struct rfs_dev_ram *ram, int addr, uint8_t *buf, int len)
+{
+#if 0
+    assert_param(fseek(ram->fh, addr, SEEK_SET) == 0);
+    assert_param(fread(buf, 1, len, ram->fh) == (size_t) len);
+
+    logprintf("rfs_dev_ram_read   (0x%08x) = %d bytes [ ", addr, len);
+    for (int i=0; i<len; i++) {
+        logprintf("%02x ", buf[i]);
+        if (i == 15) {
+            logprintf("... ");
+            break;
+        }
+    }
+    logprintf("]\n");
+#else
+	int32_t opt_len = 0;
+	opt_len = len;
+	if((addr+len) <= (ram->size))
+	{		
+		//地址和长度在合法的范围内;
+	}
+	else
+	{
+		//获取的内存空间超限,调整读取长度
+		opt_len = ram->size - addr; 		
+	}
+	
+	if(opt_len <= 0)
+	{
+		return;
+	}
+	
+	memcpy(buf, ram->buf+addr, opt_len);	
+	return;	
+#endif	
+}
+
+void rfs_dev_ram_program(struct rfs_dev_ram *ram, int addr, const uint8_t *buf, int len)
+{
+#if 0	
+    logprintf("rfs_dev_ram_program(0x%08x) + %d bytes [ ", addr, len);
+    for (int i=0; i<len; i++) {
+        logprintf("%02x ", buf[i]);
+        if (i == 15) {
+            logprintf("... ");
+            break;
+        }
+    }
+    logprintf("]\n");
+
+    uint8_t *data = malloc(len);
+
+    assert_param(fseek(ram->fh, addr, SEEK_SET) == 0);
+    assert_param(fread(data, 1, len, ram->fh) == (size_t) len);
+
+    for (int i=0; i<(int) len; i++)
+        data[i] &= buf[i];
+
+    assert_param(fseek(ram->fh, addr, SEEK_SET) == 0);
+    assert_param(fwrite(data, 1, len, ram->fh) == (size_t) len);
+
+    free(data);
+		
+#else
+	int32_t opt_len = 0;
+	opt_len = len;
+	if((addr+len) <= (ram->size))
+	{		
+		//地址和长度在合法的范围内;
+	}
+	else
+	{
+		//获取的内存空间超限,调整读取长度
+		opt_len = ram->size - addr; 		
+	}
+	
+	if(opt_len <= 0)
+	{
+		return;
+	}
+	
+	memcpy(ram->buf+addr, buf, opt_len);	
+	return;	
+#endif
+}
+
+#endif //----------------USE_LIB_RINGFS_RAM==1---------------------//
+/* vim: set ts=4 sw=4 et: */

+ 35 - 0
lib/lib_ringfs/tests/lib_ringfs_ram.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+ 
+#if USE_LIB_RINGFS_RAM==1 
+
+#ifndef LIB_RINGFS_RAM_H
+#define LIB_RINGFS_RAM_H
+
+#include <stdint.h>
+//#include <unistd.h>
+
+struct rfs_dev_ram;
+
+extern struct rfs_dev_ram *ramHandle;
+extern struct ringfs_flash_partition rfs_disk_ram;
+
+void init_flash_driver_ram(void);
+
+struct rfs_dev_ram *rfs_dev_ram_open(const char *name, int size, int sector_size);
+void rfs_dev_ram_close(struct rfs_dev_ram *sim);
+
+void rfs_dev_ram_sector_erase(struct rfs_dev_ram *sim, int addr);
+void rfs_dev_ram_read(struct rfs_dev_ram *sim, int addr, uint8_t *buf, int len);
+void rfs_dev_ram_program(struct rfs_dev_ram *sim, int addr, const uint8_t *buf, int len);
+
+#endif		//---------------------LIB_RINGFS_RAM_H-------------------------//
+
+
+#endif //----------------------USE_LIB_RINGFS_RAM==1-----------------------//
+/* vim: set ts=4 sw=4 et: */

+ 447 - 0
lib/lib_ringfs/tests/lib_ringfs_tests.c

@@ -0,0 +1,447 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+//#include <check.h>
+
+#include "lib_ringfs.h"
+#include "flash_ram.h"
+
+/* Flashsim tests. */
+
+START_TEST(test_flash_ram)
+{
+    printf("# test_flash_ram\n");
+
+    struct flash_ram *smallsim = flash_ram_open("tests/test.sim", 1024, 16);
+    uint8_t buf[48];
+    uint8_t data[16];
+
+    flash_ram_sector_erase(smallsim, 0);
+    flash_ram_sector_erase(smallsim, 16);
+    flash_ram_sector_erase(smallsim, 32);
+
+    memset(data, 0x5a, 16);
+    flash_ram_program(smallsim, 16, data, 16);
+
+    flash_ram_read(smallsim, 0, buf, 48);
+    for (int i=0; i<16; i++)
+        ck_assert_int_eq(buf[i], 0xff);
+    for (int i=16; i<32; i++)
+        ck_assert_int_eq(buf[i], 0x5a);
+    for (int i=32; i<48; i++)
+        ck_assert_int_eq(buf[i], 0xff);
+
+    memset(data, 0x01, 16);
+    flash_ram_program(smallsim, 0, data, 16);
+    memset(data, 0x10, 16);
+    flash_ram_program(smallsim, 32, data, 16);
+    flash_ram_sector_erase(smallsim, 16);
+
+    flash_ram_read(smallsim, 0, buf, 48);
+    for (int i=0; i<16; i++)
+        ck_assert_int_eq(buf[i], 0x01);
+    for (int i=16; i<32; i++)
+        ck_assert_int_eq(buf[i], 0xff);
+    for (int i=32; i<48; i++)
+        ck_assert_int_eq(buf[i], 0x10);
+
+    free(smallsim);
+}
+END_TEST
+
+/* Flash simulator + MTD partition fixture. */
+
+static struct flash_ram *sim;
+
+static int op_sector_erase(struct ringfs_flash_partition *flash, int address)
+{
+    (void) flash;
+    flash_ram_sector_erase(sim, address);
+    return 0;
+}
+
+static ssize_t op_program(struct ringfs_flash_partition *flash, int address, const void *data, size_t size)
+{
+    (void) flash;
+    flash_ram_program(sim, address, data, size);
+    return size;
+}
+
+static ssize_t op_read(struct ringfs_flash_partition *flash, int address, void *data, size_t size)
+{
+    (void) flash;
+    flash_ram_read(sim, address, data, size);
+    return size;
+}
+
+/*
+ * A really small filesystem: 3 slots per sector, 15 slots total.
+ * Has the benefit of causing frequent wraparounds, potentially finding
+ * more bugs.
+ */
+static struct ringfs_flash_partition flash = {
+    .sector_size = 32,
+    .sector_offset = 4,
+    .sector_count = 6,
+
+    .sector_erase = op_sector_erase,
+    .program = op_program,
+    .read = op_read,
+};
+
+static void fixture_flash_ram_setup(void)
+{
+    sim = flash_ram_open("tests/ringfs.sim",
+            flash.sector_size * (flash.sector_offset + flash.sector_count),
+            flash.sector_size);
+}
+
+static void fixture_flash_ram_teardown(void)
+{
+    flash_ram_close(sim);
+    sim = NULL;
+}
+
+/* RingFS tests. */
+
+#define DEFAULT_VERSION 0x000000042
+typedef int object_t;
+#define SECTOR_HEADER_SIZE 8
+#define SLOT_HEADER_SIZE 4
+
+static void assert_loc_equiv_to_offset(const struct ringfs *fs, const struct ringfs_loc *loc, int offset)
+{
+    int loc_offset = loc->sector * fs->slots_per_sector + loc->slot;
+    ck_assert_int_eq(offset, loc_offset);
+}
+
+static void assert_scan_integrity(const struct ringfs *fs)
+{
+    struct ringfs newfs;
+    ringfs_init(&newfs, fs->flash, fs->version, fs->object_size);
+    ck_assert(ringfs_scan(&newfs) == 0);
+    ck_assert_int_eq(newfs.read.sector, fs->read.sector);
+    ck_assert_int_eq(newfs.read.slot, fs->read.slot);
+    ck_assert_int_eq(newfs.write.sector, fs->write.sector);
+    ck_assert_int_eq(newfs.write.slot, fs->write.slot);
+}
+
+START_TEST(test_ringfs_format)
+{
+    printf("# test_ringfs_format\n");
+
+    struct ringfs fs1;
+    printf("## ringfs_init()\n");
+    ringfs_init(&fs1, &flash, DEFAULT_VERSION, sizeof(object_t));
+    printf("## ringfs_format()\n");
+    ringfs_format(&fs1);
+}
+END_TEST
+
+START_TEST(test_ringfs_scan)
+{
+    printf("# test_ringfs_scan\n");
+
+    /* first format a filesystem */
+    struct ringfs fs1;
+    printf("## ringfs_init()\n");
+    ringfs_init(&fs1, &flash, DEFAULT_VERSION, sizeof(object_t));
+    printf("## ringfs_format()\n");
+    ringfs_format(&fs1);
+
+    /* now try to scan it */
+    struct ringfs fs2;
+    printf("## ringfs_init()\n");
+    ringfs_init(&fs2, &flash, DEFAULT_VERSION, sizeof(object_t));
+    printf("## ringfs_scan()\n");
+    ck_assert(ringfs_scan(&fs2) == 0);
+
+    /* this is an empty FS, should start with this: */
+    ck_assert_int_eq(fs2.slots_per_sector, (flash.sector_size-SECTOR_HEADER_SIZE)/(SLOT_HEADER_SIZE+sizeof(object_t)));
+    assert_loc_equiv_to_offset(&fs2, &fs2.read, 0);
+    assert_loc_equiv_to_offset(&fs2, &fs2.cursor, 0);
+    assert_loc_equiv_to_offset(&fs2, &fs2.write, 0);
+
+    /* now insert some objects */
+    ck_assert(ringfs_append(&fs2, (int[]) { 0x11 }) == 0);
+    ck_assert(ringfs_append(&fs2, (int[]) { 0x22 }) == 0);
+    ck_assert(ringfs_append(&fs2, (int[]) { 0x33 }) == 0);
+
+    /* rescan */
+    printf("## ringfs_scan()\n");
+    ck_assert(ringfs_scan(&fs2) == 0);
+
+    /* make sure the objects are there */
+    ck_assert(ringfs_count_exact(&fs2) == 3);
+
+    /* scan should fail if we supply a different version */
+    struct ringfs fs3;
+    printf("## ringfs_init()\n");
+    ringfs_init(&fs3, &flash, DEFAULT_VERSION+1, sizeof(object_t));
+    printf("## ringfs_scan()\n");
+    ck_assert(ringfs_scan(&fs3) != 0);
+}
+END_TEST
+
+START_TEST(test_ringfs_append)
+{
+    printf("# test_ringfs_append\n");
+
+    /* first format a filesystem */
+    int obj;
+    struct ringfs fs;
+    printf("## ringfs_init()\n");
+    ringfs_init(&fs, &flash, DEFAULT_VERSION, sizeof(object_t));
+    printf("## ringfs_format()\n");
+    ringfs_format(&fs);
+
+    /* fetches before appends should not change anything */
+    for (int i=0; i<3; i++) {
+        printf("## ringfs_fetch()\n");
+        ck_assert(ringfs_fetch(&fs, &obj) < 0);
+    }
+    assert_loc_equiv_to_offset(&fs, &fs.read, 0);
+    assert_loc_equiv_to_offset(&fs, &fs.write, 0);
+    assert_loc_equiv_to_offset(&fs, &fs.cursor, 0);
+    assert_scan_integrity(&fs);
+
+    /* now we're brave and we write some data */
+    for (int i=0; i<3; i++) {
+        printf("## ringfs_append()\n");
+        ringfs_append(&fs, (int[]) { 0x11*(i+1) });
+
+        /* make sure the write head has advanced */
+        assert_loc_equiv_to_offset(&fs, &fs.write, i+1);
+        assert_scan_integrity(&fs);
+    }
+
+    /* now we fetch at it. */
+    for (int i=0; i<3; i++) {
+        printf("## ringfs_fetch()\n");
+        ck_assert(ringfs_fetch(&fs, &obj) == 0);
+        ck_assert_int_eq(obj, 0x11*(i+1));
+
+        /* make sure the cursor head has advanced */
+        assert_loc_equiv_to_offset(&fs, &fs.cursor, i+1);
+    }
+    /* there should be no data left */
+    ck_assert(ringfs_fetch(&fs, &obj) < 0);
+
+    /* test the rewind. */
+    ck_assert(ringfs_rewind(&fs) == 0);
+    assert_loc_equiv_to_offset(&fs, &fs.cursor, 0);
+
+    /* try to read the objects once again. */
+    for (int i=0; i<3; i++) {
+        printf("## ringfs_fetch()\n");
+        ck_assert(ringfs_fetch(&fs, &obj) == 0);
+        ck_assert_int_eq(obj, 0x11*(i+1));
+    }
+}
+END_TEST
+
+START_TEST(test_ringfs_discard)
+{
+    printf("# test_ringfs_discard\n");
+
+    struct ringfs fs;
+    printf("## ringfs_init()\n");
+    ringfs_init(&fs, &flash, DEFAULT_VERSION, sizeof(object_t));
+    printf("## ringfs_format()\n");
+    ringfs_format(&fs);
+
+    /* write some records */
+    for (int i=0; i<4; i++) {
+        printf("## ringfs_append()\n");
+        ringfs_append(&fs, (int[]) { 0x11*(i+1) });
+        assert_scan_integrity(&fs);
+    }
+    /* read some of them */
+    int obj;
+    for (int i=0; i<2; i++) {
+        printf("## ringfs_fetch()\n");
+        ck_assert(ringfs_fetch(&fs, &obj) == 0);
+        ck_assert_int_eq(obj, 0x11*(i+1));
+    }
+    /* discard whatever was read */
+    ck_assert(ringfs_discard(&fs) == 0);
+    assert_scan_integrity(&fs);
+    /* make sure we're consistent */
+    assert_loc_equiv_to_offset(&fs, &fs.read, 2);
+    assert_loc_equiv_to_offset(&fs, &fs.cursor, 2);
+    assert_loc_equiv_to_offset(&fs, &fs.write, 4);
+
+    /* read the rest of the records */
+    for (int i=2; i<4; i++) {
+        printf("## ringfs_fetch()\n");
+        ck_assert(ringfs_fetch(&fs, &obj) == 0);
+        ck_assert_int_eq(obj, 0x11*(i+1));
+    }
+    /* discard them */
+    ck_assert(ringfs_discard(&fs) == 0);
+    assert_loc_equiv_to_offset(&fs, &fs.read, 4);
+    assert_loc_equiv_to_offset(&fs, &fs.cursor, 4);
+    assert_loc_equiv_to_offset(&fs, &fs.write, 4);
+    assert_scan_integrity(&fs);
+}
+END_TEST
+
+START_TEST(test_ringfs_capacity)
+{
+    printf("# test_ringfs_capacity\n");
+
+    struct ringfs fs;
+    ringfs_init(&fs, &flash, DEFAULT_VERSION, sizeof(object_t));
+
+    int slots_per_sector = (flash.sector_size-SECTOR_HEADER_SIZE)/(SLOT_HEADER_SIZE+sizeof(object_t));
+    int sectors = flash.sector_count;
+    ck_assert_int_eq(ringfs_capacity(&fs), (sectors-1) * slots_per_sector);
+}
+END_TEST
+
+START_TEST(test_ringfs_count)
+{
+    printf("# test_ringfs_count\n");
+
+    int obj;
+    struct ringfs fs;
+    ringfs_init(&fs, &flash, DEFAULT_VERSION, sizeof(object_t));
+    ringfs_format(&fs);
+    ck_assert(ringfs_count_exact(&fs) == 0);
+
+    printf("## write some records\n");
+    for (int i=0; i<10; i++)
+        ringfs_append(&fs, (int[]) { 0x11*(i+1) });
+    ck_assert_int_eq(ringfs_count_exact(&fs), 10);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 10);
+
+    printf("## rescan\n");
+    ck_assert(ringfs_scan(&fs) == 0);
+    ck_assert_int_eq(ringfs_count_exact(&fs), 10);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 10);
+
+    printf("## append more records\n");
+    for (int i=10; i<13; i++)
+        ringfs_append(&fs, (int[]) { 0x11*(i+1) });
+    ck_assert_int_eq(ringfs_count_exact(&fs), 13);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 13);
+
+    printf("## fetch some objects without discard\n");
+    for (int i=0; i<4; i++) {
+        ck_assert(ringfs_fetch(&fs, &obj) == 0);
+        ck_assert_int_eq(obj, 0x11*(i+1));
+    }
+    ck_assert_int_eq(ringfs_count_exact(&fs), 13);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 13);
+
+    printf("## rescan\n");
+    ck_assert(ringfs_scan(&fs) == 0);
+    ck_assert_int_eq(ringfs_count_exact(&fs), 13);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 13);
+
+    printf("## fetch some objects with discard\n");
+    for (int i=0; i<4; i++) {
+        ck_assert(ringfs_fetch(&fs, &obj) == 0);
+        ck_assert_int_eq(obj, 0x11*(i+1));
+    }
+    ck_assert_int_eq(ringfs_count_exact(&fs), 13);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 13);
+    ck_assert(ringfs_discard(&fs) == 0);
+    ck_assert_int_eq(ringfs_count_exact(&fs), 9);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 9);
+
+    printf("## fill the segment\n");
+    int count = fs.slots_per_sector - 1;
+    for (int i=0; i<count; i++)
+        ringfs_append(&fs, (int[]) { 0x42 });
+    ck_assert_int_eq(ringfs_count_exact(&fs), 9+count);
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 9+count);
+
+    printf("## extra synthetic tests for estimation\n");
+    /* wrapping around */
+    fs.read = (struct ringfs_loc) { fs.flash->sector_count - 1, fs.slots_per_sector - 1 };
+    fs.write = (struct ringfs_loc) { 0, 0 };
+    ck_assert_int_eq(ringfs_count_estimate(&fs), 1);
+}
+END_TEST
+
+START_TEST(test_ringfs_overflow)
+{
+    printf("# test_ringfs_overflow\n");
+
+    printf("## format\n");
+    struct ringfs fs;
+    ringfs_init(&fs, &flash, DEFAULT_VERSION, sizeof(object_t));
+    ringfs_format(&fs);
+
+    int capacity = ringfs_capacity(&fs);
+
+    printf("## fill filesystem to the brim\n");
+    for (int i=0; i<capacity; i++)
+        ringfs_append(&fs, (int[]) { i });
+    ck_assert_int_eq(ringfs_count_exact(&fs), capacity);
+    assert_scan_integrity(&fs);
+
+    /* won't hurt to stress it a little bit! */
+    for (int round=0; round<3; round++) {
+        printf("## add one more object\n");
+        ringfs_append(&fs, (int[]) { 0x42 });
+        /* should kill one entire sector to make space */
+        ck_assert_int_eq(ringfs_count_exact(&fs), capacity - fs.slots_per_sector + 1);
+        assert_scan_integrity(&fs);
+
+        printf("## fill back up to the sector capacity\n");
+        for (int i=0; i<fs.slots_per_sector-1; i++)
+            ringfs_append(&fs, (int[]) { i });
+
+        ck_assert_int_eq(ringfs_count_exact(&fs), capacity);
+        assert_scan_integrity(&fs);
+    }
+}
+END_TEST
+
+Suite *ringfs_suite(void)
+{
+    Suite *s = suite_create ("ringfs");
+    TCase *tc;
+
+    tc = tcase_create("flash_ram");
+    tcase_add_test(tc, test_flash_ram);
+    suite_add_tcase(s, tc);
+
+    tc = tcase_create("ringfs");
+    tcase_add_checked_fixture(tc, fixture_flash_ram_setup, fixture_flash_ram_teardown);
+    tcase_add_test(tc, test_ringfs_format);
+    tcase_add_test(tc, test_ringfs_scan);
+    tcase_add_test(tc, test_ringfs_append);
+    tcase_add_test(tc, test_ringfs_discard);
+    tcase_add_test(tc, test_ringfs_capacity);
+    tcase_add_test(tc, test_ringfs_count);
+    tcase_add_test(tc, test_ringfs_overflow);
+    suite_add_tcase(s, tc);
+
+    return s;
+}
+
+int main()
+{
+    int number_failed;
+    Suite *s = ringfs_suite();
+    SRunner *sr = srunner_create(s);
+    srunner_run_all(sr, CK_NORMAL);
+    number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+/* vim: set ts=4 sw=4 et: */

+ 147 - 0
lib/lib_ringfs/tests/lib_ringfs_w25q.c

@@ -0,0 +1,147 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+#include "lib_ringfs.h"
+#include "lib_ringfs_func.h"
+
+#if  USE_LIB_RINGFS_W25Q==1
+
+#include "obj_spi_w25qxx.h"
+#include "obj_hal_w25qxx.h"
+#include "obj_soft_w25qxx.h"
+#include "func_spi_w25qxx.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#ifdef FLASHSIM_LOG
+#define logprintf(args...) printf(args)
+#else
+#define logprintf(args...) do {} while (0)
+#endif
+
+#define FLASH_W25Q_SECTOR_SIZE       4096
+#define FLASH_W25Q_PARTITION_OFFSET  16
+#define FLASH_W25Q_PARTITION_SIZE    6	
+#define FLASH_W25Q_TOTAL_SECTORS     (FLASH_W25Q_PARTITION_OFFSET + \
+																			FLASH_W25Q_PARTITION_SIZE)	
+	
+struct rfs_dev_w25q {
+		char name[32];
+    int total_size;
+    int sector_size;	
+
+};
+
+struct rfs_dev_w25q *rfs_dev_w25q_open(const char *name, int size, int sector_size);
+static ssize_t op_program(struct ringfs_flash_partition *flash, int address, const void *data, size_t size);
+static ssize_t op_read(struct ringfs_flash_partition *flash, int address, void *data, size_t size);
+
+static int op_sector_erase(struct ringfs_flash_partition *flash, int address);
+
+
+struct rfs_dev_w25q  rfs_dev_w25q_obj = {0};
+struct rfs_dev_w25q *h_rfs_w25q = 0;
+
+struct ringfs_flash_partition rfs_disk_w25q = {
+    .sector_size 		= FLASH_W25Q_SECTOR_SIZE,
+    .sector_offset 	= FLASH_W25Q_PARTITION_OFFSET,
+    .sector_count 	= FLASH_W25Q_PARTITION_SIZE,
+
+    .sector_erase 	= op_sector_erase,
+    .program 				= op_program,
+    .read 					= op_read,
+};
+
+
+
+
+void init_flash_driver_w25q(void)
+{
+		if(W25QXX_ID_OK() == true)
+		{
+			rfs_disk_w25q.sector_size = w25qxx_obj.SectorSize;
+			
+			//ringfs 的扇区数量为,总扇区数减去偏移量;偏移量暂定为16个扇区
+			rfs_disk_w25q.sector_count 	=  w25qxx_obj.SectorCount - rfs_disk_w25q.sector_offset;
+		}
+		else
+		{
+			return;
+		}
+		
+#if 0	
+    h_rfs_w25q = rfs_dev_w25q_open("rfs_disk.w25q",
+            FLASH_W25Q_TOTAL_SECTORS*FLASH_W25Q_SECTOR_SIZE,
+            FLASH_W25Q_SECTOR_SIZE);
+#else		
+    h_rfs_w25q = rfs_dev_w25q_open("rfs_disk.w25q",
+            w25qxx_obj.SectorSize*w25qxx_obj.SectorCount,
+            w25qxx_obj.SectorSize);
+#endif
+		
+}
+
+static int op_sector_erase(struct ringfs_flash_partition *flash, int address)
+{
+    (void) flash;
+	
+		int sector_start = address - (address % flash->sector_size);
+		UNUSED(sector_start);
+    logprintf("rfs_dev_w25q_erase  (0x%08x) * erasing sector at 0x%08x\n", addr, sector_start);
+
+    W25QXX_Erase_Sector(address/4096);
+    return 0;
+}
+
+static ssize_t op_program(struct ringfs_flash_partition *flash, int address, const void *data, size_t size)
+{
+    (void) flash;
+		W25QXX_Write_NoCheck((uint8_t*)data, address, size);
+    return size;
+}
+
+static ssize_t op_read(struct ringfs_flash_partition *flash, int address, void *data, size_t size)
+{
+    (void) flash;
+		W25QXX_Read((uint8_t*)data, address, size);;
+    return size;
+}
+
+
+
+
+struct rfs_dev_w25q *rfs_dev_w25q_open(const char *name, int size, int sector_size)
+{
+		func_w25q_init();
+	
+		func_w25q_test();
+		
+    struct rfs_dev_w25q *h_w25q = &rfs_dev_w25q_obj;		
+		h_w25q = &rfs_dev_w25q_obj;
+		
+		if(strlen(name) < sizeof(rfs_dev_w25q_obj.name))
+		{
+			strcpy(rfs_dev_w25q_obj.name,name);
+		}		
+	
+    h_w25q->total_size  = size;
+    h_w25q->sector_size = sector_size;
+
+    return h_w25q;
+}
+
+void rfs_dev_w25q_close(struct rfs_dev_w25q *ram)
+{
+		return;
+}
+
+
+#endif //---------------------USE_LIB_RINGFS_W25Q==1--------------------//
+
+/* vim: set ts=4 sw=4 et: */

+ 28 - 0
lib/lib_ringfs/tests/lib_ringfs_w25q.h

@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2014 Kosma Moczek <kosma@cloudyourcar.com>
+ * This program is free software. It comes without any warranty, to the extent
+ * permitted by applicable law. You can redistribute it and/or modify it under
+ * the terms of the Do What The Fuck You Want To Public License, Version 2, as
+ * published by Sam Hocevar. See the COPYING file for more details.
+ */
+
+#if  USE_LIB_RINGFS_W25Q==1
+
+#ifndef LIB_RINGFS_W25Q_H
+#define LIB_RINGFS_W25Q_H
+
+#include <stdint.h>
+//#include <unistd.h>
+
+struct rfs_dev_w25q;
+extern struct ringfs_flash_partition rfs_disk_w25q;
+
+void init_flash_driver_w25q(void);
+void rfs_dev_w25q_close(struct rfs_dev_w25q *sim);
+
+
+#endif	//----------------------LIB_RINGFS_W25Q_H--------------------//
+
+#endif //---------------------USE_LIB_RINGFS_W25Q==1--------------------//
+
+/* vim: set ts=4 sw=4 et: */

+ 39 - 0
lib/lib_ringfs/tests/pyflashsim.py

@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+from sharedlibrary import GenericLibrary
+from ctypes import *
+
+
+class libflashsim(GenericLibrary):
+    dllname = 'tests/flashsim.so'
+    functions = [
+        ['flashsim_open', [c_char_p, c_int, c_int], c_void_p],
+        ['flashsim_sector_erase', [c_void_p, c_int], None],
+        ['flashsim_read', [c_void_p, c_int, c_void_p, c_int], None],
+        ['flashsim_program', [c_void_p, c_int, c_void_p, c_int], None],
+        ['flashsim_close', [c_void_p], None],
+    ]
+
+
+class FlashSim(object):
+
+    def __init__(self, name, size, sector_size):
+        self.libflashsim = libflashsim()
+        self.sim = self.libflashsim.flashsim_open(name ,size, sector_size)
+
+    def sector_erase(self, addr):
+        self.libflashsim.flashsim_sector_erase(self.sim, addr)
+
+    def read(self, addr, size):
+        buf = create_string_buffer(size)
+        self.libflashsim.flashsim_read(self.sim, addr, buf, size)
+        return buf.raw
+
+    def program(self, addr, data):
+        self.libflashsim.flashsim_program(self.sim, addr, data, len(data))
+
+    def __del__(self):
+        self.libflashsim.flashsim_close(self.sim)

+ 135 - 0
lib/lib_ringfs/tests/pyringfs.py

@@ -0,0 +1,135 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import sys
+from sharedlibrary import GenericLibrary
+from ctypes import *
+
+
+# forward declaration
+class StructRingFSFlashPartition(Structure):
+    pass
+
+op_sector_erase_t = CFUNCTYPE(c_int, POINTER(StructRingFSFlashPartition), c_int)
+op_program_t = CFUNCTYPE(c_ssize_t, POINTER(StructRingFSFlashPartition), c_int, c_void_p, c_size_t)
+op_read_t = CFUNCTYPE(c_ssize_t, POINTER(StructRingFSFlashPartition), c_int, c_void_p, c_size_t)
+
+StructRingFSFlashPartition._fields_ = [
+    ('sector_size', c_int),
+    ('sector_offset', c_int),
+    ('sector_count', c_int),
+
+    ('sector_erase', op_sector_erase_t),
+    ('program', op_program_t),
+    ('read', op_read_t),
+]
+
+class StructRingFSLoc(Structure):
+    _fields_ = [
+        ('sector', c_int),
+        ('slot', c_int),
+    ]
+
+class StructRingFS(Structure):
+    _fields_ = [
+        ('flash', POINTER(StructRingFSFlashPartition)),
+        ('version', c_uint32),
+        ('object_size', c_int),
+        ('slots_per_sector', c_int),
+
+        ('read', StructRingFSLoc),
+        ('write', StructRingFSLoc),
+        ('cursor', StructRingFSLoc),
+    ]
+
+
+class libringfs(GenericLibrary):
+    dllname = './ringfs.so'
+    functions = [
+        ['ringfs_init', [POINTER(StructRingFS), POINTER(StructRingFSFlashPartition), c_uint32, c_int], c_int],
+        ['ringfs_format', [POINTER(StructRingFS)], c_int],
+        ['ringfs_scan', [POINTER(StructRingFS)], c_int],
+        ['ringfs_capacity', [POINTER(StructRingFS)], c_int],
+        ['ringfs_count_estimate', [POINTER(StructRingFS)], c_int],
+        ['ringfs_count_exact', [POINTER(StructRingFS)], c_int],
+        ['ringfs_append', [POINTER(StructRingFS), c_void_p], c_int],
+        ['ringfs_fetch', [POINTER(StructRingFS), c_void_p], c_int],
+        ['ringfs_discard', [POINTER(StructRingFS)], c_int],
+        ['ringfs_rewind', [POINTER(StructRingFS)], c_int],
+        ['ringfs_dump', [c_void_p, POINTER(StructRingFS)], None],
+    ]
+
+
+class RingFSFlashPartition(object):
+
+    def __init__(self, sector_size, sector_offset, sector_count, sector_erase, program, read):
+
+        def op_sector_erase(flash, address):
+            sector_erase(flash, address)
+            return 0
+
+        def op_program(flash, address, data, size):
+            program(flash, address, string_at(data, size))
+            return size
+
+        def op_read(flash, address, buf, size):
+            data = read(flash, address, size)
+            memmove(buf, data, size)
+            return size
+
+        self.struct = StructRingFSFlashPartition(sector_size, sector_offset, sector_count,
+                op_sector_erase_t(op_sector_erase),
+                op_program_t(op_program),
+                op_read_t(op_read))
+
+
+class RingFS(object):
+
+    def __init__(self, flash, version, object_size):
+        self.libringfs = libringfs()
+        self.ringfs = StructRingFS()
+        self.flash = flash.struct
+        self.libringfs.ringfs_init(byref(self.ringfs), byref(self.flash), version, object_size)
+        self.object_size = object_size
+
+    def format(self):
+        self.libringfs.ringfs_format(byref(self.ringfs))
+
+    def scan(self):
+        return self.libringfs.ringfs_scan(byref(self.ringfs))
+
+    def capacity(self):
+        return self.libringfs.ringfs_capacity(byref(self.ringfs))
+
+    def count_estimate(self):
+        return self.libringfs.ringfs_count_estimate(byref(self.ringfs))
+
+    def count_exact(self):
+        return self.libringfs.ringfs_count_exact(byref(self.ringfs))
+
+    def append(self, obj):
+        self.libringfs.ringfs_append(byref(self.ringfs), obj)
+
+    def fetch(self):
+        obj = create_string_buffer(self.object_size)
+        self.libringfs.ringfs_append(byref(self.ringfs), obj)
+        return obj.raw
+
+    def discard(self):
+        self.libringfs.ringfs_discard(byref(self.ringfs))
+
+    def rewind(self):
+        self.libringfs.ringfs_rewind(byref(self.ringfs))
+
+    def dump(self):
+        import ctypes
+        ctypes.pythonapi.PyFile_AsFile.argtypes= [ ctypes.py_object ]
+        ctypes.pythonapi.PyFile_AsFile.restype= ctypes.c_void_p
+        cstdout = ctypes.pythonapi.PyFile_AsFile(sys.stdout)
+        self.libringfs.ringfs_dump(cstdout, byref(self.ringfs))
+
+__all__ = [
+    'StructRingFSFlashPartition',
+    'RingFS',
+]

+ 13 - 0
lib/lib_ringfs/tests/sharedlibrary.py

@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from ctypes import CDLL
+
+class GenericLibrary(CDLL):
+
+    def __init__(self, *args, **kwargs):
+        super(GenericLibrary, self).__init__(self.dllname, *args, **kwargs)
+
+        for name, argtypes, restype in self.functions:
+            getattr(self, name).argtypes = argtypes
+            getattr(self, name).restype = restype