一、文件系统
- RT-Thread 文件系统结构图
- 最顶层是一套面向嵌入式系统,专门优化过的设备虚拟文件系统 POSIX 文件接口
- 中间层是各种文件系统的实现
- 比如 ELM FatFS、RomFS、devfs、RamFS、Yaffs2、Uffs2、JFFS2 、NFS 等
- 最底层是各类存储设备驱动
- 初始化存储设备并向上层提供存储设备的驱动接口。存储设备的类型可能是 SPI Flash,SD卡 等
1.文件系统的移植
1)开启/配置 DFS 框架
-
进入menuconfig : RT-Thread Components → Device virtual file system
- [x] Using device virtual file system : 使用设备虚拟文件系统,即 RT-Thread 文件系统。
- [x] Using working directory : 打开这个选项,在 finsh/msh 中就可以使用基于当前工作目录的相对路径。
- [ ] The maximal number of mounted file system : 最大挂载文件系统的数量。
- [ ] The maximal number of file system type : 最大支持文件系统类型的数量。
- [ ] The maximal number of opened files : 打开文件的最大数量。
- [x] Enable elm-chan fatfs : 使用 elm-chan FatFs,用于挂载在spi flash等存储设备上。
- elm-chan's FatFs, Generic FAT Filesystem Module : elm-chan 文件系统的配置项。
- [x] Using devfs for device objects : 开启 devfs 文件系统。
- [ ] Enable BSD socket operated by file system API : 使 BSD socket 可以使用文件系统的 API 来管理,比如读写操作和 select/poll 的 POSIX API 调用。
- [x] Enable ReadOnly file system on flash : 在 Flash 上使用只读文件系统RomFS。
- [ ] Enable RAM file system : 使用 RAM 文件系统。
- [ ] Enable UFFS file system: Ultra-low-cost Flash File System :使用 UFFS。
- [ ] Enable JFFS2 file system : 使用 JFFS2 文件系统。
- [ ] Using NFS v3 client file system :使用 NFS 文件系统。
配置和指定文件系统
2)存储设备驱动初始化
根据所使用的储存设备,如 SPI Flash,SD卡,初始化其驱动
如:RT-Thread Components → Device Drivers 界面中选中 Using SPI Bus/Device device drivers 以及 Using Serial Flash Universal Driver 选项,
-
检查储存设备驱动
编译程序并下载到开发板上
list_device #查看是否识别到有spi 驱动 sf probe xxx #检测spi设备接口下是否有 spi flash sf bench yes #对存储设备进行测试
3)创建存储设备
由于只有块设备类型的设备才能和文件系统对接,所以需要根据 SPI Device 找到 SPI Flash 设备,并创建与其对应的 Block Device。
-
在drv_spi_flash.c文件中添加如下函数,注册块设备
static int rt_hw_spi_flash_with_sfud_init(void) { //使用spi50 设备接口注册W25Q256块设备 if (RT_NULL == rt_sfud_flash_probe("W25Q256", "spi50")) { return RT_ERROR; }; return RT_EOK; } INIT_COMPONENT_EXPORT(rt_hw_spi_flash_with_sfud_init);
-
重新编译下载程序,使用list_device命令可以找到W25Q256设备
2.文件系统使用
1)文件系统的初始化
- 初始化 DFS 框架
- 初始化文件系统必须的数据表,以及互斥锁
- 由dfs_init函数完成
- 初始化具体文件系统
- 将所选择的
elm FatFS
等文件系统的操作函数注册到 DFS 框架中 - 由elm_init等函数完成
- 将所选择的
- 初始化存储设备
2)在存储设备创建文件系统
存储设备上需要先创建相应的文件系统,才能挂载文件系统
当重启开发板直接挂载文件系统,就会看到 spi flash mount to /spi failed! 的提示,因为此时在 SPI Flash 中还没有创建相应类型的文件系统。
-
在存储设备上创建相应的文件系统
-
使用mkfs命令:mkfs [-t type] device
mkfs -t elm W25Q256 #文件系统创建完成后需要重启设备
-
3)挂载文件系统
文件系统的挂载指的是将文件系统和具体的存储设备关联起来,并挂载到某个挂载点,这个挂载点即为这个文件系统的根目录。
-
在rt_application_init函数初始化的线程中调用api函数挂载文件系统(如application.c的rt_init_thread_entry函数)
//挂载romfs到根目录/ if (dfs_mount(RT_NULL, "/", "rom", 0, &(romfs_root)) == 0) { rt_kprintf("ROM file system initializated!\n"); } //将elm FatFS文件系统与W25Q256设备关联,并挂载到/spi目录下 /* mount sd card fat partition 0 as root directory */ if (dfs_mount("W25Q256", "/spi", "elm", 0, 0) == 0) { rt_kprintf("spi flash mount to /spi !\n"); } else { rt_kprintf("spi flash mount to /spi failed!\n"); } //将elm FatFS文件系统与sd0设备关联,并挂载到/sdcard目录下 /* mount sd card fat partition 0 as root directory */ if (dfs_mount("sd0", "/sdcard", "elm", 0, 0) == 0) { rt_kprintf("sd card mount to /sdcard!\n"); } else { rt_kprintf("sd card mount to /sdcard failed!\n"); }
3.文件与目录操作 shell 命令
- 文件系统的操作命令在 RT-Thread online packages → miscellaneous packages → samples: kernel and components sample -> filesystem sample options中选择.
- 默认命令有ls、cd、cp、rm、mv、ifconfig、echo、cat、pwd、mkdir等
- 文件系统提供的 Sample 还有 openfile、readwrite、stat、rename、opendir、readdir 、 tell_seek_dir等命令
- 添加新的sample会在工程中添加新的文件夹
二、FinSH shell
finsh运行于开发板,它可以使用串口/以太网/USB等与PC机进行通信,提供一套供用户在命令行的操作接口。
finsh是一个C语言风格的Shell,在finsh shell中使用命令(即C语言中的函数),必须携带()符号,finsh命令的输出为此函数的返回值。
-
finsh支持两种模式:
-
C语言解释器模式,为行文方便称之为c-style;
#列举支持的命令 finsh >list() --Function List: pinMode -- set hardware pin mode pinWrite -- write value to hardware pin pinRead -- read status from hardware pin hello -- say hello world version -- show RT-Thread version information list_thread -- list thread list_sem -- list semaphore in system list_event -- list event in system list_mutex -- list mutex in system list_mailbox -- list mail box in system list_msgqueue -- list message queue in system list_memheap -- list memory heap in system list_mempool -- list memory pool in system list_timer -- list timer in system list_device -- list device in system list -- list all symbol in system msh -- use module shell --Variable List: dummy -- dummy variable for finsh
#测试命令格式 finsh >hello() finsh >version()
-
传统命令行模式,此模式又称为msh(module shell)。
#列举支持的命令 msh >help RT-Thread shell commands: reboot - Reboot System version - show RT-Thread version information list_thread - list thread list_sem - list semaphore in system list_event - list event in system list_mutex - list mutex in system list_mailbox - list mail box in system list_msgqueue - list message queue in system list_memheap - list memory heap in system list_mempool - list memory pool in system list_timer - list timer in system list_device - list device in system exit - return to RT-Thread shell mode. help - RT-Thread shell help. ps - List threads in the system. time - Execute command with time. free - Show the memory usage in the system.
#测试命令格式 msh >help msh >version
-
-
所以的finsh命令或msh命令都是在cmd.c文件中导出的
- finsh命令通过宏定义FINSH_FUNCTION_EXPORT导出
- msh命令通过宏定义MSH_CMD_EXPORT导出
三、动态模块
1.简介
-
dlmodule
则是 RT-Thread 下,在内核空间对外提供的动态模块加载机制的软件组件。-
dlmodule
组件更多的是一个 ELF 格式加载器,把单独编译的一个 elf 文件的代码段,数据段加载到内存
中,并对其中的符号进行解析,绑定到内核导出的 API 地址上。- 动态模块被系统加载到内存的
-
[图片上传失败...(image-dd0ae4-1563508716000)]
动态模块 elf 文件需要放置于 RT-Thread 下的文件系统上
-
RT-Thread 的动态模块支持两种格式:
-
.mo
动态模块;它可以被加载,并且系统中会自动创建一个主线程执行这个动态模块中的main
函数;同时这个main(int argc, char**argv)
函数也可以接受命令行上的参数。 -
.so
动态库;它可以被加载,并驻留在内存中,并提供一些函数集由其他程序(内核里的代码或动态模块)来使用。
-
2.编译固件
-
进入bsp库,执行:menuconfig ,选择
RT-Thread Components ---> POSIX layer and C standard library ---> [*] Enable dynamic module with dlopen/dlsym/dlclose feature RT-Thread Components ---> Device virtual file system ---> [*] Using device virtual file system
-
在编译文件rtconfig.py中添加动态模块编译时需要的配置参数
#CXXFLAGS = CFLAGS + ' -Woverloaded-virtual -fno-exceptions -fno-rtti' M_CFLAGS = CFLAGS + '-mlong-calls -fPIC' M_CXXFLAGS = CXXFLAGS + '-mlong-calls -fPIC' M_LFLAGS = DEVICE + CXXFLAGS + '-Wl,--gc-sections,-z,max-page-size=0x4' +\ '-shared -fPIC -nostartfiles -nostdlib -static-libgcc' M_POST_ACTION = STRIP + '-R .hash $TARGET\n' + SIZE + '$TARGET \n' M_BIN_PATH = r'E:\qemu-dev310\fatdisk\root'
-
在链接脚本xxx.ld中添加对应的信息
/* section information for modules */ . = ALIGN(4); __rtmsymtab_start = .; KEEP(*(RTMSymTab)) __rtmsymtab_end = .;
-
执行编译
scons #使用动态模块只能使用gcc编译 #生成编译动态模块时需要包括的内核头文件搜索路径及全局宏定义 scons --target=ua -s
3.编译动态模块
在 github 上有一份独立仓库: rtthread-apps ,这份仓库中放置了一些和动态模块。
目录名 | 说明 |
---|---|
cxx | 演示了如何在动态模块中使用 C++ 进行编程 |
hello | 最简单的 hello world 示例 |
lib | 动态库的示例 |
md5 | 为一个文件产生 md5 码 |
tools | 动态模块编译时需要使用到的 Python/SConscript 脚本 |
ymodem | 通过串口以 YModem 协议下载一个文件到文件系统上 |
- 执行编译
#指向到 RT-Thread 代码的根目录
set RTT_ROOT=E:\@Git_Depository\rt-thread
#指向到 BSP 的工程目录
set BSP_ROOT=E:\@Git_Depository\rt-thread\bsp\stm32f429-apollo #注意工程路径
#编译hello/动态模块
scons --app=hello
#编译lib/动态库
scons --lib=lib
编译成功会生成xxx.mo文件,将文件放置到rt-thread的文件系统上,就可以执行。
4.动态模块开发
在msh命令中输入list_symbol命令。可以看到内核符号表(kernel symbol table)所映射的函数,这些函数就是模块模块开发当前能使用的函数
msh /spi>list_module
module ref address
-------- -------- ------------
msh /spi>list_sy
list_symbols
msh /spi>list_symbols\
list_symbols\: command not found.
msh /spi>list_symbols
rt_tick_get => 0x0800c4e1
rt_tick_from_millisecond => 0x0800c53d
rt_device_register => 0x0800c6b1
rt_device_unregister => 0x0800c715
rt_device_find => 0x0800c781
rt_device_create => 0x0800c811
rt_device_destroy => 0x0800c85d
rt_device_open => 0x0800c941
rt_device_close => 0x0800ca5d
rt_device_read => 0x0800caf9
rt_device_write => 0x0800cb81
rt_device_control => 0x0800cc09
rt_device_set_rx_indicate => 0x0800cc71
rt_device_set_tx_complete => 0x0800ccc5
rt_sem_init => 0x0800d06d
rt_sem_detach => 0x0800d0d5
rt_sem_create => 0x0800d149
rt_sem_delete => 0x0800d1d9
rt_sem_take => 0x0800d285
rt_sem_trytake => 0x0800d3e5
rt_sem_release => 0x0800d401
rt_sem_control => 0x0800d4a1
rt_mutex_init => 0x0800d525
rt_mutex_detach => 0x0800d58d
rt_mutex_create => 0x0800d609
rt_mutex_delete => 0x0800d695
rt_mutex_take => 0x0800d741
rt_mutex_release => 0x0800d91d
rt_mutex_control => 0x0800dabd
rt_event_init => 0x0800db0d
rt_event_detach => 0x0800db61
rt_event_create => 0x0800dbdd
rt_event_delete => 0x0800dc51
rt_event_send => 0x0800dcfd
rt_event_recv => 0x0800de45
rt_event_control => 0x0800e041
rt_mb_init => 0x0800e0c1
rt_mb_detach => 0x0800e139
rt_mb_create => 0x0800e1bd
rt_mb_delete => 0x0800e279
rt_mb_send_wait => 0x0800e339
rt_mb_send => 0x0800e541
rt_mb_recv => 0x0800e561
rt_mb_control => 0x0800e795
rt_mq_init => 0x0800e829
rt_mq_detach => 0x0800e8e9
rt_mq_create => 0x0800e965
rt_mq_delete => 0x0800ea65
rt_mq_send => 0x0800eb1d
rt_mq_urgent => 0x0800ec71
rt_mq_recv => 0x0800edb5
rt_mq_control => 0x0800f001
rt_interrupt_enter => 0x0800f0b5
rt_interrupt_leave => 0x0800f0f5
rt_interrupt_get_nest => 0x0800f135
rt_hw_interrupt_disable => 0x080001ad
rt_hw_interrupt_enable => 0x080001b5
rt_get_errno => 0x0800f14d
rt_set_errno => 0x0800f185
_rt_errno => 0x0800f1c5
rt_memset => 0x0800f1f9
rt_memcpy => 0x0800f2b1
rt_memmove => 0x0800f385
rt_memcmp => 0x0800f409
rt_strstr => 0x0800f461
rt_strcasecmp => 0x0800f4c1
rt_strncpy => 0x0800f525
rt_strncmp => 0x0800f589
rt_strcmp => 0x0800f5d5
rt_strnlen => 0x0800f619
rt_strlen => 0x0800f659
rt_strdup => 0x0800f689
rt_show_version => 0x0800f6c5
rt_vsnprintf => 0x0800f98d
rt_snprintf => 0x0800fed5
rt_vsprintf => 0x0800ff05
rt_sprintf => 0x0800ff29
rt_console_get_device => 0x0800ff55
rt_console_set_device => 0x0800ff6d
rt_hw_console_output => 0x0800ffb9
rt_kprintf => 0x0800ffcd
rt_malloc_align => 0x0801004d
rt_free_align => 0x080100bd
rt_assert_handler => 0x0801014d
rt_malloc => 0x080103c5
rt_realloc => 0x08010659
rt_calloc => 0x080107f1
rt_free => 0x0801082d
rt_memheap_init => 0x080109f9
rt_memheap_detach => 0x08010b3d
rt_memheap_alloc => 0x08010bb1
rt_memheap_realloc => 0x08010da9
rt_memheap_free => 0x080110b9
rt_mp_init => 0x080112ed
rt_mp_detach => 0x080113bd
rt_mp_create => 0x08011469
rt_mp_delete => 0x08011575
rt_mp_alloc => 0x08011661
rt_mp_free => 0x080117bd
rt_object_get_information => 0x080118c1
rt_enter_critical => 0x08012099
rt_exit_critical => 0x080120c5
rt_critical_level => 0x08012119
rt_thread_init => 0x08012365
rt_thread_self => 0x080123d1
rt_thread_startup => 0x080123e9
rt_thread_detach => 0x08012489
rt_thread_create => 0x0801254d
rt_thread_delete => 0x080125b1
rt_thread_yield => 0x08012659
rt_thread_delay => 0x0801275d
rt_thread_mdelay => 0x08012775
rt_thread_control => 0x08012795
rt_thread_suspend => 0x08012869
rt_thread_resume => 0x08012911
rt_thread_timeout => 0x080129a9
rt_thread_find => 0x08012a2d
rt_timer_init => 0x08012c11
rt_timer_detach => 0x08012c59
rt_timer_create => 0x08012cd5
rt_timer_delete => 0x08012d15
rt_timer_start => 0x08012d95
rt_timer_stop => 0x08012f91
rt_timer_control => 0x08013025
dfs_subdir => 0x08013b11
dfs_normalize_path => 0x08013b61
open => 0x0801517d
close => 0x080151e9
read => 0x0801523d
write => 0x08015299
lseek => 0x080152f5
rename => 0x080153a9
unlink => 0x080153d9
stat => 0x08015405
fstat => 0x08015435
fsync => 0x080154ad
fcntl => 0x080154e9
ioctl => 0x08015555
statfs => 0x08015589
mkdir => 0x080155b9
rmdir => 0x08015631
opendir => 0x0801565d
readdir => 0x080156f5
telldir => 0x080157b1
seekdir => 0x080157fd
rewinddir => 0x08015851
closedir => 0x080158a5
chdir => 0x08015905
getcwd => 0x080159b1
system => 0x0801dce5
strcpy => 0x08046d3d
strncpy => 0x08046ec1
strlen => 0x080007c1
strcat => 0x08046c2d
strstr => 0x08047205
strchr => 0x08046c6d
strcmp => 0x080004e9
strtol => 0x08047581
strtoul => 0x08047739
strncmp => 0x08046e21
memcpy => 0x08000391
memcmp => 0x08045dc1
memmove => 0x08045e25
memset => 0x08045eed
memchr => 0x080002f1
putchar => 0x08046565
puts => 0x08046635
printf => 0x0804653d
sprintf => 0x08046b55
snprintf => 0x08046ab9
fwrite => 0x08045a51
localtime => 0x08045a71
time => 0x08023a15
longjmp => 0x080004d1
setjmp => 0x080004c5
exit => 0x0802398d
abort => 0x080239e1
rand => 0x08046645
__assert_func => 0x08045149
dlclose => 0x08023a89
dlerror => 0x08024951
dlmodule_find => 0x08025315
dlopen => 0x080253f5
dlsym => 0x080254bd
lwip_accept => 0x0802960d
lwip_bind => 0x080298a5
lwip_shutdown => 0x0802abb1
lwip_getpeername => 0x0802adc9
lwip_getsockname => 0x0802aded
lwip_getsockopt => 0x0802ae11
lwip_setsockopt => 0x0802b369
lwip_close => 0x080299a1
lwip_connect => 0x08029a55
lwip_listen => 0x08029b71
lwip_recv => 0x08029fe9
lwip_read => 0x08029fbd
lwip_recvfrom => 0x08029c3d
lwip_send => 0x0802a015
lwip_sendto => 0x0802a0e1
lwip_socket => 0x0802a251
lwip_write => 0x0802a309
lwip_select => 0x0802a5c9
lwip_ioctl => 0x0802b791
lwip_fcntl => 0x0802b911
lwip_htons => 0x0802bd4d
lwip_htonl => 0x0802bd69
lwip_gethostbyname => 0x08028e39
lwip_gethostbyname_r => 0x08028ed1
lwip_freeaddrinfo => 0x08028fd1
lwip_getaddrinfo => 0x08028ffd
dhcp_start => 0x08036c49
dhcp_renew => 0x080371d9
dhcp_stop => 0x08037629
netifapi_netif_set_addr => 0x08029329
netif_set_link_callback => 0x0802d879
netif_set_status_callback => 0x0802d791
netif_find => 0x0802d4a9
netif_set_addr => 0x0802d451
netif_set_ipaddr => 0x0802d519
netif_set_gw => 0x0802d5bd
netif_set_netmask => 0x0802d5f5
gethostbyname => 0x0803cf21
gethostbyname_r => 0x0803cf39
freeaddrinfo => 0x0803cf65
getaddrinfo => 0x0803cf7d
accept => 0x0803d315
bind => 0x0803d3c9
shutdown => 0x0803d3f1
getpeername => 0x0803d475
getsockname => 0x0803d49d
getsockopt => 0x0803d4c5
setsockopt => 0x0803d4f5
connect => 0x0803d525
listen => 0x0803d54d
recv => 0x0803d571
recvfrom => 0x0803d5a5
send => 0x0803d5d9
sendto => 0x0803d60d
socket => 0x0803d641
closesocket => 0x0803d6d9
ioctlsocket => 0x0803d759
rt_completion_init => 0x08042df9
rt_completion_wait => 0x08042e3d
rt_completion_done => 0x08042f39
rt_data_queue_init => 0x08043025
rt_data_queue_push => 0x080430a9
rt_data_queue_pop => 0x08043239
rt_data_queue_peak => 0x0804341d
rt_data_queue_reset => 0x080434b9
rt_rbb_init => 0x08043691
rt_rbb_create => 0x08043731
rt_rbb_destroy => 0x080437ad
rt_rbb_blk_alloc => 0x08043859
rt_rbb_blk_put => 0x08043a59
rt_rbb_blk_get => 0x08043a9d
rt_rbb_blk_size => 0x08043b25
rt_rbb_blk_buf => 0x08043b59
rt_rbb_blk_free => 0x08043b89
rt_rbb_blk_queue_get => 0x08043c09
rt_rbb_blk_queue_len => 0x08043d21
rt_rbb_blk_queue_buf => 0x08043d85
rt_rbb_blk_queue_free => 0x08043db5
rt_rbb_next_blk_queue_len => 0x08043e25
rt_rbb_get_buf_size => 0x08043edd
rt_ringbuffer_init => 0x08043f5d
rt_ringbuffer_put => 0x08044001
rt_ringbuffer_put_force => 0x0804416d
rt_ringbuffer_get => 0x0804433d
rt_ringbuffer_putchar => 0x08044499
rt_ringbuffer_putchar_force => 0x08044551
rt_ringbuffer_getchar => 0x0804464d
rt_ringbuffer_data_len => 0x08044701
rt_ringbuffer_reset => 0x08044785
rt_ringbuffer_create => 0x080447d9
rt_ringbuffer_destroy => 0x0804484d
上述函数主要来自于rt-thread/src/xx.c文件、rt-thread/components/使用的组件xxx/src/xx.c文件
1)导出函数到内核符号表
通过宏定义RTM_EXPORT(symbol) ,可以将函数导出到符号表。
RTM_EXPORT(rt_timer_control);
2)动态模块操作片级资源
-
操作gpio
- rt-thread\components\drivers\misc\pin.c默认没有把rt_pin_mode、rt_pin_write、rt_pin_read等函数添加到符号表,需要人为添加
- STM32F429-apollo是基于STM32F4xx_PIN_NUMBERS == 176的芯片,参考rt-thread\bsp\stm32f429-apollo\drivers\drv_gpio.c的pins[]数组,PB.0和PB.1分别对应index 56和57。
#include <stdio.h> #include <board.h> #include <rtthread.h> #include <rtdevice.h> #include <rthw.h> int main(int argc, char *argv[]) { rt_pin_mode(56, PIN_MODE_OUTPUT); printf("Hello, world1\n"); while (1) { rt_pin_write(56, PIN_HIGH); rt_thread_mdelay(2000); rt_pin_write(56, PIN_LOW); rt_thread_mdelay(2000); } return 0; }
- rt-thread\components\drivers\misc\pin.c默认没有把rt_pin_mode、rt_pin_write、rt_pin_read等函数添加到符号表,需要人为添加
5.对动态模块的操作
1)动态模块的结构体
rt_dlmodule结构体
struct rt_dlmodule
{
struct rt_object parent;
rt_list_t object_list; /* objects inside this module */
rt_uint8_t stat; /* status of module */ //动态模块的状态
/* main thread of this module */
rt_uint16_t priority;
rt_uint32_t stack_size;
struct rt_thread *main_thread;
/* the return code */
int ret_code;
/* VMA base address for the first LOAD segment */
rt_uint32_t vstart_addr;
/* module entry, RT_NULL for dynamic library */
rt_dlmodule_entry_func_t entry_addr;
char *cmd_line; /* command line */
rt_addr_t mem_space; /* memory space */
rt_uint32_t mem_size; /* sizeof memory space */
/* init and clean function */
rt_dlmodule_init_func_t init_func;
rt_dlmodule_cleanup_func_t cleanup_func;
rt_uint16_t nref; /* reference count */
rt_uint16_t nsym; /* number of symbols in the module */
struct rt_module_symtab *symtab; /* module symbol table */
};
2)动态模块API
动态模块API函数在rt-thread\components\libc\libdl\dlmodule.c文件中定义。
#include "dlmodule.h"
//加载动态模块
struct rt_dlmodule *dlmodule_load(const char* pgname);
//执行动态模块
struct rt_dlmodule *dlmodule_exec(const char* pgname, const char* cmd, int cmd_size);
//退出动态模块
void dlmodule_exit(int ret_code);
//查找动态模块
struct rt_dlmodule *dlmodule_find(const char *name);
//返回动态模块:返回调用上下文环境下动态模块的指针
struct rt_dlmodule *dlmodule_self(void);
//查找符号
rt_uint32_t dlmodule_symbol_find(const char *sym_str);
- 在keil工程中是不会添加dlmodule.c的,但是在gcc工程中已经包含其路径。
停止动态模块
rt_err_t dlmodule(uint8_t argc, char **argv)
{
rt_err_t res = 0;
struct rt_dlmodule *module;
if (argc != 2) {
rt_kprintf("uasge:dlmodule name\n");
return 0;
}
module = dlmodule_find(argv[1]);
if ( module != RT_NULL) {
//close dlmodule
module->stat = RT_DLMODULE_STAT_CLOSING;
rt_timer_stop(&(module->main_thread->thread_timer));
res = rt_thread_delete(module->main_thread);
} else {
rt_kprintf("dlmodule find fail\n");
}
return res;
}
MSH_CMD_EXPORT(dlmodule, find dlmodule symbol);