diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 2b57a00bdf..697ce412d9 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -50,7 +50,7 @@ jobs: - name: generate doxygen html shell: bash run: | - cd documentation/doxygen + cd documentation doxygen Doxyfile cat Doxyfile @@ -58,7 +58,7 @@ jobs: id: deployment uses: actions/upload-pages-artifact@main # or specific "vX.X.X" version tag for this action with: - path: documentation/doxygen/html/ + path: documentation/html/ deploy: if: github.event_name == 'push' diff --git a/README.md b/README.md index f0e7d25093..45e88cb177 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Based on [STM32F103 BluePill](https://github.com/RT-Thread/rt-thread/tree/master ## Simulator RT-Thread BSP can be compiled directly and downloaded to the corresponding development board for use. In addition, RT-Thread also provides qemu-vexpress-a9 BSP, which can be used without hardware platform. See the getting started guide below for details. Getting Started of QEMU with Env: -[Windows](documentation/quick-start/quick_start_qemu/quick_start_qemu.md) | [Linux Ubuntu](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md) +[Windows](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md) | [Linux Ubuntu](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md) # License diff --git a/README_de.md b/README_de.md index d4b3477e10..57211f87c9 100644 --- a/README_de.md +++ b/README_de.md @@ -122,7 +122,7 @@ Basierend auf [STM32F103 BluePill](https://github.com/RT-Thread/rt-thread/tree/m ## Simulator Das RT-Thread BSP kann direkt kompiliert und zur Verwendung auf das entsprechende Entwicklungsboard heruntergeladen werden. Darüber hinaus bietet RT-Thread auch das qemu-vexpress-a9 BSP, das ohne Hardware-Plattform verwendet werden kann. Weitere Informationen finden Sie in der Anleitung für die ersten Schritte unten. -[Windows](documentation/quick-start/quick_start_qemu/quick_start_qemu.md) | [Linux Ubuntu](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md) +[Windows](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md) | [Linux Ubuntu](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md) # Lizenz diff --git a/README_es.md b/README_es.md index 8e723b692e..a75173132b 100644 --- a/README_es.md +++ b/README_es.md @@ -121,7 +121,7 @@ Basado en [STM32F103 BluePill](https://github.com/RT-Thread/rt-thread/tree/maste ## Simulator -El BSP de RT-Thread puede compilarse directamente y descargarse en la placa de desarrollo correspondiente para su uso. Además, RT-Thread también proporciona el BSP qemu-vexpress-a9, que puede utilizarse sin plataforma de hardware. Consulte la guía de inicio más abajo para más detalles. [Windows](documentation/quick-start/quick_start_qemu/quick_start_qemu.md) | [Linux Ubuntu](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md) +El BSP de RT-Thread puede compilarse directamente y descargarse en la placa de desarrollo correspondiente para su uso. Además, RT-Thread también proporciona el BSP qemu-vexpress-a9, que puede utilizarse sin plataforma de hardware. Consulte la guía de inicio más abajo para más detalles. [Windows](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md) | [Linux Ubuntu](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md) | [Mac OS](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md) # Licencia diff --git a/README_zh.md b/README_zh.md index f19821edac..cba276f41f 100644 --- a/README_zh.md +++ b/README_zh.md @@ -124,9 +124,9 @@ RT-Thread Studio演示: RT-Thread BSP可以直接编译并下载到相应的开发板使用。此外,RT-Thread还提供 qemu-vexpress-a9 BSP,无需硬件平台即可使用。有关详细信息,请参阅下面的入门指南。 -[QEMU 入门指南(Windows)](documentation/quick-start/quick_start_qemu/quick_start_qemu.md) +[QEMU 入门指南(Windows)](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md) -[QEMU 入门指南(Ubuntu)](documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md) +[QEMU 入门指南(Ubuntu)](documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md) ## 文档 diff --git a/documentation/doxygen/basicdef.h b/documentation/0.doxygen/basicdef.h similarity index 100% rename from documentation/doxygen/basicdef.h rename to documentation/0.doxygen/basicdef.h diff --git a/documentation/doxygen/filesystem.h b/documentation/0.doxygen/filesystem.h similarity index 100% rename from documentation/doxygen/filesystem.h rename to documentation/0.doxygen/filesystem.h diff --git a/documentation/doxygen/finsh.h b/documentation/0.doxygen/finsh.h similarity index 100% rename from documentation/doxygen/finsh.h rename to documentation/0.doxygen/finsh.h diff --git a/documentation/doxygen/hardware.h b/documentation/0.doxygen/hardware.h similarity index 100% rename from documentation/doxygen/hardware.h rename to documentation/0.doxygen/hardware.h diff --git a/documentation/doxygen/images/Kernel_Object.png b/documentation/0.doxygen/images/Kernel_Object.png similarity index 100% rename from documentation/doxygen/images/Kernel_Object.png rename to documentation/0.doxygen/images/Kernel_Object.png diff --git a/documentation/doxygen/images/System_Arch.png b/documentation/0.doxygen/images/System_Arch.png similarity index 100% rename from documentation/doxygen/images/System_Arch.png rename to documentation/0.doxygen/images/System_Arch.png diff --git a/documentation/doxygen/images/Thread_Scheduler.png b/documentation/0.doxygen/images/Thread_Scheduler.png similarity index 100% rename from documentation/doxygen/images/Thread_Scheduler.png rename to documentation/0.doxygen/images/Thread_Scheduler.png diff --git a/documentation/doxygen/images/dfs.png b/documentation/0.doxygen/images/dfs.png similarity index 100% rename from documentation/doxygen/images/dfs.png rename to documentation/0.doxygen/images/dfs.png diff --git a/documentation/doxygen/images/finsh.png b/documentation/0.doxygen/images/finsh.png similarity index 100% rename from documentation/doxygen/images/finsh.png rename to documentation/0.doxygen/images/finsh.png diff --git a/documentation/doxygen/images/rtthread_logo.png b/documentation/0.doxygen/images/rtthread_logo.png similarity index 100% rename from documentation/doxygen/images/rtthread_logo.png rename to documentation/0.doxygen/images/rtthread_logo.png diff --git a/documentation/doxygen/kernel.h b/documentation/0.doxygen/kernel.h similarity index 100% rename from documentation/doxygen/kernel.h rename to documentation/0.doxygen/kernel.h diff --git a/documentation/doxygen/mainpage.h b/documentation/0.doxygen/mainpage.h similarity index 100% rename from documentation/doxygen/mainpage.h rename to documentation/0.doxygen/mainpage.h diff --git a/documentation/doxygen/module.h b/documentation/0.doxygen/module.h similarity index 100% rename from documentation/doxygen/module.h rename to documentation/0.doxygen/module.h diff --git a/documentation/doxygen/systeminit.h b/documentation/0.doxygen/systeminit.h similarity index 100% rename from documentation/doxygen/systeminit.h rename to documentation/0.doxygen/systeminit.h diff --git a/documentation/doxygen/thread.h b/documentation/0.doxygen/thread.h similarity index 100% rename from documentation/doxygen/thread.h rename to documentation/0.doxygen/thread.h diff --git a/documentation/introduction/figures/02Software_framework_diagram.png b/documentation/1.introduction/figures/02Software_framework_diagram.png similarity index 100% rename from documentation/introduction/figures/02Software_framework_diagram.png rename to documentation/1.introduction/figures/02Software_framework_diagram.png diff --git a/documentation/introduction/introduction.md b/documentation/1.introduction/introduction.md similarity index 98% rename from documentation/introduction/introduction.md rename to documentation/1.introduction/introduction.md index 1ba59bbb09..9d3dcc754b 100644 --- a/documentation/introduction/introduction.md +++ b/documentation/1.introduction/introduction.md @@ -1,8 +1,8 @@ -# RT-Thread Introduction +@page introduction Introduction As a beginner of Real-time Operating Systems (RTOS), you might be new to RT-Thread. However, with a better understanding of it over time, you will gradually discover the charm of RT-Thread and its advantages over other RTOSs of the same type. RT-Thread is an RTOS. With over 16 years of experience accumulated, along with the rise of the Internet of Things (IoT), it is evolving into a powerful, component-rich IoT operating system. -## RT-Thread Overview +# RT-Thread Overview RT-Thread, short for Real Time-Thread, is an embedded real-time multi-threaded operating system. One of its main purposes is to support multi-tasking. Allowing multiple tasks to run simultaneously does not mean that the processor actually performs multiple tasks at the same time - a processor core can only run one task at a time. Every task is executed quickly, and through the task scheduler which determines the sequence according to priority, the tasks are switched rapidly, giving the illusion that multiple tasks are running at the same time. In the RT-Thread system, tasks are implemented by threads, and scheduled by the task scheduler. @@ -10,11 +10,11 @@ RT-Thread is mainly written in the C programming language, making it easy to und Compared with the Linux operating system, RT-Thread is small in size, low in cost, low in power consumption and fast in startup. In addition, RT-Thread is highly responsible, with low resource usage, which is ideally suitable for various resource constraints such as cost, power consumption, etc. Although the 32-bit MCU is its main operating platform, other CPUs, such as ones with MMU, ones based on ARM9, ARM11 and even the Cortex-A series CPUs are suitable for RT-Thread in specific applications. -## License Agreement +# License Agreement The RT-Thread system is a completely open source system, which follows the Apache License 2.0 open source license agreement. The RT-Thread system can be used free of charge in commercial products and does not require opening private code up to the public. -## RT-Thread Frame +# RT-Thread Frame In recent years, the concept of the Internet of Things has become widely known, and the IoT market has developed rapidly. The networking of embedded devices is the trend of the times. Terminal networking has greatly increased the complexity of software, and traditional RTOS kernels can hardly meet the needs of the market. For this reason, the concept of the Internet of Things Operating System (IoT OS) came into being. **IoT operating system refers to the software platform that is based on operating system kernel (like RTOS, Linux, etc.) and includes relatively complete middleware components such as a file system, graphics library, etc. It has low overhead and high security, abides by the Communication Protocol and is capable of connecting to the cloud.** RT-Thread is an IoT OS. diff --git a/documentation/quick-start/figures/10.png b/documentation/2.quick-start/figures/10.png similarity index 100% rename from documentation/quick-start/figures/10.png rename to documentation/2.quick-start/figures/10.png diff --git a/documentation/quick-start/figures/11.png b/documentation/2.quick-start/figures/11.png similarity index 100% rename from documentation/quick-start/figures/11.png rename to documentation/2.quick-start/figures/11.png diff --git a/documentation/quick-start/figures/14.png b/documentation/2.quick-start/figures/14.png similarity index 100% rename from documentation/quick-start/figures/14.png rename to documentation/2.quick-start/figures/14.png diff --git a/documentation/quick-start/figures/5.png b/documentation/2.quick-start/figures/5.png similarity index 100% rename from documentation/quick-start/figures/5.png rename to documentation/2.quick-start/figures/5.png diff --git a/documentation/quick-start/figures/6.png b/documentation/2.quick-start/figures/6.png similarity index 100% rename from documentation/quick-start/figures/6.png rename to documentation/2.quick-start/figures/6.png diff --git a/documentation/quick-start/figures/7.png b/documentation/2.quick-start/figures/7.png similarity index 100% rename from documentation/quick-start/figures/7.png rename to documentation/2.quick-start/figures/7.png diff --git a/documentation/quick-start/figures/8.png b/documentation/2.quick-start/figures/8.png similarity index 100% rename from documentation/quick-start/figures/8.png rename to documentation/2.quick-start/figures/8.png diff --git a/documentation/quick-start/figures/9.png b/documentation/2.quick-start/figures/9.png similarity index 100% rename from documentation/quick-start/figures/9.png rename to documentation/2.quick-start/figures/9.png diff --git a/documentation/quick-start/figures/compile.jpg b/documentation/2.quick-start/figures/compile.jpg similarity index 100% rename from documentation/quick-start/figures/compile.jpg rename to documentation/2.quick-start/figures/compile.jpg diff --git a/documentation/quick-start/figures/debug.jpg b/documentation/2.quick-start/figures/debug.jpg similarity index 100% rename from documentation/quick-start/figures/debug.jpg rename to documentation/2.quick-start/figures/debug.jpg diff --git a/documentation/quick-start/keil-installation/figures/1.png b/documentation/2.quick-start/keil-installation/figures/1.png similarity index 100% rename from documentation/quick-start/keil-installation/figures/1.png rename to documentation/2.quick-start/keil-installation/figures/1.png diff --git a/documentation/quick-start/keil-installation/figures/12.png b/documentation/2.quick-start/keil-installation/figures/12.png similarity index 100% rename from documentation/quick-start/keil-installation/figures/12.png rename to documentation/2.quick-start/keil-installation/figures/12.png diff --git a/documentation/quick-start/keil-installation/figures/13.png b/documentation/2.quick-start/keil-installation/figures/13.png similarity index 100% rename from documentation/quick-start/keil-installation/figures/13.png rename to documentation/2.quick-start/keil-installation/figures/13.png diff --git a/documentation/quick-start/keil-installation/figures/2.png b/documentation/2.quick-start/keil-installation/figures/2.png similarity index 100% rename from documentation/quick-start/keil-installation/figures/2.png rename to documentation/2.quick-start/keil-installation/figures/2.png diff --git a/documentation/quick-start/keil-installation/figures/3.png b/documentation/2.quick-start/keil-installation/figures/3.png similarity index 100% rename from documentation/quick-start/keil-installation/figures/3.png rename to documentation/2.quick-start/keil-installation/figures/3.png diff --git a/documentation/quick-start/keil-installation/figures/4.png b/documentation/2.quick-start/keil-installation/figures/4.png similarity index 100% rename from documentation/quick-start/keil-installation/figures/4.png rename to documentation/2.quick-start/keil-installation/figures/4.png diff --git a/documentation/quick-start/keil-installation/keil-installation.md b/documentation/2.quick-start/keil-installation/keil-installation.md similarity index 98% rename from documentation/quick-start/keil-installation/keil-installation.md rename to documentation/2.quick-start/keil-installation/keil-installation.md index 9eb6ad32ac..951f360ed9 100644 --- a/documentation/quick-start/keil-installation/keil-installation.md +++ b/documentation/2.quick-start/keil-installation/keil-installation.md @@ -1,4 +1,4 @@ -# Keil MDK Installation +@page quickstart_keil Keil MDK Installation Before running the RT-Thread operating system, we need to install MDK-ARM 5.24 (either official or evaluation version, version 5.14 and above), this version is also a relatively new version. This version can provide relatively complete debugging functions. Here, we are using evaluation version 5.24 of 16k compiled code limit. If you want to remove the 16k compiled code limit, please purchase the official MDK-ARM. diff --git a/documentation/quick-start/quick-start.md b/documentation/2.quick-start/quick-start.md similarity index 97% rename from documentation/quick-start/quick-start.md rename to documentation/2.quick-start/quick-start.md index ea8a4154d1..88a46ea5b8 100644 --- a/documentation/quick-start/quick-start.md +++ b/documentation/2.quick-start/quick-start.md @@ -1,4 +1,4 @@ -# Start Guide: Simulate STM32F103 on Keil Simulator +@page quick_start Start Guide Because of its particularity, the embedded operating system is often closely related to the hardware platform, and specific embedded operating systems can only run on specific hardware. For those who might not have an RT-Thread compatible hardware module, or want to test out their ideas, a complete RT-Thread system can be developed in the simulation environment MDK-ARM. @@ -8,11 +8,11 @@ Because of its full STM32F103 software simulation environment, the MDK-ARM integ What will follow is a demonstration of RT-Thread running on a simulated STM32F103 microcontroller through MDK-ARM. -## Preparation +# Preparation -MDK development environment: MDK-ARM 5.24 (official or evaluation version, version 5.14 and above) needs to be installed. This version is a relatively new version, which can provide relatively complete debugging functions. An installation guide can be found here: [Keil MDK Installation](./keil-installation/keil-installation.md). +MDK development environment: MDK-ARM 5.24 (official or evaluation version, version 5.14 and above) needs to be installed. This version is a relatively new version, which can provide relatively complete debugging functions. An installation guide can be found here: @subpage quickstart_keil. -## First acquaintance with RT-Thread +# First acquaintance with RT-Thread To see the code size of RT-Thread we first need to get an example of RT-Thread that is suited for this environment, which can be obtained from the following link: @@ -69,7 +69,7 @@ After compiling RT-Thread/STM32, we can simulate running RT-Thread through the M ![simulate RT-Thread2](./figures/6.png) -## User Entry Code +# User Entry Code The above startup code is related to the RT-Thread system, so how do users add initialization code for their own applications? RT-Thread uses main function as the user code entry, all you need to do is just add your own code to the main function. @@ -83,7 +83,7 @@ int main(void) >Note: In order to complete the initialization for the system functions before entering the main program, you can use the `$sub$$` and `$super$$` function identifiers to call another sample before entering the main program, this was, users can ignore the initialization operations before the main() function. See [ARM® Compiler v5.06 for µVision® armlink User Guide](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0377g/pge1362065967698.html) for details. -## Example of a Marquee +# Example of a Marquee For technical engineers working on electronics, marquee is probably the simplest example, the equivalent of Hello World in every programming language programmers learn. So we will start with a marquee in the following example, to make it periodically update (turn on or off) the LED. @@ -123,13 +123,13 @@ int led(void) MSH_CMD_EXPORT(led, RT-Thread first led sample); ``` -## Other Examples +# Other Examples Additional kernel examples can be found in the kernel-sample-0.1.0 directory. ![more kernel samples](./figures/14.png) -## Frequently Asked Question +# Frequently Asked Question * Compilation error occurred as following: diff --git a/documentation/quick-start/quick_start_qemu/figures/echo-cat.png b/documentation/2.quick-start/quick_start_qemu/figures/echo-cat.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/echo-cat.png rename to documentation/2.quick-start/quick_start_qemu/figures/echo-cat.png diff --git a/documentation/quick-start/quick_start_qemu/figures/env.png b/documentation/2.quick-start/quick_start_qemu/figures/env.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/env.png rename to documentation/2.quick-start/quick_start_qemu/figures/env.png diff --git a/documentation/quick-start/quick_start_qemu/figures/env_menu.png b/documentation/2.quick-start/quick_start_qemu/figures/env_menu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/env_menu.png rename to documentation/2.quick-start/quick_start_qemu/figures/env_menu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/env_menu_ubuntu.png b/documentation/2.quick-start/quick_start_qemu/figures/env_menu_ubuntu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/env_menu_ubuntu.png rename to documentation/2.quick-start/quick_start_qemu/figures/env_menu_ubuntu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/finsh-cmd.png b/documentation/2.quick-start/quick_start_qemu/figures/finsh-cmd.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/finsh-cmd.png rename to documentation/2.quick-start/quick_start_qemu/figures/finsh-cmd.png diff --git a/documentation/quick-start/quick_start_qemu/figures/finsh-thread.png b/documentation/2.quick-start/quick_start_qemu/figures/finsh-thread.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/finsh-thread.png rename to documentation/2.quick-start/quick_start_qemu/figures/finsh-thread.png diff --git a/documentation/quick-start/quick_start_qemu/figures/gnu-arm.png b/documentation/2.quick-start/quick_start_qemu/figures/gnu-arm.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/gnu-arm.png rename to documentation/2.quick-start/quick_start_qemu/figures/gnu-arm.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-env-menu.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-env-menu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-env-menu.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-env-menu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-filesys.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-filesys.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-filesys.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-filesys.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-mkfs-sd0.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-mkfs-sd0.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-mkfs-sd0.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-mkfs-sd0.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-msh-help.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-msh-help.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-msh-help.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-msh-help.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-pkgs-add-to-menu.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-pkgs-add-to-menu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-pkgs-add-to-menu.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-pkgs-add-to-menu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-qemu-bsp.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-qemu-bsp.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-qemu-bsp.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-qemu-bsp.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-qemu-sh.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-qemu-sh.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-qemu-sh.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-qemu-sh.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-save.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-save.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-save.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-save.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-select-pkg.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-select-pkg.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-select-pkg.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-select-pkg.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-thread-timer.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-thread-timer.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-thread-timer.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-thread-timer.png diff --git a/documentation/quick-start/quick_start_qemu/figures/macos-update-pkg.png b/documentation/2.quick-start/quick_start_qemu/figures/macos-update-pkg.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/macos-update-pkg.png rename to documentation/2.quick-start/quick_start_qemu/figures/macos-update-pkg.png diff --git a/documentation/quick-start/quick_start_qemu/figures/menuconfig.png b/documentation/2.quick-start/quick_start_qemu/figures/menuconfig.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/menuconfig.png rename to documentation/2.quick-start/quick_start_qemu/figures/menuconfig.png diff --git a/documentation/quick-start/quick_start_qemu/figures/menuconfig_menu.png b/documentation/2.quick-start/quick_start_qemu/figures/menuconfig_menu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/menuconfig_menu.png rename to documentation/2.quick-start/quick_start_qemu/figures/menuconfig_menu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/mkfs-sd0.png b/documentation/2.quick-start/quick_start_qemu/figures/mkfs-sd0.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/mkfs-sd0.png rename to documentation/2.quick-start/quick_start_qemu/figures/mkfs-sd0.png diff --git a/documentation/quick-start/quick_start_qemu/figures/python3-version.png b/documentation/2.quick-start/quick_start_qemu/figures/python3-version.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/python3-version.png rename to documentation/2.quick-start/quick_start_qemu/figures/python3-version.png diff --git a/documentation/quick-start/quick_start_qemu/figures/qemu.bat.png b/documentation/2.quick-start/quick_start_qemu/figures/qemu.bat.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/qemu.bat.png rename to documentation/2.quick-start/quick_start_qemu/figures/qemu.bat.png diff --git a/documentation/quick-start/quick_start_qemu/figures/qemu.png b/documentation/2.quick-start/quick_start_qemu/figures/qemu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/qemu.png rename to documentation/2.quick-start/quick_start_qemu/figures/qemu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/qemubsp.png b/documentation/2.quick-start/quick_start_qemu/figures/qemubsp.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/qemubsp.png rename to documentation/2.quick-start/quick_start_qemu/figures/qemubsp.png diff --git a/documentation/quick-start/quick_start_qemu/figures/scons.png b/documentation/2.quick-start/quick_start_qemu/figures/scons.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/scons.png rename to documentation/2.quick-start/quick_start_qemu/figures/scons.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-env-menu.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-env-menu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-env-menu.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-env-menu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-filesys.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-filesys.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-filesys.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-filesys.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-menuconfig.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-menuconfig.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-menuconfig.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-menuconfig.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-mkfs-sd0.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-mkfs-sd0.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-mkfs-sd0.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-mkfs-sd0.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-msh-help.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-msh-help.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-msh-help.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-msh-help.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-pkg-menuconfig.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-pkg-menuconfig.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-pkg-menuconfig.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-pkg-menuconfig.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-pkg-set.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-pkg-set.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-pkg-set.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-pkg-set.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-pkgs-add-to-menu.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-pkgs-add-to-menu.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-pkgs-add-to-menu.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-pkgs-add-to-menu.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-qemu-bsp.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-qemu-bsp.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-qemu-bsp.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-qemu-bsp.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-qume-sh.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-qume-sh.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-qume-sh.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-qume-sh.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-rtconfig-py.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-rtconfig-py.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-rtconfig-py.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-rtconfig-py.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-save.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-save.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-save.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-save.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-scons.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-scons.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-scons.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-scons.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-select-pkg.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-select-pkg.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-select-pkg.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-select-pkg.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-thread-timer.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-thread-timer.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-thread-timer.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-thread-timer.png diff --git a/documentation/quick-start/quick_start_qemu/figures/ubuntu-update-pkg.png b/documentation/2.quick-start/quick_start_qemu/figures/ubuntu-update-pkg.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/ubuntu-update-pkg.png rename to documentation/2.quick-start/quick_start_qemu/figures/ubuntu-update-pkg.png diff --git a/documentation/quick-start/quick_start_qemu/figures/win-menuconfig.png b/documentation/2.quick-start/quick_start_qemu/figures/win-menuconfig.png similarity index 100% rename from documentation/quick-start/quick_start_qemu/figures/win-menuconfig.png rename to documentation/2.quick-start/quick_start_qemu/figures/win-menuconfig.png diff --git a/documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md b/documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md similarity index 100% rename from documentation/quick-start/quick_start_qemu/quick_start_qemu_linux.md rename to documentation/2.quick-start/quick_start_qemu/quick_start_qemu_linux.md diff --git a/documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md b/documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md similarity index 100% rename from documentation/quick-start/quick_start_qemu/quick_start_qemu_macos.md rename to documentation/2.quick-start/quick_start_qemu/quick_start_qemu_macos.md diff --git a/documentation/quick-start/quick_start_qemu/quick_start_qemu_windows.md b/documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md similarity index 100% rename from documentation/quick-start/quick_start_qemu/quick_start_qemu_windows.md rename to documentation/2.quick-start/quick_start_qemu/quick_start_qemu_windows.md diff --git a/documentation/quick-start/rtthread_simulator_v0.1.0.7z b/documentation/2.quick-start/rtthread_simulator_v0.1.0.7z similarity index 100% rename from documentation/quick-start/rtthread_simulator_v0.1.0.7z rename to documentation/2.quick-start/rtthread_simulator_v0.1.0.7z diff --git a/documentation/quick-start/rtthread_simulator_v0.1.0.zip b/documentation/2.quick-start/rtthread_simulator_v0.1.0.zip similarity index 100% rename from documentation/quick-start/rtthread_simulator_v0.1.0.zip rename to documentation/2.quick-start/rtthread_simulator_v0.1.0.zip diff --git a/documentation/3.kernel/INDEX.md b/documentation/3.kernel/INDEX.md new file mode 100644 index 0000000000..6aeddfa6b8 --- /dev/null +++ b/documentation/3.kernel/INDEX.md @@ -0,0 +1,10 @@ +@page kernel Kenrel + +- @subpage kernel_basics +- @subpage thread_management +- @subpage clock_management +- @subpage thread_sync +- @subpage thread_comm +- @subpage memory_management +- @subpage interrupt_management +- @subpage kernel_porting diff --git a/documentation/4.tool/INDEX.md b/documentation/4.tool/INDEX.md new file mode 100644 index 0000000000..05454e1991 --- /dev/null +++ b/documentation/4.tool/INDEX.md @@ -0,0 +1,5 @@ +@page tool Tool + +- @subpage env + +- @subpage scons diff --git a/documentation/5.device/INDEX.md b/documentation/5.device/INDEX.md new file mode 100644 index 0000000000..95baa04ade --- /dev/null +++ b/documentation/5.device/INDEX.md @@ -0,0 +1,14 @@ +@page device Device + +- @subpage device_framework +- @subpage device_pin +- @subpage device_uart +- @subpage device_adc +- @subpage device_i2c +- @subpage device_spi +- @subpage device_pwm +- @subpage device_rtc +- @subpage device_hwtimer +- @subpage device_watchdog +- @subpage device_wlan +- @subpage device_sensor diff --git a/documentation/6.components/INDEX.md b/documentation/6.components/INDEX.md new file mode 100644 index 0000000000..3ee86cde59 --- /dev/null +++ b/documentation/6.components/INDEX.md @@ -0,0 +1,12 @@ +@page components Components + +- @subpage component_finsh +- @subpage component_vfs +- @subpage component_utest +- @subpage component_dlmodule +- @subpage component_sal +- @subpage component_at +- @subpage component_posix +- @subpage component_ulog +- @subpage component_pm +- @subpage component_network \ No newline at end of file diff --git a/documentation/7.contribution/INDEX.md b/documentation/7.contribution/INDEX.md new file mode 100644 index 0000000000..17a4ea83e8 --- /dev/null +++ b/documentation/7.contribution/INDEX.md @@ -0,0 +1,9 @@ +@page code_contribution Contribution + +# Contribution Guide + +We sincerely thank you for your contribution, and welcome to submit the code through GitHub's fork and Pull Request processes. RT-Thread 3.1.0 version and its earlier versions follow the GPL V2 open source license agreement. Versions from the 3.1.0 version onwards follow the Apache License 2.0 open source license agreement. + +All the real-time operating system kernel and open source components can be used free of charge for commercial products, there is no potential commercial risk and you will not being request to publish application source. + +@subpage rtt_code_style_en \ No newline at end of file diff --git a/documentation/doxygen/Doxyfile b/documentation/Doxyfile similarity index 98% rename from documentation/doxygen/Doxyfile rename to documentation/Doxyfile index 44a09c85d1..b6c3a1e2d2 100644 --- a/documentation/doxygen/Doxyfile +++ b/documentation/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "RT-Thread RTOS" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.2.0 +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -51,14 +51,14 @@ PROJECT_BRIEF = "An open source embedded real-time operating system" # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = ./images/rtthread_logo.png +PROJECT_LOGO = ./0.doxygen/images/rtthread_logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = . +OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -864,13 +864,13 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../../src \ - ../../include \ - . \ - ../../components/finsh \ - ../../components/drivers/include/drivers \ - ../../components/dfs/dfs_v2/src \ - ../../components/dfs/dfs_v2/include +INPUT = . \ + ../src \ + ../include \ + ../components/finsh \ + ../components/drivers/include/drivers \ + ../components/dfs/dfs_v2/src \ + ../components/dfs/dfs_v2/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -903,13 +903,14 @@ FILE_PATTERNS = *.c \ *.cc \ *.cpp \ *.h \ - *.inc + *.inc \ + *.md # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. -RECURSIVE = NO +RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a @@ -918,7 +919,11 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = .svn +EXCLUDE = ./0.doxygen/mainpage.h \ + ./README.md \ + ./2.quick-start/quick_start_qemu \ + ./env/env-vscode.md \ + ./contribution_guide/coding_style_cn.md # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -971,7 +976,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = ./images +IMAGE_PATH = . # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -1643,7 +1648,7 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://www.mathjax.org/mathjax +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1776,7 +1781,7 @@ LATEX_OUTPUT = latex # the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_CMD_NAME = latex +LATEX_CMD_NAME = # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. @@ -1880,7 +1885,7 @@ LATEX_EXTRA_FILES = # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. -PDF_HYPERLINKS = NO +PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as # specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX @@ -1890,7 +1895,7 @@ PDF_HYPERLINKS = NO # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. -USE_PDFLATEX = NO +USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running @@ -2125,10 +2130,6 @@ DOCBOOK_PROGRAMLISTING = NO GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# Configuration options related to Sqlite3 output -#--------------------------------------------------------------------------- - #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2337,7 +2338,7 @@ HIDE_UNDOC_RELATIONS = YES # http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO -# The default value is: NO. +# The default value is: YES. HAVE_DOT = YES @@ -2515,7 +2516,9 @@ DIRECTORY_GRAPH = YES # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, +# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, +# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, # png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and # png:gdiplus:gdiplus. # The default value is: png. @@ -2546,7 +2549,7 @@ DOT_PATH = # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = ../doxygen/images +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile diff --git a/documentation/INDEX.md b/documentation/INDEX.md new file mode 100644 index 0000000000..84dde62904 --- /dev/null +++ b/documentation/INDEX.md @@ -0,0 +1,52 @@ +@mainpage RT-Thread User Guide + +@subpage introduction + +@subpage quick_start + +@subpage kernel + +- @ref kernel_basics +- @ref thread_management +- @ref clock_management +- @ref thread_sync +- @ref thread_comm +- @ref memory_management +- @ref interrupt_management +- @ref kernel_porting + +@subpage tool + +- @ref env +- @ref scons + +@subpage device + +- @ref device_framework +- @ref device_pin +- @ref device_uart +- @ref device_adc +- @ref device_i2c +- @ref device_spi +- @ref device_pwm +- @ref device_rtc +- @ref device_hwtimer +- @ref device_watchdog +- @ref device_wlan +- @ref device_sensor + +@subpage components + +- @ref component_finsh +- @ref component_vfs +- @ref component_utest +- @ref component_dlmodule +- @ref component_sal +- @ref component_at +- @ref component_posix +- @ref component_ulog +- @ref component_pm +- @ref component_network + +@subpage code_contribution + diff --git a/documentation/README.md b/documentation/README.md index d27cec1366..55a0043d46 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -1,49 +1,55 @@ -# Manual Catalogue +# How to build doxygen html -- [RT-Thread Introduction](introduction/introduction.md) -- [Start Guide: Simulate STM32F103 on KEIL simulator](quick-start/quick-start.md) +1. download from https://doxygen.nl/index.html +2. open `Doxywizard` +3. `File` -> `Open` +4. Open the file ./Doxyfile +5. To tab `Run` , Click `Run doxygen` -**Kernel** +# How to build & run doxygen html on Ubuntu -- [Kernel Basics](basic/basic.md) -- [Thread Management](thread/thread.md) -- [Clock&Timer Management](timer/timer.md) -- [Inter-thread Synchronization](thread-sync/thread-sync.md) -- [Inter-thread Communication](thread-comm/thread-comm.md) -- [Memory Management](memory/memory.md) -- [Interrupt Management](interrupt/interrupt.md) -- [Kernel Porting](kernel-porting/kernel-porting.md) +The following steps are verified on Ubuntu 22.04: -**Tool** +```shell +$ lsb_release -a +No LSB modules are available. +Distributor ID: Ubuntu +Description: Ubuntu 22.04.5 LTS +Release: 22.04 +Codename: jammy +``` -- [User Manual of Env](env/env.md) -- [SCons](scons/scons.md) +The following packages (and dependents) need to be installed: -**Device** +```shell +$ sudo apt update +$ sudo apt install doxygen +$ sudo apt install graphviz +``` -- [I/O Device Framework](device/device.md) -- [PIN Device](device/pin/pin.md) -- [UART Device](device/uart/uart.md) -- [ADC Device](device/adc/adc.md) -- [I2C Bus Device](device/i2c/i2c.md) -- [SPI Device](device/spi/spi.md) -- [PWM Device](device/pwm/pwm.md) -- [RTC Device](device/rtc/rtc.md) -- [HWTIMER Device](device/hwtimer/hwtimer.md) -- [WATCHDOG Device](device/watchdog/watchdog.md) -- [WLAN Device](device/wlan/wlan.md) -- [Sensor Device](device/sensor/sensor.md) +Assume that the path of RT-Thead code tree is $RTT, execute the following command to build html. -**Components** +```shell +$ cd $RTT/documentation +$ rm -rf html +$ doxygen +``` -- [FinSH Console](finsh/finsh.md) -- [Virtual File System](filesystem/README.md) -- [utest Framework](utest/utest.md) -- [Dynamic Module: dlmodule](dlmodule/README.md) -- [Socket Abstraction Layer: SAL](sal/sal.md) -- [AT Commands](at/at.md) -- [POSIX Interface](posix/README.md) -- [Ulog Log](ulog/ulog.md) -- [Power Management: PM](pm/pm.md) -- [Network Framework](network/network.md) +A new html directory will be created and all the html files will be placed in this directory. +If you want to quickly browse HTML locally (in Ubuntu environment), you can enter the html directory and start a local HTML server through Python. + +```shell +$ cd html +$ python3 -m http.server +Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... +``` + +A bash script `run.sh` is provided to automatic upon operations. + +```shell +$ cd $RTT/documentation +$ ./run.sh +``` + +Then open the browser and enter `http://:8000/index.html` to access the created html web pages. If it is a local access, then `` should be replaced by `localhost`. If it is a remote access, then `` should be replaced by the actual accessible IP address of the machine where HTML is located. diff --git a/documentation/at/at.md b/documentation/at/at.md index c807ec70d3..905fc44365 100644 --- a/documentation/at/at.md +++ b/documentation/at/at.md @@ -1,6 +1,6 @@ -# AT Commands # +@page component_at AT Commands -## Introduction to AT Commands +# Introduction to AT Commands The AT command set was originally a control protocol invented by Dennis Hayes, initially used to control dial-up modems. Later, with the upgrade of network bandwidth, low-speed dial-up modems with very low speed essentially exited the general market, but the AT command set was retained. However, the AT command set lived on when major mobile phone manufacturers jointly developed a set of commands to control the GSM modules of mobile phones. The AT command set evolved on this basis and added the GSM 07.05 standard and the later GSM 07.07 standard to achieve more robust standardization. @@ -32,7 +32,7 @@ Although the AT command set has standardization to a certain degree, the AT comm In order to facilitate the user to use AT commands which can be easily adapted to different AT modules, RT-Thread provides AT components for AT Device connectivity and data communication. The implementation of the AT components consists of both a client and a server. -## Introduction to AT Components +# Introduction to AT Components The AT component is based on the implementation of the `AT Server` and `AT Client` of the RT-Thread system. The component completes the AT command transmission, command format and parameter parsing, command response, response data reception, response data parsing, URC data processing, etc.. @@ -66,9 +66,9 @@ Overall, the AT component resources are extremely small, making them ideal for u - AT Socket: An extension of AT Client function, it uses the AT command set to send and receive as the basis. This is implemented through the standard BSD Socket API, which completes the data sending and receiving function, and enables users to implement complete device networking and data communication through AT commands. - Multi-client support: The AT component supports multiple clients running simultaneously. -## AT Server ## +# AT Server -### AT Server Configuration ### +## AT Server Configuration ### When we use the AT Server feature in the AT component, we need to define the following configuration in rtconfig.h: @@ -110,7 +110,7 @@ RT-Thread Components ---> After the add configuration is complete, you can use the command line to rebuild the project, or use `scons` to compile. -### AT Server Initialization ### +## AT Server Initialization After enabling the AT Server in Env, you need to initialize it at startup to enable the AT Server function. If the component has been initialized automatically, no additional initialization is required. Otherwise, you need to call the following function in the initialization task: @@ -121,7 +121,7 @@ The AT Server initialization function, which belongs to the application layer fu After the AT Server is successfully initialized, the device can be used as an AT Server to connect to an AT Client's serial device for data communication, or use a serial-to-USB conversion tool to connect to a PC, so that the PC-side serial debugging assistant can communicate with the AT Client. -### Add custom AT commands ### +## Add custom AT commands At present, the format of the AT command set used by AT devices of different manufacturers does not have a completely uniform standard, so the AT Server in the AT component only supports some basic general AT commands, such as ATE, AT+RST, etc. These commands can only be used to meet the basic operation of the device. If users want to use more functions, they need to implement custom AT Server commands for different AT devices. The AT component provides an AT command addition method similar to the FinSH/msh command addition method, which is convenient for users to implement the required commands. @@ -175,9 +175,9 @@ static at_result_t at_test_query(void) AT_CMD_EXPORT("AT+TEST", =[,], NULL, at_test_query, NULL, at_test_exec); ``` -### AT Server APIs +## AT Server APIs -#### Send Data to the Client (no newline) +### Send Data to the Client (no newline) ```c void at_server_printf(const char *format, ...); @@ -190,7 +190,7 @@ This function is used by the AT Server to send fixed-format data to the correspo | format | Customize the expression of the input data | | ... | Input data list, variable parameters | -#### Send Data to the Client (newline) +### Send Data to the Client (newline) ```c void at_server_printfln(const char *format, ...); @@ -203,7 +203,7 @@ This function is used by the AT Server to send fixed-format data to the correspo | format | Customize the expression of the input data | | ... | Input data list, variable parameters | -#### Send Command Execution Results to the Client +### Send Command Execution Results to the Client ```c void at_server_print_result(at_result_t result); @@ -252,7 +252,7 @@ static at_result_t at_test_exec(void) AT_CMD_EXPORT("AT+TEST", =,, NULL, NULL, at_test_setup, at_test_exec); ``` -#### Parsing Input Command Parameters +### Parsing Input Command Parameters ```c int at_req_parse_args(const char *req_args, const char *req_expr, ...); @@ -299,7 +299,7 @@ static at_result_t at_test_setup(const char *args) AT_CMD_EXPORT("AT+TEST", =,, NULL, NULL, at_test_setup, NULL); ``` -#### Porting-related interfaces +### Porting-related interfaces The AT Server supports a variety of basic commands (ATE, ATZ, etc.) by default. The function implementation of some commands is related to hardware or platform and requires user-defined implementation. The AT component source code `src/at_server.c` file gives the weak function definition of the migration file. The user can create a new migration file in the project to implement the following function to complete the migration interface, or modify the weak function to complete the migration interface directly in the file. @@ -326,9 +326,9 @@ If you use the gcc toolchain in your project, you need to add the *section* corr } > CODE ``` -## AT Client +# AT Client -### AT Client Configuration +## AT Client Configuration When using the AT Client feature in the AT component, the following configuration in rtconfig.h needs to be defined: @@ -371,7 +371,7 @@ RT-Thread Components ---> After the configuration is complete, you can use the command line to rebuild the project, or use `scons` to compile. -### AT Client Initialization ### +## AT Client Initialization After configuring the AT Client, you need to initialize it at startup to enable the AT Client function. If the component has been initialized automatically, no additional initialization is required. Otherwise, you need to call the following function in the initialization task: @@ -381,7 +381,7 @@ int at_client_init(const char *dev_name, rt_size_t recv_bufsz); The AT Client initialization function, which belongs to the application layer function, needs to be called before using the AT Client function or using the AT Client CLI function. The `at_client_init()` function completes the initialization of the AT Client device, the initialization of the AT Client porting function, the semaphore and mutex used by the AT Client, and other resources, and creates the `at_client` thread for parsing the data received in the AT Client and for processing the URC data. -### AT Client data receiving and sending ### +## AT Client data receiving and sending The main function of the AT Client is to send AT commands, receive data, and parse data. The following is an introduction to the processes and APIs related to AT Client data reception and transmission. @@ -418,7 +418,7 @@ In the AT component, this structure is used to define a control block for AT com Introduction to related API interfaces: -#### Create a Response Structure +### Create a Response Structure ```c at_response_t at_create_resp(rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout); @@ -435,7 +435,7 @@ at_response_t at_create_resp(rt_size_t buf_size, rt_size_t line_num, rt_int32_t This function is used to create a custom response data receiving structure for later receiving and parsing the send command response data. -#### Delete a Response Structure +### Delete a Response Structure ```c void at_delete_resp(at_response_t resp); @@ -447,7 +447,7 @@ void at_delete_resp(at_response_t resp); This function is used to delete the created response structure object, which is generally paired with the **at_create_resp** creation function. -#### Set the Parameters of Response Structure +### Set the Parameters of Response Structure ```c at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t line_num, rt_int32_t timeout); @@ -465,7 +465,7 @@ at_response_t at_resp_set_info(at_response_t resp, rt_size_t buf_size, rt_size_t This function is used to set the response structure information that has been created. It mainly sets the restriction information on the response data. It is generally used after creating the structure and before sending the AT command. This function is mainly used to send commands when the device is initialized, which can reduce the number of times the response structure is created and reduce the code resource occupation. -#### Send a Command and Receive a Response +### Send a Command and Receive a Response ```c rt_err_t at_exec_cmd(at_response_t resp, const char *cmd_expr, ...); @@ -535,11 +535,11 @@ MSH_CMD_EXPORT(at_Client_send, AT Client send commands to AT Server and get resp The implementation principle of sending and receiving data is relatively simple. It mainly reads and writes the serial port device bound by the AT client, and sets the relevant number of rows and timeout to limit the response data. It is worth noting that the `res` response needs to be created first. The structure passed `in_exec_cmd` function is for data reception. When the `at_exec_cmd` function's parameter `resp` is NULL, it means that the data sent this time **does not consider processing the response data and directly returns the result**. -### AT Client Data Parsing Method ### +## AT Client Data Parsing Method After the data is normally acquired, the response data needs to be parsed, which is one of the important functions of the AT Client. Parsing of data in the AT Client provides a parsed form of a custom parsing expression whose parsing syntax uses the standard `sscanf` parsing syntax. Developers can use the custom data parsing expression to respond to useful information in the data, provided that the developer needs to review the relevant manual in advance to understand the basic format of the AT Server device response data that the AT Client connects to. The following is a simple AT Client data parsing method through several functions and routines. -#### Get Response Data for the Specified Line Number +### Get Response Data for the Specified Line Number ```c const char *at_resp_get_line(at_response_t resp, rt_size_t resp_line); @@ -555,7 +555,7 @@ const char *at_resp_get_line(at_response_t resp, rt_size_t resp_line); This function is used to get a row of data with the specified line number in the AT Server response data. The line number is judged by the standard data terminator. The above send and receive functions `at_exec_cmd` have recorded and processed the data and line numbers of the response data in the `resp` response structure, where the data information of the corresponding line number can be directly obtained. -#### Get Response Data by the Specified Keyword +### Get Response Data by the Specified Keyword ```c const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword); @@ -571,7 +571,7 @@ const char *at_resp_get_line_by_kw(at_response_t resp, const char *keyword); This function is used to get a corresponding row of data by keyword in the AT Server response data. -#### Parse Response Data for the Specified Line Number +### Parse Response Data for the Specified Line Number ```c int at_resp_parse_line_args(at_response_t resp, rt_size_t resp_line, const char *resp_expr, ...); @@ -590,7 +590,7 @@ int at_resp_parse_line_args(at_response_t resp, rt_size_t resp_line, const char This function is used to get a row of data with the specified line number in the AT Server response data, and parse the parameters in the row data. -#### Parse Response Data for a Row with Specified Keyword +### Parse Response Data for a Row with Specified Keyword ```c int at_resp_parse_line_args_by_kw(at_response_t resp, const char *keyword, const char *resp_expr, ...); @@ -611,7 +611,7 @@ This function is used to get a row of data containing a keyword in the AT Server The data parsing syntax uses the standard `sscanf` syntax, the content of the syntax is more, developers can search their parsing syntax, here two procedures are used to introduce the simple use method. -#### Serial Port Configuration Information Analysis Example +### Serial Port Configuration Information Analysis Example The data sent by the client: @@ -644,7 +644,7 @@ printf("baudrate=%d, databits=%d, stopbits=%d, parity=%d, control=%d\n", at_delete_resp(resp); ``` -#### IP and MAC Address Resolution Example #### +### IP and MAC Address Resolution Example The data sent by the client: @@ -678,7 +678,7 @@ at_delete_resp(resp); The key to parsing data is to correctly define the expression. Because the response data of the different device manufacturers is not unique to the response data of the AT device, only the form of the custom parsing expression can be obtained to obtain the required information. The design of the `at_resp_parse_line_args` parsing parameter function is based on the `sscanf` data parsing method. Before using it, the developer needs to understand the basic parsing syntax and then design the appropriate parsing syntax in combination with the response data. If the developer does not need to parse the specific parameters, you can use the `at_resp_get_line` function to get the specific data of a row. -### AT Client URC Data Processing ### +## AT Client URC Data Processing The processing of URC data is another important feature of AT Client. URC data is the data that is actively sent by the server. It cannot be received by the above data sending and receiving functions. The URC data format and function are different for different devices. Therefore, the URC data processing mode needs to be customized. The AT component provides a list management method for the processing of URC data. Users can customize the addition of URC data and its execution functions to the management list, so the processing of URC data is also the main porting work of AT Client. @@ -697,7 +697,7 @@ typedef struct at_urc *at_urc_t; Each URC data has a structure control block that defines and determines the prefix and suffix of the URC data, as well as the execution function of the URC data. A piece of data can be defined as URC data only if it matches the prefix and suffix of the URC exactly. The URC data execution function is executed immediately after the matching URC data is obtained. So developers adding a URC data requires a custom matching prefix, suffix, and execution function. -#### URC Data List Initialization +### URC Data List Initialization ```c void at_set_urc_table(const struct at_urc *table, rt_size_t size); @@ -745,9 +745,9 @@ int at_client_port_init(void) } ``` -### AT Client Other APIs Introduction +## AT Client Other APIs Introduction -#### Send Specified Length Data +### Send Specified Length Data ```c rt_size_t at_client_send(const char *buf, rt_size_t size); @@ -763,7 +763,7 @@ rt_size_t at_client_send(const char *buf, rt_size_t size); This function is used to send the specified length data to the AT Server device through the AT Client device, which is mostly used for the AT Socket function. -#### Receive Specified Length Data +### Receive Specified Length Data ```c rt_size_t at_client_recv(char *buf, rt_size_t size,rt_int32_t timeout); @@ -780,7 +780,7 @@ rt_size_t at_client_recv(char *buf, rt_size_t size,rt_int32_t timeout); This function is used to receive data of a specified length through the AT Client device, and is mostly used for the AT Socket function. This function can only be used in URC callback handlers. -#### Set the line terminator for receiving data #### +### Set the line terminator for receiving data ```c void at_set_end_sign(char ch); @@ -794,7 +794,7 @@ void at_set_end_sign(char ch); This function is used to set the line terminator, which is used to judge the end of a row of data received by the client, and is mostly used for the AT Socket function. -#### Waiting for module initialization to complete #### +### Waiting for module initialization to complete ```c int at_client_wait_connect(rt_uint32_t timeout); @@ -809,7 +809,7 @@ int at_client_wait_connect(rt_uint32_t timeout); This function is used to cyclically send AT commands when the AT module starts, until the module responds to the data, indicating that the module is successfully started. -### AT Client Multi-Client Support ### +## AT Client Multi-Client Support In general, the device as the AT Client only connects to one AT module (the AT module acts as the AT Server) and can directly use the above functions of data transmission and reception and command parsing. In a few cases, the device needs to connect multiple AT modules as the AT Client. In this case, the multi-client support function of the device is required. @@ -882,16 +882,16 @@ at_delete_resp(resp); The process differences used by other functions are similar to the above `at_obj_exec_cmd()` function. The main function is to obtain the client object through the `at_client_get()` function, and then determine which client is the client through the incoming object to achieve multi-client support. -## FAQs +# FAQs -### Q: What should I do if the log on the shell shows an error when enabling the AT command to send and receive data real-time printing function. ? +## Q: What should I do if the log on the shell shows an error when enabling the AT command to send and receive data real-time printing function. ? **A:** Increase the baudrate of the serial port device corresponding to the shell to 921600, improve the serial port printing speed, and prevent the printing error when the data is too large. -### Q: When the AT Socket function is started, the compile prompt "The AT socket device is not selected, please select it through the env menuconfig". +## Q: When the AT Socket function is started, the compile prompt "The AT socket device is not selected, please select it through the env menuconfig". **A:** After the AT Socket function is enabled, the corresponding device model is enabled in the at device package by default. Enter the at device package, configure the device as an ESP8266 device, configure WIFI information, re-generate the project, compile and download. -### Q: AT Socket function data reception timeout or data reception is not complete. +## Q: AT Socket function data reception timeout or data reception is not complete. **A:** The error may be that the receive data buffer in the serial device used by the AT is too small (RT_SERIAL_RB_BUFSZ default is 64 bytes), and the data is overwritten after the data is not received in time. The buffer size of the serial port receiving data (such as 256 bytes) is appropriately increased. diff --git a/documentation/basic/basic.md b/documentation/basic/basic.md index ec5215b132..9fa2deebd2 100644 --- a/documentation/basic/basic.md +++ b/documentation/basic/basic.md @@ -1,4 +1,4 @@ -# Kernel Basics +@page kernel_basics Kernel Basics This chapter gives a brief introduction to the software architecture of the RT-Thread kernel, beginning with its composition and implementation. While also introducing RT-Thread kernel-related concepts for beginners. After understanding this chapter, readers will have an elementary understanding of the RT Thread kernel and will be able to answer questions such as - @@ -10,15 +10,7 @@ After understanding this chapter, readers will have an elementary understanding In the nutshell, this is only a brief introduction to software architecture decomposition and implementation of the real-time kernel. This will give understanding and concepts of how RT-Thread kernel works togther. After learning from this chapter, readers will have basic knowledge of each kernel components, system booting up proccesses, memory allocation and distrubtion, and methods of kernel configuration. -## **Table of Contents** - -1. [Introduction to RT-Thread Kernel](#introduction-to-rt-thread-kernel) -2. [RT-Thread Startup Process](#rt-thread-startup-process) -3. [RT-Thread Program Memory Distribution](#rt-thread-program-memory-distribution) -4. [RT-Thread Automatic Initialization Mechanism](#rt-thread-automatic-initialization-mechanism) -5. [RT-Thread Kernel Object Model](#rt-thread-kernel-object-model) - -## Introduction to RT-Thread Kernel +# Introduction to RT-Thread Kernel Kernel is the most basic and fundenmental part of an Operating System. Kernel service library and RT-Thread kernel libraries are interfacing between hardware and components/service layer. This includes the implementation of real-time kernel service library (rtservice.h/kservice.c) and other RT-Thread kernel libraries such as object management, thread management and scheduler, inter-thread communication management, clock management and memory management respectively. Below diagram is the core architecture diagram of the core kernel. @@ -30,7 +22,7 @@ Implementation of core kernel libraries are similar to a small set of standard C The built of the Kernel will be vary depending on the complier. For example, using GNU GCC compiler, it will use more implementation from the standard C library. Last but not least, the minimum resource requirements of the Kernel is 3KB ROM and 1.2KB RAM. -### Thread Scheduling +## Thread Scheduling Thread is the smallest scheduling unit in the RT-Thread operating system. The thread scheduling algorithm is a **Priority-based Full Preemptive Multi-Thread** scheduling algorithm. The system can support up to 256(0 - 255) thread priorities. For systems with tight resources, configurations with 8 or 32 thread priorities can be chosen(For example, STM32 has 32 thread priorities as per the default configuration). Lower numbers have a higher priority where 0 represents the highest priority furthermore the lowest priority(highest number) is reserved for idle threads. @@ -39,7 +31,7 @@ The number of threads is bounded by the memory of the hardware platform and not Thread management will be covered in detail in the "Thread Management" chapter. -### Clock Management +## Clock Management RT-Thread's Clock management is based upon a **clock beat**, which is the smallest clock unit in the RT-Thread operating system. The RT-Thread timer provides two types of timer mechanisms: @@ -52,7 +44,7 @@ The timer service is concluded using a timer timing callback i.e. a timeout func Timer will be explained further in the "Clock Management" chapter. -### Synchronization between Threads +## Synchronization between Threads RT-Thread uses thread semaphores, mutexes, and event sets to achieve inter-thread synchronization. Thread synchronizations happen through the acquisition and release of semaphore and mutexes. @@ -61,13 +53,13 @@ Event sets are primarily used for synchronization between threads, they can achi The concepts of semaphores, mutexes, and event sets are detailed in the "Inter-Thread Synchronization" chapter. -### Inter-Thread Communication +## Inter-Thread Communication RT-Thread supports communication mechanisms such as mailbox, message queue, etc. The mailbox's message length is fixed to 4 bytes. Whereas, message queue can receive messages in variable size and cache the messages in its own memory space. Compared to a message queue, a mailbox is more efficient. The sending action of the mailbox and message queue can be safely used in an ISR (Interrupt Service Routine). The communication mechanism allows threads to wait by priority or to acquire by the First In First Out (FIFO) method. The concept of mailbox and message queue will be explained in detail in the "Inter-Thread Communication" chapter. -### Memory Management +## Memory Management RT-Thread allows: 1. Static Memory Pool @@ -82,13 +74,13 @@ There is also a dynamic memory heap management called memheap, suitable for memo The concept of memory management will be explained in the "Memory Management" chapter. -### I/O Device Management +## I/O Device Management RT-Thread uses I2C, SPI, USB, UART, etc., as peripheral devices and is uniformly registered through the device. It realized a device management subsystem accessed by the name, and it can access hardware devices according to a unified API interface. On the device driver interface, depending on the characteristics of the embedded system, corresponding events can be attached to different devices. The driver notifies the upper application program when the device event is triggered. The concept of I/O device management will be explained in the "Device Model" and "General Equipment" chapters. -## RT-Thread Startup Process +# RT-Thread Startup Process The understanding of most codes usually starts from learning the startup process. We will firstly look for the source of the startup. Taking MDK-ARM as an example, the user program entry for MDK-ARM is the main() function located in the main.c file. The launching of the system starts from the assembly code startup_stm32f103xe.s, jumps to the C code, initializes the RT-Thread system function, and finally enters the user program entry main(). @@ -172,7 +164,7 @@ int main(void) } ``` -## RT-Thread Program Memory Distribution +# RT-Thread Program Memory Distribution The general MCU contains storage space that includes the on-chip Flash and the on-chip RAM. RAM is equivalent to memory, and Flash is comparable to a hard disk. The compiler classifies a program into several parts stored in different memory areas of the MCU. @@ -239,7 +231,7 @@ void sensor_init() ``` The `sensor_value` is stored in the ZI segment and is automatically initialized to zero after system startup (some library functions provided by the user program or compiler are initialized to zero). The sensor_inited variable is stored in the RW segment, and the sensor_enable is stored in the RO segment. -## RT-Thread Automatic Initialization Mechanism +# RT-Thread Automatic Initialization Mechanism The automatic initialization mechanism means that the initialization function does not need to be called by explicit function. It only needs to be declared by macro definition at the function definition, and it will be executed during system startup. @@ -288,10 +280,9 @@ The macro interface definitions used to implement the automatic initialization f Initialization function actively declares through these macro interfaces, such as INIT_BOARD_EXPORT (rt_hw_usart_init), the linker will automatically collect all the declared initialization functions, placed in the RTI symbol segment, the symbol segment is located in the RO segment of the memory distribution. All functions in this RTI symbol segment are automatically called when the system is initialized. -RT-Thread Kernel Object Model ---------------------- +# RT-Thread Kernel Object Model -### Static and Dynamic Objects +## Static and Dynamic Objects The RT-Thread kernel is designed with object-oriented method. The system-level infrastructures are all kernel objects such as threads, semaphores, mutexes, timers, and more. Kernel objects fall into two categories: static kernel objects and dynamic kernel objects. Static kernel objects are usually placed in RW and ZI segments, initialized in the program after system startup; dynamic kernel objects are created from the memory heap and then manually initialized. @@ -372,7 +363,7 @@ In this example, thread1 is a static thread object and thread2 is a dynamic thre Static objects take up RAM space and is not depend on the memory heap manager. When allocating static objects, the time needed is determined. Dynamic objects depend on the memory heap manager. It requests RAM space while running. When the object is deleted, the occupied RAM space is released. These two methods have their own advantages and disadvantages, and can be selected according to actual needs. -### Kernel Object Management Structure +## Kernel Object Management Structure RT-Thread uses the kernel object management system to access/manage all kernel objects. Kernel objects contain most of the facilities in the kernel. These kernel objects can be statically allocated static objects and dynamic objects allocated from the system memory heap. . @@ -396,7 +387,7 @@ The advantages of this design approach are: Derivations from object control block rt_object in the above figure includes: thread object, memory pool object, timer object, device object and IPC object (IPC: Inter-Process Communication. In RT-Thread real-time operating system, IPC objects is used for synchronization and communicate between threads); derivations from IPC objects includes: semaphores, mutexes, events, mailboxes, message queues, signals, etc. -### Object Control Block +## Object Control Block Data structure of kernel object control block: @@ -452,7 +443,7 @@ enum rt_object_class_type From the above type specification, we can see that if it is a static object, the highest bit of the object type will be 1 (which is the OR operation of RT_Object_Class_Static and other object types and operations). Otherwise it will be dynamic object, and the maximum number of object classes that the system can accommodate is 127. -### Kernel Object Management +## Kernel Object Management Data structure of kernel object container: @@ -470,7 +461,7 @@ struct rt_object_information A class of objects is managed by an rt_object_information structure, and each practical instance of such type of object is mounted to the object_list in the form of a linked list. The memory block size of this type of object is identified by object_size (the memory block each practical instance of each type of object is the same size). -#### Initialization Object +### Initialization Object An uninitialized static object must be initialized before it can be used. The initialization object uses the following interfaces: @@ -489,7 +480,7 @@ When this function is called to initialize the object, the system will place the | type | The type of the object must be a enumeration type listed in rt_object_class_type, RT_Object_Class_Static excluded. (For static objects, or objects initialized with the rt_object_init interface, the system identifies it as an RT_Object_Class_Static type) | | name | Name of the object. Each object can be set to a name, and the maximum length for the name is specified by RT_NAME_MAX. The system does not care if it uses ’`\0`’as a terminal symbol. | -#### Detach Object +### Detach Object Detach an object from the kernel object manager. The following interfaces are used to detach objects: @@ -499,7 +490,7 @@ void rt_object_detach(rt_object_t object); Calling this interface makes a static kernel object to be detached from the kernel object container, meaning the corresponding object node is deleted from the kernel object container linked list. After the object is detached, the memory occupied by the object will not be released. -#### Allocate object +### Allocate object The above descriptions are interfaces of objects initialization and detachment, both of which are under circumstances that object-oriented memory blocks already exist. But dynamic objects can be requested when needed. The memory space is freed for other applications when not needed. To request assigning new objects, you can use the following interfaces: @@ -519,7 +510,7 @@ When calling the above interface, the system first needs to obtain object inform | object handle allocated successfully | Allocate successfully | | RT_NULL | Fail to allocate | -#### Delete Object +### Delete Object For a dynamic object, when it is no longer used, you can call the following interface to delete the object and release the corresponding system resources: @@ -534,7 +525,7 @@ When the above interface is called, the object is first detached from the object |----------|------------| | object | object handle | -#### Identify objects +### Identify objects Identify whether the specified object is a system object (static kernel object). The following interface is used to identify the object: diff --git a/documentation/contribution_guide/coding_style_en.md b/documentation/contribution_guide/coding_style_en.md index 9b1a03fc58..4daa430fb4 100644 --- a/documentation/contribution_guide/coding_style_en.md +++ b/documentation/contribution_guide/coding_style_en.md @@ -1,4 +1,4 @@ - RT-Thread Coding Style +@page rtt_code_style_en RT-Thread Coding Style This is an developing instruction for RT-Thread developers. As open source software, RT-Thread is created by the cooperation of different people. This @@ -7,7 +7,7 @@ RT-Thread users should also get to know some conventions in the code through it and thus easier to understand the implementations of RT-Thread. -1. Directory Naming +# 1. Directory Naming In normal conditions, please name directories in lowercase. Directories should have descriptive names. For example, the port of a chip should be composed of @@ -15,14 +15,14 @@ the name of the chip and the category of the chip. Directories under components/ should name what the component does. -2. File Naming +# 2. File Naming In normal conditions, please name files in lowercase. If the file is referencing other places, it can have the original name. To avoid naming collision, do not use general names or the names that are frequently used. -3. Header Files +# 3. Header Files To avoid include the same header file for multiple times, you need to define a symbol like this: @@ -36,7 +36,7 @@ The symbol should begin and end with "__" to avoid naming collision. The words of the file name should be connected by "_". (This convention is called "snake case".) -4. Header File Comments +# 4. Header File Comments In every header file, there should be copyright information and Change Log record like this: @@ -52,7 +52,7 @@ record like this: * 2006-04-26 Bernard add semaphore APIs */ -5. Structure Defines +# 5. Structure Defines Please name structures in lowercase and connect words with "_". For example: @@ -76,7 +76,7 @@ example: typedef struct rt_timer* rt_timer_t; -6. Macros +# 6. Macros In RT-Thread, please use uppercase names for macro definitions. Words are connected by "_". Like: @@ -84,7 +84,7 @@ connected by "_". Like: #define RT_TRUE 1 -7. Function Naming and Declaration +# 7. Function Naming and Declaration Please name functions in lowercase. Separate words with "_". The API provided to upper application should be declared in header files. If the function don't have @@ -93,7 +93,7 @@ parameters, it should be declared as void: rt_thread_t rt_thread_self(void); -8. Commenting +# 8. Commenting Please use English to comment. There shouldn't be many comments as the comments should describe what the code does. It should describe complicated @@ -101,7 +101,7 @@ algorithms, for example. Comments for statements should be placed before the statements or to the right of them. Any other locations are invalid. -9. Indent +# 9. Indent Please use TAB or 4 spaces to indent. It's preferred to use 4 spaces. If no other special meanings, the indent should begin right after "{": @@ -123,7 +123,7 @@ aligned with "switch": "case" is aligned with "switch". The following code block should be indented. -10. Braces and Spaces +# 10. Braces and Spaces For ease of reading, it is advised that braces should occupy the whole line instead of following other statements. Like: @@ -160,7 +160,7 @@ operators and the strings. There should be no spaces around(inside) parentheses, This is a bad practice. -11. trace, log Information +# 11. trace, log Information In RT-Thread, rt_kprintf is a commonly used logging routine. In RT-Thread rt_kprintf is implemented as a polling, non-interrupting string output. It is @@ -175,14 +175,14 @@ variable or a macro). When logging, it should be easy to understand and easy to determine where the problem is. -12. Functions +# 12. Functions Functions in kernel should be K.I.S.S. ("Keep it simple, stupid.") If the function is too long, you should split it into smaller ones, with each of them simplified to be easy to understand. -13. Objects +# 13. Objects The kernel of RT-Thread uses object-oriented techniques in C. The naming convention is: structure names are the object names, object names + verb phrases are the @@ -211,7 +211,7 @@ When creating a new object, think twice on memory allocations: whether a static object could be created or it could only created dynamically on the heap. Allocations can be slower, but may be necessary in dynamic environments. -14. Use astyle to format the code automatically +# 14. Use astyle to format the code automatically parameters: --style=allman --indent=spaces=4 --indent-preproc-block diff --git a/documentation/device/adc/adc.md b/documentation/device/adc/adc.md index 9ded20ae7f..84c43a9821 100644 --- a/documentation/device/adc/adc.md +++ b/documentation/device/adc/adc.md @@ -1,10 +1,10 @@ -# ADC Device +@page device_adc ADC Device -## An Introduction to ADC +# An Introduction to ADC An ADC (analog-to-digital converter) is a hardware device that converts continuously changing analog signals to discrete digital signals. Usually, these analog signals include temperature, pressure, sound, video and many other types of signals. Converting them is important, as digital signals are easier to store, process, and transmit. This conversion can be achieved by using an ADC device which is commonly integrated in various platforms. Historically, ADCs were first used to convert received wireless signals to digital signals, for example, television signals, or signals from long-short broadcast stations. -### Conversion Process +## Conversion Process As shown in the figure below, the analog-to-digital conversion generally involves steps of sampling, holding, quantifying, and encoding. In actual circuits, some processes are combined, such as sampling and holding, while quantization and encoding are implemented simultaneously in the conversion process. @@ -14,19 +14,19 @@ Sampling is the conversion of analog signals that changes continuously over time The process of converting a numerically continuous analog quantity into a digital quantity is called quantization. Digital signals are discrete numerically. The output voltage of the sample-and-hold circuit also needs to be naturalized to a corresponding discrete level in a similar way, and any digital quantity can only be an integer multiple of a certain minimum quantity unit. The quantized value also requires the encoding process, which is the digital output of the A/D converter. -### Resolution +## Resolution Resolution is represented as binary (or decimal) numbers. Generally, it comes in 8 bits, 10 bits, 12 bits, 16 bits, etc. A larger resolution, in bits, means more accuracy in the conversion of analog to digital signals. -### Precision +## Precision Precision is the maximum error value between analog signals and real ADC device numerical points’ values.An ADC with a high resolution might have a low precision, meaning that factors like noise can affect the numerical ADC reading more than small changes in the input signal. -### Conversion Rate +## Conversion Rate The conversion rate is the reciprocal of time taken for an ADC device to complete conversion from an analog to a digital signal. For example, an ADC device with a conversion rate of 1MHz means that the ADC conversion time is 1 microsecond. -## Access ADC Device +# Access ADC Device The application accesses the ADC hardware through the ADC device management interface provided by RT-Thread. The relevant interfaces are as follows: @@ -37,7 +37,7 @@ The application accesses the ADC hardware through the ADC device management inte | rt_adc_read() | Read ADC device data | | rt_adc_disable() | Close the ADC device | -### Find ADC Devices +## Find ADC Devices The application gets the device handler based on the ADC device name to operate the ADC device. Following is the interface function to find the devices: @@ -62,7 +62,7 @@ rt_adc_device_t adc_dev; /* ADC device handle */ adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME); ``` -### Enable ADC Channel +## Enable ADC Channel It is required to enable the ADC device with the following interface function before reading and operating the ADC device. @@ -91,7 +91,7 @@ adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME); rt_adc_enable(adc_dev, ADC_DEV_CHANNEL); ``` -### Read ADC Channel Sample Values +## Read ADC Channel Sample Values Reading the ADC channel sample values can be done by the following function: @@ -129,7 +129,7 @@ rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100); The calculation formula of the actual voltage value is: `sampling value * reference voltage/(1 << resolution digit)`. In the above example, variable *vol* was enlarged 100 times, so finally the integer part of voltage is obtained through *vol / 100*, and the decimal part of voltage is obtained through *vol % 100*. -### Disabling the ADC Channel +## Disabling the ADC Channel An ADC channel can be disabled through the following function: @@ -166,7 +166,7 @@ rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100); rt_adc_disable(adc_dev, ADC_DEV_CHANNEL); ``` -### FinSH Command +## FinSH Command To find out the registered device, you can use the command adc probe followed by the registered ADC device name as following, @@ -198,7 +198,7 @@ adc1 channel 5 disable success msh > ``` -## ADC Device Usage Example +# ADC Device Usage Example The specific usage of the ADC device can refer to the following sample code. The main steps of the sample code are as follows: diff --git a/documentation/device/device.md b/documentation/device/device.md index 4c8c026c18..0e31d463dc 100644 --- a/documentation/device/device.md +++ b/documentation/device/device.md @@ -1,12 +1,12 @@ -# I/O Device Framework +@page device_framework I/O Device Framework Most embedded systems include some I/O (Input/Output) devices, data displays on instruments, serial communication on industrial devices, Flash or SD cards for saving data on data acquisition devices,as well as Ethernet interfaces for network devices, are examples of I/O devices that are commonly seen in embedded systems. This chapter describes how RT-Thread manages different I/O devices. -## I/O Device Introduction +# I/O Device Introduction -### I/O Device Framework +## I/O Device Framework RT-Thread provides a set of I/O device framework, as shown in the following figure. It is located between the hardware and the application. It is divided into three layers. From top to bottom, they are I/O device management layer, device driver framework layer, and device driver layer. @@ -35,7 +35,7 @@ Usage of Watchdog device: ![Watchdog Device Use Sequence Diagram](figures/wtd-uml.png) -### I/O Device Model +## I/O Device Model The device model of RT-Thread is based on the kernel object model, which is considered a kind of objects and is included in the scope of the object manager. Each device object is derived from the base object. Each concrete device can inherit the properties of its parent class object and derive its own properties. The following figure is a schematic diagram of the inheritance and derivation relationship of device object. @@ -66,7 +66,7 @@ typedef struct rt_device *rt_device_t; ``` -### I/O Device Type +## I/O Device Type RT-Thread supports multiple I/O device types, the main device types are as follows: @@ -95,7 +95,7 @@ A block device transfers one data block at a time, for example 512 bytes data at When the system serves a write operation with a large amount of data, the device driver must first divide the data into multiple packets, each with the data size specified by the device. In the actual process, the last part of the data size may be smaller than the normal device block size. Each block in the above figure is written to the device using a separate write request, and the first three are directly written. However, the last data block size is smaller than the device block size, and the device driver must process the last data block differently than the first 3 blocks. Normally, the device driver needs to first perform a read operation of the corresponding device block, then overwrite the write data onto the read data, and then write the "composited" data block back to the device as a whole block. . For example, for block 4 in the above figure, the driver needs to read out the device block corresponding to block 4, and then overwrite the data to be written to the data read from the device block, and merge them into a new block. Finally write back to the block device. -## Create and Register I/O Device +# Create and Register I/O Device The driver layer is responsible for creating device instances and registering them in the I/O Device Manager. You can create device instances in a statically declared manner or dynamically create them with the following interfaces: @@ -245,13 +245,13 @@ rt_err_t rt_hw_watchdog_register(struct rt_watchdog_device *wtd, ``` -## Access I/O Devices +# Access I/O Devices The application accesses the hardware device through the I/O device management interface, which is accessible to the application when the device driver is implemented. The mapping relationship between the I/O device management interface and the operations on the I/O device is as follows: ![Mapping between the I/O Device Management Interface and the Operations on the I/O Device](figures/io-fun-call.png) -### Find Device +## Find Device The application obtains the device handle based on the device name, which in turn allows the device to operate. To find device, use function below: @@ -266,7 +266,7 @@ rt_device_t rt_device_find(const char* name); | device handle | finding the corresponding device will return the corresponding device handle | | RT_NULL | no corresponding device object found | -### Initialize Device +## Initialize Device Once the device handle is obtained, the application can initialize the device using the following functions: @@ -283,7 +283,7 @@ rt_err_t rt_device_init(rt_device_t dev); >When a device has been successfully initialized, calling this interface will not repeat initialization. -### Open and Close Device +## Open and Close Device Through the device handle, the application can open and close the device. When the device is opened, it will detect whether the device has been initialized. If it is not initialized, it will call the initialization interface to initialize the device by default. Open the device with the following function: @@ -333,7 +333,7 @@ rt_err_t rt_device_close(rt_device_t dev); >Device interfaces `rt_device_open()` and `rt_device_close()` need to used in pairs. Open a device requires close the device, so that the device will be completely closed, otherwise the device will remain on. -### Control Device +## Control Device By commanding the control word, the application can also control the device with the following function: @@ -362,7 +362,7 @@ The generic device command for the parameter `cmd` can be defined as follows: #define RT_DEVICE_CTRL_GET_INT 0x12 /* obtain interrupt status */ ``` -### Read and Write Device +## Read and Write Device Application can read data from the device by the following function: @@ -400,7 +400,7 @@ rt_size_t rt_device_write(rt_device_t dev, rt_off_t pos,const void* buffer, rt_s Calling this function will write the data in the buffer to the *dev* device . The maximum length of the written data is *size*, and *pos* has different meanings depending on the device class. -### Data Transceiving and Call-back +## Data Transceiving and Call-back When the hardware device receives the data, the following function can be used to call back another function to set the data receiving indication to notify the upper application thread that the data arrives: @@ -432,7 +432,7 @@ rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_devic When this function is called, the callback function is provided by the user. When the hardware device sends the data, the driver calls back the function and passes the sent data block address buffer as a parameter to the upper application. When the upper layer application (thread) receives the indication, it will release the buffer memory block or use it as the buffer for the next write data according to the condition of sending the buffer. -### Access Device Sample +## Access Device Sample The following code is an example of accessing a device. First, find the watchdog device through the `rt_device_find()` port, obtain the device handle, then initialize the device through the `rt_device_init()` port, and set the watchdog device timeout through the `rt_device_control()`port. diff --git a/documentation/device/hwtimer/hwtimer.md b/documentation/device/hwtimer/hwtimer.md index da8903a547..0a7135c43f 100644 --- a/documentation/device/hwtimer/hwtimer.md +++ b/documentation/device/hwtimer/hwtimer.md @@ -1,7 +1,6 @@ -# HWTIMER Device +@page device_hwtimer HWTIMER Device - -## Introduction to the Timer +# Introduction to the Timer Hardware timers generally have two modes of operation, timer mode and counter mode. No matter which mode is operated, it works by counting the pulse signal counted by the internal counter module. Here are some important concepts of timers. @@ -11,7 +10,7 @@ Hardware timers generally have two modes of operation, timer mode and counter mo **Counting frequency**:Since the input frequency is usually fixed, the time it takes for the counter to reach its desired count number can be calculated from just the given frequency - `time = count value / count frequency`. For example, if the counting frequency is 1 MHz, the counter counts once every 1 / 1000000 seconds. That is, every 1 microsecond, the counter is incremented by one (or subtracted by one), at this time, the maximum timing capability of the 16-bit counter is 65535 microseconds, or 65.535 milliseconds. -## Access Hardware Timer Device +# Access Hardware Timer Device The application accesses the hardware timer device through the I/O device management interface provided by RT-Thread. The related interfaces are as follows: @@ -25,7 +24,7 @@ The application accesses the hardware timer device through the I/O device manage | rt_device_read() | to get the current value of the timer | | rt_device_close() | to turn off the timer device. | -### Find Timer Device +## Find Timer Device The application obtains the device handle based on the hardware timer device name, and thus can operate the hardware timer device. The device function is as follows: @@ -49,7 +48,7 @@ rt_device_t hw_dev; /* timer device handle */ hw_dev = rt_device_find(HWTIMER_DEV_NAME); ``` -### Open Timer Device +## Open Timer Device With the device handle, the application can open the device. When the device is open, it will detect whether the device has been initialized. If it is not initialized, it will call the initialization interface to initialize the device by default. Open the device with the following function: @@ -76,7 +75,7 @@ hw_dev = rt_device_find(HWTIMER_DEV_NAME); rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR); ``` -### Set the Timeout Callback Function +## Set the Timeout Callback Function Set the timer timeout callback function with the following function - this is the function that will be called when the timer reaches its set count value: @@ -117,7 +116,7 @@ static int hwtimer_sample(int argc, char *argv[]) } ``` -### Control the Timer Device +## Control the Timer Device By sending control words, the application can configure the hardware timer device with the following function: @@ -189,7 +188,7 @@ static int hwtimer_sample(int argc, char *argv[]) } ``` -### Set the Timer Timeout Value +## Set the Timer Timeout Value The timer timeout value can be set by the following function: @@ -253,7 +252,7 @@ static int hwtimer_sample(int argc, char *argv[]) } ``` -### Obtain the Current Value of the Timer +## Obtain the Current Value of the Timer The current value of the timer can be obtained by the following function: @@ -279,7 +278,7 @@ rt_hwtimerval_t timeout_s; /* Used to save the time the timer has elapsed * rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s)); ``` -### Close the Timer Device +## Close the Timer Device The timer device can be closed with the following function: @@ -310,7 +309,7 @@ rt_device_close(hw_dev); >Timing errors may occur. Assume that the counter has a maximum value of 0xFFFF, a counting frequency of 1Mhz, and a timing time of 1 second and 1 microsecond. Since the timer can only count up to 65535us at a time, the timing requirement for 1000001us can be completed 20 times at 50000us, and the calculation error will be 1us. -## Hardware Timer Device Usage Example +# Hardware Timer Device Usage Example The specific use of the hardware timer device can refer to the following sample code. The main steps of the sample code are as follows: diff --git a/documentation/device/i2c/i2c.md b/documentation/device/i2c/i2c.md index a275e9e803..a1ee1bfe23 100644 --- a/documentation/device/i2c/i2c.md +++ b/documentation/device/i2c/i2c.md @@ -1,6 +1,6 @@ -# I2C Bus Device +@page device_i2c I2C Bus Device -## Introduction of I2C +# Introduction of I2C The I2C (Inter Integrated Circuit) bus is a half-duplex, bidirectional two-wire synchronous serial bus developed by Philips. The I2C bus has only two signal lines, one is the bidirectional data line SDA (serial data), and the other is the bidirectional clock line SCL (serial clock). Compared to the SPI bus, which has two lines for receiving data and transmitting data between the master and slave devices, the I2C bus uses only one line for data transmission and reception. @@ -28,7 +28,7 @@ When the bus is idle, both SDA and SCL are in a high state. When the host wants * **Stop Condition:** When SDA is low, the master pulls SCL high and stays high, then pulls SDA high to indicate the end of the transfer. -## Access to I2C Bus Devices +# Access to I2C Bus Devices In general, the MCU's I2C device communicates as a master and slave. In the RT-Thread, the I2C master is virtualized as an I2C bus device. The I2C slave communicates with the I2C bus through the I2C device interface. The related interfaces are as follows: @@ -37,7 +37,7 @@ In general, the MCU's I2C device communicates as a master and slave. In the RT-T | rt_device_find() | Find device handles based on I2C bus device name | | rt_i2c_transfer() | transfer data | -### Finding I2C Bus Device +## Finding I2C Bus Device Before using the I2C bus device, you need to obtain the device handle according to the I2C bus device name, so that you can operate the I2C bus device. The device function is as follows. @@ -62,7 +62,7 @@ struct rt_i2c_bus_device *i2c_bus; /* I2C bus device handle */ i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name); ``` -### Data Transmission +## Data Transmission You can use `rt_i2c_transfer()` for data transfer by getting the I2C bus device handle. The function prototype is as follows: @@ -144,7 +144,7 @@ static rt_err_t read_regs(struct rt_i2c_bus_device *bus, rt_uint8_t len, rt_uint } ``` -## I2C Bus Device Usage Example +# I2C Bus Device Usage Example The specific usage of the I2C device can be referred to the following sample code. The main steps of the sample code are as follows: diff --git a/documentation/device/pin/pin.md b/documentation/device/pin/pin.md index b0dd95033a..136bfe4f34 100644 --- a/documentation/device/pin/pin.md +++ b/documentation/device/pin/pin.md @@ -1,6 +1,6 @@ -# PIN Device +@page device_pin PIN Device -## Introduction of Pin +# Introduction of Pin The pins on the chip are generally divided into four categories: power supply, clock, control, and I/O. The I/O pins are further divided into General Purpose Input Output (GPIO) and function-multiplexed I/O (such as SPI/I2C/UART, etc.) pins, referring to their usage mode. @@ -16,7 +16,7 @@ Most MCU pins have more than one function. Their internal structure is different * Input modes generally include: Input floating, Input pull-up, Input pull-down, and Analog. When the pin is in the input mode, the level state of the pin can be read, that is, high level or low level. -## Access PIN Device +# Access PIN Device The application accesses the GPIO through the PIN device management interface provided by RT-Thread. The related interfaces are as follows: @@ -29,11 +29,11 @@ The application accesses the GPIO through the PIN device management interface pr | rt_pin_irq_enable() | Enable pin interrupt | | rt_pin_detach_irq() | Detach pin interrupt callback function | -### Obtain Pin Number +## Obtain Pin Number The pin numbers provided by RT-Thread need to be distinguished from the chip pin numbers, which not the same. The pin numbers are defined by the PIN device driver and are related to the specific chip used. There are two ways to obtain the pin number: use the macro definition or view the PIN driver file. -#### Use Macro Definition +### Use Macro Definition If you use the BSP in the `rt-thread/bsp/stm32` directory, you can use the following macro to obtain the pin number: @@ -47,7 +47,7 @@ The sample code for the pin number corresponding to LED0 with pin number PF9 is #define LED0_PIN GET_PIN(F, 9) ``` -#### View Driver Files +### View Driver Files If you use a different BSP, you will need to check the PIN driver code `drv_gpio.c` file to confirm the pin number. There is an array in this file that holds the number information for each PIN pin, as shown below: @@ -70,7 +70,7 @@ static const rt_uint16_t pins[] = Take `__STM32_PIN(2, A, 15)` as an example, 2 is the pin number used by RT-Thread, A is the port number, and 15 is the pin number, so the pin number corresponding to PA15 is 2. -### Set Pin Mode +## Set Pin Mode Before the pin is used, you need to set the input or output mode first, and the following functions are used: @@ -102,7 +102,7 @@ An example of use is as follows: rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT); ``` -### Set The Pin Level +## Set The Pin Level The function to set the pin output level is as follows: @@ -126,7 +126,7 @@ rt_pin_mode(BEEP_PIN_NUM, PIN_MODE_OUTPUT); rt_pin_write(BEEP_PIN_NUM, PIN_LOW); ``` -### Read Pin Level +## Read Pin Level The functions to read the pin level are as follows: @@ -155,7 +155,7 @@ rt_pin_write(BEEP_PIN_NUM, PIN_LOW); status = rt_pin_read(BEEP_PIN_NUM); ``` -### Bind Pin Interrupt Callback Function +## Bind Pin Interrupt Callback Function To use the interrupt functionality of a pin, you can use the following function to configure the pin to some interrupt trigger mode and bind an interrupt callback function to the corresponding pin. When the pin interrupt occurs, the callback function will be executed.: @@ -204,7 +204,7 @@ static void pin_beep_sample(void) } ``` -### Enable Pin Interrupt +## Enable Pin Interrupt After binding the pin interrupt callback function, use the following function to enable pin interrupt: @@ -242,7 +242,7 @@ static void pin_beep_sample(void) } ``` -### Detach Pin Interrupt Callback Function +## Detach Pin Interrupt Callback Function You can use the following function to detach the pin interrupt callback function: @@ -281,7 +281,7 @@ static void pin_beep_sample(void) } ``` -## PIN Device Usage Example +# PIN Device Usage Example The following sample code is the pin device usage example. The main steps of the sample code are as follows: diff --git a/documentation/device/pwm/pwm.md b/documentation/device/pwm/pwm.md index 792078289e..96c9fc2af5 100644 --- a/documentation/device/pwm/pwm.md +++ b/documentation/device/pwm/pwm.md @@ -1,6 +1,6 @@ -# PWM Device +@page device_pwm PWM Device -## Introduction to PWM +# Introduction to PWM PWM (Pulse Width Modulation) is a method of digitally encoding the level of an analog signal. The frequency of the square wave is used to encode the level of a specific analog signal by pulses of different frequencies. The output receives a series of pulses of equal magnitude and uses these pulses to replace the device with the desired waveform. @@ -12,7 +12,7 @@ One of the common PWM control scenarios is to adjust the brightness of a light o ![PWM Brightness Adjustment](figures/pwm-l.png) -## Access to PWM Devices +# Access to PWM Devices The application accesses the PWM device hardware through the PWM device management interface provided by RT-Thread. The related interfaces are as follows: @@ -23,7 +23,7 @@ The application accesses the PWM device hardware through the PWM device manageme | rt_pwm_enable() | Enable PWM device | | rt_pwm_disable() | Disable the PWM device | -### Find the PWM Device +## Find the PWM Device The application obtains the device handle based on the name of PWM device, which in turn can operate the PWM device. The function is as follows: @@ -47,7 +47,7 @@ struct rt_device_pwm *pwm_dev; /* PWM device handle */ pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME); ``` -### Set PWM Period and Pulse Width +## Set PWM Period and Pulse Width Set the PWM period and duty cycle by using the following function: @@ -88,7 +88,7 @@ pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME); rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse); ``` -### Enable the PWM Device +## Enable the PWM Device After setting the PWM period and pulse width, you can enable the PWM device by the following function: @@ -123,7 +123,7 @@ rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse); rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL); ``` -### Disable the PWM device Channel +## Disable the PWM device Channel Use the following function to turn off the corresponding channel of the PWM device. @@ -160,7 +160,7 @@ rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL); rt_pwm_disable(pwm_dev,PWM_DEV_CHANNEL); ``` -## FinSH Command +# FinSH Command To set the period and duty cycle of a channel of a PWM device, use the command `pwm_set pwm1 1 500000 5000`. The first parameter is the command, the second parameter is the PWM device name, the third parameter is the PWM channel, and the fourth parameter is PWM period (ns), the fifth parameter is the pulse width (ns). @@ -183,7 +183,7 @@ msh />pwm_disable pwm1 1 msh /> ``` -## PWM Device Usage Example +# PWM Device Usage Example The following sample code is a PWM device usage sample . The main steps of the sample code are as follows: diff --git a/documentation/device/rtc/rtc.md b/documentation/device/rtc/rtc.md index d01ef76d88..f29f7db41d 100644 --- a/documentation/device/rtc/rtc.md +++ b/documentation/device/rtc/rtc.md @@ -1,13 +1,13 @@ -# RTC Device +@page device_rtc RTC Device -## Introduction of RTC +# Introduction of RTC The RTC (Real-Time Clock) provides accurate real-time clock time, which can be used to generate information such as year, month, day, hour, minute, and second. At present, most real-time clock chips use a higher precision crystal oscillator as a clock source. In order to work when the main power supply is powered down, some clock chips will be powered by a battery to keep the time information valid. The RT-Thread RTC device provides the basic services for the operating system's time system. RTCs find many uses in IoT scenarios, and even in secure transmission processes such as SSL, RTC has become an indispensable part. -## Access RTC Devices +# Access RTC Devices The application accesses the RTC hardware through the RTC device management interface, and the relevant interfaces are as follows: @@ -17,7 +17,7 @@ The application accesses the RTC hardware through the RTC device management inte | set_time() | Set time, hour, minute, second | | time() | Obtain current time | -### Set Date +## Set Date Set the current date value of the RTC device by the following functions: @@ -42,7 +42,7 @@ An example of use is as follows: set_date(2018, 12, 3); ``` -### Set Time +## Set Time Set the current time value of the RTC device by the following function: @@ -67,7 +67,7 @@ An example of use is as follows: set_time(11, 15, 50); ``` -### Obtain Current Time +## Obtain Current Time Obtain time using the time API in the C standard library: @@ -93,9 +93,9 @@ rt_kprintf("%s\n", ctime(&now)); >Currently only one RTC device is allowed in the system and the name is `"rtc"`. -## Functional Configuration +# Functional Configuration -### Enable Soft RTC (Software Emulation RTC) +## Enable Soft RTC (Software Emulation RTC) You can use the function of enabling RTC software emulation, which is ideal for products that do not require high time precision and have no hardware RTC. The configuration options of menuconfig are as follows: @@ -106,7 +106,7 @@ RT-Thread Components → [ ] Using software simulation RTC device /* Use software simulation RTC device */ ``` -### Enable NTP Time Automatic Synchronization +## Enable NTP Time Automatic Synchronization If the RT-Thread is connected to the Internet, you can enable automatic NTP time synchronization to synchronize local time periodically. @@ -131,7 +131,7 @@ RT-Thread Components → (3600) NTP auto sync period(second) /* NTP The synchronization period is automatically synchronized in seconds, and the default period is one hour (ie 3600S). */ ``` -## FinSH Command +# FinSH Command Enter `date` to view the current time. @@ -148,7 +148,7 @@ msh />date 2018 02 16 01 15 30 msh /> ``` -## RTC Device Usage Examples +# RTC Device Usage Examples For the specific usage of the RTC device, refer to the following example code. First, set the year, month, date, hour, minute and second information, and then delay the data for 3 seconds to get the current time information. diff --git a/documentation/device/sensor/sensor.md b/documentation/device/sensor/sensor.md index 68a7fc85ce..4b31c91ee0 100644 --- a/documentation/device/sensor/sensor.md +++ b/documentation/device/sensor/sensor.md @@ -1,6 +1,6 @@ -# Sensor Device +@page device_sensor Sensor Device -## Introduction +# Introduction Sensors are an important part of the Internet of Things, and sensors in an IoT system are equivalent to the eyes of humans. Without eyes, human beings can not see and interpret the world around them. The same is true for the Internet of Things. @@ -8,13 +8,13 @@ Nowadays, with the development of IoT, a large number of sensors are available f The function of the Sensor device is to provide a unified operation interface for the upper layer and improve the reusability of the upper code. -### Characteristics of the Sensor Device +## Characteristics of the Sensor Device - **Interface:** Standard device interface (open/close/read/control) - **Work mode:** Supports polling, interrupts, three FIFO (First In, First Out) modes - **Power mode:** support four modes: power failure, common, low power consumption and high power consumption -## Access Sensor Device +# Access Sensor Device The application accesses the sensor device through the I/O device management interface provided by RT-Thread. The related interfaces are as follows: @@ -27,7 +27,7 @@ The application accesses the sensor device through the I/O device management int | rt_device_set_rx_indicate() | setting reveive callback fuction | | rt_device_close() | close sensor device | -### Find Sensor Device +## Find Sensor Device The application obtains the device handle according to the name of the sensor device, and then can operate the sensor device. The function of finding the device is as follows: @@ -51,7 +51,7 @@ static rt_device_t sensor_dev; /* sensor device handle */ sensor_dev = rt_device_find(SENSOR_DEVICE_NAME); ``` -### Open Sensor Device +## Open Sensor Device Through the device handle, the application can open and close the device. When the device is opened, it will check whether the device has been initialized or not. If it is not initialized, it will call the initialization interface by default. Open the device through the following functions: @@ -107,7 +107,7 @@ int main(void) } ``` -### Control Sensor Device +## Control Sensor Device By command control words, the application program can configure the sensor device through the following functions: @@ -137,7 +137,7 @@ rt_err_t rt_device_control(rt_device_t dev, rt_uint8_t cmd, void* arg); #define RT_SEN_CTRL_SELF_TEST (6) /* selfcheck */ ``` -#### Get device information +### Get device information ```c struct rt_sensor_info info; @@ -149,7 +149,7 @@ LOG_I("intf_type :%d", info.intf_type); LOG_I("period_min:%d", info.period_min); ``` -#### Read Device ID +### Read Device ID ```c rt_uint8_t reg = 0xFF; @@ -157,7 +157,7 @@ rt_device_control(dev, RT_SEN_CTRL_GET_ID, ®); LOG_I("device id: 0x%x!", reg); ``` -#### Setting the measuring range of the sensor +### Setting the measuring range of the sensor The unit that sets the measuring range of the sensor is the unit that is provided when the device is registered. @@ -165,7 +165,7 @@ The unit that sets the measuring range of the sensor is the unit that is provide rt_device_control(dev, RT_SEN_CTRL_SET_RANGE, (void *)1000); ``` -#### Setting the Output Rate of Sensor Data +### Setting the Output Rate of Sensor Data Set the output rate to 100Hz and call the following interface. @@ -173,7 +173,7 @@ Set the output rate to 100Hz and call the following interface. rt_device_control(dev, RT_SEN_CTRL_SET_ODR, (void *)100); ``` -#### Setting up working mode +### Setting up working mode ```c /* Set the working mode to polling mode */ @@ -184,7 +184,7 @@ rt_device_control(dev, RT_SEN_CTRL_SET_MODE, (void *)RT_SEN_MODE_INT); rt_device_control(dev, RT_SEN_CTRL_SET_MODE, (void *)RT_SEN_MODE_FIFO); ``` -#### Setting up power mode +### Setting up power mode ```c /* Set power mode to power-off mode */ @@ -197,7 +197,7 @@ rt_device_control(dev, RT_SEN_CTRL_SET_POWER, (void *)RT_SEN_POWER_LOW); rt_device_control(dev, RT_SEN_CTRL_SET_POWER, (void *)RT_SEN_POWER_HIGH); ``` -#### Device self-inspection +### Device self-inspection ```c int test_res; @@ -205,7 +205,7 @@ int test_res; rt_device_control(dev, RT_SEN_CTRL_SELF_TEST, &test_res); ``` -### Setting Reveive Callback Fuction +## Setting Reveive Callback Fuction Data reception instructions can be set by following functions. When the sensor receives data, it notifies the upper application thread that data arrives: @@ -255,7 +255,7 @@ static int sensor_sample(int argc, char *argv[]) ``` -### Read Data of Sensor Device +## Read Data of Sensor Device The following functions can be called to read the data received by the sensor: @@ -349,7 +349,7 @@ int main(void) } ``` -### Close Sensor Device +## Close Sensor Device When the application completes the sensor operation, the sensor device can be closed by the following functions: @@ -367,7 +367,7 @@ rt_err_t rt_device_close(rt_device_t dev); Closing the device interface and opening the device interface should be used in pairs, opening the primary device should close the primary device, so that the device will be completely closed, otherwise the device is still in an open state. -## Example Code for Sensor Device +# Example Code for Sensor Device The specific use of sensor devices can be referred to the following sample code, the main steps of the sample code are as follows: diff --git a/documentation/device/spi/spi.md b/documentation/device/spi/spi.md index de56a20823..a86a316efc 100644 --- a/documentation/device/spi/spi.md +++ b/documentation/device/spi/spi.md @@ -1,6 +1,6 @@ -# SPI Device +@page device_spi SPI Device -## Introduction to SPI +# Introduction to SPI SPI (Serial Peripheral Interface) is a high-speed, full-duplex, synchronous communication bus commonly used for short-range communication. It is mainly used in EEPROM, FLASH, real-time clock, AD converter, and digital signal processing and between the device and the digital signal decoder. SPI generally uses 4 lines of communication, as shown in the following figure: @@ -34,7 +34,7 @@ The slave's clock is provided by the master through SCLK, and MOSI and MISO comp So for SPI Flash, there are three types of standard SPI Flash, Dual SPI Flash, Quad SPI Flash. At the same clock, the higher the number of lines, the higher the transmission rate. -## Mount SPI Device +# Mount SPI Device The SPI driver registers the SPI bus and the SPI device needs to be mounted to the SPI bus that has already been registered. @@ -84,7 +84,7 @@ static int rt_hw_spi_flash_init(void) INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init); ``` -## Configuring SPI Device +# Configuring SPI Device The SPI device's transmission parameters need to be configured after the SPI device is mounted to the SPI bus. @@ -152,7 +152,7 @@ The example for configuration is as follows: rt_spi_configure(spi_dev, &cfg); ``` -## QSPI Configuration +# QSPI Configuration To configure the transmission parameters of a QSPI device, use the following function: @@ -181,7 +181,7 @@ struct rt_qspi_configuration }; ``` -## Access SPI Device +# Access SPI Device In general, the MCU's SPI device communicates as a master and slave. In the RT-Thread, the SPI master is virtualized as an SPI bus device. The application uses the SPI device management interface to access the SPI slave device. The main interfaces are as follows: @@ -197,7 +197,7 @@ In general, the MCU's SPI device communicates as a master and slave. In the RT-T >The SPI data transfer related interface will call rt_mutex_take(). This function cannot be called in the interrupt service routine, which will cause the assertion to report an error. -### Find SPI Device +## Find SPI Device Before using the SPI device, you need to find and obtain the device handle according to the SPI device name, so that you can operate the SPI device. The device function is as follows. @@ -222,7 +222,7 @@ struct rt_spi_device *spi_dev_w25q; /* SPI device handle */ spi_dev_w25q = (struct rt_spi_device *)rt_device_find(W25Q_SPI_DEVICE_NAME); ``` -### Transfer Custom Data +## Transfer Custom Data By obtaining the SPI device handle, the SPI device management interface can be used to access the SPI device device for data transmission and reception. You can transfer messages by the following function: @@ -298,7 +298,7 @@ rt_spi_transfer_message(spi_dev_w25q, &msg1); rt_kprintf("use rt_spi_transfer_message() read w25q ID is:%x%x\n", id[3], id[4]); ``` -### Transfer Data Once +## Transfer Data Once If only transfer data for once, use the following function: @@ -332,7 +332,7 @@ msg.cs_release = 1; msg.next = RT_NULL; ``` -### Send Data Once +## Send Data Once If only send data once and ignore the received data, use the following function: @@ -366,7 +366,7 @@ msg.cs_release = 1; msg.next = RT_NULL; ``` -### Receive Data Once +## Receive Data Once If only receive data once, use the following function: @@ -400,7 +400,7 @@ msg.cs_release = 1; msg.next = RT_NULL; ``` -### Send Data Twice in Succession +## Send Data Twice in Succession If need to send data of 2 buffers in succession and the CS is not released within the process, you can call the following function: @@ -447,7 +447,7 @@ msg2.cs_release = 1; msg2.next = RT_NULL; ``` -### Receive Data After Sending Data +## Receive Data After Sending Data If need to send data to the slave device first, then receive the data sent from the slave device, and the CS is not released within the process, call the following function to implement: @@ -496,7 +496,7 @@ msg2.next = RT_NULL; The SPI device management module also provides `rt_spi_sendrecv8()` and `rt_spi_sendrecv16()` functions, both are wrapper of the `rt_spi_send_then_recv()`. `rt_spi_sendrecv8()` sends a byte data and receives one byte data, and`rt_spi_sendrecv16()` sends 2 bytes. The section data receives 2 bytes of data at the same time. -## Access QSPI Device +# Access QSPI Device The data transfer interface of QSPI is as follows: @@ -508,7 +508,7 @@ The data transfer interface of QSPI is as follows: >The QSPI data transfer related interface will call rt_mutex_take(). This function cannot be called in the interrupt service routine, which will cause the assertion to report an error. -### Transfer Data +## Transfer Data Transfer messages by the following function: @@ -548,7 +548,7 @@ struct rt_qspi_message }; ``` -### Receive Data +## Receive Data Use the following function to receive data: @@ -573,7 +573,7 @@ rt_err_t rt_qspi_send_then_recv(struct rt_qspi_device *device, The send_buf parameter contains the sequence of commands that will be sent. -### Send Data +## Send Data ```c rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length) @@ -590,11 +590,11 @@ rt_err_t rt_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_si The send_buf parameter contains the sequence of commands and data to be sent. -## Special Usage Scenarios +# Special Usage Scenarios In some special usage scenarios, a device wants to monopolize the bus for a period of time, and the CS is always valid during the period, during which the data transmission may be intermittent, then the relevant interface can be used as shown. The transfer data function must use `rt_spi_transfer_message()`, and this function must set the cs_take and cs_release of the message to be transmitted to 0 value, because the CS has already used other interface control, and does not need to control during data transmission. -### Acquire the SPI bus +## Acquire the SPI bus In the case of multi-threading, the same SPI bus may be used in different threads. In order to prevent the data being transmitted by the SPI bus from being lost, the slave device needs to acquire the right to use the SPI bus before starting to transfer data. To transfer data using the bus, use the following function to acquire the SPI bus: @@ -609,7 +609,7 @@ rt_err_t rt_spi_take_bus(struct rt_spi_device *device); | RT_EOK | Successful | | Other Errors | Failed | -### Select CS +## Select CS After obtaining the usage right of the bus from the device, you need to set the corresponding chip selection signal to be valid. You can use the following function to select the CS: @@ -624,7 +624,7 @@ rt_err_t rt_spi_take(struct rt_spi_device *device); | 0 | Successful | | Other Errors | Failed | -### Add a New Message +## Add a New Message When using `rt_spi_transfer_message()` to transfer messages, all messages to be transmitted are connected in the form of a singly linked list. Use the following function to add a new message to be sent to the message list: @@ -638,7 +638,7 @@ void rt_spi_message_append(struct rt_spi_message *list, | list | Message link node to be transmitted | | message | New message pointer | -### Release CS +## Release CS After the device data transfer is completed, CS need to be released. Use the following function to release the CS: @@ -653,7 +653,7 @@ rt_err_t rt_spi_release(struct rt_spi_device *device); | 0 | Successful | | Other Errors | Failed | -### Release Data Bus +## Release Data Bus The slave device does not use the SPI bus to transfer data. The bus must be released as soon as possible so that other slave devices can use the SPI bus to transfer data. The following function can be used to release the bus: @@ -667,7 +667,7 @@ rt_err_t rt_spi_release_bus(struct rt_spi_device *device); | **Return** | —— | | RT_EOK | Successful | -## SPI Device Usage Example +# SPI Device Usage Example The specific use of the SPI device can be referred to the following sample code. The sample code first finds the SPI device to get the device handle, and then uses the rt_spi_transfer_message() send command to read the ID information. diff --git a/documentation/device/uart/uart.md b/documentation/device/uart/uart.md index 92ca9b4bf8..b7e4c5f35a 100644 --- a/documentation/device/uart/uart.md +++ b/documentation/device/uart/uart.md @@ -1,6 +1,6 @@ -# UART Device +@page device_uart UART Device -## UART Introduction +# UART Introduction UART (Universal Asynchronous Receiver/Transmitter), as a kind of asynchronous serial communication protocol, the working principle is to transmit each character of the transmitted data one by one. It is the most frequently used data bus during application development. @@ -14,7 +14,7 @@ The UART serial port is characterized by sequentially transmitting data one bit - Stop Bit: Indicates the end of one frame of data. The level logic is "1". - Baudrate: It is the rate at which a serial port communicates, which expressed in bits per second (bps) of the binary code transmitted in unit time. The common baud rate values are 4800, 9600, 14400, 38400, 115200, etc. The higher the value is, the faster the data transmission will be. -## Access UART Device +# Access UART Device The application accesses the serial port hardware through the I/O device management interface provided by RT-Thread. The related interfaces are as follows: @@ -29,7 +29,7 @@ The application accesses the serial port hardware through the I/O device managem | rt_device_set_tx_complete() | set send complete callback function | | rt_device_close() | close device | -### Find UART Device +## Find UART Device The application obtains the device handle according to the uart device name, and then can operate the uart device.The device find function is shown below @@ -53,7 +53,7 @@ static rt_device_t serial; /* uart device handle */ serial = rt_device_find(SAMPLE_UART_NAME); ``` -### Open UART Device +## Open UART Device Through the device handle, the application can open and close the device. When the device is opened, it will detect whether the device has been initialized. If it is not initialized, it will call the initialization interface to initialize the device by default. Open the device through the following functions: @@ -114,7 +114,7 @@ serial = rt_device_find(SAMPLE_UART_NAME); rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX); ``` -### Control UART Device +## Control UART Device Through command control word, the application can configure the uart device by the following function: @@ -231,7 +231,7 @@ config.parity = PARITY_NONE; rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &config); ``` -### Send Data +## Send Data To write data to the serial port, the following functions can be used: @@ -267,7 +267,7 @@ rt_device_open(serial, RT_DEVICE_FLAG_INT_RX); rt_device_write(serial, 0, str, (sizeof(str) - 1)); ``` -### Set The Send completion Callback Function +## Set The Send completion Callback Function When the application calls `rt_device_write()` to write data, if the underlying hardware can support automatic transmission, the upper application can set a callback function. This callback function is called after the underlying hardware data has been sent (for example, when the DMA transfer is complete or the FIFO has been written to complete the completion interrupt). You can set the device to send completion instructions by the following function: @@ -284,7 +284,7 @@ rt_err_t rt_device_set_tx_complete(rt_device_t dev, rt_err_t (*tx_done)(rt_devic When this function is called, the callback function is provided by the user. When the hardware device sends the data, the device driver calls back this function and passes the sent data block address buffer as a parameter to the upper application. When the application (thread) receives the indication, it will release the buffer memory block or use it as the buffer for the next write data according to the condition of sending the buffer. -### Set The Receive Callback Function +## Set The Receive Callback Function The data receiving instruction can be set by the following function. When the serial port receives the data, it will inform the upper application thread that the data has arrived: @@ -337,7 +337,7 @@ static int uart_sample(int argc, char *argv[]) ``` -### Receive Data +## Receive Data You can call the following function to read the data received by the uart: @@ -383,7 +383,7 @@ static void serial_thread_entry(void *parameter) } ``` -### Close The UART Device +## Close The UART Device After the application completes the serial port operation, the uart device can be closed by the following functions: @@ -401,9 +401,9 @@ rt_err_t rt_device_close(rt_device_t dev); Use the `rt_device_close()` interface and `rt_device_open()` interface in pair. When you open the device, you need to close the device once, so that the device will be completely shut down, otherwise the device will remain open. -## Examples Of Using UART Device +# Examples Of Using UART Device -### Interrupt Receiving And Polling Send +## Interrupt Receiving And Polling Send The main steps of the sample code are as follows: @@ -512,7 +512,7 @@ static int uart_sample(int argc, char *argv[]) MSH_CMD_EXPORT(uart_sample, uart device sample); ``` -### DMA Reception And Polling Transmission +## DMA Reception And Polling Transmission When the serial port receives a batch of data, it will call the receive callback function. The receive callback function will send the data size of the buffer at this time to the waiting data processing thread through the message queue. After the thread gets the message, it is activated and reads the data. In general, the DMA receive mode completes data reception in conjunction with the DMA receive completion interrupt and the serial port idle interrupt. diff --git a/documentation/device/watchdog/watchdog.md b/documentation/device/watchdog/watchdog.md index e300f5a798..4f0273643b 100644 --- a/documentation/device/watchdog/watchdog.md +++ b/documentation/device/watchdog/watchdog.md @@ -1,6 +1,6 @@ -# WATCHDOG Device +@page device_watchdog WATCHDOG Device -## An Introduction to WATCHDOG +# An Introduction to WATCHDOG The hardware watchdog timer is a timer whose timing output is connected to the reset terminal of the circuit. In a productized embedded system, in order to automatically reset the system under abnormal conditions, it generally needs a watchdog. @@ -8,7 +8,7 @@ When the watchdog was started, the counter starts counting automatically. If it In general, users can feed the dog in the idlehook function and key function of RT-Thread. -## Access to the WATCHDOG Device +# Access to the WATCHDOG Device The application accesses the watchdog hardware through the I/O device management interface provided by RT-Thread. The related interfaces are as follows: @@ -19,7 +19,7 @@ The application accesses the watchdog hardware through the I/O device management | rt_device_control() |Control the watchdog device | | rt_device_close() | Close the watchdog device | -### Find the Watchdog Device +## Find the Watchdog Device The application obtains the device handle based on the watchdog device's name, and then it can operate the watchdog device. The function for finding a device is as follows: @@ -44,7 +44,7 @@ static rt_device_t wdg_dev; /* device handle of the watchdog */ wdg_dev = rt_device_find(IWDG_DEVICE_NAME); ``` -### Initialize the Watchdog Device +## Initialize the Watchdog Device The watchdog device need to be initialized before using, which can be done by the following function: @@ -73,7 +73,7 @@ wdg_dev = rt_device_find(IWDG_DEVICE_NAME); rt_device_init(wdg_dev); ``` -### Control the Watchdog Device +## Control the Watchdog Device The application can configure the watchdog device using the command control word, which can be done by the following function: @@ -130,7 +130,7 @@ static void idle_hook(void) } ``` -### Close the Watchdog Device +## Close the Watchdog Device When the application completes the operation of the watchdog, it can close the watchdog device: @@ -148,7 +148,7 @@ rt_err_t rt_device_close(rt_device_t dev); Closing the device interface and opening the device interface need to match each other. When you open the device, you need to close the device once correspondingly, so that the device will be completely shut down, otherwise the device will remain unclosed. -## Watchdog Device usage example +# Watchdog Device usage example The specific use of the watchdog device can be referred to the following sample code. The main steps of the sample code are as follows: diff --git a/documentation/device/wlan/wlan.md b/documentation/device/wlan/wlan.md index cbde241ea4..36fd1461de 100644 --- a/documentation/device/wlan/wlan.md +++ b/documentation/device/wlan/wlan.md @@ -1,8 +1,8 @@ -# WLAN Device +@page device_wlan WLAN Device With the rapid development of the Internet of Things, more and more embedded devices are equipped with WIFI wireless network devices. In order to be able to manage WIFI network devices, RT-Thread introduces a WLAN device management framework. This framework has many features to control and manage WIFI, providing developers with many conveniences for using WIFI devices. -## Introduction to the WLAN Framework +# Introduction to the WLAN Framework The WLAN framework is a set of middleware developed by RT-Thread for managing WIFI. Connect to the specific WIFI driver, control the WIFI connection disconnection, scan and other operations. Support different applications, provide WIFI control, events, data diversion and other operations for the application, and provide a unified WIFI control interface for the upper application. The WLAN framework consists of three main parts. The DEV driver interface layer provides a unified API for the WLAN framework. Manage layer provides users with specific functions such as WIFI scanning, connection, and disconnection. Protocol is responsible for processing the data stream generated on the WIFI. Different protocols such as LWIP can be mounted according to different usage scenarios. It has the characteristics of simple use, complete functions, convenient docking and strong compatibility. @@ -22,14 +22,14 @@ The Fifth Part: `WLAN Config`, the parameter management layer. Manage hotspot in The Sixth Part: `WLAN Device`, the driver interface layer. Connect to specific WLAN hardware and provide unified APIs for management. -### Functions +## Functions * Automatic Connection: After using automatic connection function, as long as the WIFI is disconnected, the hotspot information of the previous successful connection will be automatically read, and the hotspot will be connected. If a hotspot connection fails, switch to the next hotspot to connect until the connection is successful. The hotspot information used by the automatic connection is sequentially tried in the order of the success of the connection, and the hotspot information of the latest connection success is preferentially used. After the connection is successful, the hotspot information is cached first, and use it first when reconnecting after the next disconnection. * Parameter storage: Stores the WIFI parameters for successful connection. The WIFI parameter will be cached in the memory. If the external non-volatile storage interface is configured, it will be stored in the external storage medium. Users can implement the `struct rt_wlan_cfg_ops` structure according to his actual situation and save the parameters anywhere. The cached parameters mainly provide hotspot information for automatic connections. When WIFI is unconnected, it will read the cached parameters and try to connect. * WIFI control: Provide complete WIFI control APIs, scanning, connection, hotspot, etc. Provide WIFI related status callback events, disconnect, connection, connection failure, etc. Provide users with an easy to use WIFI management APIs. * Shell command: You can enter the command in Msh to control WIFI to perform scanning, connecting, disconnecting and other actions. Print debugging information such as WIFI status. -### Configuration +## Configuration Use `menuconfig` command in ENV to enter the WLAN configuration interface by following the menu: @@ -58,7 +58,7 @@ Configuration options are described in detail as follows: [ ] Enable WLAN Debugging Options /* Enable WLAN Debugging Options */ ``` -## Access Wi-Fi Devices +# Access Wi-Fi Devices The application accesses the WLAN device hardware through the WLAN device management interface, and the relevant interfaces are as follows: @@ -70,7 +70,7 @@ The application accesses the WLAN device hardware through the WLAN device manage | rt_wlan_disconnect() | Synchronized Hotspot Disconnection | | rt_wlan_config_autoreconnect() | Configuration automatic reconnection mode | -### Specify Protocol +## Specify Protocol ```c rt_err_t rt_wlan_prot_attach(const char *dev_name, const char *prot_name); @@ -84,7 +84,7 @@ rt_err_t rt_wlan_prot_attach(const char *dev_name, const char *prot_name); | -RT_ERROR | Execution failed | | RT_EOK | Execution succeed | -### Synchronized WLAN Scan +## Synchronized WLAN Scan ```c struct rt_wlan_scan_result *rt_wlan_scan_sync(void); @@ -104,7 +104,7 @@ struct rt_wlan_scan_result }; ``` -### Synchronized Hotspot Connection +## Synchronized Hotspot Connection ```c rt_err_t rt_wlan_connect(const char *ssid, const char *password); @@ -120,7 +120,7 @@ rt_err_t rt_wlan_connect(const char *ssid, const char *password); | -RT_ERROR | Connection failed | | RT_EOK | Connection successful | -### Synchronized Hotspot Disconnection +## Synchronized Hotspot Disconnection ```c rt_err_t rt_wlan_disconnect(void); @@ -133,7 +133,7 @@ rt_err_t rt_wlan_disconnect(void); | -RT_ERROR | Disconnection failed | | RT_EOK | Disconnection successful | -### Automatic Reconnection Mode Configuration +## Automatic Reconnection Mode Configuration ```c void rt_wlan_config_autoreconnect(rt_bool_t enable); @@ -143,7 +143,7 @@ void rt_wlan_config_autoreconnect(rt_bool_t enable); | ----------------------------- | ---------------------------------- | | enable | enable or disable automatic reconnection | -## FinSH Command +# FinSH Command Using shell commands can help us quickly debug WiFi-related features. The wifi related shell commands are as follows: @@ -159,7 +159,7 @@ wifi status /* Print wifi status sta + ap */ wifi smartconfig /* Start to configure network function */ ``` -### WiFi Scan +## WiFi Scan The wifi scan command is `wifi scan`. After the wifi scan command is executed, the surrounding hotspot information will be printed on the terminal. Through the printed hotspot information, you can see multiple attributes such as SSID and MAC address. @@ -175,7 +175,7 @@ rtt_test_ssid_2 ec:88:8f:88:aa:9a WPA2_MIXED_PSK -47 6 144 rtt_test_ssid_3 c0:3d:46:00:41:ca WPA2_MIXED_PSK -48 3 300 ``` -### WiFi Connection +## WiFi Connection The wifi scan command is `wifi join`. The command needs to be followed by the hotspot name and hotspot password. If the hotspot does not have a password, you may not enter this item. After the WiFi connection command is executed, if the hotspot exists and the password is correct, the board will connect to the hotspot and obtain the IP address. After the network connection is successful, you can use `socket` sockets for network communication. @@ -187,7 +187,7 @@ wifi join ssid_test 12345678 [I/WLAN.lwip] Got IP address : 192.168.1.110 ``` -### WiFi Disconnection +## WiFi Disconnection The command to disconnect WiFi is `wifi disc`. After the WiFi disconnect command is executed, the development board will disconnect from the hotspot. @@ -198,9 +198,9 @@ wifi disc [I/WLAN.mgnt] disconnect success! ``` -## Example for WLAN Device Usage +# Example for WLAN Device Usage -### WiFi Scan +## WiFi Scan The following code will show a WiFi sync scan, and then print the results on the terminal. First perform WIFI initialization, and then execute the WIFI scan function `rt_wlan_scan_sync`, this function is synchronous, the number of scans and results returned by the function. In this example, the scanned hotspot name will be printed. @@ -241,7 +241,7 @@ The results are as follows: ![Scan](figures/an0026_3.png) -### WiFi Connection and Disconnection +## WiFi Connection and Disconnection The code below will show a WiFi sync connection. Initialize WIFI first, and then create a semaphore for waiting for the `RT_WLAN_EVT_READY` event. Register the callback function of the event that needs attention, execute the `rt_wlan_connect` wifi connection function, and return value will indicate whether the connection has been successful. If the WiFi connection succeeds, it needs to wait for the network to get the IP address before communication. Use the semaphore created in advance to wait for the network to be ready. Once the network is ready, it will be able to communicate. @@ -364,7 +364,7 @@ The results are as follows: ![Disconnection](figures/an0026_4.png) -### WiFi Auto Reconnection when Turn On +## WiFi Auto Reconnection when Turn On First enable the automatic reconnection function, use the command line to connect to the hotspot A, and connect another hotspot B. After waiting for a few seconds, power off hotspot B, the system will automatically retry connecting B hotspot. At this time, B hotspot connection can not be connected, and the system automatically switches hotspot A to connect. After the connection is successful, the system stops connecting. diff --git a/documentation/dlmodule/README.md b/documentation/dlmodule/README.md index de6b1928a9..1ffa5ad328 100644 --- a/documentation/dlmodule/README.md +++ b/documentation/dlmodule/README.md @@ -1,10 +1,10 @@ -# Dynamic Module: dlmodule # +@page component_dlmodule Dynamic Module: dlmodule In traditional desktop operating systems, user space and kernel space are separate. The application runs in user space, and the kernel and kernel modules run in kernel space. The kernel module can be dynamically loaded and deleted to extend the kernel functionality. `dlmodule` is a software component of the dynamic module loading mechanism provided in kernel space of RT-Thread. In versions of RT-Thread v3.1.0, this was also called the `Application Module`. After RT-Thread v3.1.0 and later, it returned to the tradition and was named after the `dynamic module`. `dlmodule` is more of an ELF format loader. The code segment and data segment of a separately compiled elf file are loaded into memory, and the symbols are parsed and bound to the API address exported by the kernel. The elf files are primarily placed on file systems under RT-Thread. -## Introduction ## +# Introduction The dynamic module provides a mechanism for dynamically loading program modules for RT-Thread. Because it is also compiled independently of the kernel, it is more flexible to use. In terms of implementation, this is a mechanism to separate the kernel from the dynamic modules. Through this mechanism, the kernel and dynamic modules can be compiled separately, and at runtime, the compiled dynamic modules are loaded into the kernel through the module loader in the kernel. @@ -15,11 +15,11 @@ In the dynamic module of RT-Thread, two formats are currently supported: The current RT-Thread architecture supporting dynamic modules mainly includes ARM architecture and x86 architecture, and will be extended to MIPS and RISC-V architecture in the future. The RT-Thread kernel firmware section can use a variety of compiler toolchains, such as GCC, ARMCC, IAR and other toolchains; however, dynamic module partial compilation currently only supports GNU GCC toolchain compilation. Therefore, compiling the RT-Thread module requires downloading GCC tools, such as CodeSourcery's arm-none-eabi toolchain. In general, it's best to use kernel and dynamic modules to compile with the same toolchain (so that it doesn't produce inconsistent behavior in *libc*). In addition, dynamic modules can only be loaded into RAM and used for symbol resolution binding to the API address exported by the kernel. Instead of running directly in XIP mode based on Flash (because Flash can't modify the code segment again). -## Using Dynamic Module ## +# Using Dynamic Module When you want to use the dynamic modules in your system, you need to compile a firmware that supports dynamic modules, as well as dynamic modules that need to be run. The following two parts are compiling firmware and compiling dynamic modules. -### Compile Firmware ### +## Compile Firmware When you want to use the dynamic module, you need to open the corresponding option in the firmware configuration, use menuconfig to open the following configuration: @@ -82,7 +82,7 @@ Then execute the `scons` under the BSP project directory and generate the firmwa to generate the kernel header file search path and global macro definitions that need to be included when compiling the dynamic module. -### Compile Dynamic Module ### +## Compile Dynamic Module There is a separate repository on github: [rtthread-apps](https://github.com/RT-Thread/rtthread-apps) , which contains some examples of dynamic modules and dynamic libraries. @@ -151,11 +151,11 @@ int main(int argc, char *argv[]) } ``` -## APIs of Dynamic Module +# APIs of Dynamic Module In addition to dynamically loading and executing dynamic modules via msh, dynamic modules can be loaded or unloaded using the dynamic module API provided by RT-Thread in the main program. -### Load Dynamic Module +## Load Dynamic Module ```c struct rt_dlmodule *dlmodule_load(const char* pgname); @@ -170,7 +170,7 @@ struct rt_dlmodule *dlmodule_load(const char* pgname); This function loads the dynamic module from the file system into memory, and if it is loaded correctly, returns a pointer to the module. This function does not create a thread to execute this dynamic module, just load the module into memory and parse the symbolic address. -### Execute Dynamic Module +## Execute Dynamic Module ```c struct rt_dlmodule *dlmodule_exec(const char* pgname, const char* cmd, int cmd_size); @@ -187,7 +187,7 @@ struct rt_dlmodule *dlmodule_exec(const char* pgname, const char* cmd, int cmd_s This function loads the dynamic module according to the `pgname` path and starts a thread to execute `main` of the dynamic module. At the same time, `cmd` is passed as the command line Parameter to `main` entry of the dynamic module. -### Exit Dynamic Module +## Exit Dynamic Module ```c void dlmodule_exit(int ret_code); @@ -199,7 +199,7 @@ void dlmodule_exit(int ret_code); This function is called by the module runtime, it can set the return value of the module exit `ret_code`, and then exit from the module. -### Find Dynamic Modules +## Find Dynamic Modules ```c struct rt_dlmodule *dlmodule_find(const char *name); @@ -214,7 +214,7 @@ struct rt_dlmodule *dlmodule_find(const char *name); This function uses `name` to find out if there is already a dynamic module loaded in the system. -### Return Dynamic Module +## Return Dynamic Module ```c struct rt_dlmodule *dlmodule_self(void); @@ -227,7 +227,7 @@ struct rt_dlmodule *dlmodule_self(void); This function returns a pointer of the dynamic module in the calling context. -### Find Symbol +## Find Symbol ```c rt_uint32_t dlmodule_symbol_find(const char *sym_str); @@ -242,11 +242,11 @@ rt_uint32_t dlmodule_symbol_find(const char *sym_str); This function returns the symbol address based on the symbol name. -## Libdl API of POSIX Standard ## +# Libdl API of POSIX Standard The POSIX standard libdl API is also supported in RT-Thread dlmodule. It is similar to loading a dynamic library into memory (and parsing some of the symbol information). This dynamic library provides the corresponding set of function operations. The libdl API needs to include the header files: `#include ` -### Open Dynamic Library +## Open Dynamic Library ```c void * dlopen (const char * pathname, int mode); @@ -262,7 +262,7 @@ void * dlopen (const char * pathname, int mode); This function is similar to the `dlmodule_load` , which loads the dynamic library from the file system and returns the handle pointer of the dynamic library. -### Find Symbol +## Find Symbol ```c void* dlsym(void *handle, const char *symbol); @@ -278,7 +278,7 @@ void* dlsym(void *handle, const char *symbol); This function looks in the dynamic library `handle` for the presence of the symbol of `symbol` , if there is an address that returns it. -### Close Dynamic Library +## Close Dynamic Library ``` int dlclose (void *handle); @@ -293,15 +293,15 @@ int dlclose (void *handle); This function closes the dynamic library pointed to by `handle` and unloads it from memory. It should be noted that when the dynamic library is closed, the symbolic address originally returned by `dlsym` will no longer be available. If you still try to access it, it may cause a fault error. -## FAQs +# FAQs -Please refer to [*User Manual of Env*](../env/env.md) for issues related to the Env tool. +Please refer to @ref env for issues related to the Env tool. -### Q: Dynamic modules cannot be run successfully according to the documentation. +## Q: Dynamic modules cannot be run successfully according to the documentation. **A:** Please update the RT-Thread source code to version 3.1.0 and above. -### Q: Compile the project with the scons command, prompting "undefined reference to __rtmsymtab_start". +## Q: Compile the project with the scons command, prompting "undefined reference to __rtmsymtab_start". **A:** Please refer to the qemu-vexpress-a9 BSP GCC link script file *link.lds* to add the following to the TEXT section of the project's GCC link script. diff --git a/documentation/doxygen/.gitignore b/documentation/doxygen/.gitignore deleted file mode 100644 index fe056cc69f..0000000000 --- a/documentation/doxygen/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -html/ -latex/ \ No newline at end of file diff --git a/documentation/doxygen/readme.md b/documentation/doxygen/readme.md deleted file mode 100644 index 5228645937..0000000000 --- a/documentation/doxygen/readme.md +++ /dev/null @@ -1,48 +0,0 @@ -# How to build doxygen html - -1. download from https://doxygen.nl/index.html -2. open `Doxywizard` -3. `File` -> `Open` -4. Open the file ./Doxyfile -5. To tab `Run` , Click `Run doxygen` - -# How to build & run doxygen html on Ubuntu - -The following steps are verified on Ubuntu 22.04: - -```shell -$ lsb_release -a -No LSB modules are available. -Distributor ID: Ubuntu -Description: Ubuntu 22.04.5 LTS -Release: 22.04 -Codename: jammy -``` - -The following packages (and dependents) need to be installed: - -```shell -$ sudo apt update -$ sudo apt install doxygen -$ sudo apt install graphviz -``` - -Assume that the path of RT-Thead code tree is $RTT, execute the following command to build html. - -```shell -$ cd $RTT/documentation/doxygen -$ rm -rf html -$ doxygen -``` - -A new html directory will be created and all the html files will be placed in this directory. - -If you want to quickly browse HTML locally (in Ubuntu environment), you can enter the html directory and start a local HTML server through Python. - -```shell -$ cd html -$ python3 -m http.server -Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... -``` - -Open the browser and enter `http://:8000/index.html` to access the created html web pages. If it is a local access, then `` should be replaced by `localhost`. If it is a remote access, then `` should be replaced by the actual accessible IP address of the machine where HTML is located. diff --git a/documentation/env/env.md b/documentation/env/env.md index 3f2daaf4b8..a8ca57f420 100644 --- a/documentation/env/env.md +++ b/documentation/env/env.md @@ -1,4 +1,4 @@ -# User Manual of Env +@page env User Manual of Env Env is a handy utility tool developed by RT-Thread team to build environment, graphical system configuration, and packages management for software projects that intend to run on RT-Thread operating system. Env tool come with source code builder, compilation environment and package management system. @@ -6,7 +6,7 @@ It is a wrapper tool for build-in menuconfig, which is an open source GUI tool w Env for Windows repository: https://github.com/RT-Thread/env-windows -## Main Features +# Main Features - menuconfig provides graphical interface to interact with operational logic and configuration parameters - Each configuration option come with help session by default. @@ -16,24 +16,24 @@ Env for Windows repository: https://github.com/RT-Thread/env-windows - Modular software packages and decoupling design make it easier to maintain. - It also featured with point and click to download additional software packages and dependencies directly from Internet. -## Download +# Download - [Download the Env tool](https://github.com/RT-Thread/env-windows/releases), e.g. `env-windows-v1.3.5.7z`. - Extract the .7z file and the path shouldn't contain any non-ascii or space characters. -## User Guide of Env +# User Guide of Env -### Open the control Console +## Open the control Console The rt-thread software package environment is mainly based on the command line console so that the rt-thread development environment can be set up by minimizing the modification of configuration files. There are two ways to open the console: -#### 1. click the Env directory executable file +### 1. click the Env directory executable file To enter the Env directory, you can run `env.exe` in this directory. If it fails to open, you can try to use `env.bat`. -#### 2. open the Env console from the right-click menu in the folder +### 2. open the Env console from the right-click menu in the folder Add Env to the right-click menu: @@ -49,11 +49,11 @@ Follow the steps from the image to launch the Env console from the right-click m > Due to the need for the environment variables of the Env process to be set, the anti-virus software may misreport at the first startup. If the anti-virus software misreport is encountered, allow Env related programs to run, and then add related programs to the white list. -### Compile +## Compile Scons is a compile building tool used by RT-Thread to compile RT-Threads using the scons related commands. -#### Step One: Switch to the BSP root directory +### Step One: Switch to the BSP root directory If you use Method 1 to open Env console, you need to switch to the target BSP using the `cd` command. @@ -61,11 +61,11 @@ For example, the target BSP is `rt-thread\bsp\stm32\stm32f103-dofly-lyc8`: ![stm32f429-apollo project directory](figures/cd_cmd.png) -#### Step Two: Compile the BSP +### Step Two: Compile the BSP Env for Windows carries Python2.7 & Scons . To compile BSP, just use the default ARM_GCC toolchain by running `scons` or `scons -j12` (12 CPU cores compiling) command in the target BSP directory. -Env for Windows carries ARM GCC toolchain by default. When users compile ARM BSPs, users can directly type `scons` or `scons -j12` command to compile the BSP. However, if the BSP is other architecture, e.g. RISC-V, users need to use `scons --exec-path='C:\xxx\sdk-toolchain-RISC-V-GCC-WCH-1.0.0\bin' -j12` command to specify the toolchain when compiling. +Env for Windows carries ARM GCC toolchain by default. When users compile ARM BSPs, users can directly type `scons` or `scons -j12` command to compile the BSP. However, if the BSP is other architecture, e.g. RISC-V, users need to use `scons --exec-path='C:\\xxx\\sdk-toolchain-RISC-V-GCC-WCH-1.0.0\\bin' -j12` command to specify the toolchain when compiling. ![compilation project using scons command](figures/use_scons.png) @@ -82,30 +82,30 @@ scons --target=mdk4 scons --target=mdk5 ``` -For more scons tutorials, please refer to [*Scons*](../scons/scons.md). +For more scons tutorials, please refer to @ref scons. -### BSP configuration: menuconfig +## BSP configuration: menuconfig Menuconfig is a graphical configuration tool that RT-Thread uses to configure and tailor the entire system. -#### Instruction for Shortcuts +### Instruction for Shortcuts Go to the BSP root directory and open the interface by entering `menuconfig`. The menuconfig common shortcuts are as shown: ![Commonly-used Shortcuts for menuconfig](figures/hotkey.png) -#### Modify Settings +### Modify Settings There are many types of configuration items in menuconfig, and the modification methods are different. The common types are: - On/Off Type: Use the space bar to select or close - Value, string type: After pressing the Enter key, a dialog box will appear, and the configuration items will be modified in the dialog box. -#### Save Settings +### Save Settings After selecting the configuration item, press `ESC` to exit, and select `Save` to automatically generate the `rtconfig.h` file. At this point, using the `scons` command again will recompile the project according to the new rtconfig.h file. -### Package Management +## Package Management RT-Thread provides a package management platform where the officially available or developer-supplied packages are stored. The platform provides developers with a choice of reusable software packages that are an important part of RT-Thread. @@ -141,7 +141,7 @@ optional arguments: --printenv print environmental variables to check ``` -#### Download, update, and delete packages +### Download, update, and delete packages Before downloading and updating the software package, you need to **open** the target package in `menuconfig`. @@ -155,13 +155,13 @@ Find the package you need and open, then save and exit menuconfig. The package w - **update**: if the selected package has a latest update on the server and the version is selected **latest**, then enter `pkgs --update` , the package will be updated in local; - **delete**: if a software package is not needed, deselect it in menuconfig and then use `pkgs --update` command. Then locally downloaded but unselected packages will be deleted. -#### Update local package information and index +### Update local package information and index As the package system grows, more and more packages will be added, so the list of packages in menuconfig may be **unsynchronized** with the server. This can be fixed by using `pkgs --upgrade` or `pkgs --upgrade-force` command (recommended), which not only synchronizes updates to local software packages [information and index](https://github.com/RT-Thread/packages), which are recommended for regular use. If there is a upgrade failure or merge failure, please use `pkgs --upgrade-force` command to force upgrade the local software packages index (recommended to use). If wants to upgrade the [Env script](https://github.com/RT-Thread/env) as well, please use `pkgs --upgrade-script-force` command. This command not only can upgrade the software packages index, but also can upgrade the Env script. -### Env Tool Configuration +## Env Tool Configuration - The new version of the Env tool includes an automatic update package and an option to automatically generate mdk/iar projects. The default is not enabled. It can be configured using `menuconfig -s/--setting` . @@ -180,13 +180,13 @@ The three options are: - **Send usage data for improve product**: For user number statistic. -## Use Env in Your Project +# Use Env in Your Project -### How to Modify Options in Menuconfig +## How to Modify Options in Menuconfig If you want to add a macro definition in the configuration item of menuconfig, you can modify the `Kconfig` file under BSP. The modification method can search Kconfig syntax on the Internet for detailed documentation, or refer to the Kconfig file in RT-Thread or The Kconfig file in the BSP that supports menuconfig. -### To Add menuconfig function to New Project +## To Add menuconfig function to New Project New project here refers to a newly developed project that has not yet generated `.config` and `rtconfig.h`. Because these two files are only created when menuconfig is first saved. The specific process is as follows: @@ -194,7 +194,7 @@ New project here refers to a newly developed project that has not yet generated 2. Note that modifying the RTT_ROOT value in Kconfig is the directory where RT-Thread is located, otherwise RTT_ROOT may be not found. 3. Start the configuration with the menuconfig command. -### To Add menuconfig function to old Project +## To Add menuconfig function to old Project Old project here refers to the development that has been going on for a while, and there is a modified `rtconfig.h` file in the project, but there is no project configured with menuconfig. The specific process is as follows: @@ -205,41 +205,41 @@ Old project here refers to the development that has been going on for a while, a 5. Use the menuconfig command to configure the old project we want to modify. Menuconfig will read the `.config` file generated in the second step and generate a new `.config` file and rtconfig.h file based on the configuration parameters of the old project. 6. Check the old and new rtconfig.h files. If there are any inconsistencies, you can use the menuconfig command to adjust the configuration items. -## Notes for Using Env +# Notes for Using Env - For the first time, Env is recommended to go to the official website to download the latest version of the Env tool. The new version of Env will have better compatibility and also support automatic update commands. - You can use the Env built-in command `pkgs --upgrade` or `pkgs --upgrade-force` (recommended to use) to update the package list and Env's function code to minimize the problems you have fixed. - Do not have Chinese or spaces in the routes of Env. - Do not have Chinese or spaces in the routes where the BSP project is located. -## FAQs +# FAQs -### Q: It prompts that the git command cannot be found. +## Q: It prompts that the git command cannot be found. 'git' is not recognized as an internal or external command, possible program or batch file. **A:** Git is not installed. You need to install git and add environment variables. -### Q: It prompts that the CMD command cannot be found. +## Q: It prompts that the CMD command cannot be found. **A:** Right-click–>> Property—>> Advanced System Settings—>> Environment Variable, Add `C:\Windows\System32` to system environment variables. -### Q: Prompt "no module named site" when running python. +## Q: Prompt "no module named site" when running python. **A:** Computer right button –>> Properties—>> Advanced System Settings—>> Environment Variable, in the user variable of the administrator, create a new variable named PYTHONHOME, and the variable value is: `F:\git_repositories\env\tools\Python27` (the installation route of Python in Env), do not add ";" afterwards, otherwise it will be invalid. If add PYTHONHOME can not solve theproblem, try to add PYTHONPATH in the same way. -### Q: What types of projects can I generate under Env? +## Q: What types of projects can I generate under Env? **A:** 1. Currently, you can use the scons tool to generate mdk/iar projects under Env. There is no automatic generation of eclipse projects. 2. Generally, using gcc's toolchain, using an editor such as source insight or VS Code to edit the code and compile with `scons` command. -### Q:How can my own BSP support menuconfig? +## Q: How can my own BSP support menuconfig? **A:** You can refer to this chapter **Use Env in Your Project**. -### Q: What is the difference between the pkgs --upgrade/--upgrade-force command and the pkgs --update command? +## Q: What is the difference between the pkgs --upgrade/--upgrade-force command and the pkgs --update command? **A:** @@ -247,11 +247,11 @@ Old project here refers to the development that has been going on for a while, a 2. The `pkgs --update` command is used to update the package itself. For example, if you selected json and mqtt packages in menuconfig, you did not download them when you exit menuconfig. You need to use the `pkgs --update` command, at which point Env will download the package you selected and add it to your project. 3. The new version of Env supports the `menuconfig -s/--setting` command. If you don't want to use the `pkgs --update` command after replacing the package, configure Env after using the `menuconfig -s/--setting` command. Select each time you use menuconfig. After the package is automatically updated. -### Q: Prompt "can't find file Kconfig" while using menuconfig. +## Q: Prompt "can't find file Kconfig" while using menuconfig. **A:** The Kconfig file is missing from the current working BSP directory. Please refer *To Add menuconfig function to New Project* and *To Add menuconfig function to Old Project*. -### Q: There's unintelligible texts appear in Env. +## Q: There's unintelligible texts appear in Env. **A:** First check if there is a Chinese route. diff --git a/documentation/filesystem/README.md b/documentation/filesystem/README.md index 15a2601487..6fef5c1670 100644 --- a/documentation/filesystem/README.md +++ b/documentation/filesystem/README.md @@ -1,17 +1,17 @@ -# Virtual File System +@page component_vfs Virtual File System In early days, the amount of data to be stored in embedded systems was relatively small and data types were relatively simple. The data were stored by directly writing to a specific address in storage devices. However, with today modern technology, embedded device's functions are getting complicated and required more data storage. Therefore, we need new data management methods to simplify and organize the data storage. A file system is made up of abstract data types and also a mechanism for providing data access, retrieve, implements, and store them in hierarchical structure. A folder contains multiple files and a file contains multiple organized data on the file system. This chapter explains about the RT-Thread file system, architecture, features and usage of virtual file system in RT-Thread OS. -## An Introduction to DFS +# An Introduction to DFS Device File System (DFS) is a virtual file system component and name structure is similar to UNIX files and folders. Following is the files and folders structure: The root directory is represented by "/". For example, if users want to access to f1.bin file under root directory, it can be accessed by "/f1.bin". If users want to access to f1.bin file under /2019 folder, it can be accessed by "/data/2019/f1.bin" according to their folder paths as in UNIX/Linux unlike Windows System. -### The Architecture of DFS +## The Architecture of DFS The main features of the RT-Thread DFS component are: @@ -23,7 +23,7 @@ The hierarchical structure of DFS is shown in the following figure, which is mai ![The hierarchical structure of DFS](figures/fs-layer.png) -### POSIX Interface Layer +## POSIX Interface Layer POSIX stands for Portable Operating System Interface of UNIX (POSIX). The POSIX standard defines the interface standard that the operating system should provide for applications. It is a general term for a series of API standards defined by IEEE for software to run on various UNIX operating systems. @@ -33,7 +33,7 @@ On UNIX-like systems, normal files, device files, and network file descriptors a Using the `poll/select` interface to block and simultaneously detect whether a group of I/O devices which support non-blocking have events (such as readable, writable, high-priority error output, errors, etc.) until a device trigger the event was or exceed the specified wait time. This mechanism can help callers find devices that are currently ready, reducing the complexity of programming. -### Virtual File System Layer +## Virtual File System Layer Users can register specific file systems to DFS, such as FatFS, RomFS, DevFS, etc. Here are some common file system types: @@ -44,13 +44,13 @@ Users can register specific file systems to DFS, such as FatFS, RomFS, DevFS, et * NFS (Network File System) is a technology for sharing files over a network between different machines and different operating systems. In the development and debugging phase of the operating system, this technology can be used to build an NFS-based root file system on the host and mount it on the embedded device, which can easily modify the contents of the root file system. * UFFS is short for Ultra-low-cost Flash File System. It is an open source file system developed by Chinese people and used for running Nand Flash in small memory environments such as embedded devices. Compared with the Yaffs file system which often used in embedded devices, it has the advantages of less resource consumption, faster startup speed and free. -### Device Abstraction Layer +## Device Abstraction Layer The device abstraction layer abstracts physical devices such as SD Card, SPI Flash, and Nand Flash into devices that are accessible to the file system. For example, the FAT file system requires that the storage device be a block device type. Different file system types are implemented independently of the storage device driver, so the file system function can be correctly used after the drive interface of the underlying storage device is docked with the file system. -## Mount Management +# Mount Management The initialization process of the file system is generally divided into the following steps: @@ -61,11 +61,11 @@ The initialization process of the file system is generally divided into the foll 5. Mount the block device to the DFS directory. 6. When the file system is no longer in use, you can unmount it. -### Initialize the DFS Component +## Initialize the DFS Component The initialization of the DFS component is done by the dfs_init() function. The dfs_init() function initializes the relevant resources required by DFS and creates key data structures that allow DFS to find a specific file system in the system and get a way to manipulate files within a particular storage device. This function will be called automatically if auto-initialization is turned on (enabled by default). -### Registered File System +## Registered File System After the DFS component is initialized, you also need to initialize the specific type of file system used, that is, register a specific type of file system into DFS. The interface to register the file system is as follows: @@ -86,13 +86,13 @@ The `elm_init()` function initializes the elm-FAT file system, which calls the ` ![Register file system](figures/fs-reg.png) -### Register a Storage Device as a Block Device +## Register a Storage Device as a Block Device Only block devices can be mounted to the file system, so you need to create the required block devices on the storage device. If the storage device is SPI Flash, you can use the "Serial Flash Universal Driver Library SFUD" component, which provides various SPI Flash drivers, and abstracts the SPI Flash into a block device for mounting. The process of registering block device is shown as follows: ![The timing diagram of registering block device](figures/fs-reg-block.png) -### Format the file system +## Format the file system After registering a block device, you also need to create a file system of the specified type on the block device, that is, format the file system. You can use the `dfs_mkfs()` function to format the specified storage device and create a file system. The interface to format the file system is as follows: @@ -132,7 +132,7 @@ msh /> msh />mkfs -t elm sd0 # Use the -t parameter to specify the file system type as elm-FAT file system ``` -### Mount file system +## Mount file system In RT-Thread, mounting refers to attaching a storage device to an existing path. To access a file on a storage device, we must mount the partition where the file is located to an existing path and then access the storage device through this path. The interface to mount the file system is as follows: @@ -157,7 +157,7 @@ int dfs_mount(const char *device_name, If there is only one storage device, it can be mounted directly to the root directory `/`. -### Unmount a file system +## Unmount a file system When a file system does not need to be used anymore, it can be unmounted. The interface to unmount the file system is as follows: @@ -172,13 +172,13 @@ int dfs_unmount(const char *specialfile); | 0 | unmount the file system successfully | | -1 | fail to unmount the file system | -## Document Management +# Document Management This section introduces the functions that are related to the operation of the file. The operation of the file is generally based on the file descriptor fd, as shown in the following figure: ![common function of file management](figures/fs-mg.png) -### Open and Close Files +## Open and Close Files To open or create a file, you can call the following open() function: @@ -218,7 +218,7 @@ int close(int fd); | 0 | file closed successfully | | -1 | fail to close the file | -### Read and Write Data +## Read and Write Data To read the contents of a file, use the `read()` function: @@ -255,7 +255,7 @@ int write(int fd, const void *buf, size_t len); This function writes `len` bytes in the memory pointed out by the `buf pointer` into the file pointed out by the parameter `fd`. In addition, the read and write location pointer of the file moves with the bytes written. -### Rename +## Rename To rename a file, use the `rename()` function: @@ -273,7 +273,7 @@ int rename(const char *old, const char *new); This function changes the file name specified by the parameter `old` to the file name pointed to by the parameter `new`. If the file specified by `new` already exists, the file will be overwritten. -### Get Status +## Get Status To get the file status, use the following `stat()` function: @@ -289,7 +289,7 @@ int stat(const char *file, struct stat *buf); | 0 | access status successfully | | -1 | fail to access to status | -### Delete Files +## Delete Files Delete a file in the specified directory using the `unlink()` function: @@ -304,7 +304,7 @@ int unlink(const char *pathname); | 0 | deleted the file successfully | | -1 | fail to deleted the file | -### Synchronize File Data to Storage Devices +## Synchronize File Data to Storage Devices Synchronize all modified file data in memory to the storage device using the `fsync()` function: @@ -319,7 +319,7 @@ int fsync(int fildes); | 0 | synchronize files successfully | | -1 | fail to synchronize files | -### Query file system related information +## Query file system related information Use the `statfs()` function to query file system related information. @@ -335,7 +335,7 @@ int statfs(const char *path, struct statfs *buf); | 0 | query file system information successfully | | -1 | fail to query file system information | -### Monitor I/O device status +## Monitor I/O device status To monitor the I/O device for events, use the `select()` function: @@ -361,13 +361,13 @@ int select( int nfds, Use the `select()` interface to block and simultaneously detect whether a group of non-blocking I/O devices have events (such as readable, writable, high-priority error output, errors, etc.) until a device triggered an event or exceeded a specified wait time. -## Directory management +# Directory management This section describes functions that directory management often uses, and operations on directories are generally based on directory addresses, as shown in the following image: ![functions that directory management often uses](figures/fs-dir-mg.png) -### Create and Delete Directories +## Create and Delete Directories To create a directory, you can use the mkdir() function: @@ -398,7 +398,7 @@ int rmdir(const char *pathname); | 0 | delete the directory successfully | | -1 | fail to delete the directory | -### Open and Close the Directory +## Open and Close the Directory Open the directory to use the `opendir()` function: @@ -428,7 +428,7 @@ int closedir(DIR* d); This function is used to close a directory and must be used with the `opendir()` function. -### Read Directory +## Read Directory To read the directory, use the `readdir()` function: @@ -445,7 +445,7 @@ struct dirent* readdir(DIR *d); This function is used to read the directory, and the parameter d is the directory stream pointer. In addition, each time a directory is read, the pointer position of the directory stream is automatically recursed by 1 position backward. -### Get the Read Position of the Directory Stream +## Get the Read Position of the Directory Stream To get the read location of the directory stream, use the `telldir()` function: @@ -461,7 +461,7 @@ long telldir(DIR *d); The return value of this function records the current position of a directory stream. This return value represents the offset from the beginning of the directory file. You can use this value in the following `seekdir()` to reset the directory to the current position. In other words, the `telldir()` function can be used with the `seekdir()` function to reset the read position of the directory stream to the specified offset. -### Set the Location to Read the Directory Next Time +## Set the Location to Read the Directory Next Time Set the location to read the directory next time using the `seekdir()` function: @@ -476,7 +476,7 @@ void seekdir(DIR *d, off_t offset); This is used to set the read position of the parameter d directory stream, and starts reading from this new position when readdir() is called. -### Reset the Position of Reading Directory to the Beginning +## Reset the Position of Reading Directory to the Beginning To reset the directory stream's read position to the beginning, use the `rewinddir()` function: @@ -490,7 +490,7 @@ void rewinddir(DIR *d); This function can be used to set the current read position of the `d` directory stream to the initial position of the directory stream. -## DFS Configuration Options +# DFS Configuration Options The specific configuration path of the file system in menuconfig is as follows: @@ -531,7 +531,7 @@ const struct dfs_mount_tbl mount_table[] = }; ``` -### elm-FatFs File System Configuration Option +## elm-FatFs File System Configuration Option Elm-FatFs can be further configured after opening the elm-FatFs file system in menuconfig. The configuration menu description and corresponding macro definitions are as follows: @@ -546,7 +546,7 @@ Elm-FatFs can be further configured after opening the elm-FatFs file system in m |[ ] Enable sector erase feature |RT_DFS_ELM_USE_ERASE | | |[*] Enable the reentrancy (thread safe) of the FatFs module |RT_DFS_ELM_REENTRANT |open reentrant| -#### Long File Name +### Long File Name By default, FatFs file naming has the following disadvantages: @@ -562,7 +562,7 @@ If you need to support long filenames, you need to turn on the option to support |( ) 2: LFN with dynamic LFN working buffer on the stack |RT_DFS_ELM_USE_LFN_2 |long file names are supported by temporary buffers in the stack. Larger demand for stack space. | |(X) 3: LFN with dynamic LFN working buffer on the heap |RT_DFS_ELM_USE_LFN_3 |use the heap (malloc request) buffer to store long filenames, it is the safest (default) | -#### Encoding Mode +### Encoding Mode When long file name support is turned on, you can set the encoding mode for the file name. RT-Thread/FatFs uses 437 encoding (American English) by default. If you need to store the Chinese file name, you can use 936 encoding (GBK encoding). The 936 encoding requires a font library of approximately 180KB. If you only use English characters as a file, we recommend using 437 encoding (American English), this will save this 180KB of Flash space. @@ -597,17 +597,17 @@ The file encodings supported by FatFs are as follows: */ ``` -#### File System Sector Size +### File System Sector Size Specify the internal sector size of FatFs, which needs to be greater than or equal to the sector size of the actual hardware driver. For example, if a spi flash chip sector is 4096 bytes, the above macro needs to be changed to 4096. Otherwise, when the FatFs reads data from the driver, the array will be out of bounds and the system will crash (the new version gives a warning message when the system is executed) . Usually Flash device can be set to 4096, and the common TF card and SD card have a sector size of 512. -#### Reentrant +### Reentrant FatFs fully considers the situation of multi-threaded safe read and write security. When reading and writing FafFs in multi-threading, in order to avoid the problems caused by re-entry, you need to open the macro above. If the system has only one thread to operate the file system and there is no reentrancy problem, you can turn it off to save resources. -#### More Configuration +### More Configuration FatFs itself supports a lot of configuration options and the configuration is very flexible. The following file is a FatFs configuration file that can be modified to customize FatFs. @@ -615,9 +615,9 @@ FatFs itself supports a lot of configuration options and the configuration is ve components/dfs/filesystems/elmfat/ffconf.h ``` -## DFS Application Example +# DFS Application Example -### FinSH Command +## FinSH Command After the file system is successfully mounted, the files and directories can be operated. The commonly used FinSH commands for file system operations are shown in the following table: @@ -687,7 +687,7 @@ Directory /: msh /> ``` -### Read and Write File Examples +## Read and Write File Examples Once the file system is working, you can run the application example. In the sample code, you first create a file `text.txt` using the `open()` function and write the string `"RT -Thread Programmer!\n"` in the file using the `write()` function, and then close the file. Use the ` open()` function again to open the `text.txt` file, read the contents and print it out, and close the file finally. @@ -729,7 +729,7 @@ MSH_CMD_EXPORT(readwrite_sample, readwrite sample); ``` -### An Example of Changing the File Name +## An Example of Changing the File Name The sample code in this section shows how to modify the file name. The program creates a function `rename_sample()` that manipulates the file and exports it to the msh command list. This function calls the `rename()` function to rename the file named `text.txt` to `text1.txt`. The sample code is as follows: @@ -766,7 +766,7 @@ text1.txt 5 In the example demonstration, we first create a file named `text.txt` using the echo command, and then run the sample code to change the file name of the file `text.txt` to `text1.txt`. -### Get File Status Example +## Get File Status Example The sample code shows how to get the file status. The program creates a function `stat_sample()` that manipulates the file and exports it to the msh command list. This function calls the `stat()` function to get the file size information of the text.txt file. The sample code is as follows: @@ -798,7 +798,7 @@ text.txt file size = 5 During the example run, the file `text.txt` is first created with the `echo` command, then the sample code is run, and the file size information for the file `text.txt` is printed. -### Create a Directory Example +## Create a Directory Example The sample code in this section shows how to create a directory. The program creates a function file `mkdir_sample()` that manipulates the file and exports it to the msh command list, which calls the `mkdir()` function to create a folder called `dir_test`. The sample code is as follows: @@ -839,7 +839,7 @@ dir_test # it indicates that the type of the dire This example demonstrates creating a folder named `dir_test` in the root directory. -### Read directory Example +## Read directory Example The sample code shows how to read the directory. The program creates a function `readdir_sample()` that manipulates the file and exports it to the msh command list. This function calls the `readdir()` function to get the contents of the `dir_test` folder and print it out. The sample code is as follows: @@ -889,7 +889,7 @@ found hello.txt In this example, first create a hello.txt file under the dir_test folder and exit the dir_test folder. At this point, run the sample program to print out the contents of the dir_test folder. -### An Example of Setting the location of the read directory +## An Example of Setting the location of the read directory The sample code in this section shows how to set the location to read the directory next time. The program creates a function `telldir_sample()` that manipulates the file and exports it to the msh command list. This function first opens the root directory, then reads all the directory information in the root directory and prints the directory information. Meanwhile, use the `telldir()` function to record the location information of the third directory entry. Before reading the directory information in the root directory for the second time, use the `seekdir()` function to set the read location to the address of the third directory entry previously recorded. At this point, read the information in the root directory again, and the directory information is printed out. The sample code is as follows: @@ -971,28 +971,28 @@ hello_5 After running the sample, you can see that the first time you read the root directory information, it starts from the first folder and prints out all the directory information in the root directory. When the directory information is printed for the second time, since the starting position of the reading is set to the position of the third folder by using the `seekdir()` function, the second time when reading the root directory is from the third folder. Start reading until the last folder, only the directory information from `hello_3` to `hello_5` is printed. -## FAQ +# FAQ -### Q: What should I do if I find that the file name or folder name is not displayed properly? +## Q: What should I do if I find that the file name or folder name is not displayed properly? **A:** Check if long file name support is enabled, DFS feature configuration section. -### Q: What should I do if the file system fails to initialize? +## Q: What should I do if the file system fails to initialize? **A:** Check if the type and number of file systems allowed to be mounted in the file system configuration project are sufficient. -### Q: What should I do if the file system *mkfs* command fails? +## Q: What should I do if the file system *mkfs* command fails? **A:** Check if the storage device exists. If it exists, check to see if the device driver can pass the function test, if it fails, check the driver error. Check if the libc function is enabled. -### Q: What should I do if the file system fails to mount? +## Q: What should I do if the file system fails to mount? **A:** - Check if the specified mount path exists. The file system can be mounted directly to the root directory ("/"), but if you want to mount it on another path, such as ("/sdcard"). You need to make sure that the ("/sdcard") path exists. Otherwise, you need to create the `sdcard` folder in the root directory before the mount is successful. - Check if the file system is created on the storage device. If there is no file system on the storage device, you need to create a file system on the storage using the `mkfs` command. -### Q: What should I do if SFUD cannot detect the Flash specific model? +## Q: What should I do if SFUD cannot detect the Flash specific model? **A:** @@ -1002,22 +1002,22 @@ After running the sample, you can see that the first time you read the root dire - Check the `Using auto probe flash JEDEC SFDP parameter` and the `Using defined supported flash chip information table' under the 'RT-Thread Components → Device Drivers -> Using SPI Bus/Device device drivers -> Using Serial Flash Universal Driver` menu, to see whether the configuration item is selected, if it is not selected then you need to enable these two options. - If the storage device is still not recognized with the above option turned on, then issues can be raised in the [SFUD](https://github.com/armink/SFUD) project. - ### Q: Why does the benchmark test of the storage device take too long? +## Q: Why does the benchmark test of the storage device take too long? **A:** - Compare the [benchmark test data](https://github.com/armink/SFUD/blob/master/docs/zh/benchmark.txt) when the `system tick` is 1000 and the length of time required for this test. If the time lag is too large, you can think that the test work is not working properly. - Check the settings of the system tick, because some delay operations will be determined according to the tick time, so you need to set the appropriate `system tick` value according to the system conditions. If the system's `system tick` value is no less than 1000, you will need to use a logic analyzer to check the waveform to determine that the communication rate is normal. -### Q: SPI Flash implements elmfat file system, and how to keep some sectors not used by file system? +## Q: SPI Flash implements elmfat file system, and how to keep some sectors not used by file system? **A:** You can create multiple block devices for the entire storage device using the [partition](https://github.com/RT-Thread-packages/partition) tool package provided by RT-Thread. And block devices can be assigned different functions. -### Q: What should I do if the program gets stuck during the test file system? +## Q: What should I do if the program gets stuck during the test file system? **A:** Try using the debugger or print some necessary debugging information to determine where the program is stuck and ask questions. -### Q: How can I check the problem of the file system step by step? +## Q: How can I check the problem of the file system step by step? **A:** You can step through the problem from the bottom to the top. diff --git a/documentation/finsh/finsh.md b/documentation/finsh/finsh.md index 1d882d6032..d5aed8cb60 100644 --- a/documentation/finsh/finsh.md +++ b/documentation/finsh/finsh.md @@ -1,4 +1,4 @@ -# FinSH Console +@page component_finsh FinSH Console In the early days of computer development, before the advent of graphics systems, there was no mouse or even a keyboard. How did people interact with computers at the time? The earliest computers used a punched note to enter commands into the computer and write the program. Later, with the continuous development of computers, monitors and keyboards became the standard configuration of computers, but the operating system at this time did not support the graphical interface. Computer pioneers developed a software that accepts commands entered by the user, and after interpretation, passes it to The operating system and return the results of the operating system execution to the user. This program wraps around the operating system like a layer of shell, so it's called a shell. @@ -6,7 +6,7 @@ Embedded devices usually need to connect the development board to the PC for com FinSH is the command line component (shell) of RT-Thread. It is based on the above considerations. FinSH is pronounced [ˈfɪnʃ]. After reading this chapter, we will have a deeper understanding of how FinSH works and how to export your own commands to FinSH. -## Introduction of FinSH +# Introduction of FinSH FinSH is the command line component of RT-Thread. It provides a set of operation interfaces for users to call from the command line. It is mainly used to debug or view system information. It can communicate with a PC using serial/Ethernet/USB, etc. The hardware topology is shown below: @@ -31,7 +31,7 @@ FinSH supports auto-completion, and viewing history commands, etc. These functio FinSH supports two input modes, the traditional command line mode and the C language interpreter mode. -### Traditional Command Line Mode +## Traditional Command Line Mode This mode is also known as msh(module shell). In msh mode, FinSH is implemented in the same way as the traditional shell (dos/bash). For example, you can switch directories to the root directory with the `cd /` command. @@ -43,7 +43,7 @@ command [arg1] [arg2] [...] The command can be either a built-in command in RT-Thread or an executable file. -### C Language Interpreter Mode +## C Language Interpreter Mode This mode is also known as C-Style mode. In C language interpreter mode, FinSH can solve and parse most C language expressions, and use functions like C to access functions and global variables in the system. In addition, it can create variables through the command line. In this mode, the command entered must be similar to the function call in C language, that is, you must carry the `()` symbol. For example, to output all current threads and their status in the system, type `list_thread()` in FinSH to print out the required information. The output of the FinSH command is the return value of this function. For some functions that do not have a return value (void return value), this printout has no meaning. @@ -51,7 +51,7 @@ Initially FinSH only supported C-Style mode. Later, with the development of RT-T If both modes are enabled in the RT-Thread, they can be dynamically switched. Enter the `exit` in msh mode and press `Enter` to switch to C-Style mode. Enter `msh()` in C-Style mode and press `Enter` to enter msh mode. The commands of the two modes are not common, and the msh command cannot be used in C-Style mode, and vice versa. -## FinSH Built-in Commands +# FinSH Built-in Commands Some FinSH commands are built in by default in RT-Thread. You can print all commands supported by the current system by entering help in FinSH and pressing Enter or directly pressing Tab. The built-in commands in C-Style and msh mode are basically the same, so msh is taken as an example here. @@ -79,7 +79,7 @@ free - Show the memory usage in the system. Here lists the field information returned after entering the common commands, so that the developer can understand the content of the returned information. -### Display Thread Status +## Display Thread Status Use the `ps` or `list_thread` command to list all thread information in the system, including thread priority, state, maximum stack usage, and more. @@ -104,7 +104,7 @@ list_thread Return field description: | left tick | The number of remaining ticks of the thread | | error | Thread error code | -### Display Semaphore Status +## Display Semaphore Status Use the `list_sem` command to display all semaphore information in the system, including the name of the semaphore, the value of the semaphore, and the number of threads waiting for this semaphore. @@ -124,7 +124,7 @@ list_sem Return field description: | v | The current value of semaphore | | suspend thread | The number of threads waiting for this semaphore | -### Display Event Status +## Display Event Status Use the `list_event` command to display all event information in the system, including the event name, the value of the event, and the number of threads waiting for this event. @@ -142,7 +142,7 @@ list_event Return field description: | set | The current event in the event set | | suspend thread | The number of threads waiting for an event in this event set | -### Display Mutex Status +## Display Mutex Status Use the `list_mutex` command to display all mutex information in the system, including the mutex name, the owner of the mutex, and the number of nestings the owner holds on the mutex. @@ -163,7 +163,7 @@ list_mutex Return field description: | hold | The number of times the holder is nested on this mutex | | suspend thread | The number of threads waiting for this mutex | -### Display Mailbox Status +## Display Mailbox Status Use the `list_mailbox` command to display all mailbox information in the system, including the mailbox name, the number of messages in the mailbox, and the maximum number of messages the mailbox can hold. @@ -184,7 +184,7 @@ list_mailbox Return field description: | size | The maximum number of messages a mailbox can hold | | suspend thread | The number of threads waiting for this mailbox | -### Display Message Queue Status +## Display Message Queue Status Use the `list_msgqueue` command to display all message queue information in the system, including the name of the message queue, the number of messages it contains, and the number of threads waiting for this message queue. @@ -202,7 +202,7 @@ list_msgqueue Return field description: | entry | The number of messages currently included in the message queue | | suspend thread | Number of threads waiting for this message queue | -### Display Memory Pool Status +## Display Memory Pool Status Use the `list_mempool` command to display all the memory pool information in the system, including the name of the memory pool, the size of the memory pool, and the maximum memory size used. @@ -223,7 +223,7 @@ list_mempool Return field description: | free | Free memory block | | suspend thread | The number of threads waiting for this memory pool | -### Display Timer Status +## Display Timer Status Use the `list_timer` command to display all the timer information in the system, including the name of the timer, whether it is the periodic timer, and the number of beats of the timer timeout. @@ -245,7 +245,7 @@ list_timer Return field description: | timeout | The number of beats when the timer expires | | flag | The state of the timer, activated indicates active, and deactivated indicates inactive | -### Display Device Status +## Display Device Status Use the `list_device` command to display all device information in the system, including the device name, device type, and the number of times the device was opened. @@ -265,7 +265,7 @@ list_device Return field description: | type | Device type | | ref count | The number of times the device was opened | -### Display Dynamic Memory Status +## Display Dynamic Memory Status Use the `free` command to display all memory information in the system. @@ -284,11 +284,11 @@ free Return field description: | used memory | Used memory size | | maximum allocated memory | Maximum allocated memory | -## Custom FinSH Command +# Custom FinSH Command In addition to the commands that come with FinSH, FinSH also provides multiple macro interfaces to export custom commands. The exported commands can be executed directly in FinSH. -### Custom msh Command +## Custom msh Command The custom msh command can be run in msh mode. To export a command to msh mode, you can use the following macro interface: @@ -323,7 +323,7 @@ static void atcmd(int argc, char**argv) MSH_CMD_EXPORT(atcmd, atcmd sample: atcmd ); ``` -### Custom C-Style Commands and Variables +## Custom C-Style Commands and Variables Export custom commands to C-Style mode can use the following interface: @@ -365,7 +365,7 @@ The following example defines a `dummy` variable and exports it to a variable co static int dummy = 0; FINSH_VAR_EXPORT(dummy, finsh_type_int, dummy variable for finsh) ``` -### Custom Command Rename +## Custom Command Rename The function name length of FinSH is limited. It is controlled by the macro definition `FINSH_NAME_MAX` in `finsh.h`. The default is 16 bytes, which means that the FinSH command will not exceed 16 bytes in length. There is a potential problem here: when a function name is longer than FINSH_NAME_MAX, after using FINSH_FUNCTION_EXPORT to export the function to the command table, the full function name is seen in the FinSH symbol table, but a full node execution will result in a *null node* error. This is because although the full function name is displayed, in fact FinSH saves the first 16 bytes as a command. Too many inputs will result in the command not being found correctly. In this case, you can use `FINSH_FUNCTION_EXPORT_ALIAS` to re-export the command name. @@ -389,23 +389,23 @@ void hello(void) FINSH_FUNCTION_EXPORT_ALIAS(hello , ho, say hello to RT-Thread); ``` -## FinSH Function Configuration +# FinSH Function Configuration The FinSH function can be cropped, and the macro configuration options are defined in the rtconfig.h file. The specific configuration items are shown in the following table. -| **Macro Definition** | **Value Type** | Description | Default | -|------------------------|----|------------|-------| -| #define RT_USING_FINSH | None | Enable FinSH | on | -| #define FINSH_THREAD_NAME | String | FinSH thread name | "tshell" | -| #define FINSH_USING_HISTORY | None | Turn on historical traceback | on | -| #define FINSH_HISTORY_LINES | Integer type | Number of historical command lines that can be traced back | 5| -| #define FINSH_USING_SYMTAB | None | Symbol table can be used in FinSH | on | -|#define FINSH_USING_DESCRIPTION | None | Add a description to each FinSH symbol | on | -| #define FINSH_USING_MSH| None | Enable msh mode | on | -| #define FINSH_USING_MSH_ONLY | None | Use only msh mode | on | -| #define FINSH_ARG_MAX | Integer type | Maximum number of input parameters | 10 | -| #define FINSH_USING_AUTH | None | Enable permission verification | off | -| #define FINSH_DEFAULT_PASSWORD | String | Authority verification password | off | +| **Macro Definition** | **Value Type** | Description | Default | +|-----------------------------------|----------------|------------------------------------------------------------|---------| +| `#define RT_USING_FINSH` | None | Enable FinSH | on | +| `#define FINSH_THREAD_NAME` | String | FinSH thread name | "tshell"| +| `#define FINSH_USING_HISTORY` | None | Turn on historical traceback | on | +| `#define FINSH_HISTORY_LINES` | Integer type | Number of historical command lines that can be traced back | 5 | +| `#define FINSH_USING_SYMTAB` | None | Symbol table can be used in FinSH | on | +| `#define FINSH_USING_DESCRIPTION` | None | Add a description to each FinSH symbol | on | +| `#define FINSH_USING_MSH` | None | Enable msh mode | on | +| `#define FINSH_USING_MSH_ONLY` | None | Use only msh mode | on | +| `#define FINSH_ARG_MAX` | Integer type | Maximum number of input parameters | 10 | +| `#define FINSH_USING_AUTH` | None | Enable permission verification | off | +| `#define FINSH_DEFAULT_PASSWORD` | String | Authority verification password | off | The reference configuration example in rtconfig.h is as follows, and can be configured according to actual functional requirements. @@ -441,9 +441,9 @@ The reference configuration example in rtconfig.h is as follows, and can be conf #define FINSH_ARG_MAX 10 ``` -## FinSH Application Examples +# FinSH Application Examples -### Examples of msh Command without Arguments +## Examples of msh Command without Arguments This section demonstrates how to export a custom command to msh. The sample code is as follows, the hello function is created in the code, and the `hello` function can be exported to the FinSH command list via the `MSH_CMD_EXPORT` command. @@ -477,7 +477,7 @@ hello RT_Thread! msh /> ``` -### Example of msh Command with Parameters +## Example of msh Command with Parameters This section demonstrates how to export a custom command with parameters to FinSH. The sample code is as follows, the `atcmd()` function is created in the code, and the `atcmd()` function can be exported to the msh command list via the MSH_CMD_EXPORT command. @@ -545,7 +545,7 @@ AT client! msh /> ``` -## FinSH Porting +# FinSH Porting FinSH is written entirely in ANSI C and has excellent portability; it has a small memory footprint, and FinSH will not dynamically request memory if you do not use the functions described in the previous section to dynamically add symbols to FinSH. The FinSH source is located in the `components/finsh` directory. Porting FinSH requires attention to the following aspects: diff --git a/documentation/interrupt/interrupt.md b/documentation/interrupt/interrupt.md index 7fe328188f..2e7f677dc0 100644 --- a/documentation/interrupt/interrupt.md +++ b/documentation/interrupt/interrupt.md @@ -1,5 +1,4 @@ -Interrupt Management -============== +@page interrupt_management Interrupt Management Interrupts often occur in embedded operating systems. When the CPU is processing a normal task, an external urgent event has occurred, requiring the CPU to suspend the current task to handle the asynchronous event. After the external event has been handled, CPU then returns to the interrupted address to continue working on the previous task. The system that implements this function is called the interrupt system, and the source of the request requesting for the CPU interrupt is called the interrupt source. An interrupt is an exception. An exception is any event that causes the processor to move away from normal operation and execute special code. If it is not processed in time, the system will either encounter an error or face a complete breakdown. So appropriately handling exceptions to avoid errors is a very important part of improving software robustness (stability). The following picture is a simple interrupt diagram. @@ -7,12 +6,11 @@ Interrupts often occur in embedded operating systems. When the CPU is processing Interrupt processing is closely related to the CPU architecture. Therefore, this chapter first introduces the ARM Cortex-M CPU architecture, and then introduces the RT-Thread interrupt management mechanism in conjunction with the Cortex-M CPU architecture. After reading this chapter, you will learn more about the interrupt handling process of RT-Thread, how to add an interrupt service routine (ISR) and other matters related. -Cortex-M CPU Architecture Foundation --------------------- +# Cortex-M CPU Architecture Foundation Unlike older classic ARM processors (like ARM7, ARM9), the ARM Cortex-M processor has a very different architecture. Cortex-M is serious which Cortex M0/M3/M4/M7 models. There will be some differences between each model. For example, the Cortex-M4 has more floating point calculation functions than the Cortex-M3, but their programming models are basically the same, so the parts of the book that describe interrupt management and porting are not going to be too finely differentiated for the Cortex M0/M3/M4/M7. This section focuses on the architectural aspects related to RT-Thread interrupt management. -### Introduction to Register +## Introduction to Register The register set of Cortex-M series CPU has 16 general register sets and several special function registers from R0~R15, as shown in the figure below. @@ -31,7 +29,7 @@ The program status word registers stores arithmetic and logic flags, such as neg In the case of a Cortex-M4 or Cortex-M7 with a floating point unit, the control register is also used to indicate whether the floating point unit is currently in use. The floating point unit contains 32 floating point general-purpose registers S0~S31 and a special FPSCR register (Floating point status and control register). -### Operating  Scheme and Privilege Level +## Operating  Scheme and Privilege Level Cortex-M introduces the concept of operation scheme and privilege level, which are thread mode and processing mode respectively. If it enters exception or interrupt processing, it enters processing mode, otherwise it is thread mode. @@ -41,7 +39,7 @@ Cortex-M has two running levels, privilege-level and user-level. Thread mode can Cortex-M's stack register SP corresponds to two physical registers MSP and PSP, MSP is the main stack, PSP is the process stack. Processing mode always uses MSP as the stack; thread mode can choose to use MSP or PSP as the stack, also controlled through special register CONTROL. After reset, Cortex-M enters thread mode, privilege-level, and uses the MSP stack by default. -### Nested Vector Interrupt Controller +## Nested Vector Interrupt Controller The Cortex-M interrupt controller is called NVIC (nested vectored interrupt controller) and supports interrupt nesting. When an interrupt is triggered and the system responds, the processor hardware automatically pushes the context register of the current location of running into the interrupt stack. The registers in this section include the PSR, PC, LR, R12, and R3-R0 registers. @@ -49,14 +47,13 @@ The Cortex-M interrupt controller is called NVIC (nested vectored interrupt cont When the system is servicing an interrupt, if a higher priority interrupt is triggered, then the processor will also interrupt the currently running interrupt service routine, and then save the context of the interrupt service program register PSR, PC, LR, R12, R3-R0 to the interrupt stack. -### PendSV System Call +## PendSV System Call PendSV, also known as a suspendable system call, is an exception that can be suspended like a normal interrupt. It is specifically designed to assist the operating system in context switching. PendSV exceptions are initialized as lowest priority exceptions. Each time a context switch is required, the PendSV exception is triggered manually, and the context switch is performed in the PendSV exception handler. The detailed process of operating system context switching using the PendSV mechanism will be illustrated in the next chapter, *Kernel Porting*. -RT-Thread Interruption Mechanism ---------------------- +# RT-Thread Interruption Mechanism -### Interrupt Vector Table +## Interrupt Vector Table The interrupt vector table is the entry point for all interrupt handlers. The following figure shows the Cortex-M serious of interrupt handlers: linking a function (user interrupt service routine) to the interrupt vector in a virtual interrupt vector table. When the interrupt vector corresponds to an interrupt, the hooked user interrupt service routine is called. @@ -112,13 +109,13 @@ void SysTick_Handler(void) } ``` -### Interrupt Processing +## Interrupt Processing In RT-Thread interrupt management, interrupt handler is divided into three parts: interrupt preamble, user interrupt service routine, and interrupt follow-up procedure, as shown in the following figure: ![3 Parts of the Interrupt Handler](figures/09interrupt_work_process.png) -#### Interrupt Preamble +### Interrupt Preamble The main job of interrupt preamble is as follows: @@ -139,7 +136,7 @@ void rt_interrupt_enter(void) } ``` -#### User Interrupt Service Routine +### User Interrupt Service Routine In the user interrupt service routine (ISR), there are two cases. The first case is that no thread switching is performed. In this case, after user interrupt service routine and interrupt subsequent program finished running, it exits and return to the interrupted thread. . @@ -149,7 +146,7 @@ In Cortex-M architecture, the function implementation of rt_hw_context_switch_in ![Function rt_hw_context_switch_interrupt() Implementation Process](figures/09fun1.png) -#### Interrupt Follow-up Procedure +### Interrupt Follow-up Procedure The main work done by interrupt follow-up procedure is: @@ -170,13 +167,13 @@ void rt_interrupt_leave(void) ![Function rt_hw_context_switch_interrupt() Implementation Process](figures/09fun2.png) -### Interrupt Nesting +## Interrupt Nesting In the case of interrupt nesting, in the process of executing the interrupt service routine, if a high priority interrupt occurs, the execution of the current interrupt service routine will be interrupted to execute the interrupt service routine of the high priority interrupt. After the processing of the high priority interrupt is completed, the interrupted interrupt service routine is resumed. If thread scheduling is required, the thread context switch will occur when all interrupt handlers finish running, as shown in the following figure. ![Thread Switching during Interrupt](figures/09ths_switch.png) -### Interrupt Stack +## Interrupt Stack During the interrupt processing, before the system responds to the interrupt, the software code (or processor) needs to save the context of the current thread (usually stored in the thread stack of the current thread), and then call the interrupt service routine for interrupt response and processing. During interrupt processing (essentially calling the user's interrupt service routine function), the interrupt handler function is likely to have its own local variables, which require the corresponding stack space to save, so the interrupt response still needs a stack space as the context to run the interrupt handler. The interrupt stack can be saved in the stack of the interrupted thread. When exiting from the interrupt, the corresponding thread is resumed to be executed. @@ -186,7 +183,7 @@ RT-Thread adopts interrupt stack that provides independence. When an interrupt o There are two stack pointers in the Cortex-M processor core. One is the main stack pointer (MSP) which is the stack pointer by default. It is used before the first thread and in the interrupt and exception handlers. The other is the thread stack pointer (PSP), used in threads. When the interrupt and exception service routine exits, modify the value of the second bit of LR register as 1, and the SP of the thread is switched from MSP to PSP. -### Processing of the Bottom Half of the Interruption +## Processing of the Bottom Half of the Interruption RT-Thread does not make any assumptions or restrictions on the processing time required by the interrupt service routine, but like other real-time operating systems or non-real-time operating systems, users need to ensure that all interrupt service routines are completed in the shortest possible time (the interrupt service routine is equivalent to having the highest priority in the system and will preempt all threads to execute first). In the process of interrupt nesting or masking the corresponding interrupt source, the other nested interrupt processing and the next interrupt signal of its own interrupt source will not delayed. @@ -258,14 +255,13 @@ void demo_nw_isr(int vector, void *param) As can be seen from the two code snippets of the above example, the interrupt service routine completes the start and end of the interrupt Bottom Half by waiting and releasing a semaphore object. Since the interrupt processing is divided into two parts, Top and Bottom, the interrupt processing becomes an asynchronous process. This part of the system overhead requires the user to seriously consider whether the interrupt service processing time is greater than the time to send notifications to Bottom Half and process when using RT-Thread. -RT-Thread Interrupt Management Interface ---------------------- +# RT-Thread Interrupt Management Interface In order to isolate the operating system from the underlying exceptions and interrupt hardware, RT-Thread encapsulates interrupts and exceptions into a set of abstract interfaces, as shown in the following figure: ![Interrupt Related Interfaces](figures/09interrupt_ops.png) -### Mount Interrupt Service Routine +## Mount Interrupt Service Routine The system associates the user's interrupt handler with the specified interrupt number. You can call the following interface to mount a new interrupt service routine: @@ -293,7 +289,7 @@ Input parameters and return values of rt_hw_interrupt_install() The interrupt service routine is a kind of runtime environment that requires special attention. It runs in a non-threaded execution environment (generally a special operating mode of the chip (privileged mode)). In this runtime environment, the current thread cannot be suspended because the current thread does not exist. During the execution of related operations, information similar to print prompt information will appear, "Function [abc_func] shall not used in ISR", meaning a function that should not be called in the interrupt service routine. -### Interrupt Source Management +## Interrupt Source Management Usually before the ISR is ready to process an interrupt signal, we need to mask the interrupt source and open the previously blocked interrupt source in time after the ISR finishes processing the status or data. @@ -329,7 +325,7 @@ Input parameters of rt_hw_interrupt_umask() >This API does not appear in every migration branch. For example, there is usually no such API in the migration branch of Cortex-M0/M3/M4. -### Global Interrupt Switch +## Global Interrupt Switch The global interrupt switch, also known as the interrupt lock, is the easiest way to disable multi-threaded access to critical sections by shutting down the interrupts to ensure that the current thread is not interrupted by other events (because the entire system no longer responds to those external events that could trigger a thread rescheduling), that is, the current thread will not be preempted unless the thread voluntarily gives up control of the processor. When you need to shut off the interrupt of the entire system , you can call the following function interface: @@ -413,7 +409,7 @@ void global_interrupt_demo(void) This feature can bring great convenience to the development of the code. For example, if interrupt is turned off in a function, call some sub-functions and then turn on the interrupt. There may also be code for interrupt switch in these subfunctions. Since the API for global interrupts allows the use of nest, users do not need to do special processing for this code. -### Interrupt Notification +## Interrupt Notification When the entire system is interrupted by an interrupt and enters the interrupt handler function, it needs to inform the kernel that it has entered the interrupt state. In this case, the following interfaces can be used: @@ -446,8 +442,7 @@ The following table describes the return value of rt_interrupt_get_nest() | 1 | the current system is in an interrupt context | | Bigger Than 1 | current interrupt nesting level | -Interrupt and Polling ----------- +# Interrupt and Polling When the drive peripheral is working, whether the programming mode is triggered by interrupt mode or polling mode is often the first problem to be considered by the driver developer, and there is a difference between the real-time operating system and the time-sharing operating system when it comes to this problem. Because the polling mode itself adopts the sequential execution mode: corresponding processing is done after finding corresponding event. Therefore, the polling mode is relatively simple and clear in terms of implementation. For example, to write data to the serial port, the program code writes the next data only when the serial controller finishes writing a data (otherwise the data is discarded). The corresponding code can look like this: @@ -480,8 +475,7 @@ Through the above calculation process, we can see some of the key factors: the s 2) Change the interrupt mode to polling mode if necessary. At the same time, in order to solve the problem that the processor is always preempted with polling mode and other low-priority threads cannot be operated, the priority of the polling thread can be lowered accordingly. -Global Interrupt Switch Usage Example --------------------- +# Global Interrupt Switch Usage Example This is an interrupted application routine: when multiple threads access the same variable, use the switch global interrupt to protect the variable, as shown in the following code: diff --git a/documentation/kernel-porting/kernel-porting.md b/documentation/kernel-porting/kernel-porting.md index b8ae87e421..cfa14efa50 100644 --- a/documentation/kernel-porting/kernel-porting.md +++ b/documentation/kernel-porting/kernel-porting.md @@ -1,12 +1,10 @@ -Kernel Porting -=============== +@page kernel_porting Kernel Porting After learning the previous chapters, everyone has a better understanding of RT-Thread, but many people are not familiar with how to port the RT-Thread kernel to different hardware platforms. Kernel porting refers to the RT-Thread kernel running on different chip architectures and different boards. It can have functions such as thread management and scheduling, memory management, inter-thread synchronization and communication, and timer management. Porting can be divided into two parts: CPU architecture porting and BSP (Board support package) porting . -This chapter will introduce CPU architecture porting and BSP porting. The CPU architecture porting part will be introduced in conjunction with the Cortex-M CPU architecture. Therefore, it is necessary to review "Cortex-M CPU Architecture Foundation" in the previous chapter ["Interrupt Management"](../interrupt/interrupt.md). After reading this chapter, how to complete the RT-Thread kernel porting will be learned. +This chapter will introduce CPU architecture porting and BSP porting. The CPU architecture porting part will be introduced in conjunction with the Cortex-M CPU architecture. Therefore, it is necessary to review "Cortex-M CPU Architecture Foundation" in the previous chapter @ref interrupt_management. After reading this chapter, how to complete the RT-Thread kernel porting will be learned. -CPU Architecture Porting ------------ +# CPU Architecture Porting There are many different CPU architectures in the embedded world, for example, Cortex-M, ARM920T, MIPS32, RISC-V, etc. In order to enable RT-Thread to run on different CPU architecture chips, RT-Thread provides a libcpu abstraction layer to adapt to different CPU architectures. The libcpu layer provides unified interfaces to the kernel, including global interrupt switches, thread stack initialization, context switching, and more. @@ -25,7 +23,7 @@ libcpu porting related API | rt_uint32_t rt_thread_switch_interrupt_flag; | A flag indicating that a switch is needed in the interrupt. | | rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; | Used to save *from* and *to* threads when the thread is context switching. | -### Implement Global Interrupt Enable/Disable +## Implement Global Interrupt Enable/Disable Regardless of kernel code or user code, there may be some variables that need to be used in multiple threads or interrupts. If there is no corresponding protection mechanism, it may lead to critical section problems. In order to solve this problem, RT-Thread provides a series of inter-thread synchronization and communication mechanism. But these mechanisms require the global interrupt enable/disable function provided in libcpu. They are, respectively: @@ -44,7 +42,7 @@ CPSID I ;PRIMASK=1, ; disable global interrupt CPSIE I ;PRIMASK=0, ; enable global interrupt ``` -#### Disable Global Interrupt +### Disable Global Interrupt The functions that need to be done in order in the rt_hw_interrupt_disable() function are: @@ -72,7 +70,7 @@ The above code first uses the MRS instruction to save the value of the PRIMASK r There are different conventions for different CPU architectures regarding how registers are managed during function calls and in interrupt handlers. A more detailed introduction to the use of registers for Cortex-M can be found in the official ARM manual, "*Procedure Call Standard for the ARM ® Architecture*." -#### Enable Global Interrupt +### Enable Global Interrupt In `rt_hw_interrupt_enable(rt_base_t level)`, the variable *level* is used as the state to be restored, overriding the global interrupt status of the chip. @@ -93,7 +91,7 @@ rt_hw_interrupt_enable PROC ; PROC pseudoinstruction definition function The above code first uses the MSR instruction to write the value register of r0 to the PRIMASK register, thus restoring the previous interrupt status. -### Implement Thread Stack Initialization +## Implement Thread Stack Initialization When dynamically creating threads and initializing threads, the internal thread initialization function *_rt_thread_init()* is used. The _rt_thread_init() function calls the stack initialization function *rt_hw_stack_init()*, which manually constructs a context in the stack initialization function. The context will be used as the initial value for each thread's first execution. The layout of the context on the stack is shown below: @@ -147,7 +145,7 @@ rt_uint8_t *rt_hw_stack_init(void *tentry, } ``` -### Implement Context Switching +## Implement Context Switching In different CPU architectures, context switches between threads and context switches from interrupts to context, the register portion of the context may be different or the same. In Cortex-M, context switching is done uniformly using PendSV exceptions, and there is no difference in the switching parts. However, in order to adapt to different CPU architectures, RT-Thread's libcpu abstraction layer still needs to implement three thread switching related functions: @@ -167,7 +165,7 @@ Context switching between threads, as shown in the following figure: ![Context Switch between Threads](figures/10ths_env1.png) -The hardware automatically saves the PSR, PC, LR, R12, R3-R0 registers of the *from* thread before entering the PendSV interrupt, then saves the R11\~R4 registers of the *from* thread in PendSV, and restores the R4\~R11 registers of the *to* thread, and finally the hardware automatically restores the R0\~R3, R12, LR, PC, PSR registers of the *to* thread after exiting the PendSV interrupt. +The hardware automatically saves the PSR, PC, LR, R12, R3-R0 registers of the *from* thread before entering the PendSV interrupt, then saves the R11~R4 registers of the *from* thread in PendSV, and restores the R4~R11 registers of the *to* thread, and finally the hardware automatically restores the R0~R3, R12, LR, PC, PSR registers of the *to* thread after exiting the PendSV interrupt. The context switch from interrupt to thread can be represented by the following figure: @@ -177,7 +175,7 @@ The hardware automatically saves the PSR, PC, LR, R12, R3-R0 registers of the *f Obviously, in the Cortex-M kernel, the rt_hw_context_switch() and rt_hw_context_switch_interrupt() have same functions, which is finishing saving and replying the remaining contexts in PendSV. So we just need to implement a piece of code to simplify the porting. -#### Implement rt_hw_context_switch_to() +### Implement rt_hw_context_switch_to() rt_hw_context_switch_to() has only the target thread and no source thread. This function implements the function of switching to the specified thread. The following figure is a flowchart: @@ -236,7 +234,7 @@ rt_hw_context_switch_to PROC ENDP ``` -#### Implement rt_hw_context_switch()/ rt_hw_context_switch_interrupt() +### Implement rt_hw_context_switch()/ rt_hw_context_switch_interrupt() The function rt_hw_context_switch() and the function rt_hw_context_switch_interrupt() have two parameters, the *from* thread and the *to* thread. They implement the function to switch from the *from* thread to the *to* thread. The following figure is a specific flow chart: @@ -285,7 +283,7 @@ _reswitch BX LR ``` -#### Implement PendSV Interrupt +### Implement PendSV Interrupt In Cortex-M3, the PendSV interrupt handler is PendSV_Handler(). The actual thread switching is done in PendSV_Handler(). The following figure is a specific flow chart: @@ -345,7 +343,7 @@ pendsv_exit ENDP ``` -### Impalement OS Tick +## Impalement OS Tick With the basics of switching global interrupts and context switching, RTOS can perform functions such as creating, running, and scheduling threads. With OS Tick, RT-Thread can schedule time-to-roll rotations for threads of the same priority, implementing timer functions, implementing rt_thread_delay() delay functions, and so on. @@ -366,8 +364,7 @@ void SysTick_Handler(void) } ``` -BSP Porting -------- +# BSP Porting In a practical project, for the same CPU architecture, different boards may use the same CPU architecture, carry different peripheral resources, and complete different products, so we also need to adapt to the board. RT-Thread provides a BSP abstraction layer to fit boards commonly seen. If you want to use the RT-Thread kernel on a board, in addition to the need to have the corresponding chip architecture porting, you need to port the corresponding board, that is, implement a basic BSP. The job is to establish a basic environment for the operating system to run. The main tasks that need to be completed are: diff --git a/documentation/memory/memory.md b/documentation/memory/memory.md index 2ac9fe30ef..3a7fa20915 100644 --- a/documentation/memory/memory.md +++ b/documentation/memory/memory.md @@ -1,5 +1,4 @@ -Memory Management -============== +@page memory_management Memory Management In a computing system, there are usually two types of memory space: internal memory space and external memory space. Internal memory can be quickly accessed, its contents can be read to and changed and only an address is required. The contents of internal memory are deleted after each power off. It is what would usually be called RAM (Random Access Memory) and is analogous to the RAM in a desktop computer. On the other hand, external memory has relatively fixed contents, retains data even after power off. It is usually called ROM (Read-Only Memory) and is analogous to the hard disk in a desktop computer. @@ -7,8 +6,7 @@ In a computer system, variables and intermediate data are generally stored in RA This chapter introduces two kinds of memory management methods in RT-Thread, namely dynamic memory heap management and static memory pool management. After studying this chapter, readers will understand the memory management principle and usage of RT-Thread. -Memory Management Functional Features ------------------- +# Memory Management Functional Features Because time requirements are very strict in real-time systems, memory management is often much more demanding than in general-purpose operating systems: @@ -26,8 +24,7 @@ The second is allocation management for large memory blocks (slab management alg The third is allocation management for multiple memory heaps (memheap management algorithm) -Memory Heap Management ----------- +# Memory Heap Management Memory heap management is used to manage a contiguous memory space. We introduced the memory distribution of RT-Thread in chapter "Kernel Basics". As shown in the following figure, RT-Thread uses the space at "the end of the ZI segment" to the end of the memory as the memory heap. @@ -41,7 +38,7 @@ Any or none of these memory heap management algorithms can be chosen when the sy >Because the memory heap manager needs to meet the security allocation in multi-threaded conditions, which means mutual exclusion between multiple threads needs to be taken into consideration, please do not allocate or release dynamic memory blocks in interrupt service routines, as that may result in the current context being suspended. -### Small Memory Management Algorithm +## Small Memory Management Algorithm The small memory management algorithm is a simple memory allocation algorithm. Initially, it is a large piece of memory. When a memory block needs to be allocated, the matching memory block is segmented from the large memory block, and then this matching free memory block is returned to the heap management system. Each memory block contains data head for management use through which the used block and the free block are linked by a doubly linked list. @@ -87,7 +84,7 @@ In addition, a 12-byte data head is reserved for `magic, used` information, and As for releasing, it is the reverse process, but the allocator will check if the adjacent memory blocks are free, and if they are free, the allocator will merge them into one large free memory block. -### Slab Management Algorithm +## Slab Management Algorithm RT-Thread's slab allocator is an optimized memory allocation algorithm for embedded systems based on the slab allocator implemented by DragonFly BSD founder Matthew Dillon. The most primitive slab algorithm is Jeff Bonwick's efficient kernel memory allocation algorithm introduced for the Solaris operating system. @@ -109,7 +106,7 @@ Assuming a 32-byte memory is allocated, the slab memory allocator first finds th The allocator needs to find the zone node where the memory block is located, and then link the memory block to the zone's free memory block linked list. If the free linked list of the zone indicates that all the memory blocks of the zone have been released, it means that the zone is completely free. The system will release the fully free zone to the page allocator when the number of free zones in the zone linked list reaches a certain number. -### memheap Management Algorithm +## memheap Management Algorithm The memheap management algorithm is suitable for systems with multiple memory heaps that are not contiguous. Using memheap memory management can simplify the use of multiple memory heaps in the system: when there are multiple memory heaps in the system, the user only needs to initialize multiple needed memheaps during system initialization and turn on the memheap function to attach multiple memheaps (addresses can be discontinuous) for the system's heap allocation. @@ -119,7 +116,7 @@ The working mechanism of memheap is shown in the figure below. First, add multip ![memheap Handling Multiple Memory Heaps](figures/08memheap.png) -### Memory Heap Configuration and Initialization +## Memory Heap Configuration and Initialization When using the memory heap, heap initialization must be done at system initialization, which can be done through the following function interface: @@ -158,13 +155,13 @@ Input parameters and return values of rt_memheap_init() |**Return** | —— | | RT_EOK | Successful | -### Memory Heap Management +## Memory Heap Management Operations of the memory heap are as shown in the following figure, including: initialization, application for memory blocks, release of memory. After use, all dynamic memory should be released for future use by other programs. ![Operations of the Memory Heap ](figures/08heap_ops.png) -#### Allocate and Release Memory Block +### Allocate and Release Memory Block Allocate a memory block of user-specified size from the memory heap. The function interface is as follows: @@ -197,7 +194,7 @@ Input parameters of rt_free() |----------|--------------------| | ptr | to-be-released memory block pointer | -#### Re-allocate Memory Block +### Re-allocate Memory Block Re-allocating the size of the memory block (increase or decrease) based on the allocated memory block can be done through the following function interface: @@ -216,7 +213,7 @@ Input parameters and return values of rt_realloc() |**Return** | —— | | Re-allocated memory block address | Successful | -#### Allocate Multiple Memory Blocks +### Allocate Multiple Memory Blocks Allocating multiple memory blocks with contiguous memory addresses from the memory heap can be done through the following function interface: @@ -236,7 +233,7 @@ Input parameters and return values of rt_calloc() | Pointer pointing to the first memory block address | Successful, all allocated memory blocks are initialized to zero. | | RT_NULL | Allocation failed | -#### Set Memory Hook Function +### Set Memory Hook Function When allocating memory blocks, user can set a hook function. The function interface called is as follows: @@ -295,7 +292,7 @@ Input parameters of the hook function |----------|--------------------| | ptr | Memory block pointer to be released | -### Memory Heap Management Application Example +## Memory Heap Management Application Example This is an example of a memory heap application. This program creates a dynamic thread that dynamically requests memory and releases it. Each time it apples for more memory, it ends when it can't apply for it, as shown in the following code: @@ -377,8 +374,7 @@ try to get 65536 byte memory failed! The memory is successfully allocated in the routine and the information is printed; when trying to apply 65536 byte, 64KB, of memory, the allocation fails because the total RAM size is only 64K and the available RAM is less than 64K. -Memory Pool ------- +# Memory Pool The memory heap manager can allocate blocks of any size, which is very flexible and convenient. However, it also has obvious shortcomings. Firstly, the allocation efficiency is not high because free memory blocks need to be looked up for each allocation. Secondly, it is easy to generate memory fragmentation. In order to improve the memory allocation efficiency and avoid memory fragmentation, RT-Thread provides another method of memory management: Memory Pool. @@ -394,9 +390,9 @@ The player thread then writes the memory block containing the decoded data to th After the sound card device is written, the callback function set by the player thread is called to release the written memory block. If the player thread is suspended because there is no memory block in the memory pool available, then it will be awakened to continue to decode. -### Memory Pool Working Mechanism +## Memory Pool Working Mechanism -#### Memory Pool Control Block +### Memory Pool Control Block The memory pool control block is a data structure used by the operating system to manage the memory pool. It stores some information about the memory pool, such as the start address of the data area in the memory pool, the memory block size and the memory block list. It also includes memory blocks, a linked list structure used for the connection between memory blocks, event set of the thread suspended due to the memory block being unavailable, and so on. @@ -425,7 +421,7 @@ struct rt_mempool typedef struct rt_mempool* rt_mp_t; ``` -#### Memory Block Allocation Mechanism +### Memory Block Allocation Mechanism When the memory pool is created, it first asks for a large amount of memory from the system. Then it divides the memory into multiple small memory blocks of the same size. The small memory blocks are directly connected by a linked list (this linked list is also called a free linked list). At each allocation, the first memory block is taken from the head of the free linked list and provided to the applicant. As you can see from the figure below, there are multiple memory pools of different sizes allowed in physical memory. Each memory pool is composed of multiple free memory blocks, which are used by the kernel for memory management. When a memory pool object is created, the memory pool object is assigned to a memory pool control block. The parameters of the memory control block include the memory pool name, memory buffer, memory block size, number of blocks, and a queue of threads waiting. @@ -435,13 +431,13 @@ The kernel is responsible for allocating memory pool control blocks to the memor Each memory pool object consists of the above structure, where suspend_thread forms a list for thread waiting for memory blocks, that is, when there is no memory block available in the memory pool, and the request thread allows waiting, the thread applying for the memory block will suspend on the suspend_thread linked list. -### Memory Pool Management +## Memory Pool Management The memory pool control block is a structure that contains important parameters related to the memory pool and acts as a link between various states of the memory pool. The related interfaces of the memory pool are as shown in the following figure. The operation of the memory pool includes: creating/initializing the memory pool, appling for memory blocks, releasing memory blocks and deleting/detaching memory pools. It needs to noted that not all memory pools will be deleted. The deletion is relegated to the user, but the used memory blocks should be released. ![Related Interfaces of Memory Pool](figures/08mempool_ops.png) -#### Create and Delete Memory Pool +### Create and Delete Memory Pool To create a memory pool, a memory pool object is created first and then a memory heap is allocated from the heap. Creating a memory pool is a prerequisite for allocating and releasing memory blocks from the corresponding memory pool. After the memory pool is created, a thread can perform operations like application, release and so on. To create a memory pool, use the following function interface. This function returns a created memory pool object. @@ -480,7 +476,7 @@ Input parameters and return values of rt_mp_delete() |**Return**| —— | | RT_EOK | Deletion successful | -#### Initialize and Detach Memory Pool +### Initialize and Detach Memory Pool Memory pool initialization is similar to memory pool creation, except that the memory pool initialization is used for static memory management, and the memory pool control block is derived from static objects that the user applies in the system. In addition, unlike memory pool creation, the memory space used by the memory pool object here is a buffer space specified by user. The user passes the pointer of the buffer to the memory pool control block, the rest of the initialization is the same as the creation of the memory pool. The function interface is as follows: @@ -527,7 +523,7 @@ Input parameters and return values for rt_mp_detach() |**Return**| —— | | RT_EOK | Successful | -#### Allocate and Release Memory Block +### Allocate and Release Memory Block To allocate a memory block from the specified memory pool, use the following interface: @@ -561,7 +557,7 @@ Input parameters of rt_mp_free() |----------|------------| | block | memory block pointer | -### Memory Pool Application Example +## Memory Pool Application Example This is a static internal memory pool application routine that creates a static memory pool object and 2 dynamic threads. One thread will try to get the memory block from the memory pool, and the other thread will release the memory block, as shown in the following code: diff --git a/documentation/network/network.md b/documentation/network/network.md index c9a137f4b1..f523215551 100644 --- a/documentation/network/network.md +++ b/documentation/network/network.md @@ -1,4 +1,4 @@ -# Network Framework +@page component_network Network Framework With the popularity of the Internet, people's lives are increasingly dependent on the application of the network. More and more products need to connect to the Internet, and device networking has become a trend. To achieve the connection between the device and the network, you need to follow the TCP/IP protocol, you can run the network protocol stack on the device to connect to the network, or you can use devices (chips with hardware network protocol stack interfaces) to connect to the Internet. @@ -6,15 +6,15 @@ When the device is connected to the network, it is like plugging in the wings. Y This chapter will explain the related content of the RT-Thread network framework, and introduce you to the concept, function and usage of the network framework. After reading this chapter, you will be familiar with the concept and implementation principle of the RT-Thread network framework and familiar with network programming using Socket API. -## TCP/IP Introduction to Network Protocols +# TCP/IP Introduction to Network Protocols TCP/IP is short for Transmission Control Protocol/Internet Protocol. It is not a single protocol, but a general term for a protocol family. It includes IP protocol, ICMP protocol, TCP protocol, and http and ftp, pop3, https protocol, etc., which define how electronic devices connect to the Internet and the standards by which data is transferred between them. -### OSI Reference Model +## OSI Reference Model OSI (Open System Interconnect), which is an open system interconnection. Generally referred to as the OSI reference model, it is a network interconnection model studied by the ISO (International Organization for Standardization) in 1985. The architecture standard defines a seven-layer framework for the network interconnection (physical layer, data link layer, network layer, transport layer, session layer, presentation layer, and application layer), that is, the ISO open system interconnection reference model. The first to third layers belong to the lower three layers of the OSI Reference Model and are responsible for creating links for network communication connections; the fourth to seventh layers are the upper four layers of the OSI reference model and is responsible for end-to-end data communication. The capabilities of each layer are further detailed in this framework to achieve interconnectivity, interoperability, and application portability in an open system environment. -### TCP/IP Reference Model +## TCP/IP Reference Model The TCP/IP communication protocol uses a four-layer hierarchical structure, and each layer calls the network provided by its next layer to fulfill its own needs. The four layers are: @@ -23,7 +23,7 @@ The TCP/IP communication protocol uses a four-layer hierarchical structure, and * **Network layer**: responsible for providing basic data packet transfer functions, so that each packet can reach the destination host (but not check whether it is received correctly), such as Internet Protocol (IP). * **Network interface layer**: Management of actual network media, defining how to use actual networks (such as Ethernet, Serial Line, etc.) to transmit data. -### Difference between TCP/IP Reference Model and OSI Reference Model +## Difference between TCP/IP Reference Model and OSI Reference Model The following figure shows the TCP/IP reference model and the OSI reference model diagram: @@ -31,19 +31,19 @@ The following figure shows the TCP/IP reference model and the OSI reference mode Both the OSI reference model and the TCP/IP reference model are hierarchical, based on the concept of a separate protocol stack. The OSI reference model has 7 layers, while the TCP/IP reference model has only 4 layers, that is, the TCP/IP reference model has no presentation layer and session layer, and the data link layer and physical layer are merged into a network interface layer. However, there is a certain correspondence between the two layers. Due to the complexity of the OSI system and the design prior to implementation, many designs are too ideal and not very convenient for software implementation. Therefore, there are not many systems that fully implement the OSI reference model, and the scope of application is limited. The TCP/IP reference model was first implemented in a computer system. It has a stable implementation on UNIX and Windows platforms, and provides a simple and convenient programming interface (API) on which a wide range of applications are developed. The TCP/IP reference model has become the international standard and industry standard for Internet connectivity. -### IP Address +## IP Address The IP address refers to the Internet Protocol Address (also translated as the Internet Protocol Address) and is a uniform address format that assigns a logical address to each network and each host on the Internet to mask physical address differences provided by Internet Protocol. The common LAN IP address is 192.168.X.X. -### Subnet Mask +## Subnet Mask Subnet mask (also called netmask, address mask), which is used to indicate which bits of an IP address identify the subnet where the host is located, and which bits are identified as the bit mask of the host. The subnet mask cannot exist alone, it must be used in conjunction with an IP address. Subnet mask has only one effect, which is to divide an IP address into two parts: network address and host address. The subnet mask is the bit of 1, the IP address is the network address, the subnet mask is the bit of 0, and the IP address is the host address. Taking the IP address 192.168.1.10 and the subnet mask 255.255.255.0 as an example, the first 24 bits of the subnet mask (converting decimal to binary) is 1, so the first 24 bits of the IP address 192.168.1 represent the network address. The remaining 0 is the host address. -### MAC Address +## MAC Address MAC (figures Access Control or Medium Access Control) address, which is translated as media access control, or physical address, hardware address, used to define the location of network devices. In OSI model, the third layer network Layer is responsible for IP address, the second layer data link layer is responsible for the MAC address. A host will have at least one MAC address. -## Introduction to the Network Framework of RT-Thread +# Introduction to the Network Framework of RT-Thread In order to support various network protocol stacks, RT-Thread has developed a **SAL** component, the full name of the **Socket abstraction layer**. RT-Thread can seamlessly access various protocol stacks, including several commonly used TCP/IP protocol stack, such as the LwIP protocol stack commonly used in embedded development and the AT Socket protocol stack component developed by RT-Thread, which complete the conversion of data from the network layer to the transport layer. @@ -92,11 +92,11 @@ In addition, based on the network framework, RT-Thread provides a large number o | netutils | A collection of useful network debugging gadgets, including: ping, TFTP, iperf, NetIO, NTP, Telnet, etc. | | OneNet | Software for accessing China Mobile OneNet Cloud | -## Network Framework Workflow +# Network Framework Workflow Using the RT-Thread network framework, you first need to initialize the SAL, then register various network protocol clusters to ensure that the application can communicate using the socket network socket interface. This section mainly uses LwIP as an example. -### Register the Network Protocol Cluster +## Register the Network Protocol Cluster First use the `sal_init()` interface to initialize resources such as mutex locks used in the component. The interface looks like this: @@ -141,23 +141,23 @@ int sal_proto_family_register(const struct proto_family *pf); | 0 | registration success | | -1 | registration failed | -### Network Data Receiving Process +## Network Data Receiving Process After the LwIP is registered to the SAL, the application can send and receive network data through the network socket interface. In LwIP, several main threads are created, and they are `tcpip` thread, `erx` receiving thread and `etx` sending thread. The network data receiving process is as shown in the following picture. The application receives data by calling the standard socket interface `recv()` with blocking mode. When the Ethernet hardware device receives the network data packet, it stores the packet in the receiving buffer, and then sends an email to notify the `erx` thread that the data arrives through the Ethernet interrupt program. The `erx` thread applies for the `pbuf` memory block according to the received data length and put the data into the pbuf's `payload` data, then send the `pbuf` memory block to the `tcpip` thread via mailbox, and the `tcpip` thread returns the data to the application that is blocking the receiving data. ![Data receiving function call flow chart](figures/net-recv.png) -### Network Data Sending Process +## Network Data Sending Process The network data sending process is shown in the figure below. When there is data to send, the application calls the standard network socket interface `send()` to hand the data to the `tcpip` thread. The `tcpip` thread sends a message to wake up the `etx` thread. The `etx` thread first determines if the Ethernet is sending data. If data is not being sent, it will put the data to be sent into the send buffer, and then send the data through the Ethernet device. If data is being sent, the `etx` thread suspends itself until the Ethernet device is idle before sending the data out. ![Data sending function call flow chart](figures/net-send.png) -## Network Socket Programming +# Network Socket Programming The application uses Socket (network socket) interface programming to implement network communication functions. Socket is a set of application program interface (API), which shields the communication details of each protocol, so that the application does not need to pay attention to the protocol itself, directly using the interfaces provide by socket to communicate between different hosts interconnected. -### TCP socket Communication Process +## TCP socket Communication Process TCP(Tranfer Control Protocol) is a connection-oriented protocol to ensure reliable data transmission. Through the TCP protocol transmission, a sequential error-free data stream is obtained. The TCP-based socket programming flow diagram is shown in the following figure. A connection must be established between the sender and the receiver's two sockets in order to communicate on the basis of the TCP protocol. When a socket (usually a server socket) waits for a connection to be established. Another socket can request a connection. Once the two sockets are connected, they can perform two-way data transmission, and both sides can send or receive data. A TCP connection is a reliable connection that guarantees that packets arrive in order, and if a packet loss occurs, the packet is automatically resent. @@ -165,7 +165,7 @@ For example, TCP is equivalent to calling in life. When you call the other party ![TCP-based socket programming flow chart](figures/net-tcp.png) -### UDP socket Communication Process +## UDP socket Communication Process UDP is short for User Datagram Protocol. It is a connectionless protocol. Each datagram is a separate information, including the complete source address and destination address. It is transmitted to the destination on the network in any possible path. Therefore, whether the destination can be reached, the time to reach the destination, and the correctness of the content cannot be guaranteed. The UDP-based socket programming flow is shown in the following figure. @@ -173,7 +173,7 @@ UDP is short for User Datagram Protocol. It is a connectionless protocol. Each d For example, UDP is equivalent to the walkie-talkie communication in life. After you set up the channel, you can directly say the information you want to express. The data is sent out by the walkie-talkie, but you don't know if your message has been received by others. By the way, unless someone else responds to you with a walkie-talkie. So this method is not reliable. -### Create a Socket +## Create a Socket Before communicating, the communicating parties first use the `socket()` interface to create a socket, assigning a socket descriptor and its resources based on the specified address family, data type, and protocol. The interface is as follows: @@ -209,7 +209,7 @@ The sample code for creating a TCP type socket is as follows: } ``` -### Binding Socket +## Binding Socket A binding socket is used to bind a port number and an IP address to a specified socket. When using socket() to create a socket, only the protocol family is given, and no address is assigned. Before the socket receives a connection from another host, it must bind it with an address and port number using bind(). The interface is as follows: @@ -226,11 +226,11 @@ int bind(int s, const struct sockaddr *name, socklen_t namelen); | 0 | Successful | | -1 | Fail | -### Establishing a TCP Connection +## Establishing a TCP Connection For server-side programs, after using `bind()` to bind the socket, you also need to use the `listen()` function to make the socket enter the passive listening state, and then call the `accept()` function to respond to the client at any time. -#### Listening Socket +### Listening Socket The listening socket is used by the TCP server to listen for the specified socket connection. The interface is as follows: @@ -246,7 +246,7 @@ int listen(int s, int backlog); | 0 | Successful | | -1 | Fail | -#### Accept the Connection +### Accept the Connection When the application listens for connections from other clients, the connection must be initialized with the `accept()` function, which creates a new socket for each connection and removes the connection from the listen queue. The interface is as follows: @@ -263,7 +263,7 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen); | >=0 | Successful, return the newly created socket descriptor | | -1 | Fail | -#### Establish Connection +### Establish Connection Used by the client to establish a connection with the specified server. The interface is as follows: @@ -300,11 +300,11 @@ if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == - } ``` -### Data Transmission +## Data Transmission TCP and UDP have different data transmission methods. TCP needs to establish a connection before data transmission, use `send()` function for data transmission, use `recv()` function for data reception, and UDP does not need to establish connection. It uses `sendto()` function sends data and receives data using the `recvfrom()` function. -#### TCP Data Transmission +### TCP Data Transmission After the TCP connection is established, the data is sent using the `send()` function. The interface is as follows: @@ -322,7 +322,7 @@ int send(int s, const void *dataptr, size_t size, int flags); | >0 | Successful, return the length of the sent data | | <=0 | Failed | -#### TCP Data Reception +### TCP Data Reception After the TCP connection is established, use `recv()` to receive the data. The interface is as follows: @@ -341,7 +341,7 @@ int recv(int s, void *mem, size_t len, int flags); | =0 | The destination address has been transferred and the connection is closed | | <0 | Fail | -#### UDP Data transmission +### UDP Data transmission In the case where a connection is not established, you can use the `sendto()` function to send UDP data to the specified destination address, as shown below: @@ -362,7 +362,7 @@ int sendto(int s, const void *dataptr, size_t size, int flags, | >0 | Successful, return the length of the sent data | | <=0 | Fail | -#### UDP Data Reception +### UDP Data Reception To receive UDP data, use the `recvfrom()` function, and the interface is: @@ -384,7 +384,7 @@ int recvfrom(int s, void *mem, size_t len, int flags, | 0 | The receiving address has been transferred and the connection is closed | | <0 | Fail | -### Close Network Connection +## Close Network Connection After the network communication is over, you need to close the network connection. There are two ways to use `closesocket()` and `shutdown()`. @@ -415,7 +415,7 @@ int shutdown(int s, int how); | 0 | Successful | | -1 | Fail | -## Network Function Configuration +# Network Function Configuration The main functional configuration options of the network framework are shown in the following table, which can be configured according to different functional requirements: @@ -462,9 +462,9 @@ LwIP Configuration options: | RT_LWIP_ETHTHREAD_STACKSIZE | Integer | Receive/send thread's stack size | | RT_LwIP_ETHTHREAD_MBOX_SIZE | Integer | Receive/send thread's mailbox size | -## Network Application Example +# Network Application Example -### View IP Address +## View IP Address In the console, you can use the ifconfig command to check the network status. The IP address is 192.168.12.26, and the FLAGS status is LINK_UP, indicating that the network is configured: @@ -481,7 +481,7 @@ dns server #0: 192.168.10.1 dns server #1: 223.5.5.5 ``` -### Ping Network Test +## Ping Network Test Use the ping command for network testing: @@ -501,7 +501,7 @@ msh /> Getting the above output indicates that the connection network is successful! -### TCP Client Example +## TCP Client Example After the network is successfully connected, you can run the network example, first run the TCP client example. This example will open a TCP server on the PC, open a TCP client on the IoT Board, and both parties will communicate on the network. @@ -683,7 +683,7 @@ msh > The above information indicates that the TCP client received 5 "hello world" data sent from the server. Finally, the exit command 'q' was received from the TCP server, and the TCP client program exited the operation and returned to the FinSH console. -### UDP Client Example +## UDP Client Example This is an example of a UDP client. This example will open a UDP server on the PC and open a UDP client on the IoT Board for network communication. A UDP client program has been implemented in the sample project. The function is to send data to the server. The sample code is as follows: diff --git a/documentation/pm/pm.md b/documentation/pm/pm.md index ff4c1b802a..509b99a37d 100644 --- a/documentation/pm/pm.md +++ b/documentation/pm/pm.md @@ -1,4 +1,4 @@ -# Power Management: PM +@page component_pm Power Management: PM The purpose of low power management of embedded system is to reduce system energy consumption as much as possible to prolong the standby time of equipment on the premise of satisfying users'performance requirements. The contradiction between high performance and limited battery energy is most prominent in embedded systems. The combination of hardware low power design and software low power management has become an effective means to solve the contradiction. Nowadays, all kinds of MCUs provide management interfaces in low power consumption more or less. For example, adjusting the frequency of the main control clock, changing the working voltage, adjusting or even closing the bus frequency, closing the working clock of peripheral equipment, etc. With the support of hardware, reasonable software design becomes the key to energy saving. Generally, low power management can be divided into three categories: @@ -18,13 +18,13 @@ With the rise of the Internet of Things (IoT), the demand for power consumption In the initial stage of product development, the first consideration is to complete the development of product functions as soon as possible. After the function of the product is gradually improved, it is necessary to add the power management (PM) function. To meet this need of IoT, RT-Thread provides power management components. The idea of power management components is to be as transparent as possible, making it easier for products to add low power functions. -## Introduction of PM Components +# Introduction of PM Components RT-Thread's PM components adopt a layered design idea, separating architecture and chip-related parts, and extracting common parts as the core. While providing a common interface to the upper layer, it also makes it easier for the bottom driver to adapt components. ![PM Component Overview](figures/pm_system.png) -### Main Features +## Main Features The main features of RT-Thread PM components are as follows: @@ -35,7 +35,7 @@ The main features of RT-Thread PM components are as follows: - Optional sleep time compensation is supported to make OS Tick dependent applications transparent. - Provide the device interface to the upper layer. If the devfs component is opened, it can also be accessed through the file system interface. -### Working Principle +## Working Principle The essence of low power consumption is that when the system is idle, the CPU stops working, interrupts or resumes working after the event wakes up. In RTOS, there is usually an IDLE task, which has the lowest priority and remains ready. When the high priority task is not ready, the OS executes the IDLE task. Generally, the CPU executes empty instructions in IDLE tasks without low power processing. The power management component of RT-Thread can effectively reduce the power consumption of the system by managing CPU, clock and equipment in IDLE tasks. @@ -43,13 +43,13 @@ The essence of low power consumption is that when the system is idle, the CPU st As shown in the figure above, when the high priority thread runs out or is suspended, the system enters the IDLE thread . After the IDLE thread is executed, it will determine whether the system can go to sleep (to save power). If the system goes to sleep, Some hardware modules will be shut down depending on the chip condition, and OS Tick is also very likely to enter a pause state. At this time, the power management framework will calculate the next timeout point according to the system timer situation, and set a low-power timer, so that the device can wake up at that point, and carry out follow-up work. When the system is awakened (low power timer interrupt or other wake-up interrupt source), the system also needs to know how long it sleeps, and compensate for OS Tick, so that the OS tick value of the system is adjusted to a correct value. -## PM Framework +# PM Framework In RT-Thrad PM components, peripherals or applications vote on the required power consumption mode by voting mechanism. When the system is idle, the appropriate power consumption mode is decided according to the voting number, and the abstract interface is called to control the chip to enter a low power consumption state, so as to reduce the power consumption of the system. When no vote is taken, it is entered in the default mode (usually idle mode). Unlike applications, some peripherals may perform specific operations when they enter a low-power state and take measures to recover when they exit a low-power state, which can be achieved by registering PM devices. By registering PM devices, `suspend` callbacks of registered devices will be triggered before entering a low power state. Developers can perform their own operations in the callbacks. Similarly, `resume` callbacks will be triggered when exiting from a low power state. ![PM Framework](figures/pm_architecture.png) -## Low Power State and Mode +# Low Power State and Mode The RT-Thread PM component divides the system into two states: RUN(running state) and Sleep(sleeping state). @@ -83,23 +83,23 @@ Running state is usually used to change the running frequency of CPU, independen | PM_RUN_MODE_MEDIUM_SPEED | Medium-speed mode, reduce CPU running speed, thereby reducing power consumption | | PM_RUN_MODE_LOW_SPEED | Low-speed mode, CPU frequency further reduced | -### Request and release of patterns +## Request and release of patterns In PM components, upper applications can actively participate in power management by requesting and releasing sleep modes. Applications can request different sleep modes according to scenarios and release them after processing. As long as any application or device requests higher-level power mode, it will not switch to a lower mode. Therefore, the requests and releases of sleep mode usually occur in pairs and can be used to protect a certain stage, such as the peripheral DMA transmission process. -### Device Sensitive to Mode Changes +## Device Sensitive to Mode Changes In PM components, switching to a new mode of operation may lead to changes in CPU frequency. If peripherals and CPUs share a part of the clock, the peripheral clock will be affected. When entering the new sleep mode, most clock sources will be stopped. If the peripheral does not support the freezing function of sleep, then the peripheral clock needs to be reconfigured when waking up from sleep. So PM components support PM mode sensitive PM devices. It enables the device to work normally when switching to a new operation mode or a new sleep mode. This function requires the underlying driver to implement the relevant interface and register as a device sensitive to mode changes. -## The calling process +# The calling process ![PM Sequence](figures/pm_sequence.png) Firstly, the application layer sets the callback function of entering and exiting the dormancy state, and then calls `rt_pm_request` to request the sleeping mode to trigger the sleeping operation. The PM component checks the number of sleeping modes when the system is idle, and gives the recommended mode according to the number of votes. Then the PM component calls `notfiy` to inform the application that it is going to enter the sleep mode, and then suspends the registered PM device and executes the sleep mode implemented by SOC after returning to OK. The system enters the sleep state (if the enabling time is compensated, the low-power timer will be started before the sleep). At this point, the CPU stops working and waits for an event or interrupt to wake up. When the system is awakened, because the global interruption is closed, the system continues to execute from there, gets the sleep time to compensate the OS tick of the system, wakes up the device in turn, and notifies the application to exit from the sleep mode. Such a cycle is completed, exits, and waits for the system to be idle next time. -## Introduction to APIs +# Introduction to APIs -### Request Sleep Mode +## Request Sleep Mode ```c void rt_pm_request(uint8_t sleep_mode); @@ -127,7 +127,7 @@ enum Calling this function adds the corresponding pattern count to 1 and locks the pattern. At this point, if a lower level of power mode is requested, it will not be accessible. Only after releasing (unlocking) the previously requested mode, the system can enter a lower level of power mode; requests to higher power mode are not affected by this. This function needs to be used in conjunction with `rt_pm_release` to protect a certain stage or process. -### Release Sleep Mode +## Release Sleep Mode ```c void rt_pm_release(uint8_t sleep_mode); @@ -139,7 +139,7 @@ void rt_pm_release(uint8_t sleep_mode); Calling this function decreases the corresponding pattern count by 1, and releases the previously requested pattern in conjunction with `rt_pm_request`. -### Setting up Running Mode +## Setting up Running Mode ```c int rt_pm_run_enter(uint8_t run_mode); @@ -165,7 +165,7 @@ enum Calling this function changes the CPU's running frequency, thereby reducing the power consumption at runtime. This function only provides levels, and the specific CPU frequency should depend on the actual situation during the migration phase. -### Setting up callback notifications for entering/exiting sleep mode +## Setting up callback notifications for entering/exiting sleep mode ```c void rt_pm_notify_set(void (*notify)(uint8_t event, uint8_t mode, void *data), void *data); @@ -187,9 +187,9 @@ enum ``` -## Instruction for Use +# Instruction for Use -### Setting Low Power Level +## Setting Low Power Level If the system needs to enter a specified level of low power consumption, it can be achieved by calling rt_pm_request. For example, into deep sleep mode: @@ -200,7 +200,7 @@ rt_pm_request(PM_SLEEP_MODE_DEEP); > Note: If higher power consumption modes, such as Light Mode or Idle Mode, are requested elsewhere in the program, then the corresponding mode needs to be released before the deep sleep mode can be entered. -### Protect a stage or process +## Protect a stage or process In special cases, for example, the system is not allowed to enter a lower power mode at a certain stage, which can be protected by rt_pm_request and rt_pm_release. For example, deep sleep mode (which may cause peripherals to stop working) is not allowed during I2C reading data, so the following processing can be done: @@ -215,7 +215,7 @@ rt_pm_release(PM_SLEEP_MODE_LIGHT); ``` -### Changing CPU Running Frequency +## Changing CPU Running Frequency Reducing the running frequency can effectively reduce the power consumption of the system, and the running frequency of the CPU can be changed through the `rt_pm_run_enter` interface. Generally speaking, frequency reduction means that CPU performance decreases and processing speed decreases, which may lead to the increase of task execution time and need to be weighed reasonably. @@ -224,7 +224,7 @@ Reducing the running frequency can effectively reduce the power consumption of t rt_pm_run_enter(PM_RUN_MODE_MEDIUM_SPEED); ``` -## Migration instructions +# Migration instructions Low power management is a very meticulous task. Developers need not only to fully understand the power management of the chip itself, but also to be familiar with the peripheral circuit of the board and deal with it one by one when they enter the low power state, so as to avoid leakage of the peripheral circuit and pull up the overall power consumption. @@ -261,7 +261,7 @@ struct rt_device_pm_ops void rt_pm_device_register(struct rt_device *device, const struct rt_device_pm_ops *ops); ``` -### Power Consumption Characteristics of Chips +## Power Consumption Characteristics of Chips ```c void (*sleep)(struct rt_pm *pm, uint8_t mode); @@ -269,7 +269,7 @@ void (*sleep)(struct rt_pm *pm, uint8_t mode); Each chip has different definitions and management of low power mode. PM component abstracts chip-related characteristics into sleep interface. The interface adapts to low power management related to chips. When entering different `sleep` modes, some hardware-related configurations, storage and other related processing are needed. -### Time Compensation for Sleep Mode +## Time Compensation for Sleep Mode ```c void (*timer_start)(struct rt_pm *pm, rt_uint32_t timeout); @@ -296,7 +296,7 @@ rt_system_pm_init(&_ops, timer_mask, RT_NULL); ``` -### Frequency Conversion in Running Mode +## Frequency Conversion in Running Mode ``` void (*run)(struct rt_pm *pm, uint8_t mode); @@ -304,7 +304,7 @@ void (*run)(struct rt_pm *pm, uint8_t mode); The frequency conversion of operation mode is realized by adapting the `run` interface in `rt_pm_ops`, and the appropriate frequency is selected according to the use scenario. -### Power management of peripherals +## Power management of peripherals Power processing of peripherals is an important part of low power management system. When entering some level of sleep mode, it is usually necessary to process some peripherals, such as emptying DMA, closing clock or setting IO to reset state, and recover after quitting sleep. @@ -312,9 +312,9 @@ In this case, PM devices can be registered through rt_pm_device_register interfa A more detailed migration case can be referred to stm32l476-nucleo BSP in the RT-Thread repository. -## MSH Commands +# MSH Commands -### Request Sleep Mode +## Request Sleep Mode The `pm_request` command can be used to request related patterns, using an example as follows: @@ -339,7 +339,7 @@ enum }; ``` -### Release Sleep Mode +## Release Sleep Mode You can use the `pm_release` command to release the sleep mode. The range of parameters is 0-5, and the examples are as follows: @@ -348,7 +348,7 @@ msh />pm_release 0 msh /> ``` -### Setting up Running Mode +## Setting up Running Mode You can use the `pm_run` command to switch the mode of operation with parameters ranging from 0 to 3, as shown in the following example @@ -371,7 +371,7 @@ enum }; ``` -### View mode status +## View mode status You can use the `pm_dump` command to view the mode state of the PM component, as shown in the following example @@ -400,7 +400,7 @@ The `Timer` column identifies whether to turn on sleep time compensation. In the The bottom part identifies the current sleep mode and running mode level respectively. -## Common problems and debugging methods +# Common problems and debugging methods - When the system enters the low power mode, the power consumption is too high. diff --git a/documentation/posix/README.md b/documentation/posix/README.md index 57e49198c0..4254caec9c 100644 --- a/documentation/posix/README.md +++ b/documentation/posix/README.md @@ -1,6 +1,6 @@ -# POSIX Interface +@page component_posix POSIX Interface -## Introduction to Pthreads +# Introduction to Pthreads POSIX Threads is abbreviated as Pthreads. POSIX is the abbreviation of "Portable Operating System Interface". POSIX is a set of standards established by IEEE Computer Society to improve the compatibility of different operating systems and the portability of applications. Pthreads is a threaded POSIX standard defined in the POSIX.1c, Threads extensions (IEEE Std1003.1c-1995) standard, which defines a set of C programming language types, functions, and constants. Defined in the `pthread.h` header file and a thread library, there are about 100 APIs, all of which have a "`pthread_`" prefix and can be divided into 4 categories: @@ -34,7 +34,7 @@ Message queues, like semaphores, are used with Pthreads and are not part of the Most Pthreads functions return a value of 0 if they succeed, and an error code contained in the `errno.h` header file if unsuccessful. Many operating systems support Pthreads, such as Linux, MacOSX, Android, and Solaris, so applications written using Pthreads functions are very portable and can be compiled and run directly on many platforms that support Pthreads. -### Use POSIX in RT-Thread +## Use POSIX in RT-Thread Using the POSIX API interface in RT-Thread includes several parts: libc (for example, newlib), filesystem, pthread, and so on. Need to open the relevant options in rtconfig.h: @@ -47,17 +47,17 @@ Using the POSIX API interface in RT-Thread includes several parts: libc (for exa RT-Thread implements most of the functions and constants of Pthreads, defined in the pthread.h, mqueue.h, semaphore.h, and sched.h header files according to the POSIX standard. Pthreads is a sublibrary of libc, and Pthreads in RT-Thread are based on the encapsulation of RT-Thread kernel functions, making them POSIX compliant. The Pthreads functions and related functions implemented in RT-Thread are described in detail in the following sections. -## Thread +# Thread -### Thread Handle +## Thread Handle ``` c typedef rt_thread_t pthread_t; ``` -`Pthread_t` is a redefinition of the `rt_thread_t` type, defined in the `pthread.h` header file. rt_thread_t is the thread handle (or thread identifier) of the RT-Thread and is a pointer to the thread control block. You need to define a variable of type pthread_t before creating a thread. Each thread corresponds to its own thread control block, which is a data structure used by the operating system to control threads. It stores some information about the thread, such as priority, thread name, and thread stack address. Thread control blocks and thread specific information are described in detail in the [Thread Management](../thread/thread.md) chapter. +`Pthread_t` is a redefinition of the `rt_thread_t` type, defined in the `pthread.h` header file. rt_thread_t is the thread handle (or thread identifier) of the RT-Thread and is a pointer to the thread control block. You need to define a variable of type pthread_t before creating a thread. Each thread corresponds to its own thread control block, which is a data structure used by the operating system to control threads. It stores some information about the thread, such as priority, thread name, and thread stack address. Thread control blocks and thread specific information are described in detail in the @ref thread_management chapter. -### Create Thread +## Create Thread ``` c int pthread_create (pthread_t *tid, @@ -82,7 +82,7 @@ Thread properties and related functions are described in detail in the *Thread A > After the pthread thread is created, if the thread needs to be created repeatedly, you need to set the pthread thread to detach mode, or use pthread_join to wait for the created pthread thread to finish. -#### Example Code for Creating Thread +### Example Code for Creating Thread The following program initializes two threads, which have a common entry function, but their entry parameters are not the same. Others, they have the same priority and are scheduled for rotation in time slices. @@ -140,7 +140,7 @@ int rt_application_init() } ``` -### Detach Thread +## Detach Thread ``` c int pthread_detach (pthread_t thread); @@ -158,7 +158,7 @@ Usage: The child thread calls `pthread_detach(pthread_self())` (*pthread_self()* > Once the detach state of the thread property is set to detached, the thread cannot be waited by the pthread_join() function or re-set to detached. -#### Example Code for Detaching Thread +### Example Code for Detaching Thread The following program initializes 2 threads, which have the same priority and are scheduled according to the time slice. Both threads will be set to the detached state. The 2 threads will automatically exit after printing 3 times of information. After exiting, the system will automatically reclaim its resources. @@ -237,7 +237,7 @@ int rt_application_init() } ``` -### Waiting for Thread to End +## Waiting for Thread to End ``` c int pthread_join (pthread_t thread, void**value_ptr); @@ -257,7 +257,7 @@ The thread calling this function blocks and waits for the thread with the joinab The pthread_join() and pthread_detach() functions are similar in that they are used to reclaim the resources occupied by threads after the thread running ends. A thread cannot wait for itself to end. The detached state of the thread thread must be `joinable`, and one thread only corresponds to the `pthread_join()` call. A thread with a split state of joinable will only release the resources it occupies when other threads execute `pthread_join()` on it. So in order to avoid memory leaks, all threads that will end up running, either detached or set to detached, or use pthread_join() to reclaim the resources they consume. -#### Example Code for Waiting for the Thread to End +### Example Code for Waiting for the Thread to End The following program code initializes 2 threads, they have the same priority, and the threads of the same priority are scheduled according to the time slice. The separation status of the 2 thread attributes is the default value joinable, and thread 1 starts running first, and ends after printing 3 times of information. Thread 2 calls pthread_join() to block waiting for thread 1 to end, and reclaims the resources occupied by thread 1, and thread 2 prints the message every 2 seconds. @@ -336,7 +336,7 @@ int rt_application_init() } ``` -### Exit Thread +## Exit Thread ``` c void pthread_exit(void *value_ptr); @@ -350,7 +350,7 @@ Calling this function by the pthread thread terminates execution, just as the pr > If the split state of the thread is joinable, the resources occupied by the thread will not be released after the thread exits. The pthread_join() function must be called to release the resources occupied by the thread. -#### Example Code for Exiting Thread +### Example Code for Exiting Thread This program initializes 2 threads, they have the same priority, and the threads of the same priority are scheduled according to the time slice. The separation state of the two thread attributes is the default value joinable, and thread 1 starts running first, sleeps for 2 seconds after printing the information once, and then prints the exit information and then ends the operation. Thread 2 calls pthread_join() to block waiting for thread 1 to end, and reclaims the resources occupied by thread 1, and thread 2 prints the message every 2 seconds. @@ -426,7 +426,7 @@ int rt_application_init() } ``` -## Mutex +# Mutex Mutexes, also known as mutually exclusive semaphores, are a special binary semaphore. Mutexes are used to ensure the integrity of shared resources. Only one thread can access the shared resource at any time. To access shared resources, the thread must first obtain the mutex. After the access is complete, the mutex must be released. Embedded shared resources include memory, IO, SCI, SPI, etc. If two threads access shared resources at the same time, there may be problems because one thread may use the resource while another thread modifies the shared resource and consider sharing. @@ -436,9 +436,9 @@ The main APIs of the mutex include: calling `pthread_mutex_init()` to initialize The rt-thread operating system implements a priority inheritance algorithm to prevent priority inversion.Priority inheritance is the practice of raising the priority of a low-priority thread that occupies a resource to the same level as the highest-priority thread of all the threads waiting for the resource, then executing, and then returning to the initial setting when the low-priority thread releases the resource.Thus, threads that inherit priority prevent system resources from being preempted by any intermediate priority thread. -For a detailed introduction to priority reversal, please refer to the [Inter-thread Synchronization](../thread-sync/thread-sync.md) Mutex section. +For a detailed introduction to priority reversal, please refer to the @ref thread_sync Mutex section. -### Mutex Lock Control Block +## Mutex Lock Control Block Each mutex corresponds to a mutex control block that contains some information about the control of the mutex. Before creating a mutex, you must first define a variable of type `pthread_mutex_t`. pthread_mutex_t is a redefinition of pthread_mutex. The pthread_mutex data structure is defined in the pthread.h header file. The data structure is as follows: @@ -463,7 +463,7 @@ struct rt_mutex typedef struct rt_mutex* rt_mutex_t; /* Rt_mutext_t is a pointer to the mutex structure */ ``` -### Initialize the Mutex +## Initialize the Mutex ``` c int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); @@ -483,7 +483,7 @@ In addition to calling the pthread_mutex_init() function to create a mutex, you The mutex lock properties and related functions are described in detail in the *thread advanced programming* chapter. In general, the default properties can be used. -### Destroy Mutex +## Destroy Mutex ``` c int pthread_mutex_destroy(pthread_mutex_t *mutex); @@ -501,7 +501,7 @@ This function destroys the mutex `mutex`. Mutex is mutable in an uninitialized s The mutex can be destroyed when it is determined that the mutex is not locked and no thread is blocked on the mutex. -### Blocking Mode Locks the Mutex +## Blocking Mode Locks the Mutex ``` c int pthread_mutex_lock(pthread_mutex_t *mutex); @@ -517,7 +517,7 @@ int pthread_mutex_lock(pthread_mutex_t *mutex); This function locks the mutex `mutex`, which is a wrapper of the rt_mutex_take() function. If the mutex has not been locked yet, the thread applying for the mutex will successfully lock the mutex. If the mutex has been locked by the current thread and the mutex type is a nested lock, the mutex's holding count is incremented by one, and the current thread will not suspend waiting (deadlock), but the thread must corresponds to the same number of unlocks. If the mutex is held by another thread, the current thread will be blocked until the other thread unlocks the mutex, and the thread waiting for the mutex will acquire the mutex according to the *first in first out* principle. . -### Non-blocking Mode Locks the Mutex +## Non-blocking Mode Locks the Mutex ``` c int pthread_mutex_trylock(pthread_mutex_t *mutex); @@ -534,7 +534,7 @@ int pthread_mutex_trylock(pthread_mutex_t *mutex); This function is a non-blocking version of the pthread_mutex_lock() function. The difference is that if the mutex has been locked, the thread will not be blocked, but the error code will be returned immediately. -### Unlock the Mutex +## Unlock the Mutex ``` c int pthread_mutex_unlock(pthread_mutex_t *mutex); @@ -551,7 +551,7 @@ int pthread_mutex_unlock(pthread_mutex_t *mutex); Calling this function to unlock the mutex. This function is a wrapper of the rt_mutex_release() function. When the thread completes the access of the shared resource, it should release the possessed mutex as soon as possible, so that other threads can acquire the mutex in time. Only a thread that already has a mutex can release it, and its holding count is decremented by one each time the mutex is released. When the mutex's holding count is zero (ie, the holding thread has released all holding operations), the mutex becomes available, and the thread waiting on the mutex is placed in a first-in-first-out manner. If the thread's run priority is promoted by the mutex lock, then when the mutex is released, the thread reverts to the priority before holding the mutex. -### Example Code for Mutex Lock +## Example Code for Mutex Lock This program will initialize 2 threads, they have the same priority, 2 threads will call the same printer() function to output their own string, the printer() function will output only one character at a time, then sleep for 1 second, call printer The thread of the () function also sleeps. If you do not use a mutex, thread 1 prints a character, and after hibernation, thread 2 is executed, and thread 2 prints a character, so that the thread 1 and thread 2 strings cannot be completely printed, and the printed string is confusing. If a mutex is used to protect the print function printer() shared by 2 threads, thread 1 takes the mutex and executes the printer() print function to print a character, then sleeps for 1 second, which is switched to thread 2 because The nick lock has been locked by thread 1, and thread 2 will block until thread 1 of thread 1 is fully released and the thread 2 is woken up after the mutex is actively released. @@ -636,7 +636,7 @@ int rt_application_init() } ``` -## Conditional Variable +# Conditional Variable A condition variable is actually a semaphore used for synchronization between threads. A condition variable is used to block a thread. When a condition is met, a condition is sent to the blocked thread. The blocking thread is woken up. The condition variable needs to be used with the mutex. The mutex is used to protect the shared data. @@ -644,7 +644,7 @@ Condition variables can be used to inform shared data status. For example, if a The main operations of the condition variable include: calling `pthread_cond_init()` to initialize the condition variable, calling `pthread_cond_destroy()` to destroy a condition variable, calling `pthread_cond_wait()` to wait for a condition variable, and calling `pthread_cond_signal()` to send a condition variable. -### Condition Variable Control Block +## Condition Variable Control Block Each condition variable corresponds to a condition variable control block, including some information about the operation of the condition variable. A `pthread_cond_t` condition variable control block needs to be defined before initializing a condition variable. `pthread_cond_t` is a redefinition of the `pthread_cond` structure type, defined in the pthread.h header file. @@ -665,7 +665,7 @@ struct rt_semaphore }; ``` -### Initialization Condition Variable +## Initialization Condition Variable ``` c int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); @@ -685,7 +685,7 @@ You can also statically initialize a condition variable with the macro PTHREAD_C Attr General setting NULL use the default value, as described in the thread advanced programming chapter. -### Destroy Condition Variables +## Destroy Condition Variables ``` c int pthread_cond_destroy(pthread_cond_t *cond); @@ -704,7 +704,7 @@ This function destroys the `cond` condition variable, and the `cond` is uninitia Before destroying a condition variable, you need to make sure that no threads are blocked on the condition variable and will not wait to acquire, signal, or broadcast. -### Blocking Mode to Obtain Condition Variables +## Blocking Mode to Obtain Condition Variables ``` c int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); @@ -720,7 +720,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); This function gets the `cond` condition variable in blocking mode. The thread needs to lock the mutex before waiting for the condition variable. This function first determines whether the condition variable is available. If it is not available, initializes a condition variable, then unlocks the mutex and then tries to acquire a semaphore when the semaphore's value is greater than zero, it indicates that the semaphore is available, the thread will get the semaphore, and the condition variable will be obtained, and the corresponding semaphore value will be decremented by 1. If the value of the semaphore is equal to zero, indicating that the semaphore is not available, the thread will block until the semaphore is available, after which the mutex will be locked again. -### Specify Blocking Time to Obtain Condition Variables +## Specify Blocking Time to Obtain Condition Variables ``` c int pthread_cond_timedwait(pthread_cond_t *cond, @@ -741,7 +741,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, The only difference between this function and the `pthread_cond_wait()` function is that if the condition variable is not available, the thread will be blocked for the `abstime` duration. After the timeout, the function will directly return the ETIMEDOUT error code and the thread will be woken up to the ready state. -### Send a Conditional Semaphore +## Send a Conditional Semaphore ``` c int pthread_cond_signal(pthread_cond_t *cond); @@ -755,7 +755,7 @@ int pthread_cond_signal(pthread_cond_t *cond); This function sends a signal and wakes up only one thread waiting for the `cond` condition variable, which encapsulates the rt_sem_release() function, which is to send a semaphore. When the value of the semaphore is equal to zero, and a thread waits for this semaphore, it will wake up the first thread waiting in the queue of the semaphore to get the semaphore. Otherwise the value of the semaphore will be increased by 1. -### Broadcast +## Broadcast ``` c int pthread_cond_broadcast(pthread_cond_t *cond); @@ -770,7 +770,7 @@ int pthread_cond_broadcast(pthread_cond_t *cond); Calling this function will wake up all threads waiting for the `cond` condition variable. -### Example Code for Condition Variable +## Example Code for Condition Variable This example is a producer consumer model with a producer thread and a consumer thread that have the same priority. The producer will produce a number every 2 seconds, put it in the list pointed to by the `head`, and then call pthread_cond_signal() to send signal to the consumer thread to inform the consumer that there is data in the thread list. The consumer thread calls pthread_cond_wait() to wait for the producer thread to send a signal. @@ -885,7 +885,7 @@ int rt_application_init() } ``` -## Read-write Lock +# Read-write Lock Read-write locks are also known as multi-reader single-writer locks. The read-write lock divides the visitors of the shared resource into readers and writers. The reader only reads and accesses the shared resources, and the writer needs to write the shared resources. Only one thread can occupy the read-write lock of the write mode at the same time, but there can be multiple threads simultaneously occupying the read-write lock of the read mode. Read-write locks are suitable for reading data structures much more often than writes because read patterns can be shared when locked, and write mode locks are exclusive. @@ -893,7 +893,7 @@ Read-write locks are usually implemented based on mutex locks and condition vari The main operations of the read-write lock include: calling `pthread_rwlock_init()` to initialize a read-write lock, the write thread calling `pthread_rwlock_wrlock()` to lock the read-write lock, and the read thread calling `pthread_rwlock_rdlock()` to lock the read-write lock , when this read-write lock is not required, calling `pthread_rwlock_destroy()` to destroys the read-write lock. -### Read-write Lock Control Block +## Read-write Lock Control Block Each read-write lock corresponds to a read-write lock control block, including some information about the operation of the read-write lock. `pthread_rwlock_t` is a redefinition of the `pthread_rwlock` data structure, defined in the `pthread.h` header file. Before creating a read-write lock, you need to define a data structure of type `pthread_rwlock_t`. @@ -912,7 +912,7 @@ struct pthread_rwlock typedef struct pthread_rwlock pthread_rwlock_t; /* Type redefinition */ ``` -### Initialize Read-write Lock +## Initialize Read-write Lock ``` c int pthread_rwlock_init (pthread_rwlock_t *rwlock, @@ -933,7 +933,7 @@ You can also use the macro PTHREAD_RWLOCK_INITIALIZER to statically initialize t `attr` generally sets NULL to the default value, as described in the chapter on advanced threading. -### Destroy Read-write Lock +## Destroy Read-write Lock ``` c int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); @@ -950,9 +950,9 @@ int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); This function destroys a `rwlock` read-write lock, which destroys the mutex and condition variables in the read-write lock. After the destruction, the properties of the read-write lock and the control block parameters will not be valid, but you can call pthread_rwlock_init() or re-initialize the read-write lock in static mode. -### Read-Lock of Read-Write Lock +## Read-Lock of Read-Write Lock -#### Blocking mode Read-lock the read-write locks +### Blocking mode Read-lock the read-write locks ``` c int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); @@ -968,7 +968,7 @@ int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); The reader thread can call this function to read-lock the `rwlock` read-write lock. If the read-write lock is not write-locked and no writer thread is blocked on the read-write lock, the read-write thread will successfully acquire the read-write lock. If the read-write lock has been write-locked, the reader thread will block until the thread that executes the write-lock unlocks the read-write lock. -#### Non-blocking Mode Read-lock Read-write Locks +### Non-blocking Mode Read-lock Read-write Locks ``` c int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); @@ -985,7 +985,7 @@ int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); This function differs from the pthread_rwlock_rdlock() function in that if the read-write lock is already write-locked, the reader thread is not blocked, but instead returns an error code EBUSY. -#### Specify Blocking Time for the Read-write Lock to be Read-Locked +### Specify Blocking Time for the Read-write Lock to be Read-Locked ``` c int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, @@ -1004,9 +1004,9 @@ int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, The difference between this function and the pthread_rwlock_rdlock() function is that if the read-write lock has been write-locked, the reader thread will block the specified abstime duration. After the timeout, the function will return the error code ETIMEDOUT and the thread will be woken up to the ready state. -### Write-Lock of Read-Write Lock +## Write-Lock of Read-Write Lock -#### Blocking Mode Write-Locks a Read-write Lock +### Blocking Mode Write-Locks a Read-write Lock ``` c int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); @@ -1022,7 +1022,7 @@ int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); The writer thread calls this function to write-lock the `rwlock` read-write lock. A write-lock read-write lock is similar to a mutex, and only one thread can write-lock a read-write lock at a time. If no thread locks the read-write lock, that is, the read-write lock value is 0, the writer thread that calls this function will write-lock the read-write lock, and other threads cannot acquire the read-write lock at this time. If there is already a thread locked the read-write lock, ie the read/write lock value is not 0, then the writer thread will be blocked until the read-write lock is unlocked. -#### Non-blocking Mode Write-Lock a Read-write Lock +### Non-blocking Mode Write-Lock a Read-write Lock ``` c int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); @@ -1039,7 +1039,7 @@ int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); The only difference between this function and the pthread_rwlock_wrlock() function is that if a thread has locked the read-write lock, ie the read-write lock value is not 0, the writer thread that called the function will directly return an error code, and the thread will not be Blocked. -#### Specify Blocking Time for the Read-write Lock to be Write-Lock +### Specify Blocking Time for the Read-write Lock to be Write-Lock ``` c int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, @@ -1057,7 +1057,7 @@ int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, The only difference between this function and the pthread_rwlock_wrlock() function is that if a thread locks the read-write lock, that is, the read-write lock value is not 0, the calling thread blocks the specified `abstime` duration. After the timeout, the function returns the error code ETIMEDOUT, and the thread will be woken up to the ready state. -### Unlock the Read-write Lock +## Unlock the Read-write Lock ``` c int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); @@ -1073,7 +1073,7 @@ int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); This function unlocks the `rwlock` read-write lock. A thread locks the same read-write lock multiple times and must have the same number of unlocks. If multiple threads wait for the read-write lock to lock after unlocking, the system will activate the waiting thread according to the first-in-first-out rule. -### Example Code for Read-write Lock +## Example Code for Read-write Lock This program has two reader threads, one reader thread. The two reader threads read-lock the read-write lock first, then sleep for 2 seconds. This time the other reader threads can read-lock the read-write lock, and then read the shared data. @@ -1165,13 +1165,13 @@ int rt_application_init() } ``` -## Barrier +# Barrier Barriers are a way to synchronize multithreading. Barrier means a barrier or railing that blocks multiple threads that arrive in the same railing until all threads arrived, then remove the railings and let them go at the same time. The thread that arrives first will block, and when all the threads that call the pthread_barrier_wait() function (the number equal to the count specified by the barrier initialization) arrive, the threads will enter the ready state from the blocked state and participate in the system scheduling again. Barriers are implemented based on condition variables and mutex locks. The main operations include: calling `pthread_barrier_init()` to initialize a barrier, and other threads calling `pthread_barrier_wait()`. After all threads arrived, the thread wakes up to the ready state. Destroy a barrier by calling pthread_barrier_destroy() when the barrier will not be used. -### Barrier Control Block +## Barrier Control Block Before creating a barrier, you need to define a `pthread_barrier_t` barrier control block. `pthread_barrier_t` is a redefinition of the `pthread_barrier` structure type, defined in the pthread.h header file. @@ -1185,7 +1185,7 @@ struct pthread_barrier typedef struct pthread_barrier pthread_barrier_t; ``` -### Create a Barrier +## Create a Barrier ``` c int pthread_barrier_init(pthread_barrier_t *barrier, @@ -1206,7 +1206,7 @@ This function creates a `barrier` barrier and initializes the conditional variab attr generally sets NULL to the default value, as described in the chapter on *thread advanced programming*. -### Destruction of Barrier +## Destruction of Barrier ``` c int pthread_barrier_destroy(pthread_barrier_t *barrier); @@ -1221,7 +1221,7 @@ int pthread_barrier_destroy(pthread_barrier_t *barrier); This function destroys a barrier. The barrier's properties and control block parameters will not be valid after destruction, but can be reinitialized by calling pthread_barrier_init(). -### Wait for Barrier +## Wait for Barrier ``` c int pthread_barrier_wait(pthread_barrier_t *barrier); @@ -1236,7 +1236,7 @@ int pthread_barrier_wait(pthread_barrier_t *barrier); This function synchronizes the threads waiting in front of the barrier and called by each thread. If the number of queue waiting threads is not 0, count will be decremented by 1. If the count is 0, indicating that all threads have reached the railing. All arriving threads will be woken up and re-entered into the ready state to participate in system scheduling. If count is not 0 after the decrease, it indicates that there is still threads that do not reach the barrier, and the calling thread will block until all threads reach the barrier. -### Example Code for Barrier +## Example Code for Barrier This program will create 3 threads, initialize a barrier, and the barrier waits for 3 threads. 3 threads will call pthread_barrier_wait() to wait in front of the barrier. When all 3 threads are arrived, 3 threads will enter the ready state. The output count information is printed every 2 seconds. @@ -1335,7 +1335,7 @@ int rt_application_init() } ``` -## Semaphore +# Semaphore Semaphores can be used for communication between processes and processes, or between in-process threads. Each semaphore has a semaphore value that is not less than 0, corresponding to the available amount of semaphore. Call sem_init() or sem_open() to assign an initial value to the semaphore . Call sem_post() to increment the semaphore value by 1. Call sem_wait() to decrement the semaphore value by 1. If the current semaphore is 0, call sem_wait(), the thread will suspended on the wait queue for this semaphore until the semaphore value is greater than 0 and is available. @@ -1353,7 +1353,7 @@ POSIX semaphores are also divided into named semaphores and unnamed semaphores: The POSIX semaphore of the RT-Thread operating system is mainly based on a package of RT-Thread kernel semaphores, mainly used for communication between threads in the system. It is used in the same way as the semaphore of the RT-Thread kernel. -### Semaphore Control Block +## Semaphore Control Block Each semaphore corresponds to a semaphore control block. Before creating a semaphore, you need to define a sem_t semaphore control block. Sem_t is a redefinition of the posix_sem structure type, defined in the semaphore.h header file. @@ -1380,11 +1380,11 @@ typedef struct rt_semaphore* rt_sem_t; ``` -### Unnamed semaphore +## Unnamed semaphore The value of an unnamed semaphore is stored in memory and is generally used for inter-thread synchronization or mutual exclusion. Before using it, you must first call sem_init() to initialize it. -#### Initialize the unnamed semaphore +### Initialize the unnamed semaphore ``` c int sem_init(sem_t *sem, int pshared, unsigned int value); @@ -1401,7 +1401,7 @@ int sem_init(sem_t *sem, int pshared, unsigned int value); This function initializes an unnamed semaphore sem, initializes the semaphore related data structure according to the given or default parameters, and puts the semaphore into the semaphore list. The semaphore value after initialization is the given initial value. This function is a wrapper of the rt_sem_create() function. -#### Destroy Unnamed Semaphore +### Destroy Unnamed Semaphore ``` c int sem_destroy(sem_t *sem); @@ -1416,11 +1416,11 @@ int sem_destroy(sem_t *sem); This function destroys an unnamed semaphore sem and releases the resources occupied by the semaphore. -### Named Semaphore +## Named Semaphore A named semaphore whose value is stored in a file and is generally used for inter-process synchronization or mutual exclusion. Two processes can operate on named semaphores of the same name. The well-known semaphore implementation in the RT-Thread operating system is similar to the unnamed semaphore. It is designed for communication between threads and is similar in usage. -#### Create or Open a Named Semaphore +### Create or Open a Named Semaphore ``` c sem_t *sem_open(const char *name, int oflag, ...); @@ -1436,7 +1436,7 @@ sem_t *sem_open(const char *name, int oflag, ...); This function creates a new semaphore based on the semaphore name or opens an existing semaphore. The optional values for Oflag are `0`, `O_CREAT` or `O_CREAT|O_EXCL`. If Oflag is set to `O_CREAT` , a new semaphore is created. If Oflag sets to `O_CREAT|O_EXCL`, it returns NULL if the semaphore already exists, and creates a new semaphore if it does not exist. If Oflag is set to 0, a semaphore does not exist and NULL is returned. -#### Detach the Named Semaphore +### Detach the Named Semaphore ``` c int sem_unlink(const char *name); @@ -1451,7 +1451,7 @@ int sem_unlink(const char *name); This function looks up the semaphore based on the semaphore name, and marks the semaphore as a detached state if the semaphore is present. Then check the reference count. If the value is 0, the semaphore is deleted immediately. If the value is not 0, it will not be deleted until all threads holding the semaphore close the semaphore. -#### Close the Named Semaphore +### Close the Named Semaphore ``` c int sem_close(sem_t *sem); @@ -1466,7 +1466,7 @@ int sem_close(sem_t *sem); When a thread terminates,it closes the semaphore it occupies. Whether the thread terminates voluntarily or involuntarily, this closing operation is performed. This is equivalent to a reduction of 1 in the number of semaphores held. If the holding count is zero after subtracting 1 and the semaphore is in separated state, the `sem` semaphore will be deleted and the resources it occupies will be released. -### Obtain Semaphore Value +## Obtain Semaphore Value ``` c int sem_getvalue(sem_t *sem, int *sval); @@ -1482,7 +1482,7 @@ int sem_getvalue(sem_t *sem, int *sval); This function obtains the value of the semaphore and saves it in the memory pointed to by `sval` to know the amount of semaphore resources. -### Blocking Mode to Wait Semaphore +## Blocking Mode to Wait Semaphore ``` c int sem_wait(sem_t *sem); @@ -1497,7 +1497,7 @@ int sem_wait(sem_t *sem); The thread calls this function to get the semaphore, which is a wrapper of the `rt_sem_take(sem,RT_WAITING_FOREVER)` function. If the semaphore value is greater than zero, the semaphore is available, the thread gets the semaphore, and the semaphore value is decremented by one. If the semaphore value is equal to 0, indicating that the semaphore is not available, the thread is blocked and entering the suspended state and queued in a first-in, first-out manner until the semaphore is available. -### Non-blocking Mode to Wait Semaphore +## Non-blocking Mode to Wait Semaphore ``` c int sem_trywait(sem_t *sem); @@ -1512,7 +1512,7 @@ int sem_trywait(sem_t *sem); This function is a non-blocking version of the sem_wait() function and is a wrapper of the `rt_sem_take(sem,0)` function. When the semaphore is not available, the thread does not block, but returns directly. -### Specify the Blocking Time Waiting for the Semaphore +## Specify the Blocking Time Waiting for the Semaphore ``` c int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); @@ -1528,7 +1528,7 @@ int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); The difference between this function and `the sem_wait()` function is that if the semaphore is not available, the thread will block the duration of `abs_timeout`. After the timeout, the function returns -1, and the thread will be awakened from the blocking state to the ready state. -### Send Semaphore +## Send Semaphore ``` c int sem_post(sem_t *sem); @@ -1543,7 +1543,7 @@ int sem_post(sem_t *sem); This function will release a sem semaphore, which is a wrapper of the rt_sem_release() function. If the thread queue waiting for the semaphore is not empty, indicating that there are threads waiting for the semaphore, the first thread waiting for the semaphore will switch from the suspended state to the ready state, waiting for system scheduling. If no thread is waiting for the semaphore, the semaphore value will be incremented by one. -### Example Code for Unnamed Semaphore +## Example Code for Unnamed Semaphore A typical case of semaphore usage is the producer consumer model. A producer thread and a consumer thread operate on the same block of memory, the producer fills the shared memory, and the consumer reads the data from the shared memory. @@ -1662,7 +1662,7 @@ int rt_application_init() } ``` -## Message Queue +# Message Queue Message Queuing is another commonly used inter-thread communication method that accepts messages of unfixed length from threads or interrupt service routines and caches the messages in their own memory space. Other threads can also read the corresponding message from the message queue, and when the message queue is empty, the reader thread can be suspended. When a new message arrives, the suspended thread will be woken up to receive and process the message. @@ -1670,7 +1670,7 @@ The main operations of the message queue include: creating or opening by the fun POSIX message queue is mainly used for inter-process communication. The POSIX message queue of RT-Thread operating system is mainly based on a package of RT-Thread kernel message queue, mainly used for communication between threads in the system. It is used in the same way as the message queue of the RT-Thread kernel. -### Message Queue Control Block +## Message Queue Control Block Each message queue corresponds to a message queue control block. Before creating a message queue, you need to define a message queue control block. The message queue control block is defined in the mqueue.h header file. @@ -1685,7 +1685,7 @@ struct mqdes typedef struct mqdes* mqd_t; /* Message queue control block pointer type redefinition */ ``` -### Create or Open a Message Queue +## Create or Open a Message Queue ``` c mqd_t mq_open(const char *name, int oflag, ...); @@ -1701,7 +1701,7 @@ mqd_t mq_open(const char *name, int oflag, ...); This function creates a new message queue or opens an existing message queue based on the name of the message queue. The optional values for Oflag are `0`, `O_CREAT` or `O_CREAT\|O_EXCL`. If Oflag is set to `O_CREAT` then a new message queue is created. If Oflag sets `O_CREAT\|O_EXCL`, it returns NULL if the message queue already exists, and creates a new message queue if it does not exist. If Oflag is set to `0`, the message queue does not exist and returns NULL. -### Detach Message Queue +## Detach Message Queue ``` c int mq_unlink(const char *name); @@ -1716,7 +1716,7 @@ int mq_unlink(const char *name); This function finds the message queue based on the message queue name name. If found, it sets the message queue to a detached state. If the hold count is 0, the message queue is deleted and the resources occupied by the message queue are released. -### Close the Message Queue +## Close the Message Queue ``` c int mq_close(mqd_t mqdes); @@ -1731,7 +1731,7 @@ int mq_close(mqd_t mqdes); When a thread terminates,it closes the message queue it occupies. Whether the thread terminates voluntarily or involuntarily, this closure is performed. This is equivalent to the message queue holding count minus 1. If the holding count is 0 after the minus 1 and the message queue is in the separated state, the `mqdes` message queue will be deleted and released the resources it occupies. -### Block Mode to Send a Message +## Block Mode to Send a Message ``` c int mq_send(mqd_t mqdes, @@ -1754,7 +1754,7 @@ This function is used to send a message to the `mqdes` message queue, which is a If the message queue is full, that is, the number of messages in the message queue is equal to the maximum number of messages, the thread that sent the message or the interrupt program will receive an error code (-RT_EFULL). -### Specify Blocking Time to Send a Message +## Specify Blocking Time to Send a Message ``` c int mq_timedsend(mqd_t mqdes, @@ -1777,7 +1777,7 @@ int mq_timedsend(mqd_t mqdes, Currently RT-Thread does not support sending messages with the specified blocking time, but the function interface has been implemented, which is equivalent to calling mq_send(). -### Blocking Mode to Receive Message +## Blocking Mode to Receive Message ``` c ssize_t mq_receive(mqd_t mqdes, @@ -1798,7 +1798,7 @@ ssize_t mq_receive(mqd_t mqdes, This function removes the oldest message from the `mqdes` message queue and puts the message in the memory pointed to by `msg_ptr`. If the message queue is empty, the thread that called the mq_receive() function will block until the message in the message queue is available. -### Specify Blocking Time to Receive Message +## Specify Blocking Time to Receive Message ``` c ssize_t mq_timedreceive(mqd_t mqdes, @@ -1821,7 +1821,7 @@ ssize_t mq_timedreceive(mqd_t mqdes, The difference between this function and the mq_receive() function is that if the message queue is empty, the thread will block the `abs_timeout` duration. After the timeout, the function will return `-1`, and the thread will be awakened from the blocking state to the ready state. -### Example Code for Message Queue +## Example Code for Message Queue This program creates 3 threads, thread2 accepts messages from the message queue, and thread2 and thread3 send messages to the message queue. @@ -1953,7 +1953,7 @@ int rt_application_init() } ``` -## Thread Advanced Programming +# Thread Advanced Programming This section provides a detailed introduction to some of the rarely used property objects and related functions. @@ -1976,7 +1976,7 @@ struct pthread_attr }; ``` -#### Thread Property Initialization and Deinitialization +## Thread Property Initialization and Deinitialization The thread property initialization and deinitialization functions are as follows: @@ -1995,7 +1995,7 @@ Using the pthread_attr_init() function initializes the thread attribute structur The pthread_attr_destroy() function deinitializes the property pointed to by `attr` and can then reinitialize this property object by calling the pthread_attr_init() function again. -#### Thread Detached State +## Thread Detached State Setting or getting the separation state of a thread is as follows. By default, the thread is non-separated. @@ -2015,7 +2015,7 @@ The thread separation state property value state can be `PTHREAD_CREATE_JOINABL` The detached state of a thread determines how a thread reclaims the resources it occupies after the end of its run. There are two types of thread separation: joinable or detached. When the thread is created, you should call pthread_join() or pthread_detach() to reclaim the resources occupied by the thread after it finishes running. If the thread's detached state is joinable, other threads can call the pthread_join() function to wait for the thread to finish and get the thread return value, and then reclaim the resources occupied by the thread. A thread with a detached state cannot be joined by another thread. Immediately after the end of its operation, the system resources are released. -#### Thread Scheduling Policy +## Thread Scheduling Policy Setting \ Obtaining thread scheduling policy function is as follows: @@ -2026,7 +2026,7 @@ int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy); Only the function interface is implemented. The default different priorities are based on priority scheduling, and the same priority time slice polling scheduling -#### Thread Scheduling Parameter +## Thread Scheduling Parameter Set / Obtain the thread's priority function as follows: @@ -2057,7 +2057,7 @@ struct sched_param The member `sched_paraority` of the `sched_param` controls the priority value of the thread. -#### Thread Stack Size +## Thread Stack Size Set / Obtain the stack size of a thread is as follows: @@ -2075,7 +2075,7 @@ int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size); The `pthread_attr_setstacksize()` function sets the stack size in bytes. Stack space address alignment is required on most systems (for example, the ARM architecture needs to be aligned to a 4-byte address). -#### Thread Stack Size and Address +## Thread Stack Size and Address Set / Obtain the stack address and stack size of a thread is as follows: @@ -2096,7 +2096,7 @@ int pthread_attr_getstack(pthread_attr_t const *attr, |**return**| —— | | 0 | Succeeded | -#### Thread Attribute Related Function +## Thread Attribute Related Function The function that sets / obtains the scope of the thread is as follows: @@ -2114,7 +2114,7 @@ int pthread_attr_getscope(pthread_attr_t const *attr); | EOPNOTSUPP | scope is PTHREAD_SCOPE_PROCESS | | EINVAL | scope is PTHREAD_SCOPE_SYSTEM | -#### Example Code for Thread Property +## Example Code for Thread Property This program will initialize 2 threads, they have a common entry function, but their entry parameters are not the same. The first thread created will use the provided `attr` thread attribute, and the other thread will use the system default attribute. Thread priority is a very important parameter, so this program will modify the first created thread to have a priority of 8, and the system default priority of 24. @@ -2178,11 +2178,11 @@ int rt_application_init() } ``` -### Thread Cancellation +## Thread Cancellation Cancellation is a mechanism that allows one thread to end other threads. A thread can send a cancel request to another thread. Depending on the settings, the target thread may ignore it and may end immediately or postpone it until the next cancellation point. -#### Send Cancellation Request +### Send Cancellation Request The cancellation request can be sent using the following function: @@ -2198,7 +2198,7 @@ int pthread_cancel(pthread_t thread); This function sends a cancel request to the `thread` thread. Whether the thread will respond to the cancellation request and when it responds depends on the state and type of thread cancellation. -#### Set Cancel Status +### Set Cancel Status The cancellation request can be set using the following function: @@ -2216,7 +2216,7 @@ int pthread_setcancelstate(int state, int *oldstate); This function sets the cancel state and is called by the thread itself. Canceling the enabled thread will react to the cancel request, and canceling the disabled thread will not react to the cancel request. -#### Set Cancellation Type +### Set Cancellation Type You can use the following function to set the cancellation type, which is called by the thread itself: @@ -2232,7 +2232,7 @@ int pthread_setcanceltype(int type, int *oldtype); | 0 | Succeeded | | EINVAL | state is neither PTHREAD_CANCEL_DEFFERED nor PTHREAD_CANCEL_ASYNCHRONOUS | -#### Set Cancellation Point +### Set Cancellation Point The cancellation point can be set using the following function: @@ -2242,7 +2242,7 @@ void pthread_testcancel(void); This function creates a cancellation point where the thread is called. Called primarily by a thread that does not contain a cancellation point, it can respond to a cancellation request. This function does not work if pthread_testcancel() is called while the cancel state is disabled. -#### Cancellation Point +### Cancellation Point The cancellation point is where the thread ends when it accepts the cancellation request. According to the POSIX standard, system calls that cause blocking, such as pthread_join(), pthread_testcancel(), pthread_cond_wait(), pthread_cond_timedwait(), and sem_wait(), are cancellation points. @@ -2282,7 +2282,7 @@ All cancellation points included in RT-Thread are as follows: - pthread_rwlock_wrlock() -#### Example Code for Thread Cancel +### Example Code for Thread Cancel This program creates 2 threads. After thread2 starts running, it sleeps for 8 seconds. Thread1 sets its own cancel state and type, and then prints the run count information in an infinite loop. After thread2 wakes up, it sends a cancel request to thread1, and thread1 ends the run immediately after receiving the cancel request. @@ -2356,7 +2356,7 @@ int rt_application_init() } ``` -### One-time Initialization +## One-time Initialization It can be initialized once using the following function: @@ -2373,7 +2373,7 @@ int pthread_once(pthread_once_t * once_control, void (*init_routine) (void)); Sometimes we need to initialize some variables only once. If we do multiple initialization procedures, it will get an error. In traditional sequential programming, one-time initialization is often managed by using Boolean variables. The control variable is statically initialized to 0, and any code that relies on initialization can test the variable. If the variable value is still 0, it can be initialized and then set the variable to 1. Codes that are checked later will skip initialization. -### Clean up after the Thread Ends +## Clean up after the Thread Ends The thread cleanup function interface: @@ -2390,9 +2390,9 @@ void pthread_cleanup_push(void (*routine)(void*), void *arg); pthread_cleanup_push() puts the specified cleanup `routine` into the thread's cleanup function list. pthread_cleanup_pop() takes the first function from the header of the cleanup function list. If `execute` is a non-zero value, then this function is executed. -### Other Thread Related Functions +## Other Thread Related Functions -#### Determine if two Threads are Equal +### Determine if two Threads are Equal ``` c int pthread_equal (pthread_t t1, pthread_t t2); @@ -2405,14 +2405,14 @@ int pthread_equal (pthread_t t1, pthread_t t2); | 0 | Not equal | | 1 | Equal | -#### Obtain Thread Handle +### Obtain Thread Handle ``` c pthread_t pthread_self (void); ``` pthread_self() returns the handle of the calling thread. -#### Get the Maximum and Minimum Priority +### Get the Maximum and Minimum Priority ``` c int sched_get_priority_min(int policy); @@ -2425,11 +2425,11 @@ int sched_get_priority_max(int policy); sched_get_priority_min() returns a value of 0, with the highest priority in RT-Thread and sched_get_priority_max() with the lowest priority. -### Mutex Attribute +## Mutex Attribute The mutex properties implemented by RT-Thread include the mutex type and the mutex scope. -#### Mutex Lock Attribute Initialization and Deinitialization +### Mutex Lock Attribute Initialization and Deinitialization ``` c int pthread_mutexattr_init(pthread_mutexattr_t *attr); @@ -2447,7 +2447,7 @@ The pthread_mutexattr_init() function initializes the property object pointed to The pthread_mutexattr_destroy() function will initialize the property object pointed to by `attr` and can be reinitialized by calling the pthread_mutexattr_init() function. -#### Mutex Lock Scope +### Mutex Lock Scope ``` c int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); @@ -2462,7 +2462,7 @@ int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared); | 0 | Succeeded | | EINVAL | Invalid parameter | -#### Mutex Type +### Mutex Type ``` c int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); @@ -2485,7 +2485,7 @@ The type of mutex determines how a thread behaves when it acquires a mutex. RT-T - **PTHREAD_MUTEX_ERRORCHECK**: Error checking lock, if a thread tries to regain the mutex without first releasing the mutex, an error is returned. This ensures that deadlocks do not occur when multiple locks are not allowed. -### Condition Variable Attribute +## Condition Variable Attribute Use the default value PTHREAD_PROCESS_PRIVATE to initialize the condition variable attribute attr to use the following function: @@ -2500,7 +2500,7 @@ int pthread_condattr_init(pthread_condattr_t *attr); | 0 | Succeeded | | EINVAL | Invalid parameter | -#### Obtain Condition Variable Scope +### Obtain Condition Variable Scope ``` c int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared); @@ -2513,9 +2513,9 @@ int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared); | 0 | Succeeded | | EINVAL | Invalid parameter | -### Read-write Lock Attribute +## Read-write Lock Attribute -#### Initialize Property +### Initialize Property ``` c int pthread_rwlockattr_init (pthread_rwlockattr_t *attr); @@ -2530,7 +2530,7 @@ int pthread_rwlockattr_init (pthread_rwlockattr_t *attr); This function initializes the read-write lock attribute `attr` with the default value PTHREAD_PROCESS_PRIVATE. -#### Obtain Scope +### Obtain Scope ``` c int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared); @@ -2546,9 +2546,9 @@ int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshare The memory pointed to by pshared is saved as PTHREAD_PROCESS_PRIVATE. -### Barrier Attribute +## Barrier Attribute -#### Initialize Property +### Initialize Property ``` c int pthread_barrierattr_init(pthread_barrierattr_t *attr); @@ -2563,7 +2563,7 @@ int pthread_barrierattr_init(pthread_barrierattr_t *attr); The modified function initializes the barrier attribute `attr` with the default value PTHREAD_PROCESS_PRIVATE. -#### Obtain Scope +### Obtain Scope ``` c int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared); @@ -2577,7 +2577,7 @@ int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshar | 0 | Succeeded | |-1 | Invalid parameter | -### Message Queue Property +## Message Queue Property The message queue attribute control block is as follows: @@ -2590,7 +2590,7 @@ struct mq_attr long mq_curmsgs; /* Message queue current message number */ }; ``` -#### Obtain Attribute +### Obtain Attribute ``` c int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); ``` diff --git a/documentation/run.sh b/documentation/run.sh new file mode 100755 index 0000000000..35959d680b --- /dev/null +++ b/documentation/run.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +rm -rf ./html + +doxygen + +pushd html +python3 -m http.server \ No newline at end of file diff --git a/documentation/sal/sal.md b/documentation/sal/sal.md index 8e768f4f06..f2ee12c7a8 100644 --- a/documentation/sal/sal.md +++ b/documentation/sal/sal.md @@ -1,6 +1,6 @@ -# Socket Abstraction Layer: SAL +@page component_sal Socket Abstraction Layer: SAL -## SAL Introduction +# SAL Introduction In order to adapt to more network protocol stack types and avoid the system's dependence on a single network protocol stack, the RT-Thread system provides a SAL (Socket Abstraction Layer) components that implement different network protocol stacks or network implementations. The abstraction of the interface provides a set of standard BSD Socket APIs to the upper layer, so that developers only need to care about and use the network interface provided by the network application layer, without concern for the underlying specific network protocol stack type and implementation, which greatly improves the system's compatibility makes it easy for developers to complete protocol stack adaptation and network-related development. Main features of the SAL component are as follows: @@ -9,7 +9,7 @@ In order to adapt to more network protocol stack types and avoid the system's de - Support standard BSD Socket APIs; - Unified FD management for easy operation of network functions using read/write poll/select; -### SAL Network Framework +## SAL Network Framework The SAL network framework of RT-Thread is mainly shown in the following structure: @@ -25,14 +25,14 @@ The fourth part is the protocol stack layer, which includes several commonly use The network application layer of RT-thread provides interfaces mainly based on the standard BSD Socket API, which ensures that programs can be written on PC, debugged, and then ported to the RT-thread operating system. -### Working Principles +## Working Principles The working principle of SAL component is mainly divided into the following three parts: - Unified abstract functions of multi-protocol stack access and interface functions; - SAL TLS encryption transmission function; -#### Multi-Protocol Stack Access and Unified Abstract Function Of Interface Function +### Multi-Protocol Stack Access and Unified Abstract Function Of Interface Function For different protocol stacks or network function implementations, the names of network interfaces may be different. Take the `connect` connection function as an example. The interface name in the lwIP protocol stack is `lwip_connect`, and the interface name in the AT Socket network implementation is `at_connect`. The SAL component provides abstraction and unification of the interface of different protocol stacks or networks. When the socket is created, the component **judges the protocol stack or network function used by judging the incoming protocol domain type**, and completes the RT-Thread. @@ -46,8 +46,7 @@ The above is the definition of the socket creation function in the standard BSD For different software packages, the protocol domain type passed to the socket may be fixed and will not change depending on how the SAL component is accessed. **In order to dynamically adapt access to different protocol stacks or network implementations**, the SAL component provides two protocol domain type matching methods for each protocol stack or network implementation: **Primary protocol domain type and secondary protocol domain type**. When socket is created, it first determines whether the incoming protocol domain type has the supported primary protocol type. If it is, it uses the corresponding protocol stack or network implementation, if not, determine whether the subprotocol cluster type supports. The current system support protocol domain types are as follows: -1. - lwIP Protocol stack: family = AF_INET、sec_family = AF_INET +1. lwIP Protocol stack: family = AF_INET、sec_family = AF_INET 2. AT Socket Protocol stack: family = AF_AT、sec_family = AF_INET @@ -109,7 +108,7 @@ int lwip_connect(int socket, const struct sockaddr *name, socklen_t namelen) } ``` -#### SAL TLS Encrypted Transmission Function +### SAL TLS Encrypted Transmission Function **1. SAL TLS Feature** @@ -221,7 +220,7 @@ MSH_CMD_EXPORT(sal_tls_test, SAL TLS function test); #endif /* FINSH_USING_MSH */ ``` -### Configuration Options +## Configuration Options When we use the SAL component we need to define the following macro definition in rtconfig.h: @@ -251,7 +250,7 @@ RT-Thread Components ---> After the configuration is complete, you can use the `scons` command to regenerate the function and complete the addition of the SAL component. -## Initialization ## +# Initialization 配置开启 SAL 选项之后,需要在启动时对它进行初始化,开启 SAL 功能,如果程序中已经使用了组件自动初始化,则不再需要额外进行单独的初始化,否则需要在初始化任务中调用如下函数: @@ -262,11 +261,11 @@ int sal_init(void); The initialization function is mainly for initializing the SAL component, supporting the component to repeatedly initialize the judgment, and completing the initialization of the resource such as the mutex used in the component. There is no new thread created in the SAL component, which means that the SAL component resource is very small. Currently, the **SAL component resource is occupied by ROM 2.8K and RAM 0.6K**. -## BSD Socket API Introduction ## +# BSD Socket API Introduction The SAL component abstracts the standard BSD Socket API interface. The following is an introduction to common network interfaces: -### Create a Socket (socket) +## Create a Socket (socket) ``` c int socket(int domain, int type, int protocol); @@ -294,7 +293,7 @@ This function is used to assign a socket descriptor and the resources it USES ba - SOCK_DGRAM: Datagram socket - SOCK_RAW: Raw socket -### Bind Socket (bind) +## Bind Socket (bind) ```c int bind(int s, const struct sockaddr *name, socklen_t namelen); @@ -392,7 +391,7 @@ MSH_CMD_EXPORT(bing_test, bind network interface device test); #endif /* FINSH_USING_MSH */ ``` -### Listen Socket (listen) +## Listen Socket (listen) ```c int listen(int s, int backlog); @@ -408,7 +407,7 @@ int listen(int s, int backlog); This function is used by the TCP server to listen for a specified socket connection。 -### Accept Connection (accept) +## Accept Connection (accept) ```c int accept(int s, struct sockaddr *addr, socklen_t *addrlen); @@ -425,7 +424,7 @@ int accept(int s, struct sockaddr *addr, socklen_t *addrlen); When the application listens for connections from other hosts, the connection is initialized with the `accept()` function, and `accept()` creates a new socket for each connection and removes the connection from the listen queue. -### Establish Connection (connect) +## Establish Connection (connect) ```c int connect(int s, const struct sockaddr *name, socklen_t namelen); @@ -442,7 +441,7 @@ int connect(int s, const struct sockaddr *name, socklen_t namelen); This function is used to establish a connection to the specified socket. -### Send TCP Data (send) +## Send TCP Data (send) ```c int send(int s, const void *dataptr, size_t size, int flags); @@ -460,7 +459,7 @@ int send(int s, const void *dataptr, size_t size, int flags); This function is commonly used to send data over a TCP connection。 -### Receive TCP Data (recv) +## Receive TCP Data (recv) ```c int recv(int s, void *mem, size_t len, int flags); @@ -479,7 +478,7 @@ int recv(int s, void *mem, size_t len, int flags); This function is used to receive data over a TCP connection。 -### Send UDP Data (sendto) +## Send UDP Data (sendto) ```c int sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen); @@ -499,7 +498,7 @@ int sendto(int s, const void *dataptr, size_t size, int flags, const struct sock This function is used for UDP connections to send data。 -### Receive UDP Data (recvfrom) +## Receive UDP Data (recvfrom) ```c int recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); @@ -520,7 +519,7 @@ int recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, soc This function is used to receive data on a UDP connection。 -### Close Socket (closesocket) +## Close Socket (closesocket) ```c int closesocket(int s); @@ -535,7 +534,7 @@ int closesocket(int s); This function is used to close the connection and release the resource.。 -### Shutdown The Socket By Setting(shutdown) +## Shutdown The Socket By Setting(shutdown) ```c int shutdown(int s, int how); @@ -557,7 +556,7 @@ This function provides more permissions to control the closing process of the so - 1: Stop sending data and discard unsent data; - 2: Stop receiving and sending data。 -### Set Socket Options(setsockopt) +## Set Socket Options(setsockopt) ```c int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); @@ -588,7 +587,7 @@ This function is used to set the socket mode and modify the socket configuration - SO_RCVTIMEO:Set socket data reception timeout - SO_SNDTIMEO:Set socket data sending timeout -### Get Socket Options(getsockopt) +## Get Socket Options(getsockopt) ```c int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); @@ -607,7 +606,7 @@ int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); This function is used to get the socket configuration options。 -### Get Remote Address Information (getpeername) +## Get Remote Address Information (getpeername) ```c int getpeername(int s, struct sockaddr *name, socklen_t *namelen); @@ -624,7 +623,7 @@ int getpeername(int s, struct sockaddr *name, socklen_t *namelen); This function is used to get the remote address information associated with the socket。 -### Get Local Address Information (getsockname) +## Get Local Address Information (getsockname) ```c int getsockname(int s, struct sockaddr *name, socklen_t *namelen); @@ -641,7 +640,7 @@ int getsockname(int s, struct sockaddr *name, socklen_t *namelen); This function is used to get local socket address information。 -### Configure Socket Parameters (ioctlsocket)) +## Configure Socket Parameters (ioctlsocket)) ```c int ioctlsocket(int s, long cmd, void *arg); @@ -662,7 +661,7 @@ This function sets the socket control mode。 - FIONBIO: Turns on or off the socket's non-blocking mode. Arg parameter 1 is open non-blocking and 0 is closed non-blocking. -## Network Protocol Stack Access +# Network Protocol Stack Access Access to the network protocol stack or network function implementation is mainly to initialize and register the protocol cluster structure, and add it to the protocol cluster list in SAL component. The protocol cluster structure is defined as follows: diff --git a/documentation/scons/figures/scons.png b/documentation/scons/figures/scons_compile.png similarity index 100% rename from documentation/scons/figures/scons.png rename to documentation/scons/figures/scons_compile.png diff --git a/documentation/scons/scons.md b/documentation/scons/scons.md index d3956d67cc..809d35e5d5 100644 --- a/documentation/scons/scons.md +++ b/documentation/scons/scons.md @@ -1,12 +1,12 @@ -# SCons +@page scons SCons -## Introduction to SCons +# Introduction to SCons SCons is an open source build system written in the Python language, similar to GNU Make. It uses a different approach than the usual Makefile, but instead uses SConstruct and SConscript files instead. These files are also Python scripts that can be written using standard Python syntax, so the Python standard library can be called in SConstruct, SConscript files for a variety of complex processing, not limited to the rules set by the Makefile. A detailed [SCons user manual](http://www.scons.org/doc/production/HTML/scons-user/index.html) can be found on the SCons website. This section describes the basic usage of SCons and how to use the SCons tool in RT-Thread. -### What is Construction Tool +## What is Construction Tool A software construction tool is a piece of software that compiles source code into an executable binary program according to certain rules or instructions. This is the most basic and important feature of building tools. In fact, these are not the only functions of construction tools. Usually these rules have a certain syntax and are organized into files. These files are used to control the behavior of the build tool, and you can do other things besides software building. @@ -14,13 +14,13 @@ The most popular build tool today is GNU Make. Many well-known open source softw Due to historical reasons, the syntax of the Makefile is confusing, which is not conducive to beginners. In addition, it is not convenient to use Make on the Windows platform, you need to install the Cygwin environment. To overcome the shortcomings of Make, other build tools have been developed, such as CMake and SCons. -### RT-Thread Construciton Tool +## RT-Thread Construciton Tool RT-Thread was built using Make/Makefile in the earlier stage. Starting from 0.3.x, the RT-Thread development team gradually introduced the SCons build system. The only goal of introducing SCons is to get everyone out of the complex Makefile configuration, IDE configuration, and focus on RT-Thread function development. Some may doubt the difference between the build tools described here and the IDE. The IDE completes the build through the operation of the graphical interface. Most IDEs generate script files like Makefile or SConscript based on the source code added by the user, and call the tools like Make or SCons to build the source code. -### Install SCons +## Install SCons It needs to be installed on the PC host before using the SCons system because it is written in the Python language, so you need to install the Python runtime environment before using SCons. @@ -30,13 +30,13 @@ In Linux and BSD environments, Python should already be installed by default, wh `sudo apt-get install scons` -## Basic Functions of SCons +# Basic Functions of SCons The RT-Thread build system supports multiple compilers, including ARM GCC, MDK, IAR, VisualStudio, and Visual DSP. The mainstream ARM Cortex M0, M3, M4 platforms, basically all support ARM GCC, MDK, IAR. Some BSPs may only support one compiler, and readers can read the currently supported compiler by reading the CROSS_TOOL option in rtconfig.py under the BSP directory. If it is a chip on the ARM platform, you can use the Env tool and enter the scons command to compile the BSP directly. At this time, the ARM GCC compiler is used by default because the Env tool comes with the ARM GCC compiler. Compile a BSP using the scons command as shown below, and the SCons will be based on this BSP. -![Compile BSP using scons](figures/scons.png) +![Compile BSP using scons](figures/scons_compile.png) If the user wants to use another compiler that the BSP already supports to compile the project, or if the BSP is a non-ARM platform chip, then you can't compile the project directly with the scons command. You need to install the corresponding compiler yourself and specify the compiler path to use. Before compiling the project, you can use the following two commands in the Env command line interface to specify the compiler path for the MDK and the compiler path to MDK. @@ -45,22 +45,22 @@ set RTT_CC=keil set RTT_EXEC_PATH=C:/Keilv5 ``` -### Commonly Used SCons Commands +## Commonly Used SCons Commands This section describes the SCons commands that are commonly used in RT-Thread. SCons not only completes basic compilation, but also generates MDK/IAR/VS projects. -#### scons +### scons Go to the BSP project directory to be compiled in the Env command line window, and then use this command to compile the project directly. If some source files are modified after executing the `scons` command, and the scons command is executed again, SCons will incrementally compile and compile only the modified source files and link them. `scons` can also be followed by a `-s` parameter, the command `scons -s`, which differs from the `scons` command in that it does not print specific internal commands. -#### scons -c +### scons -c Clear the compilation target. This command clears the temporary and target files generated when `scons` is executed. -#### scons --target=XXX +### scons --target=XXX If you use mdk/iar for project development, when you open or close some components, you need to use one of the following commands to regenerate the corresponding customized project, then compile and download in mdk/iar. @@ -85,17 +85,17 @@ This command can also be followed by a `-s` parameter, such as the command `sco > To generate a MDK or IAR project file, the prerequisite is that there is a project template file in the BSP directory, and then the scons will add relevant source code, header file search path, compilation parameters, link parameters, etc. according to the template file. As for which chip this project is for, it is directly specified by this engineering template file. So in most cases, this template file is an empty project file that is used to assist SCons in generating project.uvprojx or project.eww. -#### scons -jN +### scons -jN Multi-threaded compilation target, you can use this command to speed up compilation on multi-core computers. In general, a cpu core can support 2 threads. Use the `scons -j4` command on a dual-core machine. > If you just want to look at compilation errors or warnings, it's best not to use the -j parameter so that the error message won't be mixed with multiple files in parallel. -#### scons --dist +### scons --dist Build a project framework. Using this command will generate the `dist` directory in the BSP directory, this is the directory structure of the development project, including RT-Thread source code and BSP related projects, irrelevant BSP folder and libcpu will be removed, and you can freely copy this work to any directory. -#### scons --verbose +### scons --verbose By default, output compiled with the scons command does not display compilation parameters as follows: @@ -124,7 +124,7 @@ er\inc -ILibraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x -IF:\Project\git\rt-thre ... ``` -## SCons Advanced +# SCons Advanced SCons uses SConscript and SConstruct files to organize the source structure. Usually a project has only one SConstruct, but there will be multiple SConscripts. In general, an SConscript will be placed in each subdirectory where the source code is stored. @@ -132,29 +132,29 @@ In order to make RT-Thread better support multiple compilers and to easily adjus RT-Thread SConscript files are also present in most source folders. These files are "found" by the SConscript file in the BSP directory to add the source code corresponding to the macro defined in rtconfig.h to the compiler. The following article will take stm32f10x-HAL BSP as an example to explain how SCons builds the project. -### SCons Build-In Functions +## SCons Build-In Functions If you want to add some of your own source code to the SCons build environment, you can usually create or modify an existing SConscript file. The SConscript file can control the addition of source files and can specify the group of files (similar to the concept of Groups in IDEs such as MDK/IAR). SCons provides a lot of built-in functions to help us quickly add source code, and with these simple Python statements we can add or remove source code to our project. The following is a brief introduction to some common functions. -#### GetCurrentDir() +### GetCurrentDir() Get current directory. -#### Glob('\*.c') +### Glob('\*.c') Get all C files in the current directory. Modify the value of the parameter to match the suffix to match all files of the current directory. -#### GetDepend(macro) +### GetDepend(macro) This function is defined in the script file in the `tools` directory. It reads the configuration information from the rtconfig.h file with the macro name in rtconfig.h. This method (function) returns true if rtconfig.h has a macro turned on, otherwise it returns false. -#### Split(str) +### Split(str) Split the string str into a list list. -#### DefineGroup(name, src, depend,**parameters) +### DefineGroup(name, src, depend,**parameters) This is a method (function) of RT-Thread based on the SCons extension. DefineGroup is used to define a component. A component can be a directory (under a file or subdirectory) and a Group or folder in some subsequent IDE project files. @@ -176,7 +176,7 @@ parameters that could be added: | CPPDEFINES | Link parameter | | LIBRARY | Include this parameter, the object file generated by the component will be packaged into a library file | -#### SConscript(dirs,variant_dir,duplicate) +### SConscript(dirs,variant_dir,duplicate) Read the new SConscript file, and the parameter description of the SConscript() function is as follows: @@ -186,11 +186,11 @@ Read the new SConscript file, and the parameter description of the SConscript() | variant_dir | Specify the path to store the generated target file | | duiplicate | Set whether to copy or link the source file to variant_dir | -## SConscript Examples +# SConscript Examples Below we will use a few SConscript as an example to explain how to use the scons tool. -### SConscript Example 1 +## SConscript Example 1 Let's start with the SConcript file in the stm32f10x-HAL BSP directory. This file manages all the other SConscript files under the BSP, as shown below. @@ -218,7 +218,7 @@ Return('objs') With this SConscript file, the source code required by the BSP project is added to the compilation list. -### SConscript Example 2 +## SConscript Example 2 So what about stm32f10x-HAL BSP other SConcript files? Let's take a look at the SConcript file in the drivers directory, which will manage the source code under the drivers directory. The drivers directory is used to store the underlying driver code implemented by the driver framework provided by RT-Thread. @@ -274,7 +274,7 @@ The last line uses DefineGroup to create a group called Drivers, which correspon `CPPPATH =CPPPATH` means to add the current path to the system's header file path. The CPPPATH on the left is a built-in parameter in the DefineGroup that represents the header file path. The CPPPATH on the right is defined in the previous line of this document. This way we can reference the header files in the drivers directory in other source code. -### SConscript Example 3 +## SConscript Example 3 Let's take a look at the SConcript file in the applications directory, which will manage the source code under the applications directory for the user's own application code. @@ -298,7 +298,7 @@ The last line uses DefineGroup to create a group called `Applications`. The sour To sum up, this source program will add all c programs in the current directory to the group `Applications`, so if you add or delete files in this directory, you can add files to the project or delete them from the project. It is suitable for adding source files in batches. -### SConscript Example 4 +## SConscript Example 4 Below is the contents of the RT-Thread source code `component/finsh/SConscript` file, which will manage the source code under the finsh directory. @@ -359,11 +359,11 @@ Then add the finsh directory to the system header directory so that we can refer `LINKFLAGS = LINKFLAGS` has the same meaning as `CPPPATH = CPPPATH` . The LINKFLAGS on the left represents the link parameter, and the LINKFLAGS on the right is the value defined by the previous if else statement. That is, specify the link parameters for the project. -## Manage Projects with SCons +# Manage Projects with SCons The previous section on the SConscript related to the RT-Thread source code is explained in detail, you should also know some common ways to write SConscript files, this section will guide you how to use SCons to manage your own projects. -### Add App Code +## Add App Code As mentioned earlier, the Applications folder under BSP is used to store the user's own application code. Currently there is only one main.c file. If the user's application code is not a lot, it is recommended that the relevant source files be placed under this folder. Two simple files hello.c and hello.h have been added under the Applications folder, as shown below. @@ -394,7 +394,7 @@ MSH_CMD_EXPORT(hello_world, Hello world!) The SConcript file in the applications directory will add all source files in the current directory to the project. You need to use the `scons --target=xxx` command to add the 2 new files to your project. Note that the project will be regenerated each time a new file is added. -### Add Module +## Add Module As mentioned above, in the case that there are not many source code files, it is recommended that all source code files be placed in the applications folder. If the user has a lot of source code and wants to create your own project module, or need to use other modules that you have obtained, what would be appropriate? @@ -460,9 +460,9 @@ After saving the configuration, exit the configuration interface and open the rt Because the RT_USING_HELLO macro has been defined in rtconfig.h, the source file for hello.c is added to the new project when the project is newly built. -The above simply enumerates the configuration options for adding your own modules to the Kconfig file. Users can also refer to [*User Manual of Env*](../env/env.md), which also explains how to modify and add configuration options. They can also view the Kconfig documentation in your own Baidu to implement other more complex configuration options. +The above simply enumerates the configuration options for adding your own modules to the Kconfig file. Users can also refer to @ref env, which also explains how to modify and add configuration options. They can also view the Kconfig documentation in your own Baidu to implement other more complex configuration options. -### Add Library +## Add Library If you want to add an extra library to your project, you need to pay attention to the naming of the binary library by different toolchains. For example, the GCC toolchain, which recognizes library names such as `libabc.a`, specifies `abc` instead of `libabc` when specifying a library. So you need to pay special attention to the SConscript file when linking additional libraries. In addition, when specifying additional libraries, it is also a good idea to specify the corresponding library search path. Here is an example: @@ -482,7 +482,7 @@ group = DefineGroup('ABC', src, depend = [''], LIBS = LIBS, LIBPATH=LIBP LIBPATH specifies the path to the library, and LIBS specifies the name of the library. If the toolchain is GCC, the name of the library should be libabc.a; if the toolchain is armcc, the name of the library should be abc.lib.`LIBPATH = [cwd + '/libs']` indicates that the search path for the library is the 'libs' directory in the current directory. -### Compiler Options +## Compiler Options `rtconfig.py` is a RT-Thread standard compiler configuration file that controls most of the compilation options. It is a script file written in Python and is used to do the following: @@ -562,13 +562,13 @@ As mentioned earlier, if the user wants to compile the project with another comp Suppose a compiler is installed under `D:\Dir1\Dir2`. The following are the correct ways to write: -* EXEC_PATH = `r'D:\Dir1\Dir2'` Note that with the string `r` in front of the string, `“\”`can be used normally. +* EXEC_PATH = `r'D:\\Dir1\\Dir2'` Note that with the string `r` in front of the string, `“\”`can be used normally. * EXEC_PATH = `'D:/Dir1/Dir2'` Note that instead of `“/”`, there is no `r` in front. * EXEC_PATH = `'D:\\Dir1\\Dir2'` Note that the escapement of `“\”` s used here to escape `“\”` itself. -* This is the wrong way to write: EXEC_PATH = `'D:\Dir1\Dir2'`。 +* This is the wrong way to write: EXEC_PATH = `'D:\\Dir1\\Dir2'`。 If the rtconfig.py file has the following code, comment out the following code when configuring your own compiler. @@ -584,11 +584,11 @@ The above 2 `if` judgments will set CROSS_TOOL and EXEC_PATH to the default valu After the compiler is configured, we can use SCons to compile the BSP of RT-Thread. Open a command line window in the BSP directory and execute the `scons` command to start the compilation process. -### RT-Thread Auxiliary Compilation Script +## RT-Thread Auxiliary Compilation Script In the tools directory of the RT-Thread source code, there are some auxiliary compiled scripts defined by RT-Thread, such as the project files for automatically generating RT-Thread for some IDE. The most important of these is the building.py script. -### SCons Further Usage +## SCons Further Usage For a complex, large-scale system, it is obviously more than just a few files in a directory. It is probably a combination of several folders at the first level. diff --git a/documentation/thread-comm/thread-comm.md b/documentation/thread-comm/thread-comm.md index 758c8defa5..b65f225d56 100644 --- a/documentation/thread-comm/thread-comm.md +++ b/documentation/thread-comm/thread-comm.md @@ -1,16 +1,14 @@ -Inter-thread Communication -========== +@page thread_comm Inter-thread Communication In the last chapter, we talked about inter-thread synchronization, concepts such as semaphores, mutexes, and event sets were mentioned. Following the last chapter, this chapter is going to explain inter-thread communication. In bare-metal programming, global variables are often used for communication between functions. For example, some functions may change the value of a global variable due to some operations. Another function reads the global variable and will perform corresponding actions to achieve communication and collaboration according to the global variable values it read. More tools are available in RT-Thread to help pass information between different threads. These tools are covered in more detail in this chapter. After reading this chapter, you will learn how to use mailboxes, message queues, and signals for communication between threads. -Mailbox ----- +# Mailbox Mailbox service is a typical inter-thread communication method in real-time operating systems.For example, there are two threads, thread 1 detects the state of the button and sends it's state, and thread 2 reads the state of the button and turns on or off the LED according to the state of the button. Here, a mailbox can be used to communicate. Thread 1 sends the status of the button as an email to the mailbox. Thread 2 reads the message in the mailbox to get the button status and turn on or off the LED accordingly. Thread 1 here can also be extended to multiple threads. For example, there are three threads, thread 1 detects and sends the button state, thread 2 detects and sends the ADC information, and thread 3 performs different operations according to the type of information received. -### Mailbox Working Mechanism +## Mailbox Working Mechanism The mailbox of the RT-Thread operating system is used for inter-thread communication, which is characterized by low overhead and high efficiency. Each message in the mailbox can only hold a fixed 4 bytes(for a 32-bit processing system, the pointer is 4 bytes in size, so an email can hold only one pointer). A typical mailbox is also called message exchange. As shown in the following figure, a thread or an interrupt service routine sends a 4-byte message to a mailbox, and one or more threads can receive and process the message from the mailbox. @@ -22,7 +20,7 @@ When a thread sends a message to a mailbox, if the mailbox is not full, the mess When a thread receives a message from a mailbox, if the mailbox is empty, the thread receiving the message can choose whether to set a timeout or wait and suspend until a new message is received to be awaken. When the set timeout is up and the mailbox still hasn't received the message, the thread that chose to wait till timeout will be awaken and return -RT_ETIMEOUT. If there are messages in the mailbox, then the thread receiving the message will copy the 4-byte message in the mailbox to the receiving cache. -### Mailbox Control Block +## Mailbox Control Block In RT-Thread, the mailbox control block is a data structure used by the operating system to manage mailboxes, represented by the structure `struct rt_mailbox`. Another C expression, `rt_mailbox_t`, represents the handle of the mailbox, and the implementation in C language is a pointer to the mailbox control block. See the following code for a detailed definition of the mailbox control block structure: @@ -44,13 +42,13 @@ typedef struct rt_mailbox* rt_mailbox_t; The `rt_mailbox` object is derived from `rt_ipc_object` and is managed by the IPC container. -### Management of Mailbox +## Management of Mailbox The mailbox control block is a structure that contains important parameters related to mailbox and it plays an important role in the function implementation of the mailbox. The relevant interfaces of the mailbox are as shown in the following figure. The operation on a mailbox includes: create/initiate a mailbox, send a mail, receive a mail, and delete/detach a mailbox. ![Mailbox Related Interface](figures/07mb_ops.png) -#### Create and Delete Mailbox +### Create and Delete Mailbox To dynamically create a mailbox object, call the following function interface: @@ -87,7 +85,7 @@ Input parameters and return values of rt_mb_delete() |**Return**| —— | | RT_EOK | Successful | -#### Initialize and Detach Mailbox +### Initialize and Detach Mailbox Initializing a mailbox is similar to creating a mailbox, except that the mailbox initialized is for static mailbox objects. Different from creating a mailbox, the memory of a static mailbox object is allocated by the compiler during system compilation which is usually placed in a read-write data segment or an uninitialized data segment. The rest of the initialization is the same as the creation of a mailbox. The function interface is as follows: @@ -131,7 +129,7 @@ Input parameters and return values for rt_mb_detach() |**Return**| —— | | RT_EOK | Successful | -#### Send Mail +### Send Mail The thread or ISR can send mail to other threads through the mailbox. The function interface of sending mails is as follows: @@ -151,7 +149,7 @@ Input parameters and return values of rt_mb_send() | RT_EOK | Sent successfully | | \-RT_EFULL | The mailbox is filled | -#### Send Mails with Waiting +### Send Mails with Waiting Users can also send mails to specified mailbox through the following function interface: @@ -175,7 +173,7 @@ Input parameters and return values of rt_mb_send_wait() | \-RT_ETIMEOUT | Timeout | | \-RT_ERROR | Failed, return error | -#### Receive Mails +### Receive Mails Only when there is a mail in the mailbox, the recipient can receive the mail immediately and return RT_EOK. Otherwise, the thread receiving the message will suspend on the waiting thread queue of the mailbox or return directly according to the set timeout. The receiving mail function interface is as follows: @@ -197,7 +195,7 @@ Input parameters and return values of rt_mb_recv() | \-RT_ETIMEOUT | Timeout | | \-RT_ERROR | Failed, return error | -### Mail Usage Sample +## Mail Usage Sample This is a mailbox application routine that initializes 2 static threads, 1 static mailbox object, one of the threads sends mail to the mailbox, and one thread receives mail from the mailbox. As shown in the following code: @@ -339,7 +337,7 @@ thread1: get a mail from mailbox, the content:over The routine demonstrates how to use the mailbox. Thread 2 sends the mails, for a total of 11 times; thread 1 receives the mails, for a total of 11 mails, prints the contents of the mail, and determines end. -### Occasions to Use Mails +## Occasions to Use Mails Mailbox is a simple inter-thread messaging method, which is characterized by low overhead and high efficiency. In the implementation of the RT-Thread operating system, a 4-byte message can be delivered at a time, and the mailbox has certain storage capabilities, which can cache a certain number of messages (the number of messages is determined by the capacity specified when creating and initializing the mailbox). The maximum length of a message in a mailbox is 4 bytes, so the mailbox can be used for messages less than 4 bytes. Since on the 32 system, 4 bytes can be placed right on a pointer, when a larger message needs to be transferred between threads, a pointer pointing to a buffer can be sent as an mail to the mailbox, which means the mailbox can also delivery a pointer. For example, @@ -374,12 +372,11 @@ if (rt_mb_recv(mb, (rt_uint32_t*)&msg_ptr) == RT_EOK) } ``` -Message Queue --------- +# Message Queue Message Queuing is another commonly used inter-thread communication method, which is an extension of the mailbox. Can be used in a variety of occasions, like message exchange between threads, use the serial port to receive variable length data, etc. -### Message Queue Working Mechanism +## Message Queue Working Mechanism Message queue can receive messages with unfixed length from threads or ISR and cache messages in their own memory space. Other threads can also read the corresponding message from the message queue, and when the message queue is empty, the thread reading the messages can be suspended. When a new message arrives, the suspended thread will be awaken to receive and process the message. Message queue is an asynchronous way of communication. @@ -389,7 +386,7 @@ As shown in the following figure, a thread or interrupt service routine can put The message queue object of the RT-Thread operating system consists of multiple elements. When a message queue is created, it is assigned a message queue control block: name, memory buffer, message size, and queue length. At the same time, each message queue object contains multiple message boxes, and each message box can store one message. The first and last message boxes in the message queue are respectively called the message linked list header and the message linked list tail, corresponding to `msg_queue_head` and `msg_queue_tail` in the queue control block. Some message boxes may be empty, they form a linked list of idle message boxes via `msg_queue_free`. The total number of message boxes in all message queues is the length of the message queue, which can be specified when creating the message queue. -### Message Queue Control Block +## Message Queue Control Block In RT-Thread, a message queue control block is a data structure used by the operating system to manage message queues, represented by the structure `struct rt_messagequeue`. Another C expression, `rt_mq_t`, represents the handle of the message queue. The implementation in C language is a pointer to the message queue control block. See the following code for a detailed definition of the message queue control block structure: @@ -414,13 +411,13 @@ typedef struct rt_messagequeue* rt_mq_t; rt_messagequeue object is derived from rt_ipc_object and is managed by the IPC container. -### Management of Message Queue +## Management of Message Queue The message queue control block is a structure that contains important parameters related to the message queue and plays an important role in the implementation of functions of the message queue. The relevant interfaces of the message queue are shown in the figure below. Operations on a message queue include: create a message queue - send a message - receive a message - delete a message queue. ![Message Queue Related Interfaces](figures/07msg_ops.png) -#### Create and Delete Message Queue +### Create and Delete Message Queue The message queue should be created before it is used, or the existing static message queue objects should be initialized. The function interface for creating the message queue is as follows: @@ -460,7 +457,7 @@ Input parameters and return values of rt_mq_delete() |**Return**| —— | | RT_EOK | Successful | -#### Initialize and Detach Message Queue +### Initialize and Detach Message Queue Initializing a static message queue object is similar to creating a message queue object, except that the memory of a static message queue object is allocated by the compiler during system compilation and is typically placed in a read data segment or an uninitialized data segment. Initialization is required before using such static message queue objects. The function interface for initializing a message queue object is as follows: @@ -501,7 +498,7 @@ Input parameters and return values for rt_mq_detach() |**Return**| —— | | RT_EOK | Successful | -#### Send Message +### Send Message A thread or ISR can send a message to the message queue. When sending a message, the message queue object first takes an idle message block from the idle message list, then copies the content of the message sent by the thread or the interrupt service program to the message block, and then suspends the message block to the end of the message queue. The sender can successfully send a message if and only if there is an idle message block available on the idle message list; when there is no message block available on the idle message list, it means that the message queue is full, at this time, the thread or interrupt program that sent the message will receive an error code (-RT_EFULL). The function interface for sending messages is as follows: @@ -523,7 +520,7 @@ Input parameters and return values of rt_mq_send() | \-RT_EFULL | Message queue is full | | \-RT_ERROR | Failed, indicating that the length of the sent message is greater than the maximum length of the message in the message queue. | -#### Send an Emergency Message +### Send an Emergency Message The process of sending an emergency message is almost the same as sending a message. The only difference is that when an emergency message is sent, the message block taken from the idle message list is not put in the end of the message queue, but the head of the queue. The recipient can receive the emergency message preferentially, so that the message can be processed in time. The function interface for sending an emergency message is as follows: @@ -545,7 +542,7 @@ Input parameters and return values of rt_mq_urgent() | \-RT_EFULL | Message queue is full | | \-RT_ERROR | Fail | -#### Receive Message +### Receive Message Only when there is a message in the message queue, can the receiver receive message, otherwise the receiver will set according to the timeout, or suspend on the waiting queue of the message queue, or return directly. The function interface to receive message is as follows: @@ -569,7 +566,7 @@ Input parameters and return values of rt_mq_recv() | \-RT_ETIMEOUT | Timeout | | \-RT_ERROR | Fail, return error | -### Message Queue Application Example +## Message Queue Application Example This is a message queue application routine. Two static threads are initialized in the routine, one thread will receive messages from the message queue; and another thread will periodically send regular messages and emergency messages to the message queue, as shown in the following code: @@ -745,11 +742,11 @@ thread1: detach mq The routine demonstrates how to use message queue. Thread 1 receives messages from the message queue; thread 2 periodically sends regular and emergency messages to the message queue. Since the message "I" that thread 2 sent is an emergency message, it will be inserted directly into the front of the message queue. So after receiving the message "B", thread 1 receives the emergency message and then receives the message "C". -### Occasions to Use Message Queue +## Occasions to Use Message Queue Message Queue can be used where occasional long messages are sent, including exchanging message between threads and threads and sending message to threads in interrupt service routines (interrupt service routines cannot receive messages). The following sections describe the use of message queues from two perspectives, sending messages and synchronizing messages. -#### Sending Messages +### Sending Messages The obvious difference between message queue and mailbox is that the length of the message is not limited to 4 bytes. In addition, message queue also includes a function interface for sending emergency messages. But when you create a message queue with a maximum length of 4 bytes for all messages, the message queue object will be reduced to a mailbox. This unrestricted message is also reflected in the case of code writing which is also a mailbox-like code: @@ -793,7 +790,7 @@ void message_handler() Because message queue is a direct copy of data content, so in the above example, local structure is used to save the message structure, which eliminates the trouble of dynamic memory allocation (and no need to worry, because message memory space has already been released when the thread receives the message). -#### Synchronizing Messages +### Synchronizing Messages In general system designs, the problem of sending synchronous messages is often encountered. At this time, corresponding implementations can be selected according to the state of the time: two threads can be implemented in the form of [message queue + semaphore or mailbox]. The thread sending messages sends the corresponding message to the message queue in the form of message sending. After the message is sent, it is hoping to receive the confirmation from the threads receiving messages. The working diagram is as shown below: @@ -817,12 +814,11 @@ struct msg The first type of message uses a mailbox as a confirmation flag, while the second type of message uses a semaphore as a confirmation flag. The mailbox is used as a confirmation flag, which means that the receiving thread can notify some status values to the thread sending messages; and the semaphore is used as a confirmation flag that can only notify the thread sending messages in a single way, and the message has been confirmed to be received. -Signal ----- +# Signal A signal (also known as a soft interrupt signal), from a software perspective, is a simulation of interrupt mechanism. When it comes to its principle, thread receiving a signal is similar to processor receiving an interrupt request. -### Signal Working Mechanism +## Signal Working Mechanism Signals are used for asynchronous communication in RT-Thread. The POSIX standard defines that sigset_t type defines a signal set. However, the sigset_t type may be defined differently in different systems. In RT-Thread, sigset_t is defined as unsigned long and named rt_sigset_t, the signals that the application can use are SIGUSR1(10) and SIGUSR2(12). @@ -842,13 +838,13 @@ As shown in the following figure, suppose that thread 1 needs to process the sig When the signal is passed to thread 1, if it is suspended, it will be switched to ready to process the corresponding signal. If it is running, it will create a new stack frame space on its current thread stack to process the corresponding signal. It should be noted that the thread stack size used will also increase accordingly. -### Management of Signals +## Management of Signals Operations on signals include: install signal, block signal, unblock signal, send signal, and wait for signal. The interfaces of the signal are shown in the following figure: ![Signal Related Interface](figures/07signal_ops.png) -#### Install Signal +### Install Signal If the thread is to process a signal, then the signal needs to be installed in the thread. Signal installation is primarily used to determine the mapping relation between the signal value and the actions of the thread on that signal value, that is what signal is to be processed, what actions will be taken when the signal is passed to the thread. See the following code for a detailed definition: @@ -876,7 +872,7 @@ Setting the handler parameter during signal installation determines the differen 3) The parameter is set to SIG_DFL, and the system will call the default function _signal_default_handler() to process. -#### Block Signal +### Block Signal Blocking signal can also be understood as shielding signals. If the signal is blocked, the signal will not be delivered to the thread that installed the signal and will not cause soft interrupt processing. Call rt_signal_mask() to block the signal: @@ -892,7 +888,7 @@ rt_signal_mask() function parameters |----------|----------| | signo | Signal value | -#### Unblock Signal +### Unblock Signal Several signals can be installed in the thread. Using this function can give some "attention" to some of the signals, then sending these signals will cause a soft interrupt for the thread. Calling rt_signal_unmask() to unblock the signal: @@ -908,7 +904,7 @@ rt_signal_unmask() function parameters |----------|----------| | signo | Signal value | -#### Send Signals +### Send Signals When we need to process abnormality, a signal can be sent to the thread that has been set to process abnormality. Call rt_thread_kill() to send a signal to any thread: @@ -928,7 +924,7 @@ Input parameters and return values for rt_thread_kill() | RT_EOK | Sent successfully | | \-RT_EINVAL | Parameter error | -#### Wait for Signal +### Wait for Signal Wait for the arrival of the set signal. If this signal did not arrive, suspend the thread until the signal arrival or the wait until time exceeds the specified timeout. If the signal arrived, the pointer pointing to the signal body is stored in si, as follows is the function to wait for signal. @@ -951,7 +947,7 @@ Input parameters and return values for rt_signal_wait() | \-RT_ETIMEOUT | Timeout | | \-RT_EINVAL | Parameter error | -### Signal Application Example +## Signal Application Example This is a signal application routine, as shown in the following code. This routine creates one thread. When the signal is installed, the signal processing mode is set to custom processing. The processing function of the signal is defined to be thread1_signal_handler(). After the thread is running and the signal is installed, a signal is sent to this thread. This thread will receive the signal and print the message. diff --git a/documentation/thread-sync/thread-sync.md b/documentation/thread-sync/thread-sync.md index 9a6196c22d..3d101eb38c 100644 --- a/documentation/thread-sync/thread-sync.md +++ b/documentation/thread-sync/thread-sync.md @@ -1,4 +1,4 @@ -# Inter-thread Synchronization +@page thread_sync Inter-thread Synchronization In a multi-threaded real-time system, the completion of a task can often be accomplished through coordination of multiple threads, so how do these multiple threads collaborate well with each other to perform without errors? Here is an example. @@ -22,8 +22,7 @@ There are many ways to synchronize threads. The core idea is that **only one (or This chapter introduces several synchronization methods: **semaphores,** **mutex**, and **event**. After learning this chapter, you will learn how to use semaphores, mutex, and event to synchronize threads. -Semaphores ------- +# Semaphores Take parking lot as an example to understand the concept of semaphore: @@ -35,7 +34,7 @@ Take parking lot as an example to understand the concept of semaphore: In this example, the administrator is equivalent to the semaphore. The number of empty parking spaces that the administrator is in charge of is the value of the semaphore (non-negative, dynamic change); the parking space is equivalent to the common resource (critical section), and the cars are equivalent to the threads. Cars access the parking spaces by obtaining permission from the administrator, which is similar to thread accessing public resource by obtaining the semaphore. -### Semaphore Working Mechanism +## Semaphore Working Mechanism Semaphore is a light-duty kernel object that can solve the problems of synchronization between threads. By obtaining or releasing semaphore, a thread can achieve synchronization or mutual exclusion. @@ -43,7 +42,7 @@ Schematic diagram of semaphore is shown in the figure below. Each semaphore obje ![Schematic Diagram of Semaphore](figures/06sem_work.png) -### Semaphore Control Block +## Semaphore Control Block In RT-Thread, semaphore control block is a data structure used by the operating system to manage semaphores, represented by struct rt rt_semaphore. Another C expression is rt_sem_t, which represents the handle of the semaphore, and the implementation in C language is a pointer to the semaphore control block. The detailed definition of semaphore control block structure is as follows: @@ -59,13 +58,13 @@ typedef struct rt_semaphore* rt_sem_t; rt_semaphore object is derived from rt_ipc_object and is managed by the IPC container. The maximum semaphore is 65535. -### Semaphore Management +## Semaphore Management Semaphore control block contains important parameters related to the semaphore and acts as a link between various states of the semaphore. Interfaces related to semaphore are shown in the figure below. Operations on a semaphore includes: creating/initializing the semaphore, obtaining the semaphore, releasing the semaphore, and deleting/detaching the semaphore. ![Interfaces Related to Semaphore](figures/06sem_ops.png) -#### Create and Delete Semaphore +### Create and Delete Semaphore When creating a semaphore, the kernel first creates a semaphore control block, then performs basic initialization on the control block. The following function interface is used to create a semaphore: @@ -104,7 +103,7 @@ Input parameters and return values of rt_sem_delete() |**Return**| —— | | RT_EOK | Successfully deleted | -#### Initialize and Detach Semaphore +### Initialize and Detach Semaphore For a static semaphore object, its memory space is allocated by the compiler during compiling and placed on the read-write data segment or on the uninitialized data segment. In this case,rt_sem_create interface is no longer needed to create the semaphore to use it, just initialize it before using it. To initialize the semaphore object, use the following function interface: @@ -144,7 +143,7 @@ After using this function, the kernel wakes up all threads suspended in the sema |**Return**| —— | | RT_EOK | Successfully detached | -#### Obtain Semaphore +### Obtain Semaphore Thread obtains semaphore resource instances by obtaining semaphores. When the semaphore value is greater than zero, the thread will get the semaphore, and the corresponding semaphore value will be reduced by 1. The semaphore is obtained using the following function interface: @@ -165,7 +164,7 @@ When calling this function, if the value of the semaphore is zero, it means the | \-RT_ETIMEOUT | Did not received semaphore after timeout | | \-RT_ERROR | Other errors | -#### Obtain Semaphore without Waiting +### Obtain Semaphore without Waiting When user does not want to suspend thread on the applied semaphore and wait, the semaphore can be obtained using the wait-free mode , and the following function interface is used for obtaining the semaphore without waiting: @@ -184,7 +183,7 @@ This function has the same effect as rt_sem_take(sem, 0), which means when the | RT_EOK | Semaphore successfully obtained | | \-RT_ETIMEOUT | Semaphore obtainment failed | -#### Interrupt Service Routine +### Semaphore Release Semaphore is released to wake up the thread that suspends on the semaphore. To release the semaphore, use the following function interface: @@ -202,7 +201,7 @@ For example, when semaphore value is zero and a thread is waiting for this semap |**Return**| —— | | RT_EOK | Semaphore successfully released | -### Semaphore Application Sample +## Semaphore Application Sample This is a sample of semaphore usage routine. This routine creates a dynamic semaphore and initializes two threads, one thread sends the semaphore, and one thread receives the semaphore and performs the corresponding operations. As shown in the following code: @@ -548,23 +547,23 @@ This routine can be understood as the process of producers producing products an The producer generates 10 numbers in turn, and the consumers take them away in turn and sum the values of the 10 numbers. Semaphore lock protects array critical region resources, ensuring the exclusivity of number taking for the consumers each time and achieving inter-thread synchronization. -### Semaphore Usage Occasion +## Semaphore Usage Occasion Semaphores is a very flexible way to synchronize and can be used in a variety of situations, like forming locks, synchronization, resource counts, etc. It can also be conveniently used for synchronization between threads and threads, interrupts and threads. -#### Thread Synchronization +### Thread Synchronization Thread synchronization is one of the simplest types of semaphore applications. For example, using semaphores to synchronize between two threads, the value of the semaphore is initialized to 0, indicating that there are 0 semaphore resource instances; and the thread attempting to acquire the semaphore will wait directly on this semaphore. When the thread holding the semaphore completes the work it is processing, it will release this semaphore. Thread waiting on this semaphore can be awaken, and it can then perform the next part of the work. This occasion can also be seen as using the semaphore for the work completion flag: the thread holding the semaphore completes its own work, and then notifies the thread waiting for the semaphore to continue the next part of the work. -#### Lock +### Lock Locks, a single lock is often applied to multiple threads accessing the same shared resource (in other words, critical region). When semaphore is used as a lock, the semaphore resource instance should normally be initialized to 1, indicating that the system has one resource available by default. Because the semaphore value always varies between 1 and 0, so this type of lock is also called binary semaphore. As shown in the following figure, when a thread needs to access shared resource, it needs to obtain the resource lock first. When this thread successfully obtains the resource lock, other threads that intend to access the shared resource will suspend because they cannot obtain the resource. This is because it is already locked (semaphore value is 0) when other threads are trying to obtain the lock. When thread holding the semaphore is processed and exiting the critical region, it will release the semaphore and unlock the lock, and the first waiting thread that is suspending on the lock will be awaken to gain access to the critical region. ![Lock](figures/06sem_lock.png) -#### Interrupt Synchronization between Threads +### Interrupt Synchronization between Threads Semaphore can also be easily applied to interrupting synchronization between threads, such as an interrupt trigger. When interrupting service routine, thread needs to be notifies to perform corresponding data processing. At this time, the initial value of the semaphore can be set to 0. When the thread tries to hold this semaphore, since the initial value of the semaphore is 0, the thread will then suspends on this semaphore until the semaphore is released. When the interrupt is triggered, hardware-related actions are firstly performed, such as reading corresponding data from the hardware I/O port, and confirming the interrupt to clear interrupt source, and then releasing a semaphore to wake up the corresponding thread for subsequent data processing. For example, the processing of FinSH threads is as shown in the following figure. @@ -574,18 +573,17 @@ The value of the semaphore is initially 0. When the FinSH thread attempts to obt >The mutual exclusion between interrupts and threads cannot be done by means of semaphores (locks), but by means of switch interrupts. -#### Resource Count +### Resource Count Semaphore can also be considered as an incrementing or decrementing counter. It should be noted that the semaphore value is non-negative. For example, if the value of a semaphore is initialized to 5, then the semaphore can be reduced by a maximum of 5 consecutive times until the counter is reduced to zero. Resource count is suitable for occasions where the processing speeds between threads do not match. At this time, the semaphore can be counted as the number of completed tasks of the previous thread, and when dispatched to the next thread, it can also be used in a continuous manner handling multiple events each time. For example, in the producer and consumer problem, the producer can release the semaphore multiple times, and then the consumer can process multiple semaphore resources each time when dispatched. >Generally, resource count is mostly inter-thread synchronization in a hybrid mode, because there are still multiple accesses from threads for a single resource processing, which requires accessing and processing for a single resource, and operate lock mutex operation. -Mutex ------- +# Mutex Mutexes, also known as mutually exclusive semaphores, are a special binary semaphore. Mutex is similar to a parking lot with only one parking space: when one car enters, the parking lot gate is locked and other vehicles are waiting outside. When the car inside comes out, parking lot gate will open and the next car can enter. -### Mutex Working Mechanism +## Mutex Working Mechanism The difference between a mutex and a semaphore is that the thread with a mutex has ownership of the mutex, mutex supports recursive access and prevents thread priority from reversing; and mutex can only be released by the thread holding it, whereas semaphore can be released by any thread. @@ -603,7 +601,7 @@ In the RT-Thread operating system, mutex can solve the priority inversion proble >After the mutex is obtained, release the mutex as soon as possible. During the time when holding the mutex, you must not change the priority of the thread holding the mutex. -### Mutex Control Block +## Mutex Control Block In RT-Thread, mutex control block is a data structure used by the operating system to manage mutexes, represented by the struct rt rt_mutex. Another C expression, rt_mutex_t, represents the handle of the mutex, and the implementation in C language refers to the pointer of the mutex control block. See the following code for a detailed definition of the mutex control block structure: @@ -623,13 +621,13 @@ struct rt_mutex The rt_mutex object is derived from rt_ipc_object and is managed by the IPC container. -### Mutex Management +## Mutex Management The mutex control block contains important parameters related to mutex and it plays an important role in the implementation of the mutex function. The mutex-related interface is as shown in the following figure. The operation of a mutex includes: creating/initiating a mutex, obtaining a mutex, releasing a mutex, and deleting/detaching a mutex. ![Mutex Related Interface](figures/06mutex_ops.png) -#### Create and Delete Mutex +### Create and Delete Mutex When creating a mutex, the kernel first creates a mutex control block and then completes the initialization of the control block. Create a mutex using the following function interface: @@ -665,7 +663,7 @@ Input parameters and return values of rt_mutex_delete() |**Return**| —— | | RT_EOK | Deleted successfully | -#### Initialize and Detach Mutex +### Initialize and Detach Mutex The memory of a static mutex object is allocated by the compiler during system compilation, and is usually placed in a read-write data segment or an uninitialized data segment. Before using such static mutex objects, you need to initialize them first. To initialize the mutex, use the following function interface: @@ -701,7 +699,7 @@ Input parameters and return values for rt_mutex_detach() |**Return**| —— | | RT_EOK | Successful | -#### Obtain Mutex +### Obtain Mutex Once the thread obtains the mutex, the thread has ownership of the mutex, that is, a mutex can only be held by one thread at a time. To obtain the mutex, use the following function interface: @@ -722,7 +720,7 @@ Input parameters and return values of rt_mutex_take() | \-RT_ETIMEOUT | Timeout | | \-RT_ERROR | Failed to obtain | -#### Release Mutex +### Release Mutex When a thread completes the access to a mutually exclusive resource, it should release the mutex it occupies as soon as possible, so that other threads can obtain the mutex in time. To release the mutex, use the following function interface: @@ -740,7 +738,7 @@ Input parameters and return values of rt_mutex_release() |**Return**| —— | | RT_EOK | Success | -### Mutex Application Sample +## Mutex Application Sample This is a mutex application routine, and a mutex lock is a way to protect shared resources. When a thread has the mutex lock, it can protect shared resources from being destroyed by other threads. The following example can be used to illustrate. There are two threads: thread 1 and thread 2, thread 1 adds 1 to each of the two numbers; thread 2 also adds 1 to each of the two numbers. mutex is used to ensure that the operation of the thread changing the values of the 2 numbers is not interrupted. As shown in the following code: @@ -1003,7 +1001,7 @@ The routine demonstrates how to use the mutex. Thread 3 holds the mutex first, a >It is important to remember that mutexes cannot be used in interrupt service routines. -### Occasions to Use Mutex +## Occasions to Use Mutex The use of a mutex is relatively simple because it is a type of semaphore and it exists in the form of a lock. At the time of initialization, the mutex is always unlocked, and when it is held by the thread, it immediately becomes locked. Mutex is more suitable for: @@ -1011,8 +1009,7 @@ The use of a mutex is relatively simple because it is a type of semaphore and it (2) A situation in which priority inversion may occur due to multi-thread synchronization. -Event ------- +# Event Event set is also one of the mechanisms for synchronization between threads. An event set can contain multiple events. Event set can be used to complete one-to-many, many-to-many thread synchronization. Let's take taking bus as an example to illustrate event. There may be the following situations when waiting for a bus at a bus stop: @@ -1024,7 +1021,7 @@ Event set is also one of the mechanisms for synchronization between threads. An Here, P1 leaving for a certain place can be regarded as a thread, and “bus arrives at the bus stop” and “P2 arrives at the bus stop” are regarded as the occurrence of events. Situation ① is a specific event to wakes up the thread; situation ② is any single event to wake up the thread; situation ③ is when multiple events must occur simultaneously to wake up the thread. -### Event Set Working Mechanism +## Event Set Working Mechanism The event set is mainly used for synchronization between threads. Unlike the semaphore, it can achieve one-to-many, many-to-many synchronization. That is, the relationship between a thread and multiple events can be set as follows: any one of the events wakes up the thread, or several events wake up the thread for subsequent processing; likewise, the event can be multiple threads to synchronize multiple events. This collection of multiple events can be represented by a 32-bit unsigned integer variable, each bit of the variable representing an event, and the thread associates one or more events by "logical AND" or "logical OR" to form event combination. The "logical OR" of an event is also called independent synchronization, which means that the thread is synchronized with one of the events; the event "logical AND" is also called associative synchronization, which means that the thread is synchronized with several events. @@ -1042,7 +1039,7 @@ In RT-Thread, each thread has an event information tag with three attributes. Th As shown in the figure above, the first and 30th bits of the event flag of thread #1 are set. If the event information flag is set to logical AND, it means that thread #1 will be triggered to wake up only after both event 1 and event 30 occur. If the event information flag is set to logical OR, the occurrence of either event 1 or event 30 will trigger to wake up thread #1. If the message flag also sets the clear flag bit, this means event 1 and event 30 will be automatically cleared to zero when thread #1 wakes up, otherwise the event flag will still be present (set to 1). -### Event Set Control Block +## Event Set Control Block In RT-Thread, event set control block is a data structure used by the operating system to manage events, represented by the structure struct rt_event. Another C expression, rt_event_t, represents the handle of the event set, and the implementation in C language is a pointer to the event set control block. See the following code for a detailed definition of the event set control block structure: @@ -1060,13 +1057,13 @@ typedef struct rt_event* rt_event_t; rt_event object is derived from rt_ipc_object and is managed by the IPC container. -### Management of Event Sets +## Management of Event Sets Event set control block contains important parameters related to the event set and plays an important role in the implementation of the event set function. The event set related interfaces are as shown in the following figure. The operations on an event set include: create/initiate event sets, send events, receive events, and delete/detach event sets. ![Event Related Interface](figures/06event_ops.png) -#### Create and Delete Event Set +### Create and Delete Event Set When creating an event set, the kernel first creates an event set control block, and then performs basic initialization on the event set control block. The event set is created using the following function interface: @@ -1102,7 +1099,7 @@ Input parameters and return values of rt_event_delete() |**Return**| —— | | RT_EOK | Success | -#### Initialize and Detach Event Set +### Initialize and Detach Event Set The memory of a static event set object is allocated by the compiler during system compilation, and is usually placed in a read-write data segment or an uninitialized data segment. Before using a static event set object, you need to initialize it first. The initialization event set uses the following function interface: @@ -1138,7 +1135,7 @@ Input parameters and return values for rt_event_detach() |**Return**| —— | | RT_EOK | Success | -#### Send Event +### Send Event The send event function can send one or more events in the event set as follows: @@ -1157,7 +1154,7 @@ Input parameters and return values of rt_event_send() |**Return**| —— | | RT_EOK | Success | -#### Receive Event +### Receive Event The kernel uses a 32-bit unsigned integer to identify the event set, each bit represents an event, so an event set object can wait to receive 32 events at the same time, and the kernel can decide how to activate the thread by specifying the parameter "logical AND" or "logical OR". Using the "logical AND" parameter indicates that the thread is only activated when all waiting events occur, and using the "logical OR" parameter means that the thread is activated as soon as one waiting event occurs. To receive events, use the following function interface: @@ -1196,7 +1193,7 @@ RT_EVENT_FLAG_AND RT_EVENT_FLAG_CLEAR ``` -### Event Set Application Sample +## Event Set Application Sample This is the application routine for the event set, which initializes an event set, two threads. One thread waits for an event of interest to it, and another thread sends an event, as shown in code listing 6-5: @@ -1322,7 +1319,7 @@ thread1 leave. The routine demonstrates how to use the event set. Thread 1 receives events twice before and after, using the "logical OR" and "logical AND" respectively. -### Occasions to Use Event Set +## Occasions to Use Event Set Event sets can be used in a variety of situations, and it can replace semaphores to some extent for inter-thread synchronization. A thread or interrupt service routine sends an event to the event set object, and the waiting thread is awaken and the corresponding event is processed. However, unlike semaphore, the event transmission operation is not cumulative until the event is cleared, and the release actions of semaphore are cumulative. Another feature of the event is that the receiving thread can wait for multiple events, meaning multiple events correspond to one thread or multiple threads. At the same time, according to thread waiting parameters, you can choose between a "logical OR" trigger or a "logical AND" trigger. This feature is not available for semaphores, etc. The semaphore can only recognize a single release action, and cannot wait for multiple types of release at the same time. The following figure shows the multi-event receiving diagram: diff --git a/documentation/thread/thread.md b/documentation/thread/thread.md index 4c384cd747..e7244faa81 100644 --- a/documentation/thread/thread.md +++ b/documentation/thread/thread.md @@ -1,5 +1,4 @@ -Thread Management -======================== +@page thread_management Thread Management When we are facing a big task in our daily life, we usually break it down into a number of simple, easy-to-manage smaller tasks. Then, we would deal with these smaller tasks one by one, gradually, the big task is worked out. In a multi-threaded operating system, developers also need to break down a complex application into multiple small, schedulable, and serialized program units. When tasks are reasonably divided and properly executed, this design allows the system to meet the capacity and time requirements of the real-time system. For example, to have the embedded system to perform such tasks, the system would collect data through sensors and display the data on the screen. In a multi-threaded real-time system, the task can be decomposed into two subtasks. The subtask, as shown in the following figure, reads the sensor data continuously and writes the data into the shared memory. The other subtask periodically reads the data from the shared memory and outputs the sensor data onto the screen. @@ -11,8 +10,7 @@ When a thread runs, it thinks it is has sole access to the CPU as it is running. This chapter will be divided into five sections to introduce thread management in RT-Thread. After reading this chapter, readers will have a deeper understanding of the thread management mechanism of RT-Thread. They will have clear answers to questions like what states does a thread have, how to create a thread, why do idle threads exist, etc. -Thread Management Features ------------------- +# Thread Management Features The main function of RT-Thread's thread management is to manage and schedule threads. There are two types of threads in the system, namely system threads and user threads. System threads are threads created by the RT-Thread kernel. User threads are the thread created by the application. Both types of threads will allocate thread objects from the kernel object container. When a thread is deleted, it will also be deleted from the object container. As shown in the following figure, each thread has important attributes, such as a thread control block, thread stack, entry function, and so on. @@ -26,10 +24,9 @@ If it is the interrupt service routine that makes the running condition ready fo When the scheduler schedules threads and switches them, the current thread context is first saved. When it is switched back to this thread, the scheduler restores the context information of the thread. -Working Mechanism of Thread --------------- +# Working Mechanism of Thread -### Thread Control Block +## Thread Control Block In RT-Thread, the thread control block is represented by structure `struct rt_thread`, which is a data structure used by the operating system to manage threads. It stores information about the thread, such as priority, thread name, thread status, etc. It also includes a linked list structure for connecting threads, event collection of thread waiting, etc., which is defined as follows: @@ -75,9 +72,9 @@ struct rt_thread `init_priority` is the thread priority specified when the thread was created, and will not be changed while the thread is running (unless the user executes the thread control function to manually adjust the thread priority). `cleanup` will be called back by the idle thread when the thread exits to perform the user-setup cleanup site and so on. The last member, `user_data`, can be used by the user to send some data into the thread control block to provide an implementation similar to thread private data. -### Thread Important Attributes +## Thread Important Attributes -#### Thread Stack +### Thread Stack RT-Thread's threads have a dependent stack. When the thread is switched, the context of the current thread is stored in the stack. When the thread is about to resume operation, the context information is read from the stack and recovered. @@ -91,7 +88,7 @@ The growth direction of the thread stack is closely related to the CPU architect When setting the size for thread stack, a larger thread stack can be designed for an MCU with a relatively large resource pool; or a larger stack can be set initially, for example, a size of 1K or 2K bytes, then in FinSH, use `list_thread` command to check the size of the stack used by the thread during the running of the thread. With this command, you can see the maximum stack depth used by the thread from the start of the thread to the current point in time, and then add the appropriate margin to form the final thread stack size, and finally modify the size of the stack space. -#### Thread State +### Thread State Only one thread is allowed to run on a processor at any time. Apart from the running process, threads have various different operating states, such as initial state, suspended state, ready state, etc. In RT-Thread, a thread can have five states, and the operating system would automatically adjust its state based on its running condition. @@ -105,19 +102,19 @@ The five states of a thread in RT-Thread are shown in the following table: | Suspended State | Also known as the blocking state. It may be suspended and paused because the resource is unavailable, or the thread is suspended because it is voluntarily delayed. In suspended state, threads do not participate in scheduling. In RT-Thread, the macro definition of this state is RT_THREAD_SUSPEND | | Closed State | It will be turned to closed state when the thread finishes running. The thread in closed state does not participate in the thread's scheduling. In RT-Thread, the macro definition of this state is RT_THREAD_CLOSE | -#### Thread Priority +### Thread Priority The priority of the RT-Thread thread indicates the thread's priority of being scheduled. Each thread has its priority. The more important the thread, the higher priority it should be given, resulting in a higher chance of being scheduled. RT-Thread supports a maximum of 256 thread priorities (0~255). The lower the number, the higher the priority, with 0 being the highest priority. In some systems with tight resources, you can choose system configurations that only support 8 or 32 priorities according to the actual situation; for the ARM Cortex-M series, 32 priorities are commonly used. The lowest priority is assigned to idle threads by default and is not used by users. In the system, when a thread with a higher priority is ready, the current thread with the lower priority will be swapped out immediately, and the high-priority thread will preempt the processor. -#### Time Slice +### Time Slice Each thread has a time slice parameter, but time slice is only valid for ready-state threads of the same priority. The system schedules the ready-state threads with the same priority using time slice rotation scheduling method. In this case, time slice plays the role of constraining thread's single running time and the unit is a system tick (OS Tick). Suppose there are 2 ready-state threads, A and B with the same priority. Time slice of A thread is set to 10, and time slice of B thread is set to 5. When there is no ready-state thread with higher priority than A in the system, the system will switch back and forth between thread A and B. Each time the system performs 10 OS Ticks on thread A, and 5 OS Ticks on thread B, as shown below. ![Same Priority Time Slice Round Robin](figures/04time_slience.png) -#### Thread Entry Function +### Thread Entry Function "Entry" in Thread Control Block is the thread's entry function, which is the thread's main function. The thread's entry function is created by the user. There are generally two forms of code: @@ -154,7 +151,7 @@ static void thread_entry(void* parameter) } ``` -#### Thread Error Code +### Thread Error Code Each thread is one execution scenario. Error codes are closely related to the execution environment, so each thread is equipped with a variable to store the error code. These error codes are as follows: @@ -172,7 +169,7 @@ Each thread is one execution scenario. Error codes are closely related to the ex #define RT_EINVAL 10 /* Invalid Parameter */ ``` -### Switching Thread State +## Switching Thread State RT-Thread provides a set of operating system call interfaces that make the state of a thread to switch back and forth between these five states. The conversion relationship between these states is shown in the following figure: @@ -184,11 +181,11 @@ If a thread in suspended state calls the functions `rt_thread_delete()` or `rt_t >In RT-Thread, a thread does not actually have a running state; the ready state and the running state are equivalent. -### System thread +## System thread As mentioned previously, system threads refers to threads created by the system and user threads are threads created by the user program calling the thread management interface. System threads In RT-Thread kernel include the idle thread and the main thread. -#### Idle Thread +### Idle Thread An idle thread is the lowest priority thread created by the system, and its thread state is always ready. When no other ready thread exists in the system, the scheduler will schedule the idle thread, which is usually an infinite loop and can never be suspended. In addition, idle threads have special functions in RT-Thread: @@ -196,14 +193,13 @@ If a thread finishes running, the system will automatically delete the thread by The idle thread also provides an interface to run a hook function set by the user. The hook function is called when idle thread is running, which is suitable for operations like hooking into power management, watchdog feeding, etc. -#### Main Thread +### Main Thread When the system starts, it will create the main thread. Its entry function is `main_thread_entry()`. User's application entry function `main()` starts from here. After the system scheduler starts, the main thread starts running. The process is as follows. Users can add their own application initialization code to the `main()` function. ![Main Thread Calling Process](figures/04main_thread.png) -Thread Management --------------- +# Thread Management The first two sections of this chapter conceptually explain the function and working mechanism of threads. This section will delve into the various interfaces of threads and give some source code to help the reader understand threads. @@ -211,7 +207,7 @@ The following figure depicts related operations to threads, including creating / ![Thread Related Operations](figures/04thread_ops.png) -### Create and Delete Thread +## Create and Delete Thread To become an executable object, a thread must be created by the kernel of the operating system. You can create a dynamic thread through the following interface: @@ -246,8 +242,6 @@ rt_err_t rt_thread_delete(rt_thread_t thread); After calling this function, the thread object will be moved out of the thread list and removed from the kernel object manager. Consequently, the stack space occupied by the thread will also be freed, and the reclaimed space will be reused for other memory allocations. In fact, using the `rt_thread_delete()` function to delete the thread interface is just changing the corresponding thread state to RT_THREAD_CLOSE state and then putting it into rt_thread_defunct queue; the actual delete action (releasing the thread control block and releasing the thread stack) needs to be completed later by an idle thread when it is being executed. -### Thread deletion - The parameters and return values of thread deleting `rt_thread_delete()` interface are shown in the following table: |**Parameter** |**Description** | @@ -259,7 +253,7 @@ The parameters and return values of thread deleting `rt_thread_delete()` interfa This function is only valid when the system dynamic heap is enabled (meaning RT_USING_HEAP macro definition is already defined). -### Initialize and Detach Thread +## Initialize and Detach Thread The initialization of a thread can be done using the following function interface, to initialize a static thread object: @@ -304,7 +298,7 @@ Parameters and return values of the thread detached from the interface `rt_threa This function interface corresponds to the `rt_thread_delete()` function. The object operated by the rt_thread_delete() function is the handle created by rt_thread_create(), and the object operated by the rt_thread_detach() function is the thread control block initialized with the rt_thread_init() function. Again, the thread itself should not call this interface to detach thread itself. -### Start Thread +## Start Thread The thread created (initialized) is in initial state and does not enter the scheduling queue of the ready thread. We can call the following function interface to make the thread enter the ready state after the thread is initialized/created successfully: @@ -321,7 +315,7 @@ When this function is called, the state of the thread is changed to the ready st | RT_EOK | Thread started successfully. | | \-RT_ERROR | Thread start failed. | -### Obtaining Current Thread +## Obtaining Current Thread During the running of the program, the same piece of code may be executed by multiple threads. At the time of execution, the currently executed thread handle can be obtained through the following function interface: @@ -336,7 +330,7 @@ The return value of this interface is shown in the following table: | thread | The currently running thread handle. | | RT_NULL | Failed, the scheduler has not started yet. | -### Making Thread Release Processor Resources +## Making Thread Release Processor Resources When the current thread's time slice runs out or the thread actively requests to release the processor resource, it will no longer occupy the processor, and the scheduler will select the next thread of the same priority to execute. After the thread calls this interface, the thread is still in the ready queue. The thread gives up the processor using the following function interface: @@ -348,7 +342,7 @@ After calling this function, the current thread first removes itself from its re The `rt_thread_yield()` function is similar to the `rt_schedule()` function, but the behavior of the system is completely different when other ready-state threads of the same priority exist. After executing the `rt_thread_yield()` function, the current thread is swapped out and the next ready thread of the same priority will be executed. After the `rt_schedule()` function is executed, the current thread is not necessarily swapped out. Even if it is swapped out, it will not be placed at the end of the ready thread list. Instead, the thread with the highest priority is selected in the system and executed. If there is no thread in the system with a higher priority than the current thread, the system will continue to execute the current thread after the `rt_schedule()` function is executed. -### Thread Sleep +## Thread Sleep In practical applications, we sometimes need to delay the current thread running for a period of time and re-run at a specified time. This is called "thread sleep". Thread sleep can use the following three function interfaces: @@ -365,7 +359,7 @@ These three function interfaces have the same effect. Calling them can cause the |**Return**| —— | | RT_EOK | Successful operation. | -### Suspend and Resume Thread +## Suspend and Resume Thread When a thread calls `rt_thread_delay()`, the thread will voluntarily suspend; when a function such as `rt_sem_take()`, `rt_mb_recv()` is called, the resource is not available for use and will cause the thread to suspend. A thread in a suspended state, if it waits for resources longer than the set time, then the thread will no longer wait for these resources and will return to the ready state; or, when other threads release the resource the thread is waiting for, the thread will also return to the ready state. @@ -403,7 +397,7 @@ The parameters and return values of the thread recovery interface `rt_thread_res | RT_EOK | Thread resumed successfully. | | \-RT_ERROR | Thread recovery failed because the state of the thread is not RT_THREAD_SUSPEND state | -### Control Thread +## Control Thread When you need other control over a thread, such as dynamically changing the priority of a thread, you can call the following function interface: @@ -430,7 +424,7 @@ Demands supported by control command demand cmd include: •RT_THREAD_CTRL_CLOSE:Close a thread, equivalent to the `rt_thread_delete()` function call. -### Set and Delete Idle Hooks +## Set and Delete Idle Hooks The idle hook function is a hook function of the idle thread. If the idle hook function is set, the idle hook function can be automatically executed to perform other things, such as the LED of system indicator , when the system executes the idle thread. The interface for setting/deleting idle hooks is as follows: @@ -459,7 +453,7 @@ Input parameters and return values of deleting the idle hook function `rt_thread >An idle thread is a thread whose state is always ready. Therefore, hook function must ensure that idle threads will not be suspended at any time. Functions like rt_thread_delay(), rt_sem_take(), etc can't be used because they may cause the thread to suspend. -### Set the Scheduler Hook +## Set the Scheduler Hook During the time when the system is running, it is in the process of thread running, interrupt triggering, responding to interrupts, switching to other threads, and switching between threads. In other words, context switching is the most common event in the system. Sometimes the user may want to know what kind of thread switch has occurred at times, you can set a corresponding hook function by calling the following function interface. This hook function will be called when the system thread switches: @@ -488,12 +482,11 @@ Input parameters for the scheduler hook function hook() are shown in the followi >Please carefully compile your hook function, any carelessness is likely to cause the entire system to run abnormally (in this hook function, it is basically not allowed to call the system API, and should not cause the current running context to suspend). -Thread Application Sample ------------- +# Thread Application Sample An application example in Keil simulator environment is given below. -### Create Thread Sample +## Create Thread Sample This sample is creating a dynamic thread and initializing a static thread. A thread is automatically deleted by the system after it has finished running. The other thread is always printing the counts, as follows: @@ -597,7 +590,7 @@ When thread 2 counts to a certain value, it will stop running. Then thread 2 is >About deleting threads: Most threads are executed cyclically without needing to be deleted. For thread that can finish running, RT-Thread automatically deletes the thread after the thread finishes running, and deletes it in rt_thread_exit(). User only needs to understand the role of the interface. It is not recommended to use this interface (this interface can be called by other threads or call this interface in the timer timeout function to delete a thread which is not used very often). -### Thread Time Slice Round-Robin Scheduling Sample +## Thread Time Slice Round-Robin Scheduling Sample This sample is creating two threads that will always print counts when executing, as follows: @@ -689,7 +682,7 @@ thread 2 is running ,thread 2 count = 205 As can be seen from the running count results, thread 2 runs half the time of thread 1. -### Thread Scheduler Hook Sample +## Thread Scheduler Hook Sample When thread is scheduling switch, it executes the schedule. We can set a scheduler hook so that we can do other things when the thread is being switched. This sample is printing switch information between the threads in the scheduler hook function, as shown in the following code. diff --git a/documentation/timer/timer.md b/documentation/timer/timer.md index 921719dd7e..3004c7a3ad 100644 --- a/documentation/timer/timer.md +++ b/documentation/timer/timer.md @@ -1,16 +1,14 @@ -Clock Management -======== +@page clock_management Clock & Timer Management The concept of time is very important. You need to set a time to go out with friends and it takes time to complete tasks. Life is inseparable from time. The same is true for operating systems, which require time to regulate the execution of their tasks. The smallest time unit in operating system is clock tick (OS Tick). This chapter focuses on introduction of clock ticks and clock-based timers. After reading this chapter, we will learn how clock ticks are generated and how to use RT-Thread timers. -Clock Tick(OS Tick) --------- +# Clock Tick(OS Tick) Any operating system needs to provide a clock tick for the system to handle all time-related events, such as thread latency, thread time slice rotation scheduling, timer timeout, etc. Clock tick is a specific periodic interrupt. This interrupt can be regarded as the system heartbeat. The time interval between interrupts depends on different applications, generally it is 1ms–100ms. The faster the clock tick rate, the greater the overhead of the system. The number of clock ticks counted from the start of the system is called the system time. In RT-Thread, the length of clock tick can be adjusted according to the value of RT_TICK_PER_SECOND, which is equal to 1/RT_TICK_PER_SECOND second. -### Clock Tick Implementation +## Clock Tick Implementation Clock tick is generated by a hardware timer configured in interrupt trigger mode. `void rt_tick_increase(void)` will be called when an interrupt occurs,notifying the operating system that a system clock has passed; different hardware driver have different timer interrupt implementations. Here is an example of using STM32 `SysTick_Handler` to achieve clock Tick. @@ -58,7 +56,7 @@ You can see that global variable rt_tick is incremented by one on every clock ti >In interrupt, rt_timer_check() is used to check the system hardware timer linked list. If there is a timer timeout, the corresponding timeout function will be called. All timers are removed from the timer linked list if it timed out, and periodic timer is added to the timer linked list when it is started again. -### Obtain Clock Tick +## Obtain Clock Tick Since global variable rt_tick is incremented by one on every clock tick, the value of the current rt_tick will be returned by calling `rt_tick_get`, which is the current clock tick value. This interface can be used to record the length of time a system is running, or to measure the time it takes for a task to run. The interface function is as follows: @@ -72,8 +70,7 @@ The following table describes the return values of `rt_tick_get()` function: |----------|----------------| | rt_tick | Current clock tick value | -Timer Management ----------- +# Timer Management Timer refers to triggering an event after a certain specified time from a specified moment, for example, setting a timer to wake up yourself the next morning. Timer includes hardware timer and software timer: @@ -83,7 +80,7 @@ Timer refers to triggering an event after a certain specified time from a specif RT-Thread operating system provides software-implemented timers in units of clock tick (OS Tick), that is, the timing value must be an integer multiple of OS Tick. For example, an OS Tick is 10ms, then the software timer can only be timed 10ms, 20ms, 100ms, etc., but not 15ms. RT-Thread timer is also based on the clock tick, providing timing capabilities based on integral multiples of the clock tick. -### RT-Thread Timer Introduction +## RT-Thread Timer Introduction RT-Thread timer provides two types of timer mechanisms: the first type is a one-shot timer, which only triggers a timer event for onetime after startup, and then the timer stops automatically. The second type is a periodic trigger timer, which periodically triggers a timer event until the user manually stops it, otherwise it will continue to execute forever. @@ -91,7 +88,7 @@ In addition, according to the context in which the timeout function is executed, ![Timer Context](figures/05timer_env.png) -#### HARD_TIMER Mode +### HARD_TIMER Mode The timer timeout function of HARD_TIMER mode is executed in the interrupt context and can be specified with the parameter RT_TIMER_FLAG_HARD_TIMER when initializing/creating the timer. @@ -99,11 +96,11 @@ When executed in interrupt context, the requirements for timeout function are th The default mode of RT-Thread timer is HARD_TIMER mode which means after the timer timeout, the timeout function runs in the context of the system clock interrupt. The execution mode in the interrupt context determines that the timer's timeout function should not call any system function that will cause the current context to suspend; nor can it be executing for a very long time, otherwise the response time of other interrupts will be lengthened or the running time of other threads will be preempted. -#### SOFT_TIMER Mode +### SOFT_TIMER Mode The SOFT_TIMER mode is configurable and macro definition RT_USING_TIMER_SOFT is used to determine whether the mode should be enabled. When this mode is enabled, the system will create a timer thread at initialization, and then the timer timeout function of SOFT_TIMER mode will be executed in the context of the timer thread. SOFT_TIMER mode can be specified using the parameter RT_TIMER_FLAG_SOFT_TIMER when initializing/creating the timer. -### Timer Working Mechanism +## Timer Working Mechanism The following is an example to illustrate the working mechanism of RT-Thread timer. Two important global variables are maintained in the RT-Thread timer module: @@ -121,7 +118,7 @@ If after system's 10 ticks (current rt_tick=30), a new task has created Timer4 ![Timer linked List Insertion Diagram](figures/05timer_linked_list2.png) -#### Timer Control Block +### Timer Control Block In RT-Thread operating system, timer control block is defined by structure `struct rt_timer` and forms a timer kernel object, which is then linked to the kernel object container for management. It is a data structure used by the operating system to manage timers. It stores information about timers, such as the initial number of ticks, the number of timeout ticks, the linked list structure used to connect timers, timeout callback functions, etc. @@ -141,7 +138,7 @@ typedef struct rt_timer *rt_timer_t; Timer control block is defined by structure `struct rt_timer` and forms a timer kernel object, which is then linked to the kernel object container for management. The `list` member is used to link an active (already started) timer to the `rt_timer_list` linked list. -#### Timer Skip List Algorithm +### Timer Skip List Algorithm In the introduction of working mechanics of the timer above, we have talked about that the newly created and activated timers are inserted into the rt_timer_list linked list in the order of the timeout, that is, rt_timer_list linked list is an ordered list. RT-Thread uses a skip list algorithm to speed up the search for linked list elements. @@ -161,7 +158,7 @@ In this structure, {3, 18, 77} is extracted as first-level index, so that the nu Therefore, the timer skip list can pass the index of the upper layer, reducing the number of comparisons during the search and improving the efficiency of the search. This is an algorithm of "space in exchange of time", macro definition RT_TIMER_SKIP_LIST_LEVEL is used to configure the number of layers in skip list. The default value is 1, which means that ordered linked list algorithm for first-order ordered list graph is used. Each additional one means that another level of index is added to the original list. -### Timer Management +## Timer Management RT-Thread timer is introduced in the previous sections and the working mechanism of the timer is conceptually explained. This section will go deep into the various interfaces of the timer to help the reader understand the RT-Thread timer at the code level. @@ -181,7 +178,7 @@ Timer control block contains important parameters related to the timer and acts ![Timer Related Operations](figures/05timer_ops.png) -#### Create and Delete Timer +### Create and Delete Timer When dynamically creating a timer, the following function interface can be used: @@ -236,7 +233,7 @@ Input parameters and return values of rt_timer_delete() |**Return**| —— | | RT_EOK | Deletion is successful (if the parameter timer handle is RT_NULL, it will result in an ASSERT assertion) | -#### Initialize and Detach Timer +### Initialize and Detach Timer When creating a timer statically , the timer can be initialized by using `rt_timer_init` interface. The function interface is as follows: @@ -277,7 +274,7 @@ Input parameters and return values for `rt_timer_detach()` |**Return **| —— | | RT_EOK | Successfully detached | -#### Start and Stop Timer +### Start and Stop Timer When the timer is created or initialized, it will not be started immediately. It will start after timer function interface is called. The timer function interface is started as follows: @@ -314,7 +311,7 @@ After the timer stop function interface is called, the timer state will change t | RT_EOK | Timer successfully stopped | | \- RT_ERROR | timer is in stopped state | -#### Control Timer +### Control Timer In addition to some of the programming interfaces provided above, RT-Thread additionally provides a timer control function interface to obtain or set more timer information. The control timer function interface is as follows: @@ -345,8 +342,7 @@ Commands supported by function parameters cmd: See "dynamic timer routine" for code that uses the timer control interface. -Timer Application Sample --------------- +# Timer Application Sample This is an example of creating a timer that creates two dynamic timers, one for one shot timing, another one for periodic timing and for the periodic timer to run for a while and then stop running, as shown below: @@ -498,8 +494,7 @@ periodic timer is timeout The timeout function of periodic timer1 runs once every 10 OS Ticks for 10 times (After 10 times rt_timer_stop is called to stop timer1); the timeout function of one-shot timer2 runs once on the 30th OS Tick. -High Precision Delay ----------- +# High Precision Delay The minimum precision of the RT-Thread timer is determined by the system clock tick (1 OS Tick = 1/RT_TICK_PER_SECOND second, RT_TICK_PER_SECOND value is defined in the rtconfig.h file), and the timer must be set to an integer multiple of the OS Tick. When it is necessary to implement system timing for a shorter time length. For example, the OS Tick is 10ms but the program needs to implement a timing or delay of 1ms. In this case, the operating system timer can't meet the requirements. This problem can be solved by reading the counter of a hardware timer of the system or using hardware timer directly. diff --git a/documentation/ulog/ulog.md b/documentation/ulog/ulog.md index 78d1e0a1d6..3b300f1fc7 100644 --- a/documentation/ulog/ulog.md +++ b/documentation/ulog/ulog.md @@ -1,6 +1,6 @@ -# Ulog Log +@page component_ulog Ulog Log -## Ulog Introduction +# Ulog Introduction **Log definition**:The log is to output the status, process and other information of the software to different media (for example: file, console, display, etc.), display and save. Provide reference for software traceability, performance analysis, system monitoring, fault warning and other functions during software debugging and maintenance. It can be said that the use of logs consumes at least 80% of the software life cycle. @@ -26,7 +26,7 @@ Ulog is a very simple and easy to use C/C++ log component. The first letter u st * Compatible with `rtdbg` (RTT's early log header file) and EasyLogger's log output API. -### Ulog Architecture +## Ulog Architecture The following figure shows the ulog log component architecture diagram: @@ -38,7 +38,7 @@ The following figure shows the ulog log component architecture diagram: * **Back end**:After receiving the log frames sent from the core layer, the logs are output to the registered log backend devices, such as files, consoles, log servers, and so on. -### Configuration Options ### +## Configuration Options The path to configure ulog using menuconfig in the ENV tool is as follows: @@ -72,7 +72,7 @@ The path to configure ulog using menuconfig in the ENV tool is as follows: [ ] Enable thread information. /* Thread information */ ``` -### Log Level +## Log Level The log level represents the importance of the log, from high to low in ulog, with the following log levels: @@ -102,7 +102,7 @@ As can be seen from the above classification, the output level of the log can be Their scope of action is:**Global Static**>**Global Dynamics**>**Module Static**>**Module Dynamic**. -### Log Label +## Log Label Due to the increasing log output, in order to avoid the log being outputted indiscriminately, it is necessary to use a tag to classify each log. The definition of the label is in the form of **modular**, for example: Wi-Fi components include device driver (wifi_driver), device management (wifi_mgnt) and other modules, Wi-Fi component internal module can use `wifi.driver`, `wifi.mgnt` is used as a label to perform classified output of logs. @@ -120,9 +120,9 @@ Note that the definition log tag must be above `#include `, otherwise th The scope of the log tag is the current source file, and the project source code will usually be classified according to the module. Therefore, when defining a label, you can specify the module name and sub-module name as the label name. This is not only clear and intuitive when the log output is displayed, but also facilitates subsequent dynamic adjustment of the level or filtering by label. -## Log Initialization +# Log Initialization -### Initialization +## Initialization ```c int ulog_init(void) @@ -135,7 +135,7 @@ int ulog_init(void) This function must be called to complete ulog initialization before using ulog. This function will also be called automatically if component auto-initialization is turned on. -### Deinitialization +## Deinitialization ```c void ulog_deinit(void) @@ -143,7 +143,7 @@ void ulog_deinit(void) This deinit release resource can be executed when ulog is no longer used. -## Log Output API +# Log Output API Ulog mainly has two log output macro APIs, which are defined in the source code as follows: @@ -197,9 +197,9 @@ void show_string(const char *str) } ``` -## ULog Usage Example +# ULog Usage Example -### Example +## Example The following is a description of the ulog routine. Open `rt-thread\examples\ulog_example.c` and you can see that there are labels and static priorities defined at the top. @@ -233,7 +233,7 @@ The following will show the effect of the ulog routine on qemu: You can see that each log is displayed in rows, and different levels of logs have different colors. At the top of the log is the tick of the current system, with the log level and label displayed in the middle, and the specific log content at the end. These log formats and configuration instructions are also highlighted later in this article. -### Used in Interrupt ISR +## Used in Interrupt ISR Many times you need to output a log in the interrupt ISR, but the ISR may interrupt the thread that is doing the log output. To ensure that the interrupt log and the thread log do not interfere with each other, special handling must be performed for the interrupt condition. @@ -263,7 +263,7 @@ Here are the different strategies for interrupt logging in ulog in synchronous m **In asynchronous mode**:If the above situation occurs, the log in the interrupt will be put into the buffer first, and finally sent to the log output thread for processing together with the thread log. -### Set the Log Format +## Set the Log Format The log format supported by ulog can be configured in menuconfig, located in `RT-Thread Components` → `Utilities` → `ulog` → `log format`. The specific configuration is as follows: @@ -275,7 +275,7 @@ They can be configured separately: floating-point number support (traditional rt It can be seen that the time information has been changed from the tick value of the system to the timestamp information compared to the first run routine, and the thread information has also been output. -### Hexdump Output Using +## Hexdump Output Using Hexdump is also a more common function when logging output. hexdump can output a piece of data in hex format. The corresponding API is: `void ulog_hexdump(const char *tag, rt_size_t width, rt_uint8_t *buf, rt_size_t size)` , see below the specific use method and operation effect: @@ -297,13 +297,13 @@ You can copy the above code into the ulog routine, and then look at the actual r It can be seen that the middle is the hexadecimal information of the buf data, and the rightmost is the character information corresponding to each data. -## Log Advanced Features +# Log Advanced Features After understanding the introduction of the log in the previous section, the basic functions of ulog can be mastered. In order to let everyone better use ulog, this application note will focus on the advanced features of ulog and some experience and skills in log debugging. After learning these advanced uses, developers can also greatly improve the efficiency of log debugging. It also introduces the advanced mode of ulog: syslog mode, which is fully compatible with the Linux syslog from the front-end API to the log format, greatly facilitating the migration of software from Linux. -### Log Backend +## Log Backend ![Ulog framework](figures/ulog_framework_backend.png) @@ -311,7 +311,7 @@ Speaking of the backend, let's review the ulog's framework. As can be seen from Currently ulog has integrated the console backend, the traditional device that outputs `rt_kprintf` print logs. Ulog also supports the Flash backend, which seamlessly integrates with EasyFlash. See its package for details.([Click to view](https://github.com/armink-rtt-pkgs/ulog_easyflash_be))。Later ulog will also increase the implementation of backends such as file backends and network backends. Of course, if there are special needs, users can also implement the backend themselves. -#### Register Backend Device +### Register Backend Device ```c rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool_t support_color) @@ -327,7 +327,7 @@ rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool This function is used to register the backend device into the ulog, ensuring that the function members in the backend device structure are set before registration. -#### Logout Backend Device +### Logout Backend Device ```c rt_err_t ulog_backend_unregister(ulog_backend_t backend); @@ -341,7 +341,7 @@ rt_err_t ulog_backend_unregister(ulog_backend_t backend); This function is used to unregister a backend device that has already been registered. -#### Backend Implementation and Registration Examples +### Backend Implementation and Registration Examples The console backend is taken as an example to briefly introduce the implementation method and registration method of the backend. @@ -400,7 +400,7 @@ From the perspective of this structure, the requirements for implementing the ba * `flush` is also optional, and some internal output cached backends need to implement this interface. For example, some file systems with RAM cache. The flush of the backend is usually called by `ulog_flush` in the case of an exception such as assertion or hardfault. -### Asynchronous Log +## Asynchronous Log In ulog, the default output mode is synchronous mode, and in many scenarios users may also need asynchronous mode. When the user calls the log output API, the log is cached in the buffer, and the thread dedicated to the log output takes out the log and outputs it to the back end. @@ -420,7 +420,7 @@ The advantages and disadvantages of asynchronous mode are as follows: **Disadvantage**:First, the asynchronous mode requires a log buffer. Furthermore, the output of the asynchronous log needs to be completed by a special thread, such as an idle thread or a user-defined thread, which is slightly more complicated to use. The overall sense of asynchronous mode resource occupancy will be higher than the synchronous mode. -#### Configuration Option +### Configuration Option Use menuconfig in the Env tool to enter the ulog configuration options: @@ -444,7 +444,7 @@ When using the idle thread output, the implementation is simple, just call `rt_t * Because thread suspend operations are not allowed inside idle threads, backends such as Flash and networking may not be available based on idle threads. -#### Use Example +### Use Example Save the asynchronous output option configuration and copy `rt-thread\examples\ulog_example.c` to the `rt-thread\bsp\qemu-vexpress-a9\applications` folder. @@ -455,13 +455,13 @@ Enter the `ulog_example` command to see the results of the ulog routine. The app If you look carefully, you can see that after the asynchronous mode is turned on, the time information of these logs that are very close in code is almost the same. However, in synchronous mode, the log is output using the user thread. Since the log output takes a certain amount of time, there is a certain interval between each log. It also fully shows that the asynchronous log output is very efficient, and it takes almost no time for the caller. -### Log Dynamic Filter +## Log Dynamic Filter In the previous section, some static filtering functions have been introduced. Static filtering has its advantages such as saving resources, but in many cases, users need to dynamically adjust the filtering mode of the log while the software is running. This allows the dynamic filter function of ulog to be used. To use the dynamic filter feature, turn on the `Enable runtime log filter.` option in menuconfig, which is **turned off by default**. There are four types of dynamic filtering supported by ulog, and there are corresponding API functions and Finsh/MSH commands, which will be introduced one by one. -#### Filter by Module Level +### Filter by Module Level ```c int ulog_tag_lvl_filter_set(const char *tag, rt_uint32_t level) @@ -499,7 +499,7 @@ An example of a function call and command is as follows: | Open all logs of `wifi` module | `ulog_tag_lvl_filter_set("wifi", LOG_FILTER_LVL_ALL);` | `ulog_tag_lvl wifi 7` | | Set the `wifi` module log level to warning | `ulog_tag_lvl_filter_set("wifi", LOG_LVL_WARNING);` | `ulog_tag_lvl wifi 4` | -#### Global Filtering by Label +### Global Filtering by Label ```c void ulog_global_filter_tag_set(const char *tag) @@ -521,7 +521,7 @@ For example: there are 3 kinds of tags for `wifi.driver`, `wifi.mgnt`, `audio.dr | Set the filter tag to `driver` | `ulog_global_filter_tag_set("driver");` | `ulog_tag driver` | | Cancel label filtering | `ulog_global_filter_tag_set("");` | `ulog_tag` | -#### Global Filtering by Level +### Global Filtering by Level ```c void ulog_global_filter_lvl_set(rt_uint32_t level) @@ -549,7 +549,7 @@ After setting the global filter level by function or command, the log below **se | Open all logs | `ulog_global_filter_lvl_set(LOG_FILTER_LVL_ALL);` | `ulog_lvl 7` | | Set the log level to warning | `ulog_global_filter_lvl_set(LOG_LVL_WARNING);` | `ulog_lvl 4` | -#### Global Filtering by Keyword +### Global Filtering by Keyword ```c void ulog_global_filter_kw_set(const char *keyword) @@ -568,7 +568,7 @@ This filtering method can filter all the logs by keyword, and the log **containi | Set the filter keyword to `wifi` | `ulog_global_filter_kw_set("wifi");` | `ulog_kw wifi` | | Clear filter keywords | `ulog_global_filter_kw_set("");` | `ulog_kw` | -#### View Filter Information +### View Filter Information After setting the filter parameters, if you want to view the current filter information, you can enter the `ulog_filter` command. The approximate effect is as follows: @@ -588,7 +588,7 @@ msh /> > Filter parameters are also supported storing in Flash and also support boot autoload configuration. If you need this feature, please see the instructions for the **ulog_easyflash** package.([Click to check](https://github.com/armink-rtt-pkgs/ulog_easyflash_be)) -#### Use Example +### Use Example Still executing in qemu BSP, first open dynamic filter in menuconfig, then save the configuration and compile and run the routine. After the log output is about **20** times, the corresponding filter code in ulog_example.c will be executed: @@ -642,7 +642,7 @@ At this time, the log output level of the `test` module is adjusted to `LOG_FILT ![ulog filter routine 40](figures/ulog_example_filter40.png) -### Usage when the System is Abnormal +## Usage when the System is Abnormal Since the asynchronous mode of ulog has a caching mechanism, the registered backend may also have a cache inside. If there are error conditions such as hardfault and assertion in the system, but there are still logs in the cache that are not output, which may cause the log to be lost. It is impossible to find the cause of the exception. @@ -650,7 +650,7 @@ For this scenario, ulog provides a unified log flush function: `void ulog_flush( The following is an example of RT-Thread assertion and CmBacktrace: -#### Assertion +### Assertion RT-Thread assertions support assertion callbacks. We define an assertion hook function similar to the following, and then set it to the system via the `rt_assert_set_hook(rtt_user_assert_hook);` function. @@ -666,7 +666,7 @@ static void rtt_user_assert_hook(const char* ex, const char* func, rt_size_t lin } ``` -#### CmBacktrace +### CmBacktrace CmBacktrace is a fault diagnosis library for ARM Cortex-M series MCUs. It also has a corresponding RT-Thread package, and the latest version of the package has been adapted for ulog. The adaptation code is located in `cmb_cfg.h` : @@ -685,7 +685,7 @@ CmBacktrace is a fault diagnosis library for ARM Cortex-M series MCUs. It also h It can be seen that when ulog is enabled, each log output of CmBacktrace will use the error level, and `ulog_flush` will be executed at the same time, and the user does not need to make any modifications. -### Syslog Mode +## Syslog Mode On Unix-like operating systems, syslog is widely used in system logs. The common backends of syslog are files and networks. The syslog logs can be recorded in local files or sent over the network to the server that receives the syslog. @@ -693,7 +693,7 @@ Ulog provides support for the syslog mode, not only the front-end API is exactly To use the syslog configuration you need to enable the `Enable syslog format log and API.` option. -#### Log Format +### Log Format ![ulog syslog format](figures/ulog_syslog_format.png) @@ -706,7 +706,7 @@ As shown in the figure above, the ulog syslog log format is divided into the fol | TAG | The current log label can be passed in via the `openlog` function. If not specified, `rtt` will be used as the default label. | | Content | The specific content of the log | -#### Instruction +### Instruction The syslog option needs to be enabled in menuconfig before use. The main commonly used APIs are: @@ -721,15 +721,15 @@ syslog() is very simple to use. The input format is the same as the printf funct ![ulog syslog routine](figures/ulog_example_syslog.png) -### Migrate from *rt_dbg.h* or elog to ulog +## Migrate from *rt_dbg.h* or elog to ulog If the two types of log components were used in the project before, when ulog is to be used, it will involve how to make the previous code also support ulog. The following will focus on the migration process. -#### Migrate from rt_dbg.h +### Migrate from rt_dbg.h Currently rtdbg has completed **seamless docking** ulog. After ulog is turned on, the code of rtdbg in the old project can be used to complete the log output without any modification. -#### Migrate from Elog(EasyLogger) +### Migrate from Elog(EasyLogger) If you are not sure that a source code file is running on a target platform that will use ulog, then it is recommended to add the following changes to the file: @@ -743,58 +743,58 @@ If you are not sure that a source code file is running on a target platform that If you explicitly only use the ulog component, then simply change the header file reference from `elog.h` to `ulog .h`, and no other code needs to be changed. -### Log Usage Tip +## Log Usage Tip With the logging tool, if it is used improperly, it will also cause the log to be abused, and the log information cannot be highlighted. Here we will focus on sharing some tips on the use of the log component to make the log information more intuitive. The main concerns are: -#### Rational Use of Label Classification +### Rational Use of Label Classification Reasonably use the label function. For each module code before the use of the log, first clear the module, sub-module name. This also allows the logs to be categorized at the very beginning and ready for later log filtering. -#### Rational Use of Log Levels +### Rational Use of Log Levels When you first use the log library, you will often encounter warnings and errors. The logs cannot be distinguished. The information cannot be distinguished from the debug logs, which makes the log level selection inappropriate. Some important logs may not be visible, and unimportant logs are full of problems. Therefore, be sure to read the log level section carefully before using it. For each level, there are clear standards. -#### Avoid Repetitive and Redundant Logs +### Avoid Repetitive and Redundant Logs In some cases, repeated or cyclic execution of code occurs, and the same, similar log problems are output multiple times. Such a log not only takes up a lot of system resources, but also affects the developer's positioning of the problem. Therefore, in this case, it is recommended to add special processing for repetitive logs, such as: let the upper layer output some business-related logs, the bottom layer only returns the specific result status; the same log at the same time point, can increase to deal with the re-processing, only output once and so on when the error state has not changed. -#### Open More Log Formats +### Open More Log Formats The timestamp and thread information are not turned on in the default log format of ulog. These two log messages are useful on RTOS. They can help developers to understand the running time and time difference of each log, and clearly see which thread is executing the current code. So if conditions permit, it is still recommended to open. -#### Close Unimportant Logs +### Close Unimportant Logs Ulog provides log switch and filtering functions in various dimensions, which can completely control the refinement. Therefore, if you debug a function module, you can properly close the log output of other unrelated modules, so that you can focus on the current debugging on the module. -## Common Problems +# Common Problems -### Q: The log code has been executed, but there is no output. +## Q: The log code has been executed, but there is no output. **A:** Refer to the Log Levels section for the log level classification and check the log filtering parameters. There is also the possibility of accidentally closing the console backend and re-opening `Enable console backend`. -### Q: After ulog is turned on, the system crashes, for example: thread stack overflow. +## Q: After ulog is turned on, the system crashes, for example: thread stack overflow. **A:** Ulog will occupy more part of the thread stack space than the previous rtdbg or `rt_kprintf` printout function. If floating-point printing support is enabled, it is recommended because it uses the internal memory of libc with a large amount of `vsnprintf`. Reserve more than 250 bytes. If the timestamp function is turned on, the stack recommends a reserve of 100 bytes. -### Q: The end of the log content is missing. +## Q: The end of the log content is missing. **A:** This is because the log content exceeds the maximum width of the set log. Check the `The log's max width` option and increase it to the appropriate size. -### Q: After turning on the timestamp, why can't I see the millisecond time? +## Q: After turning on the timestamp, why can't I see the millisecond time? **A:** This is because ulog currently only supports millisecond timestamps when the software emulation RTC state is turned on. To display, just turn on the RT-Thread software to simulate the RTC function. -### Q: Define LOG_TAG and LOG_LVL before each include ulog header file, can it be simplified? +## Q: Define LOG_TAG and LOG_LVL before each include ulog header file, can it be simplified? **A:** If `LOG_TAG` is not defined, the `NO_TAG` tag will be used by default, so the output log will be easily misunderstood. Therefore the tag macro is not recommended to be omitted. If `LOG_LVL` is not defined, the debug level is used by default. If the module is in the development stage, this process can be omitted, but if the module code is stable, it is recommended to define the macro and modify the level to information level. -### Q: Warning when running:Warning: There is no enough buffer for saving async log, please increase the ULOG_ASYNC_OUTPUT_BUF_SIZE option。 +## Q: Warning when running:Warning: There is no enough buffer for saving async log, please increase the ULOG_ASYNC_OUTPUT_BUF_SIZE option。 **A:** When this prompt is encountered, it indicates that the buffer in the asynchronous mode has overflowed, which will cause some of the log to be lost. Increasing the ULOG_ASYNC_OUTPUT_BUF_SIZE option can solve the problem. -### Q: Compile time prompt:The idle thread stack size must more than 384 when using async output by idle (ULOG_ASYNC_OUTPUT_BY_IDLE)。 +## Q: Compile time prompt:The idle thread stack size must more than 384 when using async output by idle (ULOG_ASYNC_OUTPUT_BY_IDLE)。 **A:** When using an idle thread as the output thread, the stack size of the idle thread needs to be increased, depending on the specific backend device. For example, when the console being a backend, the idle thread must be at least 384 bytes. diff --git a/documentation/utest/utest.md b/documentation/utest/utest.md index d496fbed07..708a1d1893 100644 --- a/documentation/utest/utest.md +++ b/documentation/utest/utest.md @@ -1,10 +1,10 @@ -# utest Framework +@page component_utest utest Framework -## utest Introduction +# utest Introduction utest (unit test) is a unit testing framework developed by RT-Thread. The original intention of designing utest is to make it easier for RT-Thread developers to write test programs using a unified framework interface for unit testing, coverage testing, and integration testing. -### Test Case Definition +## Test Case Definition A test case (tc) is a single test performed to achieve a specific test objective. It is a specification that includes test input, execution conditions, test procedures, and expected results. It is a infinite loop with clear end conditions and test results. @@ -12,21 +12,21 @@ The utest (unit test) framework defines user-written test programs as **test cas The test code for a function, specifically through the API provided by the utest framework, is a test case. -### Test Unit Definition +## Test Unit Definition The test unit is a test point subdivided by the function to be tested. Each test point can be the smallest measurable unit of the function to be tested. Of course, different classification methods will subdivide different test units. -### utest Application Block Diagram +## utest Application Block Diagram ![utest Application Block Diagram](./figures/UtestAppStruct-1.png) As shown in the figure above, the test case is designed based on the service interface provided by the test framework utest, which supports compiling multiple test cases together for testing. In addition, as you can see from the figure, a test case corresponds to a unique *testcase* function, and multiple test units are included in *testcase*. -## utest API +# utest API To enable uniform test case code, the test framework utest provides a common API interface for test case writing. -### Macros of assertion +## Macros of assertion > NOTE: > Here assert only records the number of passes and failures, it does not generate assertions or terminates program execution. Its function is not equivalent to RT_ASSERT. @@ -45,7 +45,7 @@ To enable uniform test case code, the test framework utest provides a common API | uassert_in_range(value, min, max) | If the value is in the range of min and max, the test passes, otherwise the test fails. | | uassert_not_in_range(value, min, max)| If the value is not in the range of min and max, the test passes, otherwise the test fails. | -### Macros for Running Test Units +## Macros for Running Test Units ```c UTEST_UNIT_RUN(test_unit_func) @@ -53,7 +53,7 @@ UTEST_UNIT_RUN(test_unit_func) In the test case, the specified test unit function `test_unit_func` is executed using the `UTEST_UNIT_RUN` macro. The test unit must be executed using the `UTEST_UNIT_RUN` macro. -### Macros for Exporting Test Cases +## Macros for Exporting Test Cases ```c UTEST_TC_EXPORT(testcase, name, init, cleanup, timeout) @@ -75,7 +75,7 @@ Test cases need to be named in the prescribed format. Specifies the naming forma Assuming that there is a `testcases\components\filesystem\dfs\dfs_api_tc.c` test case file in the test case `testcases` directory, the test case name in the `dfs_api_tc.c` is named `components.filesystem.dfs.dfs_api_tc`. -### Test Case LOG Output Interface +## Test Case LOG Output Interface The utest framework relies on the *ulog log module* for log output and the log output level in the utest framework. So just add `#include "utest.h"` to the test case to use all level interfaces (LOG_D/LOG_I/LOG_E) of the ulog log module. @@ -90,7 +90,7 @@ void utest_log_lv_set(rt_uint8_t lv); Users can use the `utest_log_lv_set` interface to control the log output level in test cases. The `UTEST_LOG_ALL` configuration outputs all logs, and the `UTEST_LOG_ASSERT` configuration only outputs logs after the failure of uassert. -## Configuration Enable +# Configuration Enable Using the utest framework requires the following configuration in the ENV tool using menuconfig: @@ -105,7 +105,7 @@ RT-Thread Components ---> (20) The utest thread priority /* Set utest thread priority (required for -thread mode) */ ``` -## Application Paradigm +# Application Paradigm The utest framework and related APIs were introduced earlier. The basic test case code structure is described here. @@ -185,7 +185,7 @@ A basic test case must contain the following: Export the test case testcase function to the test framework. -## Requirements for running test cases +# Requirements for running test cases The test framework utest exports all test cases to the `UtestTcTab` code segment. The `UtestTcTab` section is not required to be defined in the link script in the IAR and MDK compilers, but it needs to be explicitly set in the link script when GCC is compiled. @@ -201,7 +201,7 @@ KEEP(*(UtestTcTab)) __rt_utest_tc_tab_end = .; ``` -## Running Test Cases +# Running Test Cases The test framework provides the following commands to make it easy for users to run test cases on the RT-Thread MSH command line. The commands are as follows: @@ -250,13 +250,13 @@ msh />utest_run components.filesystem.dfs.dfs_api_tc msh /> ``` -### Test result analysis +## Test result analysis ![utest log display](./figures/UtestRunLogShow.png) As shown in the figure above, the log of the test case run is divided into four columns from left to right, which are `(1) log header information`, `(2) result bar`, `(3) property bar`, and `(4) detail information display bar`. The test case test result (PASSED or FAILED) is identified in the log using the `result` attribute. -## Test Case Run Process +# Test Case Run Process ![Test Case Run Process](./figures/testcase-runflowchart.jpg) @@ -265,7 +265,7 @@ From the above flow chart you can get the following: * The utest framework is a sequential execution of all **test units** in the *testcase* function * Assert of the previous UTEST_UNIT_RUN macro has occurred, and all subsequent UTEST_UNIT_RUN will skip execution. -## NOTE +# NOTE - Determine whether the link script has the `UtestTcTab` section added before compiling with GCC. - Make sure `RT-Thread Kernel -> Kernel Device Object -> (256) the buffer size for console log printf` is at least 256 bytes before compiling.