Merge branch 'prepare_for_master' of https://gitlink.org.cn/xuos/xiuos into wiz_lwip

This commit is contained in:
TXuian 2023-09-21 10:34:11 +08:00
commit 159159ecde
24 changed files with 2696 additions and 480 deletions

View File

@ -17,12 +17,21 @@
extern int FrameworkInit(); extern int FrameworkInit();
extern void ApplicationOtaTaskInit(void); extern void ApplicationOtaTaskInit(void);
#ifdef OTA_BY_PLATFORM
extern int OtaTask(void);
#endif
int main(void) int main(void)
{ {
printf("Hello, world! \n"); printf("Hello, world! \n");
FrameworkInit(); FrameworkInit();
#ifdef APPLICATION_OTA #ifdef APPLICATION_OTA
ApplicationOtaTaskInit(); ApplicationOtaTaskInit();
#endif
#ifdef OTA_BY_PLATFORM
OtaTask();
#endif #endif
return 0; return 0;
} }

View File

@ -23,7 +23,7 @@ if ADD_XIZI_FEATURES
config ADAPTER_EC200T_DRIVER config ADAPTER_EC200T_DRIVER
string "EC200T device uart driver path" string "EC200T device uart driver path"
default "/dev/usart2_dev2" default "/dev/uart8_dev8"
depends on !ADAPTER_EC200T_DRIVER_EXTUART depends on !ADAPTER_EC200T_DRIVER_EXTUART
if ADAPTER_EC200T_DRIVER_EXTUART if ADAPTER_EC200T_DRIVER_EXTUART

View File

@ -163,8 +163,12 @@ static int Ec200tIoctl(struct Adapter *adapter, int cmd, void *args)
serial_cfg.serial_parity_mode = PARITY_NONE; serial_cfg.serial_parity_mode = PARITY_NONE;
serial_cfg.serial_bit_order = STOP_BITS_1; serial_cfg.serial_bit_order = STOP_BITS_1;
serial_cfg.serial_invert_mode = NRZ_NORMAL; serial_cfg.serial_invert_mode = NRZ_NORMAL;
#ifdef TOOL_USING_OTA
serial_cfg.serial_timeout = OTA_RX_TIMEOUT;
#else
//serial receive timeout 10s //serial receive timeout 10s
serial_cfg.serial_timeout = 10000; serial_cfg.serial_timeout = 100000;
#endif
serial_cfg.is_ext_uart = 0; serial_cfg.is_ext_uart = 0;
#ifdef ADAPTER_EC200T_DRIVER_EXT_PORT #ifdef ADAPTER_EC200T_DRIVER_EXT_PORT
serial_cfg.is_ext_uart = 1; serial_cfg.is_ext_uart = 1;

View File

@ -6,7 +6,7 @@ menuconfig SUPPORT_CONNECTION_FRAMEWORK
if SUPPORT_CONNECTION_FRAMEWORK if SUPPORT_CONNECTION_FRAMEWORK
config CONNECTION_FRAMEWORK_DEBUG config CONNECTION_FRAMEWORK_DEBUG
bool "Using connection framework debug log function" bool "Using connection framework debug log function"
default y default n
menuconfig CONNECTION_INDUSTRIAL_NETWORK menuconfig CONNECTION_INDUSTRIAL_NETWORK
bool "Using industrial network" bool "Using industrial network"

View File

