c87a2fea30f21891ad18105e57a161a51ca402f1
[bertos.git] / bertos / emul / diskio_emul.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2009 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Low level disk access for FatFs emulated.
34  *
35  * \version $Id$
36  * \author Luca Ottaviano <lottaviano@develer.com>
37  */
38
39 /*-----------------------------------------------------------------------*/
40 /* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2007        */
41 /*-----------------------------------------------------------------------*/
42
43 #include <fs/fatfs/src/diskio.h>
44 #include <stdio.h>
45 #include <errno.h>
46 #include <time.h>
47
48 #define SECTOR_SIZE 512
49
50 static volatile DSTATUS Stat = STA_NOINIT;
51
52 /**
53  * This is an example implementation, used to simulate the the calls to normal filesystem calls
54  * It only works for drive 0.
55  */
56
57
58 /*-----------------------------------------------------------------------*/
59 /* Inidialize a Drive                                                    */
60
61 static FILE *fake_disk = 0;
62
63 DSTATUS disk_initialize (
64         BYTE drv                                /* Physical drive nmuber (0..) */
65 )
66 {
67         if (drv)
68                 return STA_NOINIT; /* Support only drive 0 */
69         // XXX: pay attention here: some functions call disk_initialize *after* it has
70         //  been initialized for the first time.
71         //  Here we just return the status (that should always be ~STA_NOINIT after the first
72         //  call)
73         if (fake_disk)
74                 return Stat;
75
76         const char *path = "emuldisk.dsk";
77         fake_disk = fopen(path, "w+");
78         int err = errno;
79         if (!fake_disk)
80         {
81                 switch (err)
82                 {
83                 case EINVAL:
84                         fprintf(stderr, "invalid mode\n");
85                 default:
86                         return STA_NOINIT;
87                 }
88         }
89         Stat &= ~STA_NOINIT;
90         return Stat;
91 }
92
93
94
95 /*-----------------------------------------------------------------------*/
96 /* Return Disk Status                                                    */
97
98 DSTATUS disk_status (
99         BYTE drv                /* Physical drive nmuber (0..) */
100 )
101 {
102         if (drv)
103                 return STA_NOINIT; /* Support only drive 0 */
104         return Stat;
105 }
106
107
108
109 /*-----------------------------------------------------------------------*/
110 /* Read Sector(s)                                                        */
111
112 DRESULT disk_read (
113         BYTE drv,               /* Physical drive nmuber (0..) */
114         BYTE *buff,             /* Data buffer to store read data */
115         DWORD sector,   /* Sector address (LBA) */
116         BYTE count              /* Number of sectors to read (1..255) */
117 )
118 {
119         if (drv || !count) return RES_PARERR;
120         if (Stat & STA_NOINIT) return RES_NOTRDY;
121
122         fseek(fake_disk, sector * SECTOR_SIZE, SEEK_SET);
123         size_t read_items = fread(buff, SECTOR_SIZE, count, fake_disk);
124         if (read_items == count)
125                 return RES_OK;
126         else
127         {
128                 if (feof(fake_disk))
129                         fprintf(stderr, "end-of-file\n");
130                 if (ferror(fake_disk))
131                         fprintf(stderr, "error\n");
132                 return RES_ERROR;
133         }
134 }
135
136
137 /*-----------------------------------------------------------------------*/
138 /* Write Sector(s)                                                       */
139
140 #if _READONLY == 0
141 DRESULT disk_write (
142         BYTE drv,                       /* Physical drive nmuber (0..) */
143         const BYTE *buff,       /* Data to be written */
144         DWORD sector,           /* Sector address (LBA) */
145         BYTE count                      /* Number of sectors to write (1..255) */
146 )
147 {
148         if (drv || !count) return RES_PARERR;
149         if (Stat & STA_NOINIT) return RES_NOTRDY;
150         if (Stat & STA_PROTECT) return RES_WRPRT;
151
152         fseek(fake_disk, sector * SECTOR_SIZE, SEEK_SET);
153         size_t write_items = fwrite(buff, SECTOR_SIZE, count, fake_disk);
154         if (write_items == count)
155                 return RES_OK;
156         else
157         {
158                 if (feof(fake_disk))
159                         fprintf(stderr, "end-of-file\n");
160                 if (ferror(fake_disk))
161                         fprintf(stderr, "error\n");
162                 return RES_ERROR;
163         }
164 }
165 #endif /* _READONLY */
166
167
168
169 /*-----------------------------------------------------------------------*/
170 /* Miscellaneous Functions                                               */
171
172 DRESULT disk_ioctl (
173         BYTE drv,               /* Physical drive nmuber (0..) */
174         BYTE ctrl,              /* Control code */
175         void *buff              /* Buffer to send/receive control data */
176 )
177 {
178         if (drv) return RES_PARERR;
179         if (Stat & STA_NOINIT) return RES_NOTRDY;
180
181         switch (ctrl)
182         {
183         case GET_SECTOR_SIZE:
184                 *(WORD*)buff = SECTOR_SIZE;
185                 break;
186         case GET_SECTOR_COUNT:
187                 *(DWORD*)buff = 65536;
188                 break;
189         case GET_BLOCK_SIZE:
190                 *(DWORD*)buff = 1;
191                 break;
192         case CTRL_SYNC:
193                 fflush(fake_disk);
194                 break;
195         default:
196                 return RES_PARERR;
197         }
198         return RES_OK;
199 }
200
201 DWORD get_fattime(void)
202 {
203         time_t tmp = time(0);
204         struct tm *t = localtime(&tmp);
205         DWORD tim = 0;
206         // seconds
207         tim |= (t->tm_sec / 2);
208         // min
209         tim |= (t->tm_min << 5);
210         // hour
211         tim |= (t->tm_hour << 11);
212         // month day (1..31)
213         tim |= (t->tm_mday << 16);
214         // month (1..12)
215         tim |= ((t->tm_mon + 1) << 21);
216         // year (0..127)
217         tim |= ((t->tm_year - 80) << 25);
218         return tim;
219 }
220