diff --git a/APP_Framework/Applications/Kconfig b/APP_Framework/Applications/Kconfig index 7c5592045..7639f0449 100644 --- a/APP_Framework/Applications/Kconfig +++ b/APP_Framework/Applications/Kconfig @@ -11,6 +11,8 @@ menu "Applications" default 85 if KTASK_PRIORITY_256 endmenu + source "$APP_DIR/Applications/ota/Kconfig" + source "$APP_DIR/Applications/app_test/Kconfig" source "$APP_DIR/Applications/connection_app/Kconfig" source "$APP_DIR/Applications/control_app/Kconfig" diff --git a/APP_Framework/Applications/Makefile b/APP_Framework/Applications/Makefile index 7451edb74..af2f86d2c 100644 --- a/APP_Framework/Applications/Makefile +++ b/APP_Framework/Applications/Makefile @@ -1,6 +1,10 @@ -SRC_DIR := general_functions +SRC_DIR := general_functions app_test -SRC_FILES := main.c framework_init.c +SRC_FILES := main.c framework_init.c + +ifeq ($(CONFIG_APPLICATION_OTA),y) + SRC_DIR += ota +endif ifeq ($(CONFIG_APPLICATION_SENSOR),y) SRC_DIR += sensor_app diff --git a/APP_Framework/Applications/main.c b/APP_Framework/Applications/main.c index 5a7524f5b..3cb6142b5 100644 --- a/APP_Framework/Applications/main.c +++ b/APP_Framework/Applications/main.c @@ -15,11 +15,12 @@ #include extern int FrameworkInit(); - +extern void ApplicationOtaTaskInit(void); int main(void) { printf("Hello, world!\n"); FrameworkInit(); + ApplicationOtaTaskInit(); return 0; } // int cppmain(void); diff --git a/APP_Framework/Applications/ota/Kconfig b/APP_Framework/Applications/ota/Kconfig new file mode 100755 index 000000000..2943bdb32 --- /dev/null +++ b/APP_Framework/Applications/ota/Kconfig @@ -0,0 +1,7 @@ +menu "config application bin ota " + menuconfig APPLICATION_OTA + bool "Using app bin ota" + default n + + +endmenu diff --git a/APP_Framework/Applications/ota/Makefile b/APP_Framework/Applications/ota/Makefile new file mode 100644 index 000000000..2f5316c0d --- /dev/null +++ b/APP_Framework/Applications/ota/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := ota.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/APP_Framework/Applications/ota/README.md b/APP_Framework/Applications/ota/README.md new file mode 100644 index 000000000..052b383ab --- /dev/null +++ b/APP_Framework/Applications/ota/README.md @@ -0,0 +1,19 @@ +# OTA README + +xiuos当前的ota功能允许应用bin文件可以通过4G实现远程的bin文件更新(限制:1、bin文件存放在设备SD卡并且应用从SD卡启动;2、暂且支持4G实现;3、暂时只支持aiit终端)。 + +## 文件说明 + +| 名称 | 说明 | +| -- | -- | +| ota.c| 设备OTA代码 | +| ota_server.c | pc服务端的实例代码供参考 | + + +## 使用说明 +xiuos的应用bin文件更新依赖上层的adapter框架,因此需要在menuconfig同时配置以下选项: +1、ota开关APPLICATION_OTA打开; +2、adapter的4G功能开关; +3、拆分的应用启动SEPARATE_COMPILE开关从SD卡启动的配置开关APP_STARTUP_FROM_SDCARD。 + + diff --git a/APP_Framework/Applications/ota/ota.c b/APP_Framework/Applications/ota/ota.c new file mode 100644 index 000000000..7f6200f58 --- /dev/null +++ b/APP_Framework/Applications/ota/ota.c @@ -0,0 +1,231 @@ + +/* +* 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.c +* @brief: a application ota task of system +* @version: 1.0 +* @author: AIIT XUOS Lab +* @date: 2021/11/3 +* +*/ +#include +#include + +struct ota_header_t +{ + int16 frame_flag; ///< frame start flag 2 Bytes + uint8 dev_type; ///< device type + uint8 burn_mode; ///< data burn way + unsigned long total_len; ///< send data total length caculated from each frame_len + unsigned long dev_hid; ///< device hardware version + unsigned long dev_sid; ///< device software version + char resv[32]; ///< reserve +}; + +struct ota_frame_t +{ + uint32 frame_id; ///< Current frame id + uint32 frame_len; ///< Current frame data length + char frame_data[224]; ///< Current frame data,max length 224 + uint32 crc; ///< Current frame data crc +}; + +struct ota_data +{ + struct ota_header_t header; + struct ota_frame_t frame; +}; + +pthread_t ota_ktask; + +/** + * @description: CRC16 check + * @param data data buffer + * @param length data length + * @return check code + */ +uint32_t OtaCrc16(uint8_t * data, uint8_t length) +{ + int j; + unsigned int reg_crc=0xFFFF; + + while (length--) { + reg_crc ^= *data++; + for (j=0;j<8;j++) { + if(reg_crc & 0x01) + reg_crc=reg_crc >>1 ^ 0xA001; + else + reg_crc=reg_crc >>1; + } + } + + return reg_crc; +} + +static int SaveAppBin(char* buf, int len) +{ + int fd = 0; + fd = open( BOARD_APP_NAME, O_RDWR | O_CREAT ); + lseek(fd, 0, SEEK_END); + write(fd, buf, len); + close(fd); +} +static int CrcFileCheck(uint32 crc_check, unsigned long total_len) +{ + int ret = 0; + int fd = 0; + int len = 0; + char *buf = NULL; + + fd = open( BOARD_APP_NAME, O_RDONLY ); + if(fd < 0){ + printf("open %s bin failed.\n",BOARD_APP_NAME); + return -1; + } + + buf = PrivMalloc(total_len); + if(NULL == buf) + { + printf("malloc failed.\n"); + close(fd); + return -1; + } + + len = read(fd, buf, total_len); + + if (crc_check != OtaCrc16(buf, len)) + { + ret =-1; + } + + PrivFree(buf); + close(fd); + + return ret; +} + +static int OtaDataRecv(struct Adapter* adapter) +{ + struct ota_data recv_msg; + char reply[16] = {0}; + int ret = 0; + int try_times = 5; + + while(1) { + memset(&recv_msg, 0, sizeof(struct ota_data)); + ret = AdapterDeviceRecv(adapter, &recv_msg, 256); + if(ret > 0 && recv_msg.header.frame_flag == 0x5A5A) + { + if(0 == strncmp("aiit_ota_end",recv_msg.frame.frame_data, strlen("aiit_ota_end"))) + { + printf("total [%d]frames [%d]Bytes,receive successful,\n",recv_msg.frame.frame_id,recv_msg.header.total_len); + if(0 != CrcFileCheck(recv_msg.frame.crc, recv_msg.header.total_len)) + { + printf("crc check %s bin failed.please try again.\n", BOARD_APP_NAME); + ret = -1; + } + break; + } + + if (recv_msg.frame.crc == OtaCrc16(recv_msg.frame.frame_data,recv_msg.frame.frame_len)) + { + SaveAppBin(recv_msg.frame.frame_data, recv_msg.frame.frame_len); + } + else + { + printf("current [%d] frame crc check failed,try again\n",recv_msg.frame.frame_id); + goto try_again; + } + memset(reply, 0, 16); + memcpy(reply, "ok", strlen("ok")); + } + else + { +try_again: + if(try_times == 0) + { + printf("oops!!! current [%d] frame try 5 times failed,break out\n",recv_msg.frame.frame_id); + ret = -1; + break; + } + memset(reply, 0, 16); + memcpy(reply, "try_again", strlen("try_again")); + AdapterDeviceSend(adapter, reply, strlen(reply)); + try_times--; + continue; + } + } + return ret; +} + +static void *OtaKTaskEntry(void *parameter) +{ + struct ota_data recv_msg; + char reply[4] = {0}; + int baud_rate = BAUD_RATE_115200; + int len = 0; + int ret = 0; + + struct Adapter* adapter = AdapterDeviceFindByName("4G"); + uint8 server_addr[64] = "101.68.82.219"; + uint8 server_port[64] = "9898"; + + adapter->socket.socket_id = 0; + + AdapterDeviceOpen(adapter); + AdapterDeviceControl(adapter, OPE_INT, &baud_rate); + AdapterDeviceConnect(adapter, CLIENT, server_addr, server_port, IPV4); + + while(1) + { + memset(&recv_msg, 0, sizeof(struct ota_data)); + /* step1: Confirm the start signal of transmission*/ + ret = AdapterDeviceRecv(adapter, &recv_msg, 256); + if(ret > 0 && recv_msg.header.frame_flag == 0x5A5A) + { + if (0 == strncmp("aiit_ota_start",recv_msg.frame.frame_data, strlen("aiit_ota_start"))) + { + memset(reply, 0, 4); + memcpy(reply, "ok", strlen("ok")); + AdapterDeviceSend(adapter, reply, strlen(reply)); + + /* step2: start receive source bin file of application*/ + ret = OtaDataRecv(adapter); + if (0 != ret) + { + memset(reply, 0, 4); + memcpy(reply, "send_restart", strlen("send_restart")); + AdapterDeviceSend(adapter, reply, strlen(reply)); + continue; + } + else + { + break; + } + } + } + PrivTaskDelay(3000); /* check ota signal every 3s */ + } + AdapterDeviceClose(adapter); +} + +void ApplicationOtaTaskInit(void) +{ + pthread_attr_t attr; + attr.schedparam.sched_priority = 10; + attr.stacksize = 2048; + + PrivTaskCreate(&ota_ktask, &attr, OtaKTaskEntry, NULL); + +} \ No newline at end of file diff --git a/APP_Framework/Applications/ota/ota_server.c b/APP_Framework/Applications/ota/ota_server.c new file mode 100644 index 000000000..eb71b1202 --- /dev/null +++ b/APP_Framework/Applications/ota/ota_server.c @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +/*******************************mail*****************************/ + +#define MAX_BUFF_SIZE (2048) +#define IP_ADDR ("smtp.163.com") +#define IP_ADDR_PORT (25) +#define USERNAME ("18535861947@163.com") +#define TO_ADDRESS ("522736215@qq.com") +#define ACCESS_PORT ("有链接已接入服务器端口") +#define USING_DEVICE_AUTH 1 + + +#define BUFLEN 1024 +#define LISTNUM 20 +#define IP_ADDRESS "0.0.0.0" + +/*宏定义*/ +#define SID_MAX_LENGHT 16 +#define NAME_MAX_LENGHT 16 +#define MAJOR_MAX_LENGHT 64 +#define CMD_MAX_LENGHT 1024 +#define REDIS_SERVER_IP "127.0.0.1" +#define REDIS_SERVER_PORT 6379 + +typedef int BOOL; +#define true 1 +#define false 0 + +int serverfd;//服务器socket +int clientfd[100000];//客户端的socketfd,100个元素,clientfd[0]~clientfd[99] +int size = 99999;//用来控制进入聊天室的人数为50以内 +int PORT = 9898;//端口号 +typedef struct sockaddr meng; +socklen_t len; + +struct ota_header_t +{ + int16 frame_flag; ///< frame start flag 2 Bytes + uint8 dev_type; ///< device type + uint8 burn_mode; ///< data burn way + unsigned long total_len; ///< send data total length caculated from each frame_len + unsigned long dev_hid; ///< device hardware version + unsigned long dev_sid; ///< device software version + char resv[32]; ///< reserve +}; + +struct ota_frame_t +{ + uint32 frame_id; ///< Current frame id + uint32 frame_len; ///< Current frame data length + char frame_data[224]; ///< Current frame data,max length 224 + uint32 crc; ///< Current frame data crc +}; + +struct ota_data +{ + struct ota_header_t header; + struct ota_frame_t frame; +}; + +pthread_t ota_ktask; + +/** + * @description: CRC16 check + * @param data data buffer + * @param length data length + * @return check code + */ +uint32_t OtaCrc16(uint8_t * data, uint8_t length) +{ + int j; + unsigned int reg_crc=0xFFFF; + + while (length--) { + reg_crc ^= *data++; + for (j=0;j<8;j++) { + if(reg_crc & 0x01) + reg_crc=reg_crc >>1 ^ 0xA001; + else + reg_crc=reg_crc >>1; + } + } + + return reg_crc; +} + +void init(void) +{ + serverfd = socket(PF_INET,SOCK_STREAM,0); + + if (serverfd == -1) + { + perror("创建socket失败"); + exit(-1); + } + +//为套接字设置ip协议 设置端口号 并自动获取本机ip转化为网络ip + + struct sockaddr_in addr;//存储套接字的信息 + 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时,表示从本机的任一网卡接收数据 + +//绑定套接字 + int on = 1; + if(setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)) < 0) + { + perror("端口设置失败"); + exit(-1); + } + + if (bind(serverfd,(meng*)&addr,sizeof(addr)) == -1) + { + perror("绑定失败"); + exit(-1); + } + + if (listen(serverfd,100) == -1) + {//监听最大连接数 + perror("设置监听失败"); + exit(-1); + } +} +int OtaFileSend(int fd) +{ + unsigned char buf[32] = { 0 }; + struct ota_data data; + FILE *file_fd; + char ch; + int len = 0; + int try_times = 5; + int ret = 0; + int frame_cnt = 0; + int file_length = 0; + char * file_buf = NULL; + + file_fd = fopen("/tmp/xiuos_app.bin", "r"); + + while((ch = fgetc(file_fd)) != EOF) + { + memset(&data, 0, sizeof(data)); + + data.header.frame_flag = 0x5A5A; + len = read(file_fd, data.frame.frame_data, 200 ); + if(len > 0) { + data.frame.frame_id = frame_cnt; + data.frame.frame_len = len; + data.frame.crc = OtaCrc16(data.frame.frame_data, len); + file_length += len; + } + lseek(file_fd, len, SEEK_CUR); + +try_again: + send(fd, &data, sizeof(data), MSG_NOSIGNAL); + len = recv(fd, buf, sizeof(buf), 0); + if(0 == strncmp(buf, "ok", len)) + { + frame_cnt++; + continue; + } + else + { + if(try_times > 0) + { + try_times--; + goto try_again; + } + else + { + printf("send frame[%d] 5 times failed.\n",frame_cnt); + ret = -1; + break; + } + } + } + + if (ret == 0) + { + file_buf = malloc(file_length); + memset(file_buf, 0, file_length); + memset(&data, 0, sizeof(data)); + + data.header.frame_flag = 0x5A5A; + + len = read(file_fd, file_buf, file_length); + if(len > 0) { + data.frame.frame_len = strlen("aiit_ota_end!@");; + data.frame.crc = OtaCrc16(file_buf, len); + memcpy(data.frame.frame_data,"aiit_ota_end!@",strlen("aiit_ota_end!@")); + } + send(fd, &data, sizeof(data), MSG_NOSIGNAL); + free(file_buf); + } + + fclose(file_fd); + return ret; +} + +void* server_thread(void* p) +{ + int fd = *(int*)p; + unsigned char buf[32] = { 0 }; + struct ota_data data; + + printf("pthread = %d\n",fd); + + while(1) + { + memset(&data, 0 , sizeof(struct ota_data)); + data.header.frame_flag = 0x5A5A; + memcpy(data.frame.frame_data,"aiit_ota_start!@",strlen("aiit_ota_start!@")); + data.frame.frame_len = strlen("aiit_ota_start!@"); + + send(fd, &data, sizeof(data), MSG_NOSIGNAL); + + len = recv(fd, buf, sizeof(buf),0); + if (len <= 0) + { + continue; + } + else + { + if(0 == strncmp(buf, "ok", len)) + { + OtaFileSend(fd); + } + } + } +} + +void server(void) +{ + printf("Server startup\n"); + while(1) + { + struct sockaddr_in fromaddr; + socklen_t len = sizeof(fromaddr); + int fd = accept(serverfd,(meng*)&fromaddr,&len); + +//调用accept进入堵塞状态,等待客户端的连接 + + if (fd == -1) + { + printf("The client connection is wrong...\n"); + continue; + } + + int i = 0; + 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) +{ + init(); + server(); +} +