<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://anrg.usc.edu/contiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Zhikunli</id>
		<title>Contiki - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://anrg.usc.edu/contiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Zhikunli"/>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php/Special:Contributions/Zhikunli"/>
		<updated>2026-10-08T12:11:03Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.26.2</generator>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=(NEW)_Disney_Magic_Kingdoms_Hack_and_Cheats_for_APK_Android_and_Ios_No_Survey_2023&amp;diff=1870</id>
		<title>(NEW) Disney Magic Kingdoms Hack and Cheats for APK Android and Ios No Survey 2023</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=(NEW)_Disney_Magic_Kingdoms_Hack_and_Cheats_for_APK_Android_and_Ios_No_Survey_2023&amp;diff=1870"/>
				<updated>2023-03-25T19:04:24Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: Created page with &amp;quot;Are you looking for ways to get unlimited Disney Magic Kingdoms Magic Gems? The Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator,...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Are you looking for ways to get unlimited Disney Magic Kingdoms Magic Gems? The Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification are here to help!&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms is a free-to-play mobile game, developed by Gameloft. It is based on the Disney theme parks and allows players to build and manage their own virtual kingdom. The game is available for Android and iOS devices.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Click Here &amp;gt;&amp;gt; https://cheats.pics/064ea46&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The main currency of the game is Magic Gems, which can be used to purchase items, progress levels, and more. However, these gems can be difficult to obtain. This is where the Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification come in.&lt;br /&gt;
&lt;br /&gt;
These tools are designed to provide players with an unlimited number of Magic Gems. All you need to do is input your username and select the number of gems you want to generate. From there, the tool will generate the gems in no time!&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator Method and Disney Magic Kingdoms Magic Gems Generator are safe and secure to use. They are also free of cost and require no human verification. With these tools, you can get unlimited Magic Gems without having to pay anything.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Hack and Disney Magic Kingdoms Magic Gems Cheats can also be used to get an unlimited amount of Magic Gems. However, these methods require some technical knowledge and should only be used by experienced players.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification are the best way to get unlimited Magic Gems. They are easy to use and require no technical knowledge or human verification.&lt;br /&gt;
&lt;br /&gt;
So if you&amp;#039;re looking for ways to get unlimited Disney Magic Kingdoms Magic Gems, the Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification are the perfect tools for you! Try them out today and get unlimited Magic Gems.&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=(WORKING)_Disney_Magic_Kingdoms_APK_Hack_Latest_Version_2023_New_Generator_Magic_Gems_Cheats_for_Free&amp;diff=1869</id>
		<title>(WORKING) Disney Magic Kingdoms APK Hack Latest Version 2023 New Generator Magic Gems Cheats for Free</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=(WORKING)_Disney_Magic_Kingdoms_APK_Hack_Latest_Version_2023_New_Generator_Magic_Gems_Cheats_for_Free&amp;diff=1869"/>
				<updated>2023-03-25T19:04:19Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: Created page with &amp;quot;Welcome to the magical world of Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Ma...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to the magical world of Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification. This amazing resource has been created to help you enjoy all the fun of the Disney Magic Kingdoms game without the hassle of the usual grind and expense.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms game is a great way to explore the magical world of Disney and experience the magic of all of your favorite characters. Whether you’re a fan of classic Disney characters like Mickey Mouse, Cinderella, or Snow White, or modern characters like Moana and Olaf, you can explore the world of Disney with the help of the Disney Magic Kingdoms Magic Gems Generator Method. This amazing resource has been designed to help you get all the gems you need to experience the fun and excitement of the Disney Magic Kingdoms game.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Click Here &amp;gt;&amp;gt; https://cheats.pics/064ea46&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator Method provides you with an easy way to generate gems without having to put in any hard work. All you have to do is enter your username and password and you’ll have access to all of the gems you need to make your Disney Magic Kingdoms experience more enjoyable. With a few clicks of your mouse, you can get all the gems you need to make your Disney Magic Kingdoms experience more exciting and thrilling.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Hack and Disney Magic Kingdoms Magic Gems Cheats are also great tools that allow you to get more out of the game. These amazing tools provide you with amazing tips and tricks to help you complete levels more quickly and get more out of your Disney Magic Kingdoms experience. With these tools, you can quickly and easily get all the gems you need to make your Disney Magic Kingdoms experience much more enjoyable.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Free and Free Disney Magic Kingdoms Magic Gems Generator 2023 are also great tools that allow you to get more out of the game. These amazing tools provide you with amazing tips and tricks to help you complete levels more quickly and get more out of your Disney Magic Kingdoms experience. With these tools, you can quickly and easily get all the gems you need to make your Disney Magic Kingdoms experience much more enjoyable.&lt;br /&gt;