@ -124,7 +124,9 @@ int ParseATReply(char *str, const char *format, ...)
void ATSprintf(int fd, const char *format, va_list params) void ATSprintf(int fd, const char *format, va_list params)
{ {
last_cmd_len = vsnprintf(send_buf, sizeof(send_buf), format, 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); printf("AT send %s len %u\n",send_buf, last_cmd_len);
#endif
PrivWrite(fd, send_buf, last_cmd_len); PrivWrite(fd, send_buf, last_cmd_len);
} }
@ -264,29 +266,34 @@ int AtSetReplyCharNum(ATAgentType agent, unsigned int num)
int EntmSend(ATAgentType agent, const char *data, int len) int EntmSend(ATAgentType agent, const char *data, int len)
{ {
char send_buf[128]; if(len > 256){
if(len > 128){ printf("send length %d more then max 256 Bytes.\n",len);
printf("send length %d more then max 128 Bytes.\n",len);
return -1; return -1;
} }
char *send_buff = (char *)PrivMalloc(256);
PrivMutexObtain(&agent->lock); PrivMutexObtain(&agent->lock);
memset(send_buf, 0, 128); memset(send_buff, 0, 256);
agent->receive_mode = ENTM_MODE; agent->receive_mode = ENTM_MODE;
memcpy(send_buf, data, len); memcpy(send_buff, data, len);
// memcpy(send_buf + len, "!@", 2);
PrivWrite(agent->fd, send_buf, len); PrivWrite(agent->fd, send_buff, len);
PrivMutexAbandon(&agent->lock); PrivMutexAbandon(&agent->lock);
printf("entm send %s length %d\n",send_buf, len); #ifdef CONNECTION_FRAMEWORK_DEBUG
printf("entm send length %d\n", len);
#endif
PrivFree(send_buff);
return 0; return 0;
} }
int EntmRecv(ATAgentType agent, char *rev_buffer, int buffer_len, int timeout_s) int EntmRecv(ATAgentType agent, char *rev_buffer, int buffer_len, int timeout_s)
{ {
struct timespec abstime; struct timespec abstime;
uint32 real_recv_len = 0;
abstime.tv_sec = timeout_s; abstime.tv_sec = timeout_s;
if(buffer_len > ENTM_RECV_MAX){ if(buffer_len > ENTM_RECV_MAX){
@ -299,21 +306,25 @@ int EntmRecv(ATAgentType agent, char *rev_buffer, int buffer_len, int timeout_s)
PrivMutexAbandon(&agent->lock); PrivMutexAbandon(&agent->lock);
//PrivTaskDelay(1000); //PrivTaskDelay(1000);
if (PrivSemaphoreObtainWait(&agent->entm_rx_notice, &abstime)) { if (PrivSemaphoreObtainWait(&agent->entm_rx_notice, &abstime)) {
#ifdef CONNECTION_FRAMEWORK_DEBUG
printf("wait sem[%d] timeout\n",agent->entm_rx_notice); printf("wait sem[%d] timeout\n",agent->entm_rx_notice);
#endif
agent->entm_recv_len = 0;
return -1; return -1;
} }
PrivMutexObtain(&agent->lock); PrivMutexObtain(&agent->lock);
#ifdef CONNECTION_FRAMEWORK_DEBUG
printf("EntmRecv once len %d.\n", agent->entm_recv_len); printf("EntmRecv once len %d.\n", agent->entm_recv_len);
#endif
memcpy(rev_buffer, agent->entm_recv_buf, agent->entm_recv_len); memcpy(rev_buffer, agent->entm_recv_buf, agent->entm_recv_len);
memset(agent->entm_recv_buf, 0, ENTM_RECV_MAX); memset(agent->entm_recv_buf, 0, ENTM_RECV_MAX);
real_recv_len = agent->entm_recv_len;
agent->entm_recv_len = 0; agent->entm_recv_len = 0;
agent->read_len = 0; agent->read_len = 0;
PrivMutexAbandon(&agent->lock); PrivMutexAbandon(&agent->lock);
return buffer_len; return real_recv_len;
} }
static int GetCompleteATReply(ATAgentType agent) static int GetCompleteATReply(ATAgentType agent)
@ -321,21 +332,22 @@ static int GetCompleteATReply(ATAgentType agent)
uint32_t read_len = 0; uint32_t read_len = 0;
char ch = 0, last_ch = 0; char ch = 0, last_ch = 0;
bool is_full = false; bool is_full = false;
int res;
PrivMutexObtain(&agent->lock); PrivMutexObtain(&agent->lock);
memset(agent->maintain_buffer, 0x00, agent->maintain_max); memset(agent->maintain_buffer, 0x00, agent->maintain_max);
agent->maintain_len = 0; 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; agent->entm_recv_len = 0;
PrivMutexAbandon(&agent->lock); PrivMutexAbandon(&agent->lock);
while (1) { while (1) {
PrivRead(agent->fd, &ch, 1); res = PrivRead(agent->fd, &ch, 1);
#ifdef CONNECTION_FRAMEWORK_DEBUG #ifdef CONNECTION_FRAMEWORK_DEBUG
if(ch != 0) { if((res == 1) && (ch != 0)) {
printf(" %c (0x%x)\n", ch, ch); printf(" %c (0x%x)\n", ch, ch);
} }
#endif #endif
@ -343,14 +355,28 @@ static int GetCompleteATReply(ATAgentType agent)
PrivMutexObtain(&agent->lock); PrivMutexObtain(&agent->lock);
if (agent->receive_mode == ENTM_MODE) { if (agent->receive_mode == ENTM_MODE) {
if (agent->entm_recv_len < ENTM_RECV_MAX) { if (agent->entm_recv_len < ENTM_RECV_MAX) {
agent->entm_recv_buf[agent->entm_recv_len] = ch; #ifdef TOOL_USING_MQTT
agent->entm_recv_len++; if((res == 1) && (agent->entm_recv_len < agent->read_len))
{
if(agent->entm_recv_len < agent->read_len) { agent->entm_recv_buf[agent->entm_recv_len] = ch;
agent->entm_recv_len++;
PrivMutexAbandon(&agent->lock); PrivMutexAbandon(&agent->lock);
continue; 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); printf("ENTM_MODE recv %d Bytes done.\n",agent->entm_recv_len);
#endif
agent->receive_mode = DEFAULT_MODE; agent->receive_mode = DEFAULT_MODE;
PrivSemaphoreAbandon(&agent->entm_rx_notice); PrivSemaphoreAbandon(&agent->entm_rx_notice);
} }

View File

@ -28,6 +28,12 @@
#define REPLY_TIME_OUT 10 #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 enum ReceiveMode
{ {
DEFAULT_MODE = 0, DEFAULT_MODE = 0,
@ -70,7 +76,6 @@ struct ATAgent
#endif #endif
pthread_t at_handler; pthread_t at_handler;
#define ENTM_RECV_MAX 256
char entm_recv_buf[ENTM_RECV_MAX]; char entm_recv_buf[ENTM_RECV_MAX];
uint32 entm_recv_len; uint32 entm_recv_len;
enum ReceiveMode receive_mode; enum ReceiveMode receive_mode;

View File

@ -14,4 +14,5 @@ menu "app lib"
source "$APP_DIR/lib/lvgl/Kconfig" source "$APP_DIR/lib/lvgl/Kconfig"
source "$APP_DIR/lib/embedded_database/Kconfig" source "$APP_DIR/lib/embedded_database/Kconfig"
source "$APP_DIR/lib/lorawan/Kconfig" source "$APP_DIR/lib/lorawan/Kconfig"
source "$APP_DIR/lib/mqtt/Kconfig"
endmenu endmenu

View File

@ -18,4 +18,8 @@ ifeq ($(CONFIG_LIB_USING_LORAWAN),y)
SRC_DIR += lorawan SRC_DIR += lorawan
endif endif
ifeq ($(CONFIG_TOOL_USING_MQTT),y)
SRC_DIR += mqtt
endif
include $(KERNEL_ROOT)/compiler.mk include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,33 @@
menu "lib using MQTT"
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 "iv74vebCdJC"
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 "d2e613c4f714b6b0774bd7b68eeceae3"
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

View File

@ -0,0 +1,3 @@
SRC_FILES := platform_mqtt.c utils_hmacsha1.c
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,438 @@
/*
* 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/7/27
*
*/
#include <string.h>
#include <stdint.h>
#include <adapter.h>
#include <transform.h>
#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
* : 0Publish报文
* : 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
* : 1Publish报文
* : 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);
}
}

View File

@ -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/7/27
*
*/
#ifndef _PLATFORM_MQTT_H_
#define _PLATFORM_MQTT_H_
#include <stdint.h>
#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

View File

@ -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/7/27
*
*/
#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]);
}
}

View File

@ -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/7/27
*
*/
#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

View File

@ -21,8 +21,12 @@ CONFIG_BSP_USING_LPUART3=y
CONFIG_SERIAL_BUS_NAME_3="uart3" CONFIG_SERIAL_BUS_NAME_3="uart3"
CONFIG_SERIAL_DRV_NAME_3="uart3_drv" CONFIG_SERIAL_DRV_NAME_3="uart3_drv"
CONFIG_SERIAL_3_DEVICE_NAME_0="uart3_dev3" CONFIG_SERIAL_3_DEVICE_NAME_0="uart3_dev3"
# CONFIG_BSP_USING_LPUART4 is not set # CONFIG_BSP_USING_LPUART4 is not set
# CONFIG_BSP_USING_LPUART8 is not set CONFIG_BSP_USING_LPUART8=y
CONFIG_SERIAL_BUS_NAME_8="uart8"
CONFIG_SERIAL_DRV_NAME_8="uart8_drv"
CONFIG_SERIAL_8_DEVICE_NAME_0="uart8_dev8"
# CONFIG_BSP_USING_CH438 is not set # CONFIG_BSP_USING_CH438 is not set
CONFIG_BSP_USING_GPIO=y CONFIG_BSP_USING_GPIO=y
CONFIG_PIN_BUS_NAME="pin" CONFIG_PIN_BUS_NAME="pin"
@ -63,7 +67,7 @@ CONFIG___STACKSIZE__=4096
# #
CONFIG_RESOURCES_SERIAL=y CONFIG_RESOURCES_SERIAL=y
CONFIG_SERIAL_USING_DMA=y CONFIG_SERIAL_USING_DMA=y
CONFIG_SERIAL_RB_BUFSZ=128 CONFIG_SERIAL_RB_BUFSZ=256
CONFIG_RESOURCES_PIN=y CONFIG_RESOURCES_PIN=y
# #
@ -125,7 +129,7 @@ CONFIG_ZOMBIE_KTASK_STACKSIZE=2048
# #
CONFIG_KERNEL_CONSOLE=y CONFIG_KERNEL_CONSOLE=y
CONFIG_KERNEL_BANNER=y CONFIG_KERNEL_BANNER=y
CONFIG_KERNEL_CONSOLEBUF_SIZE=128 CONFIG_KERNEL_CONSOLEBUF_SIZE=256
# #
# Kernel Hook # Kernel Hook
@ -231,6 +235,7 @@ CONFIG_ADD_XIZI_FEATURES=y
# CONFIG_SUPPORT_KNOWING_FRAMEWORK is not set # CONFIG_SUPPORT_KNOWING_FRAMEWORK is not set
# CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set # CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set
# #
# Security # Security
# #

View File

@ -507,7 +507,7 @@ static status_t flexspi_config_mcr1(uint32_t instance, flexspi_mem_config_t *con
// Configure MCR1 // Configure MCR1
FLEXSPI->MCR1 = FLEXSPI_MCR1_SEQWAIT(seqWaitTicks) | FLEXSPI_MCR1_AHBBUSWAIT(ahbBusWaitTicks); FLEXSPI->MCR1 = FLEXSPI_MCR1_SEQWAIT(seqWaitTicks) | FLEXSPI_MCR1_AHBBUSWAIT(ahbBusWaitTicks);
return kStatus_Success; return (status_t)kStatus_Success;
} }
@ -647,14 +647,14 @@ uint8_t FLASH_WritePage(uint32_t addr, const uint32_t *buf, uint32_t len)
/******************************************************************************* /*******************************************************************************
* : FLASH_Read * : FLASH_ReadBuf
* : Flash内容 * : Flash内容
* : addr: * : addr:
buf: buf:
len: len:
* : kStatus_Success * : kStatus_Success
*******************************************************************************/ *******************************************************************************/
status_t FLASH_Read(uint32_t addr, uint32_t *buf, uint32_t len) status_t FLASH_ReadBuf(uint32_t addr, uint32_t *buf, uint32_t len)
{ {
status_t status; status_t status;
flexspi_xfer_t flashXfer; flexspi_xfer_t flashXfer;
@ -678,206 +678,28 @@ status_t FLASH_Read(uint32_t addr, uint32_t *buf, uint32_t len)
} }
/*******************************************************************************
* : flash_erase
* : Flash指定长度的空间
* : addr:
byte_cnt:,4k字节为最小擦除单位
* : kStatus_Success
* : 4k字节的4k字节
*******************************************************************************/
status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt)
{
uint32_t addr;
status_t status;
addr = start_addr;
while(addr < (byte_cnt + start_addr))
{
status = FLASH_EraseSector(addr);
if(status != kStatus_Success)
{
return status;
}
addr += FLASH_GetSectorSize();
}
return status;
}
/*******************************************************************************
* : flash_write
* : flash起始地址写入指定长度的数据
* : addr:
buf:
byte_cnt:
* : kStatus_Success
*******************************************************************************/
status_t flash_write(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt)
{
uint32_t size;
status_t status;
while(byte_cnt > 0)
{
size = byte_cnt > FLASH_PAGE_SIZE ? FLASH_PAGE_SIZE : byte_cnt;
status = FLASH_WritePage(start_addr, (void *)buf, size);
if(status != kStatus_Success)
{
return status;
}
start_addr += size;
buf += size;
byte_cnt -= size;
}
return kStatus_Success;
}
/*******************************************************************************
* : flash_read
* : Flash内容
* : addr:
buf:
len:
* : kStatus_Success
*******************************************************************************/
status_t flash_read(uint32_t addr, uint8_t *buf, uint32_t len)
{
/* For FlexSPI Memory ReadBack, use IP Command instead of AXI command for security */
if((addr >= 0x60000000) && (addr < 0x61000000))
{
return FLASH_Read(addr, (void *)buf, len);
}
else
{
void* result = memcpy(buf, (void*)addr, len);
if(result == NULL)
{
return (status_t)kStatus_Fail;
}
else
{
return (status_t)kStatus_Success;
}
}
}
/*******************************************************************************
* : flash_copy
* : flash数据在分区之间的拷贝
* : srcAddr:flash的起始地址
dstAddr:flash的起始地址;
imageSize:flash空间大小,
* : kStatus_Success
*******************************************************************************/
status_t flash_copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize)
{
uint32_t PageNum, Remain, i;
status_t status;
if((srcAddr == dstAddr) || imageSize > APP_FLASH_SIZE)
{
return (status_t)kStatus_Fail;
}
status = flash_erase(dstAddr,imageSize);
if(status != kStatus_Success)
{
KPrintf("Erase flash 0x%08x failure !\r\n",dstAddr);
return status;
}
PageNum = imageSize/FLASH_PAGE_SIZE;
Remain = imageSize%FLASH_PAGE_SIZE;
for(i=0;i<PageNum;i++)
{
memset(buffer, 0, sizeof(buffer));
status = flash_read(srcAddr + i*FLASH_PAGE_SIZE, buffer, sizeof(buffer));
if(status != kStatus_Success)
{
KPrintf("Read flash 0x%08x failure !\r\n", srcAddr + i*FLASH_PAGE_SIZE);
return status;
}
status = flash_write(dstAddr+ i*FLASH_PAGE_SIZE, buffer, FLASH_PAGE_SIZE);
if(status != kStatus_Success)
{
KPrintf("Write flash 0x%08x failure !\r\n", dstAddr + i*FLASH_PAGE_SIZE);
return status;
}
}
if(Remain)
{
memset(buffer, 0, sizeof(buffer));
status = flash_read(srcAddr + i*FLASH_PAGE_SIZE, buffer, Remain);
if(status != kStatus_Success)
{
KPrintf("Read flash 0x%08x failure !\r\n", srcAddr + i*FLASH_PAGE_SIZE);
return status;
}
status = flash_write(dstAddr+ i*FLASH_PAGE_SIZE, buffer, Remain);
if(status != kStatus_Success)
{
KPrintf("Write flash 0x%08x failure !\r\n", dstAddr + i*FLASH_PAGE_SIZE);
return status;
}
}
return (status_t)kStatus_Success;
}
/*******************************************************************************
* : NOR_FLASH_Erase
* : Flash指定长度的空间,imageSize
* : addr:
imageSize:
* : None
*******************************************************************************/
status_t NOR_FLASH_Erase(uint32_t app_base_addr,uint32_t imageSize)
{
uint16_t i;
uint32_t sectorNum = (imageSize%SECTOR_SIZE != 0)? (imageSize/SECTOR_SIZE + 1):(imageSize/SECTOR_SIZE);
for(i=0;i<sectorNum;i++)
{
status_t status = FLASH_EraseSector(app_base_addr+i*SECTOR_SIZE);
if (status != kStatus_Success)
{
KPrintf("Erase_Sector 0x%x faild!\r\n",i*SECTOR_SIZE);
return status;
}
}
return kStatus_Success;
}
/******************************************************************************* /*******************************************************************************
* : NorFlash_Write_PageProgram * : NorFlash_Write_PageProgram
* : Flash指定长度的数据 * : Flash指定长度的数据
* : pBuffer: * : pBuffer:
WriteAddr: WriteAddr:
NumByteToWrite:(256) NumByteToWrite:(256)
* : kStatus_Success * : , kStatus_Success,
* : 256 * : 256
*******************************************************************************/ *******************************************************************************/
void NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) status_t NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{ {
uint8_t temp_data[256] = {0xff}; uint8_t temp_data[256] = {0xff};
memcpy(temp_data,pBuffer,NumByteToWrite); memcpy(temp_data,pBuffer,NumByteToWrite);
status_t status = FLASH_WritePage(WriteAddr,(void *)temp_data,FLASH_PAGE_SIZE); status_t status = FLASH_WritePage(WriteAddr,(void *)temp_data,FLASH_PAGE_SIZE);
if (status != kStatus_Success) if(status != kStatus_Success)
{ {
KPrintf("Write_PageProgram 0x%x faild!\r\n",WriteAddr); KPrintf("Write_PageProgram 0x%x faild!\r\n",WriteAddr);
} }
return (status_t)kStatus_Success;
} }
@ -887,13 +709,14 @@ void NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t Num
* : pBuffer: * : pBuffer:
WriteAddr:(24bit) WriteAddr:(24bit)
NumByteToWrite:(65535) NumByteToWrite:(65535)
* : * : , kStatus_Success,
* : 0XFF,0XFF处写入的数据将失败! * : 0XFF,0XFF处写入的数据将失败!
,,! ,,!
*******************************************************************************/ *******************************************************************************/
void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) status_t NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{ {
uint16_t pageRemain; uint16_t pageRemain;
status_t status;
pageRemain = 256 - WriteAddr%256;//单页剩余的字节数 pageRemain = 256 - WriteAddr%256;//单页剩余的字节数
@ -904,7 +727,12 @@ void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByte
while(1) while(1)
{ {
NorFlash_Write_PageProgram(pBuffer,WriteAddr,pageRemain); status = NorFlash_Write_PageProgram(pBuffer,WriteAddr,pageRemain);
if(status != kStatus_Success)
{
KPrintf("Write_PageProgram 0x%x faild!\r\n",WriteAddr);
return status;
}
if(NumByteToWrite == pageRemain) if(NumByteToWrite == pageRemain)
{ {
break;//写入结束了 break;//写入结束了
@ -925,25 +753,54 @@ void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByte
} }
} }
} }
return (status_t)kStatus_Success;
} }
/******************************************************************************* /*******************************************************************************
* : NorFlash_Write * : Flash_Erase
* : Flash指定长度的空间,imageSize
* : start_addr:
imageSize:
* : , kStatus_Success,
*******************************************************************************/
status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize)
{
uint16_t i;
status_t status;
uint32_t sectorNum = (imageSize%SECTOR_SIZE != 0)? (imageSize/SECTOR_SIZE + 1):(imageSize/SECTOR_SIZE);
for(i=0;i<sectorNum;i++)
{
status = FLASH_EraseSector(start_addr+i*SECTOR_SIZE);
if (status != kStatus_Success)
{
KPrintf("Erase_Sector 0x%x faild!\r\n",i*SECTOR_SIZE);
return status;
}
}
return (status_t)kStatus_Success;
}
/*******************************************************************************
* : Flash_Write
* : W25QXX在指定地址开始写入指定长度的数据 * : W25QXX在指定地址开始写入指定长度的数据
* : pBuffer: * : pBuffer:
WriteAddr:(24bit) WriteAddr:
NumByteToWrite:(65535) NumByteToWrite:(65535)
* : None * : , kStatus_Success,
* : * :
*******************************************************************************/ *******************************************************************************/
void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite) status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite)
{ {
uint32_t secPos; uint32_t secPos;
uint16_t secOff; uint16_t secOff;
uint16_t secRemain; uint16_t secRemain;
uint16_t i; uint16_t i;
uint8_t *NorFlash_BUF = 0; uint8_t *NorFlash_BUF = 0;
status_t status;
NorFlash_BUF = NorFlash_BUFFER;//RAM缓冲区4K NorFlash_BUF = NorFlash_BUFFER;//RAM缓冲区4K
@ -959,7 +816,11 @@ void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
} }
while(1) while(1)
{ {
FLASH_Read(CHIP_FLAH_BASE + secPos*SECTOR_SIZE, (void *)NorFlash_BUF, SECTOR_SIZE);//读出整个扇区的内容 status = FLASH_ReadBuf(CHIP_FLAH_BASE + secPos*SECTOR_SIZE, (void *)NorFlash_BUF, SECTOR_SIZE);//读出整个扇区的内容
if (status != kStatus_Success)
{
return status;
}
for(i=0;i<secRemain;i++)//校验数据 for(i=0;i<secRemain;i++)//校验数据
{ {
if(NorFlash_BUF[secOff+i] != 0xFF) if(NorFlash_BUF[secOff+i] != 0xFF)
@ -969,16 +830,28 @@ void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
} }
if(i < secRemain)//需要擦除 if(i < secRemain)//需要擦除
{ {
FLASH_EraseSector(CHIP_FLAH_BASE + secPos*SECTOR_SIZE); status = FLASH_EraseSector(CHIP_FLAH_BASE + secPos*SECTOR_SIZE);
if (status != kStatus_Success)
{
return status;
}
for(i=0;i<secRemain;i++)//复制 for(i=0;i<secRemain;i++)//复制
{ {
NorFlash_BUF[i+secOff] = pBuffer[i]; NorFlash_BUF[i+secOff] = pBuffer[i];
} }
NorFlash_Write_NoCheck(NorFlash_BUF,CHIP_FLAH_BASE + secPos*SECTOR_SIZE,SECTOR_SIZE);//写入整个扇区 status = NorFlash_Write_NoCheck(NorFlash_BUF,CHIP_FLAH_BASE + secPos*SECTOR_SIZE,SECTOR_SIZE);//写入整个扇区
if (status != kStatus_Success)
{
return status;
}
} }
else else
{ {
NorFlash_Write_NoCheck(pBuffer,CHIP_FLAH_BASE + WriteAddr,secRemain);//写已经擦除了的,直接写入扇区剩余区间. status = NorFlash_Write_NoCheck(pBuffer,CHIP_FLAH_BASE + WriteAddr,secRemain);//写已经擦除了的,直接写入扇区剩余区间.
if (status != kStatus_Success)
{
return status;
}
} }
if(NumByteToWrite == secRemain) if(NumByteToWrite == secRemain)
@ -1003,33 +876,138 @@ void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
} }
} }
} }
return (status_t)kStatus_Success;
} }
/*******************************************************************************
* : Flash_Read
* : Flash内容
* : addr:
buf:
len:
* : kStatus_Success
*******************************************************************************/
status_t Flash_Read(uint32_t addr, uint8_t *buf, uint32_t len)
{
/* For FlexSPI Memory ReadBack, use IP Command instead of AXI command for security */
if((addr >= 0x60000000) && (addr < 0x61000000))
{
return FLASH_ReadBuf(addr, (void *)buf, len);
}
else
{
void* result = memcpy(buf, (void*)addr, len);
if(result == NULL)
{
return (status_t)kStatus_Fail;
}
else
{
return (status_t)kStatus_Success;
}
}
}
/*******************************************************************************
* : Flash_Copy
* : flash数据在分区之间的拷贝
* : srcAddr:flash的起始地址
dstAddr:flash的起始地址;
imageSize:flash空间大小,
* : kStatus_Success
*******************************************************************************/
status_t Flash_Copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize)
{
uint32_t PageNum, Remain, i;
status_t status;
if((srcAddr == dstAddr) || imageSize > APP_FLASH_SIZE)
{
return (status_t)kStatus_Fail;
}
status = Flash_Erase(dstAddr,imageSize);
if(status != kStatus_Success)
{
KPrintf("Erase flash 0x%08x failure !\r\n",dstAddr);
return status;
}
PageNum = imageSize/FLASH_PAGE_SIZE;
Remain = imageSize%FLASH_PAGE_SIZE;
for(i=0;i<PageNum;i++)
{
memset(buffer, 0, sizeof(buffer));
status = Flash_Read(srcAddr + i*FLASH_PAGE_SIZE, buffer, sizeof(buffer));
if(status != kStatus_Success)
{
KPrintf("Read flash 0x%08x failure !\r\n", srcAddr + i*FLASH_PAGE_SIZE);
return status;
}
status = Flash_Write(dstAddr+ i*FLASH_PAGE_SIZE, buffer, FLASH_PAGE_SIZE);
if(status != kStatus_Success)
{
KPrintf("Write flash 0x%08x failure !\r\n", dstAddr + i*FLASH_PAGE_SIZE);
return status;
}
}
if(Remain)
{
memset(buffer, 0, sizeof(buffer));
status = Flash_Read(srcAddr + i*FLASH_PAGE_SIZE, buffer, Remain);
if(status != kStatus_Success)
{
KPrintf("Read flash 0x%08x failure !\r\n", srcAddr + i*FLASH_PAGE_SIZE);
return status;
}
status = Flash_Write(dstAddr+ i*FLASH_PAGE_SIZE, buffer, Remain);
if(status != kStatus_Success)
{
KPrintf("Write flash 0x%08x failure !\r\n", dstAddr + i*FLASH_PAGE_SIZE);
return status;
}
}
return (status_t)kStatus_Success;
}
/******************************************************************************* /*******************************************************************************
* : NOR_FLASH_Write * : NOR_FLASH_Write
* : W25QXX在指定地址开始写入指定长度的数据 * : W25QXX在指定地址开始写入指定长度的数据
* : FlashAddress:Flash地址的指针 * : FlashAddress:Flash地址的指针
Data: Data:
DataLength: DataLength:
* : 0 * : , kStatus_Success,
*******************************************************************************/ *******************************************************************************/
#ifndef USE_HIGHT_SPEED_TRANS #ifndef USE_HIGHT_SPEED_TRANS
uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength) status_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength)
{ {
status_t status;
uint32_t WriteAddr; uint32_t WriteAddr;
WriteAddr = *FlashAddress; WriteAddr = *FlashAddress;
NorFlash_Write(Data,WriteAddr,DataLength); status = Flash_Write(WriteAddr,Data,DataLength);
if (status != kStatus_Success)
{
return status;
}
*FlashAddress += DataLength; *FlashAddress += DataLength;
return 0; return (status_t)kStatus_Success;
} }
#else #else
uint8_t packetNum = 0; uint8_t packetNum = 0;
uint32_t dataLen = 0; uint32_t dataLen = 0;
uint32_t WriteAddr; uint32_t WriteAddr;
uint8_t dataBuff[5*1024]; uint8_t dataBuff[5*1024];
uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength,uint8_t doneFlag) status_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength,uint8_t doneFlag)
{ {
status_t status;
if(!doneFlag) if(!doneFlag)
{ {
memcpy(&dataBuff[dataLen],Data,DataLength); memcpy(&dataBuff[dataLen],Data,DataLength);
@ -1042,7 +1020,11 @@ uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLen
if(dataLen>=SECTOR_SIZE) if(dataLen>=SECTOR_SIZE)
{ {
NorFlash_Write(dataBuff,WriteAddr,dataLen); status = Flash_Write(WriteAddr,dataBuff,dataLen);
if (status != kStatus_Success)
{
return status;
}
packetNum = 0; packetNum = 0;
dataLen = 0; dataLen = 0;
} }
@ -1050,10 +1032,14 @@ uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLen
} }
else else
{ {
NorFlash_Write(dataBuff,WriteAddr,dataLen); status = Flash_Write(WriteAddr,dataBuff,dataLen);
if (status != kStatus_Success)
{
return status;
}
packetNum = 0; packetNum = 0;
dataLen = 0; dataLen = 0;
} }
return (0); return (status_t)kStatus_Success;;
} }
#endif #endif

