CFS-Coffee

From Contiki
Revision as of 15:01, 29 July 2016 by Gugri (Talk | contribs)

Jump to: navigation, search

Back to Contiki Tutorials

Permanent Storage of Contiki on Tmote Sky (CFS-Coffee)

Contiki provides File System to achieve the goal of permanent storage. The Contiki File System(CFS) works as a Virtual File System and provides some interfaces for different file systems. CFS-POSIX and Coffee are two with full functionalities. CFS-POSIX is used in Contiki platforms that runs in native mode. Coffee, on the other hand, is primarily aimed at sensor devices that equiped with Flash Memories or EEPROM.

The CFS Programming Interface

For detail interface introduction, please refer to the below link:

http://contiki.sourceforge.net/docs/2.6/a00128.html

Introduction to Coffee

Coffee is a fully functional file system designed specifically for the characteristics of flash memories and EEPROM. Coffee is usually used in sensor devices with flash (e.g Tmote Sky), so two principles are pretty important. First, the metadata stored in RAM for each file should be small because sensor devices have very limited RAM space. Second, bits in flash memories can be toggled from 1 to 0, but not toggled back from 0 to 1 without doing an expensive erase. Thus, when modifying a file, Coffee creates an invisible micro log which is linked to the original file. The micro log contains the lastest data of the file. For user, the micro log and the original file is just one logical file, as if they modify the original file. When the micro log eventually fills up, Coffee transparently merges the content of the original file and the micro log into a new file, and deletes the two former files.

Coffee has a flat directory structure. It only has the root directory. Thus, cfs_opendir() only accept “/” or “.” as the second argument. When removing a file from a Coffee, there are two steps. First, external user calls cfs_remove(). The file mentioned by user will be marked as obsolete. Obsolete files cannot be seen by external users. Coffee will actually delete files only when a new file reservation request cannot be granted.

The implementation of Coffee in core/cfs/cfs-coffee.c is totally platform independent. The specific configuration of Coffee for different platforms is written in csf-coffee-arch.c. We can see many csf-coffee-arch.c files in plarform/./csf-coffee-arch.c, e.g plarform/z1/csf-coffee-arch.c, plarform/esb/csf-coffee-arch.c, plarform/sky/csf-coffee-arch.c. When we decide the platform, such as TARGET=sky, we compile plarform/sky/csf-coffee-arch.c and ignore all other csf-coffee-arch.c files. Macro definitions in plarform/sky/csf-coffee-arch.c configure the details of coffee in Sky Mote. Macro definition contains parameters like COFFEE_SECTOR_SIZE, COFFEE_PAGE_SIZE, COFFEE_FD_SET_SIZE, COFFEE_MICRO_LOGS and so on. Also, it defines COFFEE_WRITE, COFFEE_READ and COFFEE_ERASE to point to the device drivers I/O function.

CFS-Coffee Interface Extensions

For detail interface introduction, please refer to the below link:

http://contiki.sourceforge.net/docs/2.6/a00122.html

cfs_coffee_format() may take a few second because all sectors must be erased. cfs_coffee_reserve() and int cfs_coffee_configure_log() can optimize Coffee’s handling of the file.

CFS-Coffee Summary

Here is an example of how everything works. Suppose we want to run Contiki on Sky Mote. First make sure TARGET=sky. Then every file about sky is compiled and you can also see a new folder which is created called sky_obj. Inside contains everything you need to run on Sky Mote. Suppose you want to use Coffee as the File System. Write cfs_coffee_format() before the first time you try to operate on Coffee. This function notice the system that you want to use Coffee and the system will do some formatting. Let’s say then you want to read something from an existing file with the function call cfs_read(). This function is defined in core/cfs/cfs.h. Because we make use of Coffee, the implementation of this function will be in core/cfs/cfs-coffee.c. The function cfs_read() actually calls the macro definition COFFEE_READ(). The definition of COFFEE_READ() is in cfs-coffee-arch.c. Since we make TARGET=sky, the one that was compiled and used by us is platform/sky/cfs-coffee-arch.c. This file defines COFFEE_READ() to point to Sky Mote drivers I/O function. Finally, the external users’ cfs_read() gets to the Sky Driver I/O function.

An Example of Running Coffee on Tmote Sky

This example shows the basic way to open, read, write and append files in Coffee. The platform we choose here is Tmote Sky. First, open an example provided by Contiki (/home/user/contiki-2.7/example/sky/example- coffee.c). Here, it defines two test functions:

 static int file_test(const char *filename, char *msg) 