&lt;br /&gt;
Finally, the Disney Magic Kingdoms Magic Gems No Human Verification is an amazing tool that allows you to get all the gems you need without having to enter any personally identifying information. With this tool, you can get all the gems you need without having to worry about being scammed or being exposed to any potential malicious activities. With this tool, you can easily and securely get all the gems you need to make your Disney Magic Kingdoms experience more enjoyable.&lt;br /&gt;
&lt;br /&gt;
These amazing tools are just some of the resources available to help make your Disney Magic Kingdoms experience more enjoyable. With these tools, you can quickly and easily get all the gems you need to make your Disney Magic Kingdoms experience more exciting and thrilling.&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=(updated_mathod)_Free_Disney_Magic_Kingdoms_Cheats_Magic_Gems_Generator_No_Human_Verification_2023&amp;diff=1868</id>
		<title>(updated mathod) Free Disney Magic Kingdoms Cheats Magic Gems Generator No Human Verification 2023</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=(updated_mathod)_Free_Disney_Magic_Kingdoms_Cheats_Magic_Gems_Generator_No_Human_Verification_2023&amp;diff=1868"/>
				<updated>2023-03-25T19:04:18Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: Created page with &amp;quot;If you&amp;#039;re a fan of Disney Magic Kingdoms, then you&amp;#039;re probably familiar with Magic Gems. They&amp;#039;re the virtual currency that you need to purchase and upgrade your characters, bu...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;If you&amp;#039;re a fan of Disney Magic Kingdoms, then you&amp;#039;re probably familiar with Magic Gems. They&amp;#039;re the virtual currency that you need to purchase and upgrade your characters, buildings, and other items.&lt;br /&gt;
&lt;br /&gt;
The problem is, Magic Gems are expensive and hard to come by. That&amp;#039;s why many players have turned to Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification to get their hands on more Magic Gems.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Click Here &amp;gt;&amp;gt; https://cheats.pics/064ea46&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator Method can be used to generate an unlimited amount of Magic Gems. All you need to do is enter the amount of Gems you want and the Generator will give you a code that you can use to purchase them.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator is a great way to get more Magic Gems without spending a lot of money. It&amp;#039;s also very easy to use and can be used with any device, including mobile phones and tablets.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Hack is another popular option for getting more Magic Gems. It works by hacking the game&amp;#039;s system so that you can get as many Magic Gems as you want. This can be done by entering certain codes or by downloading files from the internet.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Cheats is one of the most popular cheats for the game. It allows you to get unlimited Magic Gems by entering certain codes or by downloading files from the internet.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Free is a great way to get more Magic Gems without spending a lot of money. It&amp;#039;s a website that provides free Magic Gems to players who complete tasks on the website.&lt;br /&gt;
&lt;br /&gt;
The Free Disney Magic Kingdoms Magic Gems Generator 2023 is another popular way to get more Magic Gems without spending a lot of money. It&amp;#039;s an online generator that allows you to generate an unlimited amount of Magic Gems.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems No Human Verification is an option for getting more Magic Gems without spending a lot of money. It allows you to generate an unlimited amount of Magic Gems without having to provide any personal information.&lt;br /&gt;
&lt;br /&gt;
Whether you&amp;#039;re looking for the Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, or Disney Magic Kingdoms Magic Gems No Human Verification, you&amp;#039;re sure to find a great way to get more Magic Gems without spending a lot of money. With one of these methods, you can get as many Magic Gems as you want without having to spend a fortune.&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=(Disney_Magic_Kingdoms_Cheats)_Free_Disney_Magic_Kingdoms_Generator_Working_Magic_Gems_Generator_No_Human_Verification&amp;diff=1867</id>
		<title>(Disney Magic Kingdoms Cheats) Free Disney Magic Kingdoms Generator Working Magic Gems Generator No Human Verification</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=(Disney_Magic_Kingdoms_Cheats)_Free_Disney_Magic_Kingdoms_Generator_Working_Magic_Gems_Generator_No_Human_Verification&amp;diff=1867"/>
				<updated>2023-03-25T19:04:14Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: Created page with &amp;quot;Are you a fan of Disney Magic Kingdoms and want to get your hands on the coveted Magic Gems? With the help of the Disney Magic Kingdoms Magic Gems Generator Method, you can ea...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Are you a fan of Disney Magic Kingdoms and want to get your hands on the coveted Magic Gems? With the help of the Disney Magic Kingdoms Magic Gems Generator Method, you can easily generate Magic Gems for free and without having to verify yourself.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator is a free and easy-to-use tool that allows you to generate Magic Gems with just a few clicks. This generator is designed to work with the latest version of the game and with no human verification and no downloads required, it’s the perfect way to get the Magic Gems you need to unlock new levels and get ahead in the game.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Click Here &amp;gt;&amp;gt; https://cheats.pics/064ea46&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To use the Disney Magic Kingdoms Magic Gems Generator, simply fill out the form and click the “Generate” button. Once you’ve generated the Magic Gems, you can use them in the game to purchase new levels, unlock special rewards, and even purchase exclusive items.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Hack is an even easier way to get the Magic Gems you need. With the hack, you can generate an unlimited number of Magic Gems without any downloads or human verification. All you need to do is enter your username and password into the hack, and you’ll be able to generate as many Magic Gems as you want for free.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Cheats is another hack that is designed to make it easier to get the Magic Gems you need. This cheat allows you to unlock levels and purchase items without having to pay a dime. All you have to do is download the cheat and enter your username and password into it.&lt;br /&gt;