View File

@ -280,7 +280,7 @@ int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr)
} }
/* erase user application area */ /* erase user application area */
NOR_FLASH_Erase(addr,size); Flash_Erase(addr,size);
Send_Byte(ACK); Send_Byte(ACK);
Send_Byte(CRC16); Send_Byte(CRC16);
} }
@ -300,9 +300,9 @@ int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr)
/* Write received data in Flash */ /* Write received data in Flash */
#ifndef USE_HIGHT_SPEED_TRANS #ifndef USE_HIGHT_SPEED_TRANS
if(NOR_FLASH_Write(&flashdestination, buf, (uint16_t)packet_length) == 0) if(NOR_FLASH_Write(&flashdestination, buf, (uint16_t)packet_length) == kStatus_Success)
#else #else
if(NOR_FLASH_Write(&flashdestination, buf, (uint16_t)packet_length, 0) == 0) if(NOR_FLASH_Write(&flashdestination, buf, (uint16_t)packet_length, 0) == kStatus_Success)
#endif #endif
{ {
Send_Byte(ACK); Send_Byte(ACK);
@ -349,7 +349,10 @@ int32_t Ymodem_Receive(uint8_t *buf, const uint32_t addr)
} }
} }
#ifdef USE_HIGHT_SPEED_TRANS #ifdef USE_HIGHT_SPEED_TRANS
NOR_FLASH_Write(&flashdestination, buf, (uint16_t) packet_length,1); if(NOR_FLASH_Write(&flashdestination, buf, (uint16_t) packet_length,1) != kStatus_Success)
{
return -4;
}
#endif #endif
return (int32_t)size; return (int32_t)size;
} }
@ -370,13 +373,12 @@ int32_t SerialDownload(const uint32_t addr)
Size = Ymodem_Receive(&tab_1024[0], addr); Size = Ymodem_Receive(&tab_1024[0], addr);
if(Size > 0) if(Size > 0)
{ {
Serial_PutString("\n\n\r Programming Completed Successfully!\n\r--------------------------------\r\n Name: "); Serial_PutString("\n\n\rProgramming Completed Successfully!\n\r\r\nName: ");
Serial_PutString(FileName); Serial_PutString(FileName);
Int2Str(Number, Size); Int2Str(Number, Size);
Serial_PutString("\n\r Size: "); Serial_PutString("\n\rSize: ");
Serial_PutString(Number); Serial_PutString(Number);
Serial_PutString(" Bytes\r\n"); Serial_PutString(" Bytes\r\n");
Serial_PutString("-------------------\n");
} }
else if(Size == -1) else if(Size == -1)
{ {

View File

@ -63,21 +63,19 @@ void FLASH_Init(void);
void FLASH_DeInit(void); void FLASH_DeInit(void);
uint8_t FLASH_EraseSector(uint32_t addr); uint8_t FLASH_EraseSector(uint32_t addr);
uint8_t FLASH_WritePage(uint32_t addr, const uint32_t *buf, uint32_t len); uint8_t FLASH_WritePage(uint32_t addr, const uint32_t *buf, uint32_t len);
status_t FLASH_Read(uint32_t addr, uint32_t *buf, uint32_t len); status_t FLASH_ReadBuf(uint32_t addr, uint32_t *buf, uint32_t len);
status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt); status_t NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
status_t flash_write(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt); status_t NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
status_t flash_read(uint32_t addr, uint8_t *buf, uint32_t len);
status_t flash_copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize);
status_t NOR_FLASH_Erase(uint32_t app_base_addr,uint32_t imageSize); status_t Flash_Erase(uint32_t start_addr, uint32_t imageSize);
void NorFlash_Write_PageProgram(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite); status_t Flash_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite);
void NorFlash_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite); status_t Flash_Read(uint32_t addr, uint8_t *buf, uint32_t len);
void NorFlash_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite); status_t Flash_Copy(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize);
#ifndef USE_HIGHT_SPEED_TRANS #ifndef USE_HIGHT_SPEED_TRANS
uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength); status_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength);
#else #else
uint32_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength,uint8_t doneFlag); status_t NOR_FLASH_Write(uint32_t* FlashAddress, uint8_t* Data ,uint16_t DataLength,uint8_t doneFlag);
#endif #endif
#endif #endif

