/*
 * 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: */