&lt;br /&gt;
Finally, the Disney Magic Kingdoms Magic Gems Free Generator 2023 will help you get the Magic Gems you need without spending any money. The free generator uses a special algorithm to generate Magic Gems for free, and it works with the latest version of the game. All you have to do is enter your username and password into the generator, and you can get your hands on the Magic Gems you need.&lt;br /&gt;
&lt;br /&gt;
No matter which method you choose to get your hands on the Magic Gems you need, you can rest assured that you’ll be able to get the Magic Gems without having to go through any human verification or downloads. With the Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification, you’ll be able to get your hands on the Magic Gems you need in no time.&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=(NEW_CHEATS)_Disney_Magic_Kingdoms_Free_Magic_Gems_Generator_999,999K_Magic_Gems_Free_2023_in_5_minutes&amp;diff=1866</id>
		<title>(NEW CHEATS) Disney Magic Kingdoms Free Magic Gems Generator 999,999K Magic Gems Free 2023 in 5 minutes</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=(NEW_CHEATS)_Disney_Magic_Kingdoms_Free_Magic_Gems_Generator_999,999K_Magic_Gems_Free_2023_in_5_minutes&amp;diff=1866"/>
				<updated>2023-03-25T19:04:12Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: Created page with &amp;quot;Welcome to the ultimate guide to Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney M...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to the ultimate guide to Disney Magic Kingdoms Magic Gems Generator Method, Disney Magic Kingdoms Magic Gems Generator, Disney Magic Kingdoms Magic Gems Hack, Disney Magic Kingdoms Magic Gems Cheats, Disney Magic Kingdoms Magic Gems Free, Free Disney Magic Kingdoms Magic Gems Generator 2023, and Disney Magic Kingdoms Magic Gems No Human Verification. &lt;br /&gt;
&lt;br /&gt;
Disney Magic Kingdoms is a mobile game released by Disney Interactive and Gameloft, and it has become one of the most popular mobile games on the market. The game allows players to construct their own magical kingdom and customize it with characters, attractions, and other goodies. In order to progress in the game, players need to collect Magic Gems. Magic Gems are the premium currency in the game and they are used to buy exclusive items, upgrades, and other bonuses.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Click Here &amp;gt;&amp;gt; https://cheats.pics/064ea46&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Unfortunately, Magic Gems are not easy to come by. They are quite rare and require a lot of grinding to get enough for the most powerful items and upgrades. That’s why so many players are looking for ways to get more Magic Gems without having to spend any money. Fortunately, there are several methods available to help players get more Magic Gems without having to pay real money. &lt;br /&gt;
&lt;br /&gt;
One of the most popular methods to get free Magic Gems is to use a Disney Magic Kingdoms Magic Gems Generator. A Magic Gems Generator is a tool that can generate unlimited amounts of Magic Gems for free. It works by generating codes that can be redeemed in the game for Magic Gems. This method is completely free and easy to use, and it’s the most reliable way to get free Magic Gems. &lt;br /&gt;
&lt;br /&gt;
Another method is to use a Disney Magic Kingdoms Magic Gems Hack. A Magic Gems Hack is a tool that can modify the game’s data so that players can get free Magic Gems. This method is not recommended, however, as it can be quite risky. There is also the possibility that using such a hack can get your account banned from the game. &lt;br /&gt;
&lt;br /&gt;
The last method is to use Disney Magic Kingdoms Magic Gems Cheats. Magic Gems Cheats are programs that can be used to modify the game’s code and generate Magic Gems for free. This method is also not recommended, as it can also get your account banned from the game. &lt;br /&gt;
&lt;br /&gt;
These are the three methods that players can use to get free Magic Gems without having to spend real money. If you’re looking for a safe and reliable way to get free Magic Gems, then you should definitely consider using a Disney Magic Kingdoms Magic Gems Generator. This method is completely free, easy to use, and completely safe. &lt;br /&gt;
&lt;br /&gt;
If you’re looking for a way to get free Magic Gems without having to go through a verification process, then you should consider using the Free Disney Magic Kingdoms Magic Gems Generator 2023. This generator is completely free and easy to use, and it can generate unlimited amounts of Magic Gems with no human verification. &lt;br /&gt;
&lt;br /&gt;
Finally, if you want to get free Magic Gems without having to worry about getting your account banned, then you should consider using the Disney Magic Kingdoms Magic Gems No Human Verification method. This method is completely safe and can generate unlimited amounts of Magic Gems without having to go through a verification process.&lt;br /&gt;
&lt;br /&gt;
We hope that this guide has helped you understand the different methods available to get free Magic Gems in Disney Magic Kingdoms. Whether you choose to use a Generator, a Hack, or a Cheat, we wish you the best of luck in your quest for more Magic Gems.&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=(NEW)_Disney_Magic_Kingdoms_Hack_Unlimited_Magic_Gems_Generator_No_Jailbreak_or_Root_(No_Human_Verification)&amp;diff=1865</id>
		<title>(NEW) Disney Magic Kingdoms Hack Unlimited Magic Gems Generator No Jailbreak or Root (No Human Verification)</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=(NEW)_Disney_Magic_Kingdoms_Hack_Unlimited_Magic_Gems_Generator_No_Jailbreak_or_Root_(No_Human_Verification)&amp;diff=1865"/>
				<updated>2023-03-25T19:04:07Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: Created page with &amp;quot;Are you a fan of the Disney Magic Kingdoms game? Do you want to get your hands on free Magic Gems? Well, the wait is over! Introducing the Disney Magic Kingdoms Magic Gems Gen...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Are you a fan of the Disney Magic Kingdoms game? Do you want to get your hands on free Magic Gems? Well, the wait is over! Introducing the Disney Magic Kingdoms Magic Gems Generator Method, the ultimate resource for getting unlimited free Magic Gems in the game.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator Method is a powerful tool that will allow you to generate an unlimited amount of Magic Gems for the Disney Magic Kingdoms game. This Magic Gems Generator Method is designed to be easy to use, fast and reliable. With just a few clicks of your mouse, you will be able to generate as many Magic Gems as you need.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Click Here &amp;gt;&amp;gt; https://cheats.pics/064ea46&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator Method also includes a powerful hack and cheats feature. With this feature, you can easily hack the game and get unlimited Magic Gems without having to spend a dime. This is a great way to get ahead in the game without spending real money.&lt;br /&gt;
