/****************************************************************************** 版权所有: 文件名称: IEC101_FILE.c 文件版本: 01.01 创建作者: sunxi 创建日期: 2012-10-10 功能说明: 101规约文件传输扩展 其它说明: 修改记录: */ /*------------------------------- 头文件 -------------------------------------- */ #include "head.h" /*------------------------------- 宏定义 -------------------------------------- */ #define IEC101_TYPE_FILE 137 #define IEC101_FILE_ACK 0X80 #define IEC101_FILE_NAK 0X40 #define FILE_ERR_OK 0x00 #define FILE_ERR_NAME 0x01 #define FILE_ERR_TYPE 0x02 #define FILE_ERR_BUSY 0x03 #define FILE_ERR_ADDR 0x04 #define FILE_ERR_SIZE 0x05 #define FILE_ERR_CRC 0x06 #define FILE_ERR_SAVE 0x07 #define FILE_ERR_PHASE 0x08 #define FILE_ERR_MEM 0x09 #define FILE_ERR_STATE 0x0a #define FILE_ERR_OTHER 0xff /*------------------------------ 类型结构 ------------------------------------- */ enum fState { FS_IDLE = 0, FS_VERIFY_DOWN, FS_VERIFY_UP, FS_INFO_DOWN, FS_INFO_UP, FS_DATA_DOWN, FS_DATA_UP, FS_RESULT_DOWN, FS_RESULT_UP, }; struct file101 { enum fState state; s32 file_index; u16 file_type; u16 file_crc; u32 file_length; u32 file_offset; u8* file_buf; }; /*------------------------------ 全局变量 ------------------------------------- */ struct file101 g_file101= {0}; // 通过串口下载的文件,不需要在maintain中再检查文件 u8 g_file_save=0; /*------------------------------ 函数声明 ------------------------------------- */ static int _file_up_info(int index); static int _file_save_app(int index); //static int _file_check(s8 * name,u32 attr); int printf_file101(void); struct file_item g_file_item[] = { {KO_FILE_NAME_1, "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_MAINAPP, _file_save_app}, {"m", "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"equ_res.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_BRD, _file_save_app}, {"equ_cfg.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_CFG, _file_save_app}, {"e2prom.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"brd_res.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"iectable.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_TABLE, _file_save_app}, {FILE_NAME_PPL_CFG, "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_PPL, _file_save_app}, {"fixset.csv", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, // 固定参数文件 {"pcolcfg.ini", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, // 级联规约文件 {"vol_status.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"set_data.bin", "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_SET, _file_save_app}, {FILE_NAME_RSC, "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {FILE_NAME_PPL_RSC, "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {FILE_NAME_SET_DESC, "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"env.dat", "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"instu.bin", "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"log_err.txt", "/app/data/", ATTR_UP, FILETYPE_LOG_APP, _file_save_app}, {"log_operate.txt", "/app/data/", ATTR_UP, FILETYPE_LOG_APP, _file_save_app}, {"log_soe.txt", "/app/data/", ATTR_UP, FILETYPE_LOG_APP, _file_save_app}, {"log_yx.txt", "/app/data/", ATTR_UP, FILETYPE_LOG_APP, _file_save_app}, {"log_fixset.txt", "/app/data/", ATTR_UP, FILETYPE_LOG_GPRS, _file_save_app}, {"log_gprs.txt", "/app/data/", ATTR_UP, FILETYPE_LOG_GPRS, _file_save_app}, {"logcfg.xml", "/app/IEC61850/cfg/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"osicfg.xml", "/app/IEC61850/cfg/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"file_list.bin", "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, #if (0) {"f306.ko", "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_MAINAPP, _file_save_app}, {"f308.ko", "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_MAINAPP, _file_save_app}, {"u-boot.bin", "/tmp/", ATTR_DOWN, FILETYPE_SYS, _file_save_app}, // 引导程序 {"uImage", "/tmp/", ATTR_DOWN, FILETYPE_SYS, _file_save_app}, // 内核程序 {"app.jffs2", "/tmp/", ATTR_DOWN, FILETYPE_SYS, _file_save_app}, // 应用系统 {"rootfs.jffs2", "/tmp/", ATTR_DOWN, FILETYPE_SYS, _file_save_app}, // 内核系统 {"image_flash.bin", "/tmp/", ATTR_DOWN, FILETYPE_SYS, _file_save_app}, // 烧录系统 {"innergprs.ini", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_INNERGPRS, _file_save_app}, {FILE_NAME_GPRSDRIVER, "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_GPRSDRIVER, _file_save_app}, {"gprs_app", "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_GPRSAPP, _file_save_app}, {"rec_wave.dat", "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"F308_HMI.bin", "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_F308_HMI, _file_save_app}, {"DTU-DIDO.elf.bin", "/tmp/", ATTR_UP | ATTR_DOWN, FILETYPE_CHILDPRO, _file_save_app}, {"changelog.txt", "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, // {"acfactor.bin", "/app/data/", ATTR_UP, FILETYPE_OTHER, _file_save_app}, // {"dcfactor.bin", "/app/data/", ATTR_UP, FILETYPE_OTHER, _file_save_app}, {"hzk.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sm2key0.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sm2key1.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sm2key2.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sm2key3.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"userid.bin", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"x509_time0", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"x509_time1", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"x509_time2", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"x509_time3", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sysm2_0.cer", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sysm2_1.cer", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sysm2_2.cer", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"sysm2_3.cer", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"master_slave_equ_sync", "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"factor_modify", "/app/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"mainImage.lcd", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"lcd_menu.csv", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {"vir_mix_table.csv", "/app/data/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[0], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[1], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[2], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[3], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[4], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[5], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[6], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, {wave_name[7], "/app/data/rec_wave/", ATTR_UP | ATTR_DOWN, FILETYPE_OTHER, _file_save_app}, #endif }; const int FILE_LIST_NUM = (sizeof(g_file_item) / sizeof(struct file_item)); #define FILE_ITEM_NUM (sizeof(g_file_item) / sizeof(struct file_item)) struct stat g_file_time[FILE_ITEM_NUM]; // 文件最新修改时间 /*------------------------------ 函数声明 ------------------------------------- */ int file_check(s8 *name, u32 attr); static void _file_state_reset(void); static void _file_echo(IEC101_DEF *pt, u8 *cmd_buf, u8 cmd_len); /*------------------------------ 外部函数 ------------------------------------- 外部函数供其它实体文件引用,必须仔细检查传入参数的合法性. */ int IEC101_TransFile(IEC101_DEF *pt, unsigned char *buf, int len) { u8 cmd_len; u8 cmd_buf[256]; cmd_len = com_trans_file(buf, len, cmd_buf); // 按101格式组帧 _file_echo(pt, cmd_buf, cmd_len); return 0; } extern bool g_mt_rs232; int IEC101_Maintain(IEC101_DEF *pt, unsigned char *buf, int len) { u8 cmd_buf[256]; u8 cmd_len; g_mt_rs232 = 1; memset(cmd_buf, 0, sizeof(cmd_buf)); cmd_len = Maintain_Manage(buf, len, cmd_buf); // 按101格式组帧 _file_echo(pt, &cmd_buf[0], cmd_len); return 0; } int com_trans_file(u8 *buf, u32 len, u8 *cmd_buf) { u8 cmd_len = 0; u32 offset; cmd_buf[0] = IEC101_TYPE_FILE; cmd_buf[1] = buf[1]; switch (buf[1]) { case 0x01: // 下载请求验证 // 复位状态机 _file_state_reset(); sprintf(cmd_buf + 2, szTool); sprintf(cmd_buf + 21, VER_TIME "CRC:%04XH", m_CodeCrc); cmd_len = strlen(cmd_buf + 2) + 1 + 2; #if 0 if(memcmp(buf+2,szTool,19) != 0) // 具体版本号暂时不检查(匹配V1.XX.XX) { cmd_buf[1] |= IEC101_FILE_NAK; break; } #endif cmd_buf[1] |= IEC101_FILE_ACK; g_file101.state = FS_VERIFY_DOWN; break; case 0x02: // 上传请求验证 // 复位状态机 _file_state_reset(); sprintf(cmd_buf + 2, szTool); sprintf(cmd_buf + 21, VER_TIME "CRC:%04XH", m_CodeCrc); cmd_len = strlen(cmd_buf + 2) + 1 + 2; #if 0 if(memcmp(buf+2,szTool,19) != 0) // 具体版本号暂时不检查(匹配V1.XX.XX) { cmd_buf[1] |= IEC101_FILE_NAK; break; } #endif cmd_buf[1] |= IEC101_FILE_ACK; g_file101.state = FS_VERIFY_UP; break; case 0x03: // 下载文件信息 memcpy(cmd_buf + 2, buf + 2, 64); // copy file name cmd_buf[65] = 0; memcpy(&g_file101.file_type, buf + 66, 2); swap16(&g_file101.file_type); memcpy(&g_file101.file_length, buf + 68, 4); swap32(&g_file101.file_length); memcpy(&g_file101.file_crc, buf + 72, 2); swap16(&g_file101.file_crc); g_file101.file_offset = 0; // 检查文件阶段 if ((g_file101.state != FS_VERIFY_DOWN) && (g_file101.state != FS_INFO_DOWN)) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[22] = FILE_ERR_PHASE; cmd_len = 23; break; } // 检查文件名 g_file101.file_index = file_check(cmd_buf + 2, ATTR_DOWN); if (g_file101.file_index < 0) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[66] = FILE_ERR_NAME; cmd_len = 67; break; } // 检查文件长度 if (g_file101.file_length > 4 * 1024 * 1024) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[66] = FILE_ERR_SIZE; cmd_len = 67; break; } // 分配内存 g_file101.file_buf = rt_malloc(g_file101.file_length); if ((g_file101.file_buf) == NULL) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[66] = FILE_ERR_MEM; cmd_len = 67; break; } // 所有检查通过,应答ACK cmd_buf[1] |= IEC101_FILE_ACK; cmd_len = 66; // printf_file101(); // 修改状态 g_file101.state = FS_INFO_DOWN; break; case 0x04: // 上传文件信息 memcpy(cmd_buf + 2, buf + 2, 64); // copy file name cmd_buf[65] = 0; // 检查文件阶段 if ((g_file101.state != FS_VERIFY_UP) && (g_file101.state != FS_INFO_UP)) { // 阶段不对 _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[66] = FILE_ERR_PHASE; cmd_len = 67; break; } // 检查文件名称 g_file101.file_index = file_check(cmd_buf + 2, ATTR_UP); if (g_file101.file_index < 0) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[66] = FILE_ERR_NAME; cmd_len = 67; break; } // 取得文件信息 if (_file_up_info(g_file101.file_index) != 0) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[66] = FILE_ERR_NAME; cmd_len = 67; break; } // printf_file101(); // 文件准备就绪,应答ACK memcpy(cmd_buf + 66, &g_file101.file_type, 2); swap16(cmd_buf + 66); memcpy(cmd_buf + 68, &g_file101.file_length, 4); swap32(cmd_buf + 68); memcpy(cmd_buf + 72, &g_file101.file_crc, 2); swap16(cmd_buf + 72); cmd_buf[1] |= IEC101_FILE_ACK; cmd_len = 74; // 修改状态 g_file101.state = FS_INFO_UP; break; case 0x05: // 下载文件正文 memcpy(cmd_buf + 2, buf + 2, 4); memcpy(&offset, buf + 2, 4); swap32(&offset); // 检查文件阶段 if ((g_file101.state != FS_INFO_DOWN) && (g_file101.state != FS_DATA_DOWN)) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[6] = FILE_ERR_PHASE; cmd_len = 7; break; } // 检查文件buf if (g_file101.file_buf == NULL) { rt_printf("IEC101_TransFilefile_buf==NULL\r\n"); _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[6] = FILE_ERR_STATE; cmd_len = 7; break; } // 检查文件offset if (offset == g_file101.file_offset) { // 一切正常,获取数据 len -= 2 + 4; memcpy(g_file101.file_buf + offset, buf + 6, len); g_file101.file_offset += len; } else { rt_printf("IEC101_TransFile:offset\r\n"); } // 发送ACK cmd_buf[1] |= IEC101_FILE_ACK; memcpy(cmd_buf + 2, &g_file101.file_offset, 4); swap32(cmd_buf + 2); cmd_len = 6; // 修改状态 g_file101.state = FS_DATA_DOWN; break; case 0x06: // 上传文件正文 memcpy(cmd_buf + 2, buf + 2, 4); memcpy(&offset, buf + 2, 4); swap32(&offset); // 检查文件阶段 if ((g_file101.state != FS_INFO_UP) && (g_file101.state != FS_DATA_UP)) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[6] = FILE_ERR_PHASE; cmd_len = 7; break; } // 检查文件file_buf if (g_file101.file_buf == NULL) { rt_printf("IEC101_TransFilefile_buf==NULL\r\n"); _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[6] = FILE_ERR_STATE; cmd_len = 7; break; } // 检查文件offset if (offset >= g_file101.file_length) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[6] = FILE_ERR_ADDR; cmd_len = 7; break; } // 发送ACK cmd_buf[1] |= IEC101_FILE_ACK; if (g_file101.file_length - offset > 200) { cmd_len = 200; } else { cmd_len = g_file101.file_length - offset; } memcpy(cmd_buf + 6, g_file101.file_buf + offset, cmd_len); cmd_len += 6; // 修改状态 g_file101.state = FS_DATA_UP; break; break; case 0x07: // 下载结果确认 // 检查文件阶段 if ((g_file101.state != FS_DATA_DOWN) && (g_file101.state != FS_RESULT_DOWN)) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[2] = FILE_ERR_PHASE; cmd_len = 3; break; } // 如果是重复报文,继续肯定应答。 if (g_file101.state == FS_RESULT_DOWN) { // 判断是否需要复位 if (buf[2] == 1) // 0:不复位;1:复位 { watchdog_reset_cpu(1); } cmd_buf[1] |= IEC101_FILE_ACK; cmd_len = 2; break; } // 检查文件长度 if (g_file101.file_offset != g_file101.file_length) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[2] = FILE_ERR_SIZE; cmd_len = 3; break; } // 检查文件CRC if (CrcStr(g_file101.file_buf, g_file101.file_length) != g_file101.file_crc) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[2] = FILE_ERR_CRC; cmd_len = 3; break; } // 文件保存 if (g_file_item[g_file101.file_index].file_func(g_file101.file_index) != 0) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[2] = FILE_ERR_SAVE; cmd_len = 3; break; } // 一切正常,肯定应答 cmd_buf[1] |= IEC101_FILE_ACK; cmd_len = 2; // 复位全部状态后,设置状态为FS_RESULT_DOWN,继续应答重发确认帧。 _file_state_reset(); g_file101.state = FS_RESULT_DOWN; break; case 0x08: // 上传结果确认 // 检查文件阶段 if ((g_file101.state != FS_DATA_UP) && (g_file101.state != FS_RESULT_UP)) { _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[2] = FILE_ERR_PHASE; cmd_len = 3; break; } // 如果是重复报文,继续肯定应答。 if (g_file101.state == FS_RESULT_UP) { cmd_buf[1] |= IEC101_FILE_ACK; cmd_len = 2; break; } // 一切正常,肯定应答 cmd_buf[1] |= IEC101_FILE_ACK; cmd_len = 2; // 复位全部状态后,设置状态为FS_RESULT_UP,继续应答重发确认帧。 _file_state_reset(); g_file101.state = FS_RESULT_UP; break; break; default: rt_printf("IEC101_TransFile:不支持的命令(%d)\r\n", buf[0]); _file_state_reset(); cmd_buf[1] |= IEC101_FILE_NAK; cmd_buf[2] = FILE_ERR_OTHER; cmd_len = 3; break; } return cmd_len; } int file_check(s8 *name, u32 attr) { int i; for (i = 0; i < FILE_ITEM_NUM; i++) { if (strcmp(name, g_file_item[i].file_name) == 0) { if (attr & g_file_item[i].file_attr) { return i; } } } return -1; } int file_check_type(s8 *name, u32 attr) { int i; for (i = 0; i < FILE_ITEM_NUM; i++) { if (strcmp(name, g_file_item[i].file_name) == 0) { return g_file_item[i].file_type; } } return -1; } int file_check_info(int index) { char file_name[64]; u32 len; u16 crc; u8 *buf; struct cfg_file_head *brh; unsigned int signature; // 配置文件签名 struct file *pfile; loff_t pos; if ((g_file_item[index].file_type == FILETYPE_INNERGPRS) || (g_file_item[index].file_type == FILETYPE_SYS)) { return 0; } sprintf(file_name, "%s%s", "/tmp/", g_file_item[index].file_name); // 打开文件 pfile = rt_file_open(file_name, O_RDONLY, 0); if (IS_ERR(pfile)) { return -1; } // 得到文件长度 len = rt_file_getfile_size(pfile); if (len <= 0) { rt_file_close(pfile, 0); return -11; } // 分配内存 buf = rt_malloc(len); if ((buf) == NULL) { rt_file_close(pfile, 0); return -2; } // 读出内容 pos = 0; if (rt_file_read(pfile, buf, len, &pos) != len) { rt_file_close(pfile, 0); rt_free(buf); return -3; } // 关闭文件 rt_file_close(pfile, 0); // 检查CRC crc = CrcStr(buf, len - 2); if (g_file_item[index].file_type == FILETYPE_CHILDPRO) { crc = CrcStr(buf + 64, len - 2 - 64); // swap16(&crc); } if (g_file_item[index].file_type == FILETYPE_F308_HMI) { crc = CrcStr(buf + 64, len - 2 - 64); } if ((g_file_item[index].file_type == FILETYPE_MAINAPP) || (g_file_item[index].file_type == FILETYPE_CHILDPRO) || (g_file_item[index].file_type == FILETYPE_F308_HMI)) { // ko,或子板程序 #ifdef MODE_LITTLE_ENDIAN swap16(&crc); #endif } if (crc != *(u16 *)(buf + len - 2)) { rt_free(buf); return -4; } // 检查文件签名 brh = (struct cfg_file_head *)buf; signature = 0; switch (g_file_item[index].file_type) { case FILETYPE_CFG: signature = SIG_EQU_CFG_FILE; break; case FILETYPE_SET: signature = SIG_SET_DATA_FILE; break; case FILETYPE_TABLE: signature = SIG_TABLE_FILE; break; case FILETYPE_BRD: signature = SIG_EQU_RES_FILE; break; case FILETYPE_MAINAPP: case FILETYPE_FPGA: case FILETYPE_CHILDPRO: case FILETYPE_OTHER: case FILETYPE_GPRSDRIVER: case FILETYPE_GPRSAPP: case FILETYPE_F308_HMI: case FILETYPE_PPL: rt_free(buf); return 0; break; } if (brh->signature != signature) { rt_free(buf); return -5; } return 0; } u32 file_change_time(int index) { struct stat s; char file_name[64]; sprintf(file_name, "%s%s", g_file_item[index].file_dir, g_file_item[index].file_name); if (sys_newstat((char *)file_name, &s)) { return -1; } return s.st_mtime; } /*------------------------------ 内部函数 ------------------------------------- 内部函数以下划线‘_’开头,不需要检查参数的合法性. */ #if 0 static int _file_check(s8 * name,u32 attr) { int i; char file_name[64]; for(i=0; i< FILE_ITEM_NUM; i++) { sprintf(file_name,"%s%s",g_file_item[i].file_dir,g_file_item[i].file_name); if(strcmp(name,file_name) == 0) { if(attr & g_file_item[i].file_attr) { return i; } } } return -1; } #endif static int _file_up_info(int index) { char file_name[64]; struct file *pfile; loff_t pos; sprintf(file_name, "%s%s", g_file_item[index].file_dir, g_file_item[index].file_name); // 打开文件 pfile = rt_file_open(file_name, O_RDONLY, 0); if (IS_ERR(pfile)) { return -1; } // 得到文件长度 g_file101.file_length = rt_file_getfile_size(pfile); if (g_file101.file_length == 0) { rt_file_close(pfile, 0); return -11; } // 分配内存 g_file101.file_buf = rt_malloc(g_file101.file_length); if ((g_file101.file_buf) == NULL) { rt_file_close(pfile, 0); return -2; } // 读出内容 pos = 0; if (rt_file_read(pfile, g_file101.file_buf, g_file101.file_length, &pos) != g_file101.file_length) { rt_file_close(pfile, 0); rt_free(g_file101.file_buf); g_file101.file_buf = 0; return -3; } // 关闭文件 rt_file_close(pfile, 0); // 计算CRC g_file101.file_crc = CrcStr(g_file101.file_buf, g_file101.file_length - 2); // offset g_file101.file_offset = 0; // 文件类型 g_file101.file_type = 0; return 0; } static int _file_save_app(int index) { char file_name[64]; struct file *pfile; loff_t pos; char from_file_name[64]; char to_file_name[64]; g_file_save = 0; // sprintf(file_name,"%s%s.new",g_file_item[index].file_dir,g_file_item[index].file_name); sprintf(file_name, "%s%s", "/tmp/", g_file_item[index].file_name); // 创建并打开文件 pfile = rt_file_open(file_name, O_CREAT | O_RDWR | O_TRUNC | O_SYNC, 0); if (IS_ERR(pfile)) { return -1; } // 写文件 pos = 0; if (rt_file_write(pfile, g_file101.file_buf, g_file101.file_length, &pos) != g_file101.file_length) { rt_file_close(pfile, 0); return -2; } // 关闭文件 rt_file_close(pfile, 0); if (file_check_info(index) == 0) { sprintf(to_file_name, "%s%s", g_file_item[index].file_dir, g_file_item[index].file_name); sprintf(from_file_name, "%s%s", "/tmp/", g_file_item[index].file_name); rt_file_mv(from_file_name, to_file_name); sprintf(file_name, "%s%s%s", "文件更新", g_file_item[index].file_dir, g_file_item[index].file_name); log_str_time(LOG_OPERATE, file_name, 0, 0); g_file_save = 1; } else { sprintf(from_file_name, "%s%s", "/tmp/", g_file_item[index].file_name); rt_file_del(from_file_name); } return 0; } static void _file_state_reset(void) { g_file101.state = FS_IDLE; if (g_file101.file_buf) { rt_free(g_file101.file_buf); g_file101.file_buf = 0; } } static void _file_echo(IEC101_DEF *pt, u8 *cmd_buf, u8 cmd_len) // 确认帧 { BYTE cnt, checksum, len; BYTE *p; BYTE AddByte = 0; p = pt->tx_buf_s; if (tRunPara.b101Addr2Byte) { AddByte = 1; p[7] = (BYTE)(tRunPara.byAddr >> 8); // 链路地址高地址 } // 101规约len域的值 +4=控制域、地址 、类型标识 、 文件命令 len = cmd_len + 2 + AddByte; // 报文帧长度 +6=报文头(4字节)校验和、结束符 p[0] = len + 6; // 帧头 p[1] = 0x68; // 报文头 p[2] = len; p[3] = len; p[4] = 0x68; p[5] = IEC101_ECHO_DATA; // 控制域 p[6] = (BYTE)tRunPara.byAddr; // 链路地址 // 命令 p = &pt->tx_buf_s[7 + AddByte]; // 调整位置 memcpy(p, cmd_buf, cmd_len); // 计算检验和 p = &pt->tx_buf_s[5]; checksum = 0; for (cnt = 0; cnt < len; cnt++) { checksum += *p++; } *p++ = checksum; // 帧尾 *p++ = 0x16; } /*------------------------------ 测试函数 ------------------------------------- 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数). */ int printf_file101(void) { rt_printf("g_file101:\t%p\r\n", &g_file101); rt_printf("state:\t\t%d\r\n", g_file101.state); rt_printf("file_name:\t%s\r\n", g_file_item[g_file101.file_index].file_name); rt_printf("file_index:\t%d\r\n", g_file101.file_index); rt_printf("file_type:\t%d\r\n", g_file101.file_type); rt_printf("file_crc:\t0x%04x\r\n", g_file101.file_crc); rt_printf("file_length:\t%d\r\n", g_file101.file_length); rt_printf("file_offset:\t%d\r\n", g_file101.file_offset); rt_printf("file_buf:\t%p\r\n", g_file101.file_buf); return 0; } /*------------------------------ 文件结束 ------------------------------------- */