RT_Thread组件开发

一、文件系统

  • RT-Thread 文件系统结构图
    • 最顶层是一套面向嵌入式系统,专门优化过的设备虚拟文件系统 POSIX 文件接口
    • 中间层是各种文件系统的实现
      • 比如 ELM FatFS、RomFS、devfs、RamFS、Yaffs2、Uffs2、JFFS2 、NFS 等
    • 最底层是各类存储设备驱动
      • 初始化存储设备并向上层提供存储设备的驱动接口。存储设备的类型可能是 SPI Flash,SD卡 等
RT_Thread组件开发_第1张图片
image

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

    RT_Thread组件开发_第2张图片
    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 地址上。
      • 动态模块被系统加载到内存的

[图片上传失败...(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 
    #include 
    #include 
    #include 
    #include 
    
    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);

你可能感兴趣的:(RT_Thread组件开发)