&lt;br /&gt;
The Disney Magic Kingdoms Magic Gems Generator Method also gives you access to the Free Disney Magic Kingdoms Magic Gems Generator 2023. This is a great way to get free Magic Gems in the game without having to spend any money. All you need to do is register for the Free Disney Magic Kingdoms Magic Gems Generator and you can start generating free Magic Gems in the game.&lt;br /&gt;
&lt;br /&gt;
Finally, the Disney Magic Kingdoms Magic Gems Generator Method also includes the No Human Verification feature. This feature allows you to generate free Magic Gems without having to confirm any personal information. This feature ensures that your personal information is kept safe and secure.&lt;br /&gt;
&lt;br /&gt;
If you are looking for a way to generate free Magic Gems for the Disney Magic Kingdoms game, then the Disney Magic Kingdoms Magic Gems Generator Method is the perfect resource for you. With the powerful hack and cheats feature, the Free Disney Magic Kingdoms Magic Gems Generator 2023 and the No Human Verification feature, you can easily generate an unlimited amount of Magic Gems in the game without spending real money. Get started today and get the most out of your Disney Magic Kingdoms experience.&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1518</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1518"/>
				<updated>2014-11-09T10:37:29Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Reference */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&amp;lt;br&amp;gt;&lt;br /&gt;
The Idea is based on Zane D. Purvis&amp;#039;s Coffee filesystem example.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png|850px]]&amp;lt;br&amp;gt;&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;Coffee filesystem&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/Coffee-filesystem-example] - Zane D. Purvis, &amp;quot;Coffee filesystem example&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1517</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1517"/>
				<updated>2014-11-09T10:37:12Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Reference */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&amp;lt;br&amp;gt;&lt;br /&gt;
The Idea is based on Zane D. Purvis&amp;#039;s Coffee filesystem example.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png|850px]]&amp;lt;br&amp;gt;&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;Coffee filesystem&amp;quot;&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/Coffee-filesystem-example] - Zane D. Purvis, &amp;quot;Coffee filesystem example&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1516</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1516"/>
				<updated>2014-11-09T10:36:15Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Coding With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&amp;lt;br&amp;gt;&lt;br /&gt;
The Idea is based on Zane D. Purvis&amp;#039;s Coffee filesystem example.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png|850px]]&amp;lt;br&amp;gt;&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1515</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1515"/>
				<updated>2014-11-09T10:35:56Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Coding With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
The Idea is based on Zane D. Purvis&amp;#039;s Coffee filesystem example.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png|850px]]&amp;lt;br&amp;gt;&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1485</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1485"/>
				<updated>2014-11-09T07:55:50Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Simulation Result */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png|850px]]&amp;lt;br&amp;gt;&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1484</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1484"/>
				<updated>2014-11-09T07:55:11Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Simulation Result */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png|600px]]&amp;lt;br&amp;gt;&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1482</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1482"/>
				<updated>2014-11-09T07:43:41Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Memory Organization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=File:Flowchart.png&amp;diff=1480</id>
		<title>File:Flowchart.png</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=File:Flowchart.png&amp;diff=1480"/>
				<updated>2014-11-09T07:39:39Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: Zhikunli uploaded a new version of &amp;amp;quot;File:Flowchart.png&amp;amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1479</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1479"/>
				<updated>2014-11-09T07:36:02Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* get_available_fd */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1478</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1478"/>
				<updated>2014-11-09T07:34:00Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Coding With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * Copyright (c) 2011, Swedish Institute of Computer Science.&lt;br /&gt;
 * All rights reserved.&lt;br /&gt;
 *&lt;br /&gt;
 * Redistribution and use in source and binary forms, with or without&lt;br /&gt;
 * modification, are permitted provided that the following conditions&lt;br /&gt;
 * are met:&lt;br /&gt;
 * 1. Redistributions of source code must retain the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer.&lt;br /&gt;
 * 2. Redistributions in binary form must reproduce the above copyright&lt;br /&gt;
 *    notice, this list of conditions and the following disclaimer in the&lt;br /&gt;
 *    documentation and/or other materials provided with the distribution.&lt;br /&gt;
 * 3. Neither the name of the Institute nor the names of its contributors&lt;br /&gt;
 *    may be used to endorse or promote products derived from this software&lt;br /&gt;
 *    without specific prior written permission.&lt;br /&gt;
 *&lt;br /&gt;
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS&amp;#039;&amp;#039; AND&lt;br /&gt;
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE&lt;br /&gt;
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE&lt;br /&gt;
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE&lt;br /&gt;
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL&lt;br /&gt;
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS&lt;br /&gt;
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)&lt;br /&gt;
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT&lt;br /&gt;
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY&lt;br /&gt;
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF&lt;br /&gt;
 * SUCH DAMAGE.&lt;br /&gt;
 *&lt;br /&gt;
 * This file is part of the Contiki operating system.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1475</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1475"/>
				<updated>2014-11-09T07:31:08Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Data Structure Used In The System */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Memory Organization ===&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1474</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1474"/>
				<updated>2014-11-09T07:30:34Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1472</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1472"/>
				<updated>2014-11-09T07:30:01Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* file_desc */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1471</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1471"/>
				<updated>2014-11-09T07:29:39Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1470</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1470"/>
				<updated>2014-11-09T07:29:26Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* file_desc */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1437</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1437"/>
				<updated>2014-11-09T06:59:21Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Reference */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== General Issues ==&lt;br /&gt;
