├── .clang-format ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_zh.md ├── builtin ├── help.c ├── login.c └── shsize.c ├── cherryrl ├── .clang-format ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── chry_readline.c ├── chry_readline.h ├── chry_readline_config.h ├── chry_readline_keycode.h └── example.c ├── chry_shell.c ├── chry_shell.h ├── csh.h ├── csh_config_template.h ├── doc ├── test1.png └── test2.png └── samples └── hpm ├── barebone_uart ├── CMakeLists.txt ├── README_en.md ├── README_zh.md ├── inc │ ├── csh_config.h │ └── shell.h └── src │ ├── main.c │ └── shell.c ├── barebone_usb ├── CMakeLists.txt ├── README_en.md ├── README_zh.md ├── inc │ ├── csh_config.h │ ├── shell.h │ └── usb_config.h └── src │ ├── main.c │ └── shell.c ├── freertos_uart ├── CMakeLists.txt ├── README_en.md ├── README_zh.md ├── inc │ ├── FreeRTOSConfig.h │ ├── csh_config.h │ └── shell.h └── src │ ├── main.c │ └── shell.c ├── freertos_usb ├── CMakeLists.txt ├── README_en.md ├── README_zh.md ├── inc │ ├── FreeRTOSConfig.h │ ├── csh_config.h │ ├── shell.h │ └── usb_config.h └── src │ ├── main.c │ └── shell.c └── threadx_uart ├── CMakeLists.txt ├── README_en.md ├── README_zh.md ├── inc ├── csh_config.h ├── shell.h └── tx_user.h └── src ├── main.c └── shell.c /.clang-format: -------------------------------------------------------------------------------- 1 | # clang-format configuration file. Intended for clang-format >= 11.0 2 | # 3 | # For more information, see: 4 | # 5 | # https://clang.llvm.org/docs/ClangFormat.html 6 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 7 | # 8 | --- 9 | # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto 10 | Language: Cpp 11 | # BasedOnStyle: LLVM 12 | # 访问说明符(public、private等)的偏移 13 | AccessModifierOffset: -4 14 | # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) 15 | AlignAfterOpenBracket: Align 16 | # 连续赋值时,对齐所有等号 17 | AlignConsecutiveAssignments: false 18 | # 对齐位域 19 | AlignConsecutiveBitFields: true 20 | # 连续声明时,对齐所有声明的变量名 21 | AlignConsecutiveDeclarations: false 22 | # 连续宏时,进行对齐 23 | AlignConsecutiveMacros: true 24 | # 左对齐逃脱换行(使用反斜杠换行)的反斜杠 25 | AlignEscapedNewlines: Left 26 | # 水平对齐二元和三元表达式的操作数 27 | AlignOperands: true 28 | # 对齐连续的尾随的注释 29 | AlignTrailingComments: true 30 | # 允许函数声明的所有参数在放在下一行 31 | AllowAllParametersOfDeclarationOnNextLine: false 32 | # 允许短的块放在同一行 33 | AllowShortBlocksOnASingleLine: false 34 | # 允许短的case标签放在同一行 35 | AllowShortCaseLabelsOnASingleLine: false 36 | # 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All 37 | AllowShortFunctionsOnASingleLine: None 38 | # 允许短的if语句保持在同一行 39 | AllowShortIfStatementsOnASingleLine: false 40 | # 允许短的循环保持在同一行 41 | AllowShortLoopsOnASingleLine: false 42 | # 总是在定义返回类型后换行(deprecated) 43 | AlwaysBreakAfterDefinitionReturnType: None 44 | # 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), 45 | # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) 46 | AlwaysBreakAfterReturnType: None 47 | # 总是在多行string字面量前换行 48 | AlwaysBreakBeforeMultilineStrings: false 49 | # 总是在template声明后换行 50 | AlwaysBreakTemplateDeclarations: false 51 | # false表示函数实参要么都在同一行,要么都各自一行 52 | BinPackArguments: true 53 | # false表示所有形参要么都在同一行,要么都各自一行 54 | BinPackParameters: true 55 | # 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 56 | BraceWrapping: 57 | AfterClass: false 58 | AfterControlStatement: false 59 | AfterEnum: false 60 | AfterFunction: true 61 | AfterNamespace: false 62 | AfterObjCDeclaration: false 63 | AfterStruct: false 64 | AfterUnion: false 65 | AfterExternBlock: false # Unknown to clang-format-5.0 66 | BeforeCatch: false 67 | BeforeElse: false 68 | IndentBraces: false 69 | SplitEmptyFunction: true # Unknown to clang-format-4.0 70 | SplitEmptyRecord: true # Unknown to clang-format-4.0 71 | SplitEmptyNamespace: true # Unknown to clang-format-4.0 72 | # 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) 73 | BreakBeforeBinaryOperators: None 74 | BreakBeforeBraces: Custom 75 | #BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 76 | # 在三元运算符前换行 77 | BreakBeforeTernaryOperators: false 78 | # 在构造函数的初始化列表的逗号前换行 79 | BreakConstructorInitializersBeforeComma: false 80 | BreakAfterJavaFieldAnnotations: false 81 | BreakStringLiterals: false 82 | # 每行字符的限制,0表示没有限制 83 | ColumnLimit: 0 84 | # 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 85 | CommentPragmas: '^ IWYU pragma:' 86 | CompactNamespaces: false # Unknown to clang-format-4.0 87 | # 构造函数的初始化列表要么都在同一行,要么都各自一行 88 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 89 | # 构造函数的初始化列表的缩进宽度 90 | ConstructorInitializerIndentWidth: 4 91 | # 延续的行的缩进宽度 92 | ContinuationIndentWidth: 4 93 | # 去除C++11的列表初始化的大括号{后和}前的空格 94 | Cpp11BracedListStyle: false 95 | # 继承最常用的指针和引用的对齐方式 96 | DerivePointerAlignment: false 97 | # 关闭格式化 98 | DisableFormat: false 99 | ForEachMacros: 100 | - 'SHELL_EXPORT_CMD' 101 | 102 | # 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) 103 | ExperimentalAutoDetectBinPacking: false 104 | # 缩进case标签 105 | IndentCaseLabels: true 106 | # 缩进宽度 107 | IndentWidth: 4 108 | # 函数返回类型换行时,缩进函数声明或函数定义的函数名 109 | IndentWrappedFunctionNames: false 110 | # 保留在块开始处的空行 111 | KeepEmptyLinesAtTheStartOfBlocks: false 112 | # 开始一个块的宏的正则表达式 113 | MacroBlockBegin: '' 114 | # 结束一个块的宏的正则表达式 115 | MacroBlockEnd: '' 116 | # 连续空行的最大数量 117 | MaxEmptyLinesToKeep: 1 118 | # 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All 119 | NamespaceIndentation: None 120 | # 使用ObjC块时缩进宽度 121 | ObjCBlockIndentWidth: 4 122 | # 在ObjC的@property后添加一个空格 123 | ObjCSpaceAfterProperty: false 124 | # 在ObjC的protocol列表前添加一个空格 125 | ObjCSpaceBeforeProtocolList: true 126 | # 在call(后对函数调用换行的penalty 127 | PenaltyBreakBeforeFirstCallParameter: 30 128 | # 在一个注释中引入换行的penalty 129 | PenaltyBreakComment: 10 130 | # 第一次在<<前换行的penalty 131 | PenaltyBreakFirstLessLess: 0 132 | # 在一个字符串字面量中引入换行的penalty 133 | PenaltyBreakString: 10 134 | # 对于每个在行字符数限制之外的字符的penalty 135 | PenaltyExcessCharacter: 100 136 | # 将函数的返回类型放到它自己的行的penalty 137 | PenaltyReturnTypeOnItsOwnLine: 60 138 | # 指针和引用的对齐: Left, Right, Middle 139 | PointerAlignment: Right 140 | # 允许重新排版注释 141 | ReflowComments: false 142 | # 允许排序#include 143 | SortIncludes: false 144 | # 在C风格类型转换后添加空格 145 | SpaceAfterCStyleCast: false 146 | # 在赋值运算符之前添加空格 147 | SpaceBeforeAssignmentOperators: true 148 | # 开圆括号之前添加一个空格: Never, ControlStatements, Always 149 | SpaceBeforeParens: ControlStatements 150 | # 在空的圆括号中添加空格 151 | SpaceInEmptyParentheses: false 152 | # 在尾随的评论前添加的空格数(只适用于//) 153 | SpacesBeforeTrailingComments: 1 154 | # 在尖括号的<后和>前添加空格 155 | SpacesInAngles: false 156 | # 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 157 | SpacesInContainerLiterals: false 158 | # 在C风格类型转换的括号中添加空格 159 | SpacesInCStyleCastParentheses: false 160 | # 在圆括号的(后和)前添加空格 161 | SpacesInParentheses: false 162 | # 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 163 | SpacesInSquareBrackets: false 164 | # 标准: Cpp03, Cpp11, Auto 165 | Standard: Cpp03 166 | # tab宽度 167 | TabWidth: 4 168 | # 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always 169 | UseTab: Never 170 | ... 171 | 172 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | **/build 3 | **/.cache 4 | samples/hpm/barebone_uart/Makefile 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [1.0.0] - 2024-03-28: 4 | 5 | All changes 6 | 7 | ### Added 8 | - first commit 9 | - [feat] update samples/hpm/barebone_uart, use uart isr recv 10 | - [feat] add samples/hpm/freertos_uart, use uart isr recv 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CherryShell 2 | 3 | [中文版](./README_zh.md) 4 | 5 | ## Brief 6 | 7 | CherryShell is a tiny shell specifically designed for embedded applications. 8 | 9 | ## Features 10 | - [x] Path completion support, with tab for path completion 11 | - [x] Command completion support, with tab for command completion 12 | - [x] Environment variable support, using `$` as a prefix, e.g., `$PATH` 13 | - [x] Automatic command search in specified directories using the `$PATH` environment variable 14 | - [x] History record support, with up and down arrows 15 | - [x] Compatibility with VT100 and Xterm key values 16 | - [x] Support for setting username, hostname, and path 17 | - [x] Non-blocking mode support 18 | - [x] User login support, requiring implementation of a hash function (default: strcmp) 19 | - [ ] Shortcut key support for `Ctrl + `, `Alt + `, `F1-F12` to invoke commands 20 | - [ ] Key function remapping support for `Ctrl + `, `Alt + `, `F1-F12` 21 | - [ ] Support for exec function family to directly call commands 22 | - [ ] File system support, including FatFS, FileX, LittleFS, RomFS, etc. 23 | - [ ] Support for adding, modifying, deleting, and retrieving environment variables 24 | - [ ] Signal handling support, capturing and handling different signals such as Ctrl+C ``SIGINT`` and Ctrl+Z ``SIGTSTP`` 25 | - [ ] Support for exit function to terminate command execution, return to the specified handler, using setjmp (barebonel) 26 | - [ ] Input/output redirection support 27 | - [ ] Multiple user command permission support 28 | - [ ] Job control support, allowing commands to run in the foreground or background, and using control commands (e.g., fg, bg, jobs) to manage and manipulate jobs 29 | 30 | ## Demo 31 | 32 | ![test1](./doc/test1.png) 33 | 34 | ![test2](./doc/test2.png) 35 | 36 | ## Porting 37 | 38 | Taking the example of the HPMicro hpm5301evklite board. 39 | 40 | Command lookup uses the GCC section, so we need to modify the linkerscript file to add the relevant section, for example in gcc ld: 41 | 42 | ``` 43 | .text : { 44 | ..... 45 | 46 | . = ALIGN(4); 47 | __fsymtab_start = .; 48 | KEEP(*(FSymTab)) 49 | __fsymtab_end = .; 50 | . = ALIGN(4); 51 | __vsymtab_start = .; 52 | KEEP(*(VSymTab)) 53 | __vsymtab_end = .; 54 | . = ALIGN(4); 55 | } 56 | 57 | ``` 58 | 59 | ``` c 60 | // Include header file 61 | #include "csh.h" 62 | 63 | // Create a shell instance 64 | static chry_shell_t csh; 65 | 66 | ``` 67 | 68 | ``` c 69 | // Character output function, directly outputs characters to the serial port 70 | static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size) 71 | { 72 | uint16_t i; 73 | (void)rl; 74 | for (i = 0; i < size; i++) { 75 | if (status_success != uart_send_byte(HPM_UART0, ((uint8_t *)data)[i])) { 76 | break; 77 | } 78 | } 79 | 80 | // Return the number of successfully output characters 81 | return i; 82 | } 83 | 84 | ``` 85 | 86 | ``` c 87 | // Character input function, reads characters directly from the serial port 88 | // If the baud rate is high, a FIFO input buffer can be added 89 | static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size) 90 | { 91 | uint16_t i; 92 | (void)rl; 93 | for (i = 0; i < size; i++) { 94 | if (status_success != uart_receive_byte(HPM_UART0, (uint8_t *)data + i)) { 95 | break; 96 | } 97 | } 98 | 99 | // Return the number of successfully read characters 100 | return i; 101 | } 102 | 103 | ``` 104 | 105 | ``` c 106 | // Shell initialization 107 | int shell_init(void) 108 | { 109 | // Structure for configuring initialization parameters 110 | chry_shell_init_t csh_init; 111 | 112 | // Set the character input and output functions (must be implemented) 113 | csh_init.sput = csh_sput_cb; 114 | csh_init.sget = csh_sget_cb; 115 | 116 | // Symbols defined in the linkscript, used to store exported commands and variables 117 | extern const int __fsymtab_start; 118 | extern const int __fsymtab_end; 119 | extern const int __vsymtab_start; 120 | extern const int __vsymtab_end; 121 | 122 | // Configure the start and end addresses of the function and variable tables (must be implemented) 123 | csh_init.command_table_beg = &__fsymtab_start; 124 | csh_init.command_table_end = &__fsymtab_end; 125 | csh_init.variable_table_beg = &__vsymtab_start; 126 | csh_init.variable_table_end = &__vsymtab_end; 127 | 128 | // Define a prompt buffer 129 | static char csh_prompt_buffer[128]; 130 | // Configure the prompt buffer (optional) 131 | // Depends on whether the editable prompt feature is enabled (CONFIG_CSH_PROMPTEDIT) 132 | csh_init.prompt_buffer = csh_prompt_buffer; 133 | csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer); 134 | 135 | // Define a history buffer 136 | static char csh_history_buffer[128]; 137 | 138 | // Configure the history buffer (optional) 139 | // Depends on whether the history record feature is enabled (CONFIG_CSH_LNBUFF_STATIC) 140 | csh_init.history_buffer = csh_history_buffer; 141 | csh_init.history_buffer_size = sizeof(csh_history_buffer); 142 | 143 | // Define a line input buffer 144 | static char csh_line_buffer[128]; 145 | 146 | // Configure the line input buffer (optional) 147 | // Depends on whether the static line buffer feature is enabled (CONFIG_CSH_LNBUFF_STATIC) 148 | // If the static line buffer feature is not enabled, the line buffer will exist on the stack, 149 | // and non-blocking mode (CONFIG_CSH_NOBLOCK) must be set to 0 150 | csh_init.line_buffer = csh_line_buffer; 151 | csh_init.line_buffer_size = sizeof(csh_line_buffer); 152 | 153 | // Default user count is 1 154 | csh_init.uid = 0; // Default user ID 155 | csh_init.user[0] = "cherry"; // Username for user ID 0 156 | csh_init.hash[0] = NULL; // Password hash value for user ID 0 157 | csh_init.host = "hpm5301evklite"; // Host name 158 | 159 | // Initialization 160 | int ret = chry_shell_init(&csh, &csh_init); 161 | if (ret) { 162 | return -1; 163 | } 164 | 165 | return 0; 166 | } 167 | 168 | ``` 169 | 170 | ``` c 171 | // Main function of the shell, needs to be called in a while(1) loop 172 | int shell_main(void) 173 | { 174 | int ret; 175 | 176 | restart: 177 | ret = chry_shell_task_repl(&csh); 178 | if (ret == -1) { 179 | // Execution failed or encountered an issue 180 | return -1; 181 | } else if (ret == 1) { 182 | // Non-blocking mode: Insufficient characters read during character input, return to perform other user tasks 183 | return 0; 184 | } else { 185 | // Execution successful, restart 186 | goto restart; 187 | } 188 | } 189 | ``` 190 | 191 | ``` c 192 | // Used to avoid competition between printf and shell for the same serial port, called before printf 193 | void shell_uart_lock(void) 194 | { 195 | chry_readline_erase_line(&csh.rl); 196 | } 197 | 198 | // Used to avoid competition between printf and shell for the same serial port, called after printf 199 | void shell_uart_unlock(void) 200 | { 201 | chry_readline_edit_refresh(&csh.rl); 202 | } 203 | ``` 204 | 205 | ``` c 206 | int main(void) 207 | { 208 | board_init(); 209 | board_init_led_pins(); 210 | 211 | shell_init(); 212 | 213 | uint32_t freq = clock_get_frequency(clock_mchtmr0); 214 | uint64_t time = mchtmr_get_count(HPM_MCHTMR) / (freq / 1000); 215 | 216 | while (1) { 217 | shell_main(); 218 | 219 | // Print every 5 seconds 220 | uint64_t now = mchtmr_get_count(HPM_MCHTMR) / (freq / 1000); 221 | if (now > time + 5000) { 222 | time = now; 223 | // Call the lock to avoid printf interfering with shell input 224 | shell_uart_lock(); 225 | printf("other task interval 5S\r\n"); 226 | shell_uart_unlock(); 227 | } 228 | } 229 | 230 | return 0; 231 | } 232 | 233 | ``` 234 | 235 | ``` c 236 | // Implement the export of a command 237 | // write_led 1 - Turn on the LED 238 | // write_led 0 - Turn off the LED 239 | static int write_led(int argc, char **argv) 240 | { 241 | if (argc < 2) { 242 | printf("usage: write_led \r\n\r\n"); 243 | printf(" status 0 or 1\r\n\r\n"); 244 | return -1; 245 | } 246 | 247 | board_led_write(atoi(argv[1]) == 0); 248 | return 0; 249 | } 250 | CSH_CMD_EXPORT(write_led, ); 251 | 252 | ``` 253 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # CherryShell 2 | 3 | [English](./README.md) 4 | 5 | ## 简介 6 | 7 | CherryShell是一个专为嵌入式应用程序而设计的微型Shell。 8 | 9 | ## 功能 10 | - [x] 支持路径补全,tab进行路径补全 11 | - [x] 支持命令补全,tab进行命令补全 12 | - [x] 支持环境变量,需使用 ``$` `作为前缀,例如` `$PATH`` 13 | - [x] 支持通过 ``$PATH`` 环境变量,自动在指定目录下搜索命令 14 | - [x] 支持历史记录,通过 ``↑`` ``↓`` 按键 15 | - [x] 兼容 VT100 以及 Xterm 键值 16 | - [x] 支持设定用户名、主机名、路径 17 | - [x] 支持非阻塞模式 18 | - [x] 支持用户登录,需要实现hash函数,默认strcmp 19 | - [ ] 支持``Ctrl + \`` ``Alt + \`` ``F1-F12`` 快捷键调用命令 20 | - [ ] 支持``Ctrl + \`` ``Alt + \`` ``F1-F12`` 按键功能重映射 21 | - [ ] 支持 exec 函数簇,直接调用命令 22 | - [ ] 支持文件系统,FatFS,FileX,LittleFS,RomFS等 23 | - [ ] 支持环境变量添加、修改、删除、读出 24 | - [ ] 支持信号处理,捕获和处理不同的信号,例如Ctrl+C``SIGINT``和Ctrl+Z``SIGTSTP`` 25 | - [ ] 支持 exit 函数实现终止命令执行以及现场返回并调用设定的handler,利用setjmp实现(裸机) 26 | - [ ] 支持输入输出重定向功能 27 | - [ ] 支持多用户命令权限 28 | - [ ] 支持作业控制,可以在前台或后台运行命令,并使用相关的控制命令(如fg、bg、jobs)来管理和操作作业 29 | 30 | ## 示例 31 | 32 | ![测试1](./doc/test1.png) 33 | 34 | ![测试2](./doc/test2.png) 35 | 36 | ## 移植 37 | 38 | 以先楫半导体hpm5301evklite为例。 39 | 40 | 命令查找采用的是 gcc 的 section 功能,因此,我们需要先修改 linkerscript 文件,增加相关 section,举例 gcc ld 文件: 41 | 42 | ``` 43 | .text : { 44 | ..... 45 | 46 | . = ALIGN(4); 47 | __fsymtab_start = .; 48 | KEEP(*(FSymTab)) 49 | __fsymtab_end = .; 50 | . = ALIGN(4); 51 | __vsymtab_start = .; 52 | KEEP(*(VSymTab)) 53 | __vsymtab_end = .; 54 | . = ALIGN(4); 55 | } 56 | 57 | ``` 58 | 59 | ``` c 60 | // 包含头文件 61 | #include "csh.h" 62 | 63 | // 创建一个shell实例 64 | static chry_shell_t csh; 65 | 66 | ``` 67 | 68 | ``` c 69 | // 字符输出函数,将字符直接输出到串口 70 | static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size) 71 | { 72 | uint16_t i; 73 | (void)rl; 74 | for (i = 0; i < size; i++) { 75 | if (status_success != uart_send_byte(HPM_UART0, ((uint8_t *)data)[i])) { 76 | break; 77 | } 78 | } 79 | 80 | // 返回成功输出的字符数量 81 | return i; 82 | } 83 | 84 | ``` 85 | 86 | ``` c 87 | // 字符输入函数,直接从串口读入字符,如果波特率较高可以增加一个FIFO缓冲输入 88 | static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size) 89 | { 90 | uint16_t i; 91 | (void)rl; 92 | for (i = 0; i < size; i++) { 93 | if (status_success != uart_receive_byte(HPM_UART0, (uint8_t *)data + i)) { 94 | break; 95 | } 96 | } 97 | 98 | // 返回成功读取的字符数量 99 | return i; 100 | } 101 | ``` 102 | 103 | ``` c 104 | // shell 初始化 105 | int shell_init(void) 106 | { 107 | // 结构体用于配置初始化参数 108 | chry_shell_init_t csh_init; 109 | 110 | // 设置字符输入输出函数(必须实现) 111 | csh_init.sput = csh_sput_cb; 112 | csh_init.sget = csh_sget_cb; 113 | 114 | // linkscript 中定义的符号,用于存放导出的命令和变量 115 | extern const int __fsymtab_start; 116 | extern const int __fsymtab_end; 117 | extern const int __vsymtab_start; 118 | extern const int __vsymtab_end; 119 | 120 | // 配置函数表和变量表的起始和结束地址(必须实现) 121 | csh_init.command_table_beg = &__fsymtab_start; 122 | csh_init.command_table_end = &__fsymtab_end; 123 | csh_init.variable_table_beg = &__vsymtab_start; 124 | csh_init.variable_table_end = &__vsymtab_end; 125 | 126 | // 定义一个提示符缓冲区 127 | static char csh_prompt_buffer[128]; 128 | // 配置提示符缓冲区(可选) 129 | // 取决于是否使能可编辑提示符功能 CONFIG_CSH_PROMPTEDIT 130 | csh_init.prompt_buffer = csh_prompt_buffer; 131 | csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer); 132 | 133 | // 定义一个历史记录缓冲区,缓冲的命令条数取决于缓冲区大小以及命令长度 134 | static char csh_history_buffer[128]; 135 | 136 | // 配置历史记录缓冲区(可选) 137 | // 取决于是否使能历史记录功能 CONFIG_CSH_LNBUFF_STATIC 138 | csh_init.history_buffer = csh_history_buffer; 139 | csh_init.history_buffer_size = sizeof(csh_history_buffer); 140 | 141 | // 定义一个行输入缓冲区,最大输入的单条命令无法超过缓冲区长度 142 | static char csh_line_buffer[128]; 143 | 144 | // 配置行输入缓冲区(可选) 145 | // 取决于是否使能静态行缓冲区功能 CONFIG_CSH_LNBUFF_STATIC 146 | // 如果不使能静态行缓冲区功能,行缓冲区将存在于栈上,此时不能使用非阻塞模式 147 | // 即 CONFIG_CSH_NOBLOCK 必须为0 148 | csh_init.line_buffer = csh_line_buffer; 149 | csh_init.line_buffer_size = sizeof(csh_line_buffer); 150 | 151 | // 用户数量默认为1 152 | csh_init.uid = 0; // 默认用户ID 153 | csh_init.user[0] = "cherry"; // 用户ID0的用户名 154 | csh_init.hash[0] = NULL; // 用户ID0的密码哈希值 155 | csh_init.host = "hpm5301evklite"; // Host的名称 156 | 157 | // 初始化 158 | int ret = chry_shell_init(&csh, &csh_init); 159 | if (ret) { 160 | return -1; 161 | } 162 | 163 | return 0; 164 | } 165 | ``` 166 | 167 | ``` c 168 | // shell 的主函数,需要再while(1)中循环调用 169 | int shell_main(void) 170 | { 171 | int ret; 172 | 173 | restart: 174 | ret = chry_shell_task_repl(&csh); 175 | if (ret == -1) { 176 | // 执行失败或者出现问题 177 | return -1; 178 | } else if (ret == 1) { 179 | // 非阻塞模式执行读取字符时读出字符不足,先返回执行用户其他工作 180 | return 0; 181 | } else { 182 | // 执行成功结束,重新执行 183 | goto restart; 184 | } 185 | 186 | } 187 | 188 | ``` 189 | 190 | ``` c 191 | // 用于避免printf和shell竞争同一个串口,printf之前调用 192 | void shell_uart_lock(void) 193 | { 194 | chry_readline_erase_line(&csh.rl); 195 | } 196 | 197 | // 用于避免printf和shell竞争同一个串口,printf之后调用 198 | void shell_uart_unlock(void) 199 | { 200 | chry_readline_edit_refresh(&csh.rl); 201 | } 202 | ``` 203 | 204 | ``` c 205 | 206 | int main(void) 207 | { 208 | board_init(); 209 | board_init_led_pins(); 210 | 211 | shell_init(); 212 | 213 | uint32_t freq = clock_get_frequency(clock_mchtmr0); 214 | uint64_t time = mchtmr_get_count(HPM_MCHTMR) / (freq / 1000); 215 | 216 | while (1) { 217 | shell_main(); 218 | 219 | // 每5秒打印一次 220 | uint64_t now = mchtmr_get_count(HPM_MCHTMR) / (freq / 1000); 221 | if (now > time + 5000) { 222 | time = now; 223 | // 打印时需要调用锁,避免printf影响shell输入 224 | shell_uart_lock(); 225 | printf("other task interval 5S\r\n"); 226 | shell_uart_unlock(); 227 | } 228 | } 229 | 230 | return 0; 231 | } 232 | ``` 233 | 234 | ``` c 235 | // 实现一个命令的导出 236 | // write_led 1 点亮LED 237 | // write_led 0 熄灭LED 238 | static int write_led(int argc, char **argv) 239 | { 240 | if (argc < 2) { 241 | printf("usage: write_led \r\n\r\n"); 242 | printf(" status 0 or 1\r\n\r\n"); 243 | return -1; 244 | } 245 | 246 | board_led_write(atoi(argv[1]) == 0); 247 | return 0; 248 | } 249 | CSH_CMD_EXPORT(write_led, ); 250 | 251 | ``` 252 | -------------------------------------------------------------------------------- /builtin/help.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "csh.h" 12 | 13 | /*!< help */ 14 | static int help(int argc, char **argv) 15 | { 16 | chry_shell_t *csh = (void *)argv[argc + 1]; 17 | uint16_t longest_name; 18 | bool enable_function = true; 19 | bool enable_variable = true; 20 | 21 | while (argc > 1) { 22 | argc--; 23 | argv++; 24 | } 25 | 26 | if (enable_function) { 27 | csh_printf(csh, "total function %d\r\n", 28 | ((uintptr_t)csh->cmd_tbl_end - (uintptr_t)csh->cmd_tbl_beg) / sizeof(chry_syscall_t)); 29 | } 30 | 31 | longest_name = 0; 32 | for (const chry_syscall_t *call = csh->cmd_tbl_beg; call < csh->cmd_tbl_end; call++) { 33 | uint16_t len = strlen(call->name); 34 | longest_name = len > longest_name ? len : longest_name; 35 | } 36 | 37 | for (const chry_syscall_t *call = csh->cmd_tbl_beg; call < csh->cmd_tbl_end; call++) { 38 | uint16_t len = strlen(call->name); 39 | 40 | csh_printf(csh, " \e[32m%s\e[m", call->name); 41 | 42 | for (int k = len; k < longest_name; k++) { 43 | csh_printf(csh, " "); 44 | } 45 | 46 | csh_printf(csh, " -> "); 47 | 48 | csh_printf(csh, call->path); 49 | 50 | csh_printf(csh, "\r\n"); 51 | } 52 | 53 | if (enable_variable) { 54 | if (enable_function) { 55 | csh_printf(csh, "\r\n"); 56 | } 57 | 58 | csh_printf(csh, "total variable %d\r\n", 59 | ((uintptr_t)csh->var_tbl_end - (uintptr_t)csh->var_tbl_beg) / sizeof(chry_sysvar_t)); 60 | } 61 | 62 | longest_name = 0; 63 | for (const chry_sysvar_t *var = csh->var_tbl_beg; var < csh->var_tbl_end; var++) { 64 | uint16_t len = strlen(var->name); 65 | longest_name = len > longest_name ? len : longest_name; 66 | } 67 | 68 | for (const chry_sysvar_t *var = csh->var_tbl_beg; var < csh->var_tbl_end; var++) { 69 | uint16_t len = strlen(var->name); 70 | 71 | csh_printf(csh, " $\e[33m%s\e[m", var->name); 72 | 73 | for (int k = len; k < longest_name; k++) { 74 | csh_printf(csh, " "); 75 | } 76 | 77 | char cr = var->attr & CSH_VAR_READ ? 'r' : '-'; 78 | char cw = var->attr & CSH_VAR_WRITE ? 'w' : '-'; 79 | csh_printf(csh, " %c%c %3d\r\n", cr, cw, var->attr & CSH_VAR_SIZE); 80 | } 81 | 82 | return 0; 83 | } 84 | 85 | CSH_SCMD_EXPORT(help, ); 86 | -------------------------------------------------------------------------------- /builtin/login.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "csh.h" 12 | 13 | /*!< login */ 14 | int csh_login(chry_shell_t *csh) 15 | { 16 | int ret = 0; 17 | char *password; 18 | char first = 0; 19 | 20 | #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC 21 | #define BUFFER_SIZE csh->buffsize 22 | char *buffer = csh->linebuff; 23 | uint16_t *linesize = &csh->linesize; 24 | #else 25 | #define BUFFER_SIZE 64 26 | static char buffer[BUFFER_SIZE]; 27 | uint16_t _linesize; 28 | uint16_t *linesize = &_linesize; 29 | #endif 30 | 31 | #if defined(CONFIG_CSH_NOBLOCK) && CONFIG_CSH_NOBLOCK 32 | if (csh->rl.noblock && !csh->rl.block) { 33 | goto restore; 34 | } 35 | #endif 36 | 37 | retry: 38 | csh_printf(csh, "login as: %s\r\n", csh->user[csh->uid]); 39 | csh_printf(csh, "%s@%s's password:\r\n", csh->user[csh->uid], csh->host); 40 | chry_readline_mask(&csh->rl, true); 41 | first = csh->rl.prompt[0]; 42 | csh->rl.prompt[0] = '\0'; 43 | 44 | #if defined(CONFIG_CSH_NOBLOCK) && CONFIG_CSH_NOBLOCK 45 | restore: 46 | #endif 47 | 48 | password = chry_readline(&csh->rl, buffer, BUFFER_SIZE, linesize); 49 | 50 | #if defined(CONFIG_CSH_NOBLOCK) && CONFIG_CSH_NOBLOCK 51 | if (csh->rl.noblock && !csh->rl.block) { 52 | return 1; 53 | } 54 | #endif 55 | 56 | csh->rl.prompt[0] = first; 57 | chry_readline_mask(&csh->rl, false); 58 | 59 | if (password == NULL) { 60 | return -1; 61 | } else { 62 | ret = chry_shell_substitute_user(csh, csh->uid, password); 63 | if (ret != 0) { 64 | csh_printf(csh, "\e[31mincorrect password\e[0m\r\n\r\n"); 65 | goto retry; 66 | } 67 | 68 | csh_printf(csh, "welcome to cherry shell\r\n"); 69 | 70 | return ret; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /builtin/shsize.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "csh.h" 13 | 14 | /*!< shsize */ 15 | static int shsize(int argc, char **argv) 16 | { 17 | chry_shell_t *csh = (void *)argv[argc + 1]; 18 | char *prgname = argv[0]; 19 | 20 | if ((argc == 2) && !strcmp(argv[1], "--update")) { 21 | if (5 != csh->rl.sput(&csh->rl, "\e[18t", 5)) { 22 | csh_printf(csh, "Failed to request update\r\n"); 23 | return -1; 24 | } 25 | return 0; 26 | } else if ((argc == 4) && !strcmp(argv[1], "--config")) { 27 | int row = atoi(argv[2]); 28 | int col = atoi(argv[3]); 29 | if (row > 10 && row < 4096) { 30 | csh->rl.term.row = row; 31 | } else { 32 | csh_printf(csh, "Illegal row %d\r\n", row); 33 | } 34 | if (col > 10 && col < 4096) { 35 | csh->rl.term.col = col; 36 | } else { 37 | csh_printf(csh, "Illegal col %d\r\n", col); 38 | } 39 | } else if (argc == 1) { 40 | } else { 41 | csh_printf(csh, "Usage: %s [--update | --config \r\n", prgname); 42 | return 0; 43 | } 44 | 45 | csh_printf(csh, "Window config to row:%d col:%d\r\n", csh->rl.term.row, csh->rl.term.col); 46 | 47 | return 0; 48 | } 49 | 50 | CSH_SCMD_EXPORT(shsize, ); 51 | -------------------------------------------------------------------------------- /cherryrl/.clang-format: -------------------------------------------------------------------------------- 1 | # clang-format configuration file. Intended for clang-format >= 11.0 2 | # 3 | # For more information, see: 4 | # 5 | # https://clang.llvm.org/docs/ClangFormat.html 6 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 7 | # 8 | --- 9 | # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto 10 | Language: Cpp 11 | # BasedOnStyle: LLVM 12 | # 访问说明符(public、private等)的偏移 13 | AccessModifierOffset: -4 14 | # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) 15 | AlignAfterOpenBracket: Align 16 | # 连续赋值时,对齐所有等号 17 | AlignConsecutiveAssignments: false 18 | # 对齐位域 19 | AlignConsecutiveBitFields: true 20 | # 连续声明时,对齐所有声明的变量名 21 | AlignConsecutiveDeclarations: false 22 | # 连续宏时,进行对齐 23 | AlignConsecutiveMacros: true 24 | # 左对齐逃脱换行(使用反斜杠换行)的反斜杠 25 | AlignEscapedNewlines: Left 26 | # 水平对齐二元和三元表达式的操作数 27 | AlignOperands: true 28 | # 对齐连续的尾随的注释 29 | AlignTrailingComments: true 30 | # 允许函数声明的所有参数在放在下一行 31 | AllowAllParametersOfDeclarationOnNextLine: false 32 | # 允许短的块放在同一行 33 | AllowShortBlocksOnASingleLine: false 34 | # 允许短的case标签放在同一行 35 | AllowShortCaseLabelsOnASingleLine: false 36 | # 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All 37 | AllowShortFunctionsOnASingleLine: None 38 | # 允许短的if语句保持在同一行 39 | AllowShortIfStatementsOnASingleLine: false 40 | # 允许短的循环保持在同一行 41 | AllowShortLoopsOnASingleLine: false 42 | # 总是在定义返回类型后换行(deprecated) 43 | AlwaysBreakAfterDefinitionReturnType: None 44 | # 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), 45 | # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) 46 | AlwaysBreakAfterReturnType: None 47 | # 总是在多行string字面量前换行 48 | AlwaysBreakBeforeMultilineStrings: false 49 | # 总是在template声明后换行 50 | AlwaysBreakTemplateDeclarations: false 51 | # false表示函数实参要么都在同一行,要么都各自一行 52 | BinPackArguments: true 53 | # false表示所有形参要么都在同一行,要么都各自一行 54 | BinPackParameters: true 55 | # 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 56 | BraceWrapping: 57 | AfterClass: false 58 | AfterControlStatement: false 59 | AfterEnum: false 60 | AfterFunction: true 61 | AfterNamespace: false 62 | AfterObjCDeclaration: false 63 | AfterStruct: false 64 | AfterUnion: false 65 | AfterExternBlock: false # Unknown to clang-format-5.0 66 | BeforeCatch: false 67 | BeforeElse: false 68 | IndentBraces: false 69 | SplitEmptyFunction: true # Unknown to clang-format-4.0 70 | SplitEmptyRecord: true # Unknown to clang-format-4.0 71 | SplitEmptyNamespace: true # Unknown to clang-format-4.0 72 | # 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) 73 | BreakBeforeBinaryOperators: None 74 | BreakBeforeBraces: Custom 75 | #BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 76 | # 在三元运算符前换行 77 | BreakBeforeTernaryOperators: false 78 | # 在构造函数的初始化列表的逗号前换行 79 | BreakConstructorInitializersBeforeComma: false 80 | BreakAfterJavaFieldAnnotations: false 81 | BreakStringLiterals: false 82 | # 每行字符的限制,0表示没有限制 83 | ColumnLimit: 0 84 | # 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 85 | CommentPragmas: '^ IWYU pragma:' 86 | CompactNamespaces: false # Unknown to clang-format-4.0 87 | # 构造函数的初始化列表要么都在同一行,要么都各自一行 88 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 89 | # 构造函数的初始化列表的缩进宽度 90 | ConstructorInitializerIndentWidth: 4 91 | # 延续的行的缩进宽度 92 | ContinuationIndentWidth: 4 93 | # 去除C++11的列表初始化的大括号{后和}前的空格 94 | Cpp11BracedListStyle: false 95 | # 继承最常用的指针和引用的对齐方式 96 | DerivePointerAlignment: false 97 | # 关闭格式化 98 | DisableFormat: false 99 | ForEachMacros: 100 | - 'SHELL_EXPORT_CMD' 101 | 102 | # 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) 103 | ExperimentalAutoDetectBinPacking: false 104 | # 缩进case标签 105 | IndentCaseLabels: true 106 | # 缩进宽度 107 | IndentWidth: 4 108 | # 函数返回类型换行时,缩进函数声明或函数定义的函数名 109 | IndentWrappedFunctionNames: false 110 | # 保留在块开始处的空行 111 | KeepEmptyLinesAtTheStartOfBlocks: false 112 | # 开始一个块的宏的正则表达式 113 | MacroBlockBegin: '' 114 | # 结束一个块的宏的正则表达式 115 | MacroBlockEnd: '' 116 | # 连续空行的最大数量 117 | MaxEmptyLinesToKeep: 1 118 | # 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All 119 | NamespaceIndentation: None 120 | # 使用ObjC块时缩进宽度 121 | ObjCBlockIndentWidth: 4 122 | # 在ObjC的@property后添加一个空格 123 | ObjCSpaceAfterProperty: false 124 | # 在ObjC的protocol列表前添加一个空格 125 | ObjCSpaceBeforeProtocolList: true 126 | # 在call(后对函数调用换行的penalty 127 | PenaltyBreakBeforeFirstCallParameter: 30 128 | # 在一个注释中引入换行的penalty 129 | PenaltyBreakComment: 10 130 | # 第一次在<<前换行的penalty 131 | PenaltyBreakFirstLessLess: 0 132 | # 在一个字符串字面量中引入换行的penalty 133 | PenaltyBreakString: 10 134 | # 对于每个在行字符数限制之外的字符的penalty 135 | PenaltyExcessCharacter: 100 136 | # 将函数的返回类型放到它自己的行的penalty 137 | PenaltyReturnTypeOnItsOwnLine: 60 138 | # 指针和引用的对齐: Left, Right, Middle 139 | PointerAlignment: Right 140 | # 允许重新排版注释 141 | ReflowComments: false 142 | # 允许排序#include 143 | SortIncludes: false 144 | # 在C风格类型转换后添加空格 145 | SpaceAfterCStyleCast: false 146 | # 在赋值运算符之前添加空格 147 | SpaceBeforeAssignmentOperators: true 148 | # 开圆括号之前添加一个空格: Never, ControlStatements, Always 149 | SpaceBeforeParens: ControlStatements 150 | # 在空的圆括号中添加空格 151 | SpaceInEmptyParentheses: false 152 | # 在尾随的评论前添加的空格数(只适用于//) 153 | SpacesBeforeTrailingComments: 1 154 | # 在尖括号的<后和>前添加空格 155 | SpacesInAngles: false 156 | # 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 157 | SpacesInContainerLiterals: false 158 | # 在C风格类型转换的括号中添加空格 159 | SpacesInCStyleCastParentheses: false 160 | # 在圆括号的(后和)前添加空格 161 | SpacesInParentheses: false 162 | # 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 163 | SpacesInSquareBrackets: false 164 | # 标准: Cpp03, Cpp11, Auto 165 | Standard: Cpp03 166 | # tab宽度 167 | TabWidth: 4 168 | # 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always 169 | UseTab: Never 170 | ... 171 | 172 | -------------------------------------------------------------------------------- /cherryrl/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | example -------------------------------------------------------------------------------- /cherryrl/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [1.0.0] - 2024-03-09: 4 | 5 | All changes 6 | 7 | ### Added 8 | - first commit 9 | - update readme 10 | - add change log 11 | - [feat] add noblock mode, CONFIG_READLINE_NOBLOCK 12 | - [feat] add prompt auto refresh, CONFIG_READLINE_REFRESH_PROMPT 13 | - [fix] disable completion in mask mode 14 | - [feat] callback add param chry_readline_t *rl 15 | - [fix] fix chry_readline_calculate_prompt pptsize check 16 | - [fix] fix some function error return value 17 | - [fix] fix unused variable warning 18 | - [fix] fix param check in history disabled mode 19 | - [feat] merge function callback and user event callback 20 | - [feat] add EXEC EOF_;SIGINT_;EOF;SIGINT;SIGQUIT;SIGCONT;SIGSTOP;SIGTSTP 21 | - [feat] add ignore mode 22 | - [feat] add erase to end of line api 23 | - [feat] add EOF_ to EOF;SIGINT_ to SIGINT auto convert 24 | - [fix] chry_readline arg3 arg4 change uint32_t to uint16_t 25 | - [feat] add auto_refresh control 26 | - [feat] add chry_readline_config.h 27 | - [fix] line edit add end '\0' 28 | - [feat] add CONFIG_READLINE_MAX_COMPLETION, argv argl is now saved on the stack 29 | - [fix] fix sput parameter 2, add const qualifier 30 | - [feat] add force block mode by chry_readline_block 31 | -------------------------------------------------------------------------------- /cherryrl/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /cherryrl/Makefile: -------------------------------------------------------------------------------- 1 | example: chry_readline_keycode.h chry_readline_config.h chry_readline.h chry_readline.c 2 | 3 | example: chry_readline.c example.c 4 | $(CC) -Wall -W -Wno-unused-function -Og -g3 -o example chry_readline.c example.c 5 | 6 | clean: 7 | rm -f example 8 | -------------------------------------------------------------------------------- /cherryrl/README.md: -------------------------------------------------------------------------------- 1 | # CherryReadLine 2 | 3 | CherryReadLine is a tiny designed readline and libedit replacement specifically for deeply embedded applications. 4 | 5 | ## Feature 6 | 7 | - No dynamic memory used 8 | - Support all single keycodes 9 | - Support vt map ``F1 - F12`` ``HOME`` ``INSERT`` ``DELETE`` ``END`` ``PAGE UP`` ``PAGE DN`` 10 | - Support xterm map ``F1 - F4`` ``UP`` ``DOWN`` ``RIGHT`` ``LEFT`` ``END`` ``HOME`` 11 | - Support EXEC ``CLR`` ``NLN`` ``ALN`` ``DEL`` ``BS`` ``MVRT`` ``MVLT`` ``MVED`` ``MVHM`` ``NXTH`` ``PRVH`` ``DLWD`` ``DHLN`` ``DELN`` 12 | - Support key combination with ``Ctrl + A~Z`` or ``Alt + A~Z`` 13 | - Support history with ``↑`` or ``↓`` 14 | - Support cursor movement with ``delete``, ``←``, ``→``, ``HOME`` or ``END`` 15 | - Support completion, default with ``TAB``, you can use map api to change keycode for completion 16 | - Support format list of completion 17 | - Support multiline prompt 18 | - Support color prompt 19 | - Support ``Ctrl + \`` mapping 20 | - Support ``Alt + \`` mapping 21 | - Support auto select completion or space 22 | - Support Xterm alt screen buffer mode 23 | - Support prompt edit API 24 | - Support line edit API 25 | - Support python style using prompt edit API 26 | - Support map some keycodes for user event 27 | - Support debug keycodes 28 | - Support mask mode 29 | - Support non-block mode 30 | - Support ignore mode 31 | -------------------------------------------------------------------------------- /cherryrl/chry_readline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CHRY_READLINE_H 8 | #define CHRY_READLINE_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include 15 | #include "chry_readline_keycode.h" 16 | #include "chry_readline_config.h" 17 | 18 | #if defined(CONFIG_READLINE_XTERM) && defined(CONFIG_READLINE_NOBLOCK) 19 | #if CONFIG_READLINE_XTERM && CONFIG_READLINE_NOBLOCK 20 | #error "CONFIG_READLINE_XTERM cannot be configured at the same time as CONFIG_READLINE_NOBLOCK" 21 | #endif 22 | #endif 23 | 24 | enum { 25 | CHRY_READLINE_SGR_NONE = 0, 26 | CHRY_READLINE_SGR_BLACK = 1, 27 | CHRY_READLINE_SGR_RED = 2, 28 | CHRY_READLINE_SGR_GREEN = 3, 29 | CHRY_READLINE_SGR_YELLOW = 4, 30 | CHRY_READLINE_SGR_BLUE = 5, 31 | CHRY_READLINE_SGR_MAGENTA = 6, 32 | CHRY_READLINE_SGR_CYAN = 7, 33 | CHRY_READLINE_SGR_WHITE = 8, 34 | CHRY_READLINE_SGR_DEFAULT = 10 35 | }; 36 | 37 | typedef struct chry_readline { 38 | char *prompt; /*!< prompt pointer */ 39 | uint16_t (*sput)(struct chry_readline *rl, const void *data, uint16_t size); 40 | uint16_t (*sget)(struct chry_readline *rl, void *data, uint16_t size); 41 | 42 | struct 43 | { 44 | struct { 45 | uint16_t size; /*!< linesize */ 46 | char pbuf[0]; /*!< linebuff pointer */ 47 | } *buff; 48 | 49 | uint16_t pptsize; /*!< prompt size */ 50 | uint16_t pptoff; /*!< prompt offset */ 51 | uint16_t pptlen; /*!< prompt strlen */ 52 | uint16_t lnmax; /*!< linebuff max */ 53 | uint16_t curoff; /*!< cursor offset */ 54 | uint16_t mask; /*!< line mask */ 55 | } ln; 56 | 57 | struct 58 | { 59 | union { 60 | uint16_t altnsupt; /*!< is screen not supported but alt buffer */ 61 | struct { 62 | uint8_t nsupt; /*!< is screen not supported */ 63 | uint8_t alt; /*!< is screen alt buffer */ 64 | }; 65 | }; 66 | uint16_t row; /*!< terminal row */ 67 | uint16_t col; /*!< terminal column */ 68 | } term; 69 | 70 | #if defined(CONFIG_READLINE_COMPLETION) && CONFIG_READLINE_COMPLETION 71 | struct { 72 | uint8_t (*acb)(struct chry_readline *rl, char *pre, uint16_t *size, const char **argv, uint8_t *argl, uint8_t argcmax); 73 | } cplt; 74 | #endif 75 | 76 | #if defined(CONFIG_READLINE_HISTORY) && CONFIG_READLINE_HISTORY 77 | struct { 78 | char *pbuf; /*!< histfifo buffer */ 79 | uint16_t in; /*!< histfifo in pos */ 80 | uint16_t out; /*!< histfifo out pos */ 81 | uint16_t mask; /*!< histfifo mask */ 82 | uint16_t size; /*!< histfifo size */ 83 | uint16_t cache; /*!< history cache */ 84 | uint16_t index; /*!< history index */ 85 | } hist; 86 | #endif 87 | 88 | int (*ucb)(struct chry_readline *rl, uint8_t exec); 89 | 90 | uint8_t ignore; /*!< only accept */ 91 | uint8_t auto_refresh; /*!< auto refresh */ 92 | 93 | #if defined(CONFIG_READLINE_CTRLMAP) && CONFIG_READLINE_CTRLMAP 94 | uint8_t ctrlmap[32]; 95 | #endif 96 | 97 | #if defined(CONFIG_READLINE_ALTMAP) && CONFIG_READLINE_ALTMAP 98 | uint8_t altmap[26]; 99 | #endif 100 | 101 | #if defined(CONFIG_READLINE_PROMPTEDIT) && CONFIG_READLINE_PROMPTEDIT 102 | uint8_t pptseglen[CONFIG_READLINE_PROMPTSEG + 1]; 103 | #endif 104 | 105 | #if defined(CONFIG_READLINE_NOBLOCK) && CONFIG_READLINE_NOBLOCK 106 | uint8_t noblock; 107 | uint8_t block; 108 | #endif 109 | 110 | } chry_readline_t; 111 | 112 | typedef struct { 113 | char *prompt; /*!< prompt buffer pointer */ 114 | uint16_t pptsize; /*!< prompt buffer size */ 115 | char *history; /*!< history buffer pointer */ 116 | uint16_t histsize; /*!< history buffer size, must be a power of 2 */ 117 | uint16_t (*sput)(chry_readline_t *rl, const void *, uint16_t); 118 | uint16_t (*sget)(chry_readline_t *rl, void *, uint16_t); 119 | } chry_readline_init_t; 120 | 121 | typedef struct 122 | { 123 | union { 124 | uint16_t raw; 125 | struct 126 | { 127 | uint16_t foreground : 6; 128 | uint16_t bold : 1; 129 | uint16_t underline : 1; 130 | uint16_t background : 6; 131 | uint16_t blink : 1; 132 | uint16_t inverse : 1; 133 | }; 134 | }; 135 | } chry_readline_sgr_t; 136 | 137 | extern int chry_readline_init(chry_readline_t *rl, chry_readline_init_t *init); 138 | extern void chry_readline_debug(chry_readline_t *rl); 139 | extern char *chry_readline(chry_readline_t *rl, char *linebuff, uint16_t buffsize, uint16_t *linesize); 140 | 141 | extern int chry_readline_edit_refresh(chry_readline_t *rl); 142 | extern int chry_readline_edit_clear(chry_readline_t *rl); 143 | extern int chry_readline_edit_insert(chry_readline_t *rl, char c); 144 | extern int chry_readline_edit_backspace(chry_readline_t *rl); 145 | extern int chry_readline_edit_delete(chry_readline_t *rl); 146 | extern int chry_readline_edit_moveleft(chry_readline_t *rl); 147 | extern int chry_readline_edit_moveright(chry_readline_t *rl); 148 | extern int chry_readline_edit_movehome(chry_readline_t *rl); 149 | extern int chry_readline_edit_moveend(chry_readline_t *rl); 150 | extern int chry_readline_edit_delline(chry_readline_t *rl); 151 | extern int chry_readline_edit_delend(chry_readline_t *rl); 152 | extern int chry_readline_edit_delword(chry_readline_t *rl); 153 | 154 | extern int chry_readline_complete(chry_readline_t *rl); 155 | 156 | extern void chry_readline_erase_line(chry_readline_t *rl); 157 | extern void chry_readline_newline(chry_readline_t *rl); 158 | extern void chry_readline_detect(chry_readline_t *rl); 159 | extern void chry_readline_clear(chry_readline_t *rl); 160 | extern void chry_readline_block(chry_readline_t *rl, uint8_t enable); 161 | extern void chry_readline_ignore(chry_readline_t *rl, uint8_t enable); 162 | extern void chry_readline_auto_refresh(chry_readline_t *rl, uint8_t enable); 163 | extern void chry_readline_mask(chry_readline_t *rl, uint8_t enable); 164 | extern int chry_readline_altscreen(chry_readline_t *rl, uint8_t enable); 165 | 166 | extern void chry_readline_set_completion_cb(chry_readline_t *rl, uint8_t (*acb)(chry_readline_t *rl, char *pre, uint16_t *size, const char **argv, uint8_t *argl, uint8_t argcmax)); 167 | extern void chry_readline_set_user_cb(chry_readline_t *rl, int (*ucb)(chry_readline_t *rl, uint8_t exec)); 168 | extern void chry_readline_set_ctrlmap(chry_readline_t *rl, uint8_t mapidx, uint8_t exec); 169 | extern void chry_readline_set_altmap(chry_readline_t *rl, uint8_t mapidx, uint8_t exec); 170 | 171 | extern int chry_readline_prompt_edit(chry_readline_t *rl, uint8_t segidx, uint16_t sgrraw, const char *format, ...); 172 | extern void chry_readline_prompt_clear(chry_readline_t *rl); 173 | 174 | #ifdef __cplusplus 175 | } 176 | #endif 177 | 178 | #endif 179 | -------------------------------------------------------------------------------- /cherryrl/chry_readline_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CHRY_READLINE_CONFIG_H 8 | #define CHRY_READLINE_CONFIG_H 9 | 10 | #ifdef CONFIG_READLINE_USER_DEFINE_FILE 11 | #include "chry_readline_user.h" 12 | #endif 13 | 14 | /*!< argument check */ 15 | #ifndef CONFIG_READLINE_DEBUG 16 | #define CONFIG_READLINE_DEBUG 0 17 | #endif 18 | 19 | /*!< default row */ 20 | #ifndef CONFIG_READLINE_DFTROW 21 | #define CONFIG_READLINE_DFTROW 25 22 | #endif 23 | 24 | /*!< default column */ 25 | #ifndef CONFIG_READLINE_DFTCOL 26 | #define CONFIG_READLINE_DFTCOL 80 27 | #endif 28 | 29 | /*!< history support <+600byte> */ 30 | #ifndef CONFIG_READLINE_HISTORY 31 | #define CONFIG_READLINE_HISTORY 1 32 | #endif 33 | 34 | /*!< completion support <+800byte> */ 35 | #ifndef CONFIG_READLINE_COMPLETION 36 | #define CONFIG_READLINE_COMPLETION 1 37 | #endif 38 | 39 | /*!< max completion item list count (use stack 4 x count byte) */ 40 | #ifndef CONFIG_READLINE_MAX_COMPLETION 41 | #define CONFIG_READLINE_MAX_COMPLETION 40 42 | #endif 43 | 44 | /*!< prompt edit support <+900byte> */ 45 | #ifndef CONFIG_READLINE_PROMPTEDIT 46 | #define CONFIG_READLINE_PROMPTEDIT 1 47 | #endif 48 | 49 | /*!< prompt segment count */ 50 | #ifndef CONFIG_READLINE_PROMPTSEG 51 | #define CONFIG_READLINE_PROMPTSEG 7 52 | #endif 53 | 54 | /*!< xterm support */ 55 | #ifndef CONFIG_READLINE_XTERM 56 | #define CONFIG_READLINE_XTERM 0 57 | #endif 58 | 59 | /*!< newline */ 60 | #ifndef CONFIG_READLINE_NEWLINE 61 | #define CONFIG_READLINE_NEWLINE "\r\n" 62 | #endif 63 | 64 | /*!< tab space count */ 65 | #ifndef CONFIG_READLINE_SPACE 66 | #define CONFIG_READLINE_SPACE 4 67 | #endif 68 | 69 | /*!< independent ctrl map */ 70 | #ifndef CONFIG_READLINE_CTRLMAP 71 | #define CONFIG_READLINE_CTRLMAP 0 72 | #endif 73 | 74 | /*!< independent alt map */ 75 | #ifndef CONFIG_READLINE_ALTMAP 76 | #define CONFIG_READLINE_ALTMAP 0 77 | #endif 78 | 79 | /*!< refresh prompt */ 80 | #ifndef CONFIG_READLINE_REFRESH_PROMPT 81 | #define CONFIG_READLINE_REFRESH_PROMPT 1 82 | #endif 83 | 84 | /*!< no waiting for sget */ 85 | #ifndef CONFIG_READLINE_NOBLOCK 86 | #define CONFIG_READLINE_NOBLOCK 0 87 | #endif 88 | 89 | /*!< help information */ 90 | #ifndef CONFIG_READLINE_HELP 91 | #define CONFIG_READLINE_HELP "" 92 | #endif 93 | 94 | /* 95 | "\r\n" 96 | "\t+-------------------------------------+\r\n" 97 | "\t| \e[1;31mCherry ReadLine \e[m |\r\n" 98 | "\t| |\r\n" 99 | "\t| -> CTRL + ^ return normal screen |\r\n" 100 | "\t| -> CTRL + - show this help |\r\n" 101 | "\t| -> CTRL + C abort line |\r\n" 102 | "\t| -> CTRL + K delete cursor to end |\r\n" 103 | "\t| -> CTRL + L clear screen |\r\n" 104 | "\t| -> CTRL + U delete whole line |\r\n" 105 | "\t| -> CTRL + W delete prev word |\r\n" 106 | "\t| -> CTRL + Z abort line |\r\n" 107 | "\t+-------------------------------------+\r\n" 108 | */ 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /cherryrl/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "chry_readline.h" 12 | 13 | struct termios orig_termios; 14 | 15 | static void disableRawMode(int fd) 16 | { 17 | tcsetattr(fd, TCSAFLUSH, &orig_termios); 18 | } 19 | 20 | static void AtExit(void) 21 | { 22 | disableRawMode(STDIN_FILENO); 23 | } 24 | 25 | /* Raw mode: 1960 magic shit. */ 26 | static int enableRawMode(int fd) 27 | { 28 | struct termios raw; 29 | 30 | if (!isatty(STDIN_FILENO)) 31 | goto fatal; 32 | 33 | atexit(AtExit); 34 | 35 | if (tcgetattr(fd, &orig_termios) == -1) 36 | goto fatal; 37 | 38 | raw = orig_termios; /* modify the original mode */ 39 | /* input modes: no break, no CR to NL, no parity check, no strip char, 40 | * no start/stop output control. */ 41 | raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); 42 | /* output modes - disable post processing */ 43 | raw.c_oflag &= ~(OPOST); 44 | /* control modes - set 8 bit chars */ 45 | raw.c_cflag |= (CS8); 46 | /* local modes - choing off, canonical off, no extended functions, 47 | * no signal chars (^Z,^C) */ 48 | raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 49 | /* control chars - set return condition: min number of bytes and timer. 50 | * We want read to return every single byte, without timeout. */ 51 | raw.c_cc[VMIN] = 1; 52 | raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ 53 | 54 | /* put terminal in raw mode after flushing */ 55 | if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) 56 | goto fatal; 57 | 58 | return 0; 59 | 60 | fatal: 61 | errno = ENOTTY; 62 | return -1; 63 | } 64 | 65 | static uint16_t sput(chry_readline_t *rl, const void *data, uint16_t size) 66 | { 67 | uint16_t i; 68 | (void)rl; 69 | for (i = 0; i < size; i++) { 70 | if (1 != write(STDOUT_FILENO, (uint8_t *)data + i, 1)) { 71 | break; 72 | } 73 | } 74 | 75 | return i; 76 | } 77 | 78 | static uint16_t sget(chry_readline_t *rl, void *data, uint16_t size) 79 | { 80 | uint16_t i; 81 | (void)rl; 82 | for (i = 0; i < size; i++) { 83 | if (1 != read(STDIN_FILENO, (uint8_t *)data + i, 1)) { 84 | break; 85 | } 86 | } 87 | 88 | return i; 89 | } 90 | 91 | chry_readline_t rl; 92 | 93 | static int ucb(chry_readline_t *rl, uint8_t exec) 94 | { 95 | /*!< user event callback will not output newline automatically */ 96 | chry_readline_newline(rl); 97 | 98 | switch (exec) { 99 | case CHRY_READLINE_EXEC_EOF: 100 | fprintf(stderr, "EOF\r\n"); 101 | disableRawMode(STDIN_FILENO); 102 | exit(0); 103 | break; 104 | case CHRY_READLINE_EXEC_SIGINT: 105 | chry_readline_ignore(rl, false); 106 | fprintf(stderr, "SIGINT\r\n"); 107 | break; 108 | case CHRY_READLINE_EXEC_SIGQUIT: 109 | fprintf(stderr, "SIGQUIT\r\n"); 110 | break; 111 | case CHRY_READLINE_EXEC_SIGCONT: 112 | fprintf(stderr, "SIGCONT\r\n"); 113 | break; 114 | case CHRY_READLINE_EXEC_SIGSTOP: 115 | fprintf(stderr, "SIGSTOP\r\n"); 116 | break; 117 | case CHRY_READLINE_EXEC_SIGTSTP: 118 | fprintf(stderr, "SIGTSTP\r\n"); 119 | break; 120 | case CHRY_READLINE_EXEC_F1 ... CHRY_READLINE_EXEC_F12: 121 | fprintf(stderr, "F%d event\r\n", exec - CHRY_READLINE_EXEC_F1 + 1); 122 | break; 123 | case CHRY_READLINE_EXEC_USER ... CHRY_READLINE_EXEC_END: 124 | fprintf(stderr, "U%d event\r\n", exec - CHRY_READLINE_EXEC_USER + 1); 125 | break; 126 | default: 127 | fprintf(stderr, "ERROR EXEC %d\r\n", exec); 128 | return -1; 129 | } 130 | 131 | /*!< return 1 will not refresh */ 132 | /*!< return 0 to refresh whole line (include prompt) */ 133 | /*!< return -1 to end readline (error) */ 134 | return 0; 135 | } 136 | 137 | // clang-format off 138 | static const char *clist[] = { 139 | "hello", "world", "hell", "/exit", "/mask", "/unmask", "/prompt","/ignore", 140 | "hello0","hello1","hello2","hello3","hello4","hello5","hello6","hello7","hello8","hello9", 141 | "hello10","hello11","hello12","hello13","hello14","hello15","hello16","hello17","hello18","hello19", 142 | "hello20","hello21","hello22","hello23","hello24","hello25","hello26","hello27","hello28","hello29", 143 | "hello30","hello31","hello32","hello33","hello344444","hello35","hello36","hello37","hello38","hello39", 144 | "hello40","hello41","hello42","hello43","hello44","hello45","hello46","hello47","hello48","hello49", 145 | "hello50","hello51","hello52","hello53","hello54","hello55","hello56","hello57","hello58","hello59", 146 | "hello60","hello61","hello62","hello63","hello64","hello65","hello66","hello67","hello68","hello69", 147 | "hello70","hello71","hello72","hello73","hello74","hello75","hello76","hello77","hello78","hello79", 148 | "hello80","hello81","hello82","hello83","hello84","hello85","hello86","hello87","hello88","hello89", 149 | }; 150 | // clang-format on 151 | 152 | static uint8_t acb(chry_readline_t *rl, char *pre, uint16_t *size, const char **argv, uint8_t *argl, uint8_t argcmax) 153 | { 154 | (void)rl; 155 | uint8_t argc = 0; 156 | 157 | for (uint32_t i = 0; i < sizeof(clist) / sizeof(char *); i++) { 158 | if (strncmp(pre, clist[i], *size) == 0) { 159 | argv[argc] = clist[i]; 160 | argl[argc] = strlen(clist[i]); 161 | argc++; 162 | if (argc >= argcmax) { 163 | break; 164 | } 165 | } 166 | } 167 | 168 | return argc; 169 | } 170 | 171 | int main(int argc, char **argv) 172 | { 173 | char *prgname = argv[0]; 174 | uint8_t keycode = 0; 175 | uint8_t xterm = 0; 176 | uint8_t repl = 0; 177 | (void)keycode; 178 | 179 | while (argc > 1) { 180 | argc--; 181 | argv++; 182 | if (!strcmp(*argv, "--keycodes")) { 183 | keycode = 1; 184 | } else if (!strcmp(*argv, "--xterm")) { 185 | xterm = 1; 186 | } else if (!strcmp(*argv, "--autosize")) { 187 | xterm = 1; 188 | } else if (!strcmp(*argv, "--repl")) { 189 | repl = 1; 190 | } else { 191 | fprintf(stderr, "Usage: %s [--keycodes] [--xterm] [--autosize] [--repl]\n", prgname); 192 | exit(1); 193 | } 194 | } 195 | 196 | enableRawMode(STDIN_FILENO); 197 | 198 | int flags = fcntl(STDIN_FILENO, F_GETFL, 0); 199 | if (flags == -1) { 200 | perror("fcntl"); 201 | return 1; 202 | } 203 | 204 | if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) == -1) { 205 | perror("fcntl"); 206 | return 1; 207 | } 208 | 209 | char prompt[256]; 210 | char history[256]; 211 | 212 | char linebuf[128]; 213 | char *line; 214 | uint16_t linesize; 215 | 216 | memset(prompt, 0xff, 256); 217 | 218 | chry_readline_init_t rl_init = { 219 | .prompt = prompt, 220 | .pptsize = 34 + 11, 221 | .history = history, 222 | .histsize = sizeof(history), /*!< size must be power of 2 !!! */ 223 | .sget = sget, 224 | .sput = sput 225 | }; 226 | 227 | assert(0 == chry_readline_init(&rl, &rl_init)); 228 | 229 | /*!< the segidx must be incremented at first */ 230 | assert(0 == chry_readline_prompt_edit(&rl, 0, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_GREEN, .bold = 1 }.raw, "cherry")); 231 | assert(0 == chry_readline_prompt_edit(&rl, 1, 0, ":")); 232 | assert(0 == chry_readline_prompt_edit(&rl, 2, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_BLUE, .bold = 1 }.raw, "~")); 233 | assert(0 == chry_readline_prompt_edit(&rl, 3, 0, "$ ")); 234 | 235 | #if !CONFIG_READLINE_PROMPTEDIT 236 | memcpy(prompt, "nopptedit:~$ ", sizeof("nopptedit:~$ ")); 237 | #endif 238 | 239 | #if CONFIG_READLINE_DEBUG 240 | if (keycode) { 241 | chry_readline_debug(&rl); 242 | disableRawMode(STDIN_FILENO); 243 | return 0; 244 | } 245 | #endif 246 | 247 | (void)xterm; 248 | if (xterm) { 249 | chry_readline_detect(&rl); 250 | } 251 | 252 | chry_readline_set_completion_cb(&rl, acb); 253 | chry_readline_set_user_cb(&rl, ucb); 254 | 255 | /*!< mapping ctrl+q to exec user event 1 */ 256 | chry_readline_set_ctrlmap(&rl, CHRY_READLINE_CTRLMAP_X, CHRY_READLINE_EXEC_USER); 257 | /*!< mapping alt+q to exec user event 2 */ 258 | chry_readline_set_altmap(&rl, CHRY_READLINE_ALTMAP_X, CHRY_READLINE_EXEC_USER + 1); 259 | 260 | if (repl) { 261 | goto repl; 262 | } 263 | 264 | uint8_t i = 0; 265 | uint32_t taskcnt = 0; 266 | 267 | while (1) { 268 | line = chry_readline(&rl, linebuf, sizeof(linebuf), &linesize); 269 | if (line == NULL) { 270 | printf("chry_readline error\r\n"); 271 | break; 272 | } else if (line == (void *)-1) { 273 | if (taskcnt++ > 1000 * 10000) { 274 | chry_readline_erase_line(&rl); 275 | printf("other task\r\n"); 276 | chry_readline_edit_refresh(&rl); 277 | taskcnt = 0; 278 | } 279 | } else if (linesize) { 280 | printf("len = %2d <'%s'>\r\n", linesize, line); 281 | 282 | if (strncmp(line, "/mask", linesize) == 0 && linesize == strlen("/mask")) { 283 | chry_readline_mask(&rl, 1); 284 | 285 | } else if (strncmp(line, "/unmask", linesize) == 0 && linesize == strlen("/unmask")) { 286 | chry_readline_mask(&rl, 0); 287 | 288 | } else if (strncmp(line, "/prompt", linesize) == 0 && linesize == strlen("/prompt")) { 289 | int ret = chry_readline_prompt_edit(&rl, 2, (chry_readline_sgr_t){ .foreground = CHRY_READLINE_SGR_BLUE, .bold = 1 }.raw, "~/readline/%d", i++); 290 | 291 | if (ret == 1) { 292 | printf("prompt not enouth space\r\n"); 293 | } else if (ret == -1) { 294 | /*!< check if the segidx is legal */ 295 | printf("prompt edit error\r\n"); 296 | goto end; 297 | } 298 | 299 | } else if (strncmp(line, "/exit", linesize) == 0 && linesize == strlen("/exit")) { 300 | disableRawMode(STDIN_FILENO); 301 | return 0; 302 | 303 | } else if (strncmp(line, "/ignore", linesize) == 0 && linesize == strlen("/ignore")) { 304 | chry_readline_ignore(&rl, true); 305 | } 306 | } 307 | } 308 | 309 | goto end; 310 | 311 | repl: 312 | if (!CONFIG_READLINE_PROMPTEDIT) { 313 | printf("repl example, must enable CONFIG_READLINE_PROMPTEDIT\r\n"); 314 | return 0; 315 | } 316 | 317 | printf("enter repl test mode, end with ':' to enter multiline mode\r\n"); 318 | chry_readline_prompt_clear(&rl); 319 | assert(0 == chry_readline_prompt_edit(&rl, 0, 0, ">>> ")); 320 | 321 | /*!< map ctrl+i(tab) to auto completion or space */ 322 | chry_readline_set_ctrlmap(&rl, CHRY_READLINE_CTRLMAP_I, CHRY_READLINE_EXEC_ACPLT); 323 | 324 | bool multienable = false; 325 | int linecount = 0; 326 | char multibuff[32][128]; 327 | 328 | while ((line = chry_readline(&rl, multibuff[linecount], 128, &linesize)) != NULL) { 329 | if (linesize) { 330 | if (line[linesize - 1] == ':') { 331 | multienable = true; 332 | assert(0 == chry_readline_prompt_edit(&rl, 0, 0, "... ")); 333 | } 334 | 335 | if (++linecount > 32) { 336 | printf("too many line\r\n"); 337 | break; 338 | } 339 | 340 | if (!multienable) { 341 | printf("len = %2d <'%s'>\r\n", linesize, line); 342 | 343 | if (strncmp(line, "/exit", linesize) == 0) { 344 | if (linesize == strlen("/exit")) { 345 | disableRawMode(STDIN_FILENO); 346 | return 0; 347 | } 348 | } 349 | } 350 | } else { 351 | /** 352 | * The first two bytes of the buffer store the linesize of type uint16_t, 353 | * followed by the input content and ending \0. \0 is not included in the linesize 354 | */ 355 | if (multienable) { 356 | assert(0 == chry_readline_prompt_edit(&rl, 0, 0, ">>> ")); 357 | 358 | for (int i = 0; i < linecount; i++) { 359 | printf("%3d %s\r\n", *((uint16_t *)multibuff[i]), &multibuff[i][2]); 360 | } 361 | 362 | multienable = false; 363 | linecount = 0; 364 | } 365 | } 366 | } 367 | 368 | end: 369 | disableRawMode(STDIN_FILENO); 370 | return -1; 371 | } 372 | -------------------------------------------------------------------------------- /chry_shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CHRY_SHELL_H 8 | #define CHRY_SHELL_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include "cherryrl/chry_readline.h" 18 | 19 | /*!< check maxlen */ 20 | #if defined(CONFIG_CSH_MAXLEN_PATH) && CONFIG_CSH_MAXLEN_PATH 21 | #if CONFIG_CSH_MAXLEN_PATH > 255 22 | #error "CONFIG_CSH_MAXLEN_PATH cannot be greater than 255." 23 | #endif 24 | #endif 25 | 26 | /*!< check multi-thread and lnbuff static */ 27 | #if (defined(CONFIG_CSH_MULTI_THREAD) && CONFIG_CSH_MULTI_THREAD) 28 | #if !defined(CONFIG_CSH_LNBUFF_STATIC) || (CONFIG_CSH_LNBUFF_STATIC == 0) 29 | #error "CONFIG_CSH_LNBUFF_STATIC and CONFIG_CSH_MULTI_THREAD cannot be enabled at the same time." 30 | #endif 31 | #endif 32 | 33 | #if ((defined(CONFIG_CSH_NOBLOCK) && CONFIG_CSH_NOBLOCK) && \ 34 | (!defined(CONFIG_CSH_LNBUFF_STATIC) || (CONFIG_CSH_LNBUFF_STATIC == 0))) 35 | #error "CONFIG_CSH_LNBUFF_STATIC and CONFIG_CSH_NOBLOCK must be enabled at the same time." 36 | #endif 37 | 38 | /*!< signal count */ 39 | #define CSH_SIGNAL_COUNT 7 40 | 41 | /*!< signal */ 42 | #define CSH_SIGINT 1 43 | #define CSH_SIGQUIT 3 44 | #define CSH_SIGKILL 9 45 | #define CSH_SIGTERM 15 46 | #define CSH_SIGSTOP 17 47 | #define CSH_SIGTSTP 18 48 | #define CSH_SIGCONT 19 49 | 50 | #define CSH_VAR_READ 0x80000000 51 | #define CSH_VAR_WRITE 0x40000000 52 | #define CSH_VAR_SIZE 0x3fffffff 53 | 54 | #define CSH_SIG_DFL ((chry_sighandler_t)0) /* Default action */ 55 | #define CSH_SIG_IGN ((chry_sighandler_t)1) /* Ignore action */ 56 | #define CSH_SIG_ERR ((chry_sighandler_t)-1) /* Error return */ 57 | 58 | /*!< exec status */ 59 | #define CSH_STATUS_EXEC_IDLE 0 60 | #define CSH_STATUS_EXEC_FIND 1 61 | #define CSH_STATUS_EXEC_PREP 2 62 | #define CSH_STATUS_EXEC_DONE 3 63 | 64 | typedef int (*chry_syscall_func_t)(int argc, char **argv); 65 | 66 | typedef struct { 67 | const char *path; 68 | const char *name; 69 | chry_syscall_func_t func; 70 | } chry_syscall_t; 71 | 72 | typedef struct { 73 | const char *name; 74 | void *var; 75 | uint32_t attr; 76 | } chry_sysvar_t; 77 | 78 | typedef struct { 79 | uint32_t exec; 80 | 81 | /*!< readline section */ 82 | #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC 83 | chry_readline_t rl; /*!< readline instance */ 84 | char *linebuff; /*!< readline buffer */ 85 | uint16_t buffsize; /*!< readline buffer size */ 86 | uint16_t linesize; /*!< readline size */ 87 | #else 88 | chry_readline_t rl; /*!< readline instance */ 89 | /*!< (on stack) readline buffer */ 90 | /*!< (on stack) readline buffer size */ 91 | /*!< (on stack) readline size */ 92 | #endif 93 | 94 | /*!< commmand table section */ 95 | const chry_syscall_t *cmd_tbl_beg; /*!< command table begin */ 96 | const chry_syscall_t *cmd_tbl_end; /*!< command table end */ 97 | 98 | /*!< variable table section */ 99 | const chry_sysvar_t *var_tbl_beg; /*!< variable table begin */ 100 | const chry_sysvar_t *var_tbl_end; /*!< variable table end */ 101 | 102 | /*!< execute section */ 103 | #if defined(CONFIG_CSH_MULTI_THREAD) && CONFIG_CSH_MULTI_THREAD 104 | int exec_code; /*!< exec return code */ 105 | int exec_argc; /*!< exec argument count */ 106 | const char *exec_argv[CONFIG_CSH_MAX_ARG + 3]; /*!< exec argument value */ 107 | #else 108 | int exec_code; /*!< exec return code */ 109 | /*!< (on stack) exec argument count */ 110 | /*!< (on stack) exec argument value */ 111 | #endif 112 | 113 | /*!< user host and path section */ 114 | #if defined(CONFIG_CSH_MAXLEN_PATH) && CONFIG_CSH_MAXLEN_PATH 115 | int uid; /*!< now user id */ 116 | const char *host; /*!< host name */ 117 | const char *user[CONFIG_CSH_MAX_USER]; /*!< user name */ 118 | const char *hash[CONFIG_CSH_MAX_USER]; /*!< user password hash */ 119 | char path[CONFIG_CSH_MAXLEN_PATH]; /*!< path */ 120 | #else 121 | int uid; /*!< now user id */ 122 | const char *host; /*!< host name */ 123 | const char *user[CONFIG_CSH_MAX_USER]; /*!< user name */ 124 | const char *hash[CONFIG_CSH_MAX_USER]; /*!< user password hash */ 125 | const char *path; /*!< path */ 126 | #endif 127 | 128 | #if defined(CONFIG_CSH_SIGNAL_HANDLER) && CONFIG_CSH_SIGNAL_HANDLER 129 | void (*sighdl[CSH_SIGNAL_COUNT])(void *, int); 130 | #endif 131 | 132 | /*!< reserved section */ 133 | void *data; /*!< frame data */ 134 | void *user_data; /*!< user data */ 135 | } chry_shell_t; 136 | 137 | typedef void (*chry_sighandler_t)(chry_shell_t *csh, int signum); 138 | 139 | typedef struct { 140 | /*!< I/O section */ 141 | uint16_t (*sput)(chry_readline_t *rl, const void *, uint16_t); /*!< output callback */ 142 | uint16_t (*sget)(chry_readline_t *rl, void *, uint16_t); /*!< input callback */ 143 | 144 | /*!< command table section */ 145 | const void *command_table_beg; /*!< static command table begin */ 146 | const void *command_table_end; /*!< static command table end */ 147 | 148 | /*!< variable table section */ 149 | const void *variable_table_beg; /*!< static environment variable begin */ 150 | const void *variable_table_end; /*!< static environment variable end */ 151 | 152 | /*!< prompt buffer setcion */ 153 | char *prompt_buffer; /*!< prompt buffer */ 154 | uint16_t prompt_buffer_size; /*!< prompt buffer size */ 155 | 156 | /*!< history buffer setcion */ 157 | char *history_buffer; /*!< history buffer */ 158 | uint16_t history_buffer_size; /*!< history buffer size */ 159 | 160 | /*!< line buffer setcion */ 161 | char *line_buffer; /*!< line buffer */ 162 | uint32_t line_buffer_size; /*!< line buffer size */ 163 | 164 | /*!< user host section */ 165 | int uid; /*!< default user id */ 166 | const char *host; /*!< host name */ 167 | const char *user[CONFIG_CSH_MAX_USER]; /*!< user name */ 168 | const char *hash[CONFIG_CSH_MAX_USER]; /*!< user password hash */ 169 | 170 | /*!< reserved section */ 171 | void *user_data; 172 | } chry_shell_init_t; 173 | 174 | int chry_shell_init(chry_shell_t *csh, const chry_shell_init_t *init); 175 | int chry_shell_task_repl(chry_shell_t *csh); 176 | void chry_shell_task_exec(chry_shell_t *csh); 177 | 178 | int chry_shell_parse(char *line, uint32_t linesize, const char **argv, uint8_t argcmax); 179 | int chry_shell_path_resolve(const char *cur, const char *path, const char **argv, uint8_t *argl, uint8_t argcmax); 180 | 181 | int chry_shell_set_host(chry_shell_t *csh, const char *host); 182 | int chry_shell_set_user(chry_shell_t *csh, uint8_t uid, const char *user, const char *hash); 183 | int chry_shell_set_path(chry_shell_t *csh, uint8_t size, const char *path); 184 | void chry_shell_get_path(chry_shell_t *csh, uint8_t size, char *path); 185 | int chry_shell_substitute_user(chry_shell_t *csh, uint8_t uid, const char *password); 186 | 187 | char *chry_shell_getenv(chry_shell_t *csh, const char *name); 188 | int chry_shell_execl(chry_shell_t *csh, const char *__path, const char *, ...); 189 | int chry_shell_execle(chry_shell_t *csh, const char *__path, const char *, ...); 190 | int chry_shell_execlp(chry_shell_t *csh, const char *__file, const char *, ...); 191 | int chry_shell_execv(chry_shell_t *csh, const char *__path, char *const __argv[]); 192 | int chry_shell_execve(chry_shell_t *csh, const char *__path, char *const __argv[], char *const __envp[]); 193 | int chry_shell_execvp(chry_shell_t *csh, const char *__file, char *const __argv[]); 194 | 195 | int csh_printf(chry_shell_t *csh, const char *fmt, ...); 196 | 197 | int csh_login(chry_shell_t *csh); 198 | 199 | #ifdef __cplusplus 200 | } 201 | #endif 202 | 203 | #endif 204 | -------------------------------------------------------------------------------- /csh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CSH_H 8 | #define CSH_H 9 | 10 | #include 11 | #include "csh_config.h" 12 | 13 | /*!< argument check */ 14 | #ifndef CONFIG_CSH_DEBUG 15 | #define CONFIG_CSH_DEBUG 0 16 | #endif 17 | 18 | /*!< default row */ 19 | #ifndef CONFIG_CSH_DFTROW 20 | #define CONFIG_CSH_DFTROW 25 21 | #endif 22 | 23 | /*!< default column */ 24 | #ifndef CONFIG_CSH_DFTCOL 25 | #define CONFIG_CSH_DFTCOL 80 26 | #endif 27 | 28 | /*!< history support <+550byte> */ 29 | #ifndef CONFIG_CSH_HISTORY 30 | #define CONFIG_CSH_HISTORY 1 31 | #endif 32 | 33 | /*!< completion support <+1100byte> */ 34 | #ifndef CONFIG_CSH_COMPLETION 35 | #define CONFIG_CSH_COMPLETION 1 36 | #endif 37 | 38 | /*!< max completion item list count (use stack 4 x count byte) */ 39 | #ifndef CONFIG_CSH_MAX_COMPLETION 40 | #define CONFIG_CSH_MAX_COMPLETION 48 41 | #endif 42 | 43 | /*!< prompt edit support <+1000byte> */ 44 | #ifndef CONFIG_CSH_PROMPTEDIT 45 | #define CONFIG_CSH_PROMPTEDIT 1 46 | #endif 47 | 48 | /*!< prompt segment count */ 49 | #ifndef CONFIG_CSH_PROMPTSEG 50 | #define CONFIG_CSH_PROMPTSEG 7 51 | #endif 52 | 53 | /*!< xterm support */ 54 | #ifndef CONFIG_CSH_XTERM 55 | #define CONFIG_CSH_XTERM 0 56 | #endif 57 | 58 | /*!< newline */ 59 | #ifndef CONFIG_CSH_NEWLINE 60 | #define CONFIG_CSH_NEWLINE "\r\n" 61 | #endif 62 | 63 | /*!< tab space count */ 64 | #ifndef CONFIG_CSH_SPACE 65 | #define CONFIG_CSH_SPACE 4 66 | #endif 67 | 68 | /*!< independent ctrl map */ 69 | #ifndef CONFIG_CSH_CTRLMAP 70 | #define CONFIG_CSH_CTRLMAP 0 71 | #endif 72 | 73 | /*!< independent alt map */ 74 | #ifndef CONFIG_CSH_ALTMAP 75 | #define CONFIG_CSH_ALTMAP 0 76 | #endif 77 | 78 | /*!< refresh prompt */ 79 | #ifndef CONFIG_CSH_REFRESH_PROMPT 80 | #define CONFIG_CSH_REFRESH_PROMPT 1 81 | #endif 82 | 83 | /*!< no waiting for sget */ 84 | #ifndef CONFIG_CSH_NOBLOCK 85 | #define CONFIG_CSH_NOBLOCK 0 86 | #endif 87 | 88 | /*!< help information */ 89 | #ifndef CONFIG_CSH_HELP 90 | #define CONFIG_CSH_HELP "" 91 | #endif 92 | 93 | /*!< path length 0:const path, <=255:variable path */ 94 | #ifndef CONFIG_CSH_MAXLEN_PATH 95 | #define CONFIG_CSH_MAXLEN_PATH 128 96 | #endif 97 | 98 | /*!< path segment count */ 99 | #ifndef CONFIG_CSH_MAXSEG_PATH 100 | #define CONFIG_CSH_MAXSEG_PATH 16 101 | #endif 102 | 103 | /*!< user count */ 104 | #ifndef CONFIG_CSH_MAX_USER 105 | #define CONFIG_CSH_MAX_USER 1 106 | #endif 107 | 108 | /*!< max argument count */ 109 | #ifndef CONFIG_CSH_MAX_ARG 110 | #define CONFIG_CSH_MAX_ARG 8 111 | #endif 112 | 113 | /*!< linebuffer static or on stack */ 114 | #ifndef CONFIG_CSH_LNBUFF_STATIC 115 | #define CONFIG_CSH_LNBUFF_STATIC 1 116 | #endif 117 | 118 | /*!< linebuffer size (valid only if lnbuff on stack) */ 119 | #ifndef CONFIG_CSH_LNBUFF_SIZE 120 | #define CONFIG_CSH_LNBUFF_SIZE 256 121 | #endif 122 | 123 | /*!< multi-thread mode */ 124 | #ifndef CONFIG_CSH_MULTI_THREAD 125 | #define CONFIG_CSH_MULTI_THREAD 0 126 | #endif 127 | 128 | /*!< independent signal handler (for multi instances) */ 129 | #ifndef CONFIG_CSH_SIGNAL_HANDLER 130 | #define CONFIG_CSH_SIGNAL_HANDLER 0 131 | #endif 132 | 133 | /*!< Ctrl+c/d/q/s/z/\ F1-F12 UE <+120byte> */ 134 | #ifndef CONFIG_CSH_USER_CALLBACK 135 | #define CONFIG_CSH_USER_CALLBACK 1 136 | #endif 137 | 138 | /*!< enable macro export symbol table */ 139 | #ifndef CONFIG_CSH_SYMTAB 140 | #define CONFIG_CSH_SYMTAB 1 141 | #endif 142 | 143 | /*!< print buffer size */ 144 | #ifndef CONFIG_CSH_PRINT_BUFFER_SIZE 145 | #define CONFIG_CSH_PRINT_BUFFER_SIZE 512 146 | #endif 147 | 148 | #define CONFIG_READLINE_DEBUG CONFIG_CSH_DEBUG 149 | #define CONFIG_READLINE_DFTROW CONFIG_CSH_DFTROW 150 | #define CONFIG_READLINE_DFTCOL CONFIG_CSH_DFTCOL 151 | #define CONFIG_READLINE_HISTORY CONFIG_CSH_HISTORY 152 | #define CONFIG_READLINE_COMPLETION CONFIG_CSH_COMPLETION 153 | #define CONFIG_READLINE_MAX_COMPLETION CONFIG_CSH_MAX_COMPLETION 154 | #define CONFIG_READLINE_PROMPTEDIT CONFIG_CSH_PROMPTEDIT 155 | #define CONFIG_READLINE_PROMPTSEG CONFIG_CSH_PROMPTSEG 156 | #define CONFIG_READLINE_XTERM CONFIG_CSH_XTERM 157 | #define CONFIG_READLINE_NEWLINE CONFIG_CSH_NEWLINE 158 | #define CONFIG_READLINE_SPACE CONFIG_CSH_SPACE 159 | #define CONFIG_READLINE_CTRLMAP CONFIG_CSH_CTRLMAP 160 | #define CONFIG_READLINE_ALTMAP CONFIG_CSH_ALTMAP 161 | #define CONFIG_READLINE_REFRESH_PROMPT CONFIG_CSH_REFRESH_PROMPT 162 | #define CONFIG_READLINE_NOBLOCK CONFIG_CSH_NOBLOCK 163 | #define CONFIG_READLINE_HELP CONFIG_CSH_HELP 164 | 165 | #include "cherryrl/chry_readline.h" 166 | #include "chry_shell.h" 167 | 168 | #if defined(__CC_ARM) || defined(__CLANG_ARM) || defined(__GNUC__) || defined(__ADSPBLACKFIN__) 169 | #define __CSH_SECTION(x) __attribute__((section(x))) 170 | #define __CSH_USED __attribute__((used)) 171 | #elif defined(__IAR_SYSTEMS_ICC__) 172 | #define __CSH_SECTION(x) @x 173 | #define __CSH_USED __root 174 | #else 175 | #define __CSH_SECTION(x) 176 | #define __CSH_USED 177 | #endif 178 | 179 | #if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB 180 | 181 | #if defined(_MSC_VER) 182 | #pragma section("FSymTab$f", read) 183 | #pragma section("VSymTab", read) 184 | #endif 185 | 186 | #if defined(__TI_COMPILER_VERSION__) 187 | #defien __TI_CSH_PRAGMA(x) _Pragma(#x) 188 | #endif 189 | 190 | #endif 191 | 192 | #if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB 193 | #if defined(_MSC_VER) 194 | 195 | #define CSH_EXPORT_CALL(name, func, path) \ 196 | __declspec(allocate("FSymTab$f")) \ 197 | const chry_syscall_t __fsym_##name##func = { \ 198 | path, \ 199 | #name, \ 200 | (chry_syscall_func_t)func, \ 201 | }; 202 | 203 | #pragma comment(linker, "/merge:FSymTab=mytext") 204 | 205 | #define CSH_EXPORT_VAR(name, var, attr) \ 206 | __declspec(allocate("VSymTab")) const chry_sysvar_t __vsym_##name##var = { \ 207 | #name, \ 208 | (void *)&var, \ 209 | attr, \ 210 | }; 211 | 212 | #elif defined(__TI_COMPILER_VERSION__) 213 | 214 | #define CSH_EXPORT_CALL(name, func, path) \ 215 | __TI_CSH_PRAGMA(DATA_SECTION(__fsym_##name##func, "FSymTab")); \ 216 | __attribute__((used)) const chry_syscall_t __fsym_##name##func = { \ 217 | path, \ 218 | #name, \ 219 | (chry_syscall_func_t)func, \ 220 | }; 221 | 222 | #define CSH_EXPORT_VAR(name, var, attr) \ 223 | __TI_CSH_PRAGMA(DATA_SECTION(__vsym_##name##var, "VSymTab")); \ 224 | __attribute__((used)) const chry_sysvar_t __vsym_##name##var = { \ 225 | #name, \ 226 | (void *)&var, \ 227 | attr, \ 228 | }; 229 | 230 | #else 231 | 232 | #define CSH_EXPORT_CALL(name, func, path) \ 233 | __CSH_USED const chry_syscall_t __fsym_##name##func __CSH_SECTION("FSymTab") = { \ 234 | path, \ 235 | #name, \ 236 | (chry_syscall_func_t)func, \ 237 | }; 238 | 239 | #define CSH_EXPORT_VAR(name, var, attr) \ 240 | __CSH_USED const chry_sysvar_t __vsym_##name##var __CSH_SECTION("VSymTab") = { \ 241 | #name, \ 242 | (void *)var, \ 243 | attr, \ 244 | }; 245 | 246 | #endif 247 | #else 248 | #define CSH_EXPORT_CALL(name, func, path) 249 | #define CSH_EXPORT_VAR(name, var, attr) 250 | #endif 251 | 252 | /***************************************************************************** 253 | * @brief export csh command (default path "/bin") 254 | * 255 | * @param[in] func function pointer 256 | * @param[in] _dummy (compatible descriptions) 257 | * 258 | *****************************************************************************/ 259 | #define CSH_CMD_EXPORT(func, _dummy) \ 260 | CSH_EXPORT_CALL(func, func, "/bin") 261 | 262 | /***************************************************************************** 263 | * @brief export csh command with alias (default path "/bin" ) 264 | * 265 | * @param[in] func function pointer 266 | * @param[in] name command name 267 | * @param[in] _dummy (compatible descriptions) 268 | * 269 | *****************************************************************************/ 270 | #define CSH_CMD_EXPORT_ALIAS(func, name, _dummy) \ 271 | CSH_EXPORT_CALL(name, func, "/bin") 272 | 273 | /***************************************************************************** 274 | * @brief export csh command (default path "/sbin") 275 | * 276 | * @param[in] func function pointer 277 | * @param[in] _dummy (compatible descriptions) 278 | * 279 | *****************************************************************************/ 280 | #define CSH_SCMD_EXPORT(func, _dummy) \ 281 | CSH_EXPORT_CALL(func, func, "/sbin") 282 | 283 | /***************************************************************************** 284 | * @brief export csh command with alias (default path "/sbin" ) 285 | * 286 | * @param[in] func function pointer 287 | * @param[in] name command name 288 | * @param[in] _dummy (compatible descriptions) 289 | * 290 | *****************************************************************************/ 291 | #define CSH_SCMD_EXPORT_ALIAS(func, name, _dummy) \ 292 | CSH_EXPORT_CALL(name, func, "/sbin") 293 | 294 | /***************************************************************************** 295 | * @brief export csh command with path 296 | * 297 | * @param[in] func function pointer 298 | * @param[in] name command name 299 | * @param[in] path command path 300 | * 301 | * @example CSH_CMD_EXPORT_PATH(test_func1, test1, "/bin"); // ok 302 | * CSH_CMD_EXPORT_PATH(test_func2, test2, "/sbin/test"); // ok 303 | * CSH_CMD_EXPORT_PATH(test_func2, test2, "/sbin/test/");// error, cannot end with '/' 304 | * CSH_CMD_EXPORT_PATH(test_func2, test2, "/"); // error, cannot be the root path "/" 305 | * 306 | *****************************************************************************/ 307 | #define CSH_CMD_EXPORT_PATH(func, name, path) \ 308 | CSH_EXPORT_CALL(name, func, path) 309 | 310 | /***************************************************************************** 311 | * @brief export csh read-only variable 312 | * 313 | * @param[in] var variable 314 | * @param[in] name variable name 315 | * @param[in] size variable size 316 | * 317 | *****************************************************************************/ 318 | #define CSH_RVAR_EXPORT(var, name, size) \ 319 | CSH_EXPORT_VAR(name, var, 0x80000000 | (size)) 320 | 321 | /***************************************************************************** 322 | * @brief export csh write-only variable 323 | * 324 | * @param[in] var variable 325 | * @param[in] name variable name 326 | * @param[in] size variable size 327 | * 328 | *****************************************************************************/ 329 | #define CSH_WVAR_EXPORT(var, name, size) \ 330 | CSH_EXPORT_VAR(name, var, 0x40000000 | (size)) 331 | 332 | /***************************************************************************** 333 | * @brief export csh read-write variable 334 | * 335 | * @param[in] var variable 336 | * @param[in] name variable name 337 | * @param[in] size variable size 338 | * 339 | *****************************************************************************/ 340 | #define CSH_RWVAR_EXPORT(var, name, size) \ 341 | CSH_EXPORT_VAR(name, var, 0xc0000000 | (size)) 342 | 343 | #endif 344 | -------------------------------------------------------------------------------- /csh_config_template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CSH_CONFIG_H 8 | #define CSH_CONFIG_H 9 | 10 | /*!< argument check */ 11 | #define CONFIG_CSH_DEBUG 0 12 | 13 | /*!< default row */ 14 | #define CONFIG_CSH_DFTROW 25 15 | 16 | /*!< default column */ 17 | #define CONFIG_CSH_DFTCOL 80 18 | 19 | /*!< history support <+550byte> */ 20 | #define CONFIG_CSH_HISTORY 1 21 | 22 | /*!< completion support <+1100byte> */ 23 | #define CONFIG_CSH_COMPLETION 1 24 | 25 | /*!< max completion item list count (use stack 4 x count byte) */ 26 | #define CONFIG_CSH_MAX_COMPLETION 40 27 | 28 | /*!< prompt edit support <+1000byte> */ 29 | #define CONFIG_CSH_PROMPTEDIT 1 30 | 31 | /*!< prompt segment count */ 32 | #define CONFIG_CSH_PROMPTSEG 7 33 | 34 | /*!< xterm support */ 35 | #define CONFIG_CSH_XTERM 0 36 | 37 | /*!< newline */ 38 | #define CONFIG_CSH_NEWLINE "\r\n" 39 | 40 | /*!< tab space count */ 41 | #define CONFIG_CSH_SPACE 4 42 | 43 | /*!< independent ctrl map */ 44 | #define CONFIG_CSH_CTRLMAP 0 45 | 46 | /*!< independent alt map */ 47 | #define CONFIG_CSH_ALTMAP 0 48 | 49 | /*!< refresh prompt */ 50 | #define CONFIG_CSH_REFRESH_PROMPT 1 51 | 52 | /*!< no waiting for sget */ 53 | #define CONFIG_CSH_NOBLOCK 1 54 | 55 | /*!< help information */ 56 | #define CONFIG_CSH_HELP "" 57 | 58 | /*!< path length 0:const path, <=255:variable path */ 59 | #define CONFIG_CSH_MAXLEN_PATH 128 60 | 61 | /*!< path segment count */ 62 | #define CONFIG_CSH_MAXSEG_PATH 16 63 | 64 | /*!< user count */ 65 | #define CONFIG_CSH_MAX_USER 1 66 | 67 | /*!< max argument count */ 68 | #define CONFIG_CSH_MAX_ARG 8 69 | 70 | /*!< linebuffer static or on stack */ 71 | #define CONFIG_CSH_LNBUFF_STATIC 1 72 | 73 | /*!< linebuffer size (valid only if lnbuff on stack) */ 74 | #define CONFIG_CSH_LNBUFF_SIZE 256 75 | 76 | /*!< multi-thread mode */ 77 | #define CONFIG_CSH_MULTI_THREAD 0 78 | 79 | /*!< independent signal handler (for multi instances) */ 80 | #define CONFIG_CSH_SIGNAL_HANDLER 0 81 | 82 | /*!< Ctrl+c/d/q/s/z/\ F1-F12 UE <+120byte> */ 83 | #define CONFIG_CSH_USER_CALLBACK 1 84 | 85 | /*!< enable macro export symbol table */ 86 | #define CONFIG_CSH_SYMTAB 1 87 | 88 | /*!< print buffer size */ 89 | #define CONFIG_CSH_PRINT_BUFFER_SIZE 512 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /doc/test1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cherry-embedded/CherrySH/cda6369d7bf938144d1aa49d17bb2ffdc7192145/doc/test1.png -------------------------------------------------------------------------------- /doc/test2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cherry-embedded/CherrySH/cda6369d7bf938144d1aa49d17bb2ffdc7192145/doc/test2.png -------------------------------------------------------------------------------- /samples/hpm/barebone_uart/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 HPMicro 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.13) 5 | 6 | set(CONFIG_CHERRYRB 1) 7 | 8 | find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) 9 | project(cherryshell) 10 | 11 | sdk_compile_options("-O2") 12 | 13 | sdk_inc(inc) 14 | sdk_inc(../../../) 15 | 16 | sdk_app_src( 17 | src/main.c 18 | src/shell.c 19 | ../../../cherryrl/chry_readline.c 20 | ../../../chry_shell.c 21 | ../../../builtin/help.c 22 | ../../../builtin/shsize.c 23 | ../../../builtin/login.c 24 | ) 25 | 26 | generate_ses_project() 27 | -------------------------------------------------------------------------------- /samples/hpm/barebone_uart/README_en.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell Barebone UART 2 | 3 | ## Overview 4 | 5 | The Cherry Shell Barebone example project demonstrates the basic usage of shell in bare-metal mode. In this project, you need to connect via serial port, and the shell requires a login. The default password is 12345678. After entering the password and pressing Enter, you will enter the shell. You can use the "help" command to view the available commands and variables. 6 | 7 | Please refrain from using serial port assistants and consider downloading and using [MobaXterm](https://mobaxterm.mobatek.net/download.html) 8 | 9 | ## Board Setting 10 | 11 | No special settings 12 | 13 | ## Running the example 14 | 15 | - After the project runs successfully, the serial terminal will output the following information: 16 | 17 | ```console 18 | login as: cherry 19 | cherry@hpm5301evklite's password: 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | other task interval 5S 25 | 26 | ``` 27 | 28 | - If you manually enter the correct password "12345678" and press Enter, the terminal will output the following information: 29 | 30 | ```console 31 | login as: cherry 32 | cherry@hpm5301evklite's password: 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | other task interval 5S 38 | 39 | welcome to cherry shell 40 | cherry@hpm5301evklite:/$ 41 | ``` 42 | 43 | - If you manually enter the command "help" and press Enter, the terminal will output the following information: 44 | 45 | ```console 46 | cherry@hpm5301evklite:/$ help 47 | total function 6 48 | test -> /bin 49 | toggle_led -> /bin 50 | write_led -> /bin 51 | exit -> /sbin 52 | help -> /sbin 53 | shsize -> /sbin 54 | 55 | total variable 2 56 | $PATH r- 11 57 | $ZERO r- 1 58 | cherry@hpm5301evklite:/$ 59 | ``` 60 | 61 | - If you manually enter the command "toggle_led" and press Enter, the LED will toggle. 62 | - If you manually enter the command "write_led 1" and press Enter, the LED will turn on. 63 | - If you manually enter the command "write_led 0" and press Enter, the LED will turn off. 64 | -------------------------------------------------------------------------------- /samples/hpm/barebone_uart/README_zh.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell Barebone UART 2 | 3 | ## 概述 4 | 5 | Cherry Shell Barebone示例工程展示了shell的裸机模式基本使用。在这个工程中,需要连接串口,shell默认需要登陆,密码为12345678。输入密码后回车,进入shell,输入help可以查看命令和变量。 6 | 请勿使用串口助手,推荐下载使用 [MobaXterm](https://mobaxterm.mobatek.net/download.html) 7 | 8 | ## 硬件设置 9 | 10 | 无特殊设置 11 | 12 | ## 运行现象 13 | 14 | - 当工程正确运行后,串口终端会输出如下信息: 15 | 16 | ```console 17 | login as: cherry 18 | cherry@hpm5301evklite's password: 19 | other task interval 5S 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | 25 | ``` 26 | 27 | - 如果此时通过键盘手动输入正确密码"12345678"并回车,终端会输出如下信息: 28 | 29 | ```console 30 | login as: cherry 31 | cherry@hpm5301evklite's password: 32 | other task interval 5S 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | 38 | welcome to cherry shell 39 | cherry@hpm5301evklite:/$ 40 | ``` 41 | 42 | - 如果此时通过键盘手动输入命令"help"并回车,终端会输出如下信息: 43 | 44 | ```console 45 | cherry@hpm5301evklite:/$ help 46 | total function 6 47 | test -> /bin 48 | toggle_led -> /bin 49 | write_led -> /bin 50 | exit -> /sbin 51 | help -> /sbin 52 | shsize -> /sbin 53 | 54 | total variable 2 55 | $PATH r- 11 56 | $ZERO r- 1 57 | cherry@hpm5301evklite:/$ 58 | ``` 59 | 60 | - 如果此时通过键盘手动输入命令"toggle_led"并回车,LED将会翻转 61 | - 如果此时通过键盘手动输入命令"write_led 1"并回车,LED将会点亮 62 | - 如果此时通过键盘手动输入命令"write_led 0"并回车,LED将会熄灭 63 | -------------------------------------------------------------------------------- /samples/hpm/barebone_uart/inc/csh_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CSH_CONFIG_H 8 | #define CSH_CONFIG_H 9 | 10 | /*!< argument check */ 11 | #define CONFIG_CSH_DEBUG 0 12 | 13 | /*!< default row */ 14 | #define CONFIG_CSH_DFTROW 25 15 | 16 | /*!< default column */ 17 | #define CONFIG_CSH_DFTCOL 80 18 | 19 | /*!< history support <+550byte> */ 20 | #define CONFIG_CSH_HISTORY 1 21 | 22 | /*!< completion support <+1100byte> */ 23 | #define CONFIG_CSH_COMPLETION 1 24 | 25 | /*!< max completion item list count (use stack 4 x count byte) */ 26 | #define CONFIG_CSH_MAX_COMPLETION 40 27 | 28 | /*!< prompt edit support <+1000byte> */ 29 | #define CONFIG_CSH_PROMPTEDIT 1 30 | 31 | /*!< prompt segment count */ 32 | #define CONFIG_CSH_PROMPTSEG 7 33 | 34 | /*!< xterm support */ 35 | #define CONFIG_CSH_XTERM 0 36 | 37 | /*!< newline */ 38 | #define CONFIG_CSH_NEWLINE "\r\n" 39 | 40 | /*!< tab space count */ 41 | #define CONFIG_CSH_SPACE 4 42 | 43 | /*!< independent ctrl map */ 44 | #define CONFIG_CSH_CTRLMAP 0 45 | 46 | /*!< independent alt map */ 47 | #define CONFIG_CSH_ALTMAP 0 48 | 49 | /*!< refresh prompt */ 50 | #define CONFIG_CSH_REFRESH_PROMPT 1 51 | 52 | /*!< no waiting for sget */ 53 | #define CONFIG_CSH_NOBLOCK 1 54 | 55 | /*!< help information */ 56 | #define CONFIG_CSH_HELP "" 57 | 58 | /*!< path length 0:const path, <=255:variable path */ 59 | #define CONFIG_CSH_MAXLEN_PATH 128 60 | 61 | /*!< path segment count */ 62 | #define CONFIG_CSH_MAXSEG_PATH 16 63 | 64 | /*!< user count */ 65 | #define CONFIG_CSH_MAX_USER 1 66 | 67 | /*!< max argument count */ 68 | #define CONFIG_CSH_MAX_ARG 8 69 | 70 | /*!< linebuffer static or on stack */ 71 | #define CONFIG_CSH_LNBUFF_STATIC 1 72 | 73 | /*!< linebuffer size (valid only if lnbuff on stack) */ 74 | #define CONFIG_CSH_LNBUFF_SIZE 256 75 | 76 | /*!< multi-thread mode */ 77 | #define CONFIG_CSH_MULTI_THREAD 0 78 | 79 | /*!< independent signal handler (for multi instances) */ 80 | #define CONFIG_CSH_SIGNAL_HANDLER 0 81 | 82 | /*!< Ctrl+c/d/q/s/z/\ F1-F12 UE <+120byte> */ 83 | #define CONFIG_CSH_USER_CALLBACK 1 84 | 85 | /*!< enable macro export symbol table */ 86 | #define CONFIG_CSH_SYMTAB 1 87 | 88 | /*!< print buffer size */ 89 | #define CONFIG_CSH_PRINT_BUFFER_SIZE 512 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /samples/hpm/barebone_uart/inc/shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef SHELL_H 8 | #define SHELL_H 9 | 10 | #include "hpm_uart_drv.h" 11 | #include "csh.h" 12 | 13 | extern int shell_init(UART_Type *uart, bool need_login); 14 | extern int shell_main(void); 15 | extern void shell_uart_isr(void); 16 | extern void shell_lock(void); 17 | extern void shell_unlock(void); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /samples/hpm/barebone_uart/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 HPMicro 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include 9 | #include "board.h" 10 | #include "hpm_clock_drv.h" 11 | #include "hpm_mchtmr_drv.h" 12 | #include "shell.h" 13 | 14 | SDK_DECLARE_EXT_ISR_M(BOARD_CONSOLE_UART_IRQ, shell_uart_isr) 15 | 16 | int main(void) 17 | { 18 | board_init(); 19 | board_init_led_pins(); 20 | 21 | printf("Try to initialize the uart\r\n" 22 | " if you are using the console uart as the shell uart\r\n" 23 | " failure to initialize may result in no log\r\n"); 24 | 25 | uart_config_t shell_uart_config = { 0 }; 26 | uart_default_config(BOARD_CONSOLE_UART_BASE, &shell_uart_config); 27 | shell_uart_config.src_freq_in_hz = clock_get_frequency(BOARD_CONSOLE_UART_CLK_NAME); 28 | shell_uart_config.baudrate = 115200; 29 | 30 | if (status_success != uart_init(BOARD_CONSOLE_UART_BASE, &shell_uart_config)) { 31 | /* uart failed to be initialized */ 32 | printf("Failed to initialize uart\r\n"); 33 | for (;;) { 34 | ; 35 | } 36 | } 37 | 38 | /* default password is : 12345678 */ 39 | shell_init(BOARD_CONSOLE_UART_BASE, true); 40 | 41 | /* irq must be enabled after shell_init() */ 42 | uart_enable_irq(BOARD_CONSOLE_UART_BASE, uart_intr_rx_data_avail_or_timeout); 43 | intc_m_enable_irq_with_priority(BOARD_CONSOLE_UART_IRQ, 1); 44 | 45 | uint32_t freq = clock_get_frequency(clock_mchtmr0); 46 | uint64_t time = mchtmr_get_count(HPM_MCHTMR) / (freq / 1000); 47 | 48 | while (1) { 49 | shell_main(); 50 | 51 | uint64_t now = mchtmr_get_count(HPM_MCHTMR) / (freq / 1000); 52 | if (now > time + 5000) { 53 | time = now; 54 | shell_lock(); 55 | printf("other task interval 5S\r\n"); 56 | shell_unlock(); 57 | } 58 | } 59 | 60 | return 0; 61 | } 62 | 63 | static int test(int argc, char **argv) 64 | { 65 | chry_shell_t *csh = (void *)argv[argc + 1]; 66 | csh_printf(csh, "test: \r\n"); 67 | csh_printf(csh, "argc=<%d>\r\n", argc); 68 | for (uint8_t i = 0; i < argc; i++) { 69 | csh_printf(csh, "argv[%d]:0x%08x=<%s>\r\n", i, (uintptr_t)argv[i], argv[i]); 70 | } 71 | 72 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n", argc, argv[argc]); 73 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n\r\n", argc + 1, argv[argc + 1]); 74 | 75 | return 0; 76 | } 77 | CSH_CMD_EXPORT(test, ); 78 | 79 | static int toggle_led(int argc, char **argv) 80 | { 81 | (void)argc; 82 | (void)argv; 83 | board_led_toggle(); 84 | return 0; 85 | } 86 | CSH_CMD_EXPORT(toggle_led, ); 87 | 88 | static int write_led(int argc, char **argv) 89 | { 90 | chry_shell_t *csh = (void *)argv[argc + 1]; 91 | if (argc < 2) { 92 | csh_printf(csh, "usage: write_led \r\n\r\n"); 93 | csh_printf(csh, " status 0 or 1\r\n\r\n"); 94 | return -1; 95 | } 96 | 97 | board_led_write(!board_get_led_gpio_off_level() ^ (atoi(argv[1]) == 0)); 98 | return 0; 99 | } 100 | CSH_CMD_EXPORT(write_led, ); 101 | -------------------------------------------------------------------------------- /samples/hpm/barebone_uart/src/shell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "board.h" 4 | #include "hpm_uart_drv.h" 5 | #include "chry_ringbuffer.h" 6 | #include "csh.h" 7 | 8 | static chry_shell_t csh; 9 | static UART_Type *shell_uart = NULL; 10 | static bool login = false; 11 | static chry_ringbuffer_t shell_rb; 12 | static uint8_t mempool[1024]; 13 | 14 | void shell_uart_isr(void) 15 | { 16 | uint8_t irq_id = uart_get_irq_id(shell_uart); 17 | if (irq_id == uart_intr_id_rx_data_avail) { 18 | while (uart_check_status(shell_uart, uart_stat_data_ready)) { 19 | uint8_t byte = uart_read_byte(shell_uart); 20 | chry_ringbuffer_write_byte(&shell_rb, byte); 21 | } 22 | } 23 | } 24 | 25 | static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size) 26 | { 27 | uint16_t i; 28 | (void)rl; 29 | for (i = 0; i < size; i++) { 30 | if (status_success != uart_send_byte(shell_uart, ((uint8_t *)data)[i])) { 31 | break; 32 | } 33 | } 34 | 35 | return i; 36 | } 37 | 38 | static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size) 39 | { 40 | (void)rl; 41 | return chry_ringbuffer_read(&shell_rb, data, size); 42 | } 43 | 44 | int shell_init(UART_Type *uart, bool need_login) 45 | { 46 | chry_shell_init_t csh_init; 47 | 48 | if (uart == NULL) { 49 | return -1; 50 | } 51 | 52 | if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) { 53 | return -1; 54 | } 55 | 56 | if (need_login) { 57 | login = false; 58 | } else { 59 | login = true; 60 | } 61 | 62 | shell_uart = uart; 63 | 64 | /*!< I/O callback */ 65 | csh_init.sput = csh_sput_cb; 66 | csh_init.sget = csh_sget_cb; 67 | 68 | #if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB 69 | extern const int __fsymtab_start; 70 | extern const int __fsymtab_end; 71 | extern const int __vsymtab_start; 72 | extern const int __vsymtab_end; 73 | 74 | /*!< get table from ld symbol */ 75 | csh_init.command_table_beg = &__fsymtab_start; 76 | csh_init.command_table_end = &__fsymtab_end; 77 | csh_init.variable_table_beg = &__vsymtab_start; 78 | csh_init.variable_table_end = &__vsymtab_end; 79 | #endif 80 | 81 | #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT 82 | static char csh_prompt_buffer[128]; 83 | 84 | /*!< set prompt buffer */ 85 | csh_init.prompt_buffer = csh_prompt_buffer; 86 | csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer); 87 | #endif 88 | 89 | #if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY 90 | static char csh_history_buffer[128]; 91 | 92 | /*!< set history buffer */ 93 | csh_init.history_buffer = csh_history_buffer; 94 | csh_init.history_buffer_size = sizeof(csh_history_buffer); 95 | #endif 96 | 97 | #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC 98 | static char csh_line_buffer[128]; 99 | 100 | /*!< set linebuffer */ 101 | csh_init.line_buffer = csh_line_buffer; 102 | csh_init.line_buffer_size = sizeof(csh_line_buffer); 103 | #endif 104 | 105 | csh_init.uid = 0; 106 | csh_init.user[0] = "cherry"; 107 | 108 | /*!< The port hash function is required, 109 | and the strcmp attribute is used weakly by default, 110 | int chry_shell_port_hash_strcmp(const char *hash, const char *str); */ 111 | csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */ 112 | csh_init.host = BOARD_NAME; 113 | csh_init.user_data = NULL; 114 | 115 | int ret = chry_shell_init(&csh, &csh_init); 116 | if (ret) { 117 | return -1; 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | int shell_main(void) 124 | { 125 | int ret; 126 | 127 | restart: 128 | 129 | if (login) { 130 | goto restart2; 131 | } 132 | 133 | ret = csh_login(&csh); 134 | if (ret == 0) { 135 | login = true; 136 | } else { 137 | return 0; 138 | } 139 | 140 | restart2: 141 | chry_shell_task_exec(&csh); 142 | 143 | ret = chry_shell_task_repl(&csh); 144 | 145 | if (ret == -1) { 146 | /*!< error */ 147 | return -1; 148 | } else if (ret == 1) { 149 | /*!< continue */ 150 | return 0; 151 | } else { 152 | /*!< restart */ 153 | goto restart; 154 | } 155 | 156 | return 0; 157 | } 158 | 159 | void shell_lock(void) 160 | { 161 | chry_readline_erase_line(&csh.rl); 162 | } 163 | 164 | void shell_unlock(void) 165 | { 166 | chry_readline_edit_refresh(&csh.rl); 167 | } 168 | 169 | static int csh_exit(int argc, char **argv) 170 | { 171 | (void)argc; 172 | (void)argv; 173 | login = false; 174 | return 0; 175 | } 176 | CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, ); 177 | 178 | #define __ENV_PATH "/sbin:/bin" 179 | const char ENV_PATH[] = __ENV_PATH; 180 | CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH)); 181 | 182 | #define __ENV_ZERO "" 183 | const char ENV_ZERO[] = __ENV_ZERO; 184 | CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO)); 185 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 HPMicro 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.13) 5 | 6 | set(CONFIG_CHERRYRB 1) 7 | set(CONFIG_CHERRYUSB 1) 8 | set(CONFIG_USB_DEVICE 1) 9 | set(CONFIG_USB_DEVICE_CDC 1) 10 | 11 | find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) 12 | project(cherryshell) 13 | 14 | sdk_compile_options("-O2") 15 | 16 | sdk_inc(inc) 17 | sdk_inc(../../../) 18 | 19 | sdk_app_src( 20 | src/main.c 21 | src/shell.c 22 | ../../../cherryrl/chry_readline.c 23 | ../../../chry_shell.c 24 | ../../../builtin/help.c 25 | ../../../builtin/shsize.c 26 | ../../../builtin/login.c 27 | ) 28 | 29 | generate_ses_project() 30 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/README_en.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell Barebone USB 2 | 3 | ## Overview 4 | 5 | The Cherry Shell Barebone example project demonstrates the basic usage of shell in bare-metal mode. In this project, you need to connect via USB PORT, and the shell requires a login. The default password is 12345678. After entering the password and pressing Enter, you will enter the shell. You can use the "help" command to view the available commands and variables. 6 | 7 | Please refrain from using USB PORT assistants and consider downloading and using [MobaXterm](https://mobaxterm.mobatek.net/download.html) 8 | 9 | ## Board Setting 10 | 11 | No special settings 12 | 13 | ## Running the example 14 | 15 | - After the project runs successfully, the serial terminal will output the following information: 16 | 17 | ```console 18 | login as: cherry 19 | cherry@hpm5301evklite's password: 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | other task interval 5S 25 | 26 | ``` 27 | 28 | - If you manually enter the correct password "12345678" and press Enter, the terminal will output the following information: 29 | 30 | ```console 31 | login as: cherry 32 | cherry@hpm5301evklite's password: 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | other task interval 5S 38 | 39 | welcome to cherry shell 40 | cherry@hpm5301evklite:/$ 41 | ``` 42 | 43 | - If you manually enter the command "help" and press Enter, the terminal will output the following information: 44 | 45 | ```console 46 | cherry@hpm5301evklite:/$ help 47 | total function 6 48 | test -> /bin 49 | toggle_led -> /bin 50 | write_led -> /bin 51 | exit -> /sbin 52 | help -> /sbin 53 | shsize -> /sbin 54 | 55 | total variable 2 56 | $PATH r- 11 57 | $ZERO r- 1 58 | cherry@hpm5301evklite:/$ 59 | ``` 60 | 61 | - If you manually enter the command "toggle_led" and press Enter, the LED will toggle. 62 | - If you manually enter the command "write_led 1" and press Enter, the LED will turn on. 63 | - If you manually enter the command "write_led 0" and press Enter, the LED will turn off. 64 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/README_zh.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell Barebone USB 2 | 3 | ## 概述 4 | 5 | Cherry Shell Barebone示例工程展示了shell的裸机模式基本使用。在这个工程中,需要连接 USB,shell默认需要登陆,密码为12345678。输入密码后回车,进入shell,输入help可以查看命令和变量。 6 | 请勿使用串口助手,推荐下载使用 [MobaXterm](https://mobaxterm.mobatek.net/download.html) 7 | 8 | ## 硬件设置 9 | 10 | 无特殊设置 11 | 12 | ## 运行现象 13 | 14 | - 当工程正确运行后,串口终端会输出如下信息: 15 | 16 | ```console 17 | login as: cherry 18 | cherry@hpm5301evklite's password: 19 | other task interval 5S 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | 25 | ``` 26 | 27 | - 如果此时通过键盘手动输入正确密码"12345678"并回车,终端会输出如下信息: 28 | 29 | ```console 30 | login as: cherry 31 | cherry@hpm5301evklite's password: 32 | other task interval 5S 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | 38 | welcome to cherry shell 39 | cherry@hpm5301evklite:/$ 40 | ``` 41 | 42 | - 如果此时通过键盘手动输入命令"help"并回车,终端会输出如下信息: 43 | 44 | ```console 45 | cherry@hpm5301evklite:/$ help 46 | total function 6 47 | test -> /bin 48 | toggle_led -> /bin 49 | write_led -> /bin 50 | exit -> /sbin 51 | help -> /sbin 52 | shsize -> /sbin 53 | 54 | total variable 2 55 | $PATH r- 11 56 | $ZERO r- 1 57 | cherry@hpm5301evklite:/$ 58 | ``` 59 | 60 | - 如果此时通过键盘手动输入命令"toggle_led"并回车,LED将会翻转 61 | - 如果此时通过键盘手动输入命令"write_led 1"并回车,LED将会点亮 62 | - 如果此时通过键盘手动输入命令"write_led 0"并回车,LED将会熄灭 63 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/inc/csh_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CSH_CONFIG_H 8 | #define CSH_CONFIG_H 9 | 10 | /*!< argument check */ 11 | #define CONFIG_CSH_DEBUG 0 12 | 13 | /*!< default row */ 14 | #define CONFIG_CSH_DFTROW 25 15 | 16 | /*!< default column */ 17 | #define CONFIG_CSH_DFTCOL 80 18 | 19 | /*!< history support <+550byte> */ 20 | #define CONFIG_CSH_HISTORY 1 21 | 22 | /*!< completion support <+1100byte> */ 23 | #define CONFIG_CSH_COMPLETION 1 24 | 25 | /*!< max completion item list count (use stack 4 x count byte) */ 26 | #define CONFIG_CSH_MAX_COMPLETION 40 27 | 28 | /*!< prompt edit support <+1000byte> */ 29 | #define CONFIG_CSH_PROMPTEDIT 1 30 | 31 | /*!< prompt segment count */ 32 | #define CONFIG_CSH_PROMPTSEG 7 33 | 34 | /*!< xterm support */ 35 | #define CONFIG_CSH_XTERM 0 36 | 37 | /*!< newline */ 38 | #define CONFIG_CSH_NEWLINE "\r\n" 39 | 40 | /*!< tab space count */ 41 | #define CONFIG_CSH_SPACE 4 42 | 43 | /*!< independent ctrl map */ 44 | #define CONFIG_CSH_CTRLMAP 0 45 | 46 | /*!< independent alt map */ 47 | #define CONFIG_CSH_ALTMAP 0 48 | 49 | /*!< refresh prompt */ 50 | #define CONFIG_CSH_REFRESH_PROMPT 1 51 | 52 | /*!< no waiting for sget */ 53 | #define CONFIG_CSH_NOBLOCK 1 54 | 55 | /*!< help information */ 56 | #define CONFIG_CSH_HELP "" 57 | 58 | /*!< path length 0:const path, <=255:variable path */ 59 | #define CONFIG_CSH_MAXLEN_PATH 128 60 | 61 | /*!< path segment count */ 62 | #define CONFIG_CSH_MAXSEG_PATH 16 63 | 64 | /*!< user count */ 65 | #define CONFIG_CSH_MAX_USER 1 66 | 67 | /*!< max argument count */ 68 | #define CONFIG_CSH_MAX_ARG 8 69 | 70 | /*!< linebuffer static or on stack */ 71 | #define CONFIG_CSH_LNBUFF_STATIC 1 72 | 73 | /*!< linebuffer size (valid only if lnbuff on stack) */ 74 | #define CONFIG_CSH_LNBUFF_SIZE 256 75 | 76 | /*!< multi-thread mode */ 77 | #define CONFIG_CSH_MULTI_THREAD 0 78 | 79 | /*!< independent signal handler (for multi instances) */ 80 | #define CONFIG_CSH_SIGNAL_HANDLER 0 81 | 82 | /*!< Ctrl+c/d/q/s/z/\ F1-F12 UE <+120byte> */ 83 | #define CONFIG_CSH_USER_CALLBACK 1 84 | 85 | /*!< enable macro export symbol table */ 86 | #define CONFIG_CSH_SYMTAB 1 87 | 88 | /*!< print buffer size */ 89 | #define CONFIG_CSH_PRINT_BUFFER_SIZE 512 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/inc/shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef SHELL_H 8 | #define SHELL_H 9 | 10 | #include "csh.h" 11 | 12 | extern int shell_init(uint8_t busid, uint32_t regbase, bool need_login); 13 | extern int shell_main(void); 14 | extern void shell_lock(void); 15 | extern void shell_unlock(void); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/inc/usb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, sakumisu 3 | * Copyright (c) 2022-2024, HPMicro 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | #ifndef CHERRYUSB_CONFIG_H 8 | #define CHERRYUSB_CONFIG_H 9 | 10 | #include "hpm_soc_feature.h" 11 | 12 | #define CHERRYUSB_VERSION 0x010200 13 | #define CHERRYUSB_VERSION_STR "v1.2.0" 14 | 15 | /* ================ USB common Configuration ================ */ 16 | 17 | #define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__) 18 | 19 | #define usb_malloc(size) malloc(size) 20 | #define usb_free(ptr) free(ptr) 21 | 22 | #ifndef CONFIG_USB_DBG_LEVEL 23 | #define CONFIG_USB_DBG_LEVEL USB_DBG_INFO 24 | #endif 25 | 26 | #ifdef CONFIG_USB_DEVICE_FS 27 | #undef CONFIG_USB_HS 28 | #else 29 | #define CONFIG_USB_HS 30 | #endif 31 | 32 | /* Enable print with color */ 33 | #define CONFIG_USB_PRINTF_COLOR_ENABLE 34 | 35 | /* data align size when use dma */ 36 | #ifndef CONFIG_USB_ALIGN_SIZE 37 | #define CONFIG_USB_ALIGN_SIZE 4 38 | #endif 39 | 40 | /* descriptor common define */ 41 | #define USBD_VID 0x34B7 /* Hpmicro vid */ 42 | #define USBD_PID 0xFFFF 43 | #define USBD_MAX_POWER 200 44 | #define USBD_LANGID_STRING 1033 45 | 46 | /* attribute data into no cache ram */ 47 | #define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable"))) 48 | 49 | /* ================= USB Device Stack Configuration ================ */ 50 | 51 | #define CONFIG_USBDEV_MAX_BUS USB_SOC_MAX_COUNT 52 | 53 | /* Ep0 max transfer buffer, specially for receiving data from ep0 out */ 54 | #define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512 55 | 56 | /* Setup packet log for debug */ 57 | /* #define CONFIG_USBDEV_SETUP_LOG_PRINT */ 58 | 59 | /* Check if the input descriptor is correct */ 60 | /* #define CONFIG_USBDEV_DESC_CHECK */ 61 | 62 | /* Enable test mode */ 63 | #define CONFIG_USBDEV_TEST_MODE 64 | 65 | #ifndef CONFIG_USBDEV_MSC_MAX_LUN 66 | #define CONFIG_USBDEV_MSC_MAX_LUN 1 67 | #endif 68 | 69 | #ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE 70 | #define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512 71 | #endif 72 | 73 | #ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING 74 | #define CONFIG_USBDEV_MSC_MANUFACTURER_STRING "" 75 | #endif 76 | 77 | #ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING 78 | #define CONFIG_USBDEV_MSC_PRODUCT_STRING "" 79 | #endif 80 | 81 | #ifndef CONFIG_USBDEV_MSC_VERSION_STRING 82 | #define CONFIG_USBDEV_MSC_VERSION_STRING "0.01" 83 | #endif 84 | 85 | /* #define CONFIG_USBDEV_MSC_THREAD */ 86 | 87 | #ifndef CONFIG_USBDEV_MSC_PRIO 88 | #define CONFIG_USBDEV_MSC_PRIO 4 89 | #endif 90 | 91 | #ifndef CONFIG_USBDEV_MSC_STACKSIZE 92 | #define CONFIG_USBDEV_MSC_STACKSIZE 2048 93 | #endif 94 | 95 | #ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 96 | #define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156 97 | #endif 98 | 99 | #ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 100 | #define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1536 101 | #endif 102 | 103 | #ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID 104 | #define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff 105 | #endif 106 | 107 | #ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC 108 | #define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB" 109 | #endif 110 | 111 | #define CONFIG_USBDEV_RNDIS_USING_LWIP 112 | 113 | /* ================ USB HOST Stack Configuration ================== */ 114 | 115 | #define CONFIG_USBHOST_MAX_BUS USB_SOC_MAX_COUNT 116 | #define CONFIG_USBHOST_MAX_RHPORTS 1 117 | #define CONFIG_USBHOST_MAX_EXTHUBS 1 118 | #define CONFIG_USBHOST_MAX_EHPORTS 4 119 | #define CONFIG_USBHOST_MAX_INTERFACES 8 120 | #define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2 121 | #define CONFIG_USBHOST_MAX_ENDPOINTS 8 122 | 123 | #define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4 124 | #define CONFIG_USBHOST_MAX_HID_CLASS 4 125 | #define CONFIG_USBHOST_MAX_MSC_CLASS 2 126 | #define CONFIG_USBHOST_MAX_AUDIO_CLASS 1 127 | #define CONFIG_USBHOST_MAX_VIDEO_CLASS 1 128 | 129 | #define CONFIG_USBHOST_DEV_NAMELEN 16 130 | 131 | #ifndef CONFIG_USBHOST_PSC_PRIO 132 | #define CONFIG_USBHOST_PSC_PRIO 0 133 | #endif 134 | #ifndef CONFIG_USBHOST_PSC_STACKSIZE 135 | #define CONFIG_USBHOST_PSC_STACKSIZE 2048 136 | #endif 137 | 138 | /* #define CONFIG_USBHOST_GET_STRING_DESC */ 139 | 140 | /* #define CONFIG_USBHOST_MSOS_ENABLE */ 141 | #define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00 142 | 143 | /* Ep0 max transfer buffer */ 144 | #define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512 145 | 146 | #ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 147 | #define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500 148 | #endif 149 | 150 | #ifndef CONFIG_USBHOST_MSC_TIMEOUT 151 | #define CONFIG_USBHOST_MSC_TIMEOUT 5000 152 | #endif 153 | 154 | #define CONFIG_USBHOST_BLUETOOTH_HCI_H4 155 | /* #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG */ 156 | 157 | #ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE 158 | #define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048 159 | #endif 160 | #ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE 161 | #define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048 162 | #endif 163 | 164 | /* ================ USB Device Port Configuration ================*/ 165 | 166 | #ifndef CONFIG_USBDEV_EP_NUM 167 | #define CONFIG_USBDEV_EP_NUM USB_SOC_DCD_MAX_ENDPOINT_COUNT 168 | #endif 169 | 170 | #ifndef CONFIG_HPM_USBD_BASE 171 | #define CONFIG_HPM_USBD_BASE HPM_USB0_BASE 172 | #endif 173 | #ifndef CONFIG_HPM_USBD_IRQn 174 | #define CONFIG_HPM_USBD_IRQn IRQn_USB0 175 | #endif 176 | 177 | /* ================ USB Host Port Configuration ==================*/ 178 | 179 | #define CONFIG_USBHOST_PIPE_NUM 5 180 | #define CONFIG_USB_EHCI_QTD_NUM 8 181 | 182 | #ifndef CONFIG_HPM_USBH_BASE 183 | #define CONFIG_HPM_USBH_BASE HPM_USB0_BASE 184 | #endif 185 | #ifndef CONFIG_HPM_USBH_IRQn 186 | #define CONFIG_HPM_USBH_IRQn IRQn_USB0 187 | #endif 188 | 189 | /* ================ EHCI Configuration ================ */ 190 | 191 | #define CONFIG_USB_EHCI_HPMICRO (1) 192 | #define CONFIG_USB_EHCI_HCCR_OFFSET (0x100u) 193 | #define CONFIG_USB_EHCI_HCOR_OFFSET (0x140u) 194 | #define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024 195 | /* #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE */ 196 | /* #define CONFIG_USB_EHCI_CONFIGFLAG */ 197 | #define CONFIG_USB_EHCI_PORT_POWER 198 | /* #define CONFIG_USB_EHCI_PRINT_HW_PARAM */ 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 HPMicro 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | /* HPM example includes. */ 9 | #include 10 | #include "board.h" 11 | #include "hpm_clock_drv.h" 12 | #include "shell.h" 13 | #include "usbd_core.h" 14 | 15 | int main(void) 16 | { 17 | board_init(); 18 | board_init_led_pins(); 19 | 20 | board_init_usb_pins(); 21 | intc_set_irq_priority(CONFIG_HPM_USBD_IRQn, 2); 22 | 23 | /* default password is : 12345678 */ 24 | /* shell_init() must be called in-task */ 25 | if (0 != shell_init(0, CONFIG_HPM_USBD_BASE, true)) { 26 | /* shell failed to be initialized */ 27 | printf("Failed to initialize shell\r\n"); 28 | for (;;) { 29 | ; 30 | } 31 | } 32 | 33 | printf("Initialize shell successfully\r\n"); 34 | 35 | while (1) { 36 | shell_main(); 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | static int test(int argc, char **argv) 43 | { 44 | chry_shell_t *csh = (void *)argv[argc + 1]; 45 | csh_printf(csh, "test: \r\n"); 46 | csh_printf(csh, "argc=<%d>\r\n", argc); 47 | for (uint8_t i = 0; i < argc; i++) { 48 | csh_printf(csh, "argv[%d]:0x%08x=<%s>\r\n", i, (uintptr_t)argv[i], argv[i]); 49 | } 50 | 51 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n", argc, argv[argc]); 52 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n\r\n", argc + 1, argv[argc + 1]); 53 | 54 | return 0; 55 | } 56 | CSH_CMD_EXPORT(test, ); 57 | 58 | static int toggle_led(int argc, char **argv) 59 | { 60 | (void)argc; 61 | (void)argv; 62 | board_led_toggle(); 63 | return 0; 64 | } 65 | CSH_CMD_EXPORT(toggle_led, ); 66 | 67 | static int write_led(int argc, char **argv) 68 | { 69 | chry_shell_t *csh = (void *)argv[argc + 1]; 70 | if (argc < 2) { 71 | csh_printf(csh, "usage: write_led \r\n\r\n"); 72 | csh_printf(csh, " status 0 or 1\r\n\r\n"); 73 | return -1; 74 | } 75 | 76 | board_led_write(!board_get_led_gpio_off_level() ^ (atoi(argv[1]) == 0)); 77 | return 0; 78 | } 79 | CSH_CMD_EXPORT(write_led, ); 80 | -------------------------------------------------------------------------------- /samples/hpm/barebone_usb/src/shell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "board.h" 4 | #include "chry_ringbuffer.h" 5 | #include "csh.h" 6 | #include "usbd_core.h" 7 | #include "usbd_cdc.h" 8 | 9 | static chry_shell_t csh; 10 | static bool login = false; 11 | static chry_ringbuffer_t shell_rb; 12 | static uint8_t mempool[1024]; 13 | 14 | /*!< endpoint address */ 15 | #define CDC_IN_EP 0x81 16 | #define CDC_OUT_EP 0x01 17 | #define CDC_INT_EP 0x83 18 | 19 | /*!< config descriptor size */ 20 | #define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN) 21 | 22 | #ifdef CONFIG_USB_HS 23 | #define CDC_MAX_MPS 512 24 | #else 25 | #define CDC_MAX_MPS 64 26 | #endif 27 | 28 | /*!< global descriptor */ 29 | static const uint8_t cdc_descriptor[] = { 30 | USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01), 31 | USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), 32 | CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02), 33 | /* 34 | * string0 descriptor 35 | */ 36 | USB_LANGID_INIT(USBD_LANGID_STRING), 37 | /* 38 | * string1 descriptor 39 | */ 40 | 0x14, /* bLength */ 41 | USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ 42 | 'C', 0x00, /* wcChar0 */ 43 | 'h', 0x00, /* wcChar1 */ 44 | 'e', 0x00, /* wcChar2 */ 45 | 'r', 0x00, /* wcChar3 */ 46 | 'r', 0x00, /* wcChar4 */ 47 | 'y', 0x00, /* wcChar5 */ 48 | 'U', 0x00, /* wcChar6 */ 49 | 'S', 0x00, /* wcChar7 */ 50 | 'B', 0x00, /* wcChar8 */ 51 | /* 52 | * string2 descriptor 53 | */ 54 | 0x26, /* bLength */ 55 | USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ 56 | 'C', 0x00, /* wcChar0 */ 57 | 'h', 0x00, /* wcChar1 */ 58 | 'e', 0x00, /* wcChar2 */ 59 | 'r', 0x00, /* wcChar3 */ 60 | 'r', 0x00, /* wcChar4 */ 61 | 'y', 0x00, /* wcChar5 */ 62 | 'U', 0x00, /* wcChar6 */ 63 | 'S', 0x00, /* wcChar7 */ 64 | 'B', 0x00, /* wcChar8 */ 65 | ' ', 0x00, /* wcChar9 */ 66 | 'C', 0x00, /* wcChar10 */ 67 | 'S', 0x00, /* wcChar11 */ 68 | 'H', 0x00, /* wcChar12 */ 69 | ' ', 0x00, /* wcChar13 */ 70 | 'D', 0x00, /* wcChar14 */ 71 | 'E', 0x00, /* wcChar15 */ 72 | 'M', 0x00, /* wcChar16 */ 73 | 'O', 0x00, /* wcChar17 */ 74 | /* 75 | * string3 descriptor 76 | */ 77 | 0x16, /* bLength */ 78 | USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ 79 | '2', 0x00, /* wcChar0 */ 80 | '0', 0x00, /* wcChar1 */ 81 | '2', 0x00, /* wcChar2 */ 82 | '2', 0x00, /* wcChar3 */ 83 | '1', 0x00, /* wcChar4 */ 84 | '2', 0x00, /* wcChar5 */ 85 | '3', 0x00, /* wcChar6 */ 86 | '4', 0x00, /* wcChar7 */ 87 | '5', 0x00, /* wcChar8 */ 88 | '6', 0x00, /* wcChar9 */ 89 | #ifdef CONFIG_USB_HS 90 | /* 91 | * device qualifier descriptor 92 | */ 93 | 0x0a, 94 | USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, 95 | 0x00, 96 | 0x02, 97 | 0x02, 98 | 0x02, 99 | 0x01, 100 | 0x40, 101 | 0x01, 102 | 0x00, 103 | #endif 104 | 0x00 105 | }; 106 | 107 | USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_temp_read_buffer[CDC_MAX_MPS]; 108 | USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t usb_temp_write_buffer[1024]; 109 | volatile bool ep_tx_busy_flag = false; 110 | 111 | static void usbd_event_handler(uint8_t busid, uint8_t event) 112 | { 113 | switch (event) { 114 | case USBD_EVENT_RESET: 115 | ep_tx_busy_flag = false; 116 | break; 117 | case USBD_EVENT_CONNECTED: 118 | break; 119 | case USBD_EVENT_DISCONNECTED: 120 | break; 121 | case USBD_EVENT_RESUME: 122 | break; 123 | case USBD_EVENT_SUSPEND: 124 | break; 125 | case USBD_EVENT_CONFIGURED: 126 | /* setup first out ep read transfer */ 127 | usbd_ep_start_read(busid, CDC_OUT_EP, usb_temp_read_buffer, CDC_MAX_MPS); 128 | break; 129 | case USBD_EVENT_SET_REMOTE_WAKEUP: 130 | break; 131 | case USBD_EVENT_CLR_REMOTE_WAKEUP: 132 | break; 133 | 134 | default: 135 | break; 136 | } 137 | } 138 | 139 | void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) 140 | { 141 | chry_ringbuffer_write(&shell_rb, usb_temp_read_buffer, nbytes); 142 | usbd_ep_start_read(busid, ep, usb_temp_read_buffer, CDC_MAX_MPS); 143 | } 144 | 145 | void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) 146 | { 147 | if ((nbytes % CDC_MAX_MPS) == 0 && nbytes) { 148 | /* send zlp */ 149 | usbd_ep_start_write(busid, ep, NULL, 0); 150 | } else { 151 | ep_tx_busy_flag = false; 152 | } 153 | } 154 | 155 | /*!< endpoint call back */ 156 | struct usbd_endpoint cdc_out_ep = { 157 | .ep_addr = CDC_OUT_EP, 158 | .ep_cb = usbd_cdc_acm_bulk_out 159 | }; 160 | 161 | struct usbd_endpoint cdc_in_ep = { 162 | .ep_addr = CDC_IN_EP, 163 | .ep_cb = usbd_cdc_acm_bulk_in 164 | }; 165 | 166 | static struct usbd_interface intf0; 167 | static struct usbd_interface intf1; 168 | 169 | void cdc_acm_init(uint8_t busid, uint32_t reg_base) 170 | { 171 | usbd_desc_register(busid, cdc_descriptor); 172 | usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0)); 173 | usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1)); 174 | usbd_add_endpoint(busid, &cdc_out_ep); 175 | usbd_add_endpoint(busid, &cdc_in_ep); 176 | usbd_initialize(busid, reg_base, usbd_event_handler); 177 | } 178 | 179 | static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size) 180 | { 181 | (void)rl; 182 | 183 | memcpy(usb_temp_write_buffer, data, size); 184 | usbd_ep_start_write(0, CDC_IN_EP, usb_temp_write_buffer, size); 185 | ep_tx_busy_flag = true; 186 | while(ep_tx_busy_flag){} 187 | return size; 188 | } 189 | 190 | static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size) 191 | { 192 | (void)rl; 193 | return chry_ringbuffer_read(&shell_rb, data, size); 194 | } 195 | 196 | int shell_init(uint8_t busid, uint32_t regbase, bool need_login) 197 | { 198 | chry_shell_init_t csh_init; 199 | 200 | if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) { 201 | return -1; 202 | } 203 | 204 | cdc_acm_init(busid, regbase); 205 | 206 | while(!usb_device_is_configured(busid)) 207 | { 208 | } 209 | 210 | if (need_login) { 211 | login = false; 212 | } else { 213 | login = true; 214 | } 215 | 216 | /*!< I/O callback */ 217 | csh_init.sput = csh_sput_cb; 218 | csh_init.sget = csh_sget_cb; 219 | 220 | #if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB 221 | extern const int __fsymtab_start; 222 | extern const int __fsymtab_end; 223 | extern const int __vsymtab_start; 224 | extern const int __vsymtab_end; 225 | 226 | /*!< get table from ld symbol */ 227 | csh_init.command_table_beg = &__fsymtab_start; 228 | csh_init.command_table_end = &__fsymtab_end; 229 | csh_init.variable_table_beg = &__vsymtab_start; 230 | csh_init.variable_table_end = &__vsymtab_end; 231 | #endif 232 | 233 | #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT 234 | static char csh_prompt_buffer[128]; 235 | 236 | /*!< set prompt buffer */ 237 | csh_init.prompt_buffer = csh_prompt_buffer; 238 | csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer); 239 | #endif 240 | 241 | #if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY 242 | static char csh_history_buffer[128]; 243 | 244 | /*!< set history buffer */ 245 | csh_init.history_buffer = csh_history_buffer; 246 | csh_init.history_buffer_size = sizeof(csh_history_buffer); 247 | #endif 248 | 249 | #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC 250 | static char csh_line_buffer[128]; 251 | 252 | /*!< set linebuffer */ 253 | csh_init.line_buffer = csh_line_buffer; 254 | csh_init.line_buffer_size = sizeof(csh_line_buffer); 255 | #endif 256 | 257 | csh_init.uid = 0; 258 | csh_init.user[0] = "cherry"; 259 | 260 | /*!< The port hash function is required, 261 | and the strcmp attribute is used weakly by default, 262 | int chry_shell_port_hash_strcmp(const char *hash, const char *str); */ 263 | csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */ 264 | csh_init.host = BOARD_NAME; 265 | csh_init.user_data = NULL; 266 | 267 | int ret = chry_shell_init(&csh, &csh_init); 268 | if (ret) { 269 | return -1; 270 | } 271 | 272 | return 0; 273 | } 274 | 275 | int shell_main(void) 276 | { 277 | int ret; 278 | 279 | restart: 280 | 281 | if (login) { 282 | goto restart2; 283 | } 284 | 285 | ret = csh_login(&csh); 286 | if (ret == 0) { 287 | login = true; 288 | } else { 289 | return 0; 290 | } 291 | 292 | restart2: 293 | chry_shell_task_exec(&csh); 294 | 295 | ret = chry_shell_task_repl(&csh); 296 | 297 | if (ret == -1) { 298 | /*!< error */ 299 | return -1; 300 | } else if (ret == 1) { 301 | /*!< continue */ 302 | return 0; 303 | } else { 304 | /*!< restart */ 305 | goto restart; 306 | } 307 | 308 | return 0; 309 | } 310 | 311 | void shell_lock(void) 312 | { 313 | chry_readline_erase_line(&csh.rl); 314 | } 315 | 316 | void shell_unlock(void) 317 | { 318 | chry_readline_edit_refresh(&csh.rl); 319 | } 320 | 321 | static int csh_exit(int argc, char **argv) 322 | { 323 | (void)argc; 324 | (void)argv; 325 | login = false; 326 | return 0; 327 | } 328 | CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, ); 329 | 330 | #define __ENV_PATH "/sbin:/bin" 331 | const char ENV_PATH[] = __ENV_PATH; 332 | CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH)); 333 | 334 | #define __ENV_ZERO "" 335 | const char ENV_ZERO[] = __ENV_ZERO; 336 | CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO)); 337 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 HPMicro 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.13) 5 | 6 | set(CONFIG_CHERRYRB 1) 7 | set(CONFIG_FREERTOS 1) 8 | 9 | find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) 10 | project(cherryshell) 11 | 12 | sdk_compile_options("-O2") 13 | sdk_compile_definitions(-D__freertos_irq_stack_top=_stack) 14 | sdk_compile_definitions(-DCONFIG_FREERTOS=1) 15 | sdk_compile_definitions(-DUSE_NONVECTOR_MODE=1) 16 | sdk_compile_definitions(-DDISABLE_IRQ_PREEMPTIVE=1) 17 | 18 | sdk_inc(inc) 19 | sdk_inc(../../../) 20 | 21 | sdk_app_src( 22 | src/main.c 23 | src/shell.c 24 | ../../../cherryrl/chry_readline.c 25 | ../../../chry_shell.c 26 | ../../../builtin/help.c 27 | ../../../builtin/shsize.c 28 | ../../../builtin/login.c 29 | ) 30 | 31 | generate_ses_project() 32 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/README_en.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell FreeRTOS UART 2 | 3 | ## Overview 4 | 5 | The Cherry Shell FreeRTOS example project demonstrates the basic usage of shell in multi-thread mode. In this project, you need to connect via serial port, and the shell requires a login. The default password is 12345678. After entering the password and pressing Enter, you will enter the shell. You can use the "help" command to view the available commands and variables. 6 | 7 | Please refrain from using serial port assistants and consider downloading and using [MobaXterm](https://mobaxterm.mobatek.net/download.html) 8 | 9 | ## Board Setting 10 | 11 | No special settings 12 | 13 | ## Running the example 14 | 15 | - After the project runs successfully, the serial terminal will output the following information: 16 | 17 | ```console 18 | login as: cherry 19 | cherry@hpm5301evklite's password: 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | other task interval 5S 25 | 26 | ``` 27 | 28 | - If you manually enter the correct password "12345678" and press Enter, the terminal will output the following information: 29 | 30 | ```console 31 | login as: cherry 32 | cherry@hpm5301evklite's password: 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | other task interval 5S 38 | 39 | welcome to cherry shell 40 | cherry@hpm5301evklite:/$ 41 | ``` 42 | 43 | - If you manually enter the command "help" and press Enter, the terminal will output the following information: 44 | 45 | ```console 46 | cherry@hpm5301evklite:/$ help 47 | total function 6 48 | test -> /bin 49 | toggle_led -> /bin 50 | write_led -> /bin 51 | exit -> /sbin 52 | help -> /sbin 53 | shsize -> /sbin 54 | 55 | total variable 2 56 | $PATH r- 11 57 | $ZERO r- 1 58 | cherry@hpm5301evklite:/$ 59 | ``` 60 | 61 | - If you manually enter the command "toggle_led" and press Enter, the LED will toggle. 62 | - If you manually enter the command "write_led 1" and press Enter, the LED will turn on. 63 | - If you manually enter the command "write_led 0" and press Enter, the LED will turn off. 64 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/README_zh.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell FreeRTOS UART 2 | 3 | ## 概述 4 | 5 | Cherry Shell FreeRTOS示例工程展示了shell的多线程模式基本使用。多线程模式下,命令的执行在独立的线程中,可以使用Ctrl+C中断命令执行。在这个工程中,需要连接串口,shell默认需要登陆,密码为12345678。输入密码后回车,进入shell,输入help可以查看命令和变量。 6 | 请勿使用串口助手,推荐下载使用 [MobaXterm](https://mobaxterm.mobatek.net/download.html) 7 | 8 | ## 硬件设置 9 | 10 | 无特殊设置 11 | 12 | ## 运行现象 13 | 14 | - 当工程正确运行后,串口终端会输出如下信息: 15 | 16 | ```console 17 | login as: cherry 18 | cherry@hpm5301evklite's password: 19 | other task interval 5S 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | 25 | ``` 26 | 27 | - 如果此时通过键盘手动输入正确密码"12345678"并回车,终端会输出如下信息: 28 | 29 | ```console 30 | login as: cherry 31 | cherry@hpm5301evklite's password: 32 | other task interval 5S 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | 38 | welcome to cherry shell 39 | cherry@hpm5301evklite:/$ 40 | ``` 41 | 42 | - 如果此时通过键盘手动输入命令"help"并回车,终端会输出如下信息: 43 | 44 | ```console 45 | cherry@hpm5301evklite:/$ help 46 | total function 6 47 | test -> /bin 48 | toggle_led -> /bin 49 | write_led -> /bin 50 | exit -> /sbin 51 | help -> /sbin 52 | shsize -> /sbin 53 | 54 | total variable 2 55 | $PATH r- 11 56 | $ZERO r- 1 57 | cherry@hpm5301evklite:/$ 58 | ``` 59 | 60 | - 如果此时通过键盘手动输入命令"toggle_led"并回车,LED将会翻转 61 | - 如果此时通过键盘手动输入命令"write_led 1"并回车,LED将会点亮 62 | - 如果此时通过键盘手动输入命令"write_led 0"并回车,LED将会熄灭 63 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/inc/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 HPMicro 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #ifndef FREERTOS_CONFIG_H 9 | #define FREERTOS_CONFIG_H 10 | 11 | /* 12 | * Application specific definitions. 13 | * 14 | * These definitions should be adjusted for your particular hardware and 15 | * application requirements. 16 | * 17 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 18 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 19 | * 20 | * See http://www.freertos.org/a00110.html. 21 | */ 22 | 23 | #include "board.h" 24 | 25 | #if (portasmHAS_MTIME == 0) 26 | #define configMTIME_BASE_ADDRESS (0) 27 | #define configMTIMECMP_BASE_ADDRESS (0) 28 | #else 29 | #define configMTIME_BASE_ADDRESS (HPM_MCHTMR_BASE) 30 | #define configMTIMECMP_BASE_ADDRESS (HPM_MCHTMR_BASE + 8UL) 31 | #endif 32 | 33 | #define configUSE_PREEMPTION 1 34 | #define configCPU_CLOCK_HZ ((uint32_t) 24000000) 35 | #define configTICK_RATE_HZ ((TickType_t) 1000) 36 | #define configMAX_PRIORITIES (32) 37 | #define configMINIMAL_STACK_SIZE (256) 38 | #define configMAX_TASK_NAME_LEN 16 39 | #define configUSE_16_BIT_TICKS 0 40 | #define configIDLE_SHOULD_YIELD 0 41 | #define configUSE_APPLICATION_TASK_TAG 0 42 | #define configGENERATE_RUN_TIME_STATS 0 43 | 44 | /* Memory allocation definitions. */ 45 | #define configSUPPORT_STATIC_ALLOCATION 1 46 | #define configSUPPORT_DYNAMIC_ALLOCATION 1 47 | #define configTOTAL_HEAP_SIZE ((size_t) (8 * 1024)) 48 | 49 | /* Hook function definitions. */ 50 | #define configUSE_IDLE_HOOK 0 51 | #define configUSE_TICK_HOOK 0 52 | #define configCHECK_FOR_STACK_OVERFLOW 0 53 | #define configUSE_MALLOC_FAILED_HOOK 0 54 | #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 55 | 56 | /* Run time and task stats gathering definitions. */ 57 | #define configGENERATE_RUN_TIME_STATS 0 58 | #define configUSE_TRACE_FACILITY 1 59 | #define configUSE_STATS_FORMATTING_FUNCTIONS 0 60 | 61 | /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ 62 | #define INCLUDE_vTaskPrioritySet 1 63 | #define INCLUDE_uxTaskPriorityGet 1 64 | #define INCLUDE_vTaskDelete 1 65 | #define INCLUDE_vTaskCleanUpResources 1 66 | #define INCLUDE_vTaskSuspend 1 67 | #define INCLUDE_vTaskDelayUntil 1 68 | #define INCLUDE_vTaskDelay 1 69 | #define INCLUDE_xTaskGetCurrentTaskHandle 1 70 | #define INCLUDE_xTimerPendFunctionCall 1 71 | #define INCLUDE_eTaskGetState 1 72 | #define INCLUDE_xTaskAbortDelay 1 73 | #define INCLUDE_xTaskGetHandle 1 74 | #define INCLUDE_xSemaphoreGetMutexHolder 1 75 | 76 | /* Co-routine definitions. */ 77 | #define configUSE_CO_ROUTINES 0 78 | #define configMAX_CO_ROUTINE_PRIORITIES 2 79 | 80 | /* Software timer definitions. */ 81 | #define configUSE_TIMERS 1 82 | #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) 83 | #define configTIMER_QUEUE_LENGTH 4 84 | #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE) 85 | 86 | /* Task priorities.*/ 87 | #ifndef uartPRIMARY_PRIORITY 88 | #define uartPRIMARY_PRIORITY (configMAX_PRIORITIES - 3) 89 | #endif 90 | 91 | /* Normal assert() semantics without relying on the provision of an assert.h header file. */ 92 | #define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); __asm volatile("ebreak"); for (;;); } 93 | 94 | /* 95 | * The size of the global output buffer that is available for use when there 96 | * are multiple command interpreters running at once (for example, one on a UART 97 | * and one on TCP/IP). This is done to prevent an output buffer being defined by 98 | * each implementation - which would waste RAM. In this case, there is only one 99 | * command interpreter running. 100 | */ 101 | 102 | /* 103 | * The buffer into which output generated by FreeRTOS+CLI is placed. This must 104 | * be at least big enough to contain the output of the task-stats command, as the 105 | * example implementation does not include buffer overlow checking. 106 | */ 107 | #define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 108 | #define configINCLUDE_QUERY_HEAP_COMMAND 1 109 | 110 | /* This file is included from assembler files - make sure C code is not included in assembler files. */ 111 | #ifndef __ASSEMBLER__ 112 | void vAssertCalled(const char *pcFile, unsigned long ulLine); 113 | void vConfigureTickInterrupt(void); 114 | void vClearTickInterrupt(void); 115 | void vPreSleepProcessing(unsigned long uxExpectedIdleTime); 116 | void vPostSleepProcessing(unsigned long uxExpectedIdleTime); 117 | #endif /* __ASSEMBLER__ */ 118 | 119 | /****** Hardware/compiler specific settings. *******/ 120 | /* 121 | * The application must provide a function that configures a peripheral to 122 | * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() 123 | * in FreeRTOSConfig.h to call the function. 124 | */ 125 | #define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() 126 | #define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() 127 | 128 | /* 129 | * The configPRE_SLEEP_PROCESSING() and configPOST_SLEEP_PROCESSING() macros 130 | * allow the application writer to add additional code before and after the MCU is 131 | * placed into the low power state respectively. The empty implementations 132 | * provided in this demo can be extended to save even more power. 133 | */ 134 | #define configPRE_SLEEP_PROCESSING(uxExpectedIdleTime) vPreSleepProcessing(uxExpectedIdleTime); 135 | #define configPOST_SLEEP_PROCESSING(uxExpectedIdleTime) vPostSleepProcessing(uxExpectedIdleTime); 136 | 137 | 138 | /* Compiler specifics. */ 139 | #define fabs(x) __builtin_fabs(x) 140 | 141 | /* Enable Hardware Stack Protection and Recording mechanism. */ 142 | #define configHSP_ENABLE 0 143 | 144 | /* Record the highest address of stack. */ 145 | #if (configHSP_ENABLE == 1 && configRECORD_STACK_HIGH_ADDRESS != 1) 146 | #define configRECORD_STACK_HIGH_ADDRESS 1 147 | #endif 148 | 149 | #endif /* FREERTOS_CONFIG_H */ 150 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/inc/csh_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CSH_CONFIG_H 8 | #define CSH_CONFIG_H 9 | 10 | /*!< argument check */ 11 | #define CONFIG_CSH_DEBUG 0 12 | 13 | /*!< default row */ 14 | #define CONFIG_CSH_DFTROW 25 15 | 16 | /*!< default column */ 17 | #define CONFIG_CSH_DFTCOL 80 18 | 19 | /*!< history support <+550byte> */ 20 | #define CONFIG_CSH_HISTORY 1 21 | 22 | /*!< completion support <+1100byte> */ 23 | #define CONFIG_CSH_COMPLETION 1 24 | 25 | /*!< max completion item list count (use stack 4 x count byte) */ 26 | #define CONFIG_CSH_MAX_COMPLETION 40 27 | 28 | /*!< prompt edit support <+1000byte> */ 29 | #define CONFIG_CSH_PROMPTEDIT 1 30 | 31 | /*!< prompt segment count */ 32 | #define CONFIG_CSH_PROMPTSEG 7 33 | 34 | /*!< xterm support */ 35 | #define CONFIG_CSH_XTERM 0 36 | 37 | /*!< newline */ 38 | #define CONFIG_CSH_NEWLINE "\r\n" 39 | 40 | /*!< tab space count */ 41 | #define CONFIG_CSH_SPACE 4 42 | 43 | /*!< independent ctrl map */ 44 | #define CONFIG_CSH_CTRLMAP 0 45 | 46 | /*!< independent alt map */ 47 | #define CONFIG_CSH_ALTMAP 0 48 | 49 | /*!< refresh prompt */ 50 | #define CONFIG_CSH_REFRESH_PROMPT 1 51 | 52 | /*!< no waiting for sget */ 53 | #define CONFIG_CSH_NOBLOCK 1 54 | 55 | /*!< help information */ 56 | #define CONFIG_CSH_HELP "" 57 | 58 | /*!< path length 0:const path, <=255:variable path */ 59 | #define CONFIG_CSH_MAXLEN_PATH 128 60 | 61 | /*!< path segment count */ 62 | #define CONFIG_CSH_MAXSEG_PATH 16 63 | 64 | /*!< user count */ 65 | #define CONFIG_CSH_MAX_USER 1 66 | 67 | /*!< max argument count */ 68 | #define CONFIG_CSH_MAX_ARG 8 69 | 70 | /*!< linebuffer static or on stack */ 71 | #define CONFIG_CSH_LNBUFF_STATIC 1 72 | 73 | /*!< linebuffer size (valid only if lnbuff on stack) */ 74 | #define CONFIG_CSH_LNBUFF_SIZE 256 75 | 76 | /*!< multi-thread mode */ 77 | #define CONFIG_CSH_MULTI_THREAD 1 78 | 79 | /*!< independent signal handler (for multi instances) */ 80 | #define CONFIG_CSH_SIGNAL_HANDLER 0 81 | 82 | /*!< Ctrl+c/d/q/s/z/\ F1-F12 UE <+120byte> */ 83 | #define CONFIG_CSH_USER_CALLBACK 1 84 | 85 | /*!< enable macro export symbol table */ 86 | #define CONFIG_CSH_SYMTAB 1 87 | 88 | /*!< print buffer size */ 89 | #define CONFIG_CSH_PRINT_BUFFER_SIZE 512 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/inc/shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef SHELL_H 8 | #define SHELL_H 9 | 10 | #include "hpm_uart_drv.h" 11 | #include "csh.h" 12 | 13 | extern int shell_init(UART_Type *uart, bool need_login); 14 | extern void shell_uart_isr(void); 15 | extern void shell_lock(void); 16 | extern void shell_unlock(void); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 HPMicro 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | /* FreeRTOS kernel includes. */ 9 | #include "FreeRTOS.h" 10 | #include "task.h" 11 | 12 | /* HPM example includes. */ 13 | #include 14 | #include "board.h" 15 | #include "hpm_clock_drv.h" 16 | #include "shell.h" 17 | 18 | SDK_DECLARE_EXT_ISR_M(BOARD_CONSOLE_UART_IRQ, shell_uart_isr) 19 | 20 | #define task_other_PRIORITY (configMAX_PRIORITIES - 3U) 21 | #define task_start_PRIORITY (configMAX_PRIORITIES - 2U) 22 | 23 | static void task_start(void *param); 24 | 25 | int main(void) 26 | { 27 | board_init(); 28 | board_init_led_pins(); 29 | 30 | if (pdPASS != xTaskCreate(task_start, "task_start", 1024U, NULL, task_start_PRIORITY, NULL)) { 31 | printf("Task start creation failed!\r\n"); 32 | for (;;) { 33 | ; 34 | } 35 | } 36 | 37 | vTaskStartScheduler(); 38 | printf("Unexpected scheduler exit!\r\n"); 39 | for (;;) { 40 | ; 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | static void task_other(void *pvParameters) 47 | { 48 | (void)pvParameters; 49 | for (;;) { 50 | shell_lock(); 51 | printf("other task interval 5S\r\n"); 52 | shell_unlock(); 53 | vTaskDelay(5000); 54 | } 55 | } 56 | 57 | static void task_start(void *param) 58 | { 59 | (void)param; 60 | 61 | printf("Try to initialize the uart\r\n" 62 | " if you are using the console uart as the shell uart\r\n" 63 | " failure to initialize may result in no log\r\n"); 64 | 65 | uart_config_t shell_uart_config = { 0 }; 66 | uart_default_config(BOARD_CONSOLE_UART_BASE, &shell_uart_config); 67 | shell_uart_config.src_freq_in_hz = clock_get_frequency(BOARD_CONSOLE_UART_CLK_NAME); 68 | shell_uart_config.baudrate = 115200; 69 | 70 | if (status_success != uart_init(BOARD_CONSOLE_UART_BASE, &shell_uart_config)) { 71 | /* uart failed to be initialized */ 72 | printf("Failed to initialize uart\r\n"); 73 | for (;;) { 74 | ; 75 | } 76 | } 77 | 78 | printf("Initialize shell uart successfully\r\n"); 79 | 80 | /* default password is : 12345678 */ 81 | /* shell_init() must be called in-task */ 82 | if (0 != shell_init(BOARD_CONSOLE_UART_BASE, true)) { 83 | /* shell failed to be initialized */ 84 | printf("Failed to initialize shell\r\n"); 85 | for (;;) { 86 | ; 87 | } 88 | } 89 | 90 | printf("Initialize shell successfully\r\n"); 91 | 92 | /* irq must be enabled after shell_init() */ 93 | uart_enable_irq(BOARD_CONSOLE_UART_BASE, uart_intr_rx_data_avail_or_timeout); 94 | intc_m_enable_irq_with_priority(BOARD_CONSOLE_UART_IRQ, 1); 95 | 96 | printf("Enable shell uart interrupt\r\n"); 97 | 98 | if (pdPASS != xTaskCreate(task_other, "task_other", configMINIMAL_STACK_SIZE, NULL, task_other_PRIORITY, NULL)) { 99 | printf("Task other creation failed!\r\n"); 100 | for (;;) { 101 | ; 102 | } 103 | } 104 | 105 | printf("Exit start task\r\n"); 106 | vTaskDelete(NULL); 107 | } 108 | 109 | static int test(int argc, char **argv) 110 | { 111 | chry_shell_t *csh = (void *)argv[argc + 1]; 112 | csh_printf(csh, "test: \r\n"); 113 | csh_printf(csh, "argc=<%d>\r\n", argc); 114 | for (uint8_t i = 0; i < argc; i++) { 115 | csh_printf(csh, "argv[%d]:0x%08x=<%s>\r\n", i, (uintptr_t)argv[i], argv[i]); 116 | } 117 | 118 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n", argc, argv[argc]); 119 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n\r\n", argc + 1, argv[argc + 1]); 120 | 121 | return 0; 122 | } 123 | CSH_CMD_EXPORT(test, ); 124 | 125 | static int toggle_led(int argc, char **argv) 126 | { 127 | (void)argc; 128 | (void)argv; 129 | board_led_toggle(); 130 | return 0; 131 | } 132 | CSH_CMD_EXPORT(toggle_led, ); 133 | 134 | static int write_led(int argc, char **argv) 135 | { 136 | chry_shell_t *csh = (void *)argv[argc + 1]; 137 | if (argc < 2) { 138 | csh_printf(csh, "usage: write_led \r\n\r\n"); 139 | csh_printf(csh, " status 0 or 1\r\n\r\n"); 140 | return -1; 141 | } 142 | 143 | board_led_write(!board_get_led_gpio_off_level() ^ (atoi(argv[1]) == 0)); 144 | return 0; 145 | } 146 | CSH_CMD_EXPORT(write_led, ); 147 | -------------------------------------------------------------------------------- /samples/hpm/freertos_uart/src/shell.c: -------------------------------------------------------------------------------- 1 | #include "FreeRTOS.h" 2 | #include "task.h" 3 | #include "event_groups.h" 4 | #include 5 | #include 6 | #include "board.h" 7 | #include "hpm_uart_drv.h" 8 | #include "chry_ringbuffer.h" 9 | #include "csh.h" 10 | 11 | #define task_repl_PRIORITY (configMAX_PRIORITIES - 4U) 12 | #define task_exec_PRIORITY (configMAX_PRIORITIES - 5U) 13 | 14 | static chry_shell_t csh; 15 | static UART_Type *shell_uart = NULL; 16 | static volatile bool login = false; 17 | static chry_ringbuffer_t shell_rb; 18 | static uint8_t mempool[1024]; 19 | 20 | static StaticTask_t task_buffer_repl; 21 | static StaticTask_t task_buffer_exec; 22 | 23 | static StackType_t task_stack_repl[1024]; 24 | static StackType_t task_stack_exec[1024]; 25 | 26 | static TaskHandle_t task_hdl_repl = NULL; 27 | static TaskHandle_t task_hdl_exec = NULL; 28 | 29 | static EventGroupHandle_t event_hdl; 30 | static StaticEventGroup_t event_grp; 31 | 32 | void shell_uart_isr(void) 33 | { 34 | BaseType_t xHigherPriorityTaskWoken = pdFALSE; 35 | uint8_t irq_id = uart_get_irq_id(shell_uart); 36 | 37 | if (irq_id == uart_intr_id_rx_data_avail) { 38 | while (uart_check_status(shell_uart, uart_stat_data_ready)) { 39 | uint8_t byte = uart_read_byte(shell_uart); 40 | chry_ringbuffer_write_byte(&shell_rb, byte); 41 | } 42 | 43 | xEventGroupSetBitsFromISR(event_hdl, 0x10, &xHigherPriorityTaskWoken); 44 | portYIELD_FROM_ISR(xHigherPriorityTaskWoken); 45 | } 46 | } 47 | 48 | static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size) 49 | { 50 | uint16_t i; 51 | (void)rl; 52 | for (i = 0; i < size; i++) { 53 | if (status_success != uart_send_byte(shell_uart, ((uint8_t *)data)[i])) { 54 | break; 55 | } 56 | } 57 | 58 | return i; 59 | } 60 | 61 | static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size) 62 | { 63 | (void)rl; 64 | return chry_ringbuffer_read(&shell_rb, data, size); 65 | } 66 | 67 | static void wait_char(void) 68 | { 69 | wait: 70 | EventBits_t event = xEventGroupWaitBits(event_hdl, (0x10 | 0x01 | 0x04), pdTRUE, pdFALSE, portMAX_DELAY); 71 | if ((event & 0x10) == 0) { 72 | if (event & 0x01) { 73 | chry_readline_erase_line(&csh.rl); 74 | xEventGroupSetBits(event_hdl, 0x02); 75 | } 76 | if (event & 0x04) { 77 | chry_readline_edit_refresh(&csh.rl); 78 | xEventGroupSetBits(event_hdl, 0x08); 79 | } 80 | 81 | goto wait; 82 | } 83 | } 84 | 85 | static void task_repl(void *param) 86 | { 87 | (void)param; 88 | int ret; 89 | volatile uint8_t *pexec = (void *)&csh.exec; 90 | 91 | for (;;) { 92 | restart: 93 | if (login) { 94 | goto repl; 95 | } else { 96 | } 97 | 98 | ret = csh_login(&csh); 99 | if (ret == 0) { 100 | login = true; 101 | } else if (ret == 1) { 102 | /*!< no enough char */ 103 | wait_char(); 104 | continue; 105 | } else { 106 | continue; 107 | } 108 | 109 | repl: 110 | ret = chry_shell_task_repl(&csh); 111 | 112 | if (ret == -1) { 113 | /*!< error */ 114 | goto restart; 115 | } else if (ret == 1) { 116 | /*!< no enough char */ 117 | wait_char(); 118 | } else { 119 | /*!< restart */ 120 | } 121 | 122 | /*!< check flag */ 123 | if (*pexec == CSH_STATUS_EXEC_DONE) { 124 | *pexec = CSH_STATUS_EXEC_IDLE; 125 | chry_readline_auto_refresh(&csh.rl, true); 126 | chry_readline_ignore(&csh.rl, false); 127 | chry_readline_edit_refresh(&csh.rl); 128 | } 129 | 130 | if (login == false) { 131 | chry_readline_erase_line(&csh.rl); 132 | csh.rl.noblock = false; 133 | } 134 | } 135 | } 136 | 137 | static void task_exec(void *param) 138 | { 139 | (void)param; 140 | 141 | /*!< execute shell command */ 142 | chry_shell_task_exec(&csh); 143 | 144 | /*!< notify REPL task execute done */ 145 | xEventGroupSetBits(event_hdl, 0x10); 146 | 147 | /*!< wait for REPL task delete */ 148 | vTaskSuspend(NULL); 149 | } 150 | 151 | int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **argv) 152 | { 153 | volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec; 154 | (void)csh; 155 | (void)argc; 156 | (void)argv; 157 | 158 | if (*p_task_hdl_exec != NULL) { 159 | vTaskDelete(*p_task_hdl_exec); 160 | } 161 | 162 | *p_task_hdl_exec = xTaskCreateStatic(task_exec, "task_exec", 1024U, NULL, task_exec_PRIORITY, task_stack_exec, &task_buffer_exec); 163 | return 0; 164 | } 165 | 166 | void chry_shell_port_default_handler(chry_shell_t *csh, int sig) 167 | { 168 | volatile uint8_t *pexec = (void *)&csh->exec; 169 | volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec; 170 | 171 | switch (sig) { 172 | case CSH_SIGINT: 173 | case CSH_SIGQUIT: 174 | case CSH_SIGKILL: 175 | case CSH_SIGTERM: 176 | break; 177 | default: 178 | return; 179 | } 180 | 181 | /*!< force delete task */ 182 | if (*p_task_hdl_exec != NULL) { 183 | vTaskDelete(task_hdl_exec); 184 | *p_task_hdl_exec = NULL; 185 | } 186 | 187 | switch (sig) { 188 | case CSH_SIGINT: 189 | csh->rl.sput(&csh->rl, "^SIGINT" CONFIG_CSH_NEWLINE, sizeof("^SIGINT" CONFIG_CSH_NEWLINE) - 1); 190 | break; 191 | case CSH_SIGQUIT: 192 | csh->rl.sput(&csh->rl, "^SIGQUIT" CONFIG_CSH_NEWLINE, sizeof("^SIGQUIT" CONFIG_CSH_NEWLINE) - 1); 193 | break; 194 | case CSH_SIGKILL: 195 | csh->rl.sput(&csh->rl, "^SIGKILL" CONFIG_CSH_NEWLINE, sizeof("^SIGKILL" CONFIG_CSH_NEWLINE) - 1); 196 | break; 197 | case CSH_SIGTERM: 198 | csh->rl.sput(&csh->rl, "^SIGTERM" CONFIG_CSH_NEWLINE, sizeof("^SIGTERM" CONFIG_CSH_NEWLINE) - 1); 199 | break; 200 | default: 201 | return; 202 | } 203 | 204 | *pexec = CSH_STATUS_EXEC_IDLE; 205 | chry_readline_auto_refresh(&csh->rl, true); 206 | chry_readline_ignore(&csh->rl, false); 207 | chry_readline_edit_refresh(&csh->rl); 208 | } 209 | 210 | int shell_init(UART_Type *uart, bool need_login) 211 | { 212 | chry_shell_init_t csh_init; 213 | 214 | if (uart == NULL) { 215 | return -1; 216 | } 217 | 218 | if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) { 219 | return -1; 220 | } 221 | 222 | if (need_login) { 223 | login = false; 224 | } else { 225 | login = true; 226 | } 227 | 228 | shell_uart = uart; 229 | 230 | /*!< I/O callback */ 231 | csh_init.sput = csh_sput_cb; 232 | csh_init.sget = csh_sget_cb; 233 | 234 | #if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB 235 | extern const int __fsymtab_start; 236 | extern const int __fsymtab_end; 237 | extern const int __vsymtab_start; 238 | extern const int __vsymtab_end; 239 | 240 | /*!< get table from ld symbol */ 241 | csh_init.command_table_beg = &__fsymtab_start; 242 | csh_init.command_table_end = &__fsymtab_end; 243 | csh_init.variable_table_beg = &__vsymtab_start; 244 | csh_init.variable_table_end = &__vsymtab_end; 245 | #endif 246 | 247 | #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT 248 | static char csh_prompt_buffer[128]; 249 | 250 | /*!< set prompt buffer */ 251 | csh_init.prompt_buffer = csh_prompt_buffer; 252 | csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer); 253 | #endif 254 | 255 | #if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY 256 | static char csh_history_buffer[128]; 257 | 258 | /*!< set history buffer */ 259 | csh_init.history_buffer = csh_history_buffer; 260 | csh_init.history_buffer_size = sizeof(csh_history_buffer); 261 | #endif 262 | 263 | #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC 264 | static char csh_line_buffer[128]; 265 | 266 | /*!< set linebuffer */ 267 | csh_init.line_buffer = csh_line_buffer; 268 | csh_init.line_buffer_size = sizeof(csh_line_buffer); 269 | #endif 270 | 271 | csh_init.uid = 0; 272 | csh_init.user[0] = "cherry"; 273 | 274 | /*!< The port hash function is required, 275 | and the strcmp attribute is used weakly by default, 276 | int chry_shell_port_hash_strcmp(const char *hash, const char *str); */ 277 | csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */ 278 | csh_init.host = BOARD_NAME; 279 | csh_init.user_data = NULL; 280 | 281 | int ret = chry_shell_init(&csh, &csh_init); 282 | if (ret) { 283 | return -1; 284 | } 285 | 286 | task_hdl_exec = NULL; 287 | event_hdl = xEventGroupCreateStatic(&event_grp); 288 | task_hdl_repl = xTaskCreateStatic(task_repl, "task_repl", 1024U, NULL, task_repl_PRIORITY, task_stack_repl, &task_buffer_repl); 289 | 290 | return 0; 291 | } 292 | 293 | void shell_lock(void) 294 | { 295 | xEventGroupSetBits(event_hdl, 0x01); 296 | xEventGroupWaitBits(event_hdl, 0x02, pdTRUE, pdTRUE, portMAX_DELAY); 297 | } 298 | 299 | void shell_unlock(void) 300 | { 301 | xEventGroupSetBits(event_hdl, 0x04); 302 | xEventGroupWaitBits(event_hdl, 0x08, pdTRUE, pdTRUE, portMAX_DELAY); 303 | } 304 | 305 | static int csh_exit(int argc, char **argv) 306 | { 307 | (void)argc; 308 | (void)argv; 309 | login = false; 310 | 311 | return 0; 312 | } 313 | CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, ); 314 | 315 | #define __ENV_PATH "/sbin:/bin" 316 | const char ENV_PATH[] = __ENV_PATH; 317 | CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH)); 318 | 319 | #define __ENV_ZERO "" 320 | const char ENV_ZERO[] = __ENV_ZERO; 321 | CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO)); 322 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 HPMicro 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.13) 5 | 6 | set(CONFIG_CHERRYRB 1) 7 | set(CONFIG_FREERTOS 1) 8 | set(CONFIG_CHERRYUSB 1) 9 | set(CONFIG_USB_DEVICE 1) 10 | set(CONFIG_USB_DEVICE_CDC 1) 11 | 12 | find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) 13 | project(cherryshell) 14 | 15 | sdk_compile_options("-O2") 16 | sdk_compile_definitions(-D__freertos_irq_stack_top=_stack) 17 | sdk_compile_definitions(-DCONFIG_FREERTOS=1) 18 | sdk_compile_definitions(-DUSE_NONVECTOR_MODE=1) 19 | sdk_compile_definitions(-DDISABLE_IRQ_PREEMPTIVE=1) 20 | 21 | sdk_inc(inc) 22 | sdk_inc(../../../) 23 | 24 | sdk_app_src( 25 | src/main.c 26 | src/shell.c 27 | ../../../cherryrl/chry_readline.c 28 | ../../../chry_shell.c 29 | ../../../builtin/help.c 30 | ../../../builtin/shsize.c 31 | ../../../builtin/login.c 32 | ) 33 | 34 | generate_ses_project() 35 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/README_en.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell FreeRTOS USB 2 | 3 | ## Overview 4 | 5 | The Cherry Shell FreeRTOS example project demonstrates the basic usage of shell in multi-thread mode. In this project, you need to connect via USB PORT, and the shell requires a login. The default password is 12345678. After entering the password and pressing Enter, you will enter the shell. You can use the "help" command to view the available commands and variables. 6 | 7 | Please refrain from using USB PORT assistants and consider downloading and using [MobaXterm](https://mobaxterm.mobatek.net/download.html) 8 | 9 | ## Board Setting 10 | 11 | No special settings 12 | 13 | ## Running the example 14 | 15 | - After the project runs successfully, the serial terminal will output the following information: 16 | 17 | ```console 18 | login as: cherry 19 | cherry@hpm5301evklite's password: 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | other task interval 5S 25 | 26 | ``` 27 | 28 | - If you manually enter the correct password "12345678" and press Enter, the terminal will output the following information: 29 | 30 | ```console 31 | login as: cherry 32 | cherry@hpm5301evklite's password: 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | other task interval 5S 38 | 39 | welcome to cherry shell 40 | cherry@hpm5301evklite:/$ 41 | ``` 42 | 43 | - If you manually enter the command "help" and press Enter, the terminal will output the following information: 44 | 45 | ```console 46 | cherry@hpm5301evklite:/$ help 47 | total function 6 48 | test -> /bin 49 | toggle_led -> /bin 50 | write_led -> /bin 51 | exit -> /sbin 52 | help -> /sbin 53 | shsize -> /sbin 54 | 55 | total variable 2 56 | $PATH r- 11 57 | $ZERO r- 1 58 | cherry@hpm5301evklite:/$ 59 | ``` 60 | 61 | - If you manually enter the command "toggle_led" and press Enter, the LED will toggle. 62 | - If you manually enter the command "write_led 1" and press Enter, the LED will turn on. 63 | - If you manually enter the command "write_led 0" and press Enter, the LED will turn off. 64 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/README_zh.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell FreeRTOS USB 2 | 3 | ## 概述 4 | 5 | Cherry Shell FreeRTOS示例工程展示了shell的多线程模式基本使用。多线程模式下,命令的执行在独立的线程中,可以使用Ctrl+C中断命令执行。在这个工程中,需要连接 USB,shell默认需要登陆,密码为12345678。输入密码后回车,进入shell,输入help可以查看命令和变量。 6 | 请勿使用串口助手,推荐下载使用 [MobaXterm](https://mobaxterm.mobatek.net/download.html) 7 | 8 | ## 硬件设置 9 | 10 | 无特殊设置 11 | 12 | ## 运行现象 13 | 14 | - 当工程正确运行后,串口终端会输出如下信息: 15 | 16 | ```console 17 | login as: cherry 18 | cherry@hpm5301evklite's password: 19 | other task interval 5S 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | 25 | ``` 26 | 27 | - 如果此时通过键盘手动输入正确密码"12345678"并回车,终端会输出如下信息: 28 | 29 | ```console 30 | login as: cherry 31 | cherry@hpm5301evklite's password: 32 | other task interval 5S 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | 38 | welcome to cherry shell 39 | cherry@hpm5301evklite:/$ 40 | ``` 41 | 42 | - 如果此时通过键盘手动输入命令"help"并回车,终端会输出如下信息: 43 | 44 | ```console 45 | cherry@hpm5301evklite:/$ help 46 | total function 6 47 | test -> /bin 48 | toggle_led -> /bin 49 | write_led -> /bin 50 | exit -> /sbin 51 | help -> /sbin 52 | shsize -> /sbin 53 | 54 | total variable 2 55 | $PATH r- 11 56 | $ZERO r- 1 57 | cherry@hpm5301evklite:/$ 58 | ``` 59 | 60 | - 如果此时通过键盘手动输入命令"toggle_led"并回车,LED将会翻转 61 | - 如果此时通过键盘手动输入命令"write_led 1"并回车,LED将会点亮 62 | - 如果此时通过键盘手动输入命令"write_led 0"并回车,LED将会熄灭 63 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/inc/FreeRTOSConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 HPMicro 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #ifndef FREERTOS_CONFIG_H 9 | #define FREERTOS_CONFIG_H 10 | 11 | /* 12 | * Application specific definitions. 13 | * 14 | * These definitions should be adjusted for your particular hardware and 15 | * application requirements. 16 | * 17 | * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE 18 | * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 19 | * 20 | * See http://www.freertos.org/a00110.html. 21 | */ 22 | 23 | #include "board.h" 24 | 25 | #if (portasmHAS_MTIME == 0) 26 | #define configMTIME_BASE_ADDRESS (0) 27 | #define configMTIMECMP_BASE_ADDRESS (0) 28 | #else 29 | #define configMTIME_BASE_ADDRESS (HPM_MCHTMR_BASE) 30 | #define configMTIMECMP_BASE_ADDRESS (HPM_MCHTMR_BASE + 8UL) 31 | #endif 32 | 33 | #define configUSE_PREEMPTION 1 34 | #define configCPU_CLOCK_HZ ((uint32_t) 24000000) 35 | #define configTICK_RATE_HZ ((TickType_t) 1000) 36 | #define configMAX_PRIORITIES (32) 37 | #define configMINIMAL_STACK_SIZE (256) 38 | #define configMAX_TASK_NAME_LEN 16 39 | #define configUSE_16_BIT_TICKS 0 40 | #define configIDLE_SHOULD_YIELD 0 41 | #define configUSE_APPLICATION_TASK_TAG 0 42 | #define configGENERATE_RUN_TIME_STATS 0 43 | 44 | /* Memory allocation definitions. */ 45 | #define configSUPPORT_STATIC_ALLOCATION 1 46 | #define configSUPPORT_DYNAMIC_ALLOCATION 1 47 | #define configTOTAL_HEAP_SIZE ((size_t) (8 * 1024)) 48 | 49 | /* Hook function definitions. */ 50 | #define configUSE_IDLE_HOOK 0 51 | #define configUSE_TICK_HOOK 0 52 | #define configCHECK_FOR_STACK_OVERFLOW 0 53 | #define configUSE_MALLOC_FAILED_HOOK 0 54 | #define configUSE_DAEMON_TASK_STARTUP_HOOK 0 55 | 56 | /* Run time and task stats gathering definitions. */ 57 | #define configGENERATE_RUN_TIME_STATS 0 58 | #define configUSE_TRACE_FACILITY 1 59 | #define configUSE_STATS_FORMATTING_FUNCTIONS 0 60 | 61 | /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ 62 | #define INCLUDE_vTaskPrioritySet 1 63 | #define INCLUDE_uxTaskPriorityGet 1 64 | #define INCLUDE_vTaskDelete 1 65 | #define INCLUDE_vTaskCleanUpResources 1 66 | #define INCLUDE_vTaskSuspend 1 67 | #define INCLUDE_vTaskDelayUntil 1 68 | #define INCLUDE_vTaskDelay 1 69 | #define INCLUDE_xTaskGetCurrentTaskHandle 1 70 | #define INCLUDE_xTimerPendFunctionCall 1 71 | #define INCLUDE_eTaskGetState 1 72 | #define INCLUDE_xTaskAbortDelay 1 73 | #define INCLUDE_xTaskGetHandle 1 74 | #define INCLUDE_xSemaphoreGetMutexHolder 1 75 | 76 | /* Co-routine definitions. */ 77 | #define configUSE_CO_ROUTINES 0 78 | #define configMAX_CO_ROUTINE_PRIORITIES 2 79 | 80 | /* Software timer definitions. */ 81 | #define configUSE_TIMERS 1 82 | #define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) 83 | #define configTIMER_QUEUE_LENGTH 4 84 | #define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE) 85 | 86 | /* Task priorities.*/ 87 | #ifndef uartPRIMARY_PRIORITY 88 | #define uartPRIMARY_PRIORITY (configMAX_PRIORITIES - 3) 89 | #endif 90 | 91 | /* Normal assert() semantics without relying on the provision of an assert.h header file. */ 92 | #define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); __asm volatile("ebreak"); for (;;); } 93 | 94 | /* 95 | * The size of the global output buffer that is available for use when there 96 | * are multiple command interpreters running at once (for example, one on a UART 97 | * and one on TCP/IP). This is done to prevent an output buffer being defined by 98 | * each implementation - which would waste RAM. In this case, there is only one 99 | * command interpreter running. 100 | */ 101 | 102 | /* 103 | * The buffer into which output generated by FreeRTOS+CLI is placed. This must 104 | * be at least big enough to contain the output of the task-stats command, as the 105 | * example implementation does not include buffer overlow checking. 106 | */ 107 | #define configCOMMAND_INT_MAX_OUTPUT_SIZE 2096 108 | #define configINCLUDE_QUERY_HEAP_COMMAND 1 109 | 110 | /* This file is included from assembler files - make sure C code is not included in assembler files. */ 111 | #ifndef __ASSEMBLER__ 112 | void vAssertCalled(const char *pcFile, unsigned long ulLine); 113 | void vConfigureTickInterrupt(void); 114 | void vClearTickInterrupt(void); 115 | void vPreSleepProcessing(unsigned long uxExpectedIdleTime); 116 | void vPostSleepProcessing(unsigned long uxExpectedIdleTime); 117 | #endif /* __ASSEMBLER__ */ 118 | 119 | /****** Hardware/compiler specific settings. *******/ 120 | /* 121 | * The application must provide a function that configures a peripheral to 122 | * create the FreeRTOS tick interrupt, then define configSETUP_TICK_INTERRUPT() 123 | * in FreeRTOSConfig.h to call the function. 124 | */ 125 | #define configSETUP_TICK_INTERRUPT() vConfigureTickInterrupt() 126 | #define configCLEAR_TICK_INTERRUPT() vClearTickInterrupt() 127 | 128 | /* 129 | * The configPRE_SLEEP_PROCESSING() and configPOST_SLEEP_PROCESSING() macros 130 | * allow the application writer to add additional code before and after the MCU is 131 | * placed into the low power state respectively. The empty implementations 132 | * provided in this demo can be extended to save even more power. 133 | */ 134 | #define configPRE_SLEEP_PROCESSING(uxExpectedIdleTime) vPreSleepProcessing(uxExpectedIdleTime); 135 | #define configPOST_SLEEP_PROCESSING(uxExpectedIdleTime) vPostSleepProcessing(uxExpectedIdleTime); 136 | 137 | 138 | /* Compiler specifics. */ 139 | #define fabs(x) __builtin_fabs(x) 140 | 141 | /* Enable Hardware Stack Protection and Recording mechanism. */ 142 | #define configHSP_ENABLE 0 143 | 144 | /* Record the highest address of stack. */ 145 | #if (configHSP_ENABLE == 1 && configRECORD_STACK_HIGH_ADDRESS != 1) 146 | #define configRECORD_STACK_HIGH_ADDRESS 1 147 | #endif 148 | 149 | #endif /* FREERTOS_CONFIG_H */ 150 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/inc/csh_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CSH_CONFIG_H 8 | #define CSH_CONFIG_H 9 | 10 | /*!< argument check */ 11 | #define CONFIG_CSH_DEBUG 0 12 | 13 | /*!< default row */ 14 | #define CONFIG_CSH_DFTROW 25 15 | 16 | /*!< default column */ 17 | #define CONFIG_CSH_DFTCOL 80 18 | 19 | /*!< history support <+550byte> */ 20 | #define CONFIG_CSH_HISTORY 1 21 | 22 | /*!< completion support <+1100byte> */ 23 | #define CONFIG_CSH_COMPLETION 1 24 | 25 | /*!< max completion item list count (use stack 4 x count byte) */ 26 | #define CONFIG_CSH_MAX_COMPLETION 40 27 | 28 | /*!< prompt edit support <+1000byte> */ 29 | #define CONFIG_CSH_PROMPTEDIT 1 30 | 31 | /*!< prompt segment count */ 32 | #define CONFIG_CSH_PROMPTSEG 7 33 | 34 | /*!< xterm support */ 35 | #define CONFIG_CSH_XTERM 0 36 | 37 | /*!< newline */ 38 | #define CONFIG_CSH_NEWLINE "\r\n" 39 | 40 | /*!< tab space count */ 41 | #define CONFIG_CSH_SPACE 4 42 | 43 | /*!< independent ctrl map */ 44 | #define CONFIG_CSH_CTRLMAP 0 45 | 46 | /*!< independent alt map */ 47 | #define CONFIG_CSH_ALTMAP 0 48 | 49 | /*!< refresh prompt */ 50 | #define CONFIG_CSH_REFRESH_PROMPT 1 51 | 52 | /*!< no waiting for sget */ 53 | #define CONFIG_CSH_NOBLOCK 1 54 | 55 | /*!< help information */ 56 | #define CONFIG_CSH_HELP "" 57 | 58 | /*!< path length 0:const path, <=255:variable path */ 59 | #define CONFIG_CSH_MAXLEN_PATH 128 60 | 61 | /*!< path segment count */ 62 | #define CONFIG_CSH_MAXSEG_PATH 16 63 | 64 | /*!< user count */ 65 | #define CONFIG_CSH_MAX_USER 1 66 | 67 | /*!< max argument count */ 68 | #define CONFIG_CSH_MAX_ARG 8 69 | 70 | /*!< linebuffer static or on stack */ 71 | #define CONFIG_CSH_LNBUFF_STATIC 1 72 | 73 | /*!< linebuffer size (valid only if lnbuff on stack) */ 74 | #define CONFIG_CSH_LNBUFF_SIZE 256 75 | 76 | /*!< multi-thread mode */ 77 | #define CONFIG_CSH_MULTI_THREAD 1 78 | 79 | /*!< independent signal handler (for multi instances) */ 80 | #define CONFIG_CSH_SIGNAL_HANDLER 0 81 | 82 | /*!< Ctrl+c/d/q/s/z/\ F1-F12 UE <+120byte> */ 83 | #define CONFIG_CSH_USER_CALLBACK 1 84 | 85 | /*!< enable macro export symbol table */ 86 | #define CONFIG_CSH_SYMTAB 1 87 | 88 | /*!< print buffer size */ 89 | #define CONFIG_CSH_PRINT_BUFFER_SIZE 512 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/inc/shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef SHELL_H 8 | #define SHELL_H 9 | 10 | #include "csh.h" 11 | 12 | extern int shell_init(uint8_t busid, uint32_t regbase, bool need_login); 13 | extern void shell_lock(void); 14 | extern void shell_unlock(void); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/inc/usb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, sakumisu 3 | * Copyright (c) 2022-2024, HPMicro 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | #ifndef CHERRYUSB_CONFIG_H 8 | #define CHERRYUSB_CONFIG_H 9 | 10 | #include "hpm_soc_feature.h" 11 | 12 | #define CHERRYUSB_VERSION 0x010200 13 | #define CHERRYUSB_VERSION_STR "v1.2.0" 14 | 15 | /* ================ USB common Configuration ================ */ 16 | 17 | #define CONFIG_USB_PRINTF(...) printf(__VA_ARGS__) 18 | 19 | #define usb_malloc(size) malloc(size) 20 | #define usb_free(ptr) free(ptr) 21 | 22 | #ifndef CONFIG_USB_DBG_LEVEL 23 | #define CONFIG_USB_DBG_LEVEL USB_DBG_INFO 24 | #endif 25 | 26 | #ifdef CONFIG_USB_DEVICE_FS 27 | #undef CONFIG_USB_HS 28 | #else 29 | #define CONFIG_USB_HS 30 | #endif 31 | 32 | /* Enable print with color */ 33 | #define CONFIG_USB_PRINTF_COLOR_ENABLE 34 | 35 | /* data align size when use dma */ 36 | #ifndef CONFIG_USB_ALIGN_SIZE 37 | #define CONFIG_USB_ALIGN_SIZE 4 38 | #endif 39 | 40 | /* descriptor common define */ 41 | #define USBD_VID 0x34B7 /* Hpmicro vid */ 42 | #define USBD_PID 0xFFFF 43 | #define USBD_MAX_POWER 200 44 | #define USBD_LANGID_STRING 1033 45 | 46 | /* attribute data into no cache ram */ 47 | #define USB_NOCACHE_RAM_SECTION __attribute__((section(".noncacheable"))) 48 | 49 | /* ================= USB Device Stack Configuration ================ */ 50 | 51 | #define CONFIG_USBDEV_MAX_BUS USB_SOC_MAX_COUNT 52 | 53 | /* Ep0 max transfer buffer, specially for receiving data from ep0 out */ 54 | #define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512 55 | 56 | /* Setup packet log for debug */ 57 | /* #define CONFIG_USBDEV_SETUP_LOG_PRINT */ 58 | 59 | /* Check if the input descriptor is correct */ 60 | /* #define CONFIG_USBDEV_DESC_CHECK */ 61 | 62 | /* Enable test mode */ 63 | #define CONFIG_USBDEV_TEST_MODE 64 | 65 | #ifndef CONFIG_USBDEV_MSC_MAX_LUN 66 | #define CONFIG_USBDEV_MSC_MAX_LUN 1 67 | #endif 68 | 69 | #ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE 70 | #define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512 71 | #endif 72 | 73 | #ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING 74 | #define CONFIG_USBDEV_MSC_MANUFACTURER_STRING "" 75 | #endif 76 | 77 | #ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING 78 | #define CONFIG_USBDEV_MSC_PRODUCT_STRING "" 79 | #endif 80 | 81 | #ifndef CONFIG_USBDEV_MSC_VERSION_STRING 82 | #define CONFIG_USBDEV_MSC_VERSION_STRING "0.01" 83 | #endif 84 | 85 | /* #define CONFIG_USBDEV_MSC_THREAD */ 86 | 87 | #ifndef CONFIG_USBDEV_MSC_PRIO 88 | #define CONFIG_USBDEV_MSC_PRIO 4 89 | #endif 90 | 91 | #ifndef CONFIG_USBDEV_MSC_STACKSIZE 92 | #define CONFIG_USBDEV_MSC_STACKSIZE 2048 93 | #endif 94 | 95 | #ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 96 | #define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156 97 | #endif 98 | 99 | #ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 100 | #define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1536 101 | #endif 102 | 103 | #ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID 104 | #define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff 105 | #endif 106 | 107 | #ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC 108 | #define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB" 109 | #endif 110 | 111 | #define CONFIG_USBDEV_RNDIS_USING_LWIP 112 | 113 | /* ================ USB HOST Stack Configuration ================== */ 114 | 115 | #define CONFIG_USBHOST_MAX_BUS USB_SOC_MAX_COUNT 116 | #define CONFIG_USBHOST_MAX_RHPORTS 1 117 | #define CONFIG_USBHOST_MAX_EXTHUBS 1 118 | #define CONFIG_USBHOST_MAX_EHPORTS 4 119 | #define CONFIG_USBHOST_MAX_INTERFACES 8 120 | #define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 2 121 | #define CONFIG_USBHOST_MAX_ENDPOINTS 8 122 | 123 | #define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4 124 | #define CONFIG_USBHOST_MAX_HID_CLASS 4 125 | #define CONFIG_USBHOST_MAX_MSC_CLASS 2 126 | #define CONFIG_USBHOST_MAX_AUDIO_CLASS 1 127 | #define CONFIG_USBHOST_MAX_VIDEO_CLASS 1 128 | 129 | #define CONFIG_USBHOST_DEV_NAMELEN 16 130 | 131 | #ifndef CONFIG_USBHOST_PSC_PRIO 132 | #define CONFIG_USBHOST_PSC_PRIO 0 133 | #endif 134 | #ifndef CONFIG_USBHOST_PSC_STACKSIZE 135 | #define CONFIG_USBHOST_PSC_STACKSIZE 2048 136 | #endif 137 | 138 | /* #define CONFIG_USBHOST_GET_STRING_DESC */ 139 | 140 | /* #define CONFIG_USBHOST_MSOS_ENABLE */ 141 | #define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00 142 | 143 | /* Ep0 max transfer buffer */ 144 | #define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512 145 | 146 | #ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 147 | #define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500 148 | #endif 149 | 150 | #ifndef CONFIG_USBHOST_MSC_TIMEOUT 151 | #define CONFIG_USBHOST_MSC_TIMEOUT 5000 152 | #endif 153 | 154 | #define CONFIG_USBHOST_BLUETOOTH_HCI_H4 155 | /* #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG */ 156 | 157 | #ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE 158 | #define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048 159 | #endif 160 | #ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE 161 | #define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048 162 | #endif 163 | 164 | /* ================ USB Device Port Configuration ================*/ 165 | 166 | #ifndef CONFIG_USBDEV_EP_NUM 167 | #define CONFIG_USBDEV_EP_NUM USB_SOC_DCD_MAX_ENDPOINT_COUNT 168 | #endif 169 | 170 | #ifndef CONFIG_HPM_USBD_BASE 171 | #define CONFIG_HPM_USBD_BASE HPM_USB0_BASE 172 | #endif 173 | #ifndef CONFIG_HPM_USBD_IRQn 174 | #define CONFIG_HPM_USBD_IRQn IRQn_USB0 175 | #endif 176 | 177 | /* ================ USB Host Port Configuration ==================*/ 178 | 179 | #define CONFIG_USBHOST_PIPE_NUM 5 180 | #define CONFIG_USB_EHCI_QTD_NUM 8 181 | 182 | #ifndef CONFIG_HPM_USBH_BASE 183 | #define CONFIG_HPM_USBH_BASE HPM_USB0_BASE 184 | #endif 185 | #ifndef CONFIG_HPM_USBH_IRQn 186 | #define CONFIG_HPM_USBH_IRQn IRQn_USB0 187 | #endif 188 | 189 | /* ================ EHCI Configuration ================ */ 190 | 191 | #define CONFIG_USB_EHCI_HPMICRO (1) 192 | #define CONFIG_USB_EHCI_HCCR_OFFSET (0x100u) 193 | #define CONFIG_USB_EHCI_HCOR_OFFSET (0x140u) 194 | #define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024 195 | /* #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE */ 196 | /* #define CONFIG_USB_EHCI_CONFIGFLAG */ 197 | #define CONFIG_USB_EHCI_PORT_POWER 198 | /* #define CONFIG_USB_EHCI_PRINT_HW_PARAM */ 199 | 200 | #endif 201 | -------------------------------------------------------------------------------- /samples/hpm/freertos_usb/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 HPMicro 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | /* FreeRTOS kernel includes. */ 9 | #include "FreeRTOS.h" 10 | #include "task.h" 11 | 12 | /* HPM example includes. */ 13 | #include 14 | #include "board.h" 15 | #include "hpm_clock_drv.h" 16 | #include "shell.h" 17 | #include "usbd_core.h" 18 | 19 | #define task_other_PRIORITY (configMAX_PRIORITIES - 3U) 20 | #define task_start_PRIORITY (configMAX_PRIORITIES - 2U) 21 | 22 | static void task_start(void *param); 23 | 24 | int main(void) 25 | { 26 | board_init(); 27 | board_init_led_pins(); 28 | 29 | if (pdPASS != xTaskCreate(task_start, "task_start", 1024U, NULL, task_start_PRIORITY, NULL)) 30 | { 31 | printf("Task start creation failed!\r\n"); 32 | for (;;) 33 | { 34 | ; 35 | } 36 | } 37 | 38 | vTaskStartScheduler(); 39 | printf("Unexpected scheduler exit!\r\n"); 40 | for (;;) 41 | { 42 | ; 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | static void task_start(void *param) 49 | { 50 | (void)param; 51 | 52 | board_init_usb_pins(); 53 | intc_set_irq_priority(CONFIG_HPM_USBD_IRQn, 2); 54 | 55 | /* default password is : 12345678 */ 56 | /* shell_init() must be called in-task */ 57 | if (0 != shell_init(0, CONFIG_HPM_USBD_BASE, true)) 58 | { 59 | /* shell failed to be initialized */ 60 | printf("Failed to initialize shell\r\n"); 61 | for (;;) 62 | { 63 | ; 64 | } 65 | } 66 | 67 | printf("Initialize shell successfully\r\n"); 68 | 69 | printf("Exit start task\r\n"); 70 | vTaskDelete(NULL); 71 | } 72 | 73 | 74 | static int test(int argc, char **argv) 75 | { 76 | chry_shell_t *csh = (void *)argv[argc + 1]; 77 | csh_printf(csh, "test: \r\n"); 78 | csh_printf(csh, "argc=<%d>\r\n", argc); 79 | for (uint8_t i = 0; i < argc; i++) 80 | { 81 | csh_printf(csh, "argv[%d]:0x%08x=<%s>\r\n", i, (uintptr_t)argv[i], argv[i]); 82 | } 83 | 84 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n", argc, argv[argc]); 85 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n\r\n", argc + 1, argv[argc + 1]); 86 | 87 | return 0; 88 | } 89 | CSH_CMD_EXPORT(test, ); 90 | 91 | static int toggle_led(int argc, char **argv) 92 | { 93 | (void)argc; 94 | (void)argv; 95 | board_led_toggle(); 96 | return 0; 97 | } 98 | CSH_CMD_EXPORT(toggle_led, ); 99 | 100 | static int write_led(int argc, char **argv) 101 | { 102 | chry_shell_t *csh = (void *)argv[argc + 1]; 103 | if (argc < 2) 104 | { 105 | csh_printf(csh, "usage: write_led \r\n\r\n"); 106 | csh_printf(csh, " status 0 or 1\r\n\r\n"); 107 | return -1; 108 | } 109 | 110 | board_led_write(!board_get_led_gpio_off_level() ^ (atoi(argv[1]) == 0)); 111 | return 0; 112 | } 113 | CSH_CMD_EXPORT(write_led, ); 114 | -------------------------------------------------------------------------------- /samples/hpm/threadx_uart/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021 HPMicro 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.13) 5 | 6 | set(CONFIG_CHERRYRB 1) 7 | set(CONFIG_ECLIPSE_THREADX 1) 8 | 9 | find_package(hpm-sdk REQUIRED HINTS $ENV{HPM_SDK_BASE}) 10 | project(cherryshell) 11 | 12 | sdk_compile_options("-O2") 13 | sdk_compile_definitions(-D__threadx_irq_stack_top=_stack) 14 | sdk_compile_definitions(-DCONFIG_ECLIPSE_THREADX=1) 15 | 16 | sdk_inc(inc) 17 | sdk_inc(../../../) 18 | 19 | sdk_app_src( 20 | src/main.c 21 | src/shell.c 22 | ../../../cherryrl/chry_readline.c 23 | ../../../chry_shell.c 24 | ../../../builtin/help.c 25 | ../../../builtin/shsize.c 26 | ../../../builtin/login.c 27 | ) 28 | 29 | generate_ses_project() -------------------------------------------------------------------------------- /samples/hpm/threadx_uart/README_en.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell FreeRTOS UART 2 | 3 | ## Overview 4 | 5 | The Cherry Shell FreeRTOS example project demonstrates the basic usage of shell in multi-thread mode. In this project, you need to connect via serial port, and the shell requires a login. The default password is 12345678. After entering the password and pressing Enter, you will enter the shell. You can use the "help" command to view the available commands and variables. 6 | 7 | Please refrain from using serial port assistants and consider downloading and using [MobaXterm](https://mobaxterm.mobatek.net/download.html) 8 | 9 | ## Board Setting 10 | 11 | No special settings 12 | 13 | ## Running the example 14 | 15 | - After the project runs successfully, the serial terminal will output the following information: 16 | 17 | ```console 18 | login as: cherry 19 | cherry@hpm5301evklite's password: 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | other task interval 5S 25 | 26 | ``` 27 | 28 | - If you manually enter the correct password "12345678" and press Enter, the terminal will output the following information: 29 | 30 | ```console 31 | login as: cherry 32 | cherry@hpm5301evklite's password: 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | other task interval 5S 38 | 39 | welcome to cherry shell 40 | cherry@hpm5301evklite:/$ 41 | ``` 42 | 43 | - If you manually enter the command "help" and press Enter, the terminal will output the following information: 44 | 45 | ```console 46 | cherry@hpm5301evklite:/$ help 47 | total function 6 48 | test -> /bin 49 | toggle_led -> /bin 50 | write_led -> /bin 51 | exit -> /sbin 52 | help -> /sbin 53 | shsize -> /sbin 54 | 55 | total variable 2 56 | $PATH r- 11 57 | $ZERO r- 1 58 | cherry@hpm5301evklite:/$ 59 | ``` 60 | 61 | - If you manually enter the command "toggle_led" and press Enter, the LED will toggle. 62 | - If you manually enter the command "write_led 1" and press Enter, the LED will turn on. 63 | - If you manually enter the command "write_led 0" and press Enter, the LED will turn off. 64 | -------------------------------------------------------------------------------- /samples/hpm/threadx_uart/README_zh.md: -------------------------------------------------------------------------------- 1 | # Cherry Shell FreeRTOS UART 2 | 3 | ## 概述 4 | 5 | Cherry Shell FreeRTOS示例工程展示了shell的多线程模式基本使用。多线程模式下,命令的执行在独立的线程中,可以使用Ctrl+C中断命令执行。在这个工程中,需要连接串口,shell默认需要登陆,密码为12345678。输入密码后回车,进入shell,输入help可以查看命令和变量。 6 | 请勿使用串口助手,推荐下载使用 [MobaXterm](https://mobaxterm.mobatek.net/download.html) 7 | 8 | ## 硬件设置 9 | 10 | 无特殊设置 11 | 12 | ## 运行现象 13 | 14 | - 当工程正确运行后,串口终端会输出如下信息: 15 | 16 | ```console 17 | login as: cherry 18 | cherry@hpm5301evklite's password: 19 | other task interval 5S 20 | other task interval 5S 21 | other task interval 5S 22 | other task interval 5S 23 | other task interval 5S 24 | 25 | ``` 26 | 27 | - 如果此时通过键盘手动输入正确密码"12345678"并回车,终端会输出如下信息: 28 | 29 | ```console 30 | login as: cherry 31 | cherry@hpm5301evklite's password: 32 | other task interval 5S 33 | other task interval 5S 34 | other task interval 5S 35 | other task interval 5S 36 | other task interval 5S 37 | 38 | welcome to cherry shell 39 | cherry@hpm5301evklite:/$ 40 | ``` 41 | 42 | - 如果此时通过键盘手动输入命令"help"并回车,终端会输出如下信息: 43 | 44 | ```console 45 | cherry@hpm5301evklite:/$ help 46 | total function 6 47 | test -> /bin 48 | toggle_led -> /bin 49 | write_led -> /bin 50 | exit -> /sbin 51 | help -> /sbin 52 | shsize -> /sbin 53 | 54 | total variable 2 55 | $PATH r- 11 56 | $ZERO r- 1 57 | cherry@hpm5301evklite:/$ 58 | ``` 59 | 60 | - 如果此时通过键盘手动输入命令"toggle_led"并回车,LED将会翻转 61 | - 如果此时通过键盘手动输入命令"write_led 1"并回车,LED将会点亮 62 | - 如果此时通过键盘手动输入命令"write_led 0"并回车,LED将会熄灭 63 | -------------------------------------------------------------------------------- /samples/hpm/threadx_uart/inc/csh_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef CSH_CONFIG_H 8 | #define CSH_CONFIG_H 9 | 10 | /*!< argument check */ 11 | #define CONFIG_CSH_DEBUG 0 12 | 13 | /*!< default row */ 14 | #define CONFIG_CSH_DFTROW 25 15 | 16 | /*!< default column */ 17 | #define CONFIG_CSH_DFTCOL 80 18 | 19 | /*!< history support <+550byte> */ 20 | #define CONFIG_CSH_HISTORY 1 21 | 22 | /*!< completion support <+1100byte> */ 23 | #define CONFIG_CSH_COMPLETION 1 24 | 25 | /*!< max completion item list count (use stack 4 x count byte) */ 26 | #define CONFIG_CSH_MAX_COMPLETION 40 27 | 28 | /*!< prompt edit support <+1000byte> */ 29 | #define CONFIG_CSH_PROMPTEDIT 1 30 | 31 | /*!< prompt segment count */ 32 | #define CONFIG_CSH_PROMPTSEG 7 33 | 34 | /*!< xterm support */ 35 | #define CONFIG_CSH_XTERM 0 36 | 37 | /*!< newline */ 38 | #define CONFIG_CSH_NEWLINE "\r\n" 39 | 40 | /*!< tab space count */ 41 | #define CONFIG_CSH_SPACE 4 42 | 43 | /*!< independent ctrl map */ 44 | #define CONFIG_CSH_CTRLMAP 0 45 | 46 | /*!< independent alt map */ 47 | #define CONFIG_CSH_ALTMAP 0 48 | 49 | /*!< refresh prompt */ 50 | #define CONFIG_CSH_REFRESH_PROMPT 1 51 | 52 | /*!< no waiting for sget */ 53 | #define CONFIG_CSH_NOBLOCK 1 54 | 55 | /*!< help information */ 56 | #define CONFIG_CSH_HELP "" 57 | 58 | /*!< path length 0:const path, <=255:variable path */ 59 | #define CONFIG_CSH_MAXLEN_PATH 128 60 | 61 | /*!< path segment count */ 62 | #define CONFIG_CSH_MAXSEG_PATH 16 63 | 64 | /*!< user count */ 65 | #define CONFIG_CSH_MAX_USER 1 66 | 67 | /*!< max argument count */ 68 | #define CONFIG_CSH_MAX_ARG 8 69 | 70 | /*!< linebuffer static or on stack */ 71 | #define CONFIG_CSH_LNBUFF_STATIC 1 72 | 73 | /*!< linebuffer size (valid only if lnbuff on stack) */ 74 | #define CONFIG_CSH_LNBUFF_SIZE 256 75 | 76 | /*!< multi-thread mode */ 77 | #define CONFIG_CSH_MULTI_THREAD 1 78 | 79 | /*!< independent signal handler (for multi instances) */ 80 | #define CONFIG_CSH_SIGNAL_HANDLER 0 81 | 82 | /*!< Ctrl+c/d/q/s/z/\ F1-F12 UE <+120byte> */ 83 | #define CONFIG_CSH_USER_CALLBACK 1 84 | 85 | /*!< enable macro export symbol table */ 86 | #define CONFIG_CSH_SYMTAB 1 87 | 88 | /*!< print buffer size */ 89 | #define CONFIG_CSH_PRINT_BUFFER_SIZE 512 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /samples/hpm/threadx_uart/inc/shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Egahp 3 | * 4 | * SPDX-License-Identifier: Apache-2.0 5 | */ 6 | 7 | #ifndef SHELL_H 8 | #define SHELL_H 9 | 10 | #include "hpm_uart_drv.h" 11 | #include "csh.h" 12 | 13 | extern int shell_init(UART_Type *uart, bool need_login); 14 | extern void shell_uart_isr(void); 15 | extern void shell_lock(void); 16 | extern void shell_unlock(void); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /samples/hpm/threadx_uart/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 HPMicro 3 | * 4 | * SPDX-License-Identifier: BSD-3-Clause 5 | * 6 | */ 7 | 8 | #include "tx_api.h" 9 | 10 | /* HPM example includes. */ 11 | #include 12 | #include "board.h" 13 | #include "hpm_clock_drv.h" 14 | #include "shell.h" 15 | 16 | SDK_DECLARE_EXT_ISR_M(BOARD_CONSOLE_UART_IRQ, shell_uart_isr) 17 | 18 | #define THERAD_OTHER_PRIORITY (TX_MAX_PRIORITIES - 6U) 19 | 20 | static TX_THREAD thread_other_hdl; 21 | static uint32_t thread_stack_other[1024]; 22 | 23 | int main(void) 24 | { 25 | board_init(); 26 | board_init_led_pins(); 27 | 28 | tx_kernel_enter(); 29 | 30 | printf("Unexpected scheduler exit!\r\n"); 31 | for (;;) 32 | { 33 | ; 34 | } 35 | 36 | return 0; 37 | } 38 | 39 | static void thread_other(ULONG param) 40 | { 41 | (void)param; 42 | for (;;) 43 | { 44 | shell_lock(); 45 | printf("other task interval 5S\r\n"); 46 | shell_unlock(); 47 | tx_thread_sleep(5000); 48 | } 49 | } 50 | 51 | void tx_application_define(void *first_unused_memory) 52 | { 53 | (void)first_unused_memory; 54 | 55 | printf("Try to initialize the uart\r\n" 56 | " if you are using the console uart as the shell uart\r\n" 57 | " failure to initialize may result in no log\r\n"); 58 | 59 | uart_config_t shell_uart_config = {0}; 60 | uart_default_config(BOARD_CONSOLE_UART_BASE, &shell_uart_config); 61 | shell_uart_config.src_freq_in_hz = clock_get_frequency(BOARD_CONSOLE_UART_CLK_NAME); 62 | shell_uart_config.baudrate = 115200; 63 | 64 | if (status_success != uart_init(BOARD_CONSOLE_UART_BASE, &shell_uart_config)) 65 | { 66 | /* uart failed to be initialized */ 67 | printf("Failed to initialize uart\r\n"); 68 | for (;;) 69 | { 70 | ; 71 | } 72 | } 73 | 74 | printf("Initialize shell uart successfully\r\n"); 75 | 76 | /* default password is : 12345678 */ 77 | /* shell_init() must be called in-task */ 78 | if (0 != shell_init(BOARD_CONSOLE_UART_BASE, false)) 79 | { 80 | /* shell failed to be initialized */ 81 | printf("Failed to initialize shell\r\n"); 82 | for (;;) 83 | { 84 | ; 85 | } 86 | } 87 | 88 | printf("Initialize shell successfully\r\n"); 89 | 90 | /* irq must be enabled after shell_init() */ 91 | uart_enable_irq(BOARD_CONSOLE_UART_BASE, uart_intr_rx_data_avail_or_timeout); 92 | intc_m_enable_irq_with_priority(BOARD_CONSOLE_UART_IRQ, 1); 93 | 94 | printf("Enable shell uart interrupt\r\n"); 95 | 96 | if (TX_SUCCESS != tx_thread_create( 97 | &thread_other_hdl, 98 | "other", 99 | thread_other, 100 | 0, /* param */ 101 | thread_stack_other, 102 | sizeof(thread_stack_other), 103 | THERAD_OTHER_PRIORITY, 104 | THERAD_OTHER_PRIORITY, 105 | TX_NO_TIME_SLICE, 106 | TX_AUTO_START)) 107 | { 108 | printf("Thread other creation failed!\r\n"); 109 | for (;;) 110 | { 111 | ; 112 | } 113 | } 114 | 115 | printf("Exit tx_application_define\r\n"); 116 | } 117 | 118 | static int test(int argc, char **argv) 119 | { 120 | chry_shell_t *csh = (void *)argv[argc + 1]; 121 | csh_printf(csh, "test: \r\n"); 122 | csh_printf(csh, "argc=<%d>\r\n", argc); 123 | for (uint8_t i = 0; i < argc; i++) 124 | { 125 | csh_printf(csh, "argv[%d]:0x%08x=<%s>\r\n", i, (uintptr_t)argv[i], argv[i]); 126 | } 127 | 128 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n", argc, argv[argc]); 129 | csh_printf(csh, "argv[%d]=<0x%08x>\r\n\r\n", argc + 1, argv[argc + 1]); 130 | 131 | return 0; 132 | } 133 | CSH_CMD_EXPORT(test, ); 134 | 135 | static int toggle_led(int argc, char **argv) 136 | { 137 | (void)argc; 138 | (void)argv; 139 | board_led_toggle(); 140 | return 0; 141 | } 142 | CSH_CMD_EXPORT(toggle_led, ); 143 | 144 | static int write_led(int argc, char **argv) 145 | { 146 | chry_shell_t *csh = (void *)argv[argc + 1]; 147 | if (argc < 2) 148 | { 149 | csh_printf(csh, "usage: write_led \r\n\r\n"); 150 | csh_printf(csh, " status 0 or 1\r\n\r\n"); 151 | return -1; 152 | } 153 | 154 | board_led_write(!board_get_led_gpio_off_level() ^ (atoi(argv[1]) == 0)); 155 | return 0; 156 | } 157 | CSH_CMD_EXPORT(write_led, ); 158 | -------------------------------------------------------------------------------- /samples/hpm/threadx_uart/src/shell.c: -------------------------------------------------------------------------------- 1 | #include "tx_api.h" 2 | #include 3 | #include 4 | #include "board.h" 5 | #include "hpm_uart_drv.h" 6 | #include "chry_ringbuffer.h" 7 | #include "csh.h" 8 | 9 | #ifndef THREAD_REPL_PRIORITY 10 | #define THREAD_REPL_PRIORITY (TX_MAX_PRIORITIES - 5U) 11 | #endif 12 | 13 | #ifndef THREAD_EXEC_PRIORITY 14 | #define THREAD_EXEC_PRIORITY (TX_MAX_PRIORITIES - 4U) 15 | #endif 16 | 17 | static chry_shell_t csh; 18 | static UART_Type *shell_uart = NULL; 19 | static volatile bool login = false; 20 | static chry_ringbuffer_t shell_rb; 21 | static uint8_t mempool[1024]; 22 | 23 | static TX_THREAD thread_buffer_repl; 24 | static TX_THREAD thread_buffer_exec; 25 | static volatile bool thread_exec_created; 26 | 27 | static uint32_t thread_stack_repl[1024]; 28 | static uint32_t thread_stack_exec[1024]; 29 | 30 | static TX_EVENT_FLAGS_GROUP event_hdl; 31 | 32 | void shell_uart_isr(void) 33 | { 34 | uint8_t irq_id = uart_get_irq_id(shell_uart); 35 | 36 | if ((irq_id == uart_intr_id_rx_data_avail) || (irq_id == uart_intr_id_rx_timeout)) { 37 | while (uart_check_status(shell_uart, uart_stat_data_ready)) { 38 | uint8_t byte = uart_read_byte(shell_uart); 39 | chry_ringbuffer_write_byte(&shell_rb, byte); 40 | } 41 | 42 | tx_event_flags_set(&event_hdl, 0x10, TX_OR); 43 | } 44 | } 45 | 46 | static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size) 47 | { 48 | uint16_t i; 49 | (void)rl; 50 | for (i = 0; i < size; i++) { 51 | if (status_success != uart_send_byte(shell_uart, ((uint8_t *)data)[i])) { 52 | break; 53 | } 54 | } 55 | 56 | return i; 57 | } 58 | 59 | static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size) 60 | { 61 | (void)rl; 62 | return chry_ringbuffer_read(&shell_rb, data, size); 63 | } 64 | 65 | static void wait_char(void) 66 | { 67 | ULONG event; 68 | 69 | wait: 70 | tx_event_flags_get(&event_hdl, (0x10 | 0x01 | 0x04), TX_OR_CLEAR, &event, TX_WAIT_FOREVER); 71 | if ((event & 0x10) == 0) { 72 | if (event & 0x01) { 73 | chry_readline_erase_line(&csh.rl); 74 | tx_event_flags_set(&event_hdl, 0x02, TX_OR); 75 | } 76 | if (event & 0x04) { 77 | chry_readline_edit_refresh(&csh.rl); 78 | tx_event_flags_set(&event_hdl, 0x08, TX_OR); 79 | } 80 | 81 | goto wait; 82 | } 83 | } 84 | 85 | static void thread_repl(ULONG param) 86 | { 87 | (void)param; 88 | int ret; 89 | volatile uint8_t *pexec = (void *)&csh.exec; 90 | 91 | for (;;) { 92 | restart: 93 | if (login) { 94 | goto repl; 95 | } else { 96 | } 97 | 98 | ret = csh_login(&csh); 99 | if (ret == 0) { 100 | login = true; 101 | } else if (ret == 1) { 102 | /*!< no enough char */ 103 | wait_char(); 104 | continue; 105 | } else { 106 | continue; 107 | } 108 | 109 | repl: 110 | ret = chry_shell_task_repl(&csh); 111 | 112 | if (ret == -1) { 113 | /*!< error */ 114 | goto restart; 115 | } else if (ret == 1) { 116 | /*!< no enough char */ 117 | wait_char(); 118 | } else { 119 | /*!< restart */ 120 | } 121 | 122 | /*!< check flag */ 123 | if (*pexec == CSH_STATUS_EXEC_DONE) { 124 | *pexec = CSH_STATUS_EXEC_IDLE; 125 | chry_readline_auto_refresh(&csh.rl, true); 126 | chry_readline_ignore(&csh.rl, false); 127 | chry_readline_edit_refresh(&csh.rl); 128 | } 129 | 130 | if (login == false) { 131 | chry_readline_erase_line(&csh.rl); 132 | csh.rl.noblock = false; 133 | } 134 | } 135 | } 136 | 137 | static void thread_exec(ULONG param) 138 | { 139 | (void)param; 140 | 141 | /*!< execute shell command */ 142 | chry_shell_task_exec(&csh); 143 | 144 | /*!< notify REPL thread execute done */ 145 | tx_event_flags_set(&event_hdl, 0x10, TX_OR); 146 | 147 | /*!< wait for REPL thread delete */ 148 | tx_thread_suspend(&thread_buffer_exec); 149 | } 150 | 151 | int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **argv) 152 | { 153 | (void)csh; 154 | (void)argc; 155 | (void)argv; 156 | 157 | if (thread_exec_created) { 158 | if (TX_SUCCESS != tx_thread_terminate(&thread_buffer_exec)) { 159 | return -2; 160 | } 161 | if (TX_SUCCESS != tx_thread_delete(&thread_buffer_exec)) { 162 | return -3; 163 | } 164 | thread_exec_created = false; 165 | } 166 | 167 | if (TX_SUCCESS != tx_thread_create( 168 | &thread_buffer_exec, 169 | "csh buffer exec", 170 | thread_exec, 171 | 0, /* param */ 172 | thread_stack_exec, 173 | sizeof(thread_stack_exec), 174 | THREAD_EXEC_PRIORITY, 175 | THREAD_EXEC_PRIORITY, 176 | TX_NO_TIME_SLICE, 177 | TX_AUTO_START)) { 178 | return -1; 179 | } 180 | 181 | thread_exec_created = true; 182 | 183 | return 0; 184 | } 185 | 186 | void chry_shell_port_default_handler(chry_shell_t *csh, int sig) 187 | { 188 | volatile uint8_t *pexec = (void *)&csh->exec; 189 | 190 | switch (sig) { 191 | case CSH_SIGINT: 192 | case CSH_SIGQUIT: 193 | case CSH_SIGKILL: 194 | case CSH_SIGTERM: 195 | break; 196 | default: 197 | return; 198 | } 199 | 200 | /*!< force delete thread */ 201 | if (thread_exec_created) { 202 | if (TX_SUCCESS != tx_thread_terminate(&thread_buffer_exec)) { 203 | csh->rl.sput(&csh->rl, "context terminate error" CONFIG_CSH_NEWLINE CONFIG_CSH_NEWLINE, 204 | 23 + (sizeof(CONFIG_CSH_NEWLINE) ? (sizeof(CONFIG_CSH_NEWLINE) - 1) * 2 : 0)); 205 | return; 206 | } 207 | if (TX_SUCCESS != tx_thread_delete(&thread_buffer_exec)) { 208 | csh->rl.sput(&csh->rl, "context delete error" CONFIG_CSH_NEWLINE CONFIG_CSH_NEWLINE, 209 | 20 + (sizeof(CONFIG_CSH_NEWLINE) ? (sizeof(CONFIG_CSH_NEWLINE) - 1) * 2 : 0)); 210 | return; 211 | } 212 | thread_exec_created = false; 213 | } 214 | 215 | switch (sig) { 216 | case CSH_SIGINT: 217 | csh->rl.sput(&csh->rl, "^SIGINT" CONFIG_CSH_NEWLINE, sizeof("^SIGINT" CONFIG_CSH_NEWLINE) - 1); 218 | break; 219 | case CSH_SIGQUIT: 220 | csh->rl.sput(&csh->rl, "^SIGQUIT" CONFIG_CSH_NEWLINE, sizeof("^SIGQUIT" CONFIG_CSH_NEWLINE) - 1); 221 | break; 222 | case CSH_SIGKILL: 223 | csh->rl.sput(&csh->rl, "^SIGKILL" CONFIG_CSH_NEWLINE, sizeof("^SIGKILL" CONFIG_CSH_NEWLINE) - 1); 224 | break; 225 | case CSH_SIGTERM: 226 | csh->rl.sput(&csh->rl, "^SIGTERM" CONFIG_CSH_NEWLINE, sizeof("^SIGTERM" CONFIG_CSH_NEWLINE) - 1); 227 | break; 228 | default: 229 | return; 230 | } 231 | 232 | *pexec = CSH_STATUS_EXEC_IDLE; 233 | chry_readline_auto_refresh(&csh->rl, true); 234 | chry_readline_ignore(&csh->rl, false); 235 | chry_readline_edit_refresh(&csh->rl); 236 | } 237 | 238 | int shell_init(UART_Type *uart, bool need_login) 239 | { 240 | chry_shell_init_t csh_init; 241 | 242 | if (uart == NULL) { 243 | return -1; 244 | } 245 | 246 | if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) { 247 | return -1; 248 | } 249 | 250 | if (need_login) { 251 | login = false; 252 | } else { 253 | login = true; 254 | } 255 | 256 | shell_uart = uart; 257 | 258 | /*!< I/O callback */ 259 | csh_init.sput = csh_sput_cb; 260 | csh_init.sget = csh_sget_cb; 261 | 262 | #if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB 263 | extern const int __fsymtab_start; 264 | extern const int __fsymtab_end; 265 | extern const int __vsymtab_start; 266 | extern const int __vsymtab_end; 267 | 268 | /*!< get table from ld symbol */ 269 | csh_init.command_table_beg = &__fsymtab_start; 270 | csh_init.command_table_end = &__fsymtab_end; 271 | csh_init.variable_table_beg = &__vsymtab_start; 272 | csh_init.variable_table_end = &__vsymtab_end; 273 | #endif 274 | 275 | #if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT 276 | static char csh_prompt_buffer[128]; 277 | 278 | /*!< set prompt buffer */ 279 | csh_init.prompt_buffer = csh_prompt_buffer; 280 | csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer); 281 | #endif 282 | 283 | #if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY 284 | static char csh_history_buffer[128]; 285 | 286 | /*!< set history buffer */ 287 | csh_init.history_buffer = csh_history_buffer; 288 | csh_init.history_buffer_size = sizeof(csh_history_buffer); 289 | #endif 290 | 291 | #if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC 292 | static char csh_line_buffer[128]; 293 | 294 | /*!< set linebuffer */ 295 | csh_init.line_buffer = csh_line_buffer; 296 | csh_init.line_buffer_size = sizeof(csh_line_buffer); 297 | #endif 298 | 299 | csh_init.uid = 0; 300 | csh_init.user[0] = "cherry"; 301 | 302 | /*!< The port hash function is required, 303 | and the strcmp attribute is used weakly by default, 304 | int chry_shell_port_hash_strcmp(const char *hash, const char *str); */ 305 | csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */ 306 | csh_init.host = BOARD_NAME; 307 | csh_init.user_data = NULL; 308 | 309 | int ret = chry_shell_init(&csh, &csh_init); 310 | if (ret) { 311 | return -1; 312 | } 313 | 314 | thread_exec_created = false; 315 | 316 | tx_event_flags_create(&event_hdl, "csh event"); 317 | 318 | tx_thread_create( 319 | &thread_buffer_repl, 320 | "csh buffer repl", 321 | thread_repl, 322 | 0, /* param */ 323 | thread_stack_repl, 324 | sizeof(thread_stack_repl), 325 | THREAD_REPL_PRIORITY, 326 | THREAD_REPL_PRIORITY, 327 | TX_NO_TIME_SLICE, 328 | TX_AUTO_START); 329 | 330 | return 0; 331 | } 332 | 333 | void shell_lock(void) 334 | { 335 | ULONG actual_flags_ptr; 336 | (void)actual_flags_ptr; 337 | tx_event_flags_set(&event_hdl, 0x01, TX_OR); 338 | tx_event_flags_get(&event_hdl, 0x02, TX_OR_CLEAR, &actual_flags_ptr, TX_WAIT_FOREVER); 339 | } 340 | 341 | void shell_unlock(void) 342 | { 343 | ULONG actual_flags_ptr; 344 | (void)actual_flags_ptr; 345 | tx_event_flags_set(&event_hdl, 0x04, TX_OR); 346 | tx_event_flags_get(&event_hdl, 0x08, TX_OR_CLEAR, &actual_flags_ptr, TX_WAIT_FOREVER); 347 | } 348 | 349 | static int csh_exit(int argc, char **argv) 350 | { 351 | (void)argc; 352 | (void)argv; 353 | login = false; 354 | 355 | return 0; 356 | } 357 | CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, ); 358 | 359 | #define __ENV_PATH "/sbin:/bin" 360 | const char ENV_PATH[] = __ENV_PATH; 361 | CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH)); 362 | 363 | #define __ENV_ZERO "" 364 | const char ENV_ZERO[] = __ENV_ZERO; 365 | CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO)); 366 | --------------------------------------------------------------------------------