opens a file named FILENAME with CFS_WRITE | CFS_APPEND | CFS_READ. It appends the opening file with records and prints out everything in the file.

 static int dir_test(void) 

opens the root directory and prints out all entries of root. The Process calls file_test() twice and dir_test() once. Then the process ends. Now, we do some modifications based on this example. First we add a function static int read_test(void). The implementation of this function is shown as below:



  static int
  read_test(void)
  {
	  struct cfs_dir dir;
	  struct cfs_dirent dirent;
	  int fd;
	  int r;
	  struct record {
    		  char message[16];
    		  uint8_t sequence;
  	  } record;
	  static int i = 0;
	  if (cfs_opendir(&dir, "/") != 0)
	  {
		printf("Fail to open the root directory\n");
		return -1;
	}
	while(cfs_readdir(&dir, &dirent) == 0)
	{
		i ++;
		printf("\nFile name: %s\n", dirent.name);
		if ((fd =cfs_open(dirent.name, CFS_READ)) != -1)
		{
			cfs_seek(fd, 0, CFS_SEEK_SET);
			for(;;) 
			{
    				r = cfs_read(fd, &record, sizeof(record));
    				if(r == 0) {
      					break;
    				} else if(r > sizeof(record)) {
      					printf("failed to read %d bytes from %s, got %d\n",(int)sizeof(record), dirent.name, r);
      					cfs_close(fd);
      					return -1;
    				}

    				printf("Read message \"%s\", sequence %u\n",record.message, record.sequence);
  			}
		}
	}

	if (i == 0)
	{
		printf("\nNo file exists.\n");
		return 0;
	}
	else
	{
		return 1;
	}
		
  }

 

The function of read_test() is quite simple. It opens the root file system and reads all the data in the file system. In the while() loop, it reads an entry of a file. Then it makes use of the entry to open the file and read all the data out.

Also, in the process, we add an etimer at the beginning. The process can only move on either when the timer expired or someone push a button. If the timer expire, the process will run cfs_coffee_format(), which will set all the flash to 1. Otherwise, we don’t do this. Then we call read_test(), which read all the data in the file system. After that, we check whether there are files exist in the system. If there is, we give up wirting. Otherwise, we create two files and write some data in. The process then looks like:



PROCESS_THREAD(example_coffee_process, ev, data)
{
  PROCESS_BEGIN();

	static int flag = 0;
	button_sensor.configure(SENSORS_ACTIVE, 1);

	static struct etimer ak;
	etimer_set(&ak, CLOCK_SECOND * 6);
	
	PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER || ev == sensors_event && data == &button_sensor);

	if (ev == PROCESS_EVENT_TIMER)
		cfs_coffee_format();	

	if ((flag = read_test()) == -1)
		PROCESS_EXIT();

	
	static struct etimer et;
	etimer_set(&et, CLOCK_SECOND * 2);
	PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);

	if (flag == 1)
		printf("\nData exists...No written again...\n");
	else
	{
		printf("\nData begin to write...\n");
		if(file_test(FILENAME_1, "The first test") == 0) {
    			printf("file test 1 failed\n");
  		}
		if(file_test(FILENAME_1, "The second test") == 0) {
    			printf("file test 2 failed\n");
		}
		if(file_test(FILENAME_2, "The third test") == 0) {
    			printf("file test 3 failed\n");
		}
		if(dir_test() == 0) {
    			printf("dir test failed\n");
  		}

	}

  PROCESS_END();
}

 

Now, connect your mote to your PC’s USB port and change directory.

 cd contiki-2.7/examples/sky 

Compile this Coffee example to Sky Mote.

 sudo make TARGET=sky example-coffee.upload login

Once login, wait for 6 seconds patiently for the first time out.If it success, we should see terminal has the output like this: Here you can see, we create two files and write some data in. Then, disconnect your mote and do whatever you want. Maybe one day later, you come back. Now it’s the time to keep moving. Welcome back. Now connect your mote with USB port again and do:

 sudo make TARGET=sky login

You are in the process again and please follow the following two steps: 1. push “RESET” button; 2. push “USER” button within 6 seconds. Now, the program will not call cfs_coffee_format(). If succeed, you will see: As you can see, we read out all the data that you wrote in one day ago. Everything is right there without any change.


Back to Contiki Tutorials