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