1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2018-06-23     armink       the first version
9  * 2019-08-22     MurphyZhao   adapt to none rt-thread case
10  */
11 
12 #include <fal.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <rtdevice.h>
16 
17 #define DBG_TAG "FAL"
18 #ifdef FAL_USING_DEBUG
19 #define DBG_LVL DBG_LOG
20 #else
21 #define DBG_LVL DBG_WARNING
22 #endif
23 #include <rtdbg.h>
24 
25 
26 /* ========================== block device ======================== */
27 struct fal_blk_device
28 {
29     struct rt_device                parent;
30     struct rt_device_blk_geometry   geometry;
31     const struct fal_partition     *fal_part;
32 };
33 
34 /* RT-Thread device interface */
35 #if RTTHREAD_VERSION >= 30000
blk_dev_control(rt_device_t dev,int cmd,void * args)36 static rt_err_t blk_dev_control(rt_device_t dev, int cmd, void *args)
37 #else
38 static rt_err_t blk_dev_control(rt_device_t dev, rt_uint8_t cmd, void *args)
39 #endif
40 {
41     struct fal_blk_device *part = (struct fal_blk_device*) dev;
42 
43     RT_ASSERT(part != RT_NULL);
44 
45     if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
46     {
47         struct rt_device_blk_geometry *geometry;
48 
49         geometry = (struct rt_device_blk_geometry *) args;
50         if (geometry == RT_NULL)
51         {
52             return -RT_ERROR;
53         }
54 
55         rt_memcpy(geometry, &part->geometry, sizeof(struct rt_device_blk_geometry));
56     }
57     else if (cmd == RT_DEVICE_CTRL_BLK_ERASE)
58     {
59         rt_uint32_t *addrs = (rt_uint32_t *) args, start_addr = addrs[0], end_addr = addrs[1], phy_start_addr;
60         rt_size_t phy_size;
61 
62         if (addrs == RT_NULL || start_addr > end_addr)
63         {
64             return -RT_ERROR;
65         }
66 
67         if (end_addr == start_addr)
68         {
69             end_addr++;
70         }
71 
72         phy_start_addr = start_addr * part->geometry.bytes_per_sector;
73         phy_size = (end_addr - start_addr) * part->geometry.bytes_per_sector;
74 
75         if (fal_partition_erase(part->fal_part, phy_start_addr, phy_size) < 0)
76         {
77             return -RT_ERROR;
78         }
79     }
80 
81     return RT_EOK;
82 }
83 
blk_dev_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)84 static rt_ssize_t blk_dev_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
85 {
86     int ret = 0;
87     struct fal_blk_device *part = (struct fal_blk_device*) dev;
88 
89     RT_ASSERT(part != RT_NULL);
90 
91     ret = fal_partition_read(part->fal_part, pos * part->geometry.block_size, buffer, size * part->geometry.block_size);
92 
93     if (ret != (int)(size * part->geometry.block_size))
94     {
95         ret = 0;
96     }
97     else
98     {
99         ret = size;
100     }
101 
102     return ret;
103 }
104 
blk_dev_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)105 static rt_ssize_t blk_dev_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
106 {
107     int ret = 0;
108     struct fal_blk_device *part;
109     rt_off_t phy_pos;
110     rt_size_t phy_size;
111 
112     part = (struct fal_blk_device*) dev;
113     RT_ASSERT(part != RT_NULL);
114 
115     /* change the block device's logic address to physical address */
116     phy_pos = pos * part->geometry.bytes_per_sector;
117     phy_size = size * part->geometry.bytes_per_sector;
118 
119     ret = fal_partition_erase(part->fal_part, phy_pos, phy_size);
120 
121     if (ret == (int) phy_size)
122     {
123         ret = fal_partition_write(part->fal_part, phy_pos, buffer, phy_size);
124     }
125 
126     if (ret != (int) phy_size)
127     {
128         ret = 0;
129     }
130     else
131     {
132         ret = size;
133     }
134 
135     return ret;
136 }
137 
138 #ifdef RT_USING_DEVICE_OPS
139 const static struct rt_device_ops blk_dev_ops =
140 {
141     RT_NULL,
142     RT_NULL,
143     RT_NULL,
144     blk_dev_read,
145     blk_dev_write,
146     blk_dev_control
147 };
148 #endif
149 
150 /**
151  * create RT-Thread block device by specified partition
152  *
153  * @param parition_name partition name
154  *
155  * @return != NULL: created block device
156  *            NULL: created failed
157  */
fal_blk_device_create(const char * parition_name)158 struct rt_device *fal_blk_device_create(const char *parition_name)
159 {
160     struct fal_blk_device *blk_dev;
161     const struct fal_partition *fal_part = fal_partition_find(parition_name);
162     const struct fal_flash_dev *fal_flash = NULL;
163 
164     if (!fal_part)
165     {
166         LOG_E("Error: the partition name (%s) is not found.", parition_name);
167         return NULL;
168     }
169 
170     if ((fal_flash = fal_flash_device_find(fal_part->flash_name)) == NULL)
171     {
172         LOG_E("Error: the flash device name (%s) is not found.", fal_part->flash_name);
173         return NULL;
174     }
175 
176     blk_dev = (struct fal_blk_device*) rt_malloc(sizeof(struct fal_blk_device));
177     if (blk_dev)
178     {
179         blk_dev->fal_part = fal_part;
180         blk_dev->geometry.bytes_per_sector = fal_flash->blk_size;
181         blk_dev->geometry.block_size = fal_flash->blk_size;
182         blk_dev->geometry.sector_count = fal_part->len / fal_flash->blk_size;
183 
184         /* register device */
185         blk_dev->parent.type = RT_Device_Class_Block;
186 
187 #ifdef RT_USING_DEVICE_OPS
188         blk_dev->parent.ops  = &blk_dev_ops;
189 #else
190         blk_dev->parent.init = NULL;
191         blk_dev->parent.open = NULL;
192         blk_dev->parent.close = NULL;
193         blk_dev->parent.read = blk_dev_read;
194         blk_dev->parent.write = blk_dev_write;
195         blk_dev->parent.control = blk_dev_control;
196 #endif
197 
198         /* no private */
199         blk_dev->parent.user_data = RT_NULL;
200 
201         LOG_I("The FAL block device (%s) created successfully", fal_part->name);
202         rt_device_register(RT_DEVICE(blk_dev), fal_part->name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
203     }
204     else
205     {
206         LOG_E("Error: no memory for create FAL block device");
207     }
208 
209     return RT_DEVICE(blk_dev);
210 }
211 
212 /* ========================== MTD nor device ======================== */
213 #if defined(RT_USING_MTD_NOR)
214 
215 struct fal_mtd_nor_device
216 {
217     struct rt_mtd_nor_device       parent;
218     const struct fal_partition     *fal_part;
219 };
220 
mtd_nor_dev_read(struct rt_mtd_nor_device * device,rt_off_t offset,rt_uint8_t * data,rt_size_t length)221 static rt_ssize_t mtd_nor_dev_read(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_size_t length)
222 {
223     int ret = 0;
224     struct fal_mtd_nor_device *part = (struct fal_mtd_nor_device*) device;
225 
226     RT_ASSERT(part != RT_NULL);
227 
228     ret = fal_partition_read(part->fal_part, offset, data, length);
229 
230     if (ret != (int)length)
231     {
232         ret = 0;
233     }
234     else
235     {
236         ret = length;
237     }
238 
239     return ret;
240 }
241 
mtd_nor_dev_write(struct rt_mtd_nor_device * device,rt_off_t offset,const rt_uint8_t * data,rt_size_t length)242 static rt_ssize_t mtd_nor_dev_write(struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_size_t length)
243 {
244     int ret = 0;
245     struct fal_mtd_nor_device *part;
246 
247     part = (struct fal_mtd_nor_device*) device;
248     RT_ASSERT(part != RT_NULL);
249 
250     ret = fal_partition_write(part->fal_part, offset, data, length);
251 
252     if (ret != (int) length)
253     {
254         ret = 0;
255     }
256     else
257     {
258         ret = length;
259     }
260 
261     return ret;
262 }
263 
mtd_nor_dev_erase(struct rt_mtd_nor_device * device,rt_off_t offset,rt_size_t length)264 static rt_err_t mtd_nor_dev_erase(struct rt_mtd_nor_device* device, rt_off_t offset, rt_size_t length)
265 {
266     int ret = 0;
267     struct fal_mtd_nor_device *part;
268 
269     part = (struct fal_mtd_nor_device*) device;
270     RT_ASSERT(part != RT_NULL);
271 
272     ret = fal_partition_erase(part->fal_part, offset, length);
273 
274     if (ret != (int)length || ret < 0)
275     {
276         return -RT_ERROR;
277     }
278     else
279     {
280         return RT_EOK;
281     }
282 }
283 
284 static const struct rt_mtd_nor_driver_ops _ops =
285 {
286     RT_NULL,           /* read_id */
287     mtd_nor_dev_read,  /* read */
288     mtd_nor_dev_write, /* write*/
289     mtd_nor_dev_erase, /* erase_block */
290 };
291 
292 /**
293  * create RT-Thread MTD NOR device by specified partition
294  *
295  * @param parition_name partition name
296  *
297  * @return != NULL: created MTD NOR device
298  *            NULL: created failed
299  */
fal_mtd_nor_device_create(const char * parition_name)300 struct rt_device *fal_mtd_nor_device_create(const char *parition_name)
301 {
302     struct fal_mtd_nor_device *mtd_nor_dev;
303     const struct fal_partition *fal_part = fal_partition_find(parition_name);
304     const struct fal_flash_dev *fal_flash = NULL;
305 
306     if (!fal_part)
307     {
308         LOG_E("Error: the partition name (%s) is not found.", parition_name);
309         return NULL;
310     }
311 
312     if ((fal_flash = fal_flash_device_find(fal_part->flash_name)) == NULL)
313     {
314         LOG_E("Error: the flash device name (%s) is not found.", fal_part->flash_name);
315         return NULL;
316     }
317 
318     mtd_nor_dev = (struct fal_mtd_nor_device*) rt_malloc(sizeof(struct fal_mtd_nor_device));
319     if (mtd_nor_dev)
320     {
321         mtd_nor_dev->fal_part = fal_part;
322 
323         mtd_nor_dev->parent.block_start = 0;
324         mtd_nor_dev->parent.block_end = fal_part->len / fal_flash->blk_size;
325         mtd_nor_dev->parent.block_size = fal_flash->blk_size;
326 
327         /* set ops */
328         mtd_nor_dev->parent.ops = &_ops;
329 
330         LOG_I("The FAL MTD NOR device (%s) created successfully", fal_part->name);
331         rt_mtd_nor_register_device(fal_part->name, &mtd_nor_dev->parent);
332     }
333     else
334     {
335         LOG_E("Error: no memory for create FAL MTD NOR device");
336     }
337 
338     return RT_DEVICE(&mtd_nor_dev->parent);
339 }
340 
341 #endif /* defined(RT_USING_MTD_NOR) */
342 
343 
344 /* ========================== char device ======================== */
345 struct fal_char_device
346 {
347     struct rt_device                parent;
348     const struct fal_partition     *fal_part;
349 };
350 
351 /* RT-Thread device interface */
char_dev_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)352 static rt_ssize_t char_dev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
353 {
354     int ret = 0;
355     struct fal_char_device *part = (struct fal_char_device *) dev;
356 
357     RT_ASSERT(part != RT_NULL);
358 
359     if (pos + size > part->fal_part->len)
360         size = part->fal_part->len - pos;
361 
362     ret = fal_partition_read(part->fal_part, pos, buffer, size);
363 
364     if (ret != (int)(size))
365         ret = 0;
366 
367     return ret;
368 }
369 
char_dev_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)370 static rt_ssize_t char_dev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
371 {
372     int ret = 0;
373     struct fal_char_device *part;
374 
375     part = (struct fal_char_device *) dev;
376     RT_ASSERT(part != RT_NULL);
377 
378     if (pos == 0)
379     {
380         fal_partition_erase_all(part->fal_part);
381     }
382     else if (pos + size > part->fal_part->len)
383     {
384         size = part->fal_part->len - pos;
385     }
386 
387     ret = fal_partition_write(part->fal_part, pos, buffer, size);
388 
389     if (ret != (int) size)
390         ret = 0;
391 
392     return ret;
393 }
394 
395 #ifdef RT_USING_DEVICE_OPS
396 const static struct rt_device_ops char_dev_ops =
397 {
398     RT_NULL,
399     RT_NULL,
400     RT_NULL,
401     char_dev_read,
402     char_dev_write,
403     RT_NULL
404 };
405 #endif
406 
407 #ifdef RT_USING_POSIX_DEVIO
408 #include <dfs_file.h>
409 #include <unistd.h>
410 #include <stdio.h> /* rename() */
411 #include <sys/stat.h>
412 #include <sys/statfs.h> /* statfs() */
413 
414 /* RT-Thread device filesystem interface */
char_dev_fopen(struct dfs_file * fd)415 static int char_dev_fopen(struct dfs_file *fd)
416 {
417     struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
418 
419     RT_ASSERT(part != RT_NULL);
420 
421     switch (fd->flags & O_ACCMODE)
422     {
423     case O_RDONLY:
424         break;
425     case O_WRONLY:
426     case O_RDWR:
427         /* erase partition when device file open */
428         fal_partition_erase_all(part->fal_part);
429         break;
430     default:
431         break;
432     }
433     DFS_FILE_POS(fd) = 0;
434 
435     return RT_EOK;
436 }
437 
char_dev_fread(struct dfs_file * fd,void * buf,rt_size_t count)438 static int char_dev_fread(struct dfs_file *fd, void *buf, rt_size_t count)
439 {
440     int ret = 0;
441     struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
442 
443     RT_ASSERT(part != RT_NULL);
444 
445     if (DFS_FILE_POS(fd) + count > part->fal_part->len)
446         count = part->fal_part->len - DFS_FILE_POS(fd);
447 
448     ret = fal_partition_read(part->fal_part, DFS_FILE_POS(fd), buf, count);
449 
450     if (ret != (int)(count))
451         return 0;
452 
453     DFS_FILE_POS(fd) += ret;
454 
455     return ret;
456 }
457 
char_dev_fwrite(struct dfs_file * fd,const void * buf,rt_size_t count)458 static int char_dev_fwrite(struct dfs_file *fd, const void *buf, rt_size_t count)
459 {
460     int ret = 0;
461     struct fal_char_device *part = (struct fal_char_device *) fd->vnode->data;
462 
463     RT_ASSERT(part != RT_NULL);
464 
465     if (DFS_FILE_POS(fd) + count > part->fal_part->len)
466         count = part->fal_part->len - DFS_FILE_POS(fd);
467 
468     ret = fal_partition_write(part->fal_part, DFS_FILE_POS(fd), buf, count);
469 
470     if (ret != (int) count)
471         return 0;
472 
473     DFS_FILE_POS(fd) += ret;
474 
475     return ret;
476 }
477 
478 static const struct dfs_file_ops char_dev_fops =
479 {
480     char_dev_fopen,
481     RT_NULL,
482     RT_NULL,
483     char_dev_fread,
484     char_dev_fwrite,
485     RT_NULL, /* flush */
486     RT_NULL, /* lseek */
487     RT_NULL, /* getdents */
488     RT_NULL,
489 };
490 #endif /* defined(RT_USING_POSIX_DEVIO) */
491 
492 /**
493  * create RT-Thread char device by specified partition
494  *
495  * @param parition_name partition name
496  *
497  * @return != NULL: created char device
498  *            NULL: created failed
499  */
fal_char_device_create(const char * parition_name)500 struct rt_device *fal_char_device_create(const char *parition_name)
501 {
502     struct fal_char_device *char_dev;
503     const struct fal_partition *fal_part = fal_partition_find(parition_name);
504 
505     if (!fal_part)
506     {
507         LOG_E("Error: the partition name (%s) is not found.", parition_name);
508         return NULL;
509     }
510 
511     if ((fal_flash_device_find(fal_part->flash_name)) == NULL)
512     {
513         LOG_E("Error: the flash device name (%s) is not found.", fal_part->flash_name);
514         return NULL;
515     }
516 
517     char_dev = (struct fal_char_device *) rt_malloc(sizeof(struct fal_char_device));
518     if (char_dev)
519     {
520         char_dev->fal_part = fal_part;
521 
522         /* register device */
523         char_dev->parent.type = RT_Device_Class_Char;
524 
525 #ifdef RT_USING_DEVICE_OPS
526         char_dev->parent.ops  = &char_dev_ops;
527 #else
528         char_dev->parent.init = NULL;
529         char_dev->parent.open = NULL;
530         char_dev->parent.close = NULL;
531         char_dev->parent.read = char_dev_read;
532         char_dev->parent.write = char_dev_write;
533         char_dev->parent.control = NULL;
534         /* no private */
535         char_dev->parent.user_data = NULL;
536 #endif
537 
538         rt_device_register(RT_DEVICE(char_dev), fal_part->name, RT_DEVICE_FLAG_RDWR);
539         LOG_I("The FAL char device (%s) created successfully", fal_part->name);
540 
541 #ifdef RT_USING_POSIX_DEVIO
542         /* set fops */
543         char_dev->parent.fops = &char_dev_fops;
544 #endif
545 
546     }
547     else
548     {
549         LOG_E("Error: no memory for create FAL char device");
550     }
551 
552     return RT_DEVICE(char_dev);
553 }
554 
555 #if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH)
556 
557 #include <finsh.h>
558 extern int fal_init_check(void);
559 
fal(rt_uint8_t argc,char ** argv)560 static void fal(rt_uint8_t argc, char **argv) {
561 
562 #define __is_print(ch)                ((unsigned int)((ch) - ' ') < 127u - ' ')
563 #define HEXDUMP_WIDTH                 16
564 #define CMD_PROBE_INDEX               0
565 #define CMD_READ_INDEX                1
566 #define CMD_WRITE_INDEX               2
567 #define CMD_ERASE_INDEX               3
568 #define CMD_BENCH_INDEX               4
569 
570     int result = 0;
571     static const struct fal_flash_dev *flash_dev = NULL;
572     static const struct fal_partition *part_dev = NULL;
573     rt_size_t i = 0, j = 0;
574 
575     const char* help_info[] =
576     {
577             [CMD_PROBE_INDEX]     = "fal probe [dev_name|part_name]   - probe flash device or partition by given name",
578             [CMD_READ_INDEX]      = "fal read addr size               - read 'size' bytes starting at 'addr'",
579             [CMD_WRITE_INDEX]     = "fal write addr data1 ... dataN   - write some bytes 'data' starting at 'addr'",
580             [CMD_ERASE_INDEX]     = "fal erase addr size              - erase 'size' bytes starting at 'addr'",
581             [CMD_BENCH_INDEX]     = "fal bench <blk_size>             - benchmark test with per block size",
582     };
583 
584     if (fal_init_check() != 1)
585     {
586         rt_kprintf("\n[Warning] FAL is not initialized or failed to initialize!\n\n");
587         return;
588     }
589 
590     if (argc < 2)
591     {
592         rt_kprintf("Usage:\n");
593         for (i = 0; i < sizeof(help_info) / sizeof(char*); i++)
594         {
595             rt_kprintf("%s\n", help_info[i]);
596         }
597         rt_kprintf("\n");
598     }
599     else
600     {
601         const char *operator = argv[1];
602         rt_uint32_t addr, size;
603 
604         if (!strcmp(operator, "probe"))
605         {
606             if (argc >= 3)
607             {
608                 char *dev_name = argv[2];
609                 if ((flash_dev = fal_flash_device_find(dev_name)) != NULL)
610                 {
611                     part_dev = NULL;
612                 }
613                 else if ((part_dev = fal_partition_find(dev_name)) != NULL)
614                 {
615                     flash_dev = NULL;
616                 }
617                 else
618                 {
619                     rt_kprintf("Device %s NOT found. Probe failed.\n", dev_name);
620                     flash_dev = NULL;
621                     part_dev = NULL;
622                 }
623             }
624 
625             if (flash_dev)
626             {
627                 rt_kprintf("Probed a flash device | %s | addr: %ld | len: %d |.\n", flash_dev->name,
628                         flash_dev->addr, flash_dev->len);
629             }
630             else if (part_dev)
631             {
632                 rt_kprintf("Probed a flash partition | %s | flash_dev: %s | offset: %ld | len: %d |.\n",
633                         part_dev->name, part_dev->flash_name, part_dev->offset, part_dev->len);
634             }
635             else
636             {
637                 rt_kprintf("No flash device or partition was probed.\n");
638                 rt_kprintf("Usage: %s.\n", help_info[CMD_PROBE_INDEX]);
639                 fal_show_part_table();
640             }
641         }
642         else
643         {
644             if (!flash_dev && !part_dev)
645             {
646                 rt_kprintf("No flash device or partition was probed. Please run 'fal probe'.\n");
647                 return;
648             }
649             if (!rt_strcmp(operator, "read"))
650             {
651                 if (argc < 4)
652                 {
653                     rt_kprintf("Usage: %s.\n", help_info[CMD_READ_INDEX]);
654                     return;
655                 }
656                 else
657                 {
658                     addr = strtol(argv[2], NULL, 0);
659                     size = strtol(argv[3], NULL, 0);
660                     rt_uint8_t *data = rt_malloc(size);
661                     if (data)
662                     {
663                         if (flash_dev)
664                         {
665                             result = flash_dev->ops.read(addr, data, size);
666                         }
667                         else if (part_dev)
668                         {
669                             result = fal_partition_read(part_dev, addr, data, size);
670                         }
671                         if (result >= 0)
672                         {
673                             rt_kprintf("Read data success. Start from 0x%08X, size is %ld. The data is:\n", addr,
674                                     size);
675                             rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
676                             for (i = 0; i < size; i += HEXDUMP_WIDTH)
677                             {
678                                 rt_kprintf("[%08X] ", addr + i);
679                                 /* dump hex */
680                                 for (j = 0; j < HEXDUMP_WIDTH; j++)
681                                 {
682                                     if (i + j < size)
683                                     {
684                                         rt_kprintf("%02X ", data[i + j]);
685                                     }
686                                     else
687                                     {
688                                         rt_kprintf("   ");
689                                     }
690                                 }
691                                 /* dump char for hex */
692                                 for (j = 0; j < HEXDUMP_WIDTH; j++)
693                                 {
694                                     if (i + j < size)
695                                     {
696                                         rt_kprintf("%c", __is_print(data[i + j]) ? data[i + j] : '.');
697                                     }
698                                 }
699                                 rt_kprintf("\n");
700                             }
701                             rt_kprintf("\n");
702                         }
703                         rt_free(data);
704                     }
705                     else
706                     {
707                         rt_kprintf("Low memory!\n");
708                     }
709                 }
710             }
711             else if (!strcmp(operator, "write"))
712             {
713                 if (argc < 4)
714                 {
715                     rt_kprintf("Usage: %s.\n", help_info[CMD_WRITE_INDEX]);
716                     return;
717                 }
718                 else
719                 {
720                     addr = strtol(argv[2], NULL, 0);
721                     size = argc - 3;
722                     rt_uint8_t *data = rt_malloc(size);
723                     if (data)
724                     {
725                         for (i = 0; i < size; i++)
726                         {
727                             data[i] = strtol(argv[3 + i], NULL, 0);
728                         }
729                         if (flash_dev)
730                         {
731                             result = flash_dev->ops.write(addr, data, size);
732                         }
733                         else if (part_dev)
734                         {
735                             result = fal_partition_write(part_dev, addr, data, size);
736                         }
737                         if (result >= 0)
738                         {
739                             rt_kprintf("Write data success. Start from 0x%08X, size is %ld.\n", addr, size);
740                             rt_kprintf("Write data: ");
741                             for (i = 0; i < size; i++)
742                             {
743                                 rt_kprintf("%d ", data[i]);
744                             }
745                             rt_kprintf(".\n");
746                         }
747                         rt_free(data);
748                     }
749                     else
750                     {
751                         rt_kprintf("Low memory!\n");
752                     }
753                 }
754             }
755             else if (!rt_strcmp(operator, "erase"))
756             {
757                 if (argc < 4)
758                 {
759                     rt_kprintf("Usage: %s.\n", help_info[CMD_ERASE_INDEX]);
760                     return;
761                 }
762                 else
763                 {
764                     addr = strtol(argv[2], NULL, 0);
765                     size = strtol(argv[3], NULL, 0);
766                     if (flash_dev)
767                     {
768                         result = flash_dev->ops.erase(addr, size);
769                     }
770                     else if (part_dev)
771                     {
772                         result = fal_partition_erase(part_dev, addr, size);
773                     }
774                     if (result >= 0)
775                     {
776                         rt_kprintf("Erase data success. Start from 0x%08X, size is %ld.\n", addr, size);
777                     }
778                 }
779             }
780             else if (!strcmp(operator, "bench"))
781             {
782                 if (argc < 3)
783                 {
784                     rt_kprintf("Usage: %s.\n", help_info[CMD_BENCH_INDEX]);
785                     return;
786                 }
787                 else if ((argc > 3 && strcmp(argv[3], "yes")) || argc < 4)
788                 {
789                     rt_kprintf("DANGER: It will erase full chip or partition! Please run 'fal bench %d yes'.\n", strtol(argv[2], NULL, 0));
790                     return;
791                 }
792                 /* full chip benchmark test */
793                 rt_uint32_t start_time, time_cast;
794                 rt_size_t write_size = strtol(argv[2], NULL, 0), read_size = strtol(argv[2], NULL, 0), cur_op_size;
795                 rt_uint8_t *write_data = (rt_uint8_t *)rt_malloc(write_size), *read_data = (rt_uint8_t *)rt_malloc(read_size);
796 
797                 if (write_data && read_data)
798                 {
799                     for (i = 0; i < write_size; i ++) {
800                         write_data[i] = i & 0xFF;
801                     }
802                     if (flash_dev)
803                     {
804                         size = flash_dev->len;
805                     }
806                     else if (part_dev)
807                     {
808                         size = part_dev->len;
809                     }
810                     /* benchmark testing */
811                     rt_kprintf("Erasing %ld bytes data, waiting...\n", size);
812                     start_time = rt_tick_get();
813                     if (flash_dev)
814                     {
815                         result = flash_dev->ops.erase(0, size);
816                     }
817                     else if (part_dev)
818                     {
819                         result = fal_partition_erase(part_dev, 0, size);
820                     }
821                     if (result >= 0)
822                     {
823                         time_cast = rt_tick_get() - start_time;
824                         rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
825                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
826                     }
827                     else
828                     {
829                         rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
830                     }
831                     /* write test */
832                     rt_kprintf("Writing %ld bytes data, waiting...\n", size);
833                     start_time = rt_tick_get();
834                     for (i = 0; i < size; i += write_size)
835                     {
836                         if (i + write_size <= size)
837                         {
838                             cur_op_size = write_size;
839                         }
840                         else
841                         {
842                             cur_op_size = size - i;
843                         }
844                         if (flash_dev)
845                         {
846                             result = flash_dev->ops.write(i, write_data, cur_op_size);
847                         }
848                         else if (part_dev)
849                         {
850                             result = fal_partition_write(part_dev, i, write_data, cur_op_size);
851                         }
852                         if (result < 0)
853                         {
854                             break;
855                         }
856                     }
857                     if (result >= 0)
858                     {
859                         time_cast = rt_tick_get() - start_time;
860                         rt_kprintf("Write benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
861                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
862                     }
863                     else
864                     {
865                         rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
866                     }
867                     /* read test */
868                     rt_kprintf("Reading %ld bytes data, waiting...\n", size);
869                     start_time = rt_tick_get();
870                     for (i = 0; i < size; i += read_size)
871                     {
872                         if (i + read_size <= size)
873                         {
874                             cur_op_size = read_size;
875                         }
876                         else
877                         {
878                             cur_op_size = size - i;
879                         }
880                         if (flash_dev)
881                         {
882                             result = flash_dev->ops.read(i, read_data, cur_op_size);
883                         }
884                         else if (part_dev)
885                         {
886                             result = fal_partition_read(part_dev, i, read_data, cur_op_size);
887                         }
888                         /* data check */
889                         for (rt_size_t index = 0; index < cur_op_size; index ++)
890                         {
891                             if (write_data[index] != read_data[index])
892                             {
893                                 rt_kprintf("%d %d %02x %02x.\n", i, index, write_data[index], read_data[index]);
894                             }
895                         }
896 
897                         if (memcmp(write_data, read_data, cur_op_size))
898                         {
899                             result = -RT_ERROR;
900                             rt_kprintf("Data check ERROR! Please check you flash by other command.\n");
901                         }
902                         /* has an error */
903                         if (result < 0)
904                         {
905                             break;
906                         }
907                     }
908                     if (result >= 0)
909                     {
910                         time_cast = rt_tick_get() - start_time;
911                         rt_kprintf("Read benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
912                                 time_cast % RT_TICK_PER_SECOND / ((RT_TICK_PER_SECOND * 1 + 999) / 1000));
913                     }
914                     else
915                     {
916                         rt_kprintf("Read benchmark has an error. Error code: %d.\n", result);
917                     }
918                 }
919                 else
920                 {
921                     rt_kprintf("Low memory!\n");
922                 }
923                 rt_free(write_data);
924                 rt_free(read_data);
925             }
926             else
927             {
928                 rt_kprintf("Usage:\n");
929                 for (i = 0; i < sizeof(help_info) / sizeof(char*); i++)
930                 {
931                     rt_kprintf("%s\n", help_info[i]);
932                 }
933                 rt_kprintf("\n");
934                 return;
935             }
936             if (result < 0) {
937                 rt_kprintf("This operate has an error. Error code: %d.\n", result);
938             }
939         }
940     }
941 }
942 MSH_CMD_EXPORT(fal, FAL (Flash Abstraction Layer) operate.);
943 
944 #endif /* defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) */
945