1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  */
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 
13 #include <rtthread.h>
14 #include <dfs.h>
15 
16 #define DBG_TAG    "sd.sim"
17 #define DBG_LVL    DBG_WARNING
18 #include <rtdbg.h>
19 
20 #define SDCARD_SIM  "sd.bin"
21 #define SDCARD_SIZE (16*1024*1024)  //16M
22 
23 struct sdcard_device
24 {
25     struct rt_device parent;
26     FILE *file;
27 };
28 static struct sdcard_device _sdcard;
29 
30 #define SDCARD_DEVICE(device)       (( struct sdcard_device*)(device))
31 
32 static rt_mutex_t lock;
33 
34 /* RT-Thread device interface */
35 
rt_sdcard_init(rt_device_t dev)36 static rt_err_t rt_sdcard_init(rt_device_t dev)
37 {
38     return RT_EOK;
39 }
40 
rt_sdcard_open(rt_device_t dev,rt_uint16_t oflag)41 static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
42 {
43     return RT_EOK;
44 }
45 
rt_sdcard_close(rt_device_t dev)46 static rt_err_t rt_sdcard_close(rt_device_t dev)
47 {
48     return RT_EOK;
49 }
50 
51 /* position: block page address, not bytes address
52  * buffer:
53  * size  : how many blocks
54  */
rt_sdcard_read(rt_device_t device,rt_off_t position,void * buffer,rt_size_t size)55 static rt_ssize_t rt_sdcard_read(rt_device_t device, rt_off_t position, void *buffer, rt_size_t size)
56 {
57     struct sdcard_device *sd;
58     int result = 0;
59 
60     LOG_I("sd read: pos %d, size %d", position, size);
61 
62     rt_mutex_take(lock, RT_WAITING_FOREVER);
63     sd = SDCARD_DEVICE(device);
64     fseek(sd->file, position * SECTOR_SIZE, SEEK_SET);
65 
66     result = fread(buffer, size * SECTOR_SIZE, 1, sd->file);
67     if (result < 0)
68         goto _err;
69 
70     rt_mutex_release(lock);
71     return size;
72 
73 _err:
74     LOG_E("sd read errors!");
75     rt_mutex_release(lock);
76     return 0;
77 }
78 
79 /* position: block page address, not bytes address
80  * buffer:
81  * size  : how many blocks
82  */
rt_sdcard_write(rt_device_t device,rt_off_t position,const void * buffer,rt_size_t size)83 static rt_ssize_t rt_sdcard_write(rt_device_t device, rt_off_t position, const void *buffer, rt_size_t size)
84 {
85     struct sdcard_device *sd;
86     int result = 0;
87 
88     LOG_I("sst write: pos %d, size %d", position, size);
89 
90     rt_mutex_take(lock, RT_WAITING_FOREVER);
91     sd = SDCARD_DEVICE(device);
92     fseek(sd->file, position * SECTOR_SIZE, SEEK_SET);
93 
94     result = fwrite(buffer, size * SECTOR_SIZE, 1, sd->file);
95     if (result < 0)
96         goto _err;
97 
98     rt_mutex_release(lock);
99     return size;
100 
101 _err:
102     LOG_E("sd write errors!");
103     rt_mutex_release(lock);
104     return 0;
105 }
106 
rt_sdcard_control(rt_device_t dev,int cmd,void * args)107 static rt_err_t rt_sdcard_control(rt_device_t dev, int cmd, void *args)
108 {
109     struct sdcard_device *sd;
110     unsigned int size;
111 
112     RT_ASSERT(dev != RT_NULL);
113 
114     sd = SDCARD_DEVICE(dev);
115 
116     if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
117     {
118         struct rt_device_blk_geometry *geometry;
119 
120         geometry = (struct rt_device_blk_geometry *)args;
121         if (geometry == RT_NULL) return -RT_ERROR;
122 
123         geometry->bytes_per_sector = SECTOR_SIZE;
124         geometry->block_size = SECTOR_SIZE;
125 
126         fseek(sd->file, 0, SEEK_END);
127         size = ftell(sd->file);
128 
129         geometry->sector_count = size / SECTOR_SIZE;
130     }
131     return RT_EOK;
132 }
133 
rt_hw_sdcard_init(const char * spi_device_name)134 rt_err_t rt_hw_sdcard_init(const char *spi_device_name)
135 {
136     int size;
137     struct sdcard_device *sd;
138     struct rt_device *device;
139 
140     sd = &_sdcard;
141     device = &(sd->parent);
142 
143     lock = rt_mutex_create("lock", RT_IPC_FLAG_PRIO);
144     if (lock == RT_NULL)
145     {
146         LOG_E("Create mutex in rt_hw_sdcard_init failed!");
147         return -RT_ERROR;
148     }
149 
150     /* open sd card file, if not exist, then create it  */
151     sd->file = fopen(SDCARD_SIM, "rb+");
152     if (sd->file == NULL)
153     {
154         /* create a file to simulate sd card */
155         sd->file = fopen(SDCARD_SIM, "wb+");
156 
157         fseek(sd->file, 0, SEEK_END);
158         size = ftell(sd->file);
159 
160         fseek(sd->file, 0, SEEK_SET);
161         if (size < SDCARD_SIZE)
162         {
163             int i;
164             unsigned char *ptr;
165 
166             ptr = (unsigned char *) malloc(1024 * 1024);
167             if (ptr == NULL)
168             {
169                 LOG_E("malloc error, no memory!");
170                 return -RT_ERROR;
171             }
172             memset(ptr, 0x0, 1024 * 1024);
173 
174             fseek(sd->file, 0, SEEK_SET);
175 
176             for (i = 0; i < (SDCARD_SIZE / (1024 * 1024)); i++)
177                 fwrite(ptr, 1024 * 1024, 1, sd->file);
178 
179             free(ptr);
180         }
181     }
182     fseek(sd->file, 0, SEEK_SET);
183 
184     device->type  = RT_Device_Class_Block;
185     device->init = rt_sdcard_init;
186     device->open = rt_sdcard_open;
187     device->close = rt_sdcard_close;
188     device->read = rt_sdcard_read;
189     device->write = rt_sdcard_write;
190     device->control = rt_sdcard_control;
191     device->user_data = NULL;
192 
193     rt_device_register(device, "sd0",
194                        RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
195 
196     return RT_EOK;
197 }
198 
199 #ifdef RT_USING_FINSH
200 #include <finsh.h>
sd_erase(void)201 int sd_erase(void)
202 {
203     rt_uint32_t index;
204     char * buffer;
205     struct rt_device *device;
206     device = &_sdcard.parent;
207     if ((buffer = rt_malloc(SECTOR_SIZE)) == RT_NULL)
208     {
209         rt_kprintf("out of memory\n");
210         return -1;
211     }
212 
213     memset(buffer, 0, SECTOR_SIZE);
214     /* just erase the MBR! */
215     for (index = 0; index < 2; index ++)
216     {
217         rt_sdcard_write(device, index, buffer, SECTOR_SIZE);
218     }
219     rt_free(buffer);
220     return 0;
221 }
222 FINSH_FUNCTION_EXPORT(sd_erase, erase all block in SPI flash);
223 #endif
224