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