1. Use sizeof() instead strlen() in the strncpy() function.&amp;lt;br&amp;gt;&lt;br /&gt;
2. Remember to include string.h, otherwise when you compile it will generate warnings.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1435</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1435"/>
				<updated>2014-11-09T06:55:41Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_close */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.[1]&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1433</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1433"/>
				<updated>2014-11-09T06:54:33Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Memory Organization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1430</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1430"/>
				<updated>2014-11-09T06:51:38Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Coding With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  /*Write message to Filesystem*/&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
      /* compare with the original message to see if the message was read &lt;br /&gt;
      correctly, if it reads fail then it will print fail*/&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
     /*Append test */&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
       /*seek test*/&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
    /*if the seek fails then the second message will not &lt;br /&gt;
    be the same as the last message write to the file*/&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1426</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1426"/>
				<updated>2014-11-09T06:47:43Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Test Result */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Simulation Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1423</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1423"/>
				<updated>2014-11-09T06:46:09Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Coding With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
Modify the code provided by Contiki.&amp;lt;br&amp;gt;&lt;br /&gt;
Open contiki-2.7/examples/sky/example-coffee.c, then rewrite the file_test function.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Test Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1413</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1413"/>
				<updated>2014-11-09T06:41:52Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Test Result */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
== Test Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
We can see that Coffee File System works well.&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1410</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1410"/>
				<updated>2014-11-09T06:40:42Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Coding With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
== Test Result  ==&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1405</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1405"/>
				<updated>2014-11-09T06:38:34Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_write */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1403</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1403"/>
				<updated>2014-11-09T06:38:12Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_read */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.[1]&lt;br /&gt;
&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1401</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1401"/>
				<updated>2014-11-09T06:37:42Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_close */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1399</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1399"/>
				<updated>2014-11-09T06:36:15Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* find_file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory.&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1398</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1398"/>
				<updated>2014-11-09T06:36:01Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* find_file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
If the file correspond to the name is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1397</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1397"/>
				<updated>2014-11-09T06:35:38Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* find_file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
if the file is still resides in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1395</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1395"/>
				<updated>2014-11-09T06:33:55Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Data Structure Used In The System */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][1]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1394</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1394"/>
				<updated>2014-11-09T06:33:36Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_remove */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name). After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1392</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1392"/>
				<updated>2014-11-09T06:32:45Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* The CFS Programming Interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When an open file is no longer needed, the application should close it by using cfs_close(). By closing a file, the file system can deallocate its internal resources held for the file, and possibly commit any cached data to permanent storage.&amp;lt;br&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read() fills buf with at most len bytes, starting from the current position in the file that is stored in the file descriptor. It returns the amount of bytes read, or -1 if an error occurs.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
