diff --git a/core/cfs/cfs-coffee.c b/core/cfs/cfs-coffee.c index 37b1a707e..374b3419f 100644 --- a/core/cfs/cfs-coffee.c +++ b/core/cfs/cfs-coffee.c @@ -196,7 +196,7 @@ struct file_header { /* This is needed because of a buggy compiler. */ struct log_param { cfs_offset_t offset; - const char *buf; + char *buf; uint16_t size; }; @@ -1198,7 +1198,7 @@ cfs_write(int fd, const void *buf, unsigned size) need_dummy_write = 0; for(bytes_left = size; bytes_left > 0;) { lp.offset = fdp->offset; - lp.buf = buf; + lp.buf = (void *)buf; lp.size = bytes_left; i = write_log_page(file, &lp); if(i < 0) { diff --git a/cpu/cc2538/Makefile.cc2538 b/cpu/cc2538/Makefile.cc2538 index a11dc2b87..f28a77d11 100644 --- a/cpu/cc2538/Makefile.cc2538 +++ b/cpu/cc2538/Makefile.cc2538 @@ -115,8 +115,7 @@ CUSTOM_RULE_LINK=1 cp $< $@ ### This rule is used to generate the correct linker script -LDGENFLAGS += $(addprefix -D,$(subst $(COMMA), ,$(DEFINES))) -LDGENFLAGS += $(addprefix -I,$(SOURCEDIRS)) +LDGENFLAGS += $(CFLAGS) LDGENFLAGS += -imacros "contiki-conf.h" -imacros "dev/cc2538-dev.h" LDGENFLAGS += -imacros "dev/flash.h" -imacros "cfs-coffee-arch.h" LDGENFLAGS += -x c -P -E diff --git a/cpu/cc2538/cfs-coffee-arch.h b/cpu/cc2538/cfs-coffee-arch.h index 9d53994e5..a0bf3dd75 100644 --- a/cpu/cc2538/cfs-coffee-arch.h +++ b/cpu/cc2538/cfs-coffee-arch.h @@ -102,6 +102,8 @@ /** Maximal amount of log table entries read in one batch */ #ifdef COFFEE_CONF_LOG_TABLE_LIMIT #define COFFEE_LOG_TABLE_LIMIT COFFEE_CONF_LOG_TABLE_LIMIT +#else +#define COFFEE_LOG_TABLE_LIMIT 16 #endif /** Default reserved file size */ #ifdef COFFEE_CONF_DYN_SIZE @@ -112,6 +114,8 @@ /** Default micro-log size */ #ifdef COFFEE_CONF_LOG_SIZE #define COFFEE_LOG_SIZE COFFEE_CONF_LOG_SIZE +#else +#define COFFEE_LOG_SIZE (4 * COFFEE_PAGE_SIZE) #endif /** Whether Coffee will use micro logs */ #ifdef COFFEE_CONF_MICRO_LOGS diff --git a/examples/cfs-coffee/Makefile b/examples/cfs-coffee/Makefile new file mode 100644 index 000000000..0e1fe1b13 --- /dev/null +++ b/examples/cfs-coffee/Makefile @@ -0,0 +1,12 @@ +DEFINES+=PROJECT_CONF_H=\"project-conf.h\" +CONTIKI = ../.. + +all: test-cfs test-coffee example-coffee + +CONTIKI_WITH_RIME = 1 + +ifeq ($(TARGET),avr-raven) + COFFEE_FILES = 4 +endif + +include $(CONTIKI)/Makefile.include diff --git a/examples/cfs-coffee/README.md b/examples/cfs-coffee/README.md new file mode 100644 index 000000000..991e9583b --- /dev/null +++ b/examples/cfs-coffee/README.md @@ -0,0 +1,29 @@ +Contiki File System (CFS) and Coffee Examples +============================================= + +Coffee is a very simple, relatively small and easy to use file system that you +are most likely going to be very familiar with if you have done any C file +access in the past. The notion is the same as on a normal PC: you open a file, +read and write to it and close it. Contiki will take care of the underlying +flash memory, giving you more time to focus on the real issues. + +Coffee is a full implementation of the CFS API. + +An extended explanation on CFS and Coffee internals and how they work can be +found at the [CFS](https://github.com/contiki-os/contiki/wiki/File-systems) and +[Coffee](https://github.com/contiki-os/contiki/wiki/Coffee-filesystem-example) +wiki pages. + +Supported Hardware (tested or known to work) +-------------------------------------------- +* sky +* z1 +* wismote +* avr-raven +* cc2538dk +* openmote-cc2538 +* zoul + +The examples are known to build for the 'avr-raven' platform. However, +some of them currently fail at runtime due to file system overflow. +Tweaking the file sizes in the examples is necessary. diff --git a/examples/sky/example-coffee.c b/examples/cfs-coffee/example-coffee.c similarity index 89% rename from examples/sky/example-coffee.c rename to examples/cfs-coffee/example-coffee.c index ee77849e4..7adc8d62c 100644 --- a/examples/sky/example-coffee.c +++ b/examples/cfs-coffee/example-coffee.c @@ -28,31 +28,31 @@ * * This file is part of the Contiki operating system. */ - +/*---------------------------------------------------------------------------*/ /** * \file * Example on how to use CFS/Coffee. * \author * Nicolas Tsiftes */ - +/*---------------------------------------------------------------------------*/ #include - +#include #include "contiki.h" #include "cfs/cfs.h" #include "cfs/cfs-coffee.h" - +/*---------------------------------------------------------------------------*/ PROCESS(example_coffee_process, "Coffee example"); AUTOSTART_PROCESSES(&example_coffee_process); - +/*---------------------------------------------------------------------------*/ #define FILENAME "test" -/* Formatting is needed if the storage device is in an unknown state; +/* Formatting is needed if the storage device is in an unknown state; e.g., when using Coffee on the storage device for the first time. */ #ifndef NEED_FORMATTING #define NEED_FORMATTING 0 #endif - +/*---------------------------------------------------------------------------*/ static int file_test(const char *filename, char *msg) { @@ -65,12 +65,12 @@ file_test(const char *filename, char *msg) } record; /* - * Coffee determines the file length by finding the last non-zero byte - * of the file. This I/O semantic requires that each record should end - * with a non-zero, if we are writing multiple records and closing the + * Coffee determines the file length by finding the last non-zero byte + * of the file. This I/O semantic requires that each record should end + * with a non-zero, if we are writing multiple records and closing the * file descriptor in between. * - * In this example, in which the file_test function can be called + * In this example, in which the file_test function can be called * multiple times, we ensure that the sequence counter starts at 1. */ @@ -84,7 +84,7 @@ file_test(const char *filename, char *msg) record.message[sizeof(record.message) - 1] = '\0'; record.sequence = sequence; - /* Obtain a file descriptor for the file, capable of handling both + /* Obtain a file descriptor for the file, capable of handling both reads and writes. */ fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ); if(fd < 0) { @@ -103,7 +103,7 @@ file_test(const char *filename, char *msg) printf("Wrote message \"%s\", sequence %u\n", record.message, record.sequence); - /* To read back the message, we need to move the file pointer to the + /* To read back the message, we need to move the file pointer to the beginning of the file. */ if(cfs_seek(fd, 0, CFS_SEEK_SET) != 0) { printf("seek failed\n"); @@ -133,7 +133,7 @@ file_test(const char *filename, char *msg) return 1; } - +/*---------------------------------------------------------------------------*/ static int dir_test(void) { @@ -156,7 +156,7 @@ dir_test(void) return 1; } - +/*---------------------------------------------------------------------------*/ PROCESS_THREAD(example_coffee_process, ev, data) { PROCESS_BEGIN(); diff --git a/examples/cfs-coffee/project-conf.h b/examples/cfs-coffee/project-conf.h new file mode 100644 index 000000000..4dd98edcb --- /dev/null +++ b/examples/cfs-coffee/project-conf.h @@ -0,0 +1,40 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/*---------------------------------------------------------------------------*/ +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ +/*---------------------------------------------------------------------------*/ +#if CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_OPENMOTE_CC2538 || \ + CONTIKI_TARGET_ZOUL +#define COFFEE_CONF_SIZE (CC2538_DEV_FLASH_SIZE / 2) +#define COFFEE_CONF_MICRO_LOGS 1 +#define COFFEE_CONF_APPEND_ONLY 0 +#endif /* CONTIKI_TARGET_CC2538DK || CONTIKI_TARGET_ZOUL */ + +#endif /* PROJECT_CONF_H_ */ +/*---------------------------------------------------------------------------*/ diff --git a/examples/sky/test-cfs.c b/examples/cfs-coffee/test-cfs.c similarity index 94% rename from examples/sky/test-cfs.c rename to examples/cfs-coffee/test-cfs.c index 68c91e720..2d44b6696 100644 --- a/examples/sky/test-cfs.c +++ b/examples/cfs-coffee/test-cfs.c @@ -29,19 +29,18 @@ * This file is part of the Contiki operating system. * */ - +/*---------------------------------------------------------------------------*/ /** * \file * A quick program for testing the CFS xmem driver * \author * Adam Dunkels */ - +/*---------------------------------------------------------------------------*/ #include "contiki.h" #include "cfs/cfs.h" - #include - +/*---------------------------------------------------------------------------*/ PROCESS(cfs_process, "Test CFS process"); AUTOSTART_PROCESSES(&cfs_process); /*---------------------------------------------------------------------------*/ @@ -55,6 +54,7 @@ PROCESS_THREAD(cfs_process, ev, data) uint16_t filesize = 65000; #define CHUNKSIZE 128 + cfs_remove("hej"); fd = cfs_open("hej", CFS_WRITE); if(fd < 0) { printf("could not open file for writing, aborting\n"); diff --git a/examples/sky/test-coffee.c b/examples/cfs-coffee/test-coffee.c similarity index 84% rename from examples/sky/test-coffee.c rename to examples/cfs-coffee/test-coffee.c index b4152b2a8..3fcc40cfd 100644 --- a/examples/sky/test-coffee.c +++ b/examples/cfs-coffee/test-coffee.c @@ -29,14 +29,14 @@ * This file is part of the Contiki operating system. * */ - +/*---------------------------------------------------------------------------*/ /** * \file * Basic test for CFS/Coffee. * \author * Nicolas Tsiftes */ - +/*---------------------------------------------------------------------------*/ #include "contiki.h" #include "cfs/cfs.h" #include "cfs/cfs-coffee.h" @@ -45,14 +45,12 @@ #include #include - +/*---------------------------------------------------------------------------*/ PROCESS(testcoffee_process, "Test CFS/Coffee process"); AUTOSTART_PROCESSES(&testcoffee_process); - -#define FAIL(x) error = (x); goto end; - +/*---------------------------------------------------------------------------*/ +#define TEST_FAIL(x) error = (x); goto end; #define FILE_SIZE 4096 - /*---------------------------------------------------------------------------*/ static int coffee_test_basic(void) @@ -62,8 +60,6 @@ coffee_test_basic(void) unsigned char buf[256]; int r; - cfs_remove("T1"); - wfd = rfd = afd = -1; for(r = 0; r < sizeof(buf); r++) { @@ -73,64 +69,64 @@ coffee_test_basic(void) /* Test 1: Open for writing. */ wfd = cfs_open("T1", CFS_WRITE); if(wfd < 0) { - FAIL(1); + TEST_FAIL(1); } /* Test 2 and 3: Write buffer. */ r = cfs_write(wfd, buf, sizeof(buf)); if(r < 0) { - FAIL(2); + TEST_FAIL(2); } else if(r < sizeof(buf)) { - FAIL(3); + TEST_FAIL(3); } /* Test 4: Deny reading. */ r = cfs_read(wfd, buf, sizeof(buf)); if(r >= 0) { - FAIL(4); + TEST_FAIL(4); } /* Test 5: Open for reading. */ rfd = cfs_open("T1", CFS_READ); if(rfd < 0) { - FAIL(5); + TEST_FAIL(5); } /* Test 6: Write to read-only file. */ r = cfs_write(rfd, buf, sizeof(buf)); if(r >= 0) { - FAIL(6); + TEST_FAIL(6); } /* Test 7 and 8: Read the buffer written in Test 2. */ memset(buf, 0, sizeof(buf)); r = cfs_read(rfd, buf, sizeof(buf)); if(r < 0) { - FAIL(7); + TEST_FAIL(7); } else if(r < sizeof(buf)) { printf("r=%d\n", r); - FAIL(8); + TEST_FAIL(8); } /* Test 9: Verify that the buffer is correct. */ for(r = 0; r < sizeof(buf); r++) { if(buf[r] != r) { printf("r=%d. buf[r]=%d\n", r, buf[r]); - FAIL(9); + TEST_FAIL(9); } } /* Test 10: Seek to beginning. */ if(cfs_seek(wfd, 0, CFS_SEEK_SET) != 0) { - FAIL(10); + TEST_FAIL(10); } /* Test 11 and 12: Write to the log. */ r = cfs_write(wfd, buf, sizeof(buf)); if(r < 0) { - FAIL(11); + TEST_FAIL(11); } else if(r < sizeof(buf)) { - FAIL(12); + TEST_FAIL(12); } /* Test 13 and 14: Read the data from the log. */ @@ -138,15 +134,15 @@ coffee_test_basic(void) memset(buf, 0, sizeof(buf)); r = cfs_read(rfd, buf, sizeof(buf)); if(r < 0) { - FAIL(14); + TEST_FAIL(13); } else if(r < sizeof(buf)) { - FAIL(15); + TEST_FAIL(14); } /* Test 16: Verify that the data is correct. */ for(r = 0; r < sizeof(buf); r++) { if(buf[r] != r) { - FAIL(16); + TEST_FAIL(15); } } @@ -155,16 +151,16 @@ coffee_test_basic(void) buf[r] = sizeof(buf) - r - 1; } if(cfs_seek(wfd, 0, CFS_SEEK_SET) != 0) { - FAIL(17); + TEST_FAIL(16); } r = cfs_write(wfd, buf, sizeof(buf)); if(r < 0) { - FAIL(18); + TEST_FAIL(17); } else if(r < sizeof(buf)) { - FAIL(19); + TEST_FAIL(18); } if(cfs_seek(rfd, 0, CFS_SEEK_SET) != 0) { - FAIL(20); + TEST_FAIL(19); } /* Test 21 and 22: Read the reversed buffer. */ @@ -172,16 +168,16 @@ coffee_test_basic(void) memset(buf, 0, sizeof(buf)); r = cfs_read(rfd, buf, sizeof(buf)); if(r < 0) { - FAIL(21); + TEST_FAIL(20); } else if(r < sizeof(buf)) { printf("r = %d\n", r); - FAIL(22); + TEST_FAIL(21); } /* Test 23: Verify that the data is correct. */ for(r = 0; r < sizeof(buf); r++) { if(buf[r] != sizeof(buf) - r - 1) { - FAIL(23); + TEST_FAIL(22); } } @@ -189,6 +185,7 @@ coffee_test_basic(void) end: cfs_close(wfd); cfs_close(rfd); + cfs_remove("T1"); return error; } /*---------------------------------------------------------------------------*/ @@ -202,50 +199,49 @@ coffee_test_append(void) #define APPEND_BYTES 1000 #define BULK_SIZE 10 - cfs_remove("T2"); - /* Test 1 and 2: Append data to the same file many times. */ for(i = 0; i < APPEND_BYTES; i += BULK_SIZE) { - afd = cfs_open("T3", CFS_WRITE | CFS_APPEND); + afd = cfs_open("T2", CFS_WRITE | CFS_APPEND); if(afd < 0) { - FAIL(1); + TEST_FAIL(1); } for(j = 0; j < BULK_SIZE; j++) { buf[j] = 1 + ((i + j) & 0x7f); } if((r = cfs_write(afd, buf, BULK_SIZE)) != BULK_SIZE) { printf("r=%d\n", r); - FAIL(2); + TEST_FAIL(2); } cfs_close(afd); } - /* Test 3-6: Read back the data written previously and verify that it + /* Test 3-6: Read back the data written previously and verify that it is correct. */ - afd = cfs_open("T3", CFS_READ); + afd = cfs_open("T2", CFS_READ); if(afd < 0) { - FAIL(3); + TEST_FAIL(3); } total_read = 0; while((r = cfs_read(afd, buf2, sizeof(buf2))) > 0) { for(j = 0; j < r; j++) { if(buf2[j] != 1 + ((total_read + j) & 0x7f)) { - FAIL(4); + TEST_FAIL(4); } } total_read += r; } if(r < 0) { - FAIL(5); + TEST_FAIL(5); } if(total_read != APPEND_BYTES) { - FAIL(6); + TEST_FAIL(6); } cfs_close(afd); error = 0; end: cfs_close(afd); + cfs_remove("T2"); return error; } /*---------------------------------------------------------------------------*/ @@ -258,58 +254,60 @@ coffee_test_modify(void) int r, i; unsigned offset; - cfs_remove("T3"); wfd = -1; if(cfs_coffee_reserve("T3", FILE_SIZE) < 0) { - FAIL(1); + TEST_FAIL(1); } if(cfs_coffee_configure_log("T3", FILE_SIZE / 2, 11) < 0) { - FAIL(2); + TEST_FAIL(2); } /* Test 16: Test multiple writes at random offset. */ for(r = 0; r < 100; r++) { - wfd = cfs_open("T2", CFS_WRITE | CFS_READ); + wfd = cfs_open("T3", CFS_WRITE | CFS_READ); if(wfd < 0) { - FAIL(3); + TEST_FAIL(3); } offset = random_rand() % FILE_SIZE; - for(r = 0; r < sizeof(buf); r++) { - buf[r] = r; + for(i = 0; i < sizeof(buf); i++) { + buf[i] = i; } if(cfs_seek(wfd, offset, CFS_SEEK_SET) != offset) { - FAIL(4); + TEST_FAIL(4); } if(cfs_write(wfd, buf, sizeof(buf)) != sizeof(buf)) { - FAIL(5); + TEST_FAIL(5); } if(cfs_seek(wfd, offset, CFS_SEEK_SET) != offset) { - FAIL(6); + TEST_FAIL(6); } memset(buf, 0, sizeof(buf)); if(cfs_read(wfd, buf, sizeof(buf)) != sizeof(buf)) { - FAIL(7); + TEST_FAIL(7); } for(i = 0; i < sizeof(buf); i++) { if(buf[i] != i) { printf("buf[%d] != %d\n", i, buf[i]); - FAIL(8); + TEST_FAIL(8); } } + + cfs_close(wfd); } error = 0; end: cfs_close(wfd); + cfs_remove("T3"); return error; } /*---------------------------------------------------------------------------*/ @@ -318,21 +316,17 @@ coffee_test_gc(void) { int i; - cfs_remove("alpha"); - cfs_remove("beta"); - - for (i = 0; i < 100; i++) { if (i & 1) { - if(cfs_coffee_reserve("alpha", random_rand() & 0xffff) < 0) { - return i; - } - cfs_remove("beta"); - } else { - if(cfs_coffee_reserve("beta", 93171) < 0) { + if(cfs_coffee_reserve("beta", random_rand() & 0xffff) < 0) { return i; } cfs_remove("alpha"); + } else { + if(cfs_coffee_reserve("alpha", 93171) < 0) { + return i; + } + cfs_remove("beta"); } } @@ -376,7 +370,7 @@ PROCESS_THREAD(testcoffee_process, ev, data) result = coffee_test_gc(); print_result("Garbage collection", result); - printf("Coffee test finished. Duration: %d seconds\n", + printf("Coffee test finished. Duration: %d seconds\n", (int)(clock_seconds() - start)); PROCESS_END(); diff --git a/examples/sky/Makefile b/examples/sky/Makefile index dd09f0792..6d17fd421 100644 --- a/examples/sky/Makefile +++ b/examples/sky/Makefile @@ -3,7 +3,7 @@ ifndef TARGET TARGET=sky endif -all: blink sky-collect #rt-leds test-button test-cfs tcprudolph0 +all: blink sky-collect #rt-leds test-button tcprudolph0 %.tgz: %.ihex mkdir $(basename $<) ; \ diff --git a/platform/zoul/contiki-conf.h b/platform/zoul/contiki-conf.h index 52cd22dfd..2c2bcb854 100644 --- a/platform/zoul/contiki-conf.h +++ b/platform/zoul/contiki-conf.h @@ -101,7 +101,9 @@ typedef uint32_t rtimer_clock_t; * * @{ */ +#ifndef COFFEE_CONF_SIZE #define COFFEE_CONF_SIZE (4 * COFFEE_SECTOR_SIZE) +#endif /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/regression-tests/01-compile-base/Makefile b/regression-tests/01-compile-base/Makefile index bbfbd0c6b..bc38a9777 100644 --- a/regression-tests/01-compile-base/Makefile +++ b/regression-tests/01-compile-base/Makefile @@ -37,8 +37,11 @@ settings-example/avr-raven \ ipv6/multicast/sky \ ipv6/rpl-tsch/z1 \ ipv6/rpl-tsch/z1:MAKE_WITH_ORCHESTRA=1 \ -ipv6/rpl-tsch/z1:MAKE_WITH_SECURITY=1 - +ipv6/rpl-tsch/z1:MAKE_WITH_SECURITY=1 \ +cfs-coffee/sky \ +cfs-coffee/z1 \ +cfs-coffee/wismote \ +cfs-coffee/avr-raven TOOLS= diff --git a/regression-tests/03-base/02-sky-coffee.csc b/regression-tests/03-base/02-sky-coffee.csc index f017a3e7d..050b4abc9 100644 --- a/regression-tests/03-base/02-sky-coffee.csc +++ b/regression-tests/03-base/02-sky-coffee.csc @@ -24,10 +24,10 @@ org.contikios.cooja.mspmote.SkyMoteType sky1 Sky Mote Type #1 - [CONTIKI_DIR]/examples/sky/test-coffee.c + [CONTIKI_DIR]/examples/cfs-coffee/test-coffee.c make clean TARGET=sky make test-coffee.sky TARGET=sky - [CONTIKI_DIR]/examples/sky/test-coffee.sky + [CONTIKI_DIR]/examples/cfs-coffee/test-coffee.sky org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.IPAddress org.contikios.cooja.interfaces.Mote2MoteRelations @@ -89,7 +89,7 @@ make test-coffee.sky TARGET=sky org.contikios.cooja.plugins.ScriptRunner -