View File

@ -596,6 +596,10 @@ KERNELPATHS +=-I$(KERNEL_ROOT)/tool/bootloader/flash \
-I$(KERNEL_ROOT)/tool/bootloader/ota # -I$(KERNEL_ROOT)/tool/bootloader/ota #
endif endif
ifeq ($(CONFIG_TOOL_USING_MQTT), y)
KERNELPATHS +=-I$(KERNEL_ROOT)/../../APP_Framework/lib/mqtt
endif
ifeq ($(CONFIG_FS_LWEXT4),y) ifeq ($(CONFIG_FS_LWEXT4),y)
KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/blockdev/xiuos # KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/blockdev/xiuos #
KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/include # KERNELPATHS += -I$(KERNEL_ROOT)/fs/lwext4/lwext4_submodule/include #

View File

@ -16,6 +16,22 @@ menu "OTA function"
bool "Config as application." bool "Config as application."
endchoice endchoice
if MCUBOOT_APPLICATION
choice
prompt "The way of OTA firmware upgrade."
default OTA_BY_PLATFORM
config OTA_BY_PLATFORM
bool "Through IoT management platform."
select TOOL_USING_MQTT
config OTA_BY_TCPSERVER
bool "Through the public network TCP server."
select SUPPORT_CONNECTION_FRAMEWORK
select CONNECTION_ADAPTER_4G
endchoice
endif
menu "Flash area address and size configuration." menu "Flash area address and size configuration."
config CHIP_FLAH_BASE config CHIP_FLAH_BASE
@ -42,7 +58,18 @@ menu "OTA function"
hex "Application package size,the default size is limited to 1M." hex "Application package size,the default size is limited to 1M."
default 0x00100000 default 0x00100000
endmenu 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 endif
endmenu endmenu

