From 15a53ae36a8b5f9a571e109fd97c860efa5c8e44 Mon Sep 17 00:00:00 2001 From: notrynohigh Date: Wed, 11 Dec 2024 01:11:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96UID?= =?UTF-8?q?=E5=92=8C=E5=86=99=E5=85=A5SN=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/c_cpp_properties.json | 18 + .vscode/launch.json | 24 ++ .vscode/settings.json | 59 ++++ BabyOS_Protocol/BabyOS_Protocol.pro | 2 + BabyOS_Protocol/BabyOS_Protocol.pro.user | 2 +- BabyOS_Protocol/algo_md5.c | 410 +++++++++++++++++++++++ BabyOS_Protocol/algo_md5.h | 85 +++++ BabyOS_Protocol/mainwindow.cpp | 56 ++++ BabyOS_Protocol/mainwindow.h | 4 + BabyOS_Protocol/mainwindow.ui | 58 +++- README.md | 30 ++ exe/BabyOS_Protocol.exe | Bin 66560 -> 73216 bytes 12 files changed, 736 insertions(+), 12 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 BabyOS_Protocol/algo_md5.c create mode 100644 BabyOS_Protocol/algo_md5.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..25a615f --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "windows-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "C:/Users/lkl92/Documents/tools/w64devkit/bin/gcc.exe", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x64", + "compilerArgs": [ + "" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..192b0a3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "c:/Users/lkl92/Documents/work/BabyOS/BabyOS_Protocol/BabyOS_Protocol", + "program": "c:/Users/lkl92/Documents/work/BabyOS/BabyOS_Protocol/BabyOS_Protocol/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..bb879da --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,59 @@ +{ + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false +} \ No newline at end of file diff --git a/BabyOS_Protocol/BabyOS_Protocol.pro b/BabyOS_Protocol/BabyOS_Protocol.pro index b53c43b..7edebfa 100644 --- a/BabyOS_Protocol/BabyOS_Protocol.pro +++ b/BabyOS_Protocol/BabyOS_Protocol.pro @@ -18,6 +18,7 @@ DEFINES += QT_DEPRECATED_WARNINGS SOURCES += \ algo_crc.c \ + algo_md5.c \ b_mod_utc.c \ b_protocol.c \ main.cpp \ @@ -25,6 +26,7 @@ SOURCES += \ uartclass.cpp HEADERS += \ + algo_md5.h \ b_mod_utc.h \ b_protocol.h \ mainwindow.h \ diff --git a/BabyOS_Protocol/BabyOS_Protocol.pro.user b/BabyOS_Protocol/BabyOS_Protocol.pro.user index 7a670c2..6c1ded4 100644 --- a/BabyOS_Protocol/BabyOS_Protocol.pro.user +++ b/BabyOS_Protocol/BabyOS_Protocol.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/BabyOS_Protocol/algo_md5.c b/BabyOS_Protocol/algo_md5.c new file mode 100644 index 0000000..61dd207 --- /dev/null +++ b/BabyOS_Protocol/algo_md5.c @@ -0,0 +1,410 @@ +/** + *! + * \file algo_md5.c + * \version v0.0.1 + * \date 2020/05/13 + * \author Bean(notrynohigh@outlook.com) + ******************************************************************************* + * @attention + * + * Copyright (c) 2020 Bean + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************* + */ + +/*Includes ----------------------------------------------*/ + +#include "algo_md5.h" + +#include + + +#if (defined(_ALGO_MD5_ENABLE) && (_ALGO_MD5_ENABLE == 1)) +/** + * \addtogroup ALGORITHM + * \{ + */ + +/** + * \addtogroup MD5 + * \{ + */ + +/** + * \defgroup MD5_Private_TypesDefinitions + * \{ + */ + +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + uint8_t buffer[64]; /*!< data block being processed */ +} md5_context; + +/** + * \} + */ + +/** + * \defgroup MD5_Private_Defines + * \{ + */ + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n, b, i) \ + { \ + (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | \ + ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \ + } +#endif + +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n, b, i) \ + { \ + (b)[(i)] = (uint8_t)((n)); \ + (b)[(i) + 1] = (uint8_t)((n) >> 8); \ + (b)[(i) + 2] = (uint8_t)((n) >> 16); \ + (b)[(i) + 3] = (uint8_t)((n) >> 24); \ + } +#endif + +/** + * \} + */ + +/** + * \defgroup MD5_Private_Variables + * \{ + */ +const char hexstring[] = "0123456789abcdef"; +/** + * \} + */ + +/** + * \defgroup MD5_Private_Functions + * \{ + */ + +/* + * MD5 context setup + */ +static void md5_starts(md5_context* ctx) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +static void md5_process(md5_context* ctx, const uint8_t data[64]) +{ + uint32_t X[16], A, B, C, D; + + GET_ULONG_LE(X[0], data, 0); + GET_ULONG_LE(X[1], data, 4); + GET_ULONG_LE(X[2], data, 8); + GET_ULONG_LE(X[3], data, 12); + GET_ULONG_LE(X[4], data, 16); + GET_ULONG_LE(X[5], data, 20); + GET_ULONG_LE(X[6], data, 24); + GET_ULONG_LE(X[7], data, 28); + GET_ULONG_LE(X[8], data, 32); + GET_ULONG_LE(X[9], data, 36); + GET_ULONG_LE(X[10], data, 40); + GET_ULONG_LE(X[11], data, 44); + GET_ULONG_LE(X[12], data, 48); + GET_ULONG_LE(X[13], data, 52); + GET_ULONG_LE(X[14], data, 56); + GET_ULONG_LE(X[15], data, 60); + +#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a, b, c, d, k, s, t) \ + { \ + a += F(b, c, d) + X[k] + t; \ + a = S(a, s) + b; \ + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) (z ^ (x & (y ^ z))) + + P(A, B, C, D, 0, 7, 0xD76AA478); + P(D, A, B, C, 1, 12, 0xE8C7B756); + P(C, D, A, B, 2, 17, 0x242070DB); + P(B, C, D, A, 3, 22, 0xC1BDCEEE); + P(A, B, C, D, 4, 7, 0xF57C0FAF); + P(D, A, B, C, 5, 12, 0x4787C62A); + P(C, D, A, B, 6, 17, 0xA8304613); + P(B, C, D, A, 7, 22, 0xFD469501); + P(A, B, C, D, 8, 7, 0x698098D8); + P(D, A, B, C, 9, 12, 0x8B44F7AF); + P(C, D, A, B, 10, 17, 0xFFFF5BB1); + P(B, C, D, A, 11, 22, 0x895CD7BE); + P(A, B, C, D, 12, 7, 0x6B901122); + P(D, A, B, C, 13, 12, 0xFD987193); + P(C, D, A, B, 14, 17, 0xA679438E); + P(B, C, D, A, 15, 22, 0x49B40821); + +#undef F + +#define F(x, y, z) (y ^ (z & (x ^ y))) + + P(A, B, C, D, 1, 5, 0xF61E2562); + P(D, A, B, C, 6, 9, 0xC040B340); + P(C, D, A, B, 11, 14, 0x265E5A51); + P(B, C, D, A, 0, 20, 0xE9B6C7AA); + P(A, B, C, D, 5, 5, 0xD62F105D); + P(D, A, B, C, 10, 9, 0x02441453); + P(C, D, A, B, 15, 14, 0xD8A1E681); + P(B, C, D, A, 4, 20, 0xE7D3FBC8); + P(A, B, C, D, 9, 5, 0x21E1CDE6); + P(D, A, B, C, 14, 9, 0xC33707D6); + P(C, D, A, B, 3, 14, 0xF4D50D87); + P(B, C, D, A, 8, 20, 0x455A14ED); + P(A, B, C, D, 13, 5, 0xA9E3E905); + P(D, A, B, C, 2, 9, 0xFCEFA3F8); + P(C, D, A, B, 7, 14, 0x676F02D9); + P(B, C, D, A, 12, 20, 0x8D2A4C8A); + +#undef F + +#define F(x, y, z) (x ^ y ^ z) + + P(A, B, C, D, 5, 4, 0xFFFA3942); + P(D, A, B, C, 8, 11, 0x8771F681); + P(C, D, A, B, 11, 16, 0x6D9D6122); + P(B, C, D, A, 14, 23, 0xFDE5380C); + P(A, B, C, D, 1, 4, 0xA4BEEA44); + P(D, A, B, C, 4, 11, 0x4BDECFA9); + P(C, D, A, B, 7, 16, 0xF6BB4B60); + P(B, C, D, A, 10, 23, 0xBEBFBC70); + P(A, B, C, D, 13, 4, 0x289B7EC6); + P(D, A, B, C, 0, 11, 0xEAA127FA); + P(C, D, A, B, 3, 16, 0xD4EF3085); + P(B, C, D, A, 6, 23, 0x04881D05); + P(A, B, C, D, 9, 4, 0xD9D4D039); + P(D, A, B, C, 12, 11, 0xE6DB99E5); + P(C, D, A, B, 15, 16, 0x1FA27CF8); + P(B, C, D, A, 2, 23, 0xC4AC5665); + +#undef F + +#define F(x, y, z) (y ^ (x | ~z)) + + P(A, B, C, D, 0, 6, 0xF4292244); + P(D, A, B, C, 7, 10, 0x432AFF97); + P(C, D, A, B, 14, 15, 0xAB9423A7); + P(B, C, D, A, 5, 21, 0xFC93A039); + P(A, B, C, D, 12, 6, 0x655B59C3); + P(D, A, B, C, 3, 10, 0x8F0CCC92); + P(C, D, A, B, 10, 15, 0xFFEFF47D); + P(B, C, D, A, 1, 21, 0x85845DD1); + P(A, B, C, D, 8, 6, 0x6FA87E4F); + P(D, A, B, C, 15, 10, 0xFE2CE6E0); + P(C, D, A, B, 6, 15, 0xA3014314); + P(B, C, D, A, 13, 21, 0x4E0811A1); + P(A, B, C, D, 4, 6, 0xF7537E82); + P(D, A, B, C, 11, 10, 0xBD3AF235); + P(C, D, A, B, 2, 15, 0x2AD7D2BB); + P(B, C, D, A, 9, 21, 0xEB86D391); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} + +/* + * MD5 process buffer + */ +static void md5_update(md5_context* ctx, const uint8_t* input, int ilen) +{ + int fill; + uint32_t left; + + if (ilen <= 0) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if (ctx->total[0] < (uint32_t)ilen) + ctx->total[1]++; + + if (left && ilen >= fill) + { + memcpy((void*)(ctx->buffer + left), input, fill); + md5_process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while (ilen >= 64) + { + md5_process(ctx, input); + input += 64; + ilen -= 64; + } + + if (ilen > 0) + { + memcpy((void*)(ctx->buffer + left), input, ilen); + } +} + +static const uint8_t md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +/* + * MD5 final digest + */ +static void md5_finish(md5_context* ctx, uint8_t output[16]) +{ + uint32_t last, padn; + uint32_t high, low; + uint8_t msglen[8]; + + high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + PUT_ULONG_LE(low, msglen, 0); + PUT_ULONG_LE(high, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + md5_update(ctx, md5_padding, padn); + md5_update(ctx, msglen, 8); + + PUT_ULONG_LE(ctx->state[0], output, 0); + PUT_ULONG_LE(ctx->state[1], output, 4); + PUT_ULONG_LE(ctx->state[2], output, 8); + PUT_ULONG_LE(ctx->state[3], output, 12); +} + +/* + * output = MD5( input buffer ) + */ +static void md5(uint8_t* input, int ilen, uint8_t output[16]) +{ + md5_context ctx; + memset(&ctx, 0, sizeof(md5_context)); + md5_starts(&ctx); + md5_update(&ctx, input, ilen); + md5_finish(&ctx, output); +} + +/** + * \} + */ + +/** + * \addtogroup MD5_Exported_Functions + * \{ + */ + +void md5_16(uint8_t* input, uint32_t ilen, uint8_t output[16]) +{ + uint8_t out[16], i = 0; + if (input == NULL || ilen == 0) + { + return; + } + md5(input, ilen, out); + for (i = 0; i < 8; i++) + { + output[i * 2] = hexstring[(out[4 + i] & 0xf0) >> 4]; + output[i * 2 + 1] = hexstring[(out[4 + i] & 0x0f) >> 0]; + } +} + +void md5_32(uint8_t* input, uint32_t ilen, uint8_t output[32]) +{ + uint8_t out[16], i = 0; + if (input == NULL || ilen == 0) + { + return; + } + md5(input, ilen, out); + for (i = 0; i < 16; i++) + { + output[i * 2] = hexstring[(out[i] & 0xf0) >> 4]; + output[i * 2 + 1] = hexstring[(out[i] & 0x0f) >> 0]; + } +} + +void md5_hex_16(uint8_t* input, uint32_t ilen, uint8_t output[16]) +{ + if (input == NULL || ilen == 0) + { + return; + } + md5(input, ilen, output); +} + +void md5_hex_8(uint8_t* input, uint32_t ilen, uint8_t output[8]) +{ + uint8_t out[16], i = 0; + if (input == NULL || ilen == 0) + { + return; + } + md5(input, ilen, out); + for (i = 0; i < 8; i++) + { + output[i] = out[4 + i]; + } +} + +/** + * \} + */ + +/** + * \} + */ + +/** + * \} + */ + +#endif + +/************************ Copyright (c) 2020 Bean *****END OF FILE****/ diff --git a/BabyOS_Protocol/algo_md5.h b/BabyOS_Protocol/algo_md5.h new file mode 100644 index 0000000..7433942 --- /dev/null +++ b/BabyOS_Protocol/algo_md5.h @@ -0,0 +1,85 @@ +/** + *! + * \file algo_md5.h + * \version v0.0.1 + * \date 2020/04/27 + * \author Bean(notrynohigh@outlook.com) + ******************************************************************************* + * @attention + * + * Copyright (c) 2020 Bean + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************* + */ +#ifndef __ALGO_MD5_H__ +#define __ALGO_MD5_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define _ALGO_MD5_ENABLE 1 + +#if (defined(_ALGO_MD5_ENABLE) && (_ALGO_MD5_ENABLE == 1)) + +/** + * \addtogroup ALGORITHM + * \{ + */ + +/** + * \addtogroup MD5 + * \{ + */ + +/** + * \defgroup SORT_Exported_Functions + * \{ + */ + +// 结果未小写的字符串 +void md5_16(uint8_t* input, uint32_t ilen, uint8_t output[16]); +void md5_32(uint8_t* input, uint32_t ilen, uint8_t output[32]); + +// 结果为十六进制数组 +void md5_hex_8(uint8_t* input, uint32_t ilen, uint8_t output[8]); +void md5_hex_16(uint8_t* input, uint32_t ilen, uint8_t output[16]); + +/** + * \} + */ + +/** + * \} + */ + +/** + * \} + */ + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/BabyOS_Protocol/mainwindow.cpp b/BabyOS_Protocol/mainwindow.cpp index b0c7705..45c3f01 100644 --- a/BabyOS_Protocol/mainwindow.cpp +++ b/BabyOS_Protocol/mainwindow.cpp @@ -11,6 +11,7 @@ #include "uartclass.h" #include "ui_mainwindow.h" #include "algo_crc.h" +#include "algo_md5.h" uartClass uartModule; MainWindow *tmpClass; @@ -26,6 +27,8 @@ extern "C" int Dispatch(bProtoID_t id, uint8_t cmd, uint8_t *param, bProtoLen_t #define CMD_UPGRADE_DATA (0x4) #define CMD_UPGRADE_RESULT (0x5) #define CMD_TRANS_FILE (0x6) +#define CMD_GET_UID (0x7) +#define CMD_SET_SN (0x8) /** * \brief 协议参数对应的数据结构 */ @@ -272,6 +275,11 @@ int MainWindow::AckFwInfo() /** * \brief 协议解析的分发函数,在此函数,根据指令执行对应的操作 */ + +uint8_t mcu_uid[64]; +uint8_t uid_len = 0; + + int Dispatch(bProtoID_t id, uint8_t cmd, uint8_t *param, bProtoLen_t param_len) { uint8_t result = 0; @@ -304,6 +312,12 @@ int Dispatch(bProtoID_t id, uint8_t cmd, uint8_t *param, bProtoLen_t param_len) //tmpClass->AckFwInfo(); } break; + case CMD_GET_UID: + { + uid_len = param[0]; + memcpy(mcu_uid, param + 1, uid_len); + } + break; } return 0; } @@ -515,3 +529,45 @@ void MainWindow::on_openfoldButton_clicked() ui->recTEXT->append(bin_info); } } + +void MainWindow::on_pushButtonGetUID_clicked() +{ + uint8_t table[128]; + int len = 0; + len = bProtocolPack(protocol_n, 0xFFFFFFFF, CMD_GET_UID, NULL, 0, table); + if (ui->encryptBox->isChecked() == true) + { + _bProtocolEncrypt(table, len); + } + uartModule.uartSendBuff(table, len); +} + +void MainWindow::on_pushButtonSetSN_clicked() +{ + uint8_t table[128]; + int len = 0; + uint8_t md5_val[16]; + uint8_t sn_table[64]; + uint8_t orval = 0; + orval = ui->lineEditOrval->text().toInt(); + md5_hex_16(mcu_uid, uid_len, md5_val); + sn_table[0] = sizeof(md5_val); + for (int i = 0; i < sizeof(md5_val); i++) + { + sn_table[1 + i] = md5_val[i] | orval; + } + + QString sn_string; + for (int i = 0; i < (sizeof(md5_val) + 1); ++i) { + sn_string.append(QString("%1 ").arg(sn_table[i], 2, 16, QChar('0')).toUpper()); + } + sn_string = sn_string.trimmed(); + ui->recTEXT->append("sn:" + sn_string); + + len = bProtocolPack(protocol_n, 0xFFFFFFFF, CMD_SET_SN, sn_table, sizeof(md5_val) + 1, table); + if (ui->encryptBox->isChecked() == true) + { + _bProtocolEncrypt(table, len); + } + uartModule.uartSendBuff(table, len); +} diff --git a/BabyOS_Protocol/mainwindow.h b/BabyOS_Protocol/mainwindow.h index 15c78d6..10cf97a 100644 --- a/BabyOS_Protocol/mainwindow.h +++ b/BabyOS_Protocol/mainwindow.h @@ -49,6 +49,10 @@ private slots: void on_openfoldButton_clicked(); + void on_pushButtonGetUID_clicked(); + + void on_pushButtonSetSN_clicked(); + private: Ui::MainWindow *ui; QTimer *quartTimer; diff --git a/BabyOS_Protocol/mainwindow.ui b/BabyOS_Protocol/mainwindow.ui index 33f37f5..c2482a7 100644 --- a/BabyOS_Protocol/mainwindow.ui +++ b/BabyOS_Protocol/mainwindow.ui @@ -7,19 +7,19 @@ 0 0 800 - 600 + 800 800 - 600 + 800 800 - 600 + 800 @@ -65,10 +65,10 @@ - 10 - 190 + 20 + 250 761 - 321 + 431 @@ -101,8 +101,8 @@ - 660 - 530 + 670 + 710 111 21 @@ -209,7 +209,7 @@ - + 10 @@ -252,13 +252,13 @@ - + 630 60 95 - 51 + 65 @@ -278,6 +278,42 @@ + + + + 20 + 200 + 440 + 30 + + + + + + + 获取UID + + + + + + + 额外参数 + + + + + + + + + + 写入SN + + + + + diff --git a/README.md b/README.md index 78d2496..e286088 100644 --- a/README.md +++ b/README.md @@ -143,3 +143,33 @@ typedef struct +### 获取UID + +`(上位机==>设备)` + +| 指令 | 参数(0Bytes) | +| ---- | ------------ | +| 0x7 | 无参数 | + +`(设备=回复=>上位机)` + +| 指令 | UID长度(1Bytes) | UID(nBytes) | +| ---- | --------------- | ----------- | +| 0x7 | | UID内容 | + + + +### 写入SN + +`(上位机==>设备)` + +| 指令 | SN长度(1Bytes) | SN内容(nBytes) | +| ---- | -------------- | -------------- | +| 0x8 | | | + +`(设备=回复=>上位机)` + +| 指令 | 无参数 | +| ---- | ------ | +| 0x8 | | + diff --git a/exe/BabyOS_Protocol.exe b/exe/BabyOS_Protocol.exe index 31d9f8177101e3f2f57bc3f127f90d6ecf167779..9cbd9115e7e4ce095abf19e5be0d56f137b4ae5f 100644 GIT binary patch delta 28883 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 NtVM7C>ZNjZ`hUrmyAc2Y