├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── Component ├── README.md └── RTT │ ├── SEGGER_RTT.c │ ├── SEGGER_RTT.h │ ├── SEGGER_RTT_ASM_ARMv7M.S │ ├── SEGGER_RTT_Conf.h │ └── SEGGER_RTT_printf.c ├── DAL ├── README.md └── dal_opt.c ├── LICENSE ├── Plugin └── clang-format │ ├── README.md │ └── clang-format.exe ├── Protocol ├── README.md └── modbus │ ├── modbus_master.c │ └── modbus_slave.c ├── README.md ├── commit_template.txt ├── core ├── lib │ ├── align_mm.c │ └── bget.c ├── virtual_os.ld ├── virtual_os_mm.c └── virtual_os_run.c ├── docs ├── CAN │ ├── README.md │ └── image.png ├── Shell │ └── README.md ├── config_btn │ ├── README.md │ └── image.png ├── config_log │ ├── README.md │ └── image.png ├── driver │ └── README.md ├── eeprom │ ├── README.md │ └── image.png ├── modbus │ ├── master │ │ ├── README.md │ │ ├── image-1.png │ │ └── image.png │ ├── self_protocol.md │ └── slave │ │ ├── README.md │ │ ├── image-1.png │ │ └── image.png └── new_project │ ├── README.md │ ├── image-1.png │ ├── image-2.png │ ├── image-3.png │ ├── image-4.png │ ├── image-5.png │ ├── image-6.png │ ├── image-7.png │ ├── image-8.png │ ├── image-9.png │ └── image.png ├── driver ├── virtual_os_driver.c └── virtual_os_sh_drv.c ├── include ├── bus │ ├── can_bus.h │ └── iic_bus.h ├── core │ ├── lib │ │ ├── align_mm.h │ │ └── bget.h │ ├── virtual_os_config.h │ ├── virtual_os_defines.h │ ├── virtual_os_mm.h │ └── virtual_os_run.h ├── dal │ └── dal_opt.h ├── driver │ └── virtual_os_driver.h ├── protocol │ └── modbus │ │ ├── modbus.h │ │ ├── modbus_master.h │ │ └── modbus_slave.h └── utils │ ├── button.h │ ├── crc.h │ ├── h_tree.h │ ├── list.h │ ├── log.h │ ├── qfsm.h │ ├── queue.h │ ├── simple_shell.h │ ├── soft_iic.h │ ├── stimer.h │ └── string_hash.h ├── toolchain.cmake ├── utils ├── README.md ├── button.c ├── crc.c ├── h_tree.c ├── list.c ├── log.c ├── qfsm.c ├── queue.c ├── simple_shell.c ├── soft_iic.c ├── stimer.c └── string_hash.c └── virtual_os_src.cmake /.clang-format: -------------------------------------------------------------------------------- 1 | # 缩进设置 2 | UseTab: Always # 使用制表符进行缩进 3 | IndentWidth: 4 # 缩进宽度为 4 4 | TabWidth: 4 # 一个制表符等于 4 个空格 5 | ContinuationIndentWidth: 4 # 换行续行缩进为 4 6 | IndentCaseLabels: false # 不缩进 switch 语句的 case 标签 7 | 8 | # 行宽限制 9 | ColumnLimit: 120 # 每行最多 80 个字符 10 | 11 | # 大括号样式 12 | BreakBeforeBraces: Linux # 使用 Linux 风格的大括号位置 13 | 14 | # 空格设置 15 | SpaceBeforeParens: ControlStatements # 在控制语句的括号前添加空格 16 | SpaceAfterCStyleCast: false # C 风格的强制类型转换后不加空格 17 | SpaceBeforeAssignmentOperators: true # 赋值操作符前后添加空格 18 | SpaceAroundPointerQualifiers: Before # 指针限定符前添加空格 19 | 20 | # 指针和引用对齐 21 | DerivePointerAlignment: false 22 | PointerAlignment: Right # 指针和引用符号与变量名对齐 23 | 24 | # 预处理器指令 25 | IndentPPDirectives: None # 不缩进预处理器指令 26 | 27 | # 标签和 goto 28 | IndentGotoLabels: false # 标签不缩进,置于行首 29 | 30 | # 注释设置 31 | ReflowComments: false # 不重新格式化注释 32 | 33 | # 空行设置 34 | KeepEmptyLinesAtTheStartOfBlocks: false # 代码块开头不保留空行 35 | 36 | # 短函数设置 37 | AllowShortFunctionsOnASingleLine: None # 不允许将短函数写在一行 38 | 39 | # 头文件排序 40 | SortIncludes: false # 不自动排序头文件 41 | 42 | # 对齐设置 43 | AlignTrailingComments: true # 对齐尾随注释 44 | AlignConsecutiveAssignments: false # 不对齐连续的赋值语句 45 | AlignOperands: false # 不对齐操作数 46 | AlignAfterOpenBracket: DontAlign # 括号内不对齐 47 | 48 | # 字符串字面量 49 | BreakStringLiterals: false # 不拆分字符串字面量 50 | 51 | # 大括号包裹设置 52 | BraceWrapping: 53 | AfterClass: false 54 | AfterControlStatement: false 55 | AfterEnum: false 56 | AfterFunction: false 57 | AfterNamespace: false 58 | AfterStruct: false 59 | AfterUnion: false 60 | BeforeCatch: false 61 | BeforeElse: false 62 | IndentBraces: false 63 | SplitEmptyFunction: false 64 | SplitEmptyRecord: false 65 | SplitEmptyNamespace: false 66 | 67 | # 宏定义 68 | StatementMacros: [] 69 | 70 | # 惩罚参数 71 | PenaltyBreakComment: 300 72 | PenaltyBreakFirstLessLess: 120 73 | PenaltyBreakString: 1000 74 | PenaltyExcessCharacter: 1000000 75 | PenaltyReturnTypeOnItsOwnLine: 200 76 | 77 | # 函数名换行缩进 78 | IndentWrappedFunctionNames: false 79 | 80 | # 保留的空行数 81 | MaxEmptyLinesToKeep: 1 82 | 83 | # 命名空间缩进(对 C 无影响,但设置为 None) 84 | NamespaceIndentation: None 85 | 86 | # 访问修饰符缩进(对 C 无影响,但设置为 -8) 87 | AccessModifierOffset: -8 88 | 89 | # 参数和声明换行设置 90 | AllowAllParametersOfDeclarationOnNextLine: false 91 | 92 | # 单行控制语句 93 | AllowShortIfStatementsOnASingleLine: false 94 | AllowShortLoopsOnASingleLine: false 95 | 96 | # 返回类型换行 97 | AlwaysBreakAfterReturnType: None 98 | 99 | # C++11 花括号列表(对 C 无影响,但设置为 false) 100 | Cpp11BracedListStyle: false 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Static libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared Object files 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | *.axf 31 | 32 | # Linker output 33 | *.ilk 34 | *.map 35 | *.exp 36 | 37 | # Debug files 38 | *.dSYM/ 39 | *.su 40 | *.idb 41 | *.pdb 42 | *.dbg* 43 | 44 | # Kernel Module Compile Results 45 | *.mod* 46 | *.cmd 47 | .tmp_versions/ 48 | modules.order 49 | Module.symvers 50 | Mkfile.old 51 | dkms.conf 52 | 53 | # Archive files 54 | *.rar 55 | 56 | *.d 57 | *.yml 58 | *.json 59 | 60 | # Other file formats 61 | *.crf 62 | *.htm 63 | *.dep 64 | *.bak 65 | *.lnp 66 | *.lst 67 | *.ini 68 | *.iex 69 | *.sct 70 | *.scvd 71 | *.uvguix* 72 | *.mxproject 73 | *.pyc 74 | *.dblite 75 | *.bin 76 | *.old 77 | *.orig 78 | *.uimg 79 | 80 | # Miscellaneous 81 | *~ 82 | .DS_Store 83 | .config 3 84 | .config 4 85 | .config 5 86 | Midea-X1 87 | GPATH 88 | GRTAGS 89 | GTAGS 90 | JLinkLog.txt 91 | JLinkSettings.ini 92 | cconfig.h 93 | 94 | # Folders to ignore 95 | build/ 96 | Debug/ 97 | OBJ/ 98 | documentation/html/ 99 | packages/ 100 | DebugConfig/ 101 | RTE/ 102 | settings/ 103 | .vscode/ 104 | Templates/ 105 | Examples/ 106 | output/ 107 | out/ 108 | tmp/ 109 | virtualos_install/ 110 | 111 | *.clangd 112 | *.log 113 | *.cprj 114 | 115 | # Ignore all .map files except in the root directory 116 | /**/*.map 117 | 118 | # Special files to never ignore 119 | !.gitignore 120 | !*.uvprojx 121 | !*.h 122 | !*.c 123 | 124 | # Note: Adjust paths as necessary for your project structure 125 | *.code-workspace 126 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | 3 | project(VirtualOS C ASM) 4 | 5 | set(CMAKE_SYSTEM_NAME Generic) 6 | set(CMAKE_C_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD 11) 8 | set(CMAKE_C_STANDARD_REQUIRED ON) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_LIST_DIR}/virtualos_install) 12 | 13 | if(CMAKE_BUILD_TYPE MATCHES Debug) 14 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g3") 15 | elseif(CMAKE_BUILD_TYPE MATCHES Release) 16 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Os -g3") 17 | endif() 18 | 19 | file(GLOB_RECURSE VIRTUALOS_SOURCES 20 | ${CMAKE_CURRENT_LIST_DIR}/component/RTT/*.c 21 | ${CMAKE_CURRENT_LIST_DIR}/dal/*.c 22 | ${CMAKE_CURRENT_LIST_DIR}/core/*.c 23 | ${CMAKE_CURRENT_LIST_DIR}/protocol/modbus/*.c 24 | ${CMAKE_CURRENT_LIST_DIR}/utils/*.c 25 | ${CMAKE_CURRENT_LIST_DIR}/driver/*.c 26 | ) 27 | 28 | add_library(VirtualOS STATIC ${VIRTUALOS_SOURCES}) 29 | target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILER_FLAGS}) 30 | 31 | target_include_directories(VirtualOS PUBLIC 32 | ${CMAKE_CURRENT_LIST_DIR}/include 33 | ${CMAKE_CURRENT_LIST_DIR}/component/RTT/ 34 | ) 35 | 36 | install( 37 | TARGETS VirtualOS 38 | ARCHIVE DESTINATION lib 39 | ) 40 | 41 | install( 42 | DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/ 43 | DESTINATION include 44 | ) 45 | 46 | install( 47 | DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/component/RTT/ 48 | DESTINATION include/component/RTT 49 | FILES_MATCHING PATTERN "*.h" 50 | ) 51 | 52 | install( 53 | FILES ${CMAKE_CURRENT_LIST_DIR}/core/virtual_os.ld 54 | DESTINATION ldscript 55 | ) 56 | 57 | # rm -rf build;rm -rf virtualos_install;cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake;cmake --build build --target install; -------------------------------------------------------------------------------- /Component/README.md: -------------------------------------------------------------------------------- 1 | # component (组件) 2 | 3 | - 一些开源组件 4 | 5 | ## FAL 6 | - RT-Thread的FLASH抽象层 7 | 8 | ## FlashDB 9 | - FLASH存储组件,以Key-Value键值对的形式存储数据 10 | 11 | ## LittleFS 12 | - 文件系统 13 | 14 | ## RTT 15 | - Jlink的相关组件 16 | 17 | 18 | ### 注意 19 | 如需使用组件,请在具体工程的CmakeLists.txt文件中自行导入源文件.相关头文件,本框架的Virtual.cmake已经导入 -------------------------------------------------------------------------------- /Component/RTT/SEGGER_RTT_ASM_ARMv7M.S: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * (c) SEGGER Microcontroller GmbH * 3 | * The Embedded Experts * 4 | * www.segger.com * 5 | ********************************************************************** 6 | 7 | -------------------------- END-OF-HEADER ----------------------------- 8 | 9 | File : SEGGER_RTT_ASM_ARMv7M.S 10 | Purpose : Assembler implementation of RTT functions for ARMv7M 11 | 12 | Additional information: 13 | This module is written to be assembler-independent and works with 14 | GCC and clang (Embedded Studio) and IAR. 15 | */ 16 | 17 | #define SEGGER_RTT_ASM // Used to control processed input from header file 18 | #include "SEGGER_RTT.h" 19 | 20 | /********************************************************************* 21 | * 22 | * Defines, fixed 23 | * 24 | ********************************************************************** 25 | */ 26 | 27 | #define _CCIAR 0 28 | #define _CCCLANG 1 29 | 30 | #if (defined __SES_ARM) || (defined __GNUC__) || (defined __clang__) 31 | #define _CC_TYPE _CCCLANG 32 | #define _PUB_SYM .global 33 | #define _EXT_SYM .extern 34 | #define _END .end 35 | #define _WEAK .weak 36 | #define _THUMB_FUNC .thumb_func 37 | #define _THUMB_CODE .code 16 38 | #define _WORD .word 39 | #define _SECTION(Sect, Type, AlignExp) .section Sect ##, "ax" 40 | #define _ALIGN(Exp) .align Exp 41 | #define _PLACE_LITS .ltorg 42 | #define _DATA_SECT_START 43 | #define _C_STARTUP _start 44 | #define _STACK_END __stack_end__ 45 | #define _RAMFUNC 46 | // 47 | // .text => Link to flash 48 | // .fast => Link to RAM 49 | // OtherSect => Usually link to RAM 50 | // Alignment is 2^x 51 | // 52 | #elif defined (__IASMARM__) 53 | #define _CC_TYPE _CCIAR 54 | #define _PUB_SYM PUBLIC 55 | #define _EXT_SYM EXTERN 56 | #define _END END 57 | #define _WEAK _WEAK 58 | #define _THUMB_FUNC 59 | #define _THUMB_CODE THUMB 60 | #define _WORD DCD 61 | #define _SECTION(Sect, Type, AlignExp) SECTION Sect ## : ## Type ## :REORDER:NOROOT ## (AlignExp) 62 | #define _ALIGN(Exp) alignrom Exp 63 | #define _PLACE_LITS 64 | #define _DATA_SECT_START DATA 65 | #define _C_STARTUP __iar_program_start 66 | #define _STACK_END sfe(CSTACK) 67 | #define _RAMFUNC SECTION_TYPE SHT_PROGBITS, SHF_WRITE | SHF_EXECINSTR 68 | // 69 | // .text => Link to flash 70 | // .textrw => Link to RAM 71 | // OtherSect => Usually link to RAM 72 | // NOROOT => Allows linker to throw away the function, if not referenced 73 | // Alignment is 2^x 74 | // 75 | #endif 76 | 77 | #if (_CC_TYPE == _CCIAR) 78 | NAME SEGGER_RTT_ASM_ARMv7M 79 | #else 80 | .syntax unified 81 | #endif 82 | 83 | #if defined (RTT_USE_ASM) && (RTT_USE_ASM == 1) 84 | #define SHT_PROGBITS 0x1 85 | 86 | /********************************************************************* 87 | * 88 | * Public / external symbols 89 | * 90 | ********************************************************************** 91 | */ 92 | 93 | _EXT_SYM __aeabi_memcpy 94 | _EXT_SYM __aeabi_memcpy4 95 | _EXT_SYM _SEGGER_RTT 96 | 97 | _PUB_SYM SEGGER_RTT_ASM_WriteSkipNoLock 98 | 99 | /********************************************************************* 100 | * 101 | * SEGGER_RTT_WriteSkipNoLock 102 | * 103 | * Function description 104 | * Stores a specified number of characters in SEGGER RTT 105 | * control block which is then read by the host. 106 | * SEGGER_RTT_WriteSkipNoLock does not lock the application and 107 | * skips all data, if the data does not fit into the buffer. 108 | * 109 | * Parameters 110 | * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). 111 | * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. 112 | * NumBytes Number of bytes to be stored in the SEGGER RTT control block. 113 | * MUST be > 0!!! 114 | * This is done for performance reasons, so no initial check has do be done. 115 | * 116 | * Return value 117 | * 1: Data has been copied 118 | * 0: No space, data has not been copied 119 | * 120 | * Notes 121 | * (1) If there is not enough space in the "Up"-buffer, all data is dropped. 122 | * (2) For performance reasons this function does not call Init() 123 | * and may only be called after RTT has been initialized. 124 | * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. 125 | */ 126 | _SECTION(.text, CODE, 2) 127 | _ALIGN(2) 128 | _THUMB_FUNC 129 | SEGGER_RTT_ASM_WriteSkipNoLock: // unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pData, unsigned NumBytes) { 130 | // 131 | // Cases: 132 | // 1) RdOff <= WrOff => Space until wrap-around is sufficient 133 | // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks) 134 | // 3) RdOff < WrOff => No space in buf 135 | // 4) RdOff > WrOff => Space is sufficient 136 | // 5) RdOff > WrOff => No space in buf 137 | // 138 | // 1) is the most common case for large buffers and assuming that J-Link reads the data fast enough 139 | // 140 | // Register usage: 141 | // R0 Temporary needed as RdOff, register later on 142 | // R1 pData 143 | // R2 144 | // R3 register. Hold free for subroutine calls 145 | // R4 146 | // R5 pRing->pBuffer 147 | // R6 pRing (Points to active struct SEGGER_RTT_BUFFER_DOWN) 148 | // R7 WrOff 149 | // 150 | PUSH {R4-R7} 151 | ADD R3,R0,R0, LSL #+1 152 | LDR.W R0,=_SEGGER_RTT // pRing = &_SEGGER_RTT.aUp[BufferIndex]; 153 | ADD R0,R0,R3, LSL #+3 154 | ADD R6,R0,#+24 155 | LDR R0,[R6, #+16] // RdOff = pRing->RdOff; 156 | LDR R7,[R6, #+12] // WrOff = pRing->WrOff; 157 | LDR R5,[R6, #+4] // pRing->pBuffer 158 | CMP R7,R0 159 | BCC.N _CheckCase4 // if (RdOff <= WrOff) { => Case 1), 2) or 3) 160 | // 161 | // Handling for case 1, later on identical to case 4 162 | // 163 | LDR R3,[R6, #+8] // Avail = pRing->SizeOfBuffer - WrOff - 1u; => Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) 164 | SUBS R4,R3,R7 // (Used in case we jump into case 2 afterwards) 165 | SUBS R3,R4,#+1 // 166 | CMP R3,R2 167 | BCC.N _CheckCase2 // if (Avail >= NumBytes) { => Case 1)? 168 | _Case4: 169 | ADDS R5,R7,R5 // pBuffer += WrOff 170 | ADDS R0,R2,R7 // v = WrOff + NumBytes 171 | // 172 | // 2x unrolling for the copy loop that is used most of the time 173 | // This is a special optimization for small SystemView packets and makes them even faster 174 | // 175 | _ALIGN(2) 176 | _LoopCopyStraight: // memcpy(pRing->pBuffer + WrOff, pData, NumBytes); 177 | LDRB R3,[R1], #+1 178 | STRB R3,[R5], #+1 // *pDest++ = *pSrc++ 179 | SUBS R2,R2,#+1 180 | BEQ _CSDone 181 | LDRB R3,[R1], #+1 182 | STRB R3,[R5], #+1 // *pDest++ = *pSrc++ 183 | SUBS R2,R2,#+1 184 | BNE _LoopCopyStraight 185 | _CSDone: 186 | #if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here 187 | DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct 188 | #endif 189 | STR R0,[R6, #+12] // pRing->WrOff = WrOff + NumBytes; 190 | MOVS R0,#+1 191 | POP {R4-R7} 192 | BX LR // Return 1 193 | _CheckCase2: 194 | ADDS R0,R0,R3 // Avail += RdOff; => Space incl. wrap-around 195 | CMP R0,R2 196 | BCC.N _Case3 // if (Avail >= NumBytes) { => Case 2? => If not, we have case 3) (does not fit) 197 | // 198 | // Handling for case 2 199 | // 200 | ADDS R0,R7,R5 // v = pRing->pBuffer + WrOff => Do not change pRing->pBuffer here because 2nd chunk needs org. value 201 | SUBS R2,R2,R4 // NumBytes -= Rem; (Rem = pRing->SizeOfBuffer - WrOff; => Space until end of buffer) 202 | _LoopCopyBeforeWrapAround: // memcpy(pRing->pBuffer + WrOff, pData, Rem); => Copy 1st chunk 203 | LDRB R3,[R1], #+1 204 | STRB R3,[R0], #+1 // *pDest++ = *pSrc++ 205 | SUBS R4,R4,#+1 206 | BNE _LoopCopyBeforeWrapAround 207 | // 208 | // Special case: First check that assumed RdOff == 0 calculated that last element before wrap-around could not be used 209 | // But 2nd check (considering space until wrap-around and until RdOff) revealed that RdOff is not 0, so we can use the last element 210 | // In this case, we may use a copy straight until buffer end anyway without needing to copy 2 chunks 211 | // Therefore, check if 2nd memcpy is necessary at all 212 | // 213 | ADDS R4,R2,#+0 // Save (needed as counter in loop but must be written to after the loop). Also use this inst to update the flags to skip 2nd loop if possible 214 | BEQ.N _No2ChunkNeeded // if (NumBytes) { 215 | _LoopCopyAfterWrapAround: // memcpy(pRing->pBuffer, pData + Rem, NumBytes); 216 | LDRB R3,[R1], #+1 // pData already points to the next src byte due to copy loop increment before this loop 217 | STRB R3,[R5], #+1 // *pDest++ = *pSrc++ 218 | SUBS R2,R2,#+1 219 | BNE _LoopCopyAfterWrapAround 220 | _No2ChunkNeeded: 221 | #if _CORE_NEEDS_DMB // Do not slow down cores that do not need a DMB instruction here 222 | DMB // Cortex-M7 may delay memory writes and also change the order in which the writes happen. Therefore, make sure that all buffer writes are finished, before updating the in the struct 223 | #endif 224 | STR R4,[R6, #+12] // pRing->WrOff = NumBytes; => Must be written after copying data because J-Link may read control block asynchronously while writing into buffer 225 | MOVS R0,#+1 226 | POP {R4-R7} 227 | BX LR // Return 1 228 | _CheckCase4: 229 | SUBS R0,R0,R7 230 | SUBS R0,R0,#+1 // Avail = RdOff - WrOff - 1u; 231 | CMP R0,R2 232 | BCS.N _Case4 // if (Avail >= NumBytes) { => Case 4) == 1) ? => If not, we have case 5) == 3) (does not fit) 233 | _Case3: 234 | MOVS R0,#+0 235 | POP {R4-R7} 236 | BX LR // Return 0 237 | _PLACE_LITS 238 | 239 | #endif // defined (RTT_USE_ASM) && (RTT_USE_ASM == 1) 240 | _END 241 | 242 | /*************************** End of file ****************************/ 243 | -------------------------------------------------------------------------------- /DAL/README.md: -------------------------------------------------------------------------------- 1 | # 设备抽象层 (Device Abstraction Layer) 2 | 3 | 设备抽象层(dal,Device Abstraction Layer)是一个用于封装底层设备访问的接口层。它为应用层提供了一组统一的设备操作接口,使得应用层可以直接调用相关的读写等操作,而不需要关心底层设备的具体实现。 4 | 5 | ## 接口概述 6 | 7 | 设备抽象层提供了以下主要功能: 8 | 9 | - **设备打开和关闭**:允许应用程序打开和关闭设备。 10 | - **设备读写**:提供读取和写入设备数据的接口。 11 | - **文件偏移**:支持文件指针的定位和调整。适用于FLASH等设备 12 | 13 | ## 接口函数 14 | 15 | ### 错误码说明 16 | 17 | 以下是此文件定义的错误码: 18 | 19 | - `-6`:设备不存在。 20 | - `-5`:设备被占用。 21 | - `-4`:操作异常(例如对只读设备执行写操作)。 22 | - `-3`:设备不可使用(例如设备未打开)。 23 | - `-2`:打开设备过多。 24 | - `-1`:无效参数。 25 | - `0`:无错误。 26 | 27 | ### `int dal_open(const char *dev_name);` 28 | 29 | 打开指定的设备,并返回设备文件描述符 30 | 31 | **参数:** 32 | 33 | - `dev_name`:设备名称的字符串。 34 | 35 | **返回值:** 36 | 37 | - 文件描述符有效值为3-63,0-2为框架保留值,大于等于64为无效值。 38 | - 失败时返回错误码(<0) 39 | 40 | ### `int dal_close(int fd);` 41 | 42 | 关闭指定的设备文件描述符。 43 | 44 | **参数:** 45 | 46 | - `fd`:要关闭的文件描述符。 47 | 48 | **返回值:** 49 | 50 | - 成功时返回 0。 51 | - 失败时返回错误码(<0),参考错误码说明。 52 | 53 | ### `int dal_read(int fd, uint8_t *buf, size_t len);` 54 | 55 | 从设备中读取数据。 56 | 57 | **参数:** 58 | 59 | - `fd`:设备文件描述符。 60 | - `buf`:存储读取数据的缓冲区指针。 61 | - `len`:要读取的数据长度。 62 | 63 | **返回值:** 64 | 65 | - 成功时返回读取的数据长度(>=0)。 66 | - 失败时返回错误码(<0),参考错误码说明。 67 | 68 | ### `int dal_write(int fd, const uint8_t *buf, size_t len);` 69 | 70 | 向设备中写入数据。 71 | 72 | **参数:** 73 | 74 | - `fd`:设备文件描述符。 75 | - `buf`:要写入的数据缓冲区指针。 76 | - `len`:要写入的数据长度。 77 | 78 | **返回值:** 79 | 80 | - 成功时返回写入的数据长度(>=0)。 81 | - 失败时返回错误码(<0),参考错误码说明。 82 | 83 | ### `int dal_ioctrl(uint8_t fd, int cmd, void *arg);` 84 | 85 | 从设备中读取数据。 86 | 87 | **参数:** 88 | 89 | - `fd`:设备文件描述符。 90 | - `cmd`:指令码 由驱动程序定义。 91 | - `arg`:通用参数指针,由驱动程序定义。 92 | 93 | **返回值:** 94 | 95 | - 成功时返回由驱动程序定义的值。 96 | - 失败时返回错误码(<0),参考错误码说明。 97 | 98 | ### `int dal_lseek(int fd, int offset, enum dal_lseek_whence whence);` 99 | 100 | 设置文件偏移量。 101 | 102 | **参数:** 103 | 104 | - `fd`:设备文件描述符。 105 | - `offset`:相对于 `whence` 的偏移量,可以为正负值。 106 | - `whence`:偏移的基准位置,值可以为: 107 | - `DAL_LSEEK_WHENCE_HEAD`:文件的起始位置。 108 | - `DAL_LSEEK_WHENCE_SET`:当前文件指针的位置。 109 | - `DAL_LSEEK_WHENCE_TAIL`:文件的末尾位置。 110 | 111 | **返回值:** 112 | 113 | - 成功时返回 0。 114 | - 失败时返回错误码(<0),参考错误码说明。 115 | 116 | ## 许可证 117 | 118 | The MIT License (MIT) 119 | 120 | Permission is hereby granted, free of charge, to any person obtaining a copy 121 | of this software and associated documentation files (the "Software"), to deal 122 | in the Software without restriction, including without limitation the rights 123 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 124 | copies of the Software, and to permit persons to whom the Software is 125 | furnished to do so, subject to the following conditions: 126 | 127 | The above copyright notice and this permission notice shall be included in 128 | all copies or substantial portions of the Software. 129 | 130 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 131 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 132 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 133 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 134 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 135 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 136 | THE SOFTWARE. -------------------------------------------------------------------------------- /DAL/dal_opt.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @dev dal_opt.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 应用接口 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | #include "dal/dal_opt.h" 36 | #include "driver/virtual_os_driver.h" 37 | #include "core/virtual_os_config.h" 38 | 39 | #define FD_MAX_SIZE (VIRTUALOS_MAX_DEV_NUM + RESERVED_FDS) 40 | 41 | struct fd_t { 42 | struct drv_device *dev; 43 | bool is_used; 44 | size_t offset; 45 | }; 46 | 47 | static struct fd_t fds[FD_MAX_SIZE] = { 0 }; 48 | 49 | static int alloc_fd(void) 50 | { 51 | for (uint16_t i = RESERVED_FDS; i < FD_MAX_SIZE; i++) { 52 | if (!fds[i].is_used) { 53 | fds[i].is_used = true; 54 | return i; 55 | } 56 | } 57 | return DAL_ERR_OVERFLOW; 58 | } 59 | 60 | static void free_fd(int fd) 61 | { 62 | if (fd >= RESERVED_FDS && fd < FD_MAX_SIZE) { 63 | fds[fd].is_used = false; 64 | fds[fd].dev = NULL; 65 | } 66 | } 67 | 68 | static int check_fd(int fd, struct drv_device **dev) 69 | { 70 | if (fd < RESERVED_FDS || fd >= FD_MAX_SIZE || !fds[fd].is_used) 71 | return DAL_ERR_INVALID; 72 | 73 | if (!dev) 74 | return DAL_ERR_INVALID; 75 | 76 | *dev = fds[fd].dev; 77 | return DAL_ERR_NONE; 78 | } 79 | 80 | int dal_open(const char *node_name) 81 | { 82 | struct drv_device *dev = find_device(node_name); 83 | if (!dev) 84 | return DAL_ERR_NOT_EXIST; 85 | 86 | int new_fd = alloc_fd(); 87 | if (new_fd == DAL_ERR_OVERFLOW) 88 | return DAL_ERR_OVERFLOW; 89 | 90 | if (!dev->file || !dev->file->opts->open) { 91 | free_fd(new_fd); 92 | return DAL_ERR_EXCEPTION; 93 | } 94 | 95 | int ret = dev->file->opts->open(dev->file); 96 | if (ret != DAL_ERR_NONE) { 97 | free_fd(new_fd); 98 | return ret; 99 | } 100 | 101 | fds[new_fd].dev = dev; 102 | return new_fd; 103 | } 104 | 105 | int dal_close(int fd) 106 | { 107 | struct drv_device *dev; 108 | int err = check_fd(fd, &dev); 109 | if (err != DAL_ERR_NONE) 110 | return err; 111 | 112 | if (!dev->file->opts->close) 113 | return DAL_ERR_EXCEPTION; 114 | 115 | int ret = dev->file->opts->close(dev->file); 116 | if (ret != DAL_ERR_NONE) 117 | return ret; 118 | 119 | free_fd(fd); 120 | return DAL_ERR_NONE; 121 | } 122 | 123 | size_t dal_read(int fd, void *buf, size_t len) 124 | { 125 | struct drv_device *dev; 126 | int err = check_fd(fd, &dev); 127 | if (err != DAL_ERR_NONE) 128 | return err; 129 | 130 | if (!dev->file->opts->read) 131 | return DAL_ERR_EXCEPTION; 132 | 133 | size_t real_len = len; 134 | 135 | // 如果初始化驱动时设置了设备大小,则防止溢出 136 | if (dev->dev_size > 0) 137 | real_len = ((dev->dev_size - dev->offset) < len) ? (dev->dev_size - dev->offset) : len; 138 | 139 | return dev->file->opts->read(dev->file, buf, real_len, &dev->offset); 140 | } 141 | 142 | size_t dal_write(int fd, void *buf, size_t len) 143 | { 144 | struct drv_device *dev; 145 | int err = check_fd(fd, &dev); 146 | if (err != DAL_ERR_NONE) 147 | return err; 148 | 149 | if (!dev->file->opts->write) 150 | return DAL_ERR_EXCEPTION; 151 | 152 | size_t real_len = len; 153 | 154 | // 如果初始化驱动时设置了设备大小,则防止溢出 155 | if (dev->dev_size > 0) 156 | real_len = ((dev->dev_size - dev->offset) < len) ? (dev->dev_size - dev->offset) : len; 157 | 158 | return dev->file->opts->write(dev->file, buf, real_len, &dev->offset); 159 | } 160 | 161 | int dal_ioctl(int fd, int cmd, void *arg) 162 | { 163 | struct drv_device *dev; 164 | int err = check_fd(fd, &dev); 165 | if (err != DAL_ERR_NONE) 166 | return err; 167 | 168 | if (!dev->file->opts->ioctl) 169 | return DAL_ERR_EXCEPTION; 170 | 171 | return dev->file->opts->ioctl(dev->file, cmd, arg); 172 | } 173 | 174 | int dal_lseek(int fd, int offset, enum dal_lseek_whence whence) 175 | { 176 | struct drv_device *dev; 177 | int err = check_fd(fd, &dev); 178 | if (err != DAL_ERR_NONE || dev->dev_size == 0) 179 | return err; 180 | 181 | uint32_t cur_offset = dev->offset; 182 | uint32_t dev_size = dev->dev_size; 183 | uint32_t dest_offset = 0; 184 | 185 | switch (whence) { 186 | case DAL_LSEEK_WHENCE_HEAD: 187 | if (offset < 0) 188 | return DRV_ERR_INVALID; 189 | 190 | dest_offset = (uint32_t)offset; 191 | break; 192 | 193 | case DAL_LSEEK_WHENCE_SET: 194 | dest_offset = cur_offset + offset; 195 | if (dest_offset > dev_size) 196 | return DRV_ERR_INVALID; 197 | break; 198 | 199 | case DAL_LSEEK_WHENCE_TAIL: 200 | dest_offset = dev_size + offset; 201 | if (dest_offset > dev_size) 202 | return DRV_ERR_INVALID; 203 | 204 | break; 205 | 206 | default: 207 | return DRV_ERR_INVALID; 208 | } 209 | 210 | dev->offset = dest_offset; 211 | 212 | return dest_offset; 213 | } 214 | 215 | void dal_init(void) 216 | { 217 | for (uint16_t i = 0; i < FD_MAX_SIZE; i++) { 218 | fds[i].is_used = i < RESERVED_FDS ? true : false; 219 | fds[i].dev = NULL; 220 | } 221 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 VirtualOS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Plugin/clang-format/README.md: -------------------------------------------------------------------------------- 1 | # 插件 (Plugin) 2 | 3 | ## clang-format.exe 4 | 5 | clang-format.exe 是一款开源的 C/C++ 代码格式化工具,它可以自动格式化代码,使其符合代码风格规范。 6 | -------------------------------------------------------------------------------- /Plugin/clang-format/clang-format.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/Plugin/clang-format/clang-format.exe -------------------------------------------------------------------------------- /Protocol/README.md: -------------------------------------------------------------------------------- 1 | # 协议 (protocol) 2 | 3 | ## MODBUS 4 | - ModBus协议 5 | 6 | ## 许可证 7 | 8 | The MIT License (MIT) 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VirtualOS 框架简介(已于2024-12-25日重构) 2 | 3 | VirtualOS 是一个基于前后台调度为核心搭建的裸机嵌入式开发框架,其参考了Linux设备驱动的注册方式,将应用与驱动完全分离,并以异步的方式实现了任务调度机制。在一个完全空工程的情况下,本框架资源使用率约为`8k ROM + 5K RAM`,由于无操作系统,因此称为VirtualOS 4 | 5 | ## 框架介绍 6 | 7 | - **component**:包含了部分开源组件 8 | - **core**: 框架核心启动代码 9 | - **dal**:设备抽象层,提供通用接口,供应用层调用。 10 | - **docs**:框架文档 11 | - **driver** : 驱动的注册与管理 12 | - **include** : 框架所有头文件 13 | - **plugin**:插件 14 | - **protocol**: 协议 15 | - **utils**:框架提供的组件 16 | - **toolchain.cmake**: 交叉编译工具链配置文件 17 | - **Virtual.cmake**: 框架的配置文件,所有的项目都需要包含此文件 18 | 19 | 注: 20 | 21 | 1. 本框架的编译工程使用免费开源工具链armgcc搭配CMake进行编译、下载和调试(如需在 Keil 上应用,请自行配置. 22 | 2. 编译环境配置流程如下(建议将所有下载资源放在一个统一文件夹下管理. 23 | 24 | ## 推荐工具下载和配置 25 | 26 | 1. **下载 CMake 工具** 27 | [CMake 下载页面](https://cmake.org/download/) 28 | 选择 cmake-3.30.0-windows-x86_64.msi(或最新版)下载安装,并将 bin 目录加入系统 Path 环境变量。 29 | 30 | 2. **下载 ARMGCC 交叉编译工具链** 31 | [ARMGCC 下载页面](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads) 32 | 选择 arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi.zip(或最新版)下载安装 33 | 34 | 3. **下载 Ninja** 35 | [Ninja 下载页面](https://github.com/ninja-build/ninja/releases/v1.12.1) 36 | 选择 ninja-win.zip 下载解压,完成后将目录加入系统 Path 环境变量。 37 | 38 | 4. **下载 J-Link 驱动(或Openocd)** 39 | [J-Link 驱动下载页面](https://www.segger.com/downloads/jlink/) 40 | 选择最新版 Windows 平台下的安装软件。 41 | 42 | [OpenOCD 下载界面](https://gnutoolchains.com/arm-eabi/openocd/) 43 | 选择最新版安装,并将Bin目录加入环境变量 44 | 45 | 5. **下载 VSCode** 46 | [VSCode 下载页面](https://code.visualstudio.com/) 47 | 48 | 6. **安装 VSCode 插件** 49 | 在 VSCode 左侧扩展商店里分别下载以下插件: 50 | - C/C++(实现语法检查、代码补全、高亮等功能) 51 | - C/C++ Extension Pack 52 | - Cortex-Debug(调试代码) 53 | 54 | 确保 CMake、Ninja 的 bin 目录都已经加入系统的 Path 环境变量中。 55 | 56 | ## 使用说明(全案例以GD32F303芯片为例) 57 | 58 | 1. [新建工程](./docs/new_project/README.md) 59 | 2. [如何使用日志组件](./docs/config_log/README.md) 60 | 3. [如何使用按键组件](./docs/config_btn/README.md) 61 | 4. [如何使用Modbus协议从机组件](./docs/modbus/slave/README.md) 62 | 5. [如何使用Modbus协议主机组件](./docs/modbus/master/README.md) 63 | 6. [如何编写CAN驱动与应用](./docs/CAN/README.md) 64 | 7. [如何编写存储设备驱动与应用](./docs/eeprom/README.md) 65 | -------------------------------------------------------------------------------- /commit_template.txt: -------------------------------------------------------------------------------- 1 | type(scope): subject 2 | 3 | # type: 提交的类型,如: 4 | # - feat: 新功能 5 | # - fix: 修复Bug 6 | # - docs: 文档变更 7 | # - style: 代码格式修正(如空格、格式化、缺少分号等) 8 | # - refactor: 代码重构(既不修复错误也不添加新功能) 9 | # - test: 添加或修改测试 10 | # - chore: 构建过程或辅助工具的变动, 修改注释等 11 | 12 | # scope: 影响的模块或文件,可以是文件名、模块名或功能名 13 | 14 | # subject: 对此次提交内容的简短描述,建议不超过50个字符 15 | 16 | 详细描述内容 17 | 18 | # 更详细地描述此次提交的内容,可以换行继续描述 19 | 20 | 影响的文件或模块列表 21 | 22 | # 列出所有受此次提交影响的文件或模块,一行一个 23 | -------------------------------------------------------------------------------- /core/lib/align_mm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file align_mm.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 对齐内存接口 5 | * @version 1.0 6 | * @date 2025-03-18 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include "core/lib/align_mm.h" 35 | 36 | #define IS_POWER_OF_TWO(align) ((align) != 0 && ((align) & ((align) - 1)) == 0) 37 | #define EXTRA_MEMORY(size, align) ((size) + (align) - 1 + sizeof(void *)) 38 | #define ALIGN_UP(ptr, align) ((void *)(((size_t)(ptr) + (align) - 1 + sizeof(void *)) & ~((align) - 1))) 39 | 40 | /** 41 | * @brief 内存对齐分配 42 | * 43 | * @param size 申请大小 44 | * @param align 对齐大小 45 | * @return void* 对齐后的指针,失败返回NULL 46 | */ 47 | void *aligned_malloc(size_t size, size_t align) 48 | { 49 | if (!IS_POWER_OF_TWO(align) || align < sizeof(void *)) 50 | return NULL; 51 | 52 | if (size == 0) 53 | return NULL; 54 | 55 | size_t alloc_size = EXTRA_MEMORY(size, align); 56 | void *ptr = malloc(alloc_size); 57 | if (ptr == NULL) 58 | return NULL; 59 | 60 | void *aligned_ptr = ALIGN_UP(ptr, align); 61 | ((void **)aligned_ptr)[-1] = ptr; 62 | 63 | return aligned_ptr; 64 | } 65 | 66 | /** 67 | * @brief 内存对齐释放 68 | * 69 | * @param ptr 通过aligned_malloc申请的指针 70 | */ 71 | void aligned_free(void *ptr) 72 | { 73 | if (ptr == NULL) 74 | return; 75 | 76 | if (((size_t)ptr & (sizeof(void *) - 1)) != 0) 77 | return; 78 | 79 | void *real_ptr = ((void **)ptr)[-1]; 80 | free(real_ptr); 81 | } -------------------------------------------------------------------------------- /core/virtual_os.ld: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os.ld 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief VirtualOS的链接脚本 5 | * @version 1.0 6 | * @date 2024-08-21 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | 34 | /** 35 | * @brief 此段存放所有的驱动注册代码 36 | * 37 | * 所有通过 EXPORT_DRIVER 宏导出的驱动都将被链接到这个段中 38 | */ 39 | SECTIONS 40 | { 41 | .early_driver : 42 | { 43 | __start_early_driver = .; 44 | KEEP(*(.early_driver)) 45 | __stop_early_driver = .; 46 | } > FLASH 47 | } 48 | -------------------------------------------------------------------------------- /core/virtual_os_mm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_mm.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief VirtualOS的内存管理(使用BGET组件) 5 | * @version 1.0 6 | * @date 2025-03-19 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | 35 | #include "core/virtual_os_config.h" 36 | #include "core/virtual_os_mm.h" 37 | 38 | #include "core/lib/bget.h" 39 | 40 | #if VIRTUALOS_ENABLE_BGET 41 | 42 | #endif 43 | 44 | /** 45 | * @brief 初始化内存管理 46 | * 对给定的堆空间大小,进行一次malloc申请,后续这部分空间都由VirtualOS来管理 47 | * 48 | * @param pool_size 内存池大小 49 | * @return true 成功 50 | * @return false 失败 51 | */ 52 | bool virtual_os_mm_init(size_t pool_size) 53 | { 54 | #if VIRTUALOS_ENABLE_BGET 55 | void *p = malloc(pool_size); 56 | if (!p) 57 | return false; 58 | 59 | bpool(p, pool_size); 60 | 61 | return true; 62 | #else 63 | return true; 64 | #endif 65 | } 66 | 67 | /** 68 | * @brief 申请内存 69 | * 70 | * @param size 内存大小 71 | * @return void* 失败返回NULL 72 | */ 73 | void *virtual_os_malloc(size_t size) 74 | { 75 | #if VIRTUALOS_ENABLE_BGET 76 | return bget(size); 77 | #else 78 | return malloc(size); 79 | #endif 80 | } 81 | 82 | /** 83 | * @brief 申请内存并初始化为0 84 | * 85 | * @param num 元素个数 86 | * @param per_size 每个元素的大小 87 | * @return void* 失败返回NULL 88 | */ 89 | void *virtual_os_calloc(size_t num, size_t per_size) 90 | { 91 | #if VIRTUALOS_ENABLE_BGET 92 | return bgetz(num * per_size); 93 | #else 94 | return calloc(num, per_size); 95 | #endif 96 | } 97 | 98 | /** 99 | * @brief 重新分配内存 100 | * 101 | * @param old_ptr 原内存地址 102 | * @param size 新内存大小 103 | * @return void* 失败返回NULL 104 | */ 105 | void *virtual_os_realloc(void *old_ptr, size_t size) 106 | { 107 | #if VIRTUALOS_ENABLE_BGET 108 | return bgetr(old_ptr, size); 109 | #else 110 | return realloc(old_ptr, size); 111 | #endif 112 | } 113 | 114 | /** 115 | * @brief 释放内存 116 | * 117 | * @param ptr 内存地址 118 | */ 119 | void virtual_os_free(void *ptr) 120 | { 121 | #if VIRTUALOS_ENABLE_BGET 122 | brel(ptr); 123 | #else 124 | free(ptr); 125 | #endif 126 | } 127 | -------------------------------------------------------------------------------- /core/virtual_os_run.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_run.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 系统启动入口 5 | * @version 1.0 6 | * @date 2024-08-21 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | 35 | #include "driver/virtual_os_driver.h" 36 | #include "core/virtual_os_run.h" 37 | #include "core/virtual_os_defines.h" 38 | #include "utils/stimer.h" 39 | #include "utils/string_hash.h" 40 | 41 | extern void dal_init(void); 42 | 43 | extern void (*__start_early_driver[])(void); 44 | extern void (*__stop_early_driver[])(void); 45 | 46 | static void register_drivers(void) 47 | { 48 | size_t driver_count = __stop_early_driver - __start_early_driver; 49 | 50 | for (size_t i = 0; i < driver_count; i++) { 51 | if (__start_early_driver[i]) 52 | __start_early_driver[i](); 53 | } 54 | } 55 | 56 | static void virtual_os_base_init(struct timer_port *port) 57 | { 58 | driver_manage_init(); 59 | 60 | register_drivers(); 61 | 62 | dal_init(); 63 | 64 | virtual_os_assert(stimer_init(port)); 65 | 66 | #if VIRTUALOS_SHELL_ENABLE 67 | // 使能Shell 68 | extern void virtual_os_shell_init(void); 69 | extern void virtual_os_shell_task(void); 70 | stimer_task_create(virtual_os_shell_init, virtual_os_shell_task, VIRTUALOS_SHELL_PRIOD_MS); 71 | #endif 72 | } 73 | 74 | #if VIRTUALOS_ENABLE_BGET 75 | #include "core/virtual_os_mm.h" 76 | void virtual_os_init(struct timer_port *port, size_t poll_size) 77 | { 78 | virtual_os_mm_init(poll_size); 79 | virtual_os_base_init(port); 80 | } 81 | 82 | #else 83 | 84 | void virtual_os_init(struct timer_port *port) 85 | { 86 | virtual_os_base_init(port); 87 | } 88 | 89 | #endif -------------------------------------------------------------------------------- /docs/CAN/README.md: -------------------------------------------------------------------------------- 1 | # 如何编写CAN应用与驱动 2 | 3 | ## 1. CAN帧定义 4 | 5 | - 在`include/driver/can_bus.h`中定义了标准CAN帧结构体,如下所示 6 | 7 | ```c 8 | #define CAN_MAX_DLEN 8 9 | 10 | /* 11 | * 控制器局域网 (CAN) 标识符结构 12 | * 13 | * bit 0-28 : CAN 标识符(11/29 位) 14 | * bit 29 : 错误帧标志(0 = 数据帧,1 = 错误消息帧) 15 | * bit 30 : 远程请求帧标志(1 = RTR 帧) 16 | * bit 31 : 帧格式标志(0 = 标准帧(11 位),1 = 扩展帧(29 位)) 17 | */ 18 | typedef uint32_t canid_t; 19 | 20 | #define CAN_STANDARD_ID_MASK 0x000007FF // CAN 标准帧标识符掩码 21 | #define CAN_EXTENDED_ID_MASK 0x1FFFFFFF // CAN 扩展帧标识符掩码 22 | #define CAN_ERR_FLAG 0x20000000 // 错误帧标志 23 | #define CAN_RTR_FLAG 0x40000000 // 远程请求帧标志 24 | #define CAN_EXT_FLAG 0x80000000 // 扩展帧标志 25 | 26 | // CAN帧 27 | struct can_frame { 28 | uint8_t data[CAN_MAX_DLEN]; // 数据内容 29 | canid_t can_id; // CAN ID + 帧类型 30 | uint8_t can_dlc; // 数据长度 31 | }; 32 | ``` 33 | 34 | - 应用层调用读写接口时,只需要填充/解析`can_frame`结构体即可,驱动中也需要根据平台情况填充/解析CAN帧结构体。 35 | 36 | ## 2. 驱动编写 37 | 38 | - 在项目自己新建的驱动文件中新建驱动文件, 如`can_driver.c` 39 | - 参考[驱动模板](../driver/README.md)的编写方法 40 | - 参考代码如下: 41 | 42 | ```c 43 | #include 44 | #include 45 | #include 46 | 47 | #include "driver/virtual_os_driver.h" /* 驱动注册头文件 */ 48 | #include "utils/queue.h" 49 | #include "driver/can_bus.h" 50 | 51 | #include "gd32f30x.h" 52 | 53 | static const char can_name[] = "can0"; /* 确保此设备名项目中唯一 */ 54 | static int can_open(struct drv_file *file); 55 | static int can_close(struct drv_file *file); 56 | static int can_ioctl(struct drv_file *file, int cmd, void *arg); 57 | static size_t can_read(struct drv_file *file, void *buf, size_t len, size_t *offset); 58 | static size_t can_write(struct drv_file *file, void *buf, size_t len, size_t *offset); 59 | 60 | struct can_device { 61 | bool check_over; // 发送完成标志 62 | struct queue_info rx_queue; // 接收队列 63 | }; 64 | 65 | #define RX_BUFFER_UNITS (12) // 12条CAN帧缓冲 66 | static struct can_frame rx_buffer[RX_BUFFER_UNITS] = { 0 }; // CAN帧接收缓冲 67 | static struct can_device can_dev = { 68 | .check_over = true, 69 | .rx_queue = { 0 }, 70 | }; 71 | 72 | static int can_open(struct drv_file *file) 73 | { 74 | if (file->is_opened) 75 | return DRV_ERR_OCCUPIED; 76 | 77 | /* 打开外设 */ 78 | 79 | file->is_opened = true; 80 | 81 | return DRV_ERR_NONE; 82 | } 83 | 84 | static int can_close(struct drv_file *file) 85 | { 86 | /* 关闭外设 例如进入低功耗 */ 87 | 88 | file->is_opened = false; 89 | 90 | return DRV_ERR_NONE; 91 | } 92 | 93 | static int can_ioctl(struct drv_file *file, int cmd, void *arg) 94 | { 95 | if (!file->is_opened) 96 | return DRV_ERR_UNAVAILABLE; 97 | 98 | /* 除读写外的控制命令处理 */ 99 | 100 | int ret = DRV_ERR_INVALID; 101 | 102 | #define CAN_CHECK_OVER_CMD (1) // 检查发送完成标志 103 | 104 | switch (cmd) { 105 | case CAN_CHECK_OVER_CMD: 106 | *(bool *)arg = can_dev.check_over; 107 | 108 | ret = DRV_ERR_NONE; 109 | break; 110 | 111 | default: 112 | ret = DRV_ERR_INVALID; 113 | break; 114 | } 115 | 116 | #undef CAN_CHECK_OVER_CMD 117 | 118 | return ret; 119 | } 120 | 121 | // 转换CAN帧 将框架的CAN帧定义转为GD32的发送CAN帧 122 | static void can_tx_msg_convert(can_trasnmit_message_struct *tx_msg, struct can_frame *frame) 123 | { 124 | if (!frame || !tx_msg) 125 | return; 126 | 127 | memset(tx_msg, 0, sizeof(can_trasnmit_message_struct)); 128 | 129 | tx_msg->tx_ff = (frame->can_id & CAN_EXT_FLAG) ? CAN_FF_EXTENDED : CAN_FF_STANDARD; 130 | tx_msg->tx_ft = (frame->can_id & CAN_RTR_FLAG) ? CAN_FT_REMOTE : CAN_FT_DATA; 131 | 132 | if (tx_msg->tx_ff == CAN_FF_STANDARD) { 133 | tx_msg->tx_sfid = frame->can_id & CAN_STANDARD_ID_MASK; 134 | } else { 135 | tx_msg->tx_efid = frame->can_id & CAN_EXTENDED_ID_MASK; 136 | } 137 | 138 | tx_msg->tx_dlen = frame->can_dlc; 139 | memcpy(tx_msg->tx_data, frame->data, frame->can_dlc); 140 | } 141 | 142 | // 转换CAN帧 将GD32的接收CAN帧转为框架的CAN帧定义 143 | static void can_rx_msg_convert(struct can_frame *frame, can_receive_message_struct *rx_msg) 144 | { 145 | if (!rx_msg || !frame) 146 | return; 147 | 148 | memset(frame, 0, sizeof(struct can_frame)); 149 | 150 | if (rx_msg->rx_ff == CAN_FF_STANDARD) { 151 | // 标准帧 152 | frame->can_id = rx_msg->rx_sfid & CAN_STANDARD_ID_MASK; // 标准帧ID 153 | } else { 154 | // 扩展帧 155 | frame->can_id = rx_msg->rx_efid & CAN_EXTENDED_ID_MASK; // 扩展帧ID 156 | frame->can_id |= CAN_EXT_FLAG; // 扩展帧标志 157 | } 158 | 159 | if (rx_msg->rx_ft == CAN_FT_REMOTE) 160 | frame->can_id |= CAN_RTR_FLAG; // 远程帧 161 | 162 | frame->can_dlc = rx_msg->rx_dlen; 163 | memcpy(frame->data, rx_msg->rx_data, rx_msg->rx_dlen); 164 | } 165 | 166 | // 中断接收 167 | void USBD_LP_CAN0_RX0_IRQHandler(void) 168 | { 169 | if (can_interrupt_flag_get(CAN0, CAN_INT_FLAG_RFL0) != RESET) { 170 | can_receive_message_struct receive_message; 171 | struct can_frame frame; 172 | can_message_receive(CAN0, CAN_FIFO0, &receive_message); // 读取CAN接收帧 173 | can_rx_msg_convert(&frame, &receive_message); // 转为框架CAN帧 174 | queue_add(&can_dev.rx_queue, &frame, 1); // 加入接收队列 后续读取 175 | can_interrupt_flag_clear(CAN0, CAN_INT_FLAG_RFL0); 176 | } 177 | } 178 | 179 | // 从队列中读取CAN帧 180 | static size_t can_read(struct drv_file *file, void *buf, size_t len, size_t *offset) 181 | { 182 | if (!file->is_opened || !can_dev.check_over) 183 | return 0; 184 | 185 | size_t real_frame_len = len / sizeof(struct can_frame); // 计算实际读取的帧数 186 | struct can_frame *frame = (struct can_frame *)buf; // 框架CAN帧 187 | 188 | size_t read_units = 0; 189 | size_t units = 0; 190 | 191 | for (size_t i = 0; i < real_frame_len; i++) { 192 | units = queue_get(&can_dev.rx_queue, &frame[i], 1); // 这里的CAN帧是框架CAN帧 在中断接收时已经转换 193 | read_units += units; 194 | } 195 | 196 | return read_units * sizeof(struct can_frame); /* 读取成功返回实际读取的字节数 */ 197 | } 198 | 199 | // 写入CAN帧 200 | static size_t can_write(struct drv_file *file, void *buf, size_t len, size_t *offset) 201 | { 202 | if (!file->is_opened) 203 | return 0; 204 | 205 | size_t real_frame_len = len / sizeof(struct can_frame); // 计算实际写入的帧数 206 | struct can_frame *frame = (struct can_frame *)buf; // 框架CAN帧 207 | can_trasnmit_message_struct tx_msg; // 平台CAN帧 208 | 209 | can_dev.check_over = false; // 伪锁 210 | 211 | for (size_t i = 0; i < real_frame_len; i++) { 212 | can_tx_msg_convert(&tx_msg, &frame[i]); // 框架CAN帧转为平台CAN帧 213 | can_message_transmit(CAN0, &tx_msg); 214 | } 215 | 216 | can_dev.check_over = true; 217 | 218 | return real_frame_len * sizeof(struct can_frame); // 返回实际写入的字节数 219 | } 220 | 221 | // 设备操作接口 222 | static const struct file_operations can_opts = { 223 | .close = can_close, 224 | .ioctl = can_ioctl, 225 | .open = can_open, 226 | .read = can_read, 227 | .write = can_write, 228 | }; 229 | 230 | // 设备驱动初始化 231 | static bool can_driver_init(struct drv_device *dev) 232 | { 233 | /* 外设初始化 */ 234 | 235 | rcu_periph_clock_enable(RCU_CAN0); // CAN0 236 | rcu_periph_clock_enable(RCU_GPIOB); // GPIOB 237 | rcu_periph_clock_enable(RCU_AF); // 复用 238 | gpio_pin_remap_config(GPIO_CAN_PARTIAL_REMAP, ENABLE); // 重映射CAN0引脚 239 | 240 | gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8); // PB8 RX 241 | gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9); // PB9 TX 242 | 243 | can_deinit(CAN0); 244 | 245 | // 初始化CAN参数 246 | can_parameter_struct param; 247 | can_struct_para_init(CAN_INIT_STRUCT, ¶m); 248 | param.time_triggered = DISABLE; // 关闭时间触发 249 | param.auto_bus_off_recovery = ENABLE; // 开启自恢复 250 | param.auto_wake_up = DISABLE; // 关闭自动唤醒 251 | param.auto_retrans = ENABLE; // 开启自动重发 252 | param.rec_fifo_overwrite = DISABLE; // 关闭接收FIFO溢出 253 | param.trans_fifo_order = DISABLE; // 关闭发送FIFO顺序 254 | param.working_mode = CAN_LOOPBACK_MODE; // 回环模式 测试收发 255 | param.resync_jump_width = CAN_BT_SJW_1TQ; // 再同步补偿 256 | param.time_segment_1 = CAN_BT_BS1_5TQ; // 时间段1 这里5实际为4 257 | param.time_segment_2 = CAN_BT_BS2_4TQ; // 时间段2 这里4实际为3 258 | // 波特率 = APB1 / prescaler / (time_segment_1 + time_segment_2 + resync_jump_width) = 60M / 24 / (5 + 4 + 1) = 250k 259 | param.prescaler = 24; 260 | can_init(CAN0, ¶m); 261 | 262 | // 初始化CAN过滤器参数 263 | can_filter_parameter_struct filter; 264 | can_struct_para_init(CAN_FILTER_STRUCT, &filter); 265 | filter.filter_number = 0; // 过滤器号 266 | filter.filter_mode = CAN_FILTERMODE_MASK; // 掩码模式 267 | filter.filter_bits = CAN_FILTERBITS_16BIT; // 掩码位宽 268 | filter.filter_list_low = 0x1B0 << 5; // 0X1Bx 都可以 269 | filter.filter_list_high = 0x1B0 << 5; // 0X1Bx 都可以 270 | filter.filter_mask_low = 0x7F0 << 5; // 0X1Bx 都可以 271 | filter.filter_mask_high = 0x7F0 << 5; // 0X1Bx 都可以 272 | filter.filter_fifo_number = CAN_FIFO0; // 接收FIFO0 273 | filter.filter_enable = ENABLE; // 使能过滤器 274 | can_filter_init(&filter); 275 | 276 | nvic_irq_enable(USBD_LP_CAN0_RX0_IRQn, 0, 0); 277 | can_interrupt_enable(CAN0, CAN_INT_RFNE0); 278 | 279 | // 12条CAN报文 280 | queue_init(&can_dev.rx_queue, sizeof(struct can_frame), rx_buffer, RX_BUFFER_UNITS); // 初始化接收队列 281 | 282 | return true; 283 | } 284 | 285 | // 通过宏定义导出驱动(在 virtual_os_init 函数中会被调用) 286 | EXPORT_DRIVER(can_driver_probe) 287 | void can_driver_probe(void) 288 | { 289 | driver_register(can_driver_init, &can_opts, can_name); // 调用注册接口 290 | } 291 | ``` 292 | 293 | ## 3. 编写应用层代码 294 | 295 | - 在`app/src`文件夹中新建文件,如 `app_can.c` 296 | - 在`app/inc`文件夹中新建文件,如 `app_can.h` 297 | - 编写了串口驱动后,即可使用`VirtualOS/dal/dal_opt.h`中提供的接口,其中的每个 298 | 接口都与驱动的`struct file_operations`一一对应 299 | - 使用框架定义的CAN帧进行收发 300 | - 参考代码如下: 301 | 302 | ```c 303 | // app_can.h 304 | #ifndef __APP_CAN_H__ 305 | #define __APP_CAN_H__ 306 | 307 | #define APP_CAN_TASK_PERIOD_MS (5) 308 | 309 | void app_can_init(void); 310 | void app_can_task(void); 311 | 312 | #endif 313 | ``` 314 | 315 | ```c 316 | // app_can.c 317 | 318 | #include "app_can.h" 319 | #include "dal/dal_opt.h" 320 | #include "driver/can_bus.h" // CAN帧 321 | #include "utils/log.h" 322 | #include 323 | 324 | struct app_can_dev { 325 | int fd; // 文件描述符 326 | const char *name; // 设备名 327 | }; 328 | 329 | static struct app_can_dev app_can = { 330 | .fd = -1, 331 | .name = "can0", 332 | }; 333 | 334 | // 发送测试代码 335 | static void app_can_send_test(void) 336 | { 337 | static uint32_t counter = 2000; 338 | if (counter < 2000) { 339 | counter += APP_CAN_TASK_PERIOD_MS; 340 | return; 341 | } 342 | counter = 0; // 每2s发送一次 343 | 344 | struct can_frame frame = { 0 }; // 定义CAN帧 345 | frame.can_dlc = 2; // 发送2字节 346 | frame.data[0] = 0x11; 347 | frame.data[1] = 0x22; 348 | 349 | // 发送三个不同帧 350 | frame.can_id = 0x1B0; 351 | dal_write(app_can.fd, &frame, sizeof(struct can_frame)); 352 | 353 | frame.can_id = 0x1BF; 354 | dal_write(app_can.fd, &frame, sizeof(struct can_frame)); 355 | 356 | frame.can_id = 0x2B0; 357 | dal_write(app_can.fd, &frame, sizeof(struct can_frame)); 358 | } 359 | 360 | // 接收测试代码 打印帧ID和数据 361 | static void app_can_read_test(void) 362 | { 363 | struct can_frame frame = { 0 }; 364 | size_t len = dal_read(app_can.fd, &frame, sizeof(struct can_frame)); 365 | if (len == sizeof(struct can_frame)) { 366 | log_i("ID = 0x%04x, %02x %02x\n", (frame.can_id & CAN_STANDARD_ID_MASK), frame.data[0], frame.data[1]); 367 | } 368 | } 369 | 370 | /********************API********************/ 371 | 372 | void app_can_init(void) 373 | { 374 | app_can.fd = dal_open(app_can.name); 375 | } 376 | 377 | void app_can_task(void) 378 | { 379 | app_can_send_test(); 380 | 381 | app_can_read_test(); 382 | } 383 | ``` 384 | 385 | ## 4. 在主函数中创建日志任务 386 | 387 | - 参考代码如下 388 | 389 | ```c 390 | #include 391 | #include 392 | 393 | #include "utils/stimer.h" 394 | 395 | #include "systick.h" 396 | 397 | #include "app_can.h" 398 | 399 | int main(void) 400 | { 401 | app_system_init(); // 初始化VirtualOS和调度器 402 | 403 | stimer_task_create(app_log_init, app_log_task, APP_LOG_TASK_PERIOD_MS); // 创建日志任务 404 | stimer_task_create(app_can_init, app_can_task, APP_CAN_TASK_PERIOD_MS); // 创建CAN任务 405 | 406 | stimer_start(); // 启动调度器(死循环) 407 | 408 | return 0; 409 | } 410 | ``` 411 | 412 | ## 实验结果 413 | 414 | - 实现现象为只打印了CAN帧ID为0x1B0和0x1BF的帧,0X2B0的帧没有打印,不符合过滤器的设置。 415 | - 如图所示: 416 | ![alt text](image.png) 417 | -------------------------------------------------------------------------------- /docs/CAN/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/CAN/image.png -------------------------------------------------------------------------------- /docs/Shell/README.md: -------------------------------------------------------------------------------- 1 | # 使能Shell 2 | 3 | 本框架可以通过`include/core/virtual_os_config.h` 中的宏`VIRTUALOS_SHELL_ENABLE`来启动Shell功能。 4 | 注意,由于Shell依赖一个具体的芯片平台串口,因此静态库的编译方式不适合启动Sheel功能。因为需要额外引入芯片平台的串口驱动。 5 | 因此,如要开启此功能,建议导入`virtual_os_src.cmake`,将VirtualOS的源码全部加入通应用工程一起编译。 6 | 7 | 如果用户需要在静态库编译方式下使用Shell功能,应该在应用层自行调用`utils/simple_shell`的组件进行初始化,读写回调可使用`dal/optes`中的读写来注册 8 | 9 | 如果使用源码编译方式只需填充`core/virtual_os_sh_drv.c`中的相关接口即可。 10 | 11 | 关键代码如下: 12 | 13 | ```c 14 | 15 | #include "core/virtual_os_config.h" 16 | 17 | // VIRTUALOS_SHELL_ENABLE // 注意使能此宏 18 | 19 | /** 20 | * @brief 初始化平台相关的串口 21 | * 22 | */ 23 | static void platform_serial_init(void) 24 | { 25 | /* 平台相关的串口初始化 */ 26 | } 27 | 28 | /** 29 | * @brief 平台相关的串口的接收回调 30 | * 31 | */ 32 | static struct sp_shell_opts sh_opts = { 33 | .read = NULL, // 串口读 34 | .write = NULL, // 串口写 35 | }; 36 | ``` 37 | 38 | 用户只需要初始化芯片平台的串口,并提供相关的读写回调接口即可使用Shell功能。 39 | -------------------------------------------------------------------------------- /docs/config_btn/README.md: -------------------------------------------------------------------------------- 1 | # 配置按键组件 2 | 3 | ## 使用本框架提供的按键组件,无死延时消抖,支持单击,双击,多击,长按 4 | 5 | 1. 编写按键驱动代码,即IO读取的驱动 6 | 7 | - 在项目自己新建的驱动文件中新建驱动文件, 如`key_driver.c` 8 | - 参考[驱动模板](../driver/README.md)的编写方法 9 | - 参考代码如下: 10 | 11 | ```c 12 | #include 13 | #include 14 | #include "driver/virtual_os_driver.h" /* 驱动注册头文件 */ 15 | 16 | #include "gd32f30x.h" 17 | 18 | static const char key_name[] = "key"; /* 确保此设备名项目中唯一 */ 19 | static int key_open(struct drv_file *file); 20 | static int key_close(struct drv_file *file); 21 | static int key_ioctl(struct drv_file *file, int cmd, void *arg); 22 | static size_t key_read(struct drv_file *file, void *buf, size_t len, size_t *offset); 23 | static size_t key_write(struct drv_file *file, void *buf, size_t len, size_t *offset); 24 | 25 | static int key_open(struct drv_file *file) 26 | { 27 | if (file->is_opened) 28 | return DRV_ERR_OCCUPIED; 29 | 30 | /* 打开外设 */ 31 | 32 | file->is_opened = true; 33 | 34 | return DRV_ERR_NONE; 35 | } 36 | 37 | static int key_close(struct drv_file *file) 38 | { 39 | /* 关闭外设 例如进入低功耗 */ 40 | 41 | file->is_opened = false; 42 | 43 | return DRV_ERR_NONE; 44 | } 45 | 46 | static int key_ioctl(struct drv_file *file, int cmd, void *arg) 47 | { 48 | if (!file->is_opened) 49 | return DRV_ERR_UNAVAILABLE; 50 | 51 | /* 除读写外的控制命令处理 */ 52 | 53 | return DRV_ERR_NONE; 54 | } 55 | 56 | static size_t key_read(struct drv_file *file, void *buf, size_t len, size_t *offset) 57 | { 58 | if (!file->is_opened) 59 | return DRV_ERR_UNAVAILABLE; 60 | 61 | uint8_t *p_buf = buf; 62 | 63 | /* 读取外设数据 */ 64 | FlagStatus status = gpio_input_bit_get(GPIOE, GPIO_PIN_3); // 读取GPIOE3位状态 65 | if (status == RESET) 66 | p_buf[0] = 0; 67 | else 68 | p_buf[0] = 1; 69 | 70 | return 1; /* 读取成功返回实际读取的字节数 */ 71 | } 72 | 73 | static size_t key_write(struct drv_file *file, void *buf, size_t len, size_t *offset) 74 | { 75 | if (!file->is_opened) 76 | return DRV_ERR_UNAVAILABLE; 77 | 78 | return 0; /* 写入成功返回实际写入的字节数 */ 79 | } 80 | 81 | // 设备操作接口 82 | static const struct file_operations key_dev = { 83 | .close = key_close, 84 | .ioctl = key_ioctl, 85 | .open = key_open, 86 | .read = key_read, 87 | .write = key_write, 88 | }; 89 | 90 | // 设备驱动初始化 91 | static bool key_driver_init(struct drv_device *dev) 92 | { 93 | /* 外设初始化 */ 94 | rcu_periph_clock_enable(RCU_GPIOE); 95 | rcu_periph_clock_enable(RCU_AF); 96 | 97 | gpio_init(GPIOE, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_3); 98 | 99 | return true; 100 | } 101 | 102 | // 通过宏定义导出驱动(在 virtual_os_init 函数中会被调用) 103 | EXPORT_DRIVER(key_driver_probe) 104 | void key_driver_probe(void) 105 | { 106 | driver_register(key_driver_init, &key_dev, key_name); // 调用注册接口 107 | } 108 | ``` 109 | 110 | ### 2. 编写按键的应用代码 111 | 112 | - 在`app/src`文件夹中新建文件,如 `app_key.c` 113 | - 在`app/inc`文件夹中新建文件,如 `app_key.h` 114 | - 编写了按键驱动后,即可使用`VirtualOS/dal/dal_opt.h`中提供的接口,其中的每个 115 | 接口都与驱动的`struct file_operations`一一对应 116 | - 参考代码如下 117 | 118 | ```c 119 | // app_key.h 120 | 121 | #ifndef __APP_KEY_H__ 122 | #define __APP_KEY_H__ 123 | 124 | #define APP_KEY_TASK_PERIOD_MS (2) 125 | 126 | void app_key_init(void); 127 | void app_key_task(void); 128 | 129 | #endif /* __APP_KEY_H__ */ 130 | ``` 131 | 132 | ```c 133 | // app_key.c 134 | 135 | #include 136 | 137 | #include "dal/dal_opt.h" 138 | 139 | #include "utils/button.h" // 案件组件 140 | #include "utils/log.h" // 日志组件 141 | 142 | #include "app_key.h" // 头文件 143 | 144 | #define KEY_NAME "key" // 设备名 145 | static int fd_key = -1; // 文件描述符 146 | 147 | static btn_handle key_handle = NULL; // 按键实例 148 | 149 | static uint8_t key_read(void) 150 | { 151 | uint8_t level = 1; 152 | dal_read(fd_key, &level, sizeof(uint8_t)); // 读取按键状态 153 | return level; 154 | } 155 | 156 | static void key_callback(const struct btn_ev_data *ev_data) 157 | { 158 | switch (ev_data->ev_type) { 159 | case USR_BTN_EV_SINGLE_CLICK: 160 | // 单击 161 | log_i("key single click\n"); 162 | break; 163 | 164 | case USR_BTN_EV_DOUBLE_CLICK: 165 | // 双击 166 | log_i("key double click\n"); 167 | break; 168 | 169 | case USR_BTN_EV_MORE_CLICK: 170 | // 多击 171 | log_i("key more click\n"); 172 | break; 173 | 174 | case USR_BTN_EV_LONG_CLICK: 175 | // 长按 176 | log_i("key long click\n"); 177 | break; 178 | default: 179 | break; 180 | } 181 | } 182 | 183 | static struct btn_cfg key_cfg = { 184 | .active_lv = BUTTON_LEVEL_LOW, // 低电平有效 185 | .f_io_read = key_read, // 按键读取函数 186 | .up_max_cnt = 100, // 单次按下之间的间隔(根据任务周期计算这里约(2 * 100)ms) 187 | .long_min_cnt = 1000, // 长按最小时间(根据任务周期计算这里约(2 * 1000)ms) 188 | }; 189 | 190 | static void key_init(void) 191 | { 192 | fd_key = dal_open(KEY_NAME); 193 | key_handle = button_ctor(&key_cfg, key_callback); 194 | } 195 | 196 | /******************API******************/ 197 | 198 | void app_key_init(void) 199 | { 200 | key_init(); 201 | } 202 | 203 | void app_key_task(void) 204 | { 205 | button_scan(key_handle); 206 | } 207 | ``` 208 | 209 | ### 3. 新建按键任务 210 | 211 | - 在main函数中新建任务,参考代码如下 212 | 213 | ```c 214 | #include 215 | #include 216 | 217 | #include "utils/stimer.h" 218 | 219 | #include "systick.h" 220 | 221 | #include "app_key.h" 222 | 223 | int main(void) 224 | { 225 | app_system_init(); // 初始化VirtualOS和调度器 226 | 227 | stimer_task_create(app_key_init, app_key_task, APP_KEY_TASK_PERIOD_MS); // 创建按键任务 228 | 229 | stimer_start(); // 启动调度器(死循环) 230 | 231 | return 0; 232 | } 233 | ``` 234 | 235 | ### 4. 编译烧录后 236 | 237 | 当单击,双击,多击,长按按键时,会在串口打印相应的日志信息,效果如下 238 | ![alt text](image.png) 239 | -------------------------------------------------------------------------------- /docs/config_btn/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/config_btn/image.png -------------------------------------------------------------------------------- /docs/config_log/README.md: -------------------------------------------------------------------------------- 1 | # 日志使用说明 2 | 3 | ## 本框架已经提供`utils/log.c`日志组件,只需要提供一个串口回调即可使用 4 | 5 | ### 1. 编写日志的串口驱动 6 | 7 | - 在项目自己新建的驱动文件中新建驱动文件, 如`log_driver.c` 8 | - 参考[驱动模板](../driver/README.md)的编写方法 9 | - 本案例使用DMA+串口作为底层发送方式 10 | - 参考代码如下: 11 | 12 | ```c 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "driver/virtual_os_driver.h" /* 必要的头文件 */ 19 | #include "utils/queue.h" /* 环形队列 */ 20 | 21 | #include "gd32f30x.h" 22 | 23 | static const char syslog_name[] = "syslog"; /* 确保此设备名唯一 */ 24 | static int syslog_open(struct drv_file *file); 25 | static size_t syslog_read(struct drv_file *file, void *buf, size_t len, size_t *offset); 26 | static size_t syslog_write(struct drv_file *file, void *buf, size_t len, size_t *offset); 27 | 28 | #define SYSLOG_TX_BUF_SIZE (512) 29 | #define SYSLOG_RX_BUF_SIZE (256) 30 | 31 | // 日志设备结构体 32 | struct syslog_dev { 33 | uint8_t tx_buf[SYSLOG_TX_BUF_SIZE]; // 发送缓冲区 34 | uint8_t rx_buf[SYSLOG_RX_BUF_SIZE]; // 接收缓冲区 35 | struct queue_info rx_queue; // 接收队列 36 | bool tx_over; // 发送完成标志位 37 | bool is_opened; // 打开标志位 38 | size_t pre_idx; // DMA上一次索引 39 | }; 40 | 41 | // 打开设备 42 | static int syslog_open(struct drv_file *file) 43 | { 44 | if (file->is_opened) 45 | return DRV_ERR_OCCUPIED; 46 | 47 | file->is_opened = true; 48 | 49 | return DRV_ERR_NONE; 50 | } 51 | 52 | // 关闭设备 53 | static int syslog_close(struct drv_file *file) 54 | { 55 | file->is_opened = false; 56 | 57 | return DRV_ERR_NONE; 58 | } 59 | 60 | // 获取发送完成状态 61 | static int syslog_ioctl(struct drv_file *file, int cmd, void *arg) 62 | { 63 | if (!file->is_opened) 64 | return DRV_ERR_UNAVAILABLE; 65 | 66 | struct syslog_dev *syslog = file->private; // 初始化的时候已经设置了私有数据这里可以直接拿到 67 | 68 | switch (cmd) { 69 | case 0: 70 | *(bool *)arg = syslog->tx_over; 71 | return DRV_ERR_NONE; 72 | default: 73 | return DRV_ERR_INVALID; 74 | } 75 | 76 | return DRV_ERR_NONE; 77 | } 78 | 79 | // 读数据 80 | static size_t syslog_read(struct drv_file *file, void *buf, size_t len, size_t *offset) 81 | { 82 | if (!file->is_opened) 83 | return DRV_ERR_UNAVAILABLE; 84 | 85 | struct syslog_dev *syslog = file->private; // 初始化的时候已经设置了私有数据这里可以直接拿到 86 | 87 | // DAM的Buffer就是队列初始化的Buffer,所以直接从队列中取数据即可 88 | 89 | return queue_get(&syslog->rx_queue, buf, len); /* 返回实际取到的数据长度 */ 90 | } 91 | 92 | // 写数据 93 | static size_t syslog_write(struct drv_file *file, void *buf, size_t len, size_t *offset) 94 | { 95 | if (!file->is_opened) 96 | return DRV_ERR_UNAVAILABLE; 97 | 98 | struct syslog_dev *syslog = file->private; // 初始化的时候已经设置了私有数据这里可以直接拿到 99 | 100 | // 还在发送中直接返回 101 | if (!syslog->tx_over) 102 | return 0; 103 | 104 | syslog->tx_over = false; // 重新置为发送中 105 | 106 | // DMA发送数据 107 | memcpy(syslog->tx_buf, buf, len); 108 | dma_channel_disable(DMA0, DMA_CH3); 109 | dma_transfer_number_config(DMA0, DMA_CH3, len); 110 | dma_channel_enable(DMA0, DMA_CH3); 111 | 112 | return len; /* 返回实际发送的数据长度 */ 113 | } 114 | 115 | // 设备操作接口 116 | static const struct file_operations syslog_opts = { 117 | .close = syslog_close, 118 | .ioctl = syslog_ioctl, 119 | .open = syslog_open, 120 | .read = syslog_read, 121 | .write = syslog_write, 122 | }; 123 | 124 | // DMA发送完成中断处理 125 | void DMA0_Channel3_IRQHandler(void) 126 | { 127 | static struct syslog_dev *syslog = NULL; 128 | if (syslog == NULL) { 129 | syslog = get_dev_private("syslog"); // 通过接口获取私有数据, 确保只查询一次 130 | if (syslog == NULL) 131 | return; 132 | } 133 | 134 | if (dma_interrupt_flag_get(DMA0, DMA_CH3, DMA_INT_FLAG_FTF) != RESET) { 135 | syslog->tx_over = true; 136 | 137 | dma_interrupt_flag_clear(DMA0, DMA_CH3, DMA_INT_FLAG_FTF); 138 | } 139 | } 140 | 141 | // USART接收超时中断处理 142 | void USART0_IRQHandler(void) 143 | { 144 | static struct syslog_dev *syslog = NULL; 145 | if (syslog == NULL) { 146 | syslog = get_dev_private("syslog"); // 通过接口获取私有数据, 确保只查询一次 147 | if (syslog == NULL) 148 | return; 149 | } 150 | 151 | if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_RT) != RESET) { 152 | uint32_t remain_cnt = dma_transfer_number_get(DMA0, DMA_CH4); 153 | size_t cur_pos = SYSLOG_RX_BUF_SIZE - remain_cnt; 154 | size_t cur_receive; // 计算接收的数据长度 155 | 156 | if (cur_pos >= syslog->pre_idx) 157 | cur_receive = cur_pos - syslog->pre_idx; 158 | else 159 | cur_receive = SYSLOG_RX_BUF_SIZE - syslog->pre_idx + cur_pos; // 环形队列溢出 160 | 161 | queue_advance_wr(&syslog->rx_queue, cur_receive); // 更新队列的写指针 162 | syslog->pre_idx = cur_pos; 163 | 164 | usart_interrupt_flag_clear(USART0, USART_INT_FLAG_RT); 165 | } 166 | } 167 | 168 | // 设备驱动初始化 169 | static bool syslog_driver_init(struct drv_device *dev) 170 | { 171 | if (!dev) 172 | return false; 173 | 174 | struct syslog_dev *syslog = calloc(1, sizeof(struct syslog_dev)); // 申请结构体 175 | if (!syslog) 176 | return false; 177 | syslog->tx_over = true; // 发送完成标志位 178 | 179 | // 串口 + DMA 的初始化 180 | rcu_periph_clock_enable(RCU_GPIOA); 181 | gpio_init(GPIOA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_9); 182 | gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10); 183 | 184 | rcu_periph_clock_enable(RCU_USART0); 185 | usart_baudrate_set(USART0, 115200); 186 | usart_receive_config(USART0, USART_RECEIVE_ENABLE); 187 | usart_transmit_config(USART0, USART_TRANSMIT_ENABLE); 188 | usart_interrupt_enable(USART0, USART_INT_RT); /* 超时中断 */ 189 | usart_receiver_timeout_enable(USART0); /* 使能接收超时 */ 190 | usart_receiver_timeout_threshold_config(USART0, 10); /* 超时阈值设置10 */ 191 | nvic_irq_enable(USART0_IRQn, 0, 0); 192 | usart_enable(USART0); 193 | 194 | rcu_periph_clock_enable(RCU_DMA0); 195 | dma_deinit(DMA0, DMA_CH3); 196 | dma_parameter_struct dma_param; 197 | dma_struct_para_init(&dma_param); 198 | dma_param.periph_addr = (uint32_t)(&USART_DATA(USART0)); 199 | dma_param.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; 200 | dma_param.memory_addr = (uint32_t)syslog->tx_buf; 201 | dma_param.memory_width = DMA_MEMORY_WIDTH_8BIT; 202 | dma_param.number = SYSLOG_TX_BUF_SIZE; 203 | dma_param.priority = DMA_PRIORITY_ULTRA_HIGH; 204 | dma_param.periph_inc = DMA_PERIPH_INCREASE_DISABLE; 205 | dma_param.memory_inc = DMA_MEMORY_INCREASE_ENABLE; 206 | dma_param.direction = DMA_MEMORY_TO_PERIPHERAL; 207 | usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE); 208 | dma_init(DMA0, DMA_CH3, &dma_param); 209 | dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FLAG_FTF); 210 | nvic_irq_enable(DMA0_Channel3_IRQn, 0, 1); 211 | 212 | dma_param.memory_addr = (uint32_t)syslog->rx_buf; // 接收缓冲 213 | dma_param.direction = DMA_PERIPHERAL_TO_MEMORY; 214 | dma_param.number = SYSLOG_RX_BUF_SIZE; 215 | dma_deinit(DMA0, DMA_CH4); 216 | dma_init(DMA0, DMA_CH4, &dma_param); 217 | dma_circulation_enable(DMA0, DMA_CH4); /* 使能环形缓冲 */ 218 | usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE); 219 | dma_channel_enable(DMA0, DMA_CH4); 220 | 221 | queue_init(&syslog->rx_queue, sizeof(uint8_t), syslog->rx_buf, SYSLOG_RX_BUF_SIZE); /* 初始化接收队列 */ 222 | 223 | set_dev_private(dev, syslog); // 设置私有数据 以便于其他接口获取 224 | 225 | return true; 226 | } 227 | 228 | // 通过宏定义导出驱动(在 virtual_os_init 函数中会被调用) 229 | EXPORT_DRIVER(syslog_driver_probe) 230 | void syslog_driver_probe(void) 231 | { 232 | driver_register(syslog_driver_init, &syslog_opts, syslog_name); // 调用注册接口 233 | } 234 | ``` 235 | 236 | ### 2. 编写日志的应用代码 237 | 238 | - 在`app/src`文件夹中新建文件,如 `app_log.c` 239 | - 在`app/inc`文件夹中新建文件,如 `app_log.h` 240 | - 编写了串口驱动后,即可使用`VirtualOS/dal/dal_opt.h`中提供的接口,其中的每个 241 | 接口都与驱动的`struct file_operations`一一对应 242 | - 使用框架提供的日志组件, 只需要调用`syslog_init`函数即可,其中的参数分别为 读写回调和获取发送完成状态的回调和任务的周期 243 | - 初始化完成之后则可以使用相关宏定义来打印日志, 如`log_d`, `log_i`, `log_w`, `log_e` 244 | - 参考代码如下 245 | 246 | ```c 247 | // app_log.h 248 | 249 | #ifndef _APP_LOG_H 250 | #define _APP_LOG_H 251 | 252 | #define APP_LOG_TASK_PERIOD_MS (5) // 任务周期 253 | 254 | void app_log_init(void); // 日志初始化 255 | void app_log_task(void); // 日志任务 256 | 257 | #endif /* _APP_LOG_H */ 258 | ``` 259 | 260 | ```c 261 | // app_log.c 262 | 263 | #include "dal/dal_opt.h" // 文件接口 264 | 265 | #include "utils/log.h" // 日志组件 266 | 267 | #include "app_log.h" // 头文件 268 | 269 | static int fd = -1; 270 | 271 | static size_t _log_write(uint8_t *buf, size_t len) 272 | { 273 | return dal_write(fd, buf, len); 274 | } 275 | 276 | static size_t _log_read(uint8_t *buf, size_t len) 277 | { 278 | return dal_read(fd, buf, len); 279 | } 280 | 281 | static bool _log_check_over(void) 282 | { 283 | // 轮询发送直接返回true 284 | // DMA发送这里需要判断是否发送完成 285 | 286 | bool status = false; 287 | int err = DAL_ERR_NOT_EXIST; // 错误码 288 | 289 | int cmd = 0; // 驱动中的指令0为获取发送完成状态 290 | 291 | err = dal_ioctl(fd, cmd, &status); 292 | if (err != DAL_ERR_NONE) 293 | return false; 294 | 295 | return status; 296 | } 297 | 298 | static struct log_interface interface = { 299 | .check_over = _log_check_over, 300 | .write = _log_write, 301 | .read = _log_read, 302 | }; 303 | 304 | void app_log_init(void) 305 | { 306 | fd = dal_open("syslog"); // 打开日志设备 307 | 308 | syslog_init(&interface, APP_LOG_TASK_PERIOD_MS); // 初始化日志组件 309 | 310 | syslog_set_level(LOG_LEVEL_ALL); // 开启全等级日志 311 | 312 | // 打印日志 313 | log_d("Helo, world!\n"); 314 | log_i("Helo, world!\n"); 315 | log_w("Helo, world!\n"); 316 | log_e("Helo, world!\n"); 317 | } 318 | 319 | void app_log_task(void) 320 | { 321 | syslog_task(); // 轮询日志组件的任务 322 | } 323 | ``` 324 | 325 | ### 3. 在主函数中创建日志任务 326 | 327 | - 参考代码如下 328 | 329 | ```c 330 | #include 331 | 332 | #include "utils/stimer.h" 333 | 334 | #include "systick.h" 335 | 336 | #include "app_log.h" 337 | 338 | int main(void) 339 | { 340 | app_system_init(); // 初始化VirtualOS和调度器 341 | 342 | stimer_task_create(app_log_init, app_log_task, APP_LOG_TASK_PERIOD_MS); // 创建日志任务 343 | 344 | stimer_start(); // 启动调度器(死循环) 345 | 346 | return 0; 347 | } 348 | ``` 349 | 350 | ### 4. 编译烧录 351 | 352 | - 编译烧录后,串口终端显然的日志信息如下所示 353 | ![alt text](image.png) 354 | - 其中 第一部分为日志等级,第二部分为日志所在的函数与行号,第三部分为日志内容 355 | - 可以通过`syslog_set_level`来修改不同的日志等级 356 | -------------------------------------------------------------------------------- /docs/config_log/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/config_log/image.png -------------------------------------------------------------------------------- /docs/driver/README.md: -------------------------------------------------------------------------------- 1 | # 驱动编写模板 2 | 3 | ```c 4 | #include 5 | #include "driver/virtual_os_driver.h" /* 驱动注册头文件 */ 6 | 7 | static const char xxx_name[] = "xxx"; /* 确保此设备名项目中唯一 */ 8 | static int xxx_open(struct drv_file *file); 9 | static int xxx_close(struct drv_file *file); 10 | static int xxx_ioctl(struct drv_file *file, int cmd, void *arg); 11 | static size_t xxx_read(struct drv_file *file, void *buf, size_t len, size_t *offset); 12 | static size_t xxx_write(struct drv_file *file, void *buf, size_t len, size_t *offset); 13 | 14 | static int xxx_open(struct drv_file *file) 15 | { 16 | if (file->is_opened) 17 | return DRV_ERR_OCCUPIED; 18 | 19 | /* 打开外设 */ 20 | 21 | file->is_opened = true; 22 | 23 | return DRV_ERR_NONE; 24 | } 25 | 26 | static int xxx_close(struct drv_file *file) 27 | { 28 | /* 关闭外设 例如进入低功耗 */ 29 | 30 | file->is_opened = false; 31 | 32 | return DRV_ERR_NONE; 33 | } 34 | 35 | static int xxx_ioctl(struct drv_file *file, int cmd, void *arg) 36 | { 37 | if (!file->is_opened) 38 | return DRV_ERR_UNAVAILABLE; 39 | 40 | /* 除读写外的控制命令处理 */ 41 | 42 | return DRV_ERR_NONE; 43 | } 44 | 45 | static size_t xxx_read(struct drv_file *file, void *buf, size_t len, size_t *offset) 46 | { 47 | if (!file->is_opened) 48 | return 0; 49 | 50 | /* 读取外设数据 */ 51 | 52 | return 0; /* 读取成功返回实际读取的字节数 */ 53 | } 54 | 55 | static size_t xxx_write(struct drv_file *file, void *buf, size_t len, size_t *offset) 56 | { 57 | if (!file->is_opened) 58 | return 0; 59 | 60 | return 0; /* 写入成功返回实际写入的字节数 */ 61 | } 62 | 63 | // 设备操作接口 64 | static const struct file_operations xxx_opts = { 65 | .close = xxx_close, 66 | .ioctl = xxx_ioctl, 67 | .open = xxx_open, 68 | .read = xxx_read, 69 | .write = xxx_write, 70 | }; 71 | 72 | // 设备驱动初始化 73 | static bool xxx_driver_init(struct drv_device *dev) 74 | { 75 | /* 外设初始化 */ 76 | 77 | return true; 78 | } 79 | 80 | // 通过宏定义导出驱动(在 virtual_os_init 函数中会被调用) 81 | EXPORT_DRIVER(xxx_driver_probe) 82 | void xxx_driver_probe(void) 83 | { 84 | driver_register(xxx_driver_init, &xxx_opts, xxx_name); // 调用注册接口 85 | } 86 | ``` 87 | -------------------------------------------------------------------------------- /docs/eeprom/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/eeprom/image.png -------------------------------------------------------------------------------- /docs/modbus/master/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/modbus/master/image-1.png -------------------------------------------------------------------------------- /docs/modbus/master/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/modbus/master/image.png -------------------------------------------------------------------------------- /docs/modbus/self_protocol.md: -------------------------------------------------------------------------------- 1 | # 自定义 Modbus 寄存器表 2 | 3 | ## 1. 设备信息区(地址 0 ~ 10) 4 | 5 | | 寄存器地址 | 寄存器长度 | 读/写权限 | 功能描述 | 备注 | 6 | | ---------- | ---------- | --------- | ---------- | ---- | 7 | | 0 | 1 | R | 硬件版本号 | | 8 | | 1 | 1 | R | 软件版本号 | | 9 | | 2 | 8 | R/W | 设备序列号 | | 10 | 11 | ## 2. 控制指令区(地址 10 ~ 15) 12 | 13 | | 寄存器地址 | 寄存器长度 | 读/写权限 | 功能描述 | 备注 | 14 | | ---------- | ---------- | --------- | ------------------------------- | ---- | 15 | | 10 | 1 | W | 灯控指令
0:关 1:开 | | 16 | | 11 | 1 | W | 复位指令
0:不复位 1:复位 | | 17 | | 12 | 1 | W | 休眠指令
0:不休眠 1:休眠 | | 18 | 19 | ## 3. 升级区域 20 | 21 | | 寄存器地址 | 寄存器长度 | 读/写权限 | 功能描述 | 备注 | 22 | | ---------- | ---------- | --------- | --------------------------------------- | ---- | 23 | | 100 | 20 | W | 升级包长度,表示开始升级 | | 24 | | 120 | 123 | W | 1个寄存器表示包索引 122个寄存器表示数据 | | 25 | 26 | --- 27 | -------------------------------------------------------------------------------- /docs/modbus/slave/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/modbus/slave/image-1.png -------------------------------------------------------------------------------- /docs/modbus/slave/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/modbus/slave/image.png -------------------------------------------------------------------------------- /docs/new_project/image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-1.png -------------------------------------------------------------------------------- /docs/new_project/image-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-2.png -------------------------------------------------------------------------------- /docs/new_project/image-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-3.png -------------------------------------------------------------------------------- /docs/new_project/image-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-4.png -------------------------------------------------------------------------------- /docs/new_project/image-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-5.png -------------------------------------------------------------------------------- /docs/new_project/image-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-6.png -------------------------------------------------------------------------------- /docs/new_project/image-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-7.png -------------------------------------------------------------------------------- /docs/new_project/image-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-8.png -------------------------------------------------------------------------------- /docs/new_project/image-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image-9.png -------------------------------------------------------------------------------- /docs/new_project/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i-tesetd-it-no-problem/VirtualOS/b8b849a485b17d3b33aba0d61982321e9eb8d309/docs/new_project/image.png -------------------------------------------------------------------------------- /driver/virtual_os_driver.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_driver.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 驱动管理 5 | * @version 1.0 6 | * @date 2024-08-21 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, virtual_os_free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | 36 | #include "utils/string_hash.h" 37 | #include "driver/virtual_os_driver.h" 38 | #include "core/virtual_os_defines.h" 39 | #include "core/virtual_os_config.h" 40 | #include "core/virtual_os_defines.h" 41 | #include "core/virtual_os_mm.h" 42 | 43 | static struct hash_table driver_table = { 0 }; 44 | 45 | /** 46 | * @brief 初始化驱动管理 47 | * 48 | */ 49 | void driver_manage_init(void) 50 | { 51 | virtual_os_assert(init_hash_table(&driver_table, VIRTUALOS_MAX_DEV_NUM) == HASH_SUCCESS); 52 | } 53 | 54 | /** 55 | * @brief 注册设备 56 | * 57 | * @param drv_init 驱动初始化 58 | * @param file_opts 驱动文件操作 59 | * @param name 设备名称 60 | * @return true 61 | * @return false 62 | */ 63 | bool driver_register(driver_init drv_init, const struct file_operations *file_opts, const char *name) 64 | { 65 | enum hash_error err = HASH_POINT_ERROR; 66 | 67 | struct drv_device *dev = virtual_os_calloc(1, sizeof(struct drv_device)); 68 | if (!dev) 69 | return false; 70 | 71 | dev->file = virtual_os_calloc(1, sizeof(struct drv_file)); 72 | if (!dev->file) 73 | goto free_dev; 74 | 75 | dev->file->opts = file_opts; 76 | 77 | if (!drv_init(dev)) 78 | goto free_file; 79 | 80 | char *new_name = (char *)name; 81 | if (unlikely(strlen(name) >= VIRTUALOS_MAX_DEV_NAME_LEN - 1)) { 82 | new_name = (char *)virtual_os_calloc(1, VIRTUALOS_MAX_DEV_NAME_LEN); 83 | if (!new_name) 84 | goto free_file; 85 | strncpy(new_name, name, VIRTUALOS_MAX_DEV_NAME_LEN - 1); 86 | new_name[VIRTUALOS_MAX_DEV_NAME_LEN - 1] = '\0'; 87 | } 88 | 89 | err = hash_insert(&driver_table, (const char *)new_name, (void *)dev); 90 | if (err != HASH_SUCCESS) 91 | goto free_name; 92 | 93 | return true; 94 | 95 | free_name: 96 | virtual_os_free(new_name); 97 | 98 | free_file: 99 | virtual_os_free(dev->file); 100 | 101 | free_dev: 102 | virtual_os_free(dev); 103 | 104 | return false; 105 | } 106 | 107 | /** 108 | * @brief 查找设备 109 | * 110 | * @param name 设备名 111 | * @return struct drv_device* 设备结构体 112 | */ 113 | struct drv_device *find_device(const char *name) 114 | { 115 | struct drv_device *dev = NULL; 116 | enum hash_error err; 117 | dev = (struct drv_device *)hash_find(&driver_table, name, &err); 118 | if (err == HASH_SUCCESS) 119 | return dev; 120 | else 121 | return NULL; 122 | } 123 | 124 | /** 125 | * @brief 访问所有设备名 126 | * 127 | * @param visit 访问函数 128 | */ 129 | void visit_all_device_name(void (*visit)(const char *name)) 130 | { 131 | if (!visit) 132 | return; 133 | 134 | enum hash_error err = HASH_KEY_NOT_FOUND; 135 | char **keys = NULL; 136 | size_t num_keys = 0; 137 | err = hash_get_all_keys(&driver_table, &keys, &num_keys); 138 | if (err == HASH_SUCCESS) { 139 | for (size_t i = 0; i < num_keys; i++) { 140 | visit(keys[i]); 141 | virtual_os_free(keys[i]); 142 | } 143 | virtual_os_free(keys); 144 | } 145 | } 146 | 147 | /** 148 | * @brief 填充所有设备名到缓冲区 以换行符`\r\n`分割 149 | * 150 | * @param buf 151 | * @param len 152 | */ 153 | void fill_all_device_name(char *buf, size_t len) 154 | { 155 | if (!buf || !len) 156 | return; 157 | 158 | enum hash_error err = HASH_KEY_NOT_FOUND; 159 | char **keys = NULL; 160 | size_t num_keys = 0; 161 | err = hash_get_all_keys(&driver_table, &keys, &num_keys); 162 | if (err == HASH_SUCCESS) { 163 | for (size_t i = 0; i < num_keys; i++) { 164 | size_t name_len = strlen(keys[i]); 165 | if (name_len + 1 > len) 166 | break; 167 | memcpy(buf, keys[i], name_len); 168 | buf += name_len; 169 | *buf++ = '\r'; 170 | *buf++ = '\n'; 171 | len -= name_len + 2; 172 | } 173 | if (len > 0) 174 | *buf = '\0'; 175 | for (size_t i = 0; i < num_keys; i++) 176 | virtual_os_free(keys[i]); 177 | virtual_os_free(keys); 178 | } 179 | } 180 | 181 | /** 182 | * @brief 设置设备私有数据 183 | * 184 | * @param dev 设备结构体 185 | * @param private 私有数据 186 | */ 187 | void set_dev_private(struct drv_device *dev, void *private) 188 | { 189 | if (!dev || !dev->file) 190 | return; 191 | dev->file->private = private; 192 | } 193 | 194 | /** 195 | * @brief 获取设备私有数据 196 | * 197 | * @param name 设备名称 198 | * @return void* 私有数据 199 | */ 200 | void *get_dev_private(const char *name) 201 | { 202 | struct drv_device *dev = find_device(name); 203 | if (!dev || !dev->file) 204 | return NULL; 205 | return dev->file->private; 206 | } -------------------------------------------------------------------------------- /driver/virtual_os_sh_drv.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_sh_drv.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 底层Shell驱动模板,需要根据实际情况实现 5 | * @version 1.0 6 | * @date 2024-08-21 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | // 33 | #include "core/virtual_os_config.h" 34 | 35 | #if VIRTUALOS_SHELL_ENABLE // 使能此宏 36 | 37 | #include 38 | 39 | #include "utils/simple_shell.h" 40 | 41 | #include "driver/virtual_os_driver.h" 42 | 43 | /** 44 | * @brief 初始化平台相关的串口 45 | * 46 | */ 47 | static void platform_serial_init(void) 48 | { 49 | /* 平台相关的串口初始化 */ 50 | } 51 | 52 | /** 53 | * @brief 平台相关的串口的接收回调 54 | * 55 | */ 56 | static struct sp_shell_opts sh_opts = { 57 | .read = NULL, 58 | .write = NULL, 59 | }; 60 | 61 | /* ====================== 框架内置命令: show_device ====================== */ 62 | static void show_device(int argc, char *argv[], uint8_t *out, size_t buf_size, size_t *out_len) 63 | { 64 | // 列出所有注册的设备 65 | 66 | if (argc != 1) { 67 | *out_len = 0; 68 | return; 69 | } 70 | 71 | char msg[VIRTUALOS_MAX_DEV_NUM * VIRTUALOS_MAX_DEV_NAME_LEN] = { 0 }; 72 | fill_all_device_name(msg, VIRTUALOS_MAX_DEV_NUM * VIRTUALOS_MAX_DEV_NAME_LEN); 73 | *out_len = strlen(msg); 74 | if (*out_len > buf_size) { 75 | *out_len = 0; 76 | return; 77 | } 78 | memcpy(out, msg, *out_len); 79 | } 80 | SPS_EXPORT_CMD(show_device, show_device, "list all devices") 81 | 82 | /************************************EXPOSE API************************************/ 83 | 84 | /** 85 | * @brief Shell初始化 86 | * 87 | */ 88 | void virtual_os_shell_init(void) 89 | { 90 | platform_serial_init(); // 平台串口初始化 91 | 92 | if (!sh_opts.read || !sh_opts.write) 93 | return; 94 | 95 | #define VIRTUAL_OS_WELCOME_MSG "Welcome to VirtualOS!\r\n" 96 | 97 | simple_shell_init(&sh_opts, VIRTUAL_OS_WELCOME_MSG); // Shell 初始化 98 | } 99 | 100 | /** 101 | * @brief Shell调度 102 | * 103 | */ 104 | void virtual_os_shell_task(void) 105 | { 106 | shell_dispatch(); 107 | } 108 | 109 | #endif /* VIRTUALOS_SHELL_ENABLE */ 110 | -------------------------------------------------------------------------------- /include/bus/can_bus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file can_bus.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief CAN总线定义 5 | * @version 0.1 6 | * @date 2024-12-31 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_CAN_BUS_H__ 34 | #define __VIRTUAL_OS_CAN_BUS_H__ 35 | 36 | #include 37 | 38 | #define CAN_MAX_DLEN 8 39 | 40 | /* 41 | * 控制器局域网 (CAN) 标识符结构 42 | * 43 | * bit 0-28 : CAN 标识符(11/29 位) 44 | * bit 29 : 错误帧标志(0 = 数据帧,1 = 错误消息帧) 45 | * bit 30 : 远程请求帧标志(1 = RTR 帧) 46 | * bit 31 : 帧格式标志(0 = 标准帧(11 位),1 = 扩展帧(29 位)) 47 | */ 48 | typedef uint32_t canid_t; 49 | 50 | #define CAN_STANDARD_ID_MASK 0x000007FF // CAN 标准帧标识符掩码 51 | #define CAN_EXTENDED_ID_MASK 0x1FFFFFFF // CAN 扩展帧标识符掩码 52 | #define CAN_ERR_FLAG 0x20000000 // 错误帧标志 53 | #define CAN_RTR_FLAG 0x40000000 // 远程请求帧标志 54 | #define CAN_EXT_FLAG 0x80000000 // 扩展帧标志 55 | 56 | // CAN帧 57 | struct can_frame { 58 | uint8_t data[CAN_MAX_DLEN]; // 数据内容 59 | canid_t can_id; // CAN ID + 帧类型 60 | uint8_t can_dlc; // 数据长度 61 | }; 62 | 63 | #endif /* __VIRTUAL_OS_CAN_BUS_H__ */ -------------------------------------------------------------------------------- /include/bus/iic_bus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file iic_bus.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief IIC总线定义 5 | * @version 0.1 6 | * @date 2024-12-31 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_IIC_BUS_H__ 34 | #define __VIRTUAL_OS_IIC_BUS_H__ 35 | 36 | #include "stddef.h" 37 | #include 38 | 39 | #define I2C_FLAG_WRITE (0x00) // 写标志 40 | #define I2C_FLAG_READ (0x01) // 读标志 41 | 42 | /** 43 | * @brief IIC消息结构体 44 | * 45 | */ 46 | struct i2c_msg { 47 | size_t len; // 数据长度 48 | uint8_t *buf; // 数据指针 49 | uint8_t addr; // 只支持7位地址 50 | uint8_t flags; // 读写标志 51 | }; 52 | 53 | #endif /* __VIRTUAL_OS_IIC_BUS_H__ */ -------------------------------------------------------------------------------- /include/core/lib/align_mm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file align_mm.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 对齐内存接口 5 | * @version 1.0 6 | * @date 2025-03-18 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_ALIGH_MM_H__ 34 | #define __VIRTUAL_OS_ALIGH_MM_H__ 35 | 36 | #include 37 | 38 | /** 39 | * @brief 内存对齐分配 40 | * 41 | * @param size 申请大小 42 | * @param align 对齐大小 43 | * @return void* 对齐后的指针,失败返回NULL 44 | */ 45 | void *aligned_malloc(size_t size, size_t align); 46 | 47 | /** 48 | * @brief 内存对齐释放 49 | * 50 | * @param ptr 通过aligned_malloc申请的指针 51 | */ 52 | void aligned_free(void *ptr); 53 | 54 | #endif /* __VIRTUAL_OS_ALIGH_MM_H__ */ 55 | -------------------------------------------------------------------------------- /include/core/lib/bget.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Interface definitions for bget.c, the memory management package. 4 | 5 | */ 6 | 7 | #ifndef _ 8 | #ifdef PROTOTYPES 9 | #define _(x) x /* If compiler knows prototypes */ 10 | #else 11 | #define _(x) () /* It it doesn't */ 12 | #endif /* PROTOTYPES */ 13 | #endif 14 | 15 | typedef long bufsize; 16 | void bpool _((void *buffer, bufsize len)); 17 | void *bget _((bufsize size)); 18 | void *bgetz _((bufsize size)); 19 | void *bgetr _((void *buffer, bufsize newsize)); 20 | void brel _((void *buf)); 21 | void bectl _((int (*compact)(bufsize sizereq, int sequence), 22 | void *(*acquire)(bufsize size), 23 | void (*release)(void *buf), bufsize pool_incr)); 24 | void bstats _((bufsize *curalloc, bufsize *totfree, bufsize *maxfree, 25 | long *nget, long *nrel)); 26 | void bstatse _((bufsize *pool_incr, long *npool, long *npget, 27 | long *nprel, long *ndget, long *ndrel)); 28 | void bufdump _((void *buf)); 29 | void bpoold _((void *pool, int dumpalloc, int dumpfree)); 30 | int bpoolv _((void *pool)); 31 | -------------------------------------------------------------------------------- /include/core/virtual_os_config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_config.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 框架配置 5 | * @version 1.0 6 | * @date 2025-03-04 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_CONFIG_H__ 34 | #define __VIRTUAL_OS_CONFIG_H__ 35 | 36 | /** 37 | * @brief 38 | * 39 | * 请在编译静态库之前修改此文件的宏定义 40 | * 在编译静态库后修改此文件的宏定义将不会生效 41 | * 42 | */ 43 | 44 | // 设备数量配置 45 | #define VIRTUALOS_MAX_DEV_NUM (10) /* 最大设备数量 同时用于驱动数量以及文件描述符的数量 */ 46 | #define VIRTUALOS_MAX_DEV_NAME_LEN (16) /* 最大设备名长度(包括\0) */ 47 | 48 | // Shell使能配置 49 | // 注: 如果框架使用静态库编译则不建议使用此功能,因为Shell与具体的芯片平台串口有强依赖关系,不适用于静态库链接 50 | // 使用静态库链接时,用户可以通过在应用层单独使用`utils/simple_shell`组件,使用应用层的接口进行注册 51 | // 若要使用此功能,请将框架源码与应用工程一起编译,使能此宏会提供一些框架提供的内置命令 52 | #define VIRTUALOS_SHELL_ENABLE (0) /* 使能shell 1:使能 0:禁止 */ 53 | #define VIRTUALOS_SHELL_PRIOD_MS (25) /* shell任务周期 默认25ms */ 54 | 55 | // BGET组件内存分配等功能高于标准库的malloc 56 | #define VIRTUALOS_ENABLE_BGET (1) /* 使能动态内存分配功能 1:使能 0:禁止 */ 57 | 58 | #endif /* __VIRTUAL_OS_CONFIG_H__ */ -------------------------------------------------------------------------------- /include/core/virtual_os_defines.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_run.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 框架宏定义 5 | * @version 1.0 6 | * @date 2025-03-04 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_DEFINES_H__ 34 | #define __VIRTUAL_OS_DEFINES_H__ 35 | 36 | /** 37 | * @brief 断言 38 | * 39 | * @param cond 条件表达式 40 | * 41 | * cond 为 false 时,会进入死循环 42 | * cond 为 true 时,什么都不做 43 | */ 44 | #define virtual_os_assert(cond) \ 45 | do { \ 46 | if (!(cond)) { \ 47 | while (1) \ 48 | ; \ 49 | } \ 50 | } while (0) 51 | 52 | /** 53 | * @brief 分支预测 54 | * 55 | * likely(x) 用于指示 x 表达式的结果是经常为真的,编译器可以对其进行优化,以提高效率; 56 | * unlikely(x) 用于指示 x 表达式的结果是经常为假的,编译器可以对其进行优化,以提高效率; 57 | * 58 | */ 59 | #define likely(x) __builtin_expect(!!(x), 1) 60 | #define unlikely(x) __builtin_expect(!!(x), 0) 61 | 62 | /** 63 | * @brief 主动贯穿 64 | * 65 | */ 66 | #define fallthrough __attribute__((__fallthrough__)) 67 | 68 | #endif /* __VIRTUAL_OS_DEFINES_H__ */ -------------------------------------------------------------------------------- /include/core/virtual_os_mm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_mm.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief VirtualOS的内存管理(使用BGET组件) 5 | * @version 1.0 6 | * @date 2025-03-19 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_MM_H 34 | #define __VIRTUAL_OS_MM_H 35 | 36 | #include 37 | #include 38 | 39 | /** 40 | * @brief 此接口为VirtualOS的内存管理接口,使用BGET组件 41 | * 如果未使能宏`VIRTUALOS_ENABLE_BGET`则其中所有的接口实现都 42 | * 与标准库如malloc一一对应,仅仅是为了兼容接口名 43 | * 44 | * 如果使能了该宏,则VirtualOS会使用BGET组件来管理内存, 45 | */ 46 | 47 | /** 48 | * @brief 初始化内存管理 49 | * 对给定的堆空间大小,进行一次malloc申请,后续这部分空间都由VirtualOS来管理 50 | * 如果未使能宏`VIRTUALOS_ENABLE_BGET`则不需要这一步 51 | * 52 | * @param pool_size 内存池大小 53 | * @return true 成功 54 | * @return false 失败 55 | */ 56 | bool virtual_os_mm_init(size_t pool_size); 57 | 58 | /** 59 | * @brief 申请内存 60 | * 61 | * @param size 内存大小 62 | * @return void* 失败返回NULL 63 | */ 64 | void *virtual_os_malloc(size_t size); 65 | 66 | /** 67 | * @brief 申请内存并初始化为0 68 | * 69 | * @param num 元素个数 70 | * @param per_size 每个元素的大小 71 | * @return void* 失败返回NULL 72 | */ 73 | void *virtual_os_calloc(size_t num, size_t per_size); 74 | 75 | /** 76 | * @brief 重新分配内存 77 | * 78 | * @param old_ptr 原内存地址 79 | * @param size 新内存大小 80 | * @return void* 失败返回NULL 81 | */ 82 | void *virtual_os_realloc(void *old_ptr, size_t size); 83 | 84 | /** 85 | * @brief 释放内存 86 | * 87 | * @param ptr 内存地址 88 | */ 89 | void virtual_os_free(void *ptr); 90 | 91 | #endif /* __VIRTUAL_OS_MM_H */ -------------------------------------------------------------------------------- /include/core/virtual_os_run.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_run.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 系统宏定义 5 | * @version 1.0 6 | * @date 2024-08-21 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_RUN_H__ 34 | #define __VIRTUAL_OS_RUN_H__ 35 | 36 | #include 37 | 38 | #include "core/virtual_os_config.h" 39 | #include "utils/stimer.h" 40 | 41 | #if VIRTUALOS_ENABLE_BGET 42 | 43 | /** 44 | * @brief 框架调度初始化 如果启用VirtualOS的内存管理则需要提供一个内存池大小 45 | * 46 | * @param port 时钟配置 详细参考`utils/stimer.h` 47 | * @param poll_size 内存池大小 通常是RAM剩余的大小范围内 48 | */ 49 | void virtual_os_init(struct timer_port *port, size_t poll_size); 50 | 51 | #else 52 | 53 | /** 54 | * @brief 框架调度初始化 55 | * 56 | * @param port 时钟配置 详细参考`utils/stimer.h` 57 | */ 58 | void virtual_os_init(struct timer_port *port); 59 | 60 | #endif 61 | 62 | #endif /* __VIRTUAL_OS_RUN_H__ */ -------------------------------------------------------------------------------- /include/dal/dal_opt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dal_opt.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 应用接口 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_DAL_OPT_H__ 34 | #define __VIRTUAL_OS_DAL_OPT_H__ 35 | 36 | #include 37 | 38 | #define RESERVED_FDS (3) /* 前三个文件描述符为内部保留值 */ 39 | 40 | #define DAL_ERR_NONE (0) /* 无错误 */ 41 | #define DAL_ERR_INVALID (-1) /* 无效参数 */ 42 | #define DAL_ERR_OVERFLOW (-2) /* 超过最大设备数量 */ 43 | #define DAL_ERR_UNAVAILABLE (-3) /* 设备不可用 例如未打开 */ 44 | #define DAL_ERR_EXCEPTION (-4) /* 操作异常,例如对只读设备进行写操作,空指针等 */ 45 | #define DAL_ERR_OCCUPIED (-5) /* 设备被占用 */ 46 | #define DAL_ERR_NOT_EXIST (-6) /* 设备不存在 */ 47 | 48 | /** 49 | * @brief 打开文件 50 | * 51 | * @param file_name 驱动注册提供的文件名 52 | * @return int 成功返回大于0的文件描述符 失败参考错误码 53 | */ 54 | int dal_open(const char *file_name); 55 | 56 | /** 57 | * @brief 关闭文件 58 | * 59 | * @param fd 文件描述符 60 | * @return 参考错误码 61 | */ 62 | int dal_close(int fd); 63 | 64 | /** 65 | * @brief 从文件读取数据,读取成功后将增加文件偏移量 66 | * 67 | * @param fd 文件描述符 68 | * @param buf 读缓冲区 69 | * @param len 大小 70 | * @return size_t 返回实际读取字节数 71 | */ 72 | size_t dal_read(int fd, void *buf, size_t len); 73 | 74 | /** 75 | * @brief 向文件写入数据, 写入成功后将增加文件偏移量 76 | * 77 | * @param fd 文件描述符 78 | * @param buf 写缓冲区 79 | * @param len 大小 80 | * @return 返回实际写入字节数 81 | */ 82 | size_t dal_write(int fd, void *buf, size_t len); 83 | 84 | /** 85 | * @brief 设备控制指令,除设备读写以外的操作,cmd参考对应驱动定义 86 | * 87 | * @param fd 文件描述符 88 | * @param cmd 操作命令 89 | * @param arg 参数 90 | * @return 参考错误码 91 | */ 92 | int dal_ioctl(int fd, int cmd, void *arg); 93 | 94 | enum dal_lseek_whence { 95 | DAL_LSEEK_WHENCE_HEAD, /* 指向文件头部 */ 96 | DAL_LSEEK_WHENCE_SET, /* 指向当前位置 */ 97 | DAL_LSEEK_WHENCE_TAIL, /* 指向文件末尾 */ 98 | }; 99 | 100 | /** 101 | * @brief 修改文件指针偏移 102 | * 103 | * @param fd 文件描述符 104 | * @param offset 偏移大小 105 | * @param whence 偏移基准点 106 | * @return int 新的偏移 107 | */ 108 | int dal_lseek(int fd, int offset, enum dal_lseek_whence whence); 109 | 110 | #endif /* __VIRTUAL_OS_DAL_OPT_H__ */ 111 | -------------------------------------------------------------------------------- /include/driver/virtual_os_driver.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file virtual_os_driver.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 驱动管理 5 | * @version 1.0 6 | * @date 2024-08-21 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_DRIVER_H__ 34 | #define __VIRTUAL_OS_DRIVER_H__ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #define DRV_ERR_NONE (0) /* 无错误 */ 41 | #define DRV_ERR_INVALID (-1) /* 无效参数 */ 42 | #define DRV_ERR_OVERFLOW (-2) /* 超过最大设备数量 */ 43 | #define DRV_ERR_UNAVAILABLE (-3) /* 设备不可用 例如未打开 */ 44 | #define DRV_ERR_EXCEPTION (-4) /* 操作异常,例如对只读设备进行写操作,空指针等 */ 45 | #define DRV_ERR_OCCUPIED (-5) /* 设备被占用 */ 46 | #define DRV_ERR_NOT_EXIST (-6) /* 设备不存在 */ 47 | 48 | /** 49 | * @brief 初始化驱动管理 50 | * 51 | */ 52 | void driver_manage_init(void); 53 | 54 | /** 55 | * @brief 查找设备 56 | * 57 | * @param name 设备名 58 | * @return struct drv_device* 设备结构体 59 | */ 60 | struct drv_device *find_device(const char *name); 61 | 62 | // 驱动文件 63 | struct drv_file { 64 | const struct file_operations *opts; /* 文件操作接口 */ 65 | bool is_opened; /* 是否已打开 */ 66 | void *private; /* 私有数据 */ 67 | }; 68 | 69 | // 驱动设备 70 | struct drv_device { 71 | struct drv_file *file; // 文件 72 | size_t dev_size; /* 设备大小 */ 73 | size_t offset; // 文件偏移 74 | }; 75 | 76 | /****************************USER API*****************************/ 77 | 78 | /** 79 | * @brief 文件操作接口 一一对应于应用层的`dal/dal_opts.h`中的接口 80 | * 81 | * 所有对外设的读写控制等都通过此接口进行,在调用初始化`driver_register`的时候会注册进驱动中 82 | * 83 | */ 84 | struct file_operations { 85 | int (*open)(struct drv_file *file); /* 打开设备 返回结果参考错误码 */ 86 | int (*close)(struct drv_file *file); /* 关闭设备 返回结果参考错误码 */ 87 | int (*ioctl)(struct drv_file *file, int cmd, void *arg); /* 控制命令 返回结果参考错误码 */ 88 | size_t (*read)(struct drv_file *file, void *buf, size_t len, size_t *offset); /* 读取数据 */ 89 | size_t (*write)(struct drv_file *file, void *buf, size_t len, size_t *offset); /* 写入数据 */ 90 | }; 91 | 92 | /** 93 | * @brief 驱动注册宏 94 | * 95 | * 例如: EXPORT_DRIVER(uart_driver_init); 96 | * 通常`uart_driver_init`是一个只调用`driver_register`的空函数 97 | * 98 | */ 99 | #define EXPORT_DRIVER(_func) \ 100 | void _func(void); \ 101 | void (*_func##_ptr)(void) __attribute__((section(".early_driver"), used)) = &_func; 102 | 103 | /** 104 | * @brief 驱动初始化函数指针 105 | * 106 | * @param dev 设备结构体 如果此设备是一个存储类设备,需要设置`dev_size`,初始化大小,否则可以不关注此参数 107 | * 108 | * 通常这个函数用于执行初始化外设设备 109 | * 110 | */ 111 | typedef bool (*driver_init)(struct drv_device *dev); 112 | 113 | /** 114 | * @brief 注册设备 115 | * 116 | * @param drv_init 驱动初始化 117 | * @param file_opts 驱动文件操作 118 | * @param name 设备名称 119 | * @return true 120 | * @return false 121 | */ 122 | bool driver_register(driver_init drv_init, const struct file_operations *file_opts, const char *name); 123 | 124 | /** 125 | * @brief 遍历所有设备名 126 | * 127 | * @param visit 访问函数 128 | */ 129 | void visit_all_device_name(void (*visit)(const char *name)); 130 | 131 | /** 132 | * @brief 填充所有设备名到缓冲区 以换行符分割 133 | * 134 | * @param buf 135 | * @param len 136 | */ 137 | void fill_all_device_name(char *buf, size_t len); 138 | 139 | /** 140 | * @brief 设置设备私有数据 141 | * 142 | * @param dev 设备结构体 143 | * @param private 私有数据 144 | */ 145 | void set_dev_private(struct drv_device *dev, void *private); 146 | 147 | /** 148 | * @brief 获取设备私有数据 149 | * 150 | * @param name 设备名称 151 | * @return void* 私有数据 152 | */ 153 | void *get_dev_private(const char *name); 154 | 155 | #endif /* __VIRTUAL_OS_DRIVER_H__ */ 156 | -------------------------------------------------------------------------------- /include/protocol/modbus/modbus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file modbus.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief modbus通用协议 5 | * @version 0.1 6 | * @date 2024-12-17 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_MODBUS_H__ 34 | #define __VIRTUAL_OS_MODBUS_H__ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | // 当前支持的功能码 41 | #define MODBUS_FUN_RD_REG_MUL (0x03) // 读功能码 42 | #define MODBUS_FUN_WR_REG_MUL (0x10) // 写功能码 43 | 44 | // 错误码 45 | #define MODBUS_RESP_ERR_NONE (0x00) // 无错误 46 | #define MODBUS_RESP_ERR_FUNC (0x01) // 功能码错误 例如只读寄存器不能写 47 | #define MODBUS_RESP_ERR_REG_ADDR (0x02) // 寄存器地址错误 48 | #define MODBUS_RESP_ERR_DATA (0x03) // 数据错误 49 | #define MODBUS_RESP_ERR_DEV (0x04) // 设备错误 50 | #define MODBUS_RESP_ERR_PENDING (0x05) // 正在处理中,不能及时回复,需要主机后续轮询读取 51 | #define MODBUS_RESP_ERR_BUSY (0x06) // 设备繁忙, 无法处理 52 | 53 | // 一帧最大字节数 256 54 | #define MODBUS_FRAME_BYTES_MAX (256) 55 | 56 | // 校验功能码 57 | #define MODBUS_FUNC_CHECK_VALID(f) (((f) == MODBUS_FUN_RD_REG_MUL) || ((f) == MODBUS_FUN_WR_REG_MUL)) 58 | 59 | #define MAX_READ_REG_NUM (125) // 最大读寄存器数量 60 | #define MAX_WRITE_REG_NUM (123) // 最大写寄存器数量 61 | 62 | // 检查寄存器数量 63 | #define CHECK_REG_NUM_VALID(reg_num, func) \ 64 | (((func) == MODBUS_FUN_RD_REG_MUL) \ 65 | ? ((reg_num) <= MAX_READ_REG_NUM) \ 66 | : (((func) == MODBUS_FUN_WR_REG_MUL) ? ((reg_num) <= MAX_WRITE_REG_NUM) : false)) 67 | 68 | // 校验寄存器范围 69 | #define MODBUS_CHECK_REG_RANGE(reg, num, from, to, func) \ 70 | (((reg) < (to)) && ((reg) >= (from)) && CHECK_REG_NUM_VALID((num), (func)) && (((reg) + (num)) <= (to))) 71 | 72 | #define MODBUS_ADDR_BYTES_NUM (1) // 地址字节数 73 | #define MODBUS_FUNC_BYTES_NUM (1) // 功能码字节数 74 | #define MODBUS_REG_BYTES_NUM (2) // 寄存器地址字节数 75 | #define MODBUS_REG_LEN_BYTES_NUM (2) // 寄存器长度字节数 76 | #define MODBUS_CRC_BYTES_NUM (2) // CRC字节数 77 | 78 | #define COMBINE_U8_TO_U16(h, l) ((uint16_t)(h << 8) | (uint16_t)(l)) 79 | #define COMBINE_U16_TO_U32(h, l) ((uint32_t)(h << 16) | (uint32_t)(l)) 80 | #define GET_U8_HIGH_FROM_U16(u) (((u) >> 8) & 0xff) 81 | #define GET_U8_LOW_FROM_U16(u) ((u) & 0xff) 82 | 83 | // 串口方向 84 | enum modbus_serial_dir { 85 | modbus_serial_dir_all_unuse, 86 | modbus_serial_dir_rx_only, 87 | modbus_serial_dir_tx_only, 88 | }; 89 | 90 | /** 91 | * @brief 串口初始化函数指针 92 | * 93 | * @return true 初始化成功 94 | * @return false 初始化失败 95 | */ 96 | typedef bool (*modbus_serial_init)(void); 97 | 98 | /** 99 | * @brief 串口写函数指针 100 | * 101 | * @param p_data 待写入数据指针 102 | * @param len 待写入数据长度 103 | * @return size_t 实际写入数据长度 失败返回0 104 | */ 105 | typedef size_t (*modbus_serial_write)(uint8_t *p_data, size_t len); 106 | 107 | /** 108 | * @brief 串口读函数指针 109 | * 110 | * @param p_data 读入数据指针 111 | * @param len 待读数据长度 112 | * @return size_t 实际读入数据长度 失败返回0 113 | */ 114 | typedef size_t (*modbus_serial_read)(uint8_t *p_data, size_t len); 115 | 116 | /** 117 | * @brief 检查是否发送完成 118 | * 119 | * 如果是轮训发送可直接设置为NULL 120 | * DAM发送则需要查询相关标志位 121 | * 122 | * @return ture:发送完/可以接收 false:发送中 123 | */ 124 | typedef bool (*modbus_serial_check_over)(void); 125 | 126 | // 串口回调 127 | struct serial_opts { 128 | modbus_serial_init f_init; // 串口初始化函数指针 129 | modbus_serial_write f_write; // 串口写函数指针 130 | modbus_serial_read f_read; // 串口读函数指针 131 | }; 132 | 133 | #endif /* __VIRTUAL_OS_MODBUS_H__ */ -------------------------------------------------------------------------------- /include/protocol/modbus/modbus_master.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file modbus_master.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief modbus主机协议 5 | * @version 1.0 6 | * @date 2024-12-18 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_MODBUS_MASTER_H__ 34 | #define __VIRTUAL_OS_MODBUS_MASTER_H__ 35 | 36 | #include "modbus.h" 37 | #include 38 | #include 39 | 40 | #define MASTER_REPEATS (3) // 重发次数 41 | 42 | /** 43 | * @brief 主机接收帧处理 44 | * 45 | * @param data 仅对 读 功能码有效 接收到的数据 46 | * @param len 仅对 读 功能码有效 数据长度 47 | * @param err_code 异常响应码 参考modbus.h中的错误码 48 | * @param is_timeout ture:超时未回复 false:收到回复 49 | */ 50 | typedef void (*mb_mst_pdu_resp)(uint8_t *data, size_t len, uint8_t err_code, bool is_timeout); 51 | 52 | // 请求报文 53 | struct mb_mst_request { 54 | uint32_t timeout_ms; // 此报文的超时时间 55 | mb_mst_pdu_resp resp; // 回复处理 不需要处理回复可为空, 如写功能码 56 | 57 | uint8_t slave_addr; // 从机地址 58 | uint8_t func; // 功能玛 读:0x03 写:0x10 59 | uint16_t reg_addr; // 寄存器地址 60 | uint8_t reg_len; // 寄存器长度 61 | }; 62 | 63 | // 主机句柄 64 | typedef struct mb_mst *mb_mst_handle; 65 | 66 | /** 67 | * @brief 主机初始化并申请句柄 68 | * 69 | * @param opts 读写等回调函数指针 70 | * @param period_ms 轮训周期 71 | * @return mb_mst_handle 成功返回句柄,失败返回NULL 72 | */ 73 | mb_mst_handle mb_mst_init(struct serial_opts *opts, size_t period_ms); 74 | 75 | /** 76 | * @brief 释放主机句柄 77 | * 78 | * @param handle 主机句柄 79 | */ 80 | void mb_mst_destroy(mb_mst_handle handle); 81 | 82 | /** 83 | * @brief modbus任务轮询 84 | * 85 | * @param handle 主机句柄 86 | */ 87 | void mb_mst_poll(mb_mst_handle handle); 88 | 89 | /** 90 | * @brief 91 | * 92 | * @param handle 主机句柄 93 | * @param request 请求包 94 | * @param reg_data 寄存器数据 仅在request的功能码为写请求时有效 95 | * @param reg_len 寄存器长度 仅在request的功能码为写请求时有效 96 | */ 97 | void mb_mst_pdu_request(mb_mst_handle handle, struct mb_mst_request *request, uint16_t *reg_data, uint8_t reg_len); 98 | 99 | #endif /* __VIRTUAL_OS_MODBUS_MASTER_H__ */ -------------------------------------------------------------------------------- /include/protocol/modbus/modbus_slave.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file modbus_slave.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief modbus从机协议 5 | * @version 0.1 6 | * @date 2024-12-17 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_MODBUS_SLAVE_H__ 34 | #define __VIRTUAL_OS_MODBUS_SLAVE_H__ 35 | 36 | #include "modbus.h" 37 | 38 | /** 39 | * @brief 从机接收帧处理 40 | * 41 | * @param func 功能码 42 | * @param reg 寄存器地址 43 | * @param reg_num 寄存器数量 44 | * @param p_in_out 输入输出缓冲 45 | * 46 | * @return uint8_t 参考modbus.h中的错误码 47 | */ 48 | typedef uint8_t (*mb_slv_frame_resp)(uint8_t func, uint16_t reg, uint16_t reg_num, uint16_t *p_in_out); 49 | 50 | // 寄存器区间任务处理 51 | struct mb_slv_work { 52 | uint16_t start; // 起始寄存器 53 | uint16_t end; // 结束寄存器 = 起始寄存器 + 当前区间寄存器长度 54 | mb_slv_frame_resp resp; // 响应处理函数 55 | }; 56 | 57 | // 从机句柄 58 | typedef struct mb_slv *mb_slv_handle; 59 | 60 | /** 61 | * @brief 从机初始化并申请句柄 62 | * 63 | * @param opts 读写等回调函数指针 64 | * @param slv_addr 从机地址 65 | * @param table 任务处理表 66 | * @param table_num 任务处理表数量 67 | * @return mb_slv_handle 成功返回句柄,失败返回NULL 68 | */ 69 | mb_slv_handle mb_slv_init( 70 | struct serial_opts *opts, uint8_t slv_addr, struct mb_slv_work *work_table, uint16_t table_num); 71 | 72 | /** 73 | * @brief 释放从机句柄 74 | * 75 | * @param handle 76 | */ 77 | void mb_slv_destroy(mb_slv_handle handle); 78 | 79 | /** 80 | * @brief modbus任务轮询 81 | * 82 | * @param handle 从机句柄 83 | */ 84 | void mb_slv_poll(mb_slv_handle handle); 85 | 86 | #endif /* __VIRTUAL_OS_MODBUS_SLAVE_H__ */ -------------------------------------------------------------------------------- /include/utils/button.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file button.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 按键组件 5 | * @version 0.1 6 | * @date 2024-12-27 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_BUTTON_H__ 34 | #define __VIRTUAL_OS_BUTTON_H__ 35 | 36 | #include 37 | 38 | typedef struct button *btn_handle; 39 | 40 | // 用户按键事件类型 41 | enum usr_btn_ev { 42 | USR_BTN_EV_NONE, // 无事件 43 | USR_BTN_EV_POPUP, // 弹起事件 44 | /* 以上事件用户无需判断 */ 45 | 46 | USR_BTN_EV_SINGLE_CLICK = 2, // 单击事件 47 | USR_BTN_EV_DOUBLE_CLICK, // 双击事件 48 | USR_BTN_EV_MORE_CLICK, // 多击事件 49 | USR_BTN_EV_LONG_CLICK, // 长按事件 50 | }; 51 | 52 | // 按键事件数据 53 | struct btn_ev_data { 54 | enum usr_btn_ev ev_type; /* 按键的事件类型 */ 55 | uint32_t clicks; /* 按下的次数 */ 56 | }; 57 | 58 | enum button_level { 59 | BUTTON_LEVEL_LOW, // 低电平有效 60 | BUTTON_LEVEL_HIGH, // 高电平有效 61 | }; 62 | 63 | typedef void (*btn_usr_cb)(const struct btn_ev_data *ev_data); // 按键事件回调 64 | 65 | // 按键配置结构体 66 | struct btn_cfg { 67 | uint8_t (*f_io_read)(void); /* 读 IO 回调 */ 68 | uint32_t long_min_cnt; /* 按下按键切换到长按事件最少维持的周期次数 */ 69 | uint32_t up_max_cnt; /* 按键弹起到再次按下事件最多维持的周期次数 */ 70 | enum button_level active_lv; /* 按下的有效电平 */ 71 | }; 72 | 73 | /** 74 | * @brief 创建按键实例 75 | * 76 | * @param p_cfg 参数配置 77 | * @param cb 按键事件回调 78 | * @return btn_handle 成功返回句柄,失败时返回 NULL 79 | */ 80 | btn_handle button_ctor(const struct btn_cfg *p_cfg, btn_usr_cb cb); 81 | 82 | /** 83 | * @brief 销毁按键实例,释放资源 84 | * 85 | * @param btn 按键句柄 86 | */ 87 | void button_destroy(btn_handle btn); 88 | 89 | /** 90 | * @brief 对按键进行扫描,需要由调用方周期性执行,这个周期一般设定为按键的防抖间隔 91 | * 92 | * @param btn 按键句柄 93 | */ 94 | void button_scan(btn_handle btn); 95 | 96 | #endif /* __VIRTUAL_OS_BUTTON_H__ */ 97 | -------------------------------------------------------------------------------- /include/utils/crc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file crc.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief CRC校验 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_CRC_H__ 34 | #define __VIRTUAL_OS_CRC_H__ 35 | 36 | #define VIRTUAL_OS_CRC_EN 37 | 38 | #ifdef VIRTUAL_OS_CRC_EN 39 | 40 | #include 41 | 42 | uint16_t crc16_update(uint16_t crc, uint8_t data); 43 | uint16_t crc16_update_bytes(uint16_t crc, uint8_t *data, uint32_t len); 44 | 45 | #endif /* VIRTUAL_OS_CRC_EN */ 46 | 47 | #endif /* __VIRTUAL_OS_CRC_H__ */ -------------------------------------------------------------------------------- /include/utils/h_tree.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file h_tree.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 5 | * @version 1.0 6 | * @date 2024-08-20 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUALOS_H_TREE_H__ 34 | #define __VIRTUALOS_H_TREE_H__ 35 | 36 | #include 37 | #include 38 | 39 | struct tree_node { 40 | struct tree_node *parent; // 父节点 41 | struct tree_node *first_child; // 子节点 42 | struct tree_node *next_sibling; // 兄弟节点 43 | struct tree_node *last_child; // 最后一个子节点 44 | }; 45 | 46 | typedef void (*visit_func)(struct tree_node *node); /* 访问函数 */ 47 | 48 | /** 49 | * @brief 初始化树节点 50 | * 51 | * @param node 树节点 52 | * @return bool 返回 true 表示初始化成功,false 表示失败 53 | */ 54 | bool init_tree_node(struct tree_node *node); 55 | 56 | /** 57 | * @brief 创建新节点 58 | * 59 | * @return struct tree_node* 返回节点指针,失败返回 NULL 60 | */ 61 | struct tree_node *create_tree_node(void); 62 | 63 | /** 64 | * @brief 添加 child 到 parent 的子节点列表中 65 | * 66 | * @param parent 父节点 67 | * @param child 子节点 68 | * @return bool 69 | */ 70 | bool add_tree_child(struct tree_node *parent, struct tree_node *child); 71 | 72 | /** 73 | * @brief 递归销毁树节点 74 | * 75 | * @param node 树节点 76 | */ 77 | void destroy_tree_node(struct tree_node *node, visit_func visit); 78 | 79 | /** 80 | * @brief 删除 parent 节点的 child 子节点 81 | * 82 | * @param parent 父节点 83 | * @param child 子节点 84 | * @param visit 访问函数(释放资源等) 85 | * @return bool 86 | */ 87 | bool remove_tree_child(struct tree_node *parent, struct tree_node *child, visit_func visit); 88 | 89 | /** 90 | * @brief 遍历树,深度优先遍历 91 | * 92 | * @param root 根节点 93 | * @param visit 访问函数(打印节点等) 94 | */ 95 | void traverse_tree_dfs(struct tree_node *root, visit_func visit); 96 | 97 | /** 98 | * @brief 遍历树,广度优先遍历 99 | * 100 | * @param root 根节点 101 | * @param visit 访问函数(打印节点等) 102 | */ 103 | void traverse_tree_bfs(struct tree_node *root, visit_func visit); 104 | 105 | /** 106 | * @brief 获取树的根节点 107 | * 108 | * @param node 树节点 109 | * @return 110 | */ 111 | struct tree_node *get_tree_root(struct tree_node *node); 112 | 113 | #endif /* __VIRTUALOS_H_TREE_H__ */ -------------------------------------------------------------------------------- /include/utils/list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file list.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 双向循环链表组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_LIST_H__ 34 | #define __VIRTUAL_OS_LIST_H__ 35 | 36 | #include 37 | #include 38 | 39 | typedef struct list_item { 40 | struct list_item *pre; 41 | struct list_item *next; 42 | } list_item; 43 | 44 | #define container_of(ptr, type, member) \ 45 | ({ \ 46 | const typeof(((type *)0)->member) *__mptr = (ptr); \ 47 | (type *)((char *)__mptr - offsetof(type, member)); \ 48 | }) 49 | 50 | #define list_for_each_safe(pos, n, head) for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next) 51 | 52 | /** 53 | * @brief 链表初始化 54 | * 55 | * @param head 56 | */ 57 | void list_init(list_item *head); 58 | 59 | /** 60 | * @brief 删除节点 61 | * 62 | * @param item 63 | * @return uint8_t 64 | */ 65 | uint8_t list_delete_item(list_item *item); 66 | 67 | /** 68 | * @brief 删除尾结点 69 | * 70 | * @param head 71 | * @return list_item* 72 | */ 73 | list_item *list_delete_tail(list_item *head); 74 | 75 | /** 76 | * @brief 加入尾结点 77 | * 78 | * @param head 79 | * @param item 80 | * @return uint8_t 81 | */ 82 | uint8_t list_add_tail(list_item *head, list_item *item); 83 | 84 | #endif /* __VIRTUAL_OS_LIST_H__ */ 85 | -------------------------------------------------------------------------------- /include/utils/log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file log.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 日志组件 5 | * @version 0.1 6 | * @date 2024-12-27 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_LOG_H__ 34 | #define __VIRTUAL_OS_LOG_H__ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #define USE_TIME_STAMP 0 /* 日志启用时显示时间,0为关闭,1为启用 开启会编译time.h头文件,将占用大量FLASH空间 */ 41 | #define MAX_LOG_LENGTH 256 /* 每条日志的最大长度 */ 42 | #define TOTAL_FRAME_COUNT (8) // 缓冲8条 43 | #define LOG_BUFFER_SIZE (MAX_LOG_LENGTH * TOTAL_FRAME_COUNT) /* 日志缓冲区总大小 2K */ 44 | 45 | typedef size_t (*log_write)(uint8_t *buf, size_t len); // 发送接口 46 | 47 | enum log_level { 48 | LOG_LEVEL_ALL = 0, /* 所有日志 */ 49 | LOG_LEVEL_DEBUG = 1, /* 调试日志 */ 50 | LOG_LEVEL_INFO = 2, /* 信息日志 */ 51 | LOG_LEVEL_WARN = 3, /* 警告日志 */ 52 | LOG_LEVEL_ERROR = 4, /* 错误日志 */ 53 | LOG_LEVEL_NONE = 5 /* 关闭日志 */ 54 | }; 55 | 56 | /** 57 | * @brief 日志发送 可以通过掩码过滤日志 建议使用宏定义 58 | * 59 | * @param mask 模块掩码 60 | * @param level 日志等级 61 | * @param line 行号 62 | * @param format 日志格式 63 | * @param ... 可变参数 64 | */ 65 | void origin_log(uint32_t mask, enum log_level level, int line, const char *format, ...); 66 | 67 | /** 68 | * @brief 修改输出接口 69 | * 70 | * @param interface 新的读写接口 71 | */ 72 | void modify_output(log_write f_write); 73 | 74 | /** 75 | * @brief 填充模块名称数组 按照掩码从小到大排序 模块名的索引就是实际的掩码位 76 | * 结束后 module_buf_size 指向实际填充的模块个数 77 | * @param module_buf 78 | * @param module_buf_size 79 | */ 80 | void fill_module_names(char *module_buf[], uint8_t *module_buf_size); 81 | 82 | /* 设置系统时间戳 */ 83 | void syslog_set_time(uint32_t timestamp); 84 | 85 | /* 获取系统当前时间戳 */ 86 | uint32_t syslog_get_time(void); 87 | 88 | /* 设置日志等级 */ 89 | void syslog_set_level(enum log_level level); 90 | 91 | // 设置日志模块掩码 92 | void set_log_module_mask(uint32_t mask); 93 | 94 | // 获取日志模块掩码 95 | uint32_t get_log_module_mask(void); 96 | 97 | // 启用全部模块日志 98 | void enable_all_mask(void); 99 | 100 | // 日志回调接口 101 | 102 | /****************************************关键接口****************************************/ 103 | 104 | /** 105 | * @brief 日志初始化 106 | * 107 | * @param f_write 日志输出接口 108 | * @param period_ms 任务周期(毫秒) 109 | */ 110 | void syslog_init(log_write f_write, uint32_t period_ms); 111 | 112 | /** 113 | * @brief 日志任务 114 | * 115 | */ 116 | void syslog_task(void); 117 | 118 | /** 119 | * @brief 申请日志模块掩码 120 | * 121 | * @param module_name 模块名(必须是全局变量) 122 | * @return uint32_t 123 | */ 124 | uint32_t allocate_log_mask(const char * const module_name); 125 | 126 | /* 日志宏定义 */ 127 | // 注意提前通过`allocate_log_mask`获取一个模块掩码 128 | #define log_d(_mask, format, ...) origin_log(_mask, LOG_LEVEL_DEBUG, __LINE__, format, ##__VA_ARGS__) /* 调试日志 */ 129 | #define log_i(_mask, format, ...) origin_log(_mask, LOG_LEVEL_INFO, __LINE__, format, ##__VA_ARGS__) /* 信息日志 */ 130 | #define log_w(_mask, format, ...) origin_log(_mask, LOG_LEVEL_WARN, __LINE__, format, ##__VA_ARGS__) /* 警告日志 */ 131 | #define log_e(_mask, format, ...) origin_log(_mask, LOG_LEVEL_ERROR, __LINE__, format, ##__VA_ARGS__) /* 错误日志 */ 132 | 133 | #endif /* __VIRTUAL_OS_LOG_H__ */ 134 | -------------------------------------------------------------------------------- /include/utils/qfsm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file qfsm.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 状态机组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_QFSM_H__ 34 | #define __VIRTUAL_OS_QFSM_H__ 35 | 36 | #include 37 | 38 | typedef uint32_t qsignal_t; 39 | typedef int qstate; 40 | 41 | typedef struct _qeventtag { 42 | qsignal_t sig; 43 | } qevent_t; 44 | 45 | typedef struct qfsmtag qfsm_t; 46 | 47 | typedef qstate (*qstate_handler)(qfsm_t *me, qevent_t const *e); 48 | 49 | struct qfsmtag { 50 | qstate_handler state; 51 | }; 52 | 53 | enum q_event_result { 54 | Q_EVENT_HANDLED = (qstate)0, 55 | Q_EVENT_IGNORED, 56 | Q_EVENT_TRAN, 57 | }; 58 | 59 | #define Q_HANDLED() (Q_EVENT_HANDLED) 60 | #define Q_IGNORED() (Q_EVENT_IGNORED) 61 | #define Q_TRAN(target_) (((qfsm_t *)me)->state = (qstate_handler)(target_), Q_EVENT_TRAN) 62 | 63 | enum q_reserve_signal { 64 | Q_EMPTY_SIG = (qsignal_t)0, 65 | Q_ENTRY_SIG, 66 | Q_EXIT_SIG, 67 | Q_INIT_SIG, 68 | 69 | /*自定义信号区域*/ 70 | Q_APP_EVENT_TIMEOUT, 71 | }; 72 | 73 | /** 74 | * @brief 状态机初始化 75 | * 76 | * @param me 状态机实例 77 | * @param f_initial 初始化状态 78 | * @param e 事件 79 | */ 80 | void qfsm_init(qfsm_t *me, qstate_handler f_initial, qevent_t const *e); 81 | 82 | /** 83 | * @brief 状态机调度 84 | * 85 | * @param me 状态机实例 86 | * @param e 事件 87 | */ 88 | void qfsm_dispatch(qfsm_t * const me, qevent_t const *e); 89 | 90 | #endif /* __VIRTUAL_OS_QFSM_H__ */ 91 | -------------------------------------------------------------------------------- /include/utils/queue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file queue.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 循环队列组件 5 | * @version 0.1 6 | * @date 2024-12-19 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_QUEUE_H__ 34 | #define __VIRTUAL_OS_QUEUE_H__ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | /** 41 | * @brief 循环队列结构体 42 | */ 43 | struct queue_info { 44 | void *buf; /* 缓冲区 */ 45 | size_t unit_bytes; /* 单元大小(字节数) */ 46 | size_t buf_size; /* 缓冲区容量(单位数) */ 47 | size_t rd; /* 读索引 */ 48 | size_t wr; /* 写索引 */ 49 | }; 50 | 51 | /** 52 | * @brief 初始化队列 53 | * 54 | * @param q 指向队列实例的指针(由用户分配内存) 55 | * @param unit_bytes 每个单元的字节数 56 | * @param buf 指向预分配缓冲区的指针 57 | * @param units 缓冲区容量(单元数) 58 | * @return true 成功,false 失败 59 | */ 60 | bool queue_init(struct queue_info *q, size_t unit_bytes, void *buf, size_t units); 61 | 62 | /** 63 | * @brief 销毁队列并释放资源 64 | * 65 | * @param q 指向队列实例的指针 66 | */ 67 | void queue_destroy(struct queue_info *q); 68 | 69 | /** 70 | * @brief 重置清空队列 71 | * 72 | * @param q 指向队列实例的指针 73 | */ 74 | void queue_reset(struct queue_info *q); 75 | 76 | /** 77 | * @brief 向队列中添加数据 78 | * 79 | * @param q 指向队列实例的指针 80 | * @param data 指向要添加的数据的指针 81 | * @param units 要添加的单元数 82 | * @return size_t 成功添加的单元数 83 | */ 84 | size_t queue_add(struct queue_info *q, void *data, size_t units); 85 | 86 | /** 87 | * @brief 从队列中获取数据 88 | * 89 | * @param q 指向队列实例的指针 90 | * @param data 指向存储获取数据的缓冲区的指针 91 | * @param units 要获取的单元数 92 | * @return size_t 成功获取的单元数 93 | */ 94 | size_t queue_get(struct queue_info *q, void *data, size_t units); 95 | 96 | /** 97 | * @brief 查看队列中的数据,但不移除 98 | * 99 | * @param q 指向队列实例的指针 100 | * @param data 指向存储查看数据的缓冲区的指针 101 | * @param units 要查看的单元数 102 | * @return size_t 成功查看的单元数 103 | */ 104 | size_t queue_peek(struct queue_info *q, void *data, size_t units); 105 | 106 | /** 107 | * @brief 判断队列是否为空 108 | * 109 | * @param q 指向队列实例的指针 110 | * @return true 如果队列为空,false 否则 111 | */ 112 | bool is_queue_empty(struct queue_info *q); 113 | 114 | /** 115 | * @brief 判断队列是否已满 116 | * 117 | * @param q 指向队列实例的指针 118 | * @return true 如果队列已满,false 否则 119 | */ 120 | bool is_queue_full(struct queue_info *q); 121 | 122 | /** 123 | * @brief 获取队列中已使用的单元数 124 | * 125 | * @param q 指向队列实例的指针 126 | * @return size_t 已使用的单元数 127 | */ 128 | size_t queue_used(struct queue_info *q); 129 | 130 | /** 131 | * @brief 获取队列中剩余的可用单元数 132 | * 133 | * @param q 指向队列实例的指针 134 | * @return size_t 剩余的单元数 135 | */ 136 | size_t queue_remain_space(struct queue_info *q_const); 137 | 138 | /** 139 | * @brief 进阶读取索引 140 | * 141 | * @param q 指向队列实例的指针 142 | * @param units 要前进的单元数 143 | */ 144 | void queue_advance_rd(struct queue_info *q, size_t units); 145 | 146 | /** 147 | * @brief 进阶写入索引 148 | * 149 | * @param q 指向队列实例的指针 150 | * @param units 要前进的单元数 151 | */ 152 | void queue_advance_wr(struct queue_info *q, size_t units); 153 | 154 | #endif /* __VIRTUAL_OS_QUEUE_H__ */ 155 | -------------------------------------------------------------------------------- /include/utils/simple_shell.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file simple_shell.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 简易shell 5 | * @version 1.0 6 | * @date 2024-08-19 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | // 34 | 35 | #ifndef __VIRTUAL_OS_SIMPLE_SHELL_H__ 36 | #define __VIRTUAL_OS_SIMPLE_SHELL_H__ 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #define HISTORY_SIZE 10 // 历史记录最大数量 43 | #define SPS_CMD_MAX 64 // 单条命令最大长度 44 | #define SPS_CMD_MAX_ARGS 4 // 单条命令的最大参数数量 45 | #define MAX_COMMANDS 16 // 系统可注册命令的最大数量 46 | #define MAX_OUT_LEN 512 // 命令输出缓冲区长度 47 | 48 | // 1:启用 0:不启用 49 | #define SPS_ENABLE_TAB_COMPLETE (1) // 启用tab自动补全功能 50 | #define SPS_ENABLE_HISTORY (1) // 启用历史记录功能 上下箭头可切换历史记录 51 | 52 | /** 53 | * @brief 命令回调函数 54 | * @param argc 参数数量 55 | * @param argv 参数列表 56 | * @param out 输出缓冲区 57 | * @param buffer_size 输出缓冲区大小 58 | * @param usr_out_len 实际写入输出缓冲区的字节数 59 | */ 60 | typedef void (*sp_shell_cb)(int argc, char *argv[], uint8_t *out, size_t buffer_size, size_t *usr_out_len); 61 | 62 | /** 63 | * @brief Shell命令结构体 64 | */ 65 | struct sp_shell_cmd_t { 66 | const char *name; /* 命令名 */ 67 | sp_shell_cb cb; /* 命令回调函数 */ 68 | const char *description; /* 命令描述信息 */ 69 | }; 70 | 71 | /** 72 | * @brief 读写回调接口 73 | */ 74 | struct sp_shell_opts { 75 | size_t (*read)(uint8_t *buf, size_t len); /* 读函数指针 */ 76 | size_t (*write)(uint8_t *buf, size_t len); /* 写函数指针 */ 77 | }; 78 | 79 | /** 80 | * @brief shell初始化 81 | * 82 | * @param opts 回调接口 83 | * @param welcome 自定义欢迎语,NULL则为默认值 84 | * @return true 85 | * @return false 86 | */ 87 | bool simple_shell_init(struct sp_shell_opts *opts, const char *welcome); 88 | 89 | /** 90 | * @brief 启动调度 91 | * 92 | */ 93 | void shell_dispatch(void); 94 | 95 | // 命令注册宏 96 | #define SPS_EXPORT_CMD(_name, _callback, _description) \ 97 | const struct sp_shell_cmd_t shell_cmd_##_name = { \ 98 | .name = #_name, \ 99 | .cb = _callback, \ 100 | .description = _description, \ 101 | }; \ 102 | __attribute__((constructor)) static void register_##_name(void) \ 103 | { \ 104 | extern const struct sp_shell_cmd_t *command_list[MAX_COMMANDS]; \ 105 | extern int command_count; \ 106 | if (command_count < MAX_COMMANDS) \ 107 | command_list[command_count++] = (struct sp_shell_cmd_t *)&shell_cmd_##_name; \ 108 | } 109 | 110 | #endif /* __VIRTUAL_OS_SIMPLE_SHELL_H__ */ -------------------------------------------------------------------------------- /include/utils/soft_iic.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file soft_iic.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 软件IIC组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_SOFT_IIC_H__ 34 | #define __VIRTUAL_OS_SOFT_IIC_H__ 35 | 36 | #include 37 | 38 | enum soft_iic_level { 39 | iic_low = 0, 40 | iic_high = !iic_low, 41 | }; 42 | 43 | typedef void (*soft_iic_delay_f)(uint8_t m_us); 44 | typedef void (*soft_iic_scl_out_f)(enum soft_iic_level level); 45 | typedef void (*soft_iic_sda_out_f)(enum soft_iic_level level); 46 | typedef uint8_t (*soft_iic_sda_in_f)(void); 47 | 48 | uint8_t soft_iic_write_one_byte(uint8_t addr, uint8_t reg, uint8_t data); 49 | uint8_t soft_iic_write_bytes(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf); 50 | uint8_t soft_iic_read_bytes(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf); 51 | 52 | /** 53 | * 软件iic初始化,成功返回1,失败返回0 54 | * @param scl_out_f scl输出函数 55 | * @param sda_out_f sda输出函数 56 | * @param sda_in_f sda读取函数 57 | * @param delay_f us级延时函数,没有设置为NULL 58 | * 59 | * @return 0 or 1 60 | */ 61 | uint8_t soft_iic_init( 62 | soft_iic_scl_out_f scl_out_f, soft_iic_sda_out_f sda_out_f, soft_iic_sda_in_f sda_in_f, soft_iic_delay_f delay_f); 63 | 64 | #endif /* __VIRTUAL_OS_SOFT_IIC_H__ */ 65 | -------------------------------------------------------------------------------- /include/utils/stimer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stimer.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 前后台调度组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_STIMER_H__ 34 | #define __VIRTUAL_OS_STIMER_H__ 35 | 36 | #define STIMER_PERIOD_PER_TICK_MS (1) 37 | 38 | #include 39 | #include 40 | 41 | /**************************************系统API**************************************/ 42 | 43 | typedef void (*stimer_timeout_process)(void); 44 | typedef void (*stimer_base_init)(uint32_t period_ms, stimer_timeout_process f_timeout); 45 | typedef void (*stimer_base_start)(void); 46 | 47 | typedef void (*stimer_f)(void); 48 | 49 | struct timer_port { 50 | volatile stimer_base_init f_init; 51 | volatile stimer_base_start f_start; 52 | }; 53 | 54 | /** 55 | * @brief 调度定时器初始化 56 | * 57 | * @param port 提供一个 定时器的初始化函数和启动函数 58 | * @return bool 成功返回true,失败返回false 59 | */ 60 | bool stimer_init(struct timer_port *port); 61 | 62 | /**************************************用户可用API**************************************/ 63 | 64 | /** 65 | * @brief 创建周期任务 66 | * 67 | * @param init_f 初始化函数指针 68 | * @param task_f 任务函数指针 69 | * @param period_ms 任务周期,单位毫秒 70 | * @return bool 成功返回true,失败返回false 71 | */ 72 | bool stimer_task_create(stimer_f init_f, stimer_f task_f, uint32_t period_ms); 73 | 74 | /** 75 | * @brief 运行时创建单次任务 76 | * 77 | * @param task_f 任务函数指针 78 | * @param ms 指定毫秒后执行 79 | * @return bool 成功返回true,失败返回false 80 | */ 81 | bool defer_task_create(stimer_f task_f, uint32_t ms); 82 | 83 | /** 84 | * @brief 开启调度 85 | * 86 | */ 87 | void stimer_start(void); 88 | 89 | #endif /* __VIRTUAL_OS_STIMER_H__ */ 90 | -------------------------------------------------------------------------------- /include/utils/string_hash.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file string_hash.h 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 字符串哈希组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #ifndef __VIRTUAL_OS_STRING_HASH_H__ 34 | #define __VIRTUAL_OS_STRING_HASH_H__ 35 | 36 | #include 37 | #include 38 | #include "utils/list.h" 39 | 40 | enum hash_error { 41 | HASH_KEY_NOT_FOUND = -2, // 键不存在 42 | HASH_POINT_ERROR, // 指针错误 43 | HASH_SUCCESS, // 无错误 44 | }; 45 | 46 | struct string_hash_node { 47 | char *key; 48 | void *private; 49 | list_item list; 50 | }; 51 | 52 | struct hash_table { 53 | list_item *table; 54 | size_t table_size; 55 | }; 56 | 57 | /** 58 | * @brief 哈希表初始化 59 | * 60 | * @param hash_table 一个实例 61 | * @param table_size 哈希表大小,建议为所有需要哈希处理的键大小的2-3倍 62 | * @return enum hash_error 错误码 63 | */ 64 | enum hash_error init_hash_table(struct hash_table *hash_table, size_t table_size); 65 | 66 | /** 67 | * @brief 哈希插入 68 | * 69 | * @param hash_table 表实例 70 | * @param key 字符串 71 | * @param private 需要存储数据的指针 72 | * @return enum hash_error 错误码 73 | */ 74 | enum hash_error hash_insert(struct hash_table *hash_table, const char *key, void *private); 75 | 76 | /** 77 | * @brief 哈希查找 78 | * 79 | * @param hash_table 表实例 80 | * @param key 字符串 81 | * @param error 错误码,不考虑设为NULL 82 | * @return void* 返回存储的指针,自行强转 83 | */ 84 | void *hash_find(struct hash_table *hash_table, const char *key, enum hash_error *error); 85 | 86 | /** 87 | * @brief 删除哈希键 88 | * 89 | * @param hash_table 表实例 90 | * @param key 字符串 91 | * @return enum hash_error 错误码 92 | */ 93 | enum hash_error hash_delete(struct hash_table *hash_table, const char *key); 94 | 95 | /** 96 | * @brief 获取哈希表中所有的键 97 | * 98 | * @param hash_table 表实例 99 | * @param keys 输出参数,用于存储所有的键 100 | * @param num_keys 输出参数,用于返回键的数量 101 | * @return enum hash_error 错误码 102 | */ 103 | enum hash_error hash_get_all_keys(struct hash_table *hash_table, char ***keys, size_t *num_keys); 104 | 105 | /** 106 | * @brief 删除表 107 | * 108 | * @param hash_table 109 | */ 110 | void destroy_hash_table(struct hash_table *hash_table); 111 | 112 | #endif /* __VIRTUAL_OS_STRING_HASH_H__ */ -------------------------------------------------------------------------------- /toolchain.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | set(CMAKE_SYSTEM_PROCESSOR cortex-m0) # 关键修改部分 3 | 4 | set(COMPILER_FLAGS 5 | -mcpu=${CMAKE_SYSTEM_PROCESSOR} 6 | -mthumb 7 | -mthumb-interwork 8 | -ffunction-sections 9 | -fdata-sections 10 | -fno-common 11 | -fmessage-length=0 12 | ) 13 | 14 | set(CMAKE_C_COMPILER "arm-none-eabi-gcc" CACHE STRING "C Compiler" FORCE) 15 | set(CMAKE_CXX_COMPILER "arm-none-eabi-g++" CACHE STRING "C++ Compiler" FORCE) 16 | set(CMAKE_ASM_COMPILER "arm-none-eabi-gcc" CACHE STRING "ASM Compiler" FORCE) 17 | set(CMAKE_AR "arm-none-eabi-ar" CACHE STRING "Archiver" FORCE) 18 | set(CMAKE_OBJCOPY "arm-none-eabi-objcopy" CACHE STRING "Objcopy" FORCE) 19 | set(CMAKE_OBJDUMP "arm-none-eabi-objdump" CACHE STRING "Objdump" FORCE) 20 | set(CMAKE_SIZE "arm-none-eabi-size" CACHE STRING "Size" FORCE) 21 | 22 | set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) 23 | 24 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 25 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 26 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -------------------------------------------------------------------------------- /utils/README.md: -------------------------------------------------------------------------------- 1 | ## 工具(utils) 2 | 3 | ### button 4 | - 按键组件 5 | 6 | ### crc 7 | - crc校验 8 | 9 | ### h_tree 10 | - 层次树组件 11 | 12 | ### hash 13 | - 哈希组件 14 | 15 | ### list 16 | - 双向循环链表组件 17 | 18 | ### qfsm 19 | - 有限状态机组件 20 | 21 | ### queue 22 | - 循环队列组件 23 | 24 | ### simple_shell 25 | - 简易的Shell组件 26 | 27 | ### soft_iic 28 | - 软件IIC组件 29 | 30 | ### stimer 31 | - 调度组件 32 | 33 | ## 许可证 34 | 35 | The MIT License (MIT) 36 | 37 | Permission is hereby granted, free of charge, to any person obtaining a copy 38 | of this software and associated documentation files (the "Software"), to deal 39 | in the Software without restriction, including without limitation the rights 40 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 41 | copies of the Software, and to permit persons to whom the Software is 42 | furnished to do so, subject to the following conditions: 43 | 44 | The above copyright notice and this permission notice shall be included in 45 | all copies or substantial portions of the Software. 46 | 47 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 48 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 49 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 50 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 51 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 52 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 53 | THE SOFTWARE. -------------------------------------------------------------------------------- /utils/button.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file button.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 按键组件 5 | * @version 0.1 6 | * @date 2024-12-27 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, virtual_os_free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | 36 | #include "utils/button.h" 37 | #include "core/virtual_os_mm.h" 38 | 39 | struct button_jitter { 40 | uint8_t previous; 41 | uint8_t asserted; 42 | }; 43 | 44 | enum btn_io_event { 45 | BTN_IO_EVENT_UP, // 按键弹起 46 | BTN_IO_EVENT_DOWN, // 按键按下 47 | }; 48 | 49 | typedef enum usr_btn_ev (*on_state_handler)(btn_handle handle, enum btn_io_event io_ev); 50 | 51 | struct button_state { 52 | on_state_handler state; // 当前状态 53 | struct button_jitter jit; // 抖动处理 54 | uint32_t click_cnt; // 点击次数计数 55 | uint32_t counter; // 状态计数器 56 | }; 57 | 58 | struct button { 59 | struct btn_cfg cfg; // 按键配置 60 | struct button_state state; // 按键状态 61 | btn_usr_cb f_ev_cb; // 按键事件回调 62 | }; 63 | 64 | static enum usr_btn_ev on_idle_handler(btn_handle handle, enum btn_io_event io_ev); // 空闲状态 65 | static enum usr_btn_ev on_up_handler(btn_handle handle, enum btn_io_event io_ev); // 弹起状态 66 | static enum usr_btn_ev on_down_handler(btn_handle handle, enum btn_io_event io_ev); // 按下状态 67 | static enum usr_btn_ev on_up_suspense_handler(btn_handle handle, enum btn_io_event io_ev); // 悬挂等待状态 68 | static enum usr_btn_ev on_down_short_handler(btn_handle handle, enum btn_io_event io_ev); // 短按状态 69 | static enum usr_btn_ev on_down_long_handler(btn_handle handle, enum btn_io_event io_ev); // 长按状态 70 | 71 | /** 72 | * @brief 分发点击类型事件,根据点击次数返回相应的按键事件 73 | * 74 | * @param click_cnt 点击次数 75 | * @return 对应的按键事件 76 | */ 77 | static inline enum usr_btn_ev dispatch_click_type(uint32_t click_cnt) 78 | { 79 | static const enum usr_btn_ev click_type[] = { 80 | USR_BTN_EV_NONE, // 无事件 81 | USR_BTN_EV_SINGLE_CLICK, // 单击事件 82 | USR_BTN_EV_DOUBLE_CLICK, // 双击事件 83 | }; 84 | 85 | if (click_cnt < sizeof(click_type) / sizeof(click_type[0])) 86 | return click_type[click_cnt]; 87 | else 88 | return USR_BTN_EV_MORE_CLICK; // 多次点击事件 89 | } 90 | 91 | // 空闲状态 92 | static enum usr_btn_ev on_idle_handler(btn_handle handle, enum btn_io_event io_ev) 93 | { 94 | if (io_ev == BTN_IO_EVENT_DOWN) { 95 | handle->state.counter = 0; 96 | handle->state.click_cnt = 1; 97 | handle->state.state = on_down_handler; // 被按下 98 | } 99 | 100 | return USR_BTN_EV_NONE; 101 | } 102 | 103 | // 按下状态 104 | static enum usr_btn_ev on_down_handler(btn_handle handle, enum btn_io_event io_ev) 105 | { 106 | enum usr_btn_ev ev = USR_BTN_EV_NONE; 107 | 108 | if (io_ev == BTN_IO_EVENT_UP) { 109 | ev = USR_BTN_EV_POPUP; 110 | handle->state.counter = 0; 111 | handle->state.state = on_up_suspense_handler; // 等待判断后续是否还有点击事件 112 | } else { 113 | if (++handle->state.counter >= handle->cfg.long_min_cnt) { 114 | // 按下超过最大长按时间 115 | ev = USR_BTN_EV_LONG_CLICK; 116 | handle->state.counter = 0; 117 | handle->state.state = on_down_long_handler; 118 | } 119 | } 120 | 121 | return ev; 122 | } 123 | 124 | // 悬挂等待状态 125 | static enum usr_btn_ev on_up_suspense_handler(btn_handle handle, enum btn_io_event io_ev) 126 | { 127 | enum usr_btn_ev ev = USR_BTN_EV_NONE; 128 | 129 | // 弹起 130 | if (io_ev == BTN_IO_EVENT_UP) { 131 | if (++handle->state.counter >= handle->cfg.up_max_cnt) { 132 | // 弹起一定时间后不再按下 133 | handle->state.counter = 0; 134 | ev = dispatch_click_type(handle->state.click_cnt); 135 | handle->state.state = on_up_handler; 136 | } 137 | } else { 138 | handle->state.counter = 0; 139 | ++handle->state.click_cnt; 140 | handle->state.state = on_down_short_handler; // 又继续按下 141 | } 142 | 143 | return ev; 144 | } 145 | 146 | // 弹起状态 147 | static enum usr_btn_ev on_up_handler(btn_handle handle, enum btn_io_event io_ev) 148 | { 149 | if (io_ev == BTN_IO_EVENT_DOWN) { 150 | handle->state.counter = 0; 151 | handle->state.click_cnt = 1; 152 | handle->state.state = on_down_handler; 153 | } 154 | 155 | return USR_BTN_EV_NONE; 156 | } 157 | 158 | // 短按状态 159 | static enum usr_btn_ev on_down_short_handler(btn_handle handle, enum btn_io_event io_ev) 160 | { 161 | enum usr_btn_ev ev = USR_BTN_EV_NONE; 162 | 163 | if (io_ev == BTN_IO_EVENT_UP) { 164 | ev = USR_BTN_EV_POPUP; 165 | handle->state.counter = 0; 166 | handle->state.state = on_up_suspense_handler; // 又弹起了,等待判断后续是否还有点击事件 167 | } 168 | 169 | return ev; 170 | } 171 | 172 | // 长按状态 173 | static enum usr_btn_ev on_down_long_handler(btn_handle handle, enum btn_io_event io_ev) 174 | { 175 | enum usr_btn_ev ev = USR_BTN_EV_NONE; 176 | 177 | if (io_ev == BTN_IO_EVENT_UP) { 178 | ev = USR_BTN_EV_POPUP; 179 | handle->state.state = on_up_handler; 180 | } 181 | return ev; 182 | } 183 | 184 | // 消抖 185 | static inline uint8_t button_debounce(btn_handle handle) 186 | { 187 | uint8_t cur_lv = handle->cfg.f_io_read(); 188 | 189 | handle->state.jit.asserted |= (handle->state.jit.previous & cur_lv); 190 | handle->state.jit.asserted &= (handle->state.jit.previous | cur_lv); 191 | 192 | handle->state.jit.previous = cur_lv; 193 | 194 | return handle->state.jit.asserted; 195 | } 196 | 197 | // 按键初始化 198 | btn_handle button_ctor(const struct btn_cfg *p_cfg, btn_usr_cb cb) 199 | { 200 | if (!p_cfg || !p_cfg->f_io_read) 201 | return NULL; 202 | 203 | btn_handle handle = virtual_os_malloc(sizeof(struct button)); 204 | if (!handle) { 205 | return NULL; 206 | } 207 | 208 | handle->cfg = *p_cfg; 209 | handle->f_ev_cb = cb; 210 | 211 | handle->state.jit.previous = (p_cfg->active_lv == BUTTON_LEVEL_HIGH) ? 0 : 1; 212 | handle->state.jit.asserted = handle->state.jit.previous; 213 | 214 | // 初始化为 idle 状态 215 | handle->state.state = on_idle_handler; 216 | 217 | handle->state.click_cnt = 0; 218 | handle->state.counter = 0; 219 | 220 | return handle; 221 | } 222 | 223 | // 释放句柄 224 | void button_destroy(btn_handle handle) 225 | { 226 | if (handle) { 227 | virtual_os_free(handle); // 释放动态分配的按键结构体内存 228 | } 229 | } 230 | 231 | // 按键扫描 232 | void button_scan(btn_handle handle) 233 | { 234 | if (!handle || !handle->cfg.f_io_read || !handle->state.state) 235 | return; 236 | 237 | struct btn_ev_data ev; 238 | ev.ev_type = USR_BTN_EV_NONE; 239 | ev.clicks = 0; 240 | 241 | uint8_t cur_level = button_debounce(handle); // 当前有效电平 242 | 243 | if (cur_level == (handle->cfg.active_lv == BUTTON_LEVEL_HIGH ? 1 : 0)) 244 | ev.ev_type = handle->state.state(handle, BTN_IO_EVENT_DOWN); 245 | else 246 | ev.ev_type = handle->state.state(handle, BTN_IO_EVENT_UP); 247 | 248 | if (ev.ev_type != USR_BTN_EV_NONE && ev.ev_type != USR_BTN_EV_POPUP && handle->f_ev_cb) { 249 | ev.clicks = handle->state.click_cnt; 250 | handle->f_ev_cb(&ev); 251 | } 252 | 253 | return; 254 | } 255 | -------------------------------------------------------------------------------- /utils/crc.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file crc.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief CRC校验 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include "utils/crc.h" 34 | 35 | #ifdef VIRTUAL_OS_CRC_EN 36 | 37 | uint16_t const crc16_modbus_table[256] = { 38 | 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 39 | 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 40 | 0xda81, 0x1a40, 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641, 0xd201, 41 | 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 42 | 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 43 | 0x3840, 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40, 0xe401, 0x24c0, 44 | 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 45 | 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 46 | 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41, 0xbe01, 0x7ec0, 0x7f80, 47 | 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 48 | 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 49 | 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841, 0x8801, 0x48c0, 0x4980, 0x8941, 50 | 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 51 | 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040 52 | }; 53 | 54 | uint16_t crc16_update(uint16_t crc, uint8_t data) 55 | { 56 | return (crc >> 8) ^ crc16_modbus_table[(crc ^ data) & 0xff]; 57 | } 58 | 59 | uint16_t crc16_update_bytes(uint16_t crc, uint8_t *data, uint32_t len) 60 | { 61 | const uint8_t *p = data; 62 | uint16_t _crc = crc; 63 | 64 | for (uint32_t i = len; i > 0; i--) 65 | _crc = (_crc >> 8) ^ crc16_modbus_table[(_crc ^ *p++) & 0xff]; 66 | 67 | return _crc; 68 | } 69 | 70 | #endif /*_VIRTUAL_OS_CRC_EN*/ -------------------------------------------------------------------------------- /utils/h_tree.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file h_tree.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 5 | * @version 1.0 6 | * @date 2024-08-20 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, virtual_os_free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include "utils/h_tree.h" 35 | #include "core/virtual_os_mm.h" 36 | 37 | bool init_tree_node(struct tree_node *node) 38 | { 39 | if (node == NULL) 40 | return false; 41 | 42 | *node = (struct tree_node){ 0 }; 43 | 44 | return true; 45 | } 46 | 47 | struct tree_node *create_tree_node() 48 | { 49 | struct tree_node *node = (struct tree_node *)virtual_os_calloc(1, sizeof(struct tree_node)); 50 | if (node != NULL) { 51 | if (!init_tree_node(node)) { 52 | virtual_os_free(node); 53 | return NULL; 54 | } 55 | } 56 | return node; 57 | } 58 | 59 | /** 60 | * @brief 递归销毁树节点 61 | * 62 | * @param node 树节点 63 | */ 64 | void destroy_tree_node(struct tree_node *node, visit_func visit) 65 | { 66 | if (node == NULL) 67 | return; 68 | 69 | struct tree_node *child = node->first_child; 70 | while (child != NULL) { 71 | struct tree_node *next = child->next_sibling; 72 | destroy_tree_node(child, visit); 73 | child = next; 74 | } 75 | 76 | if (visit) 77 | visit(node); 78 | 79 | virtual_os_free(node); 80 | } 81 | 82 | bool add_tree_child(struct tree_node *parent, struct tree_node *child) 83 | { 84 | if (parent == NULL || child == NULL) 85 | return false; 86 | 87 | child->parent = parent; 88 | 89 | if (parent->first_child == NULL) { 90 | parent->first_child = child; 91 | parent->last_child = child; 92 | } else { 93 | parent->last_child->next_sibling = child; 94 | parent->last_child = child; 95 | } 96 | 97 | return true; 98 | } 99 | 100 | bool remove_tree_child(struct tree_node *parent, struct tree_node *child, visit_func visit) 101 | { 102 | if (parent == NULL || child == NULL) 103 | return false; 104 | 105 | struct tree_node *prev = NULL; 106 | struct tree_node *current = parent->first_child; 107 | 108 | while (current) { 109 | if (current == child) { 110 | if (prev) 111 | prev->next_sibling = current->next_sibling; 112 | else 113 | parent->first_child = current->next_sibling; 114 | 115 | if (parent->last_child == child) 116 | parent->last_child = prev; 117 | 118 | destroy_tree_node(child, visit); 119 | 120 | return true; 121 | } 122 | prev = current; 123 | current = current->next_sibling; 124 | } 125 | 126 | return false; 127 | } 128 | 129 | /* 深度优先遍历 */ 130 | void traverse_tree_dfs(struct tree_node *root, visit_func visit) 131 | { 132 | if (root == NULL || visit == NULL) 133 | return; 134 | 135 | visit(root); 136 | 137 | struct tree_node *child = root->first_child; 138 | while (child) { 139 | traverse_tree_dfs(child, visit); 140 | child = child->next_sibling; 141 | } 142 | } 143 | 144 | static size_t get_tree_node_count(struct tree_node *root) 145 | { 146 | if (root == NULL) 147 | return 0; 148 | 149 | size_t count = 1; 150 | 151 | struct tree_node *child = root->first_child; 152 | while (child) { 153 | count += get_tree_node_count(child); 154 | child = child->next_sibling; 155 | } 156 | 157 | return count; 158 | } 159 | 160 | /* 广度优先遍历 */ 161 | void traverse_tree_bfs(struct tree_node *root, visit_func visit) 162 | { 163 | if (root == NULL || visit == NULL) 164 | return; 165 | 166 | size_t node_count = get_tree_node_count(root); 167 | 168 | struct tree_node **queue = (struct tree_node **)virtual_os_calloc(node_count, sizeof(struct tree_node *)); 169 | if (queue == NULL) 170 | return; 171 | 172 | uint16_t front = 0; 173 | uint16_t rear = 0; 174 | 175 | queue[rear++] = root; 176 | 177 | while (front < rear) { 178 | struct tree_node *current = queue[front++]; 179 | 180 | visit(current); 181 | 182 | struct tree_node *child = current->first_child; 183 | while (child) { 184 | queue[rear++] = child; 185 | child = child->next_sibling; 186 | } 187 | } 188 | 189 | virtual_os_free(queue); 190 | } 191 | 192 | struct tree_node *get_tree_root(struct tree_node *node) 193 | { 194 | if (node == NULL) 195 | return NULL; 196 | 197 | while (node->parent) 198 | node = node->parent; 199 | 200 | return node; 201 | } 202 | -------------------------------------------------------------------------------- /utils/list.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file list.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 双向循环链表组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include "utils/list.h" 34 | 35 | void list_init(list_item *head) 36 | { 37 | head->next = head; 38 | head->pre = head; 39 | } 40 | 41 | static inline uint8_t is_head_valid(list_item *head) 42 | { 43 | return (head && head->next && head->pre); 44 | } 45 | 46 | static inline uint8_t is_head_empty(list_item *head) 47 | { 48 | return is_head_valid(head) ? (head->next == head) : 1; 49 | } 50 | 51 | static inline void list_insert(list_item *item, list_item *pre, list_item *next) 52 | { 53 | next->pre = item; 54 | item->next = next; 55 | item->pre = pre; 56 | pre->next = item; 57 | } 58 | 59 | static inline void list_delete(list_item *pre, list_item *next) 60 | { 61 | next->pre = pre; 62 | pre->next = next; 63 | } 64 | 65 | static inline void list_free(list_item *item) 66 | { 67 | item->next = NULL; 68 | item->pre = NULL; 69 | } 70 | 71 | uint8_t list_delete_item(list_item *item) 72 | { 73 | if (!item || !item->pre || !item->next) 74 | return 1; 75 | 76 | list_delete(item->pre, item->next); 77 | list_free(item); 78 | return 0; 79 | } 80 | 81 | list_item *list_delete_tail(list_item *head) 82 | { 83 | list_item *del = NULL; 84 | 85 | if (is_head_empty(head)) 86 | return NULL; 87 | 88 | del = head->next; 89 | list_delete(head->pre, head); 90 | list_free(del); 91 | return del; 92 | } 93 | 94 | uint8_t list_add_tail(list_item *head, list_item *item) 95 | { 96 | if (!is_head_valid(head) || !item) 97 | return 1; 98 | 99 | list_insert(item, head->pre, head); 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /utils/log.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file log.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 日志组件 5 | * @version 0.1 6 | * @date 2024-12-27 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "utils/log.h" 41 | #include "utils/queue.h" 42 | 43 | #if USE_TIME_STAMP 44 | #include 45 | #endif 46 | 47 | #define LOG_LEVEL_STR(level) \ 48 | ((level) == LOG_LEVEL_DEBUG ? "DEBUG" \ 49 | : (level) == LOG_LEVEL_INFO ? "INFO" \ 50 | : (level) == LOG_LEVEL_WARN ? "WARN" \ 51 | : (level) == LOG_LEVEL_ERROR ? "ERROR" \ 52 | : "XXXXX") 53 | 54 | static uint8_t log_buffer[LOG_BUFFER_SIZE]; /* 日志缓冲区 */ 55 | 56 | struct syslog_instance { 57 | log_write f_write; // 输出接口 58 | struct queue_info log_queue; // 日志队列 59 | uint32_t timestamp; // 时间戳 60 | uint32_t pre_time; // 时间戳计数 61 | uint32_t period_md; // 任务周期 62 | bool initialized; // 是否初始化 63 | enum log_level current_log_level; // 当前日志等级 64 | uint32_t module_mask; // 模块掩码 用于过滤日志 65 | uint8_t module_cnt; // 最多支持32个模块 66 | }; 67 | 68 | static const char *module_info[32] = { 0 }; // 所有模块信息 69 | 70 | static inline uint8_t mask_idx(uint32_t mask) 71 | { 72 | uint8_t idx = 0; 73 | while (mask) { 74 | if (mask & 1) 75 | return idx; 76 | mask >>= 1; 77 | idx++; 78 | } 79 | } 80 | 81 | static struct syslog_instance syslog = { 0 }; 82 | 83 | /** 84 | * @brief 检查日志实例是否有效 85 | * 86 | * @param instance 日志实例指针 87 | * @return true 有效 88 | * @return false 无效 89 | */ 90 | static bool check_instance(struct syslog_instance *instance) 91 | { 92 | return instance && instance->initialized && instance->f_write; 93 | } 94 | 95 | /** 96 | * @brief 向日志队列中写入日志 97 | * 98 | * @param instance 日志实例 99 | * @param buf 日志内容缓冲区 100 | * @param len 日志内容长度 101 | * @param mask 模块掩码 102 | * @return size_t 实际写入的字节数 103 | */ 104 | static size_t syslog_write(struct syslog_instance *instance, uint8_t *buf, size_t len, uint32_t mask) 105 | { 106 | if (!check_instance(instance)) 107 | return 0; 108 | 109 | #if USE_TIME_STAMP 110 | char time_buffer[64] = "NO_TIME"; 111 | 112 | time_t raw_time = (time_t)instance->timestamp; 113 | struct tm time_info; 114 | 115 | if (localtime_r(&raw_time, &time_info) != NULL) { 116 | strftime(time_buffer, sizeof(time_buffer), "[%Y-%m-%d %H:%M:%S]", &time_info); 117 | } else { 118 | snprintf(time_buffer, sizeof(time_buffer), "[NO_TIME]"); 119 | } 120 | 121 | char new_buf[MAX_LOG_LENGTH]; 122 | size_t new_len = snprintf(new_buf, sizeof(new_buf), "%s %.*s", time_buffer, (int)len, buf); 123 | 124 | if (new_len >= MAX_LOG_LENGTH) { 125 | // 如果日志长度超过最大长度,截断 126 | new_len = MAX_LOG_LENGTH - 1; 127 | // 移除手动添加 '\0' 128 | } 129 | 130 | // 使用 new_buf 作为要发送的日志内容 131 | buf = (uint8_t *)new_buf; 132 | len = new_len; 133 | #endif 134 | 135 | size_t total_len = len + sizeof(size_t) + sizeof(uint32_t); // 日志长度信息占用 4 字节 掩码信息占用 4 字节 136 | size_t remain_space = queue_remain_space(&instance->log_queue); 137 | 138 | if (remain_space < total_len) 139 | return 0; 140 | 141 | // 长度信息 142 | if (queue_add(&instance->log_queue, (uint8_t *)&len, sizeof(size_t)) != sizeof(size_t)) 143 | return 0; 144 | 145 | // 掩码信息 146 | if (queue_add(&instance->log_queue, (uint8_t *)&mask, sizeof(uint32_t)) != sizeof(uint32_t)) 147 | return 0; 148 | 149 | // 日志内容 150 | if (queue_add(&instance->log_queue, buf, len) != len) 151 | return 0; 152 | 153 | return len; 154 | } 155 | 156 | /** 157 | * @brief 日志显示 158 | * 159 | * @param instance 任务实例 160 | */ 161 | static void syslog_show(struct syslog_instance *instance) 162 | { 163 | if (!check_instance(instance)) 164 | return; 165 | 166 | #if USE_TIME_STAMP 167 | instance->pre_time += instance->period_md; 168 | 169 | if (instance->pre_time >= 1000) { 170 | instance->timestamp++; 171 | instance->pre_time = 0; 172 | } 173 | #endif 174 | 175 | while (!is_queue_empty(&instance->log_queue)) { 176 | // 日志长度信息 177 | size_t flush_len = 0; 178 | queue_get(&instance->log_queue, (uint8_t *)&flush_len, sizeof(size_t)); 179 | 180 | if (flush_len == 0 || flush_len > MAX_LOG_LENGTH) 181 | return; 182 | 183 | // 掩码信息 184 | uint32_t mask = 0; 185 | queue_get(&instance->log_queue, (uint8_t *)&mask, sizeof(uint32_t)); 186 | 187 | // 取出日志 188 | uint8_t tmp_buf[MAX_LOG_LENGTH]; 189 | queue_get(&instance->log_queue, tmp_buf, flush_len); 190 | if (syslog.module_mask & mask) 191 | instance->f_write(tmp_buf, flush_len); // 过滤掩码 192 | } 193 | } 194 | 195 | /** 196 | * @brief 填充模块名称数组 按照掩码从小到大排序 模块名的索引就是实际的掩码位 197 | * 结束后 module_buf_size 指向实际填充的模块个数 198 | * @param module_buf 199 | * @param module_buf_size 200 | */ 201 | void fill_module_names(char *module_buf[], uint8_t *module_buf_size) 202 | { 203 | size_t less = *module_buf_size < syslog.module_cnt ? *module_buf_size : syslog.module_cnt; 204 | *module_buf_size = less; 205 | for (size_t i = 0; i < less; i++) 206 | module_buf[i] = (char *)module_info[i]; 207 | } 208 | 209 | /** 210 | * @brief 日志发送 可以通过掩码过滤日志 211 | * 212 | * @param mask 模块掩码 213 | * @param level 日志等级 214 | * @param line 行号 215 | * @param format 日志格式 216 | * @param ... 可变参数 217 | */ 218 | void origin_log(uint32_t mask, enum log_level level, int line, const char *format, ...) 219 | { 220 | if (!check_instance(&syslog)) 221 | return; 222 | 223 | if (level < syslog.current_log_level) 224 | return; 225 | 226 | char buffer[MAX_LOG_LENGTH] = { 0 }; 227 | int len; 228 | va_list args; 229 | 230 | va_start(args, format); 231 | 232 | uint8_t module_idx = mask_idx(mask); 233 | if (module_idx >= syslog.module_cnt) 234 | return; 235 | 236 | len = snprintf( 237 | buffer, sizeof(buffer), "[%-5s] [%-10s] [%-4d] : ", LOG_LEVEL_STR(level), module_info[module_idx], line); 238 | 239 | if (len < 0) { 240 | // snprintf 出错 241 | va_end(args); 242 | return; 243 | } 244 | 245 | int remaining_space = MAX_LOG_LENGTH - len; 246 | 247 | if (remaining_space > 1) { 248 | int formatted_len = vsnprintf(buffer + len, remaining_space, format, args); 249 | if (formatted_len < 0) 250 | len = MAX_LOG_LENGTH - 1; 251 | else if (formatted_len >= remaining_space) 252 | len = MAX_LOG_LENGTH - 1; 253 | else 254 | len += formatted_len; 255 | } else 256 | len = MAX_LOG_LENGTH - 1; 257 | 258 | va_end(args); 259 | 260 | syslog_write(&syslog, (uint8_t *)buffer, len, mask); 261 | } 262 | 263 | // 设置日志模块掩码 264 | void set_log_module_mask(uint32_t mask) 265 | { 266 | syslog.module_mask = mask; 267 | } 268 | 269 | // 获取日志模块掩码 270 | uint32_t get_log_module_mask(void) 271 | { 272 | return syslog.module_mask; 273 | } 274 | 275 | // 启用全部模块日志 276 | void enable_all_mask(void) 277 | { 278 | for (size_t i = 0; i < syslog.module_cnt; i++) { 279 | uint32_t mask = 1 << i; 280 | syslog.module_mask |= mask; 281 | } 282 | } 283 | 284 | /** 285 | * @brief 设置日志等级 286 | * 287 | * @param level 日志等级 288 | */ 289 | void syslog_set_level(enum log_level level) 290 | { 291 | if (check_instance(&syslog)) 292 | syslog.current_log_level = level; 293 | } 294 | 295 | /* 设置系统时间戳 */ 296 | void syslog_set_time(uint32_t timestamp) 297 | { 298 | if (check_instance(&syslog)) 299 | syslog.timestamp = timestamp; 300 | } 301 | 302 | /* 获取系统当前时间戳 */ 303 | uint32_t syslog_get_time(void) 304 | { 305 | if (check_instance(&syslog)) 306 | return syslog.timestamp; 307 | return 0; 308 | } 309 | 310 | void modify_output(log_write f_write) 311 | { 312 | syslog.f_write = f_write; 313 | } 314 | /**************************API**************************/ 315 | 316 | /** 317 | * @brief 日志初始化 318 | * 319 | * @param f_write 日志输出接口 320 | * @param period_ms 任务周期(毫秒) 321 | */ 322 | void syslog_init(log_write f_write, uint32_t period_ms) 323 | { 324 | if (!f_write) 325 | return; 326 | 327 | syslog.f_write = f_write; 328 | syslog.current_log_level = LOG_LEVEL_INFO; // 默认日志等级为INFO 329 | 330 | queue_init(&syslog.log_queue, sizeof(uint8_t), log_buffer, LOG_BUFFER_SIZE); 331 | 332 | syslog.initialized = true; 333 | } 334 | 335 | /** 336 | * @brief 日志任务 337 | * 338 | */ 339 | void syslog_task(void) 340 | { 341 | syslog_show(&syslog); 342 | } 343 | 344 | /** 345 | * @brief 申请日志模块掩码 346 | * 347 | * @param module_name 模块名(必须是全局变量) 348 | * @return uint32_t 349 | */ 350 | uint32_t allocate_log_mask(const char * const module_name) 351 | { 352 | if (syslog.module_cnt >= 32) 353 | syslog.module_cnt = 31; // 最多支持32个模块 覆盖最后一个 354 | 355 | uint32_t mask = 1 << syslog.module_cnt; 356 | syslog.module_mask |= mask; 357 | module_info[syslog.module_cnt] = module_name; 358 | syslog.module_cnt++; 359 | return mask; 360 | } 361 | -------------------------------------------------------------------------------- /utils/qfsm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file qfsm.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 状态机组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include "utils/qfsm.h" 34 | 35 | static const qevent_t q_reserve_ev[] = { 36 | { (qsignal_t)Q_EMPTY_SIG }, 37 | { (qsignal_t)Q_ENTRY_SIG }, 38 | { (qsignal_t)Q_EXIT_SIG }, 39 | { (qsignal_t)Q_INIT_SIG }, 40 | }; 41 | 42 | void qfsm_init(qfsm_t *me, qstate_handler f_initial, qevent_t const *e) 43 | { 44 | me->state = f_initial; 45 | (*me->state)(me, e); 46 | (void)(*me->state)(me, &q_reserve_ev[Q_ENTRY_SIG]); 47 | } 48 | 49 | void qfsm_dispatch(qfsm_t *const me, qevent_t const *e) 50 | { 51 | qstate_handler s = me->state; 52 | qstate r; 53 | r = (*s)(me, e); 54 | 55 | if (r == Q_EVENT_TRAN) { 56 | (void)(*s)(me, &q_reserve_ev[Q_EXIT_SIG]); 57 | (void)(*me->state)(me, &q_reserve_ev[Q_ENTRY_SIG]); 58 | } 59 | } -------------------------------------------------------------------------------- /utils/queue.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file queue.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 环形队列组件 5 | * @version 0.1 6 | * @date 2024-12-25 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in all 21 | * copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | * SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include "utils/queue.h" 37 | 38 | /* 获取较小的值 */ 39 | static inline size_t q_min(size_t a, size_t b) 40 | { 41 | return (a <= b) ? a : b; 42 | } 43 | 44 | /* 初始化队列 */ 45 | bool queue_init(struct queue_info *q, size_t unit_bytes, void *buf, size_t units) 46 | { 47 | if (!q || !buf || units == 0 || unit_bytes == 0) 48 | return false; 49 | 50 | q->unit_bytes = unit_bytes; 51 | q->buf = buf; 52 | q->buf_size = units; 53 | q->rd = 0; 54 | q->wr = 0; 55 | 56 | return true; 57 | } 58 | 59 | /* 销毁队列 */ 60 | void queue_destroy(struct queue_info *q) 61 | { 62 | if (!q) 63 | return; 64 | 65 | q->rd = 0; 66 | q->wr = 0; 67 | } 68 | 69 | /* 重置队列 */ 70 | void queue_reset(struct queue_info *q) 71 | { 72 | if (!q) 73 | return; 74 | 75 | q->rd = 0; 76 | q->wr = 0; 77 | } 78 | 79 | /* 已使用的空间,以单元为单位 */ 80 | size_t queue_used(struct queue_info *q) 81 | { 82 | if (!q) 83 | return 0; 84 | 85 | return q->wr - q->rd; 86 | } 87 | 88 | /* 剩余空间,以单元为单位 */ 89 | size_t queue_remain_space(struct queue_info *q) 90 | { 91 | if (!q) 92 | return 0; 93 | 94 | return (q->buf_size - queue_used(q)); 95 | } 96 | 97 | /* 判断队列是否为空 */ 98 | bool is_queue_empty(struct queue_info *q) 99 | { 100 | if (!q) 101 | return true; 102 | 103 | return queue_used(q) == 0; 104 | } 105 | 106 | /* 判断队列是否已满 */ 107 | bool is_queue_full(struct queue_info *q) 108 | { 109 | if (!q) 110 | return false; 111 | 112 | return (queue_remain_space(q) == 0); 113 | } 114 | 115 | /* 向队列中添加数据,以单元为单位 */ 116 | size_t queue_add(struct queue_info *q, void *data, size_t units) 117 | { 118 | if (!q || !data || units == 0 || is_queue_full(q)) 119 | return 0; 120 | 121 | size_t remain = queue_remain_space(q); 122 | if (units > remain) 123 | units = remain; // 限制写入的单元数 124 | 125 | size_t index = q->wr % q->buf_size; // 实际写索引 126 | size_t tail_cnt = q_min(units, q->buf_size - index); 127 | 128 | memcpy(q->buf + (index * q->unit_bytes), data, tail_cnt * q->unit_bytes); 129 | if (units > tail_cnt) { 130 | memcpy(q->buf, data + (tail_cnt * q->unit_bytes), (units - tail_cnt) * q->unit_bytes); 131 | } 132 | 133 | q->wr += units; 134 | 135 | return units; 136 | } 137 | 138 | /* 从队列中获取数据,以单元为单位 */ 139 | size_t queue_get(struct queue_info *q, void *data, size_t units) 140 | { 141 | if (!q || !data || units == 0 || is_queue_empty(q)) 142 | return 0; 143 | 144 | size_t used = queue_used(q); 145 | if (units > used) 146 | units = used; 147 | 148 | size_t index = q->rd % q->buf_size; // 实例读索引 149 | size_t tail_cnt = q_min(units, q->buf_size - index); 150 | 151 | memcpy(data, q->buf + (index * q->unit_bytes), tail_cnt * q->unit_bytes); 152 | if (units > tail_cnt) 153 | memcpy(data + (tail_cnt * q->unit_bytes), q->buf, (units - tail_cnt) * q->unit_bytes); 154 | 155 | q->rd += units; 156 | 157 | return units; 158 | } 159 | 160 | /* 查看队列中的数据,但不移除,以单元为单位 */ 161 | size_t queue_peek(struct queue_info *q, void *data, size_t units) 162 | { 163 | if (!q || !data || units == 0 || is_queue_empty(q)) 164 | return 0; 165 | 166 | size_t used = queue_used(q); 167 | if (units > used) 168 | units = used; 169 | 170 | size_t index = q->rd % q->buf_size; // 实例读索引 171 | size_t tail_cnt = q_min(units, q->buf_size - index); 172 | 173 | memcpy(data, q->buf + (index * q->unit_bytes), tail_cnt * q->unit_bytes); 174 | if (units > tail_cnt) 175 | memcpy(data + (tail_cnt * q->unit_bytes), q->buf, (units - tail_cnt) * q->unit_bytes); 176 | 177 | return units; 178 | } 179 | 180 | /* 增加读索引,以单元为单位 */ 181 | void queue_advance_rd(struct queue_info *q, size_t units) 182 | { 183 | if (!q) 184 | return; 185 | 186 | size_t count = q_min(units, queue_used(q)); 187 | q->rd += count; 188 | } 189 | 190 | /* 增加写索引,以单元为单位 */ 191 | void queue_advance_wr(struct queue_info *q, size_t units) 192 | { 193 | if (!q) 194 | return; 195 | 196 | size_t count = q_min(units, queue_remain_space(q)); 197 | q->wr += count; 198 | } 199 | -------------------------------------------------------------------------------- /utils/soft_iic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file soft_iic.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 软件IIC组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include "utils/soft_iic.h" 34 | 35 | soft_iic_delay_f soft_iic_delay_us = 0; 36 | soft_iic_scl_out_f scl_out = 0; 37 | soft_iic_sda_out_f sda_out = 0; 38 | soft_iic_sda_in_f sda_in = 0; 39 | 40 | void iic_delay(uint8_t us) 41 | { 42 | if (soft_iic_delay_us) 43 | soft_iic_delay_us(us); 44 | else { 45 | uint8_t i = 7; 46 | 47 | while (i) 48 | i--; 49 | } 50 | } 51 | 52 | uint8_t soft_iic_init( 53 | soft_iic_scl_out_f scl_out_f, soft_iic_sda_out_f sda_out_f, soft_iic_sda_in_f sda_in_f, soft_iic_delay_f delay_f) 54 | { 55 | if (!(scl_out_f && sda_out_f && sda_in_f)) 56 | return 0; 57 | 58 | scl_out = scl_out_f; 59 | sda_out = sda_out_f; 60 | sda_in = sda_in_f; 61 | soft_iic_delay_us = delay_f; 62 | return 1; 63 | } 64 | 65 | void soft_iic_start(void) 66 | { 67 | sda_out(iic_high); 68 | scl_out(iic_high); 69 | iic_delay(2); 70 | sda_out(iic_low); 71 | iic_delay(2); 72 | scl_out(iic_low); 73 | } 74 | 75 | void soft_iic_stop(void) 76 | { 77 | scl_out(iic_low); 78 | sda_out(iic_low); 79 | iic_delay(2); 80 | scl_out(iic_high); 81 | sda_out(iic_high); 82 | iic_delay(2); 83 | } 84 | 85 | uint8_t soft_iic_wait_ack(void) 86 | { 87 | uint8_t ucErrTime = 0; 88 | sda_out(iic_high); 89 | iic_delay(2); 90 | scl_out(iic_high); 91 | iic_delay(2); 92 | 93 | while (sda_in()) { 94 | ucErrTime++; 95 | 96 | if (ucErrTime > 250) { 97 | soft_iic_stop(); 98 | return 1; 99 | } 100 | } 101 | 102 | scl_out(iic_low); 103 | return 0; 104 | } 105 | 106 | void soft_iic_ack(void) 107 | { 108 | scl_out(iic_low); 109 | sda_out(iic_low); 110 | iic_delay(2); 111 | scl_out(iic_high); 112 | iic_delay(2); 113 | scl_out(iic_low); 114 | } 115 | 116 | void soft_iic_nack(void) 117 | { 118 | scl_out(iic_low); 119 | sda_out(iic_high); 120 | iic_delay(2); 121 | scl_out(iic_high); 122 | iic_delay(2); 123 | scl_out(iic_low); 124 | } 125 | 126 | void soft_iic_send_byte(uint8_t data) 127 | { 128 | uint8_t t; 129 | scl_out(iic_low); 130 | 131 | for (t = 0; t < 8; t++) { 132 | sda_out((data & 0x80) >> 7); 133 | data <<= 1; 134 | scl_out(iic_high); 135 | iic_delay(2); 136 | scl_out(iic_low); 137 | iic_delay(2); 138 | } 139 | } 140 | 141 | uint8_t soft_iic_rcv_byte(unsigned char ack) 142 | { 143 | unsigned char i, receive = 0; 144 | 145 | for (i = 0; i < 8; i++) { 146 | scl_out(iic_low); 147 | iic_delay(2); 148 | scl_out(iic_high); 149 | receive <<= 1; 150 | 151 | if (sda_in()) 152 | receive++; 153 | 154 | iic_delay(2); 155 | } 156 | 157 | if (!ack) 158 | soft_iic_nack(); 159 | else 160 | soft_iic_ack(); 161 | 162 | return receive; 163 | } 164 | 165 | uint8_t soft_iic_write_one_byte(uint8_t addr, uint8_t reg, uint8_t data) 166 | { 167 | soft_iic_start(); 168 | soft_iic_send_byte((addr << 1) | 0); 169 | 170 | if (soft_iic_wait_ack()) { 171 | soft_iic_stop(); 172 | return 1; 173 | } 174 | 175 | soft_iic_send_byte(reg); 176 | soft_iic_wait_ack(); 177 | soft_iic_send_byte(data); 178 | 179 | if (soft_iic_wait_ack()) { 180 | soft_iic_stop(); 181 | return 1; 182 | } 183 | 184 | soft_iic_stop(); 185 | return 0; 186 | } 187 | 188 | uint8_t soft_iic_write_bytes(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf) 189 | { 190 | uint8_t i; 191 | soft_iic_start(); 192 | soft_iic_send_byte((addr << 1) | 0); 193 | 194 | if (soft_iic_wait_ack()) { 195 | soft_iic_stop(); 196 | return 1; 197 | } 198 | 199 | soft_iic_send_byte(reg); 200 | soft_iic_wait_ack(); 201 | 202 | for (i = 0; i < len; i++) { 203 | soft_iic_send_byte(buf[i]); 204 | 205 | if (soft_iic_wait_ack()) { 206 | soft_iic_stop(); 207 | return 1; 208 | } 209 | } 210 | 211 | soft_iic_stop(); 212 | return 0; 213 | } 214 | 215 | uint8_t soft_iic_read_bytes(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf) 216 | { 217 | soft_iic_start(); 218 | soft_iic_send_byte((addr << 1) | 0); 219 | 220 | if (soft_iic_wait_ack()) { 221 | soft_iic_stop(); 222 | return 1; 223 | } 224 | 225 | soft_iic_send_byte(reg); 226 | soft_iic_wait_ack(); 227 | soft_iic_start(); 228 | soft_iic_send_byte((addr << 1) | 1); 229 | soft_iic_wait_ack(); 230 | 231 | while (len) { 232 | if (len == 1) 233 | *buf = soft_iic_rcv_byte(0); 234 | else 235 | *buf = soft_iic_rcv_byte(1); 236 | 237 | len--; 238 | buf++; 239 | } 240 | 241 | soft_iic_stop(); 242 | return 0; 243 | } 244 | -------------------------------------------------------------------------------- /utils/stimer.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stimer.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 前后台调度组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, virtual_os_free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | 35 | #include "utils/list.h" 36 | #include "utils/stimer.h" 37 | 38 | #include "core/virtual_os_mm.h" 39 | 40 | #define HIT_LIST_MASK (STIMER_TASK_HIT_LIST_MAX - 1) 41 | #define HIT_LIST_IDX(t) ((m_timer.pre_tick + (t)) & HIT_LIST_MASK) 42 | 43 | #define STIMER_TASK_HIT_LIST_MAX (32) 44 | #define MAX_DEFER_TASK (16) 45 | 46 | #define Period_to_Tick(p) (((p) >= STIMER_PERIOD_PER_TICK_MS) ? ((p) / STIMER_PERIOD_PER_TICK_MS) : 1U) 47 | 48 | struct stimer_task { 49 | stimer_f task_f; 50 | uint32_t period; 51 | uint32_t arrive; 52 | list_item item; 53 | uint8_t reserved; 54 | }; 55 | 56 | struct timer { 57 | volatile uint32_t pre_tick; 58 | volatile uint32_t cur_tick; 59 | volatile int run_flag; 60 | stimer_base_start f_start; 61 | list_item long_tick_list; 62 | list_item hit_task_list[STIMER_TASK_HIT_LIST_MAX]; 63 | list_item defer_task_list; 64 | }; 65 | 66 | static struct stimer_task defer_pool[MAX_DEFER_TASK]; 67 | static struct timer m_timer = { 0 }; 68 | 69 | static inline int is_timer_run(void) 70 | { 71 | return m_timer.run_flag == 1; 72 | } 73 | 74 | static inline void _timer_update(void) 75 | { 76 | ++m_timer.cur_tick; 77 | } 78 | 79 | static struct stimer_task *defer_task_allocate(void) 80 | { 81 | for (int i = 0; i < MAX_DEFER_TASK; i++) { 82 | if (defer_pool[i].reserved == 1) 83 | return &defer_pool[i]; 84 | } 85 | return NULL; 86 | } 87 | 88 | static void defer_task_free(struct stimer_task *task) 89 | { 90 | if (task) { 91 | task->task_f = NULL; 92 | task->reserved = 1; 93 | task->arrive = 0; 94 | task->period = 0; 95 | } 96 | } 97 | 98 | static inline void _add_timer(uint32_t period, list_item *item) 99 | { 100 | list_delete_item(item); 101 | 102 | if (period > STIMER_TASK_HIT_LIST_MAX) 103 | list_add_tail(&(m_timer.long_tick_list), item); 104 | else 105 | list_add_tail(&(m_timer.hit_task_list[HIT_LIST_IDX(period)]), item); 106 | } 107 | 108 | static bool stimer_task_add(struct stimer_task *p_task) 109 | { 110 | if (!p_task) 111 | return false; 112 | 113 | p_task->arrive = 0; 114 | _add_timer(p_task->period, &(p_task->item)); 115 | return true; 116 | } 117 | 118 | static uint32_t inline stimer_get_tick(void) 119 | { 120 | return m_timer.cur_tick; 121 | } 122 | 123 | static void stimer_task_dispatch(void) 124 | { 125 | uint32_t idx, remain; 126 | struct list_item *cur_item, *next_item; 127 | struct stimer_task *task; 128 | 129 | if (!is_timer_run() || (m_timer.pre_tick == m_timer.cur_tick)) 130 | return; 131 | 132 | ++m_timer.pre_tick; 133 | idx = HIT_LIST_IDX(0); 134 | 135 | if (idx == 0) { 136 | list_for_each_safe(cur_item, next_item, &(m_timer.long_tick_list)) 137 | { 138 | task = container_of(cur_item, struct stimer_task, item); 139 | task->arrive += STIMER_TASK_HIT_LIST_MAX; 140 | remain = task->period - task->arrive; 141 | 142 | if (remain == 0) { 143 | if (task->task_f) 144 | task->task_f(); 145 | task->arrive = 0; 146 | } else if (remain < STIMER_TASK_HIT_LIST_MAX) { 147 | _add_timer(remain, cur_item); 148 | } 149 | } 150 | } 151 | 152 | list_for_each_safe(cur_item, next_item, &(m_timer.hit_task_list[idx])) 153 | { 154 | task = container_of(cur_item, struct stimer_task, item); 155 | if (task->task_f) 156 | task->task_f(); 157 | task->arrive = -idx; 158 | _add_timer(task->period, &(task->item)); 159 | } 160 | 161 | list_for_each_safe(cur_item, next_item, &(m_timer.defer_task_list)) 162 | { 163 | task = container_of(cur_item, struct stimer_task, item); 164 | if (++task->arrive >= task->period) { 165 | if (task->task_f) 166 | task->task_f(); 167 | list_delete_item(cur_item); 168 | defer_task_free(task); 169 | } 170 | } 171 | } 172 | 173 | /*************************************API*************************************/ 174 | 175 | bool stimer_init(struct timer_port *port) 176 | { 177 | if (!port || !port->f_init || !port->f_start) 178 | return false; 179 | 180 | list_init(&(m_timer.long_tick_list)); 181 | list_init(&(m_timer.defer_task_list)); 182 | 183 | for (int i = 0; i < MAX_DEFER_TASK; i++) 184 | defer_pool[i] = (struct stimer_task){ .reserved = 1 }; 185 | 186 | for (uint8_t i = 0; i < STIMER_TASK_HIT_LIST_MAX; i++) 187 | list_init(&(m_timer.hit_task_list[i])); 188 | 189 | port->f_init(STIMER_PERIOD_PER_TICK_MS, _timer_update); 190 | m_timer.f_start = port->f_start; 191 | return true; 192 | } 193 | 194 | bool stimer_task_create(stimer_f init_f, stimer_f task_f, uint32_t period_ms) 195 | { 196 | if (init_f) 197 | init_f(); 198 | 199 | if (!task_f || !period_ms) 200 | return false; 201 | 202 | struct stimer_task *task = (struct stimer_task *)virtual_os_calloc(1, sizeof(struct stimer_task)); 203 | if (task) { 204 | task->period = Period_to_Tick(period_ms); 205 | task->reserved = 1; 206 | task->task_f = task_f; 207 | list_init(&(task->item)); 208 | 209 | return stimer_task_add(task); 210 | } 211 | return false; 212 | } 213 | 214 | bool defer_task_create(stimer_f task_f, uint32_t ms) 215 | { 216 | if (!is_timer_run()) 217 | return false; 218 | 219 | struct stimer_task *p_task = defer_task_allocate(); 220 | if (!p_task) 221 | return false; 222 | 223 | p_task->task_f = task_f; 224 | p_task->period = Period_to_Tick(ms); 225 | p_task->arrive = 0; 226 | p_task->reserved = 0; 227 | list_add_tail(&(m_timer.defer_task_list), &(p_task->item)); 228 | return true; 229 | } 230 | 231 | void stimer_start(void) 232 | { 233 | if (!m_timer.f_start) 234 | return; 235 | 236 | m_timer.f_start(); 237 | m_timer.run_flag = 1; 238 | 239 | uint32_t pre_tick = stimer_get_tick(); 240 | uint32_t cur_tick; 241 | 242 | while (1) { 243 | cur_tick = stimer_get_tick(); 244 | if (cur_tick != pre_tick) { 245 | pre_tick = cur_tick; 246 | stimer_task_dispatch(); 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /utils/string_hash.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file string_hash.c 3 | * @author wenshuyu (wsy2161826815@163.com) 4 | * @brief 字符串哈希组件 5 | * @version 1.0 6 | * @date 2024-08-12 7 | * 8 | * @copyright Copyright (c) 2024-2025 9 | * @see repository: https://github.com/i-tesetd-it-no-problem/VirtualOS.git 10 | * 11 | * The MIT License (MIT) 12 | * 13 | * Permission is hereby granted, virtual_os_free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | * 31 | */ 32 | 33 | #include 34 | #include 35 | #include "utils/string_hash.h" 36 | 37 | #include "core/virtual_os_mm.h" 38 | 39 | // FNV-1a hash 40 | static uint32_t hash(const char *key, size_t table_size) 41 | { 42 | uint32_t hash = 2166136261u; 43 | 44 | while (*key) { 45 | hash ^= (uint8_t)*key++; 46 | hash *= 16777619; 47 | } 48 | 49 | return hash % table_size; 50 | } 51 | 52 | enum hash_error init_hash_table(struct hash_table *hash_table, size_t table_size) 53 | { 54 | if (!hash_table) 55 | return HASH_POINT_ERROR; 56 | 57 | hash_table->table = (list_item *)virtual_os_calloc(table_size, sizeof(list_item)); 58 | 59 | if (!hash_table->table) 60 | return HASH_POINT_ERROR; 61 | 62 | for (size_t i = 0; i < table_size; i++) 63 | list_init(&hash_table->table[i]); 64 | 65 | hash_table->table_size = table_size; 66 | return HASH_SUCCESS; 67 | } 68 | 69 | enum hash_error hash_insert(struct hash_table *hash_table, const char *key, void *private) 70 | { 71 | if (!hash_table || !key) 72 | return HASH_POINT_ERROR; 73 | 74 | uint32_t index = hash(key, hash_table->table_size); 75 | 76 | list_item *pos, *tmp; 77 | list_for_each_safe(pos, tmp, &hash_table->table[index]) 78 | { 79 | struct string_hash_node *node = container_of(pos, struct string_hash_node, list); 80 | 81 | if (strcmp(node->key, key) == 0) { 82 | node->private = private; 83 | 84 | return HASH_SUCCESS; 85 | } 86 | } 87 | 88 | struct string_hash_node *new_node = 89 | (struct string_hash_node *)virtual_os_calloc(1, sizeof(struct string_hash_node)); 90 | list_init(&new_node->list); 91 | 92 | if (!new_node) 93 | return HASH_POINT_ERROR; 94 | 95 | new_node->key = (char *)virtual_os_calloc(1, strlen(key) + 1); 96 | if (!new_node->key) { 97 | virtual_os_free(new_node); 98 | 99 | return HASH_POINT_ERROR; 100 | } 101 | strcpy(new_node->key, key); 102 | 103 | new_node->private = private; 104 | list_add_tail(&hash_table->table[index], &new_node->list); 105 | 106 | return HASH_SUCCESS; 107 | } 108 | 109 | void *hash_find(struct hash_table *hash_table, const char *key, enum hash_error *error) 110 | { 111 | if (!hash_table || !key) { 112 | if (error) 113 | *error = HASH_POINT_ERROR; 114 | 115 | return NULL; 116 | } 117 | 118 | uint32_t index = hash(key, hash_table->table_size); 119 | 120 | list_item *pos, *tmp; 121 | list_for_each_safe(pos, tmp, &hash_table->table[index]) 122 | { 123 | struct string_hash_node *node = container_of(pos, struct string_hash_node, list); 124 | 125 | if (strcmp(node->key, key) == 0) { 126 | if (error) 127 | *error = HASH_SUCCESS; 128 | 129 | return node->private; 130 | } 131 | } 132 | 133 | if (error) 134 | *error = HASH_KEY_NOT_FOUND; 135 | 136 | return NULL; 137 | } 138 | 139 | enum hash_error hash_delete(struct hash_table *hash_table, const char *key) 140 | { 141 | if (!hash_table || !key) 142 | return HASH_POINT_ERROR; 143 | 144 | uint32_t index = hash(key, hash_table->table_size); 145 | 146 | list_item *pos, *tmp; 147 | list_for_each_safe(pos, tmp, &hash_table->table[index]) 148 | { 149 | struct string_hash_node *node = container_of(pos, struct string_hash_node, list); 150 | 151 | if (strcmp(node->key, key) == 0) { 152 | list_delete_item(pos); 153 | virtual_os_free(node->key); 154 | virtual_os_free(node); 155 | 156 | return HASH_SUCCESS; 157 | } 158 | } 159 | 160 | return HASH_KEY_NOT_FOUND; 161 | } 162 | 163 | enum hash_error hash_get_all_keys(struct hash_table *hash_table, char ***keys, size_t *num_keys) 164 | { 165 | if (!hash_table || !keys || !num_keys) 166 | return HASH_POINT_ERROR; 167 | 168 | size_t total_keys = 0; 169 | for (size_t i = 0; i < hash_table->table_size; ++i) { 170 | list_item *pos, *n; 171 | list_for_each_safe(pos, n, &hash_table->table[i]) total_keys++; 172 | } 173 | 174 | if (total_keys == 0) { 175 | *keys = NULL; 176 | *num_keys = 0; 177 | return HASH_SUCCESS; 178 | } 179 | 180 | char **key_array = (char **)virtual_os_calloc(total_keys, sizeof(char *)); 181 | if (!key_array) 182 | return HASH_POINT_ERROR; 183 | 184 | size_t index = 0; 185 | for (size_t i = 0; i < hash_table->table_size; ++i) { 186 | list_item *pos, *n; 187 | list_for_each_safe(pos, n, &hash_table->table[i]) 188 | { 189 | struct string_hash_node *node = container_of(pos, struct string_hash_node, list); 190 | 191 | size_t key_len = strlen(node->key) + 1; 192 | key_array[index] = (char *)virtual_os_calloc(1, key_len); 193 | if (!key_array[index]) { 194 | for (size_t j = 0; j < index; ++j) 195 | virtual_os_free(key_array[j]); 196 | 197 | virtual_os_free(key_array); 198 | return HASH_POINT_ERROR; 199 | } 200 | 201 | strcpy(key_array[index], node->key); 202 | index++; 203 | } 204 | } 205 | 206 | *keys = key_array; 207 | *num_keys = total_keys; 208 | return HASH_SUCCESS; 209 | } 210 | 211 | void destroy_hash_table(struct hash_table *hash_table) 212 | { 213 | if (!hash_table) 214 | return; 215 | 216 | for (size_t i = 0; i < hash_table->table_size; ++i) { 217 | list_item *pos, *tmp; 218 | list_for_each_safe(pos, tmp, &hash_table->table[i]) 219 | { 220 | struct string_hash_node *node = container_of(pos, struct string_hash_node, list); 221 | list_delete_item(pos); 222 | virtual_os_free(node->key); 223 | virtual_os_free(node); 224 | } 225 | } 226 | 227 | virtual_os_free(hash_table->table); 228 | } 229 | -------------------------------------------------------------------------------- /virtual_os_src.cmake: -------------------------------------------------------------------------------- 1 | file(GLOB_RECURSE VIRTUALOS_SOURCES 2 | ${CMAKE_CURRENT_LIST_DIR}/component/RTT/*.c 3 | ${CMAKE_CURRENT_LIST_DIR}/dal/*.c 4 | ${CMAKE_CURRENT_LIST_DIR}/core/*.c 5 | ${CMAKE_CURRENT_LIST_DIR}/protocol/modbus/*.c 6 | ${CMAKE_CURRENT_LIST_DIR}/utils/*.c 7 | ${CMAKE_CURRENT_LIST_DIR}/driver/*.c 8 | ) 9 | 10 | set(VIRTUALOS_INCLUDE_DIRS 11 | ${CMAKE_CURRENT_LIST_DIR}/include 12 | ${CMAKE_CURRENT_LIST_DIR}/component/RTT 13 | ) 14 | 15 | # add_link_options( 16 | # -T${CMAKE_CURRENT_LIST_DIR}/core/virtual_os.ld 17 | # ) --------------------------------------------------------------------------------