├── .gitignore ├── .idea ├── .gitignore ├── arduino-project-settings.xml ├── misc.xml └── vcs.xml ├── LICENSE ├── README.md ├── include └── README ├── lib └── README ├── platformio.ini ├── src └── main.ino ├── test └── README └── tinyuf2-partitions-4MB.csv /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/arduino-project-settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

KeyBox-ESP32C3电子钥匙

3 | 4 | 5 | ![Static Badge](https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-green?style=for-the-badge) 6 | ![Commit Activity](https://img.shields.io/github/commit-activity/w/JasonYANG170/KeyBox?style=for-the-badge&color=yellow) 7 | ![Languages Count](https://img.shields.io/github/languages/count/JasonYANG170/KeyBox?logo=c&style=for-the-badge) 8 | 9 | [![Discord](https://img.shields.io/discord/978108215499816980?style=social&logo=discord&label=echosec)](https://discord.com/invite/az3ceRmgVe) 10 | 11 | ![KeyBox](https://github.com/JasonYANG170/KeyBox/assets/39414350/be60f9aa-8254-4ff5-99e1-27b5d7f49282) 12 | 13 | 这是一项基于C语言的电子密钥存储器 14 | 15 |
16 | 17 | 18 | ## 演示视频 19 | 20 | [![KeyBox](https://res.cloudinary.com/marcomontalbano/image/upload/v1719168122/video_to_markdown/images/youtube--kEUG0me2HfA-c05b58ac6eb4c4700831b2b3070cd403.jpg)](https://youtu.be/kEUG0me2HfA "KeyBox") 21 | 22 | [无法播放请点此使用BiliBili](https://www.bilibili.com/video/BV1NATFeLE5D/) 23 | ## 功能 24 | - ✅支持从浏览器导入网站密钥 25 | - ✅支持 TOTP 2FA实时验证码绑定 26 | - ✅支持蓝牙模拟输入HID 27 | - ✅支持 WIFI NTP 校时 28 | - ✅支持设置设备6位密码 29 | - ✅支持息屏 30 | - ✅支持屏幕亮度调节。 31 | ## 计划 32 | - [ ] 接入IOT万物互联客户端 33 | - [ ] 天气、时间、新闻、电量显示 34 | 35 | ## 开源协议 36 | 本项目遵循CC BY-NC-SA 4.0开源协议,使用本程序时请注明出处并进行版权声明 37 | 本项目仅供学习研究与学习,严禁非授权的商业获利, 38 | 如果您有更好的建议,欢迎PR 39 | 40 | 41 | 如遇问题,请向我提出issues 42 | ## 喜欢这个项目,请为我点个Star ⭐ 43 | 44 | [![Star History Chart](https://api.star-history.com/svg?repos=JasonYANG170/KeyBox&type=Date)](https://star-history.com/#star-history/star-history&Date) 45 | ## 实物图 46 | 47 | | 1 | 2 | 48 | | --- | --- | 49 | |![d83726536861c73bab3f8e9bc06b336](https://github.com/JasonYANG170/KeyBox/assets/39414350/88ef05bc-0f1f-40b4-b222-10befc1da3f3)|![bb1c62e45152e4ef3c35a244380875b](https://github.com/JasonYANG170/KeyBox/assets/39414350/ef9d16bb-cecc-4ed1-9b79-15069e8df3df)| 50 | |![d71121f7d8fb372332b5ff2c4085806](https://github.com/JasonYANG170/KeyBox/assets/39414350/5fbc0bf8-bc44-4b91-8075-eac935da4c63)|![afcc41d5f515fb041ca14036da62cfe](https://github.com/JasonYANG170/KeyBox/assets/39414350/3665a827-3d27-452f-861a-24bea91334c3) 51 | | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:airm2m_core_esp32c3] 12 | platform = espressif32 13 | board = airm2m_core_esp32c3 14 | framework = arduino 15 | board_build.partitions = tinyuf2-partitions-4MB.csv 16 | ;将CPU频率设置为240MHz 17 | board_build.f_cpu = 130000000L 18 | board_build.f_flash = 80000000L 19 | lib_deps = 20 | 21 | olikraus/U8g2 @ ^2.35.17 22 | 23 | # Accept only backwards compatible bug fixes 24 | # (any version with the same major and minor versions, and an equal or greater patch version) 25 | olikraus/U8g2 @ ~2.35.17 26 | 27 | # The exact version 28 | olikraus/U8g2 @ 2.35.17 29 | # RECOMMENDED 30 | # Accept new functionality in a backwards compatible manner and patches 31 | bblanchon/ArduinoJson @ ^7.0.4 32 | 33 | # Accept only backwards compatible bug fixes 34 | # (any version with the same major and minor versions, and an equal or greater patch version) 35 | bblanchon/ArduinoJson @ ~7.0.4 36 | 37 | # The exact version 38 | bblanchon/ArduinoJson @ 7.0.4 39 | 40 | # RECOMMENDED 41 | # Accept new functionality in a backwards compatible manner and patches 42 | polygontechmx/TOTP++ @ ^1.0.1 43 | 44 | # Accept only backwards compatible bug fixes 45 | # (any version with the same major and minor versions, and an equal or greater patch version) 46 | polygontechmx/TOTP++ @ ~1.0.1 47 | 48 | # The exact version 49 | polygontechmx/TOTP++ @ 1.0.1 50 | 51 | arduino-libraries/NTPClient @ ^3.2.1 52 | 53 | # Accept only backwards compatible bug fixes 54 | # (any version with the same major and minor versions, and an equal or greater patch version) 55 | arduino-libraries/NTPClient @ ~3.2.1 56 | 57 | # The exact version 58 | arduino-libraries/NTPClient @ 3.2.1 59 | t-vk/ESP32 BLE Keyboard @ ^0.3.2 60 | 61 | # Accept only backwards compatible bug fixes 62 | # (any version with the same major and minor versions, and an equal or greater patch version) 63 | t-vk/ESP32 BLE Keyboard @ ~0.3.2 64 | 65 | # The exact version 66 | t-vk/ESP32 BLE Keyboard @ 0.3.2 -------------------------------------------------------------------------------- /src/main.ino: -------------------------------------------------------------------------------- 1 | /* 2 | This example opens Sqlite3 databases from SD Card and 3 | retrieves data from them. 4 | Before running please copy following files to SD Card: 5 | examples/sqlite3_sdmmc/data/mdr512.db 6 | examples/sqlite3_sdmmc/data/census2000names.db 7 | Connections: 8 | * SD Card | ESP32 9 | * DAT2 - 10 | * DAT3 SS (D5) 11 | * CMD MOSI (D23) 12 | * VSS GND 13 | * VDD 3.3V 14 | * CLK SCK (D18) 15 | * DAT0 MISO (D19) 16 | * DAT1 - 17 | */ 18 | #include "TOTP++.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "SD.h" 24 | #include 25 | #include 26 | 27 | BleKeyboard bleKeyboard; 28 | 29 | using namespace std; 30 | 31 | // WiFi credentials 32 | const char *ssid = "Hello-World 2.4G"; 33 | const char *password = "Qwe200477"; 34 | //const long utcOffsetInSeconds = 3600;//用于NTPClient timeClient,看定义 35 | 36 | WiFiUDP ntpUDP; 37 | NTPClient timeClient(ntpUDP, "pool.ntp.org"); 38 | 39 | 40 | 41 | // TOTP CONFIG 42 | 43 | 44 | 45 | 46 | int OutPutTimes; 47 | int modelchooese=0;//0:JSON,1:TXT,2:SET,3.TOTp,4.Displaytime,5.Back Light,6.BLE MODE 48 | String OutPutString = ""; 49 | int keySize; 50 | char* passwordIn; 51 | struct key { 52 | String user; 53 | String password; 54 | }; 55 | int passwordst=0; 56 | const char* data = "Callback function called"; 57 | //#include 58 | #include 59 | #include 60 | 61 | // #define ESP32 0 62 | // #define MEGA2560 1 63 | 64 | // #define MCU 1 65 | 66 | #define SPEED 4//16的因数 67 | #define ICON_SPEED 12 68 | #define ICON_SPACE 48//图标间隔,speed倍数 69 | 70 | // #define READ A0 71 | // #define BTN0 5 72 | // #define BTN1 6 73 | // #define BTN2 7 74 | 75 | #define BTN0 12 76 | #define BTN1 1 77 | #define BTN2 0 78 | 79 | U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* clock=*/ 9, /* data=*/ 8); // ESP32 Thing, pure SW emulated I2C 80 | 81 | PROGMEM const uint8_t icon_pic[][200] 82 | { 83 | { 84 | 85 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x80,0x3F,0x00,0x00,0x00,0xE0,0x79,0x00,0x00,0x00,0x70,0xE0,0x00,0x00,0x00,0x38,0xC0,0x03,0x00,0x00,0x1E,0x80,0x07,0x00,0x00,0x0F,0x00,0x0E,0x00,0x80,0x03,0x00,0x1C,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0xC0,0x3F,0x30,0x00,0xC0,0xC0,0x3F,0x30,0x00,0xC0,0xC0,0x30,0x30,0x00,0xC0,0xC0,0x30,0x30,0x00,0xC0,0xC0,0x30,0x30,0x00,0xC0,0xC0,0x30, 86 | 0x30,0x00,0xC0,0xC0,0x30,0x30,0x00,0xC0,0xC0,0x30,0x30,0x00,0xC0,0xC0,0x30,0x30,0x00,0xC0,0xFF,0xF0,0x3F,0x00,0x80,0xFF,0xF0,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\qw200\Desktop\home_40dp_FILL0_wght400_GRAD0_opsz40.bmp",0*/ 87 | }, 88 | { 89 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x80,0x7F,0x00,0x00,0x00,0xE0,0xE0,0x00,0x00,0x00,0x70,0xC0,0x01,0x00,0x00,0x38,0x00,0x03,0x00,0x00,0x18,0x00,0xFF,0xFF,0x00,0x0C,0x00,0xFE,0xFF,0x01,0x0C,0x0E,0x00,0x80,0x03,0x0C,0x1F,0x00,0x00,0x07,0x0C,0x1F,0x00,0x00,0x0E,0x0C,0x0E,0x00,0x04,0x07,0x0C,0x00,0x3E,0x8E,0x01,0x18,0x00,0x7F,0xFF,0x00,0x18,0x00,0xE3,0x71,0x00,0x70,0x80,0x81,0x20,0x00,0xE0,0xE0,0x00,0x00,0x00,0xC0,0x7F,0x00, 90 | 0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\qw200\Desktop\key_40dp_FILL0_wght400_GRAD0_opsz40 (1).bmp",0*/ 91 | 92 | /* (36 X 37 )*/ 93 | }, 94 | { 95 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0xE0,0x79,0x00,0x00,0x00,0x7C,0xE0,0x03,0x00,0x80,0x0F,0x00,0x1F,0x00,0x80,0x03,0x00,0x38,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x0F,0x30,0x00,0xC0,0x00,0x0F,0x30,0x00,0xC0,0x00,0x0F,0x30,0x00,0xC0,0x00,0x0F,0x30,0x00,0xC0,0x00,0x06,0x30,0x00,0xC0,0x00,0x06,0x30,0x00,0xC0,0x01,0x06,0x30,0x00,0x80,0x01,0x06,0x38,0x00,0x80,0x01,0x0E,0x18,0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x03,0x00,0x0C,0x00,0x00,0x03,0x00,0x0C,0x00,0x00,0x06,0x00, 96 | 0x06,0x00,0x00,0x0C,0x00,0x07,0x00,0x00,0x1C,0x00,0x03,0x00,0x00,0x38,0xC0,0x01,0x00,0x00,0x70,0xE0,0x00,0x00,0x00,0xC0,0x79,0x00,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\qw200\Desktop\encrypted_40dp_FILL0_wght400_GRAD0_opsz40.bmp",0*/ 97 | 98 | }, 99 | 100 | { 101 | 102 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x1F,0x00,0x00,0x80,0xFF,0x7F,0x00,0x00,0xC0,0x00,0xE0,0x00,0x00,0xC0,0x00,0xE0,0x00,0x00,0xC0,0x00,0xE0,0x01,0x00,0xC0,0x00,0xE0,0x07,0x00,0xC0,0x00,0xE0,0x0F,0x00,0xC0,0x00,0xE0,0x1F,0x00,0xC0,0x00,0xE0,0x1F,0x00,0xC0,0x00,0x20,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0xE0,0x7F,0x30,0x00,0xC0,0xF0,0xFF,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0xF0,0xFF, 103 | 0x30,0x00,0xC0,0xE0,0x7E,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0xC0,0x00,0x00,0x30,0x00,0x80,0xFF,0xFF,0x3F,0x00,0x80,0xFF,0xFF,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\qw200\Desktop\description_40dp_FILL0_wght400_GRAD0_opsz40.bmp",0*/ 104 | 105 | 106 | }, 107 | { 108 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x80,0x3F,0x00,0x00,0x00,0x80,0x30,0x00,0x00,0x00,0xC0,0x30,0x00,0x00,0x00,0xC0,0x30,0x00,0x00,0x80,0xE1,0x70,0x30,0x00,0xC0,0x77,0xE0,0x3F,0x00,0x60,0x1E,0x80,0x67,0x00,0x60,0x08,0x00,0x61,0x00,0x30,0x00,0x00,0xC0,0x00,0x30,0x00,0x06,0xC0,0x00,0xE0,0x80,0x1F,0xE0,0x00,0xC0,0xC1,0x3F,0x38,0x00,0x80,0xC1,0x7F,0x18,0x00,0x80,0xC1,0x7F,0x18,0x00,0x80,0xE1,0x7F,0x18,0x00,0x80,0xC1,0x7F,0x18,0x00,0xC0,0xC1,0x3F,0x38,0x00,0xE0,0x80,0x1F,0x70,0x00,0x30,0x00,0x0F,0xC0,0x00,0x30,0x00,0x00,0xC0,0x00,0x60,0x00,0x00,0xE0,0x00,0x60,0x1E,0x80, 109 | 0x67,0x00,0xC0,0x7F,0xE0,0x3F,0x00,0xC0,0xE1,0xF0,0x38,0x00,0x00,0xC0,0x30,0x00,0x00,0x00,0xC0,0x30,0x00,0x00,0x00,0x80,0x30,0x00,0x00,0x00,0x80,0x3F,0x00,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\qw200\Desktop\settings_40dp_FILL0_wght400_GRAD0_opsz40.bmp",0*/ 110 | }, 111 | {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x1F,0x00,0x00,0x00,0xC0,0x3F,0x00,0x00,0x00,0xF0,0xF0,0x00,0x00,0x00,0x70,0xE0,0x00,0x00,0x00,0x38,0xC0,0x01,0x00,0x00,0x18,0x80,0x01,0x00,0x00,0x18,0x80,0x01,0x00,0x00,0x18,0x80,0x01,0x00,0x00,0x18,0x80,0x01,0x00,0x00,0x18,0x80,0x01,0x00,0x00,0xFE,0xFF,0x07,0x00,0x80,0xFF,0xFF,0x1F,0x00,0xC0,0xFF,0xFF,0x3F,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x0F,0x38,0x00,0xC0,0x81,0x1F,0x38,0x00,0xC0,0x81,0x1F,0x38,0x00,0xC0,0x81,0x1F,0x38,0x00,0xC0,0x01,0x0F,0x38,0x00,0xC0,0x01,0x00, 112 | 0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0x01,0x00,0x38,0x00,0xC0,0xFF,0xFF,0x3F,0x00,0x80,0xFF,0xFF,0x1F,0x00,0x00,0xFE,0xFF,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\qw200\Desktop\lock_24dp_FILL0_wght400_GRAD0_opsz24.bmp",0*/}, 113 | }; 114 | 115 | uint8_t icon_width[] = { 36,36,36,36,36 ,36}; 116 | 117 | //main界面图片 118 | PROGMEM const uint8_t LOGO[] = 119 | { 120 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 121 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 122 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 123 | 0x00,0x00,0x00,0x00,0xEF,0x0F,0x70,0x00,0x00,0x00,0x00,0x00,0xE0,0xD8,0x87,0x3F, 124 | 0x00,0x00,0x00,0x80,0xEF,0x0F,0x00,0x07,0x00,0x00,0x00,0x00,0xE0,0xDC,0x8F,0x3F, 125 | 0x98,0xFF,0x7F,0xBF,0x0F,0x8F,0xFF,0xFF,0x03,0x00,0x00,0x00,0xE0,0x1D,0x8F,0x07, 126 | 0x98,0xE1,0xFF,0x3F,0x87,0x87,0x73,0x77,0x03,0x00,0x00,0x00,0xC0,0x9F,0x87,0x1F, 127 | 0x98,0xFD,0xF7,0x3B,0x87,0x83,0x7F,0xF7,0x07,0x00,0x00,0x00,0xC0,0xCF,0x03,0x3C, 128 | 0xB0,0xF7,0xF7,0x3F,0xC7,0x73,0x7E,0x7F,0x00,0x00,0x00,0x00,0xC0,0xE7,0xB7,0x3F, 129 | 0xF0,0xFE,0xF7,0x3F,0xE7,0xF1,0x7F,0xFF,0x03,0x00,0x00,0x00,0x80,0xE7,0xB7,0x1F, 130 | 0xF0,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 131 | 0x70,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 132 | 0x7C,0x00,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 133 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 134 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 135 | 0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F, 136 | 0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F, 137 | 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 138 | 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 139 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0xFF,0xFF,0xFF,0xFF,0xFF, 140 | 0xFF,0xFF,0x83,0xFF,0xF0,0x01,0x00,0x8F,0xFF,0x1E,0x00,0x7E,0x80,0x0F,0x7F,0xFE, 141 | 0xFF,0xFF,0x83,0x7F,0xF0,0x01,0x00,0x0F,0x7F,0x1E,0x7F,0x3C,0x00,0x0F,0x3E,0xFE, 142 | 0xFF,0xFF,0xC1,0x1F,0xF8,0xF1,0xFF,0x1F,0x7E,0x1E,0x7F,0x1C,0x00,0x3E,0x3C,0xFE, 143 | 0xFF,0xFF,0xC1,0x07,0xFE,0xF1,0xFF,0x3F,0x3C,0x1F,0x3F,0x1C,0x3C,0x7C,0x18,0xFE, 144 | 0xFF,0xFF,0xC0,0x81,0xFF,0xF1,0xFF,0xFF,0x98,0x1F,0x0F,0x1C,0x7E,0xFC,0x08,0xFF, 145 | 0xFF,0xFF,0x00,0xF0,0xFF,0xF1,0xFF,0xFF,0xC8,0x1F,0x00,0x1F,0x7F,0xFC,0x81,0xFF, 146 | 0xFF,0xFF,0x00,0xFC,0xFF,0x01,0xC0,0xFF,0xC9,0x1F,0xF0,0x1F,0x7F,0xFC,0xC1,0xFF, 147 | 0xFF,0xFF,0x00,0xFE,0xFF,0x01,0xC0,0xFF,0xE3,0x1F,0x80,0x1F,0x7F,0xFC,0xC0,0xFF, 148 | 0xFF,0x7F,0x00,0xF8,0xFF,0x01,0x80,0xFF,0xF3,0x1F,0x00,0x1C,0x7F,0x7C,0xC0,0xFF, 149 | 0xFF,0x7F,0xF0,0xF8,0xFF,0xF9,0xFF,0xFF,0xF3,0x1F,0x1F,0x18,0x7F,0x7C,0x88,0xFF, 150 | 0xFF,0x7F,0xF8,0xF0,0xFF,0xF8,0xFF,0xFF,0xF3,0x9F,0x3F,0x18,0x7F,0x3C,0x0C,0xFF, 151 | 0xFF,0x3F,0xF8,0xE1,0xFF,0xF8,0xFF,0xFF,0xF3,0x9F,0x3F,0x18,0x7F,0x3C,0x1E,0xFE, 152 | 0xFF,0x3F,0xF8,0xC3,0x7F,0xFC,0xFF,0xFF,0xF3,0x9F,0x3F,0x18,0x7F,0x3C,0x1F,0xFE, 153 | 0xFF,0x1F,0xFC,0x87,0x3F,0xFC,0xFF,0xFF,0xF3,0x9F,0x1F,0x18,0x3F,0x1C,0x3F,0xFC, 154 | 0xFF,0x1F,0xFC,0x0F,0x3F,0x00,0xE0,0xFF,0xF3,0x1F,0x00,0x1C,0x00,0x1C,0x3F,0xF8, 155 | 0xFF,0x1F,0xFC,0x0F,0x3E,0x00,0xE0,0xFF,0xF3,0x1F,0x00,0x7F,0x00,0xBC,0x7F,0xF8, 156 | 0xFF,0x0F,0xFE,0x1F,0x3E,0x00,0xF0,0xFF,0xF3,0x1F,0xF0,0xFF,0x03,0xFF,0x7F,0xFC, 157 | 0xFF,0xFF,0xFF,0x3F,0xFE,0xFF,0xFF,0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, 158 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 159 | 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 160 | 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 161 | 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 162 | 0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F, 163 | 0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F, 164 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 165 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 166 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 167 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 168 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 169 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 170 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 171 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 172 | 0x00,0x00,0x00,0x00,0x00,0x38,0x9E,0xDF,0xDF,0xF3,0x30,0xCF,0x73,0x7F,0xDE,0x1F, 173 | 0x00,0x00,0x00,0x00,0x00,0x38,0x9F,0xFF,0xFF,0xF7,0x99,0xDF,0xF7,0x7F,0xDF,0x1F, 174 | 0x00,0x00,0x00,0x00,0x00,0xB8,0xBB,0xE7,0xFD,0xF7,0x9F,0xD9,0xF7,0x07,0x1F,0x0E, 175 | 0x00,0x00,0x00,0x00,0x00,0xB8,0x31,0xFF,0xF8,0x7F,0xCF,0xD9,0xFD,0x7B,0x0E,0x0F, 176 | 0x00,0x00,0x00,0x00,0x00,0xFC,0x3F,0xFE,0xFC,0x7C,0xC7,0xFF,0xFD,0x7B,0x8E,0x07, 177 | 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x7C,0xE7,0xFF,0xFD,0x7F,0x8E,0x07, 178 | 0x00,0x00,0x00,0x00,0x00,0xFF,0xF1,0xCF,0xDF,0x3C,0xF7,0xF9,0x3D,0x7F,0xCE,0x03, 179 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 180 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 181 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 182 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 183 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"C:\Users\qw200\Desktop\indexa.bmp",0*/ 184 | }; 185 | 186 | const float PID_MAX = 10.00;//PID最大允许值 187 | //PID变量 188 | float Kpid[3] = { 9.97,0.2,0.01 };//Kp,Ki,Kd 189 | // float Kp=8.96; 190 | // float Ki=0.2; 191 | // float Kd=0.01; 192 | 193 | #define MAX_CHARS_PER_LINE 20 // 每行最大字符数 194 | #define MAX_LINES_PER_PAGE 5 // 每页最大行数 195 | 196 | #define BUTTON_PIN 1 197 | #define DISPLAY_ROWS 6 198 | #define CHARACTERS_PER_LINE 22 199 | 200 | //U8G2_SH1106_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); 201 | 202 | 203 | String textContent; 204 | int currentPage = 0; 205 | int totalPages = 0; 206 | uint8_t disappear_step = 1; 207 | 208 | 209 | float angle, angle_last; 210 | //实时坐标 211 | uint8_t chart_x; 212 | bool frame_is_drawed = false; 213 | 214 | //指向buf首地址的指针 215 | uint8_t* buf_ptr; 216 | uint16_t buf_len; 217 | 218 | //选择界面变量 219 | uint8_t x; 220 | int16_t y, y_trg;//目标和当前 221 | uint8_t line_y, line_y_trg;//线的位置 222 | uint8_t box_width, box_width_trg;//框的宽度 223 | int16_t box_y, box_y_trg;//框的当前值和目标值 224 | int8_t ui_select;//当前选中那一栏 225 | 226 | //pid界面变量 227 | //pid界面变量 228 | int8_t pid_x; 229 | int16_t pid_y,pid_y_trg; 230 | uint8_t pid_line_y, pid_line_y_trg;//线的位置 231 | uint8_t pid_box_width, pid_box_width_trg;//框的宽度 232 | int16_t pid_box_y, pid_box_y_trg;//框的当前值和目标值 233 | int8_t pid_select;//当前选中那一栏 234 | 235 | //icon界面变量 236 | int16_t icon_x, icon_x_trg; 237 | int16_t app_y, app_y_trg; 238 | 239 | int8_t icon_select; 240 | 241 | uint8_t ui_index, ui_state; 242 | 243 | 244 | enum//ui_index 245 | { 246 | M_LOGO,//开始界面 247 | M_SELECT,//选择界面 248 | M_PID,//PID界面 249 | M_PID_EDIT,//pid编辑 250 | M_ICON,//icon界面 251 | M_CHART,//图表 252 | M_TEXT_EDIT,//文字编辑 253 | M_VIDEO,//视频显示 254 | M_ABOUT,//关于本机 255 | M_ABOUT_pass, 256 | M_IMPORT, 257 | M_TXTREAD, 258 | M_ABOUTDEV, 259 | M_SET, 260 | M_TOTF, 261 | M_BLACK 262 | }; 263 | 264 | 265 | enum//ui_state 266 | { 267 | S_NONE, 268 | S_DISAPPEAR, 269 | S_SWITCH, 270 | S_MENU_TO_MENU, 271 | S_MENU_TO_PIC, 272 | S_PIC_TO_MENU, 273 | }; 274 | 275 | //const char* text="This is a text Hello world ! follow up one two three four may jun july"; 276 | 277 | //菜单结构体 278 | typedef struct 279 | { 280 | char* select; 281 | } SELECT_LIST; 282 | 283 | SELECT_LIST* list = NULL; // (主要的菜单结构,用于展示站点和文本)初始化结构体数组指针 284 | 285 | SELECT_LIST* pid = NULL; // (二级菜单结构,用于展示站点的多个用户)初始化结构体数组指针 286 | 287 | 288 | 289 | 290 | //SELECT_LIST list[] 291 | //{ 292 | // {"MainUI"}, 293 | // {"+PID Editor"}, 294 | // {"-Icon Test"}, 295 | // {"-Chart Test"}, 296 | // {"-Text Edit"}, 297 | // {"-Play Video"}, 298 | // {"{ About }"}, 299 | // {"{ About }"}, 300 | // {"{ About }"}, 301 | //}; 302 | int listSize = 7;//选择界面菜单个数 303 | int pidSize = 6; 304 | uint8_t pid_single_line_length = 63 /pidSize; 305 | uint8_t pid_total_line_length = pid_single_line_length * pidSize + 1; 306 | uint8_t single_line_length = 63 / listSize; 307 | uint8_t total_line_length = single_line_length * listSize + 1; 308 | 309 | SELECT_LIST icon[] 310 | { 311 | {"HOME"}, 312 | {"WEB KEY"}, 313 | {"2FA KEY"}, 314 | {"TXT"}, 315 | {"SET"}, 316 | {"LOCK"}, 317 | }; 318 | 319 | //设备名称 320 | char name[] = ""; 321 | char Passwordis[]=""; 322 | int display_time=0; 323 | //允许名字的最大长度 324 | const uint8_t name_len = 6;//0-11for name 12 for return 325 | char title[] = "Password"; 326 | char bt[] = "sure"; 327 | 328 | uint8_t edit_index = 0; 329 | bool edit_flag = false;//默认不在编辑 330 | uint8_t blink_flag;//默认高亮 331 | const uint8_t BLINK_SPEED = 16;//2的倍数 332 | 333 | uint8_t icon_num = sizeof(icon) / sizeof(SELECT_LIST); 334 | 335 | //按键变量 336 | typedef struct 337 | { 338 | bool val; 339 | bool last_val; 340 | }KEY; 341 | 342 | KEY key[3] = { false }; 343 | 344 | //按键信息 345 | typedef struct 346 | { 347 | uint8_t id; 348 | bool pressed; 349 | }KEY_MSG; 350 | 351 | KEY_MSG key_msg = { 0 }; 352 | 353 | void createJson(String fileName, String key, String value) { 354 | StaticJsonDocument<200> doc; //JSON document size 355 | 356 | doc[key] = value; 357 | 358 | delay(500); // 添加延时以确保前一个文件句柄已被释放 359 | 360 | File jsonFile = SD.open("/"+fileName, FILE_WRITE); // 定义并初始化File对象 361 | 362 | delay(100); // 添加另一个延时 363 | 364 | if (jsonFile) { 365 | serializeJson(doc, jsonFile); 366 | jsonFile.close(); 367 | } else { 368 | Serial.println("Error opening file for writing!"); 369 | } 370 | } 371 | void updateJson(String fileName, String key, String value) { 372 | File jsonFile = SD.open("/"+fileName, FILE_READ); 373 | 374 | DynamicJsonDocument doc(1024); 375 | 376 | DeserializationError error = deserializeJson(doc, jsonFile); 377 | 378 | jsonFile.close(); 379 | 380 | if (error) { 381 | Serial.println("Error deserializing JSON file!"); 382 | return; 383 | } 384 | 385 | doc[key] = value; 386 | 387 | delay(100); // 添加延时以确保前一个文件句柄已被释放 388 | 389 | jsonFile = SD.open("/"+fileName, FILE_WRITE); 390 | 391 | if (jsonFile) { 392 | serializeJson(doc, jsonFile); 393 | jsonFile.close(); 394 | } else { 395 | Serial.println("Error opening222 file for writing!"); 396 | } 397 | } 398 | void writeCSV(){ 399 | 400 | // 打开CSV文件 401 | File csvFile = SD.open("/data.csv"); 402 | 403 | // 跳过第一行 404 | if (csvFile) { 405 | csvFile.readStringUntil('\n'); // 跳过第一行 406 | } else { 407 | Serial.println("Error opening CSV file!"); 408 | return; 409 | } 410 | 411 | // 读取CSV文件内容并创建/更新JSON文件 412 | while (csvFile.available()) { 413 | String data = csvFile.readStringUntil('\n'); // 读取一行数据 414 | if (data == "") { 415 | break; // 结束循环,文件已读取完整 416 | } 417 | 418 | String ip = data.substring(0, data.indexOf(",")); 419 | int firstCommaIndex = data.indexOf(","); 420 | int secondCommaIndex = data.indexOf(",", firstCommaIndex + 1); 421 | int thirdCommaIndex = data.indexOf(",", secondCommaIndex + 1); 422 | int fourthCommaIndex = data.indexOf(",", thirdCommaIndex + 1); 423 | int fourth2CommaIndex = data.indexOf(",", fourthCommaIndex + 1); 424 | String key = data.substring(thirdCommaIndex + 1, fourthCommaIndex); 425 | String value = data.substring(fourthCommaIndex + 1, fourth2CommaIndex); 426 | Serial.println(ip); 427 | Serial.println(key); 428 | Serial.println(value); 429 | Serial.println("----------------------------------"); 430 | String fileName = ip + ".web"; 431 | 432 | if (SD.exists("/" + fileName)) { 433 | // 文件已存在,更新JSON文件中的键值对 434 | updateJson(fileName, key, value); 435 | } else { 436 | // 文件不存在,创建新的JSON文件 437 | createJson(fileName, key, value); 438 | } 439 | } 440 | 441 | csvFile.close(); // 关闭CSV文件 442 | // 关闭CSV文件 443 | 444 | } 445 | bool get_key_val(uint8_t ch) 446 | { 447 | switch (ch) 448 | { 449 | case 0: 450 | return digitalRead(BTN0); 451 | break; 452 | case 1: 453 | return digitalRead(BTN1); 454 | break; 455 | case 2: 456 | return digitalRead(BTN2); 457 | break; 458 | default: 459 | break; 460 | } 461 | } 462 | 463 | void key_init() 464 | { 465 | for (uint8_t i = 0; i < (sizeof(key) / sizeof(KEY)); ++i) 466 | { 467 | key[i].val = key[i].last_val = get_key_val(i); 468 | } 469 | } 470 | 471 | void key_scan() 472 | { 473 | for (uint8_t i = 0; i < (sizeof(key) / sizeof(KEY)); ++i) 474 | { 475 | key[i].val = get_key_val(i);//获取键值 476 | if (key[i].last_val != key[i].val)//发生改变 477 | { 478 | key[i].last_val = key[i].val;//更新状态 479 | if (key[i].val == LOW) 480 | { 481 | key_msg.id = i; 482 | key_msg.pressed = true; 483 | } 484 | } 485 | } 486 | } 487 | 488 | //移动函数 489 | bool move(int16_t* a, int16_t* a_trg) 490 | { 491 | if (*a < *a_trg) 492 | { 493 | *a += SPEED; 494 | if (*a > *a_trg) *a = *a_trg;//加完超过 495 | } 496 | else if (*a > *a_trg) 497 | { 498 | *a -= SPEED; 499 | if (*a < *a_trg) *a = *a_trg;//减完不足 500 | } 501 | else 502 | { 503 | return true;//到达目标 504 | } 505 | return false;//未到达 506 | } 507 | 508 | //移动函数 509 | bool move_icon(int16_t* a, int16_t* a_trg) 510 | { 511 | if (*a < *a_trg) 512 | { 513 | *a += ICON_SPEED; 514 | if (*a > *a_trg) *a = *a_trg;//加完超过 515 | } 516 | else if (*a > *a_trg) 517 | { 518 | *a -= ICON_SPEED; 519 | if (*a < *a_trg) *a = *a_trg;//减完不足 520 | } 521 | else 522 | { 523 | return true;//到达目标 524 | } 525 | return false;//未到达 526 | } 527 | 528 | //宽度移动函数 529 | bool move_width(uint8_t* a, uint8_t* a_trg, uint8_t select, uint8_t id) 530 | { 531 | if (*a < *a_trg) 532 | { 533 | uint8_t step = 16 / SPEED;//判断步数 534 | uint8_t len; 535 | if (ui_index == M_SELECT) 536 | { 537 | len = abs(u8g2.getStrWidth(list[select].select) - u8g2.getStrWidth(list[id == 0 ? select + 1 : select - 1].select)); 538 | } 539 | else if (ui_index == M_PID) 540 | { 541 | len = abs(u8g2.getStrWidth(pid[select].select) - u8g2.getStrWidth(pid[id == 0 ? select + 1 : select - 1].select)); 542 | } 543 | uint8_t width_speed = ((len % step) == 0 ? (len / step) : (len / step + 1)); //计算步长 544 | *a += width_speed; 545 | if (*a > *a_trg) *a = *a_trg;// 546 | } 547 | else if (*a > *a_trg) 548 | { 549 | uint8_t step = 16 / SPEED;//判断步数 550 | uint8_t len; 551 | if (ui_index == M_SELECT) 552 | { 553 | len = abs(u8g2.getStrWidth(list[select].select) - u8g2.getStrWidth(list[id == 0 ? select + 1 : select - 1].select)); 554 | } 555 | else if (ui_index == M_PID) 556 | { 557 | len = abs(u8g2.getStrWidth(pid[select].select) - u8g2.getStrWidth(pid[id == 0 ? select + 1 : select - 1].select)); 558 | } 559 | uint8_t width_speed = ((len % step) == 0 ? (len / step) : (len / step + 1)); //计算步长 560 | *a -= width_speed; 561 | if (*a < *a_trg) *a = *a_trg; 562 | } 563 | else 564 | { 565 | return true;//到达目标 566 | } 567 | return false;//未到达 568 | } 569 | 570 | //进度条移动函数 571 | bool move_bar(uint8_t* a, uint8_t* a_trg) 572 | { 573 | if (*a < *a_trg) 574 | { 575 | uint8_t step = 16 / SPEED;//判断步数 576 | uint8_t width_speed = ((single_line_length % step) == 0 ? (single_line_length / step) : (single_line_length / step + 1)); //计算步长 577 | *a += width_speed; 578 | if (*a > *a_trg) *a = *a_trg;// 579 | } 580 | else if (*a > *a_trg) 581 | { 582 | uint8_t step = 16 / SPEED;//判断步数 583 | uint8_t width_speed = ((single_line_length % step) == 0 ? (single_line_length / step) : (single_line_length / step + 1)); //计算步长 584 | *a -= width_speed; 585 | if (*a < *a_trg) *a = *a_trg; 586 | } 587 | else 588 | { 589 | return true;//到达目标 590 | } 591 | return false;//未到达 592 | } 593 | 594 | //文字编辑函数 595 | void text_edit(bool dir, uint8_t index) 596 | { 597 | if (!dir) 598 | { 599 | if (name[index] >= 'A' && name[index] <= 'Z')//大写字母 600 | { 601 | if (name[index] == 'A') 602 | { 603 | name[index] = 'z'; 604 | } 605 | else 606 | { 607 | name[index] -= 1; 608 | } 609 | } 610 | else if (name[index] >= 'a' && name[index] <= 'z')//小写字母 611 | { 612 | if (name[index] == 'a') 613 | { 614 | name[index] = ' '; 615 | } 616 | else 617 | { 618 | name[index] -= 1; 619 | } 620 | } 621 | else 622 | { 623 | name[index] = 'Z'; 624 | } 625 | } 626 | else 627 | { 628 | if (name[index] >= 'A' && name[index] <= 'Z')//大写字母 629 | { 630 | if (name[index] == 'Z') 631 | { 632 | name[index] = ' '; 633 | } 634 | else 635 | { 636 | name[index] += 1; 637 | } 638 | } 639 | else if (name[index] >= 'a' && name[index] <= 'z')//小写字母 640 | { 641 | if (name[index] == 'z') 642 | { 643 | name[index] = 'A'; 644 | } 645 | else 646 | { 647 | name[index] += 1; 648 | } 649 | } 650 | else 651 | { 652 | name[index] = 'a'; 653 | } 654 | } 655 | Serial.println("NOW IS"); 656 | Serial.println(name); 657 | } 658 | 659 | //消失函数 660 | void disappear() 661 | { 662 | switch (disappear_step) 663 | { 664 | case 1: 665 | for (uint16_t i = 0; i < buf_len; ++i) 666 | { 667 | if (i % 2 == 0) buf_ptr[i] = buf_ptr[i] & 0x55; 668 | } 669 | break; 670 | case 2: 671 | for (uint16_t i = 0; i < buf_len; ++i) 672 | { 673 | if (i % 2 != 0) buf_ptr[i] = buf_ptr[i] & 0xAA; 674 | } 675 | break; 676 | case 3: 677 | for (uint16_t i = 0; i < buf_len; ++i) 678 | { 679 | if (i % 2 == 0) buf_ptr[i] = buf_ptr[i] & 0x00; 680 | } 681 | break; 682 | case 4: 683 | for (uint16_t i = 0; i < buf_len; ++i) 684 | { 685 | if (i % 2 != 0) buf_ptr[i] = buf_ptr[i] & 0x00; 686 | } 687 | break; 688 | default: 689 | ui_state = S_NONE; 690 | disappear_step = 0; 691 | break; 692 | } 693 | disappear_step++; 694 | } 695 | 696 | int compare(const void *a, const void *b) { 697 | return strcmp(((SELECT_LIST*)a)->select, ((SELECT_LIST*)b)->select); 698 | } 699 | int compare2(const void *elem1, const void *elem2) { 700 | SELECT_LIST* item1 = (SELECT_LIST*)elem1; 701 | SELECT_LIST* item2 = (SELECT_LIST*)elem2; 702 | 703 | // 判断如果元素为最后一个元素,则不进行排序 704 | if (item1 == &pid[pidSize-1] || item2 == &pid[pidSize-1]) { 705 | return 0; // 返回0表示两个元素相等 706 | } 707 | 708 | return strcmp(item1->select, item2->select); 709 | } 710 | 711 | void drawPage(int page) { 712 | u8g2.firstPage(); 713 | do { 714 | u8g2.setFont(u8g2_font_ncenB08_tr); 715 | for (int i = 0; i < DISPLAY_ROWS; i++) { 716 | int startIdx = page * DISPLAY_ROWS * CHARACTERS_PER_LINE + i * CHARACTERS_PER_LINE; 717 | int endIdx = startIdx + CHARACTERS_PER_LINE; 718 | if (endIdx > textContent.length()) endIdx = textContent.length(); 719 | if (startIdx < textContent.length()) { 720 | u8g2.setCursor(0, 10 + i * 10); 721 | u8g2.print(textContent.substring(startIdx, endIdx)); 722 | } 723 | } 724 | } while (u8g2.nextPage()); 725 | } 726 | 727 | /**************************界面显示*******************************/ 728 | 729 | void logo_ui_show()//显示logo 730 | { 731 | if (!SD.begin(7)) { 732 | Serial.println("SD 卡初始化失败!"); 733 | u8g2.firstPage(); 734 | do { 735 | u8g2.drawStr(0, 10, "No Find TF card !"); 736 | u8g2.drawStr(0, 23, "Please check it"); 737 | u8g2.drawStr(0, 36, "And restart..."); 738 | u8g2.drawStr(0, 49, "More see at yang17.site"); 739 | u8g2.drawStr(0, 62," ---KeyBox"); 740 | } while (u8g2.nextPage()); 741 | 742 | }else { 743 | u8g2.drawXBMP(0, 0, 128, 64, LOGO); 744 | } 745 | // for(uint16_t i=0;i 0) Kpid[pid_select] -= 0.01; 1024 | break; 1025 | case 1: 1026 | if (Kpid[pid_select] < PID_MAX) Kpid[pid_select] += 0.01; 1027 | break; 1028 | case 2: 1029 | ui_index = M_PID; 1030 | break; 1031 | default: 1032 | break; 1033 | } 1034 | } 1035 | pid_ui_show(); 1036 | for (uint16_t i = 0; i < buf_len; ++i) 1037 | { 1038 | buf_ptr[i] = buf_ptr[i] & (i % 2 == 0 ? 0x55 : 0xAA); 1039 | } 1040 | pid_edit_ui_show(); 1041 | } 1042 | void addPassword(char* mainsite,char* mainuser); 1043 | void pid_proc()//pid界面处理函数 1044 | { 1045 | 1046 | pid_ui_show(); 1047 | 1048 | if (key_msg.pressed) 1049 | { 1050 | key_msg.pressed = false; 1051 | Serial.println("-------------------"); 1052 | Serial.println(pid_select); 1053 | Serial.println(pidSize); 1054 | 1055 | switch (key_msg.id) 1056 | { 1057 | 1058 | // Serial.println(pid_select); 1059 | case 0: 1060 | // Serial.println("============="); 1061 | // Serial.println(pid_select); 1062 | if (pid_select < 1) break; 1063 | pid_select -= 1; 1064 | pid_line_y_trg -= pid_single_line_length; 1065 | if (pid_select < -(pid_y / 16)) 1066 | { 1067 | pid_y_trg += 16; 1068 | } 1069 | else 1070 | { 1071 | pid_box_y_trg -= 16; 1072 | } 1073 | break; 1074 | 1075 | 1076 | case 1: 1077 | 1078 | if ((pid_select + 2) > pidSize) break; 1079 | pid_select += 1; 1080 | pid_line_y_trg += pid_single_line_length; 1081 | if ((pid_select + 1) > (4 - pid_y / 16)) 1082 | { 1083 | pid_y_trg -= 16; 1084 | } 1085 | else 1086 | { 1087 | pid_box_y_trg += 16; 1088 | } 1089 | 1090 | 1091 | break; 1092 | case 2: 1093 | if (pid_select == pidSize-1) 1094 | { 1095 | if(modelchooese==5||modelchooese==4||modelchooese==6){ 1096 | modelchooese = 2; 1097 | } 1098 | 1099 | ui_index = M_SELECT; 1100 | ui_state = S_DISAPPEAR; 1101 | pid_x = 4; 1102 | pid_y = pid_y_trg = 0; 1103 | pid_select = 0; 1104 | pid_line_y = pid_line_y_trg = 1; 1105 | pid_box_y = pid_box_y_trg = 0; 1106 | pid_box_width = pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2; 1107 | } 1108 | else if(modelchooese==0){ 1109 | 1110 | //json 1111 | Serial.println("json in"); 1112 | UserIn = pid[pid_select].select; 1113 | addPassword(SiteIn, UserIn); 1114 | ui_index = M_ABOUT; 1115 | 1116 | } else if(modelchooese==3){ 1117 | 1118 | //json 1119 | Serial.println("totp in"); 1120 | UserIn = pid[pid_select].select; 1121 | addPassword(SiteIn, UserIn); 1122 | ui_index = M_ABOUT; 1123 | 1124 | }else if (modelchooese == 4) { 1125 | Serial.println("at seting--------------------------------------------!!!!!!!!!!!!!!"); 1126 | Serial.println(pid_select); 1127 | switch (pid_select) { 1128 | case 0: 1129 | display_time=60000; 1130 | modelchooese = 2; 1131 | ui_state = S_DISAPPEAR; 1132 | ui_index = M_SELECT; 1133 | break; 1134 | case 1: 1135 | display_time=300000; 1136 | modelchooese = 2; 1137 | ui_state = S_DISAPPEAR; 1138 | ui_index = M_SELECT; 1139 | break; 1140 | case 2: 1141 | display_time=0; 1142 | modelchooese = 2; 1143 | ui_state = S_DISAPPEAR; 1144 | ui_index = M_SELECT; 1145 | break; 1146 | // u8g2.setContrast(50); 1147 | } 1148 | }else if (modelchooese == 5) { 1149 | Serial.println("at seting--------------------------------------------!!!!!!!!!!!!!!"); 1150 | Serial.println(pid_select); 1151 | switch (pid_select) { 1152 | case 0: 1153 | u8g2.setContrast(0); 1154 | modelchooese = 2; 1155 | ui_state = S_DISAPPEAR; 1156 | ui_index = M_SELECT; 1157 | 1158 | 1159 | break; 1160 | 1161 | case 1: 1162 | u8g2.setContrast(100); 1163 | modelchooese = 2; 1164 | ui_state = S_DISAPPEAR; 1165 | ui_index = M_SELECT; 1166 | break; 1167 | 1168 | case 2: 1169 | u8g2.setContrast(200); 1170 | modelchooese = 2; 1171 | ui_state = S_DISAPPEAR; 1172 | ui_index = M_SELECT; 1173 | break; 1174 | 1175 | } 1176 | }else if (modelchooese == 6) { 1177 | Serial.println("at seting--------------------------------------------!!!!!!!!!!!!!!"); 1178 | Serial.println(pid_select); 1179 | switch (pid_select) { 1180 | case 0: 1181 | bleKeyboard.begin(); 1182 | modelchooese = 2; 1183 | ui_state = S_DISAPPEAR; 1184 | ui_index = M_SELECT; 1185 | 1186 | 1187 | break; 1188 | 1189 | case 1: 1190 | bleKeyboard.end(); 1191 | modelchooese = 2; 1192 | ui_state = S_DISAPPEAR; 1193 | ui_index = M_SELECT; 1194 | break; 1195 | 1196 | 1197 | 1198 | } 1199 | } 1200 | break; 1201 | default: 1202 | break; 1203 | } 1204 | pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2; 1205 | } 1206 | } 1207 | // 函数原型声明 1208 | void addUser(char* mainnowdisplay); 1209 | int justonece=0; 1210 | void select_proc(void)//选择界面处理重要的 1211 | { 1212 | if (key_msg.pressed) 1213 | { 1214 | key_msg.pressed = false; 1215 | switch (key_msg.id) 1216 | { 1217 | case 0: 1218 | if (ui_select < 1) break; 1219 | ui_select -= 1; 1220 | line_y_trg -= single_line_length; 1221 | if (ui_select < -(y / 16)) 1222 | { 1223 | y_trg += 16; 1224 | } 1225 | else 1226 | { 1227 | box_y_trg -= 16; 1228 | } 1229 | 1230 | break; 1231 | case 1: 1232 | if ((ui_select + 2) > listSize) break;//变更菜单数组个数3 1233 | ui_select += 1; 1234 | line_y_trg += single_line_length; 1235 | if ((ui_select + 1) > (4 - y / 16)) 1236 | { 1237 | y_trg -= 16; 1238 | } 1239 | else 1240 | { 1241 | box_y_trg += 16; 1242 | } 1243 | 1244 | break; 1245 | case 2: 1246 | Serial.println("ui_select"); 1247 | switch (ui_select) 1248 | { 1249 | case 0: //return 1250 | ui_state = S_DISAPPEAR; //S_DISAPPEAR; 1251 | ui_index = M_ICON;//M_LOGO; 1252 | break; 1253 | // case 1: //pid 1254 | // addUser(list[ui_select].select); 1255 | // ui_state = S_DISAPPEAR; 1256 | // ui_index = M_PID; 1257 | // break; 1258 | // case 2: //icon 1259 | // ui_state = S_DISAPPEAR; 1260 | // ui_index = M_ICON; 1261 | // break; 1262 | // case 3: //chart 1263 | // ui_state = S_DISAPPEAR; 1264 | // ui_index = M_CHART; 1265 | // break; 1266 | // case 4: //textedit 1267 | // ui_state = S_DISAPPEAR; 1268 | // ui_index = M_TEXT_EDIT; 1269 | // break; 1270 | // case 6: //about 1271 | // ui_state = S_DISAPPEAR; 1272 | // ui_index = M_ABOUT; 1273 | // break; 1274 | // case 7: //about 1275 | // ui_state = S_DISAPPEAR; 1276 | // ui_index = M_ABOUT; 1277 | // break; 1278 | // case 8: //about 1279 | // ui_state = S_DISAPPEAR; 1280 | // ui_index = M_ABOUT; 1281 | // break; 1282 | default: { 1283 | Serial.println("modelchooese"); 1284 | Serial.println(modelchooese); 1285 | if (modelchooese == 0) { 1286 | SiteIn = list[ui_select].select; 1287 | // if(justonece==0) {//防止重复向数组写入导致内存浪费溢出 1288 | addUser(list[ui_select].select); 1289 | // justonece+=1; 1290 | // } 1291 | pid_box_width = pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2;//两边各多2 1292 | ui_state = S_DISAPPEAR; 1293 | ui_index = M_PID; 1294 | break; 1295 | } else if (modelchooese == 1){ 1296 | // list[ui_select].select 1297 | //txt 1298 | ui_state = S_DISAPPEAR; 1299 | File file = SD.open("/"+(String)list[ui_select].select+".txt"); 1300 | if (file) { 1301 | while (file.available()) { 1302 | textContent += (char)file.read(); 1303 | } 1304 | file.close(); 1305 | } else { 1306 | Serial.println("无法打开文件"); 1307 | } 1308 | 1309 | // 计算总页数 1310 | totalPages = ceil((float)textContent.length() / (DISPLAY_ROWS * CHARACTERS_PER_LINE)); 1311 | 1312 | Serial.println("txt connte"); 1313 | Serial.println("txt in"); 1314 | 1315 | ui_index = M_TXTREAD; 1316 | 1317 | break; 1318 | } else if (modelchooese == 2) { 1319 | 1320 | Serial.print("NOW:"); 1321 | Serial.println(list[ui_select].select); 1322 | ui_state = S_DISAPPEAR; 1323 | ui_index = M_SET; 1324 | }else if (modelchooese == 3) { 1325 | SiteIn = list[ui_select].select; 1326 | // if(justonece==0) {//防止重复向数组写入导致内存浪费溢出 1327 | addUser(list[ui_select].select); 1328 | // justonece+=1; 1329 | // } 1330 | pid_box_width = pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2;//两边各多2 1331 | ui_state = S_DISAPPEAR; 1332 | ui_index = M_PID; 1333 | break; 1334 | // Serial.print("NOW:"); 1335 | // Serial.println(list[ui_select].select); 1336 | // ui_state = S_DISAPPEAR; 1337 | // ui_index = M_TOTF; 1338 | } 1339 | } 1340 | } 1341 | 1342 | //Serial.println("Btn2"); 1343 | default: 1344 | break; 1345 | } 1346 | Serial.println("ui_select------------------test"); 1347 | Serial.println(ui_select); 1348 | Serial.println(list[ui_select].select); 1349 | box_width_trg = u8g2.getStrWidth(list[ui_select].select) + x * 2; 1350 | } 1351 | select_ui_show(); 1352 | } 1353 | int WIFIst=0; 1354 | 1355 | long epochTime; 1356 | void setting(int select){ 1357 | switch (select) { 1358 | case 1: 1359 | free(pid); 1360 | pid = NULL; 1361 | pidSize=3;//此值自增1才可出返回设置//此值存在问题,需要修复!超出4则UI错误 1362 | modelchooese = 6; 1363 | 1364 | 1365 | pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 1366 | pid[0].select =strdup("ON BLE"); 1367 | pid[1].select =strdup("OFF BLE"); 1368 | pid[2].select =strdup("Back"); 1369 | pid_box_width = pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2;//两边各多2 1370 | ui_state = S_DISAPPEAR; 1371 | ui_index = M_PID; 1372 | break; 1373 | case 2://时间同步模式 1374 | // Serial.begin(115200); 1375 | u8g2.drawStr(2, 12, "Wait WIFI CONNECT!"); 1376 | if(WIFIst==0) { 1377 | WiFi.begin(ssid, password); 1378 | if (WiFi.status() == WL_CONNECTED) { 1379 | timeClient.forceUpdate(); 1380 | epochTime = timeClient.getEpochTime(); 1381 | WiFi.disconnect(); 1382 | u8g2.drawStr(2, 44, "Can not connect!"); 1383 | WIFIst=1; 1384 | }else{ 1385 | u8g2.drawStr(2, 44, "Was connect!"); 1386 | } 1387 | 1388 | } 1389 | Serial.println("Epoch Time: " + String(epochTime)); 1390 | 1391 | 1392 | 1393 | break; 1394 | case 3://密码设置模式 1395 | ui_state = S_DISAPPEAR; 1396 | ui_index = M_TEXT_EDIT; 1397 | break; 1398 | case 4: 1399 | free(pid); 1400 | pid = NULL; 1401 | pidSize=4;//此值自增1才可出返回设置//此值存在问题,需要修复!超出4则UI错误 1402 | modelchooese = 5; 1403 | 1404 | 1405 | pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 1406 | pid[0].select =strdup("10%"); 1407 | 1408 | // pid[2].select =strdup("10min");//未知,缺少size函数 1409 | pid[1].select =strdup("50%"); 1410 | 1411 | pid[2].select =strdup("100%"); 1412 | pid[3].select =strdup("Back"); 1413 | pid_box_width = pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2;//两边各多2 1414 | ui_state = S_DISAPPEAR; 1415 | ui_index = M_PID; 1416 | break; 1417 | 1418 | case 5://息屏时长设置(该功能有待完善,主要体现在息屏时间判断不完善) 1419 | free(pid); 1420 | pid = NULL; 1421 | pidSize=4;//此值自增1才可出返回设置 1422 | 1423 | modelchooese=4; 1424 | 1425 | pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 1426 | pid[0].select =strdup("1min"); 1427 | pid[1].select =strdup("5min"); 1428 | // pid[2].select =strdup("10min");//未知,缺少size函数 1429 | pid[2].select =strdup("Never"); 1430 | pid[3].select =strdup("Back"); 1431 | pid_box_width = pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2;//两边各多2 1432 | ui_state = S_DISAPPEAR; 1433 | ui_index = M_PID; 1434 | break; 1435 | case 6://升级功能(待实现) 1436 | // ui_state = S_DISAPPEAR; 1437 | u8g2.drawStr(2,12,"Not Find New DATA !"); 1438 | // u8g2.drawStr(2,28,"FLASH : 4MB"); 1439 | u8g2.drawStr(2,44,"Press any key go back"); 1440 | // u8g2.drawStr(2,60,"Firmware : V3.0"); 1441 | break; 1442 | case 7://展示设备信息 1443 | ui_state = S_DISAPPEAR; 1444 | ui_index = M_ABOUTDEV; 1445 | break; 1446 | default: 1447 | Serial.println("now is default"); 1448 | break; 1449 | } 1450 | 1451 | } 1452 | void set_proc(){ 1453 | setting(ui_select); 1454 | Serial.println("txgog11111111111111ogote"); 1455 | if (key_msg.pressed) 1456 | { 1457 | key_msg.pressed = false; 1458 | switch (key_msg.id) 1459 | { 1460 | case 2: { 1461 | //按键操作已经在setting内实现 1462 | // writeCSV();存在危险操作,建议提高延迟,否则易损卡 1463 | } 1464 | default: 1465 | ui_state = S_DISAPPEAR; 1466 | ui_index = M_SELECT; 1467 | 1468 | break; 1469 | 1470 | } 1471 | } 1472 | 1473 | } 1474 | void black_proc(){ 1475 | 1476 | // setting(ui_select); 1477 | // Serial.println("txgog11111111111111ogote"); 1478 | if (key_msg.pressed) 1479 | { 1480 | key_msg.pressed = false; 1481 | switch (key_msg.id) 1482 | { 1483 | case 2: { 1484 | 1485 | // writeCSV();存在危险操作,建议提高延迟,否则易损卡 1486 | } 1487 | default: 1488 | ui_state = S_DISAPPEAR; 1489 | ui_index = M_LOGO; 1490 | 1491 | break; 1492 | 1493 | } 1494 | } 1495 | 1496 | } 1497 | long GMT; 1498 | 1499 | char code[6]; 1500 | void TOTF_proc(char* site, char* totpkey) { 1501 | TOTP totp = TOTP(); 1502 | // 调整大小以容纳空终止符 1503 | char *newCode = totp.getCode(totpkey, 30, timeClient.getEpochTime()); 1504 | 1505 | // 检查 newCode 是否有效 1506 | 1507 | strcpy(code, newCode); 1508 | Serial.println(GMT); 1509 | Serial.print("---> CODE["); 1510 | Serial.print(code); 1511 | 1512 | int screenWidth = u8g2.getWidth(); 1513 | int textWidth = u8g2.getStrWidth(site); 1514 | int x = (screenWidth - textWidth) / 2; 1515 | int y = 20; // 垂直位置 1516 | int textWidth2 = u8g2.getStrWidth(code); 1517 | int x2 = (screenWidth - textWidth2) / 2; 1518 | 1519 | u8g2.drawStr(x, y, site); 1520 | u8g2.drawStr(x2, y + 20, code); 1521 | // bleKeyboard.print(code); 1522 | // 连接到 Wi-Fi 1523 | 1524 | Serial.print("---> CODE["); 1525 | 1526 | } 1527 | 1528 | void allcount(); 1529 | void addSiteDataToArr(); 1530 | void icon_proc(void)//icon界面处理 1531 | { 1532 | icon_ui_show(); 1533 | if (key_msg.pressed) 1534 | { 1535 | key_msg.pressed = false; 1536 | switch (key_msg.id) 1537 | { 1538 | case 1: 1539 | if (icon_select != (icon_num - 1)) 1540 | { 1541 | icon_select += 1; 1542 | app_y_trg += 16; 1543 | icon_x_trg -= ICON_SPACE; 1544 | } 1545 | break; 1546 | case 0: 1547 | 1548 | if (icon_select != 0) 1549 | { 1550 | icon_select -= 1; 1551 | app_y_trg -= 16; 1552 | icon_x_trg += ICON_SPACE; 1553 | } 1554 | break; 1555 | case 2://2代表按下Mid按键 1556 | 1557 | 1558 | switch (icon_select) { 1559 | case 0: ui_state = S_DISAPPEAR;//主界面 1560 | ui_index = M_LOGO; 1561 | break; 1562 | case 1: {//密钥模式,用于展示TF卡内的json格式密钥文件 1563 | modelchooese=0; 1564 | allcount(); 1565 | addSiteDataToArr(); 1566 | list[0].select = strdup("HOME");//插入主界面返回按键,此按键应当固定于数组首位 1567 | 1568 | box_width = box_width_trg = u8g2.getStrWidth(list[ui_select].select) + x * 2;//两边各多2 1569 | 1570 | // pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 1571 | // pid[0].select = strdup("main"); 1572 | // 动态分配内存以存储结构体数组 1573 | 1574 | qsort(list + 1, listSize - 1, sizeof(SELECT_LIST), compare); 1575 | 1576 | // 在串口上打印按照字母顺序排序后的结果 1577 | for (int i = 0; i < listSize; i++) { 1578 | Serial.println(list[i].select); 1579 | } 1580 | ui_state = S_DISAPPEAR; 1581 | ui_index = M_SELECT; 1582 | 1583 | break; 1584 | } 1585 | case 2://TOTP模式,建议设计参考1,Webkey调用json 1586 | modelchooese=3; 1587 | allcount(); 1588 | addSiteDataToArr(); 1589 | list[0].select = strdup("HOME");//插入主界面返回按键,此按键应当固定于数组首位 1590 | 1591 | box_width = box_width_trg = u8g2.getStrWidth(list[ui_select].select) + x * 2;//两边各多2 1592 | 1593 | // pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 1594 | // pid[0].select = strdup("main"); 1595 | // 动态分配内存以存储结构体数组 1596 | 1597 | qsort(list + 1, listSize - 1, sizeof(SELECT_LIST), compare); 1598 | 1599 | // 在串口上打印按照字母顺序排序后的结果 1600 | for (int i = 0; i < listSize; i++) { 1601 | Serial.println(list[i].select); 1602 | } 1603 | ui_state = S_DISAPPEAR; 1604 | ui_index = M_SELECT; 1605 | 1606 | break; 1607 | case 3://文档模式,用于展示TF卡内的TXT文件及内容 1608 | // ui_state = S_DISAPPEAR; 1609 | // ui_index = M_IMPORT; 1610 | modelchooese=1; 1611 | allcount(); 1612 | addSiteDataToArr(); 1613 | list[0].select = strdup("HOME");//同1 1614 | 1615 | box_width = box_width_trg = u8g2.getStrWidth(list[ui_select].select) + x * 2;//两边各多2 1616 | 1617 | // pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 1618 | // pid[0].select = strdup("main"); 1619 | // 动态分配内存以存储结构体数组 1620 | 1621 | qsort(list + 1, listSize - 1, sizeof(SELECT_LIST), compare); 1622 | 1623 | // 在串口上打印按照字母顺序排序后的结果 1624 | for (int i = 0; i < listSize; i++) { 1625 | Serial.println(list[i].select); 1626 | } 1627 | ui_state = S_DISAPPEAR; 1628 | ui_index = M_SELECT; 1629 | 1630 | break; 1631 | case 4://设置模式(可进行方法归类) 1632 | // ui_state = S_DISAPPEAR; 1633 | // ui_index = M_IMPORT; 1634 | Serial.println("ui_select11"); 1635 | modelchooese=2; 1636 | listSize=8; 1637 | Serial.println("ui_select22"); 1638 | free(list); 1639 | list = NULL; 1640 | list = (SELECT_LIST*)malloc(listSize * sizeof(SELECT_LIST)); 1641 | list[0].select = strdup("HOME"); 1642 | list[1].select = strdup("BLE Connect"); 1643 | list[2].select = strdup("Updata Time"); 1644 | list[3].select = strdup("Password");//插入功能按键 1645 | list[4].select = strdup("Back light"); 1646 | list[5].select = strdup("Display Time"); 1647 | list[6].select = strdup("Updata"); 1648 | list[7].select = strdup("About"); 1649 | 1650 | Serial.println("ui_selectsadad"); 1651 | pid_box_width = pid_box_width_trg = u8g2.getStrWidth(pid[pid_select].select) + x * 2;//两边各多2 1652 | box_width = box_width_trg = u8g2.getStrWidth(list[ui_select].select) + x * 2;//两边各多2 1653 | Serial.println("ui_select33"); 1654 | // pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 1655 | // pid[0].select = strdup("main"); 1656 | // 动态分配内存以存储结构体数组 1657 | 1658 | // qsort(list + 1, listSize - 1, sizeof(SELECT_LIST), compare); 1659 | Serial.println("ui_select33"); 1660 | // 在串口上打印按照字母顺序排序后的结果 1661 | for (int i = 0; i < listSize; i++) { 1662 | Serial.println(list[i].select); 1663 | } 1664 | ui_state = S_DISAPPEAR; 1665 | ui_index = M_SELECT; 1666 | Serial.println("ui_select3366"); 1667 | break; 1668 | case 5://锁屏模式 1669 | if(Passwordis[0] != '\0'){//未设置密码时 1670 | passwordst=1; 1671 | } 1672 | ui_state = S_DISAPPEAR;//息屏 1673 | ui_index = M_BLACK; 1674 | break; 1675 | } 1676 | Serial.println("button press");//调试输出 1677 | Serial.println(icon_select); 1678 | Serial.println(icon_x); 1679 | Serial.println( app_y); 1680 | Serial.println("num to zero"); 1681 | icon_select = 0; 1682 | icon_x = icon_x_trg = 0; 1683 | app_y = app_y_trg = 0; 1684 | 1685 | 1686 | break; 1687 | default: 1688 | break; 1689 | } 1690 | } 1691 | } 1692 | 1693 | //void chart_proc()//chart界面处理函数 1694 | //{ 1695 | // chart_ui_show(); 1696 | // if (key_msg.pressed) 1697 | // { 1698 | // key_msg.pressed = false; 1699 | // ui_state = S_DISAPPEAR; 1700 | // ui_index = M_SELECT; 1701 | // frame_is_drawed = false;//退出后框架为未画状态 1702 | // chart_x = 0; 1703 | // } 1704 | //} 1705 | void passwordmode(){ 1706 | for (int i = 0; i < 6; i++) { 1707 | if (name[i] != '\0') {//输入不为空 1708 | 1709 | 1710 | if (passwordst == 0) {//未设置密码状态下设置密码 1711 | strcpy(Passwordis, name);//密码等于输入 1712 | passwordst=1; 1713 | ui_state = S_DISAPPEAR; 1714 | ui_index = M_LOGO; 1715 | }else if (passwordst == 1&&strcmp(name, Passwordis) == 0) {//设备解锁,存在密码切密码等于输入 1716 | passwordst=0; 1717 | ui_state = S_DISAPPEAR; 1718 | ui_index = M_ICON; 1719 | 1720 | }else if (passwordst == 1&&strcmp(name, Passwordis) != 0) {//密码错误,设备不解锁,存在密码,密码不等于输入 1721 | ui_state = S_DISAPPEAR; 1722 | ui_index = M_LOGO; 1723 | } 1724 | break; 1725 | 1726 | }else{//输入为空状态下 1727 | 1728 | 1729 | if (passwordst == 0) {//未设置密码 1730 | ui_state = S_DISAPPEAR; 1731 | ui_index = M_LOGO; 1732 | }else{//输入为空且设置密码状态下 1733 | // Passwordis[0]='\0';//首位为空 1734 | memset(name, '\0', sizeof(Passwordis));//密码初始化,取消密码设置 1735 | ui_state = S_DISAPPEAR; 1736 | ui_index = M_LOGO; 1737 | } 1738 | 1739 | } 1740 | } 1741 | } 1742 | void text_edit_proc() 1743 | { 1744 | // memset(name, '\0', sizeof(name)); 1745 | text_edit_ui_show(); 1746 | if (key_msg.pressed) 1747 | { 1748 | key_msg.pressed = false; 1749 | switch (key_msg.id) 1750 | { 1751 | case 0: 1752 | if (edit_flag) 1753 | { 1754 | //编辑 1755 | text_edit(false, edit_index); 1756 | } 1757 | else 1758 | { 1759 | if (edit_index == 0) 1760 | { 1761 | edit_index = name_len; 1762 | } 1763 | else 1764 | { 1765 | edit_index -= 1; 1766 | } 1767 | } 1768 | break; 1769 | case 1: 1770 | if (edit_flag) 1771 | { 1772 | //编辑 1773 | text_edit(true, edit_index); 1774 | } 1775 | else 1776 | { 1777 | if (edit_index == name_len) 1778 | { 1779 | edit_index = 0; 1780 | } 1781 | else 1782 | { 1783 | edit_index += 1; 1784 | } 1785 | } 1786 | break; 1787 | case 2: 1788 | if (edit_index == name_len) { 1789 | 1790 | 1791 | 1792 | passwordmode(); 1793 | edit_index = 0; 1794 | blink_flag = 0; 1795 | memset(name, '\0', 6); 1796 | } 1797 | else 1798 | { 1799 | edit_flag = !edit_flag; 1800 | } 1801 | break; 1802 | default: 1803 | 1804 | break; 1805 | } 1806 | } 1807 | } 1808 | void about_ui_show()//about界面 1809 | { 1810 | if(modelchooese==0) { 1811 | // std::string SiteStr = SiteIn; 1812 | Serial.println("PUSH---------"); 1813 | Serial.println(SiteIn); 1814 | Serial.println(UserIn); 1815 | Serial.println(passwordIn); 1816 | std::string SiteStr = SiteIn; 1817 | // Concatenate the strings 1818 | std::string SiteString = "Site: " + SiteStr; 1819 | std::string UserStr = UserIn; 1820 | 1821 | // Concatenate the strings 1822 | std::string UserString = "User: " + UserStr; 1823 | 1824 | u8g2.drawStr(2, 12, SiteString.c_str()); 1825 | u8g2.drawStr(2, 28, UserString.c_str()); 1826 | 1827 | u8g2.drawStr(2, 60, "---Press to Driver---"); 1828 | 1829 | }else if (modelchooese==3){ 1830 | 1831 | 1832 | TOTF_proc(SiteIn,passwordIn); 1833 | 1834 | } 1835 | 1836 | // u8g2.drawStr(2,12,"MCU : MEGA2560"); 1837 | // u8g2.drawStr(2,28,"FLASH : 256KB"); 1838 | // u8g2.drawStr(2,44,"SRAM : 8KB"); 1839 | // u8g2.drawStr(2,60,"EEPROM : 4KB"); 1840 | 1841 | } 1842 | void about_proc()//about界面处理函数 1843 | { 1844 | if (key_msg.pressed) { 1845 | 1846 | if (modelchooese == 0) {//预留蓝牙输入接口 1847 | if (bleKeyboard.isConnected()) { 1848 | Serial.println("Sending 'Hello world'..."); 1849 | bleKeyboard.print(UserIn); 1850 | } 1851 | key_msg.pressed = false; 1852 | ui_state = S_DISAPPEAR; 1853 | ui_index = M_ABOUT_pass; 1854 | } else if (modelchooese == 3) { 1855 | if (bleKeyboard.isConnected()) { 1856 | Serial.println("Sending 'Hello world'..."); 1857 | bleKeyboard.print(code); 1858 | } 1859 | key_msg.pressed = false; 1860 | 1861 | modelchooese = 3; 1862 | ui_state = S_DISAPPEAR; 1863 | ui_index = M_SELECT; 1864 | 1865 | 1866 | } else { 1867 | key_msg.pressed = false; 1868 | ui_state = S_DISAPPEAR; 1869 | ui_index = M_SELECT; 1870 | } 1871 | } 1872 | about_ui_show(); 1873 | } 1874 | void about_pass_ui_show(){ 1875 | std::string PasswordStr = passwordIn; 1876 | // Concatenate the strings 1877 | std::string PasswordString = "Password: " + PasswordStr; 1878 | u8g2.drawStr(2, 44, PasswordString.c_str()); 1879 | 1880 | } 1881 | void about_pass_proc(){ 1882 | if (key_msg.pressed) 1883 | { 1884 | key_msg.pressed = false; 1885 | switch (key_msg.id) 1886 | { 1887 | 1888 | default: 1889 | if(bleKeyboard.isConnected()) {//预留蓝牙输入接口 1890 | Serial.println("Sending 'Hello world'..."); 1891 | bleKeyboard.print(passwordIn); 1892 | } 1893 | ui_state = S_DISAPPEAR; 1894 | ui_index = M_SELECT; 1895 | break; 1896 | 1897 | } 1898 | } 1899 | about_pass_ui_show(); 1900 | } 1901 | void aboutdev_proc()//about界面处理函数 1902 | { 1903 | if (key_msg.pressed) 1904 | { 1905 | key_msg.pressed = false; 1906 | ui_state = S_DISAPPEAR; 1907 | ui_index = M_SELECT; 1908 | } 1909 | aboutdev_ui_show(); 1910 | } 1911 | void import_proc()//about界面处理函数 1912 | { 1913 | u8g2.setFont(u8g2_font_ncenB08_tr); 1914 | u8g2.setCursor(0, 10); 1915 | u8g2.drawStr(2,12,"PLEASE PUSH"); 1916 | u8g2.println("IF YOU ARE RIGHT"); 1917 | 1918 | if (key_msg.pressed) 1919 | { 1920 | key_msg.pressed = false; 1921 | switch (key_msg.id) 1922 | { 1923 | case 2: { 1924 | ui_state = S_DISAPPEAR; 1925 | 1926 | u8g2.firstPage(); 1927 | 1928 | u8g2.setFont(u8g2_font_ncenB08_tr); 1929 | u8g2.setCursor(0, 10); 1930 | u8g2.println("Now WILL RUN"); 1931 | 1932 | delay(5000); // 继续等待5秒 1933 | // writeCSV();存在危险操作,建议提高延迟,否则易损卡 1934 | } 1935 | default: 1936 | ui_state = S_DISAPPEAR; 1937 | ui_index = M_ICON; 1938 | break; 1939 | 1940 | } 1941 | } 1942 | // delay(5000); // 等待5秒 1943 | 1944 | 1945 | } 1946 | void txtred_proc(){ 1947 | 1948 | 1949 | Serial.println("txt wait"); 1950 | drawPage(currentPage); 1951 | Serial.print("当前页码: "); 1952 | Serial.println(currentPage); 1953 | // delay(200); 1954 | // delay(200); 1955 | 1956 | if (key_msg.pressed) 1957 | { 1958 | key_msg.pressed = false; 1959 | switch (key_msg.id) 1960 | { 1961 | case 0: { 1962 | currentPage--; 1963 | break; 1964 | // writeCSV();存在危险操作,建议提高延迟,否则易损卡 1965 | } 1966 | case 1: { 1967 | currentPage++; 1968 | if (currentPage >= totalPages) { 1969 | currentPage = 0; 1970 | } 1971 | break; 1972 | // writeCSV();存在危险操作,建议提高延迟,否则易损卡 1973 | } 1974 | case 2: 1975 | ui_state = S_DISAPPEAR; 1976 | ui_index = M_SELECT; 1977 | currentPage=0; 1978 | textContent=""; 1979 | 1980 | break; 1981 | 1982 | } 1983 | } 1984 | 1985 | } 1986 | 1987 | /********************************总的UI显示************************************/ 1988 | 1989 | void ui_proc()//总的UI进程 1990 | { 1991 | switch (ui_state) 1992 | { 1993 | case S_NONE: 1994 | if (ui_index != M_CHART) u8g2.clearBuffer(); 1995 | switch (ui_index) 1996 | { 1997 | case M_LOGO: 1998 | logo_proc(); 1999 | break; 2000 | case M_SELECT: 2001 | select_proc(); 2002 | break; 2003 | case M_PID: 2004 | pid_proc(); 2005 | break; 2006 | case M_ICON: 2007 | icon_proc(); 2008 | break; 2009 | // case M_CHART: 2010 | // chart_proc(); 2011 | // break; 2012 | case M_TEXT_EDIT: 2013 | text_edit_proc(); 2014 | break; 2015 | case M_PID_EDIT: 2016 | pid_edit_proc(); 2017 | break; 2018 | case M_ABOUT: 2019 | 2020 | about_proc(); 2021 | break; 2022 | case M_ABOUT_pass: 2023 | 2024 | about_pass_proc(); 2025 | break; 2026 | case M_ABOUTDEV: 2027 | 2028 | aboutdev_proc(); 2029 | break; 2030 | case M_IMPORT: 2031 | import_proc(); 2032 | break; 2033 | case M_TXTREAD: 2034 | txtred_proc(); 2035 | break; 2036 | case M_SET: 2037 | set_proc(); 2038 | break; 2039 | case M_BLACK: 2040 | black_proc(); 2041 | break; 2042 | // case M_TOTF: 2043 | // TOTF_proc(String site,String totpkey); 2044 | // break; 2045 | default: 2046 | break; 2047 | } 2048 | break; 2049 | case S_DISAPPEAR: 2050 | disappear(); 2051 | break; 2052 | default: 2053 | break; 2054 | } 2055 | u8g2.sendBuffer(); 2056 | } 2057 | 2058 | 2059 | // 比较函数,用于对字符串进行排序 2060 | 2061 | 2062 | void addUser(char* mainnowdisplay){ 2063 | free(pid); 2064 | pid = NULL; 2065 | Serial.println("Btn2----------------------"); 2066 | Serial.println(mainnowdisplay); 2067 | 2068 | String filePath; 2069 | if(modelchooese==0){ 2070 | filePath = String("/") + String(mainnowdisplay)+String(".web"); 2071 | }else if(modelchooese==3){ 2072 | filePath = String("/") + String(mainnowdisplay)+String(".totp"); 2073 | } 2074 | // 打开 data.json 文件 2075 | File jsonFile = SD.open(filePath); 2076 | if (!jsonFile) { 2077 | Serial.println("无法打开 data.json 文件"); 2078 | return; 2079 | } 2080 | 2081 | String jsonStr; 2082 | while (jsonFile.available()) { 2083 | char c = jsonFile.read(); 2084 | jsonStr += c; 2085 | } 2086 | 2087 | // 关闭文件 2088 | jsonFile.close(); 2089 | 2090 | // 解析JSON数据 2091 | DynamicJsonDocument doc(1024); 2092 | DeserializationError error = deserializeJson(doc, jsonStr); 2093 | 2094 | if (error) { 2095 | Serial.println("解析JSON失败"); 2096 | return; 2097 | } 2098 | int numx=0; 2099 | // 仅输出JSON键而不输出值 2100 | for (JsonPair keyValue : doc.as()) { 2101 | 2102 | numx++; 2103 | } 2104 | Serial.print("numx------------xxx: "); 2105 | Serial.println(numx); 2106 | 2107 | pidSize=numx+1;//此值自增1才可出返回设置 2108 | 2109 | 2110 | 2111 | pid = (SELECT_LIST*)malloc(pidSize * sizeof(SELECT_LIST)); 2112 | 2113 | int num=0; 2114 | // 仅输出JSON键而不输出值 2115 | for (JsonPair keyValue : doc.as()) { 2116 | Serial.print("键: "); 2117 | Serial.println(keyValue.key().c_str()); 2118 | pid[num].select =strdup(keyValue.key().c_str()); 2119 | num++; 2120 | } 2121 | pid[num].select =strdup("Back"); 2122 | qsort(pid, pidSize, sizeof(SELECT_LIST), compare2); 2123 | 2124 | // 在串口上打印按照字母顺序排序后的结果 2125 | // for (int i = 0; i < pidSize; i++) { 2126 | // Serial.println(pid[i].select); 2127 | // } 2128 | 2129 | // pid[4].select =strdup("keyVal"); 2130 | Serial.println( "pid[3].select"); 2131 | // Serial.println( pid[2].select); 2132 | // Serial.println( pid[3].select); 2133 | 2134 | } 2135 | 2136 | void addPassword(char* mainsite,char* mainuser){ 2137 | String filePath; 2138 | if(modelchooese==0){ 2139 | filePath = String("/") + String(mainsite)+String(".web"); 2140 | }else if(modelchooese==3){ 2141 | filePath = String("/") + String(mainsite)+String(".totp"); 2142 | } 2143 | // String filePath = String("/") + String(mainsite)+String(".web"); 2144 | // 打开 data.json 文件 2145 | File jsonFile = SD.open(filePath); 2146 | 2147 | if (!jsonFile) { 2148 | Serial.println("无法打开文件"); 2149 | return; 2150 | } 2151 | 2152 | // 读取文件内容 2153 | String jsonStr; 2154 | while (jsonFile.available()) { 2155 | char c = jsonFile.read(); 2156 | jsonStr += c; 2157 | } 2158 | 2159 | // 关闭文件 2160 | jsonFile.close(); 2161 | 2162 | // 解析 JSON 数据 2163 | DynamicJsonDocument doc(1024); 2164 | DeserializationError error = deserializeJson(doc, jsonStr); 2165 | 2166 | if (error) { 2167 | Serial.println("解析 JSON 失败"); 2168 | return; 2169 | } 2170 | Serial.println("read----"); 2171 | Serial.println(mainuser); 2172 | // 提取并输出 location 字段的值 2173 | const char* location = doc[mainuser]; 2174 | Serial.println("read----"); 2175 | Serial.println(location); 2176 | // Convert String to char* and store in Site 2177 | passwordIn = strdup(location); 2178 | Serial.println("password--------"); 2179 | Serial.println(passwordIn); 2180 | Serial.println("password--------"); 2181 | 2182 | 2183 | 2184 | } 2185 | 2186 | void allcount(){ 2187 | char* model=".web"; 2188 | if(modelchooese==0){ 2189 | model=".web"; 2190 | }else if(modelchooese==1){ 2191 | model=".txt"; 2192 | }else if(modelchooese==3){ 2193 | model=".totp"; 2194 | } 2195 | 2196 | File root = SD.open("/"); 2197 | int count=0; 2198 | while (true) { 2199 | File entry = root.openNextFile(); 2200 | if (!entry) { 2201 | // 没有更多文件 2202 | break; 2203 | } 2204 | 2205 | if (!entry.isDirectory() && entry.name()[0] != '.') { 2206 | String filename = entry.name(); 2207 | if (filename.endsWith( model)) { 2208 | count++; 2209 | } 2210 | } 2211 | 2212 | entry.close(); 2213 | } 2214 | 2215 | root.close(); 2216 | listSize=count+1; 2217 | } 2218 | void addSiteDataToArr() {//此函数提供方法使其全部网站保存在数组中,界面分类用 2219 | free(list); 2220 | list = NULL; 2221 | char* model=".web"; 2222 | if(modelchooese==0){ 2223 | model=".web"; 2224 | }else if(modelchooese==1){ 2225 | model=".txt"; 2226 | }else if(modelchooese==3){ 2227 | model=".totp"; 2228 | } 2229 | Serial.println(model); 2230 | Serial.println("read JSON Start:"); 2231 | File root = SD.open("/"); 2232 | int index = 0; // 用于追踪数组中的索引位置 2233 | 2234 | list = (SELECT_LIST*)malloc(listSize * sizeof(SELECT_LIST)); 2235 | int fileCount = 0;//此值传向list 数组长度 2236 | while (true) { 2237 | File entry = root.openNextFile(); 2238 | if (!entry) { 2239 | // 没有更多文件 2240 | Serial.println("entry"); 2241 | break; 2242 | } 2243 | 2244 | if (!entry.isDirectory() && entry.name()[0] != '.') { 2245 | const char* filename = entry.name(); 2246 | if (strstr(filename, model) != NULL) { 2247 | Serial.println(filename); 2248 | // const char* filename = "example.txt"; // 您的文件名 2249 | 2250 | int length = strlen(filename); 2251 | 2252 | 2253 | char* newFilename = new char[length]; // 创建动态分配的新字符串来存储较短的文件名 2254 | if(modelchooese==0) { 2255 | strncpy(newFilename, filename, length - 4); 2256 | newFilename[length - 4] = '\0'; // 添加字符串终止符 2257 | }else if(modelchooese==1){ 2258 | strncpy(newFilename, filename, length - 4); 2259 | newFilename[length - 4] = '\0'; // 添加字符串终止符 2260 | }else if(modelchooese==3){ 2261 | strncpy(newFilename, filename, length - 5); 2262 | newFilename[length - 5] = '\0'; // 添加字符串终止符 2263 | } 2264 | list[index+1].select = strdup(newFilename); 2265 | index++; 2266 | } 2267 | } 2268 | 2269 | entry.close(); 2270 | } 2271 | 2272 | } 2273 | void setup() {//加大审查,尽量关闭sd卡使用时间延长寿命 2274 | Serial.begin(115200); 2275 | Serial.println("Starting BLE work!"); 2276 | 2277 | 2278 | 2279 | // 写入数据到 data.json 文件 2280 | // writeJSONToFile(); 2281 | 2282 | // 读取并打印 SD 卡上的所有 JSON 文件 2283 | // readAndPrintAllJSONFiles(); 2284 | // readJSONFile() ; 2285 | 2286 | Serial.println("entry"); 2287 | 2288 | //Wire.begin(21,22,400000); 2289 | pinMode(BTN0, INPUT_PULLUP); 2290 | pinMode(BTN1, INPUT_PULLUP); 2291 | pinMode(BTN2, INPUT_PULLUP); 2292 | key_init(); 2293 | 2294 | u8g2.setBusClock(800000); 2295 | u8g2.begin(); 2296 | u8g2.setFont(u8g2_font_unifont_t_chinese1); 2297 | //u8g2.setContrast(10); 2298 | 2299 | buf_ptr = u8g2.getBufferPtr();//拿到buffer首地址 2300 | buf_len = 8 * u8g2.getBufferTileHeight() * u8g2.getBufferTileWidth(); 2301 | 2302 | x = 4; 2303 | y = y_trg = 0; 2304 | pid_x = 4; 2305 | pid_y = pid_y_trg = 0; 2306 | line_y = line_y_trg = 1; 2307 | pid_line_y = pid_line_y_trg = 1; 2308 | ui_select = pid_select = icon_select = 0; 2309 | icon_x = icon_x_trg = 0; 2310 | app_y = app_y_trg = 0; 2311 | 2312 | u8g2.setFont(u8g2_font_ncenB08_tr); 2313 | ui_index = M_LOGO; 2314 | // ui_index=M_TEXT_EDIT; 2315 | ui_state = S_NONE; 2316 | Serial.println("entry2"); 2317 | } 2318 | unsigned long previousMillis = 0; 2319 | //const long interval = 60000; // 5 minutes in milliseconds 2320 | void loop() { 2321 | // Serial.println("entry3"); 2322 | unsigned long currentMillis = millis(); 2323 | if(display_time!=0) { 2324 | if (currentMillis - previousMillis >= display_time) { 2325 | // 在这里执行您想要每隔5分钟执行的任务 2326 | // 例如,您可以添加要执行的代码块或调用函数 2327 | 2328 | ui_state = S_DISAPPEAR; 2329 | setting(ui_select); 2330 | Serial.println("txgog11111111111111ogote"); 2331 | if (key_msg.pressed) { 2332 | key_msg.pressed = false; 2333 | switch (key_msg.id) { 2334 | case 2: { 2335 | // writeCSV();存在危险操作,建议提高延迟,否则易损卡 2336 | } 2337 | default: 2338 | previousMillis = currentMillis; 2339 | ui_state = S_DISAPPEAR; 2340 | ui_index = M_SELECT; 2341 | break; 2342 | } 2343 | } 2344 | // 更新上一次执行任务的时间戳 2345 | } 2346 | } 2347 | key_scan(); 2348 | ui_proc(); 2349 | } -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | -------------------------------------------------------------------------------- /tinyuf2-partitions-4MB.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs, data, nvs, 0x9000, 0x5000, 3 | otadata, data, ota, 0xe000, 0x2000, 4 | app0, app, ota_0, 0x10000, 0x200000, 5 | spiffs, data, spiffs, 0x210000,0x1E0000, 6 | coredump, data, coredump,0x3F0000,0x10000, --------------------------------------------------------------------------------