diff --git a/APP_Framework/Applications/main.c b/APP_Framework/Applications/main.c index e1de024b5..53de5ed34 100644 --- a/APP_Framework/Applications/main.c +++ b/APP_Framework/Applications/main.c @@ -18,12 +18,21 @@ extern int FrameworkInit(); extern void ApplicationOtaTaskInit(void); + +#ifdef OTA_BY_PLATFORM +extern int OtaTask(void); +#endif + int main(void) { - printf("Hello, world! \n"); - FrameworkInit(); + printf("Hello, world! \n"); + FrameworkInit(); #ifdef APPLICATION_OTA - ApplicationOtaTaskInit(); + ApplicationOtaTaskInit(); +#endif + +#ifdef OTA_BY_PLATFORM + OtaTask(); #endif return 0; } diff --git a/APP_Framework/Framework/connection/4g/ec200t/ec200t.c b/APP_Framework/Framework/connection/4g/ec200t/ec200t.c index 67076fe44..92f687303 100644 --- a/APP_Framework/Framework/connection/4g/ec200t/ec200t.c +++ b/APP_Framework/Framework/connection/4g/ec200t/ec200t.c @@ -163,8 +163,12 @@ static int Ec200tIoctl(struct Adapter *adapter, int cmd, void *args) serial_cfg.serial_parity_mode = PARITY_NONE; serial_cfg.serial_bit_order = STOP_BITS_1; serial_cfg.serial_invert_mode = NRZ_NORMAL; +#ifdef TOOL_USING_OTA + serial_cfg.serial_timeout = OTA_RX_TIMEOUT; +#else //serial receive timeout 10s - serial_cfg.serial_timeout = 10000; + serial_cfg.serial_timeout = 100000; +#endif serial_cfg.is_ext_uart = 0; #ifdef ADAPTER_EC200T_DRIVER_EXT_PORT serial_cfg.is_ext_uart = 1; diff --git a/APP_Framework/Framework/connection/adapter_agent.c b/APP_Framework/Framework/connection/adapter_agent.c index f36fb338d..e9c4dcb98 100755 --- a/APP_Framework/Framework/connection/adapter_agent.c +++ b/APP_Framework/Framework/connection/adapter_agent.c @@ -124,7 +124,9 @@ int ParseATReply(char *str, const char *format, ...) void ATSprintf(int fd, const char *format, va_list params) { last_cmd_len = vsnprintf(send_buf, sizeof(send_buf), format, params); +#ifdef CONNECTION_FRAMEWORK_DEBUG printf("AT send %s len %u\n",send_buf, last_cmd_len); +#endif PrivWrite(fd, send_buf, last_cmd_len); } @@ -279,7 +281,9 @@ int EntmSend(ATAgentType agent, const char *data, int len) PrivWrite(agent->fd, send_buff, len); PrivMutexAbandon(&agent->lock); +#ifdef CONNECTION_FRAMEWORK_DEBUG printf("entm send length %d\n", len); +#endif PrivFree(send_buff); @@ -289,6 +293,7 @@ int EntmSend(ATAgentType agent, const char *data, int len) int EntmRecv(ATAgentType agent, char *rev_buffer, int buffer_len, int timeout_s) { struct timespec abstime; + uint32 real_recv_len = 0; abstime.tv_sec = timeout_s; if(buffer_len > ENTM_RECV_MAX){ @@ -301,21 +306,25 @@ int EntmRecv(ATAgentType agent, char *rev_buffer, int buffer_len, int timeout_s) PrivMutexAbandon(&agent->lock); //PrivTaskDelay(1000); if (PrivSemaphoreObtainWait(&agent->entm_rx_notice, &abstime)) { +#ifdef CONNECTION_FRAMEWORK_DEBUG printf("wait sem[%d] timeout\n",agent->entm_rx_notice); +#endif + agent->entm_recv_len = 0; return -1; } PrivMutexObtain(&agent->lock); - +#ifdef CONNECTION_FRAMEWORK_DEBUG printf("EntmRecv once len %d.\n", agent->entm_recv_len); - +#endif memcpy(rev_buffer, agent->entm_recv_buf, agent->entm_recv_len); - memset(agent->entm_recv_buf, 0, ENTM_RECV_MAX); + + real_recv_len = agent->entm_recv_len; agent->entm_recv_len = 0; agent->read_len = 0; PrivMutexAbandon(&agent->lock); - return buffer_len; + return real_recv_len; } static int GetCompleteATReply(ATAgentType agent) @@ -323,21 +332,22 @@ static int GetCompleteATReply(ATAgentType agent) uint32_t read_len = 0; char ch = 0, last_ch = 0; bool is_full = false; + int res; PrivMutexObtain(&agent->lock); memset(agent->maintain_buffer, 0x00, agent->maintain_max); agent->maintain_len = 0; - memset(agent->entm_recv_buf, 0x00, 256); + memset(agent->entm_recv_buf, 0x00, ENTM_RECV_MAX); agent->entm_recv_len = 0; PrivMutexAbandon(&agent->lock); while (1) { - PrivRead(agent->fd, &ch, 1); + res = PrivRead(agent->fd, &ch, 1); #ifdef CONNECTION_FRAMEWORK_DEBUG - if(ch != 0) { + if((res == 1) && (ch != 0)) { printf(" %c (0x%x)\n", ch, ch); } #endif @@ -345,14 +355,28 @@ static int GetCompleteATReply(ATAgentType agent) PrivMutexObtain(&agent->lock); if (agent->receive_mode == ENTM_MODE) { if (agent->entm_recv_len < ENTM_RECV_MAX) { - agent->entm_recv_buf[agent->entm_recv_len] = ch; - agent->entm_recv_len++; - - if(agent->entm_recv_len < agent->read_len) { +#ifdef TOOL_USING_MQTT + if((res == 1) && (agent->entm_recv_len < agent->read_len)) + { + agent->entm_recv_buf[agent->entm_recv_len] = ch; + agent->entm_recv_len++; PrivMutexAbandon(&agent->lock); continue; - } else { + } +#else + agent->entm_recv_buf[agent->entm_recv_len] = ch; + agent->entm_recv_len++; + if(agent->entm_recv_len < agent->read_len) + { + PrivMutexAbandon(&agent->lock); + continue; + } +#endif + else + { +#ifdef CONNECTION_FRAMEWORK_DEBUG printf("ENTM_MODE recv %d Bytes done.\n",agent->entm_recv_len); +#endif agent->receive_mode = DEFAULT_MODE; PrivSemaphoreAbandon(&agent->entm_rx_notice); } diff --git a/APP_Framework/Framework/connection/at_agent.h b/APP_Framework/Framework/connection/at_agent.h index 812a6aa9f..81ed948cf 100755 --- a/APP_Framework/Framework/connection/at_agent.h +++ b/APP_Framework/Framework/connection/at_agent.h @@ -28,6 +28,12 @@ #define REPLY_TIME_OUT 10 +#ifdef TOOL_USING_OTA +#define ENTM_RECV_MAX OTA_RX_BUFFERSIZE +#else +#define ENTM_RECV_MAX 256 +#endif + enum ReceiveMode { DEFAULT_MODE = 0, @@ -70,7 +76,6 @@ struct ATAgent #endif pthread_t at_handler; - #define ENTM_RECV_MAX 2048 char entm_recv_buf[ENTM_RECV_MAX]; uint32 entm_recv_len; enum ReceiveMode receive_mode; diff --git a/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/.defconfig b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/.defconfig index 687d21e75..18029b242 100644 --- a/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/.defconfig +++ b/Ubiquitous/XiZi_IIoT/board/xidatong-arm32/.defconfig @@ -129,7 +129,7 @@ CONFIG_ZOMBIE_KTASK_STACKSIZE=2048 # CONFIG_KERNEL_CONSOLE=y CONFIG_KERNEL_BANNER=y -CONFIG_KERNEL_CONSOLEBUF_SIZE=128 +CONFIG_KERNEL_CONSOLEBUF_SIZE=256 # # Kernel Hook diff --git a/Ubiquitous/XiZi_IIoT/path_kernel.mk b/Ubiquitous/XiZi_IIoT/path_kernel.mk index d97b59204..028ee43e3 100755 --- a/Ubiquitous/XiZi_IIoT/path_kernel.mk +++ b/Ubiquitous/XiZi_IIoT/path_kernel.mk @@ -564,6 +564,10 @@ KERNELPATHS +=-I$(KERNEL_ROOT)/tool/bootloader/flash \ -I$(KERNEL_ROOT)/tool/bootloader/ota # endif +ifeq ($(CONFIG_TOOL_USING_MQTT), y) +KERNELPATHS +=-I$(KERNEL_ROOT)/tool/mqtt +endif + ifeq ($(CONFIG_FS_LWEXT4),y) KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/blockdev/xiuos # KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/include # diff --git a/Ubiquitous/XiZi_IIoT/tool/Kconfig b/Ubiquitous/XiZi_IIoT/tool/Kconfig index 1989064ce..0c3aa9494 100644 --- a/Ubiquitous/XiZi_IIoT/tool/Kconfig +++ b/Ubiquitous/XiZi_IIoT/tool/Kconfig @@ -1,5 +1,6 @@ menu "Tool feature" source "$KERNEL_DIR/tool/bootloader/Kconfig" + source "$KERNEL_DIR/tool/mqtt/Kconfig" endmenu diff --git a/Ubiquitous/XiZi_IIoT/tool/Makefile b/Ubiquitous/XiZi_IIoT/tool/Makefile index cd148dd4f..e18b07080 100644 --- a/Ubiquitous/XiZi_IIoT/tool/Makefile +++ b/Ubiquitous/XiZi_IIoT/tool/Makefile @@ -8,4 +8,8 @@ ifeq ($(CONFIG_TOOL_USING_OTA),y) SRC_DIR += bootloader endif +ifeq ($(CONFIG_TOOL_USING_MQTT),y) + SRC_DIR += mqtt +endif + include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig b/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig index adca101fd..c826295d4 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/Kconfig @@ -17,23 +17,19 @@ menu "OTA function" endchoice if MCUBOOT_APPLICATION - menu "The way of OTA firmware upgrade." - config OTA_BY_IAP - bool "Through serial port IAP." - default y - - config OTA_BY_TCPSERVER - bool "Through the public network TCP server." - default n - select SUPPORT_CONNECTION_FRAMEWORK - select CONNECTION_ADAPTER_4G + choice + prompt "The way of OTA firmware upgrade." + default OTA_BY_PLATFORM config OTA_BY_PLATFORM bool "Through IoT management platform." - default n + select TOOL_USING_MQTT + + config OTA_BY_TCPSERVER + bool "Through the public network TCP server." select SUPPORT_CONNECTION_FRAMEWORK select CONNECTION_ADAPTER_4G - endmenu + endchoice endif @@ -62,7 +58,18 @@ menu "OTA function" hex "Application package size,the default size is limited to 1M." default 0x00100000 endmenu - + + config OTA_RX_TIMEOUT + int "OTA receive data timeout(ms)." + default 600 if OTA_BY_PLATFORM + default 10000 if OTA_BY_TCPSERVER + default 10000 if MCUBOOT_BOOTLOADER + + config OTA_RX_BUFFERSIZE + int "OTA receive data buffer size." + default 3072 if OTA_BY_PLATFORM + default 2048 if OTA_BY_TCPSERVER + default 256 if MCUBOOT_BOOTLOADER endif endmenu diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c index 309cb2941..3aedba32d 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.c @@ -18,6 +18,7 @@ * @date: 2023/4/23 * */ +#include #include #include "shell.h" #include "xsconfig.h" @@ -29,10 +30,15 @@ #include #endif +#ifdef OTA_BY_PLATFORM +#include "platform_mqtt.h" +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static uint32_t calculate_crc32(uint32_t addr, uint32_t len); +static int create_version(uint8_t* cur_version, uint8_t* new_version); static status_t UpdateOTAFlag(ota_info_t *ptr); static void InitialVersion(void); static void BackupVersion(void); @@ -116,6 +122,47 @@ static uint32_t calculate_crc32(uint32_t addr, uint32_t len) } +/******************************************************************************* +* 函 数 名: create_version +* 功能描述: 根据当前版本号生成新的三段式版本号,适用于iap方式和TCPSERVER +* 形 参: cur_version:当前版本号,new_version:生成的新版本号 +* 返 回 值: 0:生成成功,-1:生成失败 +* 说 明: 为保持一致,平台通过OTA传输而来的版本号也要保持这样三段式的形式 + 版本形式为major.minor.patch,如01.02.03 +*******************************************************************************/ +static int create_version(uint8_t* cur_version, uint8_t* new_version) +{ + int major, minor, patch; //三段式版本号的各个部分 + + //解析当前版本号,版本号格式不对直接返回 + if (sscanf(cur_version, "%03d.%03d.%03d", &major, &minor, &patch) != 3) { + return -1; + } + + //将当前版本号加1 + patch++; + if(patch > 999) + { + minor++; + patch = 0; + if(minor > 999) + { + major++; + minor = 0; + patch = 0; + if(major > 999) + { + return -1; + } + } + } + + //更新版本号 + sprintf(new_version, "%03d.%03d.%03d", major, minor, patch); + return 0; +} + + /******************************************************************************* * 函 数 名: UpdateOTAFlag * 功能描述: 更新OTA Flag区域的信息,版本完成下载后在app里进行调用 @@ -154,8 +201,10 @@ static void InitialVersion(void) { ota_info.os.size = size; ota_info.os.crc32 = calculate_crc32(XIUOS_FLAH_ADDRESS, size); - ota_info.os.version = 0x1; + + strncpy(ota_info.os.version,"001.000.000",sizeof(ota_info.os.version)); strncpy(ota_info.os.description, "The initial firmware.", sizeof(ota_info.os.description)); + UpdateOTAFlag(&ota_info); } } @@ -171,7 +220,7 @@ static void BackupVersion(void) { status_t status; - ota_info_t ota_info; + ota_info_t ota_info; memset(&ota_info, 0, sizeof(ota_info_t)); mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); @@ -183,15 +232,23 @@ static void BackupVersion(void) mcuboot.print_string("\r\n------Backup app version success!------\r\n"); ota_info.os.size = ota_info.bak.size; ota_info.os.crc32 = ota_info.bak.crc32; - ota_info.os.version = ota_info.bak.version; + + memset(ota_info.os.version,0,sizeof(ota_info.os.version)); + strncpy(ota_info.os.version, ota_info.bak.version, sizeof(ota_info.bak.version)); + + memset(ota_info.os.description,0,sizeof(ota_info.os.description)); strncpy(ota_info.os.description, ota_info.bak.description, sizeof(ota_info.bak.description)); + UpdateOTAFlag(&ota_info); } else { mcuboot.print_string("\r\n------Backup app version failed!------\r\n"); ota_info.status = OTA_STATUS_ERROR; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "Backup app version failed!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info); } } @@ -208,8 +265,8 @@ static void UpdateNewApplication(void) { status_t status; ota_info_t ota_info; // 定义OTA信息结构体 - - memset(&ota_info, 0, sizeof(ota_info_t)); + + memset(&ota_info, 0, sizeof(ota_info_t)); // 从Flash中读取OTA信息 mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); @@ -230,15 +287,23 @@ static void UpdateNewApplication(void) mcuboot.print_string("\r\n------Backup app success!------\r\n"); ota_info.bak.size = ota_info.os.size; ota_info.bak.crc32 = ota_info.os.crc32; - ota_info.bak.version = ota_info.os.version; + + memset(ota_info.bak.version,0,sizeof(ota_info.bak.version)); + strncpy(ota_info.bak.version, ota_info.os.version, sizeof(ota_info.os.version)); + + memset(ota_info.bak.description,0,sizeof(ota_info.bak.description)); strncpy(ota_info.bak.description, ota_info.os.description, sizeof(ota_info.os.description)); + UpdateOTAFlag(&ota_info);; } else { mcuboot.print_string("\r\n------Backup app failed!------\r\n"); ota_info.status = OTA_STATUS_ERROR; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "Backup app failed!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info);; goto finish; } @@ -251,8 +316,13 @@ static void UpdateNewApplication(void) ota_info.os.size = ota_info.down.size; ota_info.os.crc32 = ota_info.down.crc32; - ota_info.os.version = ota_info.down.version; + + memset(ota_info.os.version,0,sizeof(ota_info.os.version)); + strncpy(ota_info.os.version, ota_info.down.version, sizeof(ota_info.down.version)); + + memset(ota_info.os.description,0,sizeof(ota_info.os.description)); strncpy(ota_info.os.description, ota_info.down.description, sizeof(ota_info.down.description)); + ota_info.status == OTA_STATUS_IDLE; // 拷贝download分区到XiUOS System分区成功,将OTA升级状态设置为IDLE UpdateOTAFlag(&ota_info);; } @@ -260,7 +330,10 @@ static void UpdateNewApplication(void) { mcuboot.print_string("\r\n------The download partition copy failed!------\r\n"); ota_info.status = OTA_STATUS_ERROR; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "The download partition copy failed!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info);; goto finish; } @@ -273,7 +346,10 @@ static void UpdateNewApplication(void) // 如果download分区CRC校验失败,升级失败 mcuboot.print_string("\r\n------Download Firmware CRC check failed!------\r\n"); ota_info.status = OTA_STATUS_ERROR; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "Download Firmware CRC check failed!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info);; goto finish; } @@ -343,7 +419,6 @@ static void BootLoaderJumpApp(void) } -#ifdef OTA_BY_IAP /********************************************************************************* * 函 数 名: app_ota_by_iap * 功能描述: 通过命令来进行ota升级,该函数与升级的命令关联,通过串口iap方式传输bin文件 @@ -368,23 +443,32 @@ static void app_ota_by_iap(void) { ota_info.down.size = size; ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, size); - ota_info.down.version = ota_info.os.version + 1; + + memset(ota_info.down.version,0,sizeof(ota_info.down.version)); + create_version(ota_info.os.version, ota_info.down.version); + + memset(ota_info.down.description,0,sizeof(ota_info.down.description)); strncpy(ota_info.down.description, "OTA Test bin.",sizeof(ota_info.down.description)); + ota_info.status = OTA_STATUS_READY; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message)); UpdateOTAFlag(&ota_info); } else { ota_info.status = OTA_STATUS_ERROR; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "Failed to download firmware to download partition!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info); } mcuboot.flash_deinit(); mcuboot.op_reset(); } SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),iap, app_ota_by_iap, ota by iap function); -#endif #ifdef OTA_BY_TCPSERVER @@ -429,7 +513,7 @@ static uint16_t calculate_crc16(uint8_t * data, uint32_t len) static void get_start_signal(struct Adapter* adapter) { ota_info_t ota_info; - char reply[16] = {0}; + uint8_t reply[16] = {0}; uint32_t flashdestination = DOWN_FLAH_ADDRESS; memset(&ota_info, 0, sizeof(ota_info_t)); @@ -462,7 +546,7 @@ static void get_start_signal(struct Adapter* adapter) { memset(reply, 0, sizeof(reply)); memcpy(reply, "notready", strlen("notready")); - KPrintf("not receive start signal,send [notready] signal to server\n"); + KPrintf("not receive start signal,send [notready] signal to server\n"); while(AdapterDeviceSend(adapter, reply, strlen(reply)) < 0); continue; } @@ -479,7 +563,7 @@ static void get_start_signal(struct Adapter* adapter) static int ota_data_recv(struct Adapter* adapter) { ota_info_t ota_info; - char reply[16] = {0}; + uint8_t reply[16] = {0}; int ret = 0, frame_cnt = 0, try_times = 5; uint32_t file_size = 0; uint32_t flashdestination = DOWN_FLAH_ADDRESS; @@ -581,16 +665,27 @@ try_again: { ota_info.down.size = file_size; ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, file_size); - ota_info.down.version = ota_info.os.version + 1; + + memset(ota_info.down.version,0,sizeof(ota_info.down.version)); + create_version(ota_info.os.version, ota_info.down.version); + + memset(ota_info.down.description,0,sizeof(ota_info.down.description)); strncpy(ota_info.down.description, "4G OTA bin.",sizeof(ota_info.down.description)); + ota_info.status = OTA_STATUS_READY; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info); } else { ota_info.status = OTA_STATUS_ERROR; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "Failed to download firmware to download partition!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info); } return ret; @@ -600,12 +695,11 @@ try_again: /******************************************************************************* * 函 数 名: app_ota_by_4g * 功能描述: 通过命令来进行ota升级,该函数与升级的命令关联,通过4g方式传输bin文件 -* 形 参: adapter:Adapter指针,指向注册的4G设备 -* 返 回 值: 0:传输成功,-1:传输失败 +* 形 参: 无 +* 返 回 值: 无 *******************************************************************************/ static void app_ota_by_4g(void) { - char reply[16] = {0}; uint32_t baud_rate = BAUD_RATE_115200; uint8_t server_addr[16] = "115.238.53.60"; uint8_t server_port[8] = "7777"; @@ -618,22 +712,22 @@ static void app_ota_by_4g(void) AdapterDeviceOpen(adapter); AdapterDeviceControl(adapter, OPE_INT, &baud_rate); AdapterDeviceConnect(adapter, CLIENT, server_addr, server_port, IPV4); - PrivTaskDelay(100); + MdelayKTask(100); while(1) { /* step1:Confirm the start signal of transmission. */ get_start_signal(adapter); KPrintf("start receive ota bin file.\n"); /* step2:start receive bin file,first wait for 4s. */ - PrivTaskDelay(4000); + MdelayKTask(4000); if(0 == ota_data_recv(adapter)) { break; } } mcuboot.flash_deinit(); - KPrintf("ota file done,start reboot.\n"); - PrivTaskDelay(2000); + KPrintf("ota file transfer complete,start reboot!\n"); + MdelayKTask(2000); mcuboot.op_reset(); } @@ -642,6 +736,242 @@ SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHE #ifdef OTA_BY_PLATFORM +#define FRAME_LEN 2048 //每帧数据的数据包长度 +static uint8_t MqttRxbuf[3072]; +static uint8_t FrameBuf[FRAME_LEN]; +static OTA_TCB AliOTA; + +/******************************************************************************* +* 函 数 名: PropertyVersion +* 功能描述: 向服务器上传当前设备版本信息 +* 形 参: 无 +* 返 回 值: 无 +*******************************************************************************/ +static void PropertyVersion(void) +{ + uint8_t topicdatabuff[64]; + uint8_t tempdatabuff[128]; + ota_info_t ota_info; + + memset(topicdatabuff,0,64); + sprintf(topicdatabuff,"/ota/device/inform/%s/%s", PLATFORM_PRODUCTKEY, CLIENT_DEVICENAME); + + memset(&ota_info, 0, sizeof(ota_info_t)); + mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); + + memset(tempdatabuff,0,128); + sprintf(tempdatabuff,"{\"id\": \"1\",\"params\": {\"version\": \"%s\"}}",ota_info.os.version); + + MQTT_PublishDataQs1(topicdatabuff,tempdatabuff,strlen(tempdatabuff)); //发送等级QS=1的PUBLISH报文 +} + + +/*-------------------------------------------------*/ +/*函数名:OTA下载数据 */ +/*参 数:size:本次下载量 */ +/*参 数:offset:本次下载偏移量 */ +/*返回值:无 */ +/*-------------------------------------------------*/ +void OTA_Download(int size, int offset) +{ + uint8_t topicdatabuff[64]; + uint8_t tempdatabuff[128]; + + memset(topicdatabuff,0,64); + sprintf(topicdatabuff,"/sys/%s/%s/thing/file/download",PLATFORM_PRODUCTKEY,CLIENT_DEVICENAME); + + memset(tempdatabuff,0,128); + sprintf(tempdatabuff,"{\"id\": \"1\",\"params\": {\"fileInfo\":{\"streamId\":%d,\"fileId\":1},\"fileBlock\":{\"size\":%d,\"offset\":%d}}}",AliOTA.streamId,size,offset); + + MQTT_PublishDataQs0(topicdatabuff, tempdatabuff, strlen(tempdatabuff)); +} + +/******************************************************************************* +* 函 数 名: app_ota_by_platform +* 功能描述: 通过命令来进行ota升级,该函数与升级的命令关联,通过云平台MQTT进行升级 +* 形 参: 无 +* 返 回 值: 无 +*******************************************************************************/ +static void app_ota_by_platform(void* parameter) +{ + int datalen; + int ret = 0; + int freecnt = 0; + ota_info_t ota_info; + uint32_t heart_time = 0; + uint32_t flashdestination = DOWN_FLAH_ADDRESS; + uint8_t topicdatabuff[64]; + char *ptr; + + mcuboot.flash_init(); + memset(&ota_info, 0, sizeof(ota_info_t)); + mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); + ota_info.status = OTA_STATUS_DOWNLOADING; + UpdateOTAFlag(&ota_info); + memset(topicdatabuff,0,64); + sprintf(topicdatabuff,"/sys/%s/%s/thing/file/download_reply",PLATFORM_PRODUCTKEY,CLIENT_DEVICENAME); + +reconnect: + if((AdapterNetActive() == 0) && (MQTT_Connect() == 0) && MQTT_SubscribeTopic(topicdatabuff) == 0) + { + KPrintf("Log in to the cloud platform and subscribe to the topic successfully.\n"); + PropertyVersion(); + } + else + { + KPrintf("Log in to the cloud platform failed, retry!\n"); + goto reconnect; + } + + while(1) + { + memset(MqttRxbuf,0,sizeof(MqttRxbuf)); + datalen = MQTT_Recv(MqttRxbuf, sizeof(MqttRxbuf)); + if(datalen <= 0) + { + freecnt++; + } + else if(MqttRxbuf[0] == 0x30) + { + freecnt = 0; + MQTT_DealPublishData(MqttRxbuf, datalen); + ptr = strstr((char *)Platform_mqtt.cmdbuff,"{\"code\":\"1000\""); + if(ptr != NULL) + { + if(sscanf(ptr,"{\"code\":\"1000\",\"data\":{\"size\":%d,\"streamId\":%d,\"sign\":\"%*32s\",\"dProtocol\":\"mqtt\",\"version\":\"%11s\"",&AliOTA.size,&AliOTA.streamId,AliOTA.version)==3) + { + KPrintf("ota file size:%d\r\n",AliOTA.size); + KPrintf("ota file id:%d\r\n",AliOTA.streamId); + KPrintf("ota file version:%s\r\n",AliOTA.version); + if(mcuboot.op_flash_erase(DOWN_FLAH_ADDRESS,AliOTA.size != kStatus_Success)) + { + KPrintf("Failed to erase target fash!\n"); + ret = -1; + break; + } + AliOTA.counter = (AliOTA.size%FRAME_LEN != 0)? (AliOTA.size/FRAME_LEN + 1):(AliOTA.size/FRAME_LEN); + AliOTA.num = 1; //下载次数,初始值为1 + AliOTA.downlen = FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 + } + else + { + KPrintf("Failed to get ota information!\n"); + ret = -1; + break; + } + } + + if(strstr((char *)Platform_mqtt.cmdbuff,"download_reply")) + { + memset(FrameBuf,0,sizeof(FrameBuf)); + memcpy(FrameBuf, &MqttRxbuf[datalen-AliOTA.downlen-2], AliOTA.downlen); + if(mcuboot.op_flash_write(flashdestination,FrameBuf,AliOTA.downlen) != kStatus_Success) + { + KPrintf("current frame[%d] flash failed.\n",AliOTA.num-1); + ret = -1; + break; + } + else + { + KPrintf("current frame[%d] is written to flash 0x%x address successful.\n", AliOTA.num -1, flashdestination); + KPrintf("Current progress is %d/%d\r\n",AliOTA.num,AliOTA.counter); + flashdestination += AliOTA.downlen; + AliOTA.num++; + } + + if(AliOTA.num < AliOTA.counter) //如果小于总下载次数 + { + AliOTA.downlen = FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 + } + else if(AliOTA.num == AliOTA.counter) //如果等于总下载次数,说明是最后一次下载 + { + if(AliOTA.size%FRAME_LEN == 0) //判断固件大小是否是FRAME_LEN的整数倍 + { + AliOTA.downlen = FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 + } + else + { + AliOTA.downlen = AliOTA.size%FRAME_LEN; //记录本次下载量 + OTA_Download(AliOTA.downlen,(AliOTA.num - 1)*FRAME_LEN); //发送要下载的数据信息给服务器 + } + } + + else //下载完毕 + { + ret = 0; + break; + } + } + + } + else + { + freecnt = 0; + continue; + } + + if((freecnt >= 10) && (CalculateTimeMsFromTick(CurrentTicksGain()) - heart_time >= HEART_TIME)) //连续10次未收到数据默认为为空闲状态,需每隔一段时间发送需要发送心跳包保活 + { + heart_time = CalculateTimeMsFromTick(CurrentTicksGain()); + if(MQTT_SendHeart() != 0) //发送心跳包失败可能连接断开,需要重连 + { + KPrintf("The connection has been disconnected, reconnecting!\n"); + freecnt = 0; + heart_time = 0; + goto reconnect; + } + KPrintf("Send heartbeat packet successful!\n"); + } + } + + if(0 == ret) + { + ota_info.down.size = AliOTA.size; + ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, AliOTA.size); + + memset(ota_info.down.version,0,sizeof(ota_info.down.version)); + strncpy(ota_info.down.version, AliOTA.version, sizeof(ota_info.down.version)); + + memset(ota_info.down.description,0,sizeof(ota_info.down.description)); + strncpy(ota_info.down.description, "MQTT OTA bin.",sizeof(ota_info.down.description)); + + ota_info.status = OTA_STATUS_READY; + + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); + strncpy(ota_info.error_message, "No error message!",sizeof(ota_info.error_message)); + + UpdateOTAFlag(&ota_info); + } + else + { + ota_info.status = OTA_STATUS_ERROR; + memset(ota_info.error_message,0,sizeof(ota_info.error_message)); + strncpy(ota_info.error_message, "Failed to download firmware to download partition!",sizeof(ota_info.error_message)); + UpdateOTAFlag(&ota_info); + } + MQTT_UnSubscribeTopic(topicdatabuff); + MQTT_Disconnect(); + mcuboot.flash_deinit(); + KPrintf("ota file transfer complete,start reboot!\n"); + MdelayKTask(2000); + mcuboot.op_reset(); +} + +int OtaTask(void) +{ + int32 ota_task = 0; + ota_task = KTaskCreate("ota_platform", app_ota_by_platform, NULL,8192, 10); + if(ota_task < 0) { + KPrintf("ota_task create failed ...%s %d.\n", __FUNCTION__,__LINE__); + return ERROR; + } + + StartupKTask(ota_task); + return 0; +} #endif @@ -653,8 +983,8 @@ SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHE *******************************************************************************/ void app_clear_jumpflag(void) { - ota_info_t ota_info; - mcuboot.flash_init(); + ota_info_t ota_info; + mcuboot.flash_init(); //跳转成功设置lastjumpflag为JUMP_SUCCESS_FLAG memset(&ota_info, 0, sizeof(ota_info_t)); mcuboot.op_flash_read(FLAG_FLAH_ADDRESS, (void*)&ota_info, sizeof(ota_info_t)); diff --git a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h index 3c8142007..48880a85c 100644 --- a/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h +++ b/Ubiquitous/XiZi_IIoT/tool/bootloader/ota/ota.h @@ -45,8 +45,8 @@ typedef enum { typedef struct { uint32_t size; // 应用程序大小,记录分区固件的大小 uint32_t crc32; // 应用程序CRC32校验值,记录分区固件的crc32值 - uint32_t version; // 应用程序版本号,记录分区固件的版本号 - uint8_t description[32]; // 固件的描述信息,最多32个字符 + uint8_t version[32]; // 应用程序版本号,记录分区固件的版本 + uint8_t description[32]; // 固件的描述信息,最多32个字符 } firmware_t; @@ -61,6 +61,7 @@ typedef struct { } ota_info_t; +#ifdef OTA_BY_TCPSERVER /*bin包传输过程中的数据帧相关的结构体*/ typedef struct { @@ -82,7 +83,18 @@ typedef struct ota_header_t header; ota_frame_t frame; } ota_data; +#endif +#ifdef OTA_BY_PLATFORM +typedef struct{ + uint32_t size; //OTA固件大小 + uint32_t streamId; //OTA固件下载时ID编号 + uint32_t counter; //OTA总下载次数 + uint32_t num; //OTA当前下载次数 + uint32_t downlen; //OTA当前下载次数的下载量 + uint8_t version[32]; //OTA下载时存储版本号的缓存区 +}OTA_TCB; +#endif void app_clear_jumpflag(void); void ota_entry(void); diff --git a/Ubiquitous/XiZi_IIoT/tool/mqtt/Kconfig b/Ubiquitous/XiZi_IIoT/tool/mqtt/Kconfig new file mode 100644 index 000000000..609b0dc78 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/mqtt/Kconfig @@ -0,0 +1,33 @@ +menu "MQTT function" + + menuconfig TOOL_USING_MQTT + bool "Enable support MQTT function" + default n + select SUPPORT_CONNECTION_FRAMEWORK + select CONNECTION_ADAPTER_4G + + if TOOL_USING_MQTT + menu "MQTT connection parameter configuration." + config PLATFORM_PRODUCTKEY + string "Product Key, used to identify a product." + default "iywhcgnuezz" + + config CLIENT_DEVICENAME + string "Device name, used to identify a client device." + default "D001" + + config CLIENT_DEVICESECRET + string "Device secret, used for device authentication and data encryption." + default "43b3c332233e2204a0612bfbfe21bb67" + + config PLATFORM_SERVERIP + string "mqtt platform server ip." + default "101.133.196.127" + + config PLATFORM_SERVERPORT + string "mqtt platform server port." + default "1883" + endmenu + endif + +endmenu diff --git a/Ubiquitous/XiZi_IIoT/tool/mqtt/Makefile b/Ubiquitous/XiZi_IIoT/tool/mqtt/Makefile new file mode 100644 index 000000000..b924f47d1 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/mqtt/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := platform_mqtt.c utils_hmacsha1.c + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/mqtt/platform_mqtt.c b/Ubiquitous/XiZi_IIoT/tool/mqtt/platform_mqtt.c new file mode 100644 index 000000000..b26e2aa61 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/mqtt/platform_mqtt.c @@ -0,0 +1,440 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: platform_mqtt.c +* @brief: platform_mqtt.c file +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/6/14 +* +*/ + +#include +#include +#include +#include "shell.h" +#include "xsconfig.h" +#include +#include "platform_mqtt.h" + +MQTT_TCB Platform_mqtt; //创建一个用于连接云平台mqtt的结构体 +static struct Adapter *adapter; +static const uint8_t parket_connetAck[] = {0x20,0x02,0x00,0x00}; //连接成功服务器回应报文 +static const uint8_t parket_disconnet[] = {0xE0,0x00}; //客户端主动断开连接发送报文 +static const uint8_t parket_heart[] = {0xC0,0x00}; //客户端发送保活心跳包 +static const uint8_t parket_subAck[] = {0x90,0x03,0x00,0x0A,0x01}; //订阅成功服务器回应报文 +static const uint8_t parket_unsubAck[] = {0xB0,0x02,0x00,0x0A}; //取消订阅成功服务器回应报文 +static uint8_t mqtt_rxbuf[16]; + + +/******************************************************************************* +* 函 数 名: AdapterNetActive +* 功能描述: 使能设备的网络模块连接,连接TCP服务器并进入透传模式,当前使用4G方式 +* 形 参: 无 +* 返 回 值: 0表示成功,其他值表示失败 +*******************************************************************************/ +int AdapterNetActive(void) +{ + int ret = 0; + uint32_t baud_rate = BAUD_RATE_115200; + adapter = AdapterDeviceFindByName(ADAPTER_4G_NAME); + adapter->socket.socket_id = 0; + + ret = AdapterDeviceOpen(adapter); + if (ret < 0) + { + goto out; + } + + ret = AdapterDeviceControl(adapter, OPE_INT, &baud_rate); + if (ret < 0) + { + goto out; + } + + ret = AdapterDeviceConnect(adapter, CLIENT, PLATFORM_SERVERIP, PLATFORM_SERVERPORT, IPV4); + if (ret < 0) + { + goto out; + } + +out: + if (ret < 0) + { + AdapterDeviceClose(adapter); + } + + return ret; +} + + + +/******************************************************************************* +* 函 数 名: MQTT_Send +* 功能描述: MQTT client数据发送函数 +* 形 参: buf:要发送的数据,buflen:要发送的数据长度 +* 返 回 值: 发送成功为0,发送失败为-1 +*******************************************************************************/ +int MQTT_Send(const uint8_t* buf, int buflen) +{ + return AdapterDeviceSend(adapter, buf, buflen) ; +} + + +/******************************************************************************* +* 函 数 名: MQTT_Recv +* 功能描述: MQTT client数据接收函数 +* 形 参: buf:数据缓冲区,buflen:期望接收的数据长度 +* 返 回 值: 实际接收到的数据长度,接收失败为-1 +*******************************************************************************/ +int MQTT_Recv(uint8_t* buf, int buflen) +{ + return AdapterDeviceRecv(adapter, buf, buflen) ; +} + + +/******************************************************************************* +* 函 数 名: MQTT_Connect +* 功能描述: 登录MQTT服务器 +* 形 参: 无 +* 返 回 值: 0表示成功,1表示失败 +*******************************************************************************/ +int MQTT_Connect(void) +{ + uint8_t TryConnect_time = 10; //尝试登录次数 + uint8_t passwdtemp[PASSWARD_SIZE]; + + memset(&Platform_mqtt,0,sizeof(Platform_mqtt)); + sprintf(Platform_mqtt.ClientID,"%s|securemode=3,signmethod=hmacsha1|",CLIENT_DEVICENAME); //构建客户端ID并存入缓冲区 + sprintf(Platform_mqtt.Username,"%s&%s",CLIENT_DEVICENAME,PLATFORM_PRODUCTKEY); //构建用户名并存入缓冲区 + memset(passwdtemp,0,sizeof(passwdtemp)); + sprintf(passwdtemp,"clientId%sdeviceName%sproductKey%s",CLIENT_DEVICENAME,CLIENT_DEVICENAME,PLATFORM_PRODUCTKEY); //构建加密时的明文 + utils_hmac_sha1(passwdtemp,strlen(passwdtemp),Platform_mqtt.Passward,(char *)CLIENT_DEVICESECRET,strlen(CLIENT_DEVICESECRET)); //以DeviceSecret为秘钥对temp中的明文进行hmacsha1加密即为密码 + + Platform_mqtt.MessageID = 0; //报文标识符清零,CONNECT报文虽然不需要添加报文标识符,但是CONNECT报文是第一个发送的报文,在此清零报文标识符为后续报文做准备 + Platform_mqtt.Fixed_len = 1; //CONNECT报文固定报头长度暂定为1 + Platform_mqtt.Variable_len = 10; //CONNECT报文可变报头长度为10 + Platform_mqtt.Payload_len = (2+strlen(Platform_mqtt.ClientID)) + (2+strlen(Platform_mqtt.Username)) + (2+strlen(Platform_mqtt.Passward)); //CONNECT报文中负载长度 + Platform_mqtt.Remaining_len = Platform_mqtt.Variable_len + Platform_mqtt.Payload_len; //剩余长度=可变报头长度+负载长度 + memset(Platform_mqtt.Pack_buff,0,sizeof(Platform_mqtt.Pack_buff)); + + Platform_mqtt.Pack_buff[0] = 0x10; //CONNECT报文 固定报头第1个字节0x10 + do{ + if((Platform_mqtt.Remaining_len/128) == 0) + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = Platform_mqtt.Remaining_len; + } + else + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = (Platform_mqtt.Remaining_len%128)|0x80; + } + Platform_mqtt.Fixed_len++; + Platform_mqtt.Remaining_len = Platform_mqtt.Remaining_len/128; + }while(Platform_mqtt.Remaining_len); + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+0] = 0x00; //CONNECT报文,可变报头第1个字节:固定0x00 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+1] = 0x04; //CONNECT报文,可变报头第2个字节:固定0x04 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+2] = 0x4D; //CONNECT报文,可变报头第3个字节:固定0x4D,大写字母M + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+3] = 0x51; //CONNECT报文,可变报头第4个字节:固定0x51,大写字母Q + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+4] = 0x54; //CONNECT报文,可变报头第5个字节:固定0x54,大写字母T + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+5] = 0x54; //CONNECT报文,可变报头第6个字节:固定0x54,大写字母T + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+6] = 0x04; //CONNECT报文,可变报头第7个字节:固定0x04 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+7] = 0xC2; //CONNECT报文,可变报头第8个字节:使能用户名和密码校验,不使用遗嘱功能,不保留会话功能 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+8] = KEEPALIVE_TIME/256; //CONNECT报文,可变报头第9个字节:保活时间高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+9] = KEEPALIVE_TIME%256; //CONNECT报文,可变报头第10个字节:保活时间低字节,单位s + + /* CLIENT_ID */ + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+10] = strlen(Platform_mqtt.ClientID)/256; //客户端ID长度高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+11] = strlen(Platform_mqtt.ClientID)%256; //客户端ID长度低字节 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+12],Platform_mqtt.ClientID,strlen(Platform_mqtt.ClientID)); //复制过来客户端ID字串 + /* USER_NAME */ + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+12+strlen(Platform_mqtt.ClientID)] = strlen(Platform_mqtt.Username)/256; //用户名长度高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+13+strlen(Platform_mqtt.ClientID)] = strlen(Platform_mqtt.Username)%256; //用户名长度低字节 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+14+strlen(Platform_mqtt.ClientID)],Platform_mqtt.Username,strlen(Platform_mqtt.Username)); //复制过来用户名字串 + /* PASSWARD */ + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+14+strlen(Platform_mqtt.ClientID)+strlen(Platform_mqtt.Username)] = strlen(Platform_mqtt.Passward)/256; //密码长度高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+15+strlen(Platform_mqtt.ClientID)+strlen(Platform_mqtt.Username)] = strlen(Platform_mqtt.Passward)%256; //密码长度低字节 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+16+strlen(Platform_mqtt.ClientID)+strlen(Platform_mqtt.Username)],Platform_mqtt.Passward,strlen(Platform_mqtt.Passward)); //复制过来密码字串 + + while(TryConnect_time > 0) + { + memset(mqtt_rxbuf,0,sizeof(mqtt_rxbuf)); + MQTT_Send(Platform_mqtt.Pack_buff,Platform_mqtt.Fixed_len + Platform_mqtt.Variable_len + Platform_mqtt.Payload_len); + MdelayKTask(50); + MQTT_Recv(mqtt_rxbuf, 4); + if(mqtt_rxbuf[0] == parket_connetAck[0] && mqtt_rxbuf[1] == parket_connetAck[1]) //连接成功 + { + return 0; + } + TryConnect_time--; + } + return 1; +} + + +/******************************************************************************* +* 函 数 名: MQTT_Disconnect +* 功能描述: 断开与MQTT服务器的连接 +* 形 参: 无 +* 返 回 值: 无 +*******************************************************************************/ +void MQTT_Disconnect(void) +{ + while(MQTT_Send(parket_disconnet,sizeof(parket_disconnet)) < 0); +} + + +/******************************************************************************* +* 函 数 名: MQTT_SubscribeTopic +* 功能描述: MQTT订阅单个主题 +* 形 参: topic_name:要订阅的主题 +* 返 回 值: 0表示订阅成功,1表示订阅失败 +*******************************************************************************/ +int MQTT_SubscribeTopic(uint8_t *topic_name) +{ + uint8_t TrySub_time = 10; //尝试订阅次数 + + Platform_mqtt.Fixed_len = 1; //SUBSCRIBE报文,固定报头长度暂定为1 + Platform_mqtt.Variable_len = 2;//SUBSCRIBE报文,可变报头长度=2,2为字节报文标识符 + Platform_mqtt.Payload_len = 0; //SUBSCRIBE报文,负载数据长度暂定为0 + + Platform_mqtt.Payload_len = strlen(topic_name) + 2 + 1; //每个需要订阅的topic除了本身的字符串长度,还包含表示topic字符串长度的2字节,以及订阅等级1字节 + Platform_mqtt.Remaining_len = Platform_mqtt.Variable_len + Platform_mqtt.Payload_len; //计算剩余长度=可变报头长度+负载长度 + memset(Platform_mqtt.Pack_buff,0,sizeof(Platform_mqtt.Pack_buff)); + + Platform_mqtt.Pack_buff[0]=0x82; //SUBSCRIBE报文,固定报头第1个字节0x82 + do{ + if((Platform_mqtt.Remaining_len/128) == 0) + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = Platform_mqtt.Remaining_len; + } + else + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = (Platform_mqtt.Remaining_len%128)|0x80; + } + Platform_mqtt.Fixed_len++; + Platform_mqtt.Remaining_len = Platform_mqtt.Remaining_len/128; + }while(Platform_mqtt.Remaining_len); + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+0] = Platform_mqtt.MessageID/256; //报文标识符高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+1] = Platform_mqtt.MessageID%256; //报文标识符低字节 + Platform_mqtt.MessageID++; //每用一次MessageID加1 + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+2] = strlen(topic_name)/256; //主题长度高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+3] = strlen(topic_name)%256; //主题长度低字节 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+4],topic_name,strlen(topic_name)); //复制主题字串 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+4+strlen(topic_name)] = 0; //QOS等级设置为0 + + while(TrySub_time > 0) + { + memset(mqtt_rxbuf,0,sizeof(mqtt_rxbuf)); + MQTT_Send(Platform_mqtt.Pack_buff,Platform_mqtt.Fixed_len + Platform_mqtt.Variable_len + Platform_mqtt.Payload_len); + MdelayKTask(50); + MQTT_Recv(mqtt_rxbuf, 5); + if(mqtt_rxbuf[0] == parket_subAck[0] && mqtt_rxbuf[1] == parket_subAck[1]) //订阅成功 + { + return 0; + } + TrySub_time--; + } + return 1; +} + + +/******************************************************************************* +* 函 数 名: MQTT_UnSubscribeTopic +* 功能描述: MQTT取消订阅单个主题 +* 形 参: topic_name:要取消订阅的主题 +* 返 回 值: 0表示订阅成功,1表示订阅失败 +*******************************************************************************/ +int MQTT_UnSubscribeTopic(uint8_t *topic_name) +{ + uint8_t TryUnSub_time = 10; //尝试取消订阅次数 + + Platform_mqtt.Fixed_len = 1; //UNSUBSCRIBE报文,固定报头长度暂定为1 + Platform_mqtt.Variable_len = 2; //UNSUBSCRIBE报文,可变报头长度=2,2为字节报文标识符 + Platform_mqtt.Payload_len = strlen(topic_name) + 2; //每个需要取消的订阅topic除了本身的字符串长度,还包含表示topic字符串长度的2字节 + Platform_mqtt.Remaining_len = Platform_mqtt.Variable_len + Platform_mqtt.Payload_len; //计算剩余长度=可变报头长度+负载长度 + memset(Platform_mqtt.Pack_buff,0,sizeof(Platform_mqtt.Pack_buff)); + + Platform_mqtt.Pack_buff[0]=0xA0; //UNSUBSCRIBE报文,固定报头第1个字节0xA0 + do{ + if((Platform_mqtt.Remaining_len/128) == 0) + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = Platform_mqtt.Remaining_len; + } + else + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = (Platform_mqtt.Remaining_len%128)|0x80; + } + Platform_mqtt.Fixed_len++; + Platform_mqtt.Remaining_len = Platform_mqtt.Remaining_len/128; + }while(Platform_mqtt.Remaining_len); + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+0] = Platform_mqtt.MessageID/256; //报文标识符高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+1] = Platform_mqtt.MessageID%256; //报文标识符低字节 + Platform_mqtt.MessageID++; //每用一次MessageID加1 + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+2] = strlen(topic_name)/256; //主题长度高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+3] = strlen(topic_name)%256; //主题长度低字节 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+4],topic_name,strlen(topic_name)); //复制主题字串 + + while(TryUnSub_time > 0) + { + memset(mqtt_rxbuf,0,sizeof(mqtt_rxbuf)); + MQTT_Send(Platform_mqtt.Pack_buff,Platform_mqtt.Fixed_len + Platform_mqtt.Variable_len + Platform_mqtt.Payload_len); + MdelayKTask(50); + MQTT_Recv(mqtt_rxbuf, 4); + if(mqtt_rxbuf[0] == parket_unsubAck[0] && mqtt_rxbuf[1] == parket_unsubAck[1]) //取消订阅成功 + { + return 0; + } + TryUnSub_time--; + } + return 1; +} + + +/******************************************************************************* +* 函 数 名: MQTT_PublishDataQs0 +* 功能描述: 向服务器发送等级0的Publish报文 +* 形 参: topic_name:主题名称 + data:数据缓存 + data_len:数据长度 +* 返 回 值: 发布Qs=0的消息服务器不返回确认消息 +*******************************************************************************/ +void MQTT_PublishDataQs0(uint8_t *topic_name,uint8_t *data, uint16_t data_len) +{ + Platform_mqtt.Fixed_len = 1; //PUBLISH等级0报文固定报头长度暂定为1 + Platform_mqtt.Variable_len = 2 + strlen(topic_name); //PUBLISH等级0报文,可变报头长度=2字节topic长度标识字节+topic字符串的长度 + Platform_mqtt.Payload_len = data_len; //PUBLISH等级0报文,负载数据长度=data_len + Platform_mqtt.Remaining_len = Platform_mqtt.Variable_len + Platform_mqtt.Payload_len; //计算剩余长度=可变报头长度+负载长度 + memset(Platform_mqtt.Pack_buff,0,sizeof(Platform_mqtt.Pack_buff)); + + Platform_mqtt.Pack_buff[0]=0x30; //PUBLISH等级0报文固定报头第1个字节0x30 + do{ + if((Platform_mqtt.Remaining_len/128) == 0) + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = Platform_mqtt.Remaining_len; + } + else + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = (Platform_mqtt.Remaining_len%128)|0x80; + } + Platform_mqtt.Fixed_len++; + Platform_mqtt.Remaining_len = Platform_mqtt.Remaining_len/128; + }while(Platform_mqtt.Remaining_len); + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+0]=strlen(topic_name)/256; //主题长度高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+1]=strlen(topic_name)%256; //主题长度低字节 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+2],topic_name,strlen(topic_name)); //复制主题字串 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+2+strlen(topic_name)],data,data_len); //复制data数据 + + MQTT_Send(Platform_mqtt.Pack_buff, Platform_mqtt.Fixed_len + Platform_mqtt.Variable_len + Platform_mqtt.Payload_len); +} + + +/******************************************************************************* +* 函 数 名: MQTT_PublishDataQs1 +* 功能描述: 向服务器发送等级1的Publish报文 +* 形 参: topic_name:主题名称 + data:数据缓存 + data_len:数据长度 +* 返 回 值: 无 +*******************************************************************************/ +void MQTT_PublishDataQs1(uint8_t *topic_name,uint8_t *data, uint16_t data_len) +{ + Platform_mqtt.Fixed_len = 1; //PUBLISH等级1报文固定报头长度暂定为1 + Platform_mqtt.Variable_len = 2 + 2 + strlen(topic_name); //PUBLISH等级1报文,可变报头长度=2字节消息标识符+2字节topic长度标识字节+topic字符串的长度 + Platform_mqtt.Payload_len = data_len; //PUBLISH等级1报文,负载数据长度=data_len + Platform_mqtt.Remaining_len = Platform_mqtt.Variable_len + Platform_mqtt.Payload_len; //计算剩余长度=可变报头长度+负载长度 + + Platform_mqtt.Pack_buff[0] = 0x32; //等级1的Publish报文固定报头第1个字节,0x32 + do{ + if(Platform_mqtt.Remaining_len/128 == 0) + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = Platform_mqtt.Remaining_len; + } + else + { + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len] = (Platform_mqtt.Remaining_len%128)|0x80; + } + Platform_mqtt.Fixed_len++; + Platform_mqtt.Remaining_len = Platform_mqtt.Remaining_len/128; + }while(Platform_mqtt.Remaining_len); + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+0] = strlen(topic_name)/256; //主题长度高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+1] = strlen(topic_name)%256; //主题长度低字节 + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+2],topic_name,strlen(topic_name)); //复制主题字串 + + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+2+strlen(topic_name)] = Platform_mqtt.MessageID/256; //报文标识符高字节 + Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+3+strlen(topic_name)] = Platform_mqtt.MessageID%256; //报文标识符低字节 + Platform_mqtt.MessageID++; //每用一次MessageID加1 + + memcpy(&Platform_mqtt.Pack_buff[Platform_mqtt.Fixed_len+4+strlen(topic_name)],data,strlen(data)); //复制data数据 + + MQTT_Send(Platform_mqtt.Pack_buff,Platform_mqtt.Fixed_len + Platform_mqtt.Variable_len + Platform_mqtt.Payload_len); +} + + +/******************************************************************************* +* 函 数 名: MQTT_SendHeart +* 功能描述: 发送心跳保活包 +* 形 参: 无 +* 返 回 值: 0表示发送成功,其他值表示发送失败 +*******************************************************************************/ +int MQTT_SendHeart(void) +{ + uint8_t TrySentHeart_time = 10; //尝试发送心跳保活次数 + while(TrySentHeart_time > 0) + { + memset(mqtt_rxbuf,0,sizeof(mqtt_rxbuf)); + MQTT_Send(parket_heart,sizeof(parket_heart)); + MdelayKTask(50); + MQTT_Recv(mqtt_rxbuf, 2); + if(mqtt_rxbuf[0] == 0xD0 && mqtt_rxbuf[1] == 0x00) + { + return 0; + } + TrySentHeart_time--; + } + return 1; +} + + +/******************************************************************************* +* 函 数 名: MQTT_DealPublishData +* 功能描述: 处理服务器发来的等级0的推送数据,附带topic信息 +* 形 参: redata:接收的数据,data_len:要处理的数据长度 +* 返 回 值: 无 +*******************************************************************************/ +void MQTT_DealPublishData(uint8_t *data, uint16_t data_len) +{ + uint8_t i; + uint16_t cmdpos,cmdlen; + + for(i = 1;i < 5;i++) + { + if((data[i] & 0x80) == 0) + break; + } + + cmdpos = 1+i+2; + cmdlen = data_len-(1+i+2); + + if(data_len <= CMD_SIZE) + { + memset(Platform_mqtt.cmdbuff, 0, CMD_SIZE); + memcpy(Platform_mqtt.cmdbuff, &data[cmdpos], cmdlen); + } +} diff --git a/Ubiquitous/XiZi_IIoT/tool/mqtt/platform_mqtt.h b/Ubiquitous/XiZi_IIoT/tool/mqtt/platform_mqtt.h new file mode 100644 index 000000000..a7331ffed --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/mqtt/platform_mqtt.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: platform_mqtt.h +* @brief: platform_mqtt.h file +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/6/14 +* +*/ + +#ifndef _PLATFORM_MQTT_H_ +#define _PLATFORM_MQTT_H_ + +#include +#include "utils_hmacsha1.h" + +#define KEEPALIVE_TIME 300 //保活时间(单位s),300s +#define HEART_TIME 120000 //空闲时发送心跳包的时间间隔(单位ms),120s +#define PACK_SIZE 512 //存放报文数据缓冲区大小 +#define CMD_SIZE 3072 //保存推送的PUBLISH报文中的数据缓冲区大小 +#define CLIENTID_SIZE 64 //存放客户端ID的缓冲区大小 +#define USERNAME_SIZE 64 //存放用户名的缓冲区大小 +#define PASSWARD_SIZE 64 //存放密码的缓冲区大小 + +typedef struct{ + uint8_t ClientID[CLIENTID_SIZE]; //存放客户端ID的缓冲区 + uint8_t Username[USERNAME_SIZE]; //存放用户名的缓冲区 + uint8_t Passward[PASSWARD_SIZE]; //存放密码的缓冲区 + uint8_t Pack_buff[PACK_SIZE]; //存放发送报文数据缓冲区 + uint16_t MessageID; //记录报文标识符 + uint16_t Fixed_len; //固定报头长度 + uint16_t Variable_len; //可变报头长度 + uint16_t Payload_len; //有效负荷长度 + uint16_t Remaining_len; //保存报文剩余长度字节 + uint8_t cmdbuff[CMD_SIZE]; //保存推送的PUBLISH报文中的数据缓冲区 +}MQTT_TCB; + +extern MQTT_TCB Platform_mqtt; //外部变量声明 + +int AdapterNetActive(void); +int MQTT_Send(const uint8_t* buf, int buflen); +int MQTT_Recv(uint8_t* buf, int buflen); +int MQTT_Connect(void); +void MQTT_Disconnect(void); +int MQTT_SubscribeTopic(uint8_t *topic_name); +int MQTT_UnSubscribeTopic(uint8_t *topic_name); +void MQTT_PublishDataQs0(uint8_t *topic_name,uint8_t *data, uint16_t data_len); +void MQTT_PublishDataQs1(uint8_t *topic_name,uint8_t *data, uint16_t data_len); +int MQTT_SendHeart(void); +void MQTT_DealPublishData(uint8_t *data, uint16_t data_len); +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/mqtt/utils_hmacsha1.c b/Ubiquitous/XiZi_IIoT/tool/mqtt/utils_hmacsha1.c new file mode 100644 index 000000000..41b63e6e0 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/mqtt/utils_hmacsha1.c @@ -0,0 +1,399 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: utils_hmacsha1.c +* @brief: utils_hmacsha1.c file +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/6/29 +* +*/ + +#include "utils_hmacsha1.h" + +#define KEY_IOPAD_SIZE 64 +#define SHA1_DIGEST_SIZE 20 + +static void utils_sha1_zeroize(void *v, size_t n); +static void utils_sha1_init(iot_sha1_context *ctx); +static void utils_sha1_free(iot_sha1_context *ctx); +static void utils_sha1_clone(iot_sha1_context *dst, const iot_sha1_context *src); +static void utils_sha1_starts(iot_sha1_context *ctx); +static void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]); +static void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen); +static void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]); +static void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]); +static int8_t utils_hb2hex(uint8_t hb); + +const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* Implementation that should never be optimized out by the compiler */ +static void utils_sha1_zeroize(void *v, size_t n) +{ + volatile unsigned char *p = v; + while(n--) { + *p++ = 0; + } +} + +/* 32-bit integer manipulation macros (big endian) */ +#ifndef IOT_SHA1_GET_UINT32_BE +#define IOT_SHA1_GET_UINT32_BE(n,b,i) \ + { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ + } +#endif + +#ifndef IOT_SHA1_PUT_UINT32_BE +#define IOT_SHA1_PUT_UINT32_BE(n,b,i) \ + { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ + } +#endif + +void utils_sha1_init(iot_sha1_context *ctx) +{ + memset(ctx, 0, sizeof(iot_sha1_context)); +} + +void utils_sha1_free(iot_sha1_context *ctx) +{ + if(ctx == NULL) { + return; + } + + utils_sha1_zeroize(ctx, sizeof(iot_sha1_context)); +} + +void utils_sha1_clone(iot_sha1_context *dst, + const iot_sha1_context *src) +{ + *dst = *src; +} + +/* SHA-1 context setup */ +void utils_sha1_starts(iot_sha1_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; + ctx->state[4] = 0xC3D2E1F0; +} + +void utils_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]) +{ + uint32_t temp, W[16], A, B, C, D, E; + + IOT_SHA1_GET_UINT32_BE(W[ 0], data, 0); + IOT_SHA1_GET_UINT32_BE(W[ 1], data, 4); + IOT_SHA1_GET_UINT32_BE(W[ 2], data, 8); + IOT_SHA1_GET_UINT32_BE(W[ 3], data, 12); + IOT_SHA1_GET_UINT32_BE(W[ 4], data, 16); + IOT_SHA1_GET_UINT32_BE(W[ 5], data, 20); + IOT_SHA1_GET_UINT32_BE(W[ 6], data, 24); + IOT_SHA1_GET_UINT32_BE(W[ 7], data, 28); + IOT_SHA1_GET_UINT32_BE(W[ 8], data, 32); + IOT_SHA1_GET_UINT32_BE(W[ 9], data, 36); + IOT_SHA1_GET_UINT32_BE(W[10], data, 40); + IOT_SHA1_GET_UINT32_BE(W[11], data, 44); + IOT_SHA1_GET_UINT32_BE(W[12], data, 48); + IOT_SHA1_GET_UINT32_BE(W[13], data, 52); + IOT_SHA1_GET_UINT32_BE(W[14], data, 56); + IOT_SHA1_GET_UINT32_BE(W[15], data, 60); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ + ( \ + temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ + W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ + ) + +#define P(a,b,c,d,e,x) \ + { \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P(A, B, C, D, E, W[0]); + P(E, A, B, C, D, W[1]); + P(D, E, A, B, C, W[2]); + P(C, D, E, A, B, W[3]); + P(B, C, D, E, A, W[4]); + P(A, B, C, D, E, W[5]); + P(E, A, B, C, D, W[6]); + P(D, E, A, B, C, W[7]); + P(C, D, E, A, B, W[8]); + P(B, C, D, E, A, W[9]); + P(A, B, C, D, E, W[10]); + P(E, A, B, C, D, W[11]); + P(D, E, A, B, C, W[12]); + P(C, D, E, A, B, W[13]); + P(B, C, D, E, A, W[14]); + P(A, B, C, D, E, W[15]); + P(E, A, B, C, D, R(16)); + P(D, E, A, B, C, R(17)); + P(C, D, E, A, B, R(18)); + P(B, C, D, E, A, R(19)); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P(A, B, C, D, E, R(20)); + P(E, A, B, C, D, R(21)); + P(D, E, A, B, C, R(22)); + P(C, D, E, A, B, R(23)); + P(B, C, D, E, A, R(24)); + P(A, B, C, D, E, R(25)); + P(E, A, B, C, D, R(26)); + P(D, E, A, B, C, R(27)); + P(C, D, E, A, B, R(28)); + P(B, C, D, E, A, R(29)); + P(A, B, C, D, E, R(30)); + P(E, A, B, C, D, R(31)); + P(D, E, A, B, C, R(32)); + P(C, D, E, A, B, R(33)); + P(B, C, D, E, A, R(34)); + P(A, B, C, D, E, R(35)); + P(E, A, B, C, D, R(36)); + P(D, E, A, B, C, R(37)); + P(C, D, E, A, B, R(38)); + P(B, C, D, E, A, R(39)); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P(A, B, C, D, E, R(40)); + P(E, A, B, C, D, R(41)); + P(D, E, A, B, C, R(42)); + P(C, D, E, A, B, R(43)); + P(B, C, D, E, A, R(44)); + P(A, B, C, D, E, R(45)); + P(E, A, B, C, D, R(46)); + P(D, E, A, B, C, R(47)); + P(C, D, E, A, B, R(48)); + P(B, C, D, E, A, R(49)); + P(A, B, C, D, E, R(50)); + P(E, A, B, C, D, R(51)); + P(D, E, A, B, C, R(52)); + P(C, D, E, A, B, R(53)); + P(B, C, D, E, A, R(54)); + P(A, B, C, D, E, R(55)); + P(E, A, B, C, D, R(56)); + P(D, E, A, B, C, R(57)); + P(C, D, E, A, B, R(58)); + P(B, C, D, E, A, R(59)); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P(A, B, C, D, E, R(60)); + P(E, A, B, C, D, R(61)); + P(D, E, A, B, C, R(62)); + P(C, D, E, A, B, R(63)); + P(B, C, D, E, A, R(64)); + P(A, B, C, D, E, R(65)); + P(E, A, B, C, D, R(66)); + P(D, E, A, B, C, R(67)); + P(C, D, E, A, B, R(68)); + P(B, C, D, E, A, R(69)); + P(A, B, C, D, E, R(70)); + P(E, A, B, C, D, R(71)); + P(D, E, A, B, C, R(72)); + P(C, D, E, A, B, R(73)); + P(B, C, D, E, A, R(74)); + P(A, B, C, D, E, R(75)); + P(E, A, B, C, D, R(76)); + P(D, E, A, B, C, R(77)); + P(C, D, E, A, B, R(78)); + P(B, C, D, E, A, R(79)); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} + +/* SHA-1 process buffer */ +void utils_sha1_update(iot_sha1_context *ctx, const unsigned char *input, size_t ilen) +{ + size_t fill; + uint32_t left; + + if(ilen == 0) { + return; + } + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) 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); + utils_sha1_process(ctx, ctx->buffer); + input += fill; + ilen -= fill; + left = 0; + } + + while(ilen >= 64) { + utils_sha1_process(ctx, input); + input += 64; + ilen -= 64; + } + + if(ilen > 0) { + memcpy((void *)(ctx->buffer + left), input, ilen); + } +} + +static const unsigned char iot_sha1_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 +}; + +/* SHA-1 final digest */ +void utils_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = (ctx->total[0] >> 29) + | (ctx->total[1] << 3); + low = (ctx->total[0] << 3); + + IOT_SHA1_PUT_UINT32_BE(high, msglen, 0); + IOT_SHA1_PUT_UINT32_BE(low, msglen, 4); + + last = ctx->total[0] & 0x3F; + padn = (last < 56) ? (56 - last) : (120 - last); + + utils_sha1_update(ctx, iot_sha1_padding, padn); + utils_sha1_update(ctx, msglen, 8); + + IOT_SHA1_PUT_UINT32_BE(ctx->state[0], output, 0); + IOT_SHA1_PUT_UINT32_BE(ctx->state[1], output, 4); + IOT_SHA1_PUT_UINT32_BE(ctx->state[2], output, 8); + IOT_SHA1_PUT_UINT32_BE(ctx->state[3], output, 12); + IOT_SHA1_PUT_UINT32_BE(ctx->state[4], output, 16); +} + + +/* output = SHA-1(input buffer) */ +void utils_sha1(const unsigned char *input, size_t ilen, unsigned char output[20]) +{ + iot_sha1_context ctx; + + utils_sha1_init(&ctx); + utils_sha1_starts(&ctx); + utils_sha1_update(&ctx, input, ilen); + utils_sha1_finish(&ctx, output); + utils_sha1_free(&ctx); +} + + +inline int8_t utils_hb2hex(uint8_t hb) +{ + hb = hb & 0xF; + return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a'); +} + + +void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len) +{ + iot_sha1_context context; + unsigned char k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */ + unsigned char out[SHA1_DIGEST_SIZE]; + int i; + + if((NULL == msg) || (NULL == digest) || (NULL == key)) { + return; + } + + if(key_len > KEY_IOPAD_SIZE) { + return; + } + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for(i = 0; i < KEY_IOPAD_SIZE; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* perform inner SHA */ + utils_sha1_init(&context); /* init context for 1st pass */ + utils_sha1_starts(&context); /* setup context for 1st pass */ + utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE); /* start with inner pad */ + utils_sha1_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */ + utils_sha1_finish(&context, out); /* finish up 1st pass */ + + /* perform outer SHA */ + utils_sha1_init(&context); /* init context for 2nd pass */ + utils_sha1_starts(&context); /* setup context for 2nd pass */ + utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */ + utils_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */ + utils_sha1_finish(&context, out); /* finish up 2nd pass */ + + for(i = 0; i < SHA1_DIGEST_SIZE; ++i) { + digest[i * 2] = utils_hb2hex(out[i] >> 4); + digest[i * 2 + 1] = utils_hb2hex(out[i]); + } +} \ No newline at end of file diff --git a/Ubiquitous/XiZi_IIoT/tool/mqtt/utils_hmacsha1.h b/Ubiquitous/XiZi_IIoT/tool/mqtt/utils_hmacsha1.h new file mode 100644 index 000000000..da56792a4 --- /dev/null +++ b/Ubiquitous/XiZi_IIoT/tool/mqtt/utils_hmacsha1.h @@ -0,0 +1,41 @@ +/* +* Copyright (c) 2020 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file: utils_hmacsha1.h +* @brief: utils_hmacsha1.h file +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2023/6/29 +* +*/ + +#ifndef UTILS_HMACSHA1_H_ +#define UTILS_HMACSHA1_H_ + +#include "stdio.h" +#include "stdint.h" +#include "stdlib.h" +#include "string.h" + +/* SHA-1 context structure */ +typedef struct { + uint32_t total[2]; /* number of bytes processed */ + uint32_t state[5]; /* intermediate digest state */ + unsigned char buffer[64]; /* data block being processed */ +} iot_sha1_context; + + +void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len); + +#endif +