一、文件系统

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设备

image

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 地址上。

动态模块被系统加载到内存的

动态模块 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;

}

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);