View File

@ -30,8 +30,8 @@ typedef struct
void (*flash_deinit)(void); void (*flash_deinit)(void);
/* flash operation */ /* flash operation */
status_t (*op_flash_erase)(uint32_t start_addr, uint32_t byte_cnt); status_t (*op_flash_erase)(uint32_t start_addr, uint32_t imageSize);
status_t (*op_flash_write)(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt); status_t (*op_flash_write)(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumByteToWrite);
status_t (*op_flash_read)(uint32_t addr, uint8_t *buf, uint32_t len); status_t (*op_flash_read)(uint32_t addr, uint8_t *buf, uint32_t len);
status_t (*op_flash_copy)(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize); status_t (*op_flash_copy)(uint32_t srcAddr,uint32_t dstAddr, uint32_t imageSize);

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,22 @@
/* /*
* Copyright 2018-2020 NXP * Copyright (c) 2020 AIIT XUOS Lab
* All rights reserved. * XiUOS is licensed under Mulan PSL v2.
* * You can use this software according to the terms and conditions of the Mulan PSL v2.
* SPDX-License-Identifier: BSD-3-Clause * 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 ota.h * @file: ota.h
* @brief file ota.h * @brief: file ota.h
* @version 2.0 * @version: 1.0
* @author AIIT XUOS Lab * @author: AIIT XUOS Lab
* @date 2023-04-03 * @date: 2023/4/23
*
*/ */
#ifndef __OTA_DEF_H__ #ifndef __OTA_DEF_H__
#define __OTA_DEF_H__ #define __OTA_DEF_H__
@ -19,6 +25,10 @@
#define JUMP_FAILED_FLAG 0XABABABAB #define JUMP_FAILED_FLAG 0XABABABAB
#define JUMP_SUCCESS_FLAG 0XCDCDCDCD #define JUMP_SUCCESS_FLAG 0XCDCDCDCD
#define STARTFLAG 0x1A2B //数据帧开始信号标记
#define DATAFLAG 0x3C4D //数据帧数据信号标记
#define ENDTFLAG 0x5E6F //数据帧结束信号标记
#define LENGTH 1024 //每帧数据的数据包长度
typedef enum { typedef enum {
OTA_STATUS_IDLE = 0, // 空闲状态,没有进行OTA升级 OTA_STATUS_IDLE = 0, // 空闲状态,没有进行OTA升级
@ -35,9 +45,8 @@ typedef enum {
typedef struct { typedef struct {
uint32_t size; // 应用程序大小,记录分区固件的大小 uint32_t size; // 应用程序大小,记录分区固件的大小
uint32_t crc32; // 应用程序CRC32校验值,记录分区固件的crc32值 uint32_t crc32; // 应用程序CRC32校验值,记录分区固件的crc32值
uint32_t version; // 应用程序版本号,记录分区固件的版本号 uint8_t version[32]; // 应用程序版本号,记录分区固件的版本
uint32_t reserve; // 保留字段 uint8_t description[32]; // 固件的描述信息,最多32个字符
uint8_t description[128]; // 固件的描述信息,最多128个字符
} firmware_t; } firmware_t;
@ -48,10 +57,45 @@ typedef struct {
firmware_t down; // Download分区属性信息 firmware_t down; // Download分区属性信息
uint32_t status; // 升级状态,取值来自于ota_status_t类型 uint32_t status; // 升级状态,取值来自于ota_status_t类型
uint32_t lastjumpflag; // bootloaer跳转失败的标志,bootloader里置0xABABABAB,跳转成功后在应用里置0xCDCDCDCD uint32_t lastjumpflag; // bootloaer跳转失败的标志,bootloader里置0xABABABAB,跳转成功后在应用里置0xCDCDCDCD
uint32_t reserve[2]; // 保留字段 uint8_t error_message[64]; // 错误信息,最多64个字符
uint8_t error_message[128]; // 错误信息,最多128个字符
} ota_info_t; } ota_info_t;
#ifdef OTA_BY_TCPSERVER
/*bin包传输过程中的数据帧相关的结构体*/
typedef struct
{
uint16_t frame_flag; // frame start flag 2 Bytes
uint16_t dev_sid; // device software version
uint32_t total_len; // send data total length caculated from each frame_len
} ota_header_t;
typedef struct
{
uint32_t frame_id; // Current frame id
uint8_t frame_data[LENGTH]; // Current frame data
uint16_t frame_len; // Current frame data length
uint16_t crc; // Current frame data crc
} ota_frame_t;
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 app_clear_jumpflag(void);
void ota_entry(void); void ota_entry(void);
#endif #endif

View File

@ -0,0 +1,508 @@
/*
* 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: ota_server.c
* @brief: a application ota task of system running in Linux
* @version: 1.0
* @author: AIIT XUOS Lab
* @date: 2023/5/26
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include <time.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/time.h>
#include <assert.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ifaddrs.h>
#define STARTFLAG 0x1A2B //数据帧开始信号标记
#define DATAFLAG 0x3C4D //数据帧数据信号标记
#define ENDTFLAG 0x5E6F //数据帧结束信号标记
#define PORT 7777 //socket端口号
#define SIZE 100 //socket链接限制为100
#define LENGTH 1024 //每帧数据的数据包长度
#define BIN_PATH "/home/aep05/wgz/XiZi-xidatong-arm32-app.bin" //bin包的路径
typedef struct
{
uint16_t frame_flag; // frame start flag 2 Bytes
uint16_t dev_sid; // device software version
uint32_t total_len; // send data total length caculated from each frame_len
} ota_header_t;
typedef struct
{
uint32_t frame_id; // Current frame id
uint8_t frame_data[LENGTH]; // Current frame data
uint16_t frame_len; // Current frame data length
uint16_t crc; // Current frame data crc
} ota_frame_t;
typedef struct
{
ota_header_t header;
ota_frame_t frame;
} ota_data;
static int serverfd; // 服务器socket
static int clientfd[SIZE] = {0}; // 客户端的socketfd,100个元素clientfd[0]~clientfd[99]
/*******************************************************************************
* : calculate_crc16
* : crc16的值,OTA传输过程中数据帧的校验
* : data:buffer
len:CRC16的数据长度
* : CRC16值
*******************************************************************************/
static uint16_t calculate_crc16(uint8_t * data, uint32_t len)
{
uint16_t reg_crc=0xFFFF;
while(len--)
{
reg_crc ^= *data++;
for(int j=0;j<8;j++)
{
if(reg_crc & 0x01)
reg_crc=reg_crc >>1 ^ 0xA001;
else
reg_crc=reg_crc >>1;
}
}
printf("crc = [0x%x]\n",reg_crc);
return reg_crc;
}
/*******************************************************************************
* : sockt_init
* : TCP Server上创建socet监听
* : data:buffer
len:CRC16的数据长度
* : CRC16值
*******************************************************************************/
void sockt_init(void)
{
struct sockaddr_in addr, *sa;//存储套接字的信息
struct ifaddrs *ifap, *ifa;
char *ipaddr;
serverfd = socket(AF_INET,SOCK_STREAM,0);
if(serverfd == -1)
{
perror("Failed to create socket");
exit(-1);
}
//为套接字设置ip协议 设置端口号并自动获取本机ip转化为网络ip
addr.sin_family = AF_INET;//地址族
addr.sin_port = htons(PORT);//设置server端端口号,随便设置,当sin_port = 0时系统随机选择一个未被使用的端口号
addr.sin_addr.s_addr = htons(INADDR_ANY);//当sin_addr=INADDR_ANY时表示从本机的任一网卡接收数据
/*显示当前TCP server的*/
getifaddrs(&ifap);
for(ifa = ifap; ifa != NULL; ifa = ifa->ifa_next)
{
if(ifa->ifa_addr->sa_family == AF_INET)
{
sa = (struct sockaddr_in *) ifa->ifa_addr;
ipaddr = inet_ntoa(sa->sin_addr);
printf("Interface:%-16s Address:%-16s\n", ifa->ifa_name, ipaddr);
}
}
freeifaddrs(ifap);
//绑定套接字
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if(setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &timeout, sizeof(struct timeval)) < 0)
{
perror("Failed to set setsock option");
exit(-1);
}
if(bind(serverfd,(struct sockaddr*)&addr,sizeof(addr)) == -1)
{
perror("Failed to bind socket port");
exit(-1);
}
//监听最大连接数
if(listen(serverfd,SIZE) == -1)
{
perror("Failed to set socket listening");
exit(-1);
}
}
/*******************************************************************************
* : ota_start_signal
* : ,ready
* : fd:fd
* : 0:,-1:
*******************************************************************************/
void ota_start_signal(int fd)
{
ota_data data;
struct stat st;
uint8_t buf[32];
int file_size = 0, file_frame_cnt = 0, length = 0;
if (access(BIN_PATH, F_OK) == 0)
{
printf("%s exists.\n", basename(BIN_PATH));
}
else
{
printf("%s does not exist,please cheack!\n", BIN_PATH);
exit(-1);
}
//获取文件大小(以字节为单位)
if(stat(BIN_PATH, &st) == 0)
{
file_size = st.st_size;
file_frame_cnt = ((file_size%LENGTH) != 0)? (file_size/LENGTH + 1):(file_size/LENGTH);
printf("%s size is %d bytes,frame count is %d!\n",basename(BIN_PATH), file_size, file_frame_cnt);
}
else
{
printf("Failed to get file size\n");
exit(-1);
}
while(1)
{
memset(&data, 0x0, sizeof(ota_data));
data.header.frame_flag = STARTFLAG;
//发送起始帧时把bin文件的大小一并发送出去
data.header.total_len = file_size;
while(send(fd, &data, sizeof(data), MSG_NOSIGNAL) <= 0);
printf("send start signal to client %d.\n", fd);
memset(buf, 0, sizeof(buf));
length = recv(fd, buf, sizeof(buf), 0);
if(length == 0)
{
printf("The current socket %d is disconnected,please check it!\n",fd);
close(fd);
pthread_exit(0);
}
else if(length > 0 && (0 == strncmp(buf, "ready", length)))
{
printf("recv buf %s length %d from client %d.\n", buf, length, fd);
break;
}
else
{
continue;
}
}
}
/*******************************************************************************
* : ota_file_send
* : TCP Server发送bin文件
* : fd:fd
* : 0-1
*******************************************************************************/
int ota_file_send(int fd)
{
unsigned char buf[32] = { 0 };
ota_data data;
FILE *file_fd;
int length = 0;
int try_times;
int recv_end_times = 3;
int ret = 0;
int frame_cnt = 0;
int file_length = 0;
char * file_buf = NULL;
file_fd = fopen(BIN_PATH, "r");
if(NULL == file_fd)
{
printf("open file failed.\n");
fclose(file_fd);
return -1;
}
fseek(file_fd, 0, SEEK_SET);
printf("start send bin file to client %d.\n", fd);
while(!feof(file_fd))
{
memset(&data, 0, sizeof(data));
data.header.frame_flag = DATAFLAG;
length = fread(data.frame.frame_data, 1, LENGTH, file_fd);
if(length == LENGTH)
{
printf("read %d bytes\n",length);
data.frame.frame_id = frame_cnt;
data.frame.frame_len = length;
data.frame.crc = calculate_crc16(data.frame.frame_data, length);
file_length += length;
}
else if(length > 0 && length < LENGTH)
{
if(ferror(file_fd))
{
printf("read %s file error!\n", basename(BIN_PATH));
ret = -1;
break;
}
else
{
printf("read %d bytes\n",length);
data.frame.frame_id = frame_cnt;
data.frame.frame_len = length;
data.frame.crc = calculate_crc16(data.frame.frame_data, length);
file_length += length;
}
}
//fread返回值为0,此时是个空包,不需要再发送了否则是冗余数据
else
{
printf("read %s file done!\n", basename(BIN_PATH));
break;
}
send_again:
printf("send frame[%d] to client %d.\n", frame_cnt, fd);
length = send(fd, &data, sizeof(data), MSG_NOSIGNAL);
if(length < 0)
{
printf("send frame[%d] to client %d failed,send again\n", frame_cnt, fd);
goto send_again;
}
recv_again:
memset(buf, 0, sizeof(buf));
length = recv(fd, buf, sizeof(buf), 0);
if(length == 0)
{
printf("current socket %d is disconnected,please check it!\n", fd);
ret = -1;
close(fd);
pthread_exit(0);
break;
}
else if(length < 0 )
{
printf("send frame[%d] to client %d waiting for ok timeout,receive again.\n", frame_cnt, fd);
goto recv_again;
}
else if(0 == strncmp(buf, "ok", length))
{
printf("receive buf[%s] length %d from client %d.\n", buf, length, fd);
try_times = 5;
printf("send to client %d frame[%d] data send done.\n",fd, frame_cnt);
frame_cnt++;
continue;
}
//接收到的回复不是ok,说明刚发的包有问题,需要再发一次
else
{
if(try_times > 0)
{
try_times--;
goto send_again;
}
else
{
printf("send to client %d frame[%d] 5 times failed.\n",fd, frame_cnt);
ret = -1;
break;
}
}
}
/* finally,crc check total bin file.*/
if(ret == 0)
{
printf("total send file length %d bytes, %d frames to client %d.\n", file_length, frame_cnt, fd);
printf("now crc check total bin file.\n");
file_buf = malloc(file_length);
memset(file_buf, 0, file_length);
memset(&data, 0, sizeof(data));
data.header.frame_flag = ENDTFLAG;
file_fd = fopen(BIN_PATH, "r");
if(NULL == file_fd)
{
printf("open file failed.\n");
return -1;
}
fseek(file_fd, 0, SEEK_SET);
length = fread(file_buf,1, file_length, file_fd);
printf("read file length = %d\n",length);
if(length > 0)
{
data.frame.frame_id = frame_cnt;
data.header.total_len = file_length;
data.frame.crc = calculate_crc16(file_buf, length);
}
send_end_signal:
printf("send ota end signal to client %d.\n", fd);
length = send(fd, &data, sizeof(data), MSG_NOSIGNAL);
if(length < 0)
{
printf("send to client %d ota end signal faile,send again\n",fd);
goto send_end_signal;
}
recv_end_signal:
memset(buf, 0, sizeof(buf));
length = recv(fd, buf, sizeof(buf), 0);
if(length == 0)
{
printf("current socket %d is disconnected,please check it!\n",fd);
ret = -1;
free(file_buf);
fclose(file_fd);
close(fd);
pthread_exit(0);
}
if(length < 0 || (0 != strncmp(buf, "ok", length)))
{
recv_end_times--;
printf("from client %d end signal waiting for ok timeout,receive again.\n", fd);
if(recv_end_times > 0)
{
goto recv_end_signal;
}
else
{
printf("client %d error end !!!\n", fd);
ret = -1;
}
}
free(file_buf);
}
fclose(file_fd);
return ret;
}
/*******************************************************************************
* : server_thread
* : TCP Server的服务线程入口函数
* : p:
* :
*******************************************************************************/
void* server_thread(void* p)
{
int fd = *(int*)p;
unsigned char buf[32] = { 0 };
ota_data data;
printf("pthread = %d\n",fd);
sleep(3);
while(1)
{
/* if ota failed then restart the ota process */
ota_start_signal(fd);
sleep(5);
if(0 == ota_file_send(fd))
{
printf("ota file send to client %d successful.\n", fd);
break;
}
}
printf("exit fd = %d\n",fd);
close(fd);
pthread_exit(0);
}
/*******************************************************************************
* : server
* : TCP Server的服务函数
* :
* :
*******************************************************************************/
void server(void)
{
int i = 0;
printf("ota Server startup\n");
while(1)
{
struct sockaddr_in fromaddr;
socklen_t len = sizeof(fromaddr);
int fd = accept(serverfd,(struct sockaddr*)&fromaddr,&len);//调用accept进入堵塞状态等待客户端的连接
if(fd == -1)
{
printf("The client connection is wrong...\n");
continue;
}
for(i = 0;i < SIZE;i++)
{
if(clientfd[i] == 0)
{
//记录客户端的socket
clientfd[i] = fd;
//有客户端连接之后,启动线程给此客户服务
pthread_t tid;
pthread_create(&tid,0,server_thread,&fd);
break;
}
if(SIZE == i)
{
//发送给客户端聊天室满了
char* str = "Devices full";
printf("%s", str);
send(fd,str,strlen(str),0);
close(fd);
}
}
}
}
int main(void)
{
sockt_init();
server();
}