cfs_write() writes len bytes from the memory buffer buf into the file, starting from the current position in the file descriptor. The file must have been opened with the CFS_WRITE flag. It returns the amount of bytes written, or -1 if an error occurred.&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
cfs_seek() moves the current file position to the position determined by the combination of the offset and the whence. CFS_SEEK_SET tells cfs_seek() to compute the offset from the beginning of the file, i.e., as an absolute offset. CFS_SEEK_CUR specifies that the offset should be compute relative to the current position of the file position. Similarly, CFS_SEEK_END computes the offset in relation to the end of the file, and can be used to move beyond the end if the file system implementation allows it. Negative offset values are accepted by both CFS_SEEK_CUR and CFS_SEEK_END, if the program wishes to move the file position backwards from the base that is indicated by the whence parameter. cfs_seek() returns the new absolute file position upon success, or -1 if the file pointer could not be moved to the requested position.[1]&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name), if the file is still reside in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory. After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1387</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1387"/>
				<updated>2014-11-09T06:29:05Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Code With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read read size bytes from the opened file then store the date in the buf, then return the data size reader from the file.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name), if the file is still reside in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory. After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Coding With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1386</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1386"/>
				<updated>2014-11-09T06:28:25Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* How To Code With Coffee API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read read size bytes from the opened file then store the date in the buf, then return the data size reader from the file.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name), if the file is still reside in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory. After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1385</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1385"/>
				<updated>2014-11-09T06:27:11Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Reference */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read read size bytes from the opened file then store the date in the buf, then return the data size reader from the file.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name), if the file is still reside in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory. After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1384</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1384"/>
				<updated>2014-11-09T06:26:58Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Reference */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read read size bytes from the opened file then store the date in the buf, then return the data size reader from the file.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name), if the file is still reside in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory. After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1][https://github.com/contiki-os/contiki/wiki/File-systems] - Zane D. Purvis, &amp;quot;File systems&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[Contiki_tutorials | Back to Contiki Tutorials]]&lt;br /&gt;
&lt;br /&gt;
Edited by: Zhikun Liu&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1381</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1381"/>
				<updated>2014-11-09T06:23:33Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* The CFS Programming Interface */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
cfs_read read size bytes from the opened file then store the date in the buf, then return the data size reader from the file.&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
cfs_remove remove the file correspond to the name. It first find the file by find_file(name), if the file is still reside in coffee_files[COFFEE_MAX_OPEN_FILES] and the physical file is still valid then it return the pointer to that file, otherwise scan the FLSAH, and cache the file into memory. After that invoke remove_by_page to delete the file.&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1376</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1376"/>
				<updated>2014-11-09T06:12:15Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_close */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void cfs_close(int fd)&lt;br /&gt;
{&lt;br /&gt;
  if (FD_VALID(fd))&lt;br /&gt;
  {&lt;br /&gt;
    coffee_fd_set[fd].flags = COFFEE_FD_FREE;&lt;br /&gt;
    coffee_fd_set[fd].file-&amp;gt;references--;&lt;br /&gt;
    coffee_fd_set[fd].file = NULL;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#define FD_VALID(fd) ((fd)&amp;gt;= 0 &amp;amp;&amp;amp; (fd)&amp;lt;COFFEE_FD_SET_SIZE &amp;amp;&amp;amp; coffee_fd_set[(fd)].flags!=COFFEE_FD_FREE)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
When file is no longer needed, it will close the file and release the resource. It first make sure fd is valid, then set the flag in this fd_desc to COFFEE_FD_FREE, and then decrease the reference count of that file. Finally set the file_desc point to NULL.&lt;br /&gt;
&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1375</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1375"/>
				<updated>2014-11-09T06:05:52Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_open */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
==== cfs_close ====&lt;br /&gt;
==== cfs_read ====&lt;br /&gt;
==== cfs_write ====&lt;br /&gt;
==== cfs_seek ====&lt;br /&gt;
==== cfs_remove ====&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1373</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1373"/>
				<updated>2014-11-09T06:04:41Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* cfs_open */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== The CFS Programming Interface ===&lt;br /&gt;
&lt;br /&gt;
==== cfs_open ====&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1372</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1372"/>
				<updated>2014-11-09T06:02:27Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM. Contiki takes care of underlying hardware implementation. Coffee file system will provide a API which is similar to normal C file operations: Open a file, read and write to it and then close it. &amp;lt;br&amp;gt; Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== cfs_open ===&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1371</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1371"/>
				<updated>2014-11-09T05:58:04Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* You Will Learn */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM.  Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you are going  to understand how the Coffee file system works. And get to know how to program with the coffee file system API.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== cfs_open ===&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1370</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1370"/>
				<updated>2014-11-09T05:56:00Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.&amp;lt;br&amp;gt;Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM.  Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you will learn about how the Coffee file system works.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== cfs_open ===&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	<entry>
		<id>http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1369</id>
		<title>Contiki Coffee File System</title>
		<link rel="alternate" type="text/html" href="http://anrg.usc.edu/contiki/index.php?title=Contiki_Coffee_File_System&amp;diff=1369"/>
				<updated>2014-11-09T05:55:26Z</updated>
		
		<summary type="html">&lt;p&gt;Zhikunli: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
The tutorial covers the main features of Coffee File System available in ContikiOS 2.7.Contiki provides a set of file systems for using various kinds of storage devices in resource-constrained systems. All of these file systems implement a subset of the Contiki File System (CFS) interface, and two of them provide the full functionality: CFS-POSIX and Coffee[1]. Coffee is used with device equipped with flash memories or EEPROM.  Due to the restrained resource and affected by the environment, the data transmission will get lost sometimes, which then need to be retransmitted, applying file system in the wireless sensor node will help to make the system become more reliable by store the data in the nodes locally. Since we can store the data in the node locally then we can send multiple data via one transmission, which leads to less number of transmission, then reduce the power consumption.&lt;br /&gt;
&lt;br /&gt;
== You Will Learn ==&lt;br /&gt;
&lt;br /&gt;
Through this tutorial you will learn about how the Coffee file system works.&lt;br /&gt;
&lt;br /&gt;
== Source Code ==&lt;br /&gt;
&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.h&amp;lt;br&amp;gt;&lt;br /&gt;
~/contiki-2.7/core/cfs/cfs-coffee.c&lt;br /&gt;
&lt;br /&gt;
== Coffee File System API ==&lt;br /&gt;
&lt;br /&gt;
=== Data Structure Used In The System===&lt;br /&gt;
&lt;br /&gt;
==== Memory Organization ====&lt;br /&gt;
[[File:coffee-structure.png]][2]&amp;lt;br&amp;gt;&lt;br /&gt;
Coffee File System organize the file_desc as an array and mark it as a member in the protected_mem_t&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * The protected memory consists of structures that should not be &lt;br /&gt;
 * overwritten during system checkpointing because they may be used by &lt;br /&gt;
 * the checkpointing implementation. These structures need not be &lt;br /&gt;
 * protected if checkpointing is not used.&lt;br /&gt;
 */&lt;br /&gt;
static struct protected_mem_t {&lt;br /&gt;
  struct file coffee_files[COFFEE_MAX_OPEN_FILES];&lt;br /&gt;
  struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
  coffee_page_t next_free;&lt;br /&gt;
  char gc_wait;&lt;br /&gt;
} protected_mem;&lt;br /&gt;
static struct file * const coffee_files = protected_mem.coffee_files;&lt;br /&gt;
static struct file_desc * const coffee_fd_set = protected_mem.coffee_fd_set;&lt;br /&gt;
static coffee_page_t * const next_free = &amp;amp;protected_mem.next_free;&lt;br /&gt;
static char * const gc_wait = &amp;amp;protected_mem.gc_wait;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== file_desc ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc {&lt;br /&gt;
  cfs_offset_t offset; &lt;br /&gt;
  struct file *file; //  a file pointer which point to the corresponding file.&lt;br /&gt;
  uint8_t flags; //flag used to indicate the open mode of the file and whether the fd is free.&lt;br /&gt;
#if COFFEE_IO_SEMANTICS&lt;br /&gt;
  uint8_t io_flags;&lt;br /&gt;
#endif&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file_desc coffee_fd_set[COFFEE_FD_SET_SIZE];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Datastr.png|670px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== file ====&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
struct file {&lt;br /&gt;
  cfs_offset_t end;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  coffee_page_t max_pages;&lt;br /&gt;
  int16_t record_count;&lt;br /&gt;
  uint8_t references;&lt;br /&gt;
  uint8_t flags;&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:file.png|670px]]&lt;br /&gt;
&lt;br /&gt;
=== get_available_fd ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static int&lt;br /&gt;
get_available_fd(void)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_FD_SET_SIZE; i++) {&lt;br /&gt;
    if(coffee_fd_set[i].flags == COFFEE_FD_FREE) {&lt;br /&gt;
      return i;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return -1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contiki is a Linux like system, everything is a file, and the opened file is represented by the file descriptor. The get_available_fd will return the smallest available fd by check the file_desc array in an ascending order, the first one with flag == 0(COFFEE_FD_FREE) is what we want. If all the flags are set, then return -1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== find_file ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
static struct file *&lt;br /&gt;
find_file(const char *name)&lt;br /&gt;
{&lt;br /&gt;
  int i;&lt;br /&gt;
  struct file_header hdr;&lt;br /&gt;
  coffee_page_t page;&lt;br /&gt;
  &lt;br /&gt;
  /* First check if the file metadata is cached. */&lt;br /&gt;
  for(i = 0; i &amp;lt; COFFEE_MAX_OPEN_FILES; i++) {&lt;br /&gt;
    if(FILE_FREE(&amp;amp;coffee_files[i])) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    read_header(&amp;amp;hdr, coffee_files[i].page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return &amp;amp;coffee_files[i];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /* Scan the flash memory sequentially otherwise. */&lt;br /&gt;
  for(page = 0; page &amp;lt; COFFEE_PAGE_COUNT; page = next_file(page, &amp;amp;hdr)) {&lt;br /&gt;
    read_header(&amp;amp;hdr, page);&lt;br /&gt;
    if(HDR_ACTIVE(hdr) &amp;amp;&amp;amp; !HDR_LOG(hdr) &amp;amp;&amp;amp; strcmp(name, hdr.name) == 0) {&lt;br /&gt;
      return load_file(page, &amp;amp;hdr);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return NULL;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== cfs_open ===&lt;br /&gt;
cf_open is  used to open a file. If it successfully open the file then it returns the file descriptor(fd), otherwise it returns -1.&amp;lt;br&amp;gt;&lt;br /&gt;
cfs_open source code:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
int&lt;br /&gt;
cfs_open(const char *name, int flags)&lt;br /&gt;
{&lt;br /&gt;
  int fd;&lt;br /&gt;
  struct file_desc *fdp;&lt;br /&gt;
&lt;br /&gt;
  fd = get_available_fd(); //find the smallest available fd, see section 4.2&lt;br /&gt;
  if(fd &amp;lt; 0) {&lt;br /&gt;
    PRINTF(&amp;quot;Coffee: Failed to allocate a new file descriptor!\n&amp;quot;);&lt;br /&gt;
    return -1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp = &amp;amp;coffee_fd_set[fd];&lt;br /&gt;
  fdp-&amp;gt;flags = 0; //set the fd to FREE&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;file = find_file(name); //find the file corresponding to name(not exist, In flash but not cached, cached)&lt;br /&gt;
&lt;br /&gt;
  /*** if there isn&amp;#039;t any corresponding file, then try to create new file ***/&lt;br /&gt;
  if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
    if((flags &amp;amp; (CFS_READ | CFS_WRITE)) == CFS_READ) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file = reserve(name, page_count(COFFEE_DYN_SIZE), 1, 0);&lt;br /&gt;
    if(fdp-&amp;gt;file == NULL) {&lt;br /&gt;
      return -1;&lt;br /&gt;
    }&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = 0; // Since it&amp;#039;s a new created file, the end will be set to 0&lt;br /&gt;
  }&lt;br /&gt;
   /*** find the file,seek for the end of the file***/ &lt;br /&gt;
   else if(fdp-&amp;gt;file-&amp;gt;end == UNKNOWN_OFFSET) {&lt;br /&gt;
    fdp-&amp;gt;file-&amp;gt;end = file_end(fdp-&amp;gt;file-&amp;gt;page);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  fdp-&amp;gt;flags |= flags;&lt;br /&gt;
  fdp-&amp;gt;offset = flags &amp;amp; CFS_APPEND ? fdp-&amp;gt;file-&amp;gt;end : 0; //if the flag is set to APPEND, then the offset is set to the end of the file, otherwise set to 0&lt;br /&gt;
  fdp-&amp;gt;file-&amp;gt;references++; //reference count will increment&lt;br /&gt;
&lt;br /&gt;
  return fd;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:flowchart.png]]&lt;br /&gt;
&lt;br /&gt;
== How To Code With Coffee API   ==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;quot;contiki.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs.h&amp;quot;&lt;br /&gt;
#include &amp;quot;cfs/cfs-coffee.h&amp;quot;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
PROCESS(example_coffee_process, &amp;quot;Coffee example&amp;quot;);&lt;br /&gt;
AUTOSTART_PROCESSES(&amp;amp;example_coffee_process);&lt;br /&gt;
#define FILENAME &amp;quot;test&amp;quot;&lt;br /&gt;
/* Formatting is needed if the storage device is in an unknown state; &lt;br /&gt;
   e.g., when using Coffee on the storage device for the first time. */&lt;br /&gt;
#ifndef NEED_FORMATTING&lt;br /&gt;
#define NEED_FORMATTING 0&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
static int&lt;br /&gt;
file_test(const char *filename, char *msg)&lt;br /&gt;
{&lt;br /&gt;
	int fd;&lt;br /&gt;
	int r;&lt;br /&gt;
	char message[32];&lt;br /&gt;
	char buf[64];&lt;br /&gt;
	strncpy(message, &amp;quot;First Message&amp;quot;, sizeof(message) - 1);&lt;br /&gt;
	message[sizeof(message) - 1] = &amp;#039;\0&amp;#039;;&lt;br /&gt;
	strcpy(buf,message);&lt;br /&gt;
	/*First message is to test if the write will succeed*/&lt;br /&gt;
	printf(&amp;quot;Write Test: Will write \&amp;quot;%s\&amp;quot; to file \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf,FILENAME);&lt;br /&gt;
&lt;br /&gt;
  /* Obtain a file descriptor for the file, capable of handling both &lt;br /&gt;
     reads and writes. */&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,&lt;br /&gt;
				(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Write Test: Successfully wrote \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; wrote %d bytes\n &amp;quot;,message,FILENAME,r);&lt;br /&gt;
&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_read(fd, buf, sizeof(message));&lt;br /&gt;
	if(r != sizeof(message)) {&lt;br /&gt;
		printf(&amp;quot;failed to write %d bytes to %s\n&amp;quot;,(int)sizeof(message), FILENAME);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Read Test: Read \&amp;quot;%s\&amp;quot; from \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf, FILENAME);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
&lt;br /&gt;
	strcpy(message,&amp;quot;Append Something&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_WRITE | CFS_APPEND | CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	r = cfs_write(fd, message, sizeof(message));&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
	printf(&amp;quot;Append Test: Successfully \&amp;quot;%s\&amp;quot; to \&amp;quot;%s\&amp;quot; \n &amp;quot;,message,FILENAME);&lt;br /&gt;
	strcpy(buf,&amp;quot;fail&amp;quot;);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd &amp;lt; 0) {&lt;br /&gt;
		printf(&amp;quot;failed to open %s\n&amp;quot;, FILENAME);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read First Part \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	if(cfs_seek(fd, sizeof(message), CFS_SEEK_SET) == -1) {&lt;br /&gt;
		printf(&amp;quot;seek failed\n&amp;quot;);&lt;br /&gt;
		cfs_close(fd);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
  //cfs_seek(fd, sizeof(message), CFS_SEEK_SET);&lt;br /&gt;
	cfs_read(fd,buf,sizeof(message));&lt;br /&gt;
	printf(&amp;quot;Read Second Part: \&amp;quot;%s\&amp;quot;\n&amp;quot;,buf);&lt;br /&gt;
	cfs_close(fd);&lt;br /&gt;
  /* Release the internal resources held by Coffee for&lt;br /&gt;
     the file descriptor. */&lt;br /&gt;
	cfs_remove(FILENAME);&lt;br /&gt;
	fd = cfs_open(FILENAME, CFS_READ);&lt;br /&gt;
	if(fd != -1) {&lt;br /&gt;
		printf(&amp;quot;ERROR: could read from memory\n&amp;quot;);&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
	printf(&amp;quot;Successfully removed file\n&amp;quot;);&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PROCESS_THREAD(example_coffee_process, ev, data)&lt;br /&gt;
{&lt;br /&gt;
  PROCESS_BEGIN();&lt;br /&gt;
&lt;br /&gt;
#if NEED_FORMATTING&lt;br /&gt;
  cfs_coffee_format();&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
  /* Ensure that we will be working with a new file. */&lt;br /&gt;
  cfs_remove(FILENAME);&lt;br /&gt;
&lt;br /&gt;
  if(file_test(FILENAME, &amp;quot;The first test&amp;quot;) == 0) {&lt;br /&gt;
    printf(&amp;quot;file test 1 failed\n&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
  printf(&amp;quot;test succeed\n&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  PROCESS_END();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
[[File:result.png]]&lt;br /&gt;
&lt;br /&gt;
==Reference ==&lt;br /&gt;
[1]https://github.com/contiki-os/contiki/wiki/File-systems&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Zhikunli</name></author>	</entry>

	</feed>