在嵌入式程序开发中,除了与hex文件接触得比较多外,也遇到过不少是用mot文件来进行程序烧写的。我们所说的mot文件实际上就是Motorola S-records文件,是摩托罗拉公司定义的一种S开头的数据记录文件格式。

如下图所示:

平时该格式文件通过专门的烧录工具进行程序烧写,无需知道里面数据的含义,但是当想对接串口、can口等外设进行程序升级时,我们就必须明白mot文件中数据的含义了,只有知道数据的含义,才能提取其关键的信息进行程序开发。

1.格式介绍:

.mot文件每行以‘S’字符开头,第二个字符为数字字符,决定了该行数据的类型,之后的数据为二进制数据转换为hex字符串形式表示,可视为字节数组。

2.数据解析

解析一行数据的代码可参考: https://blog.csdn.net/lin_strong/article/details/79448091

但是仔细分析数据后发现,多行数据其实是一个连续的数据块,将其按数据块解析,将会更加便于我们使用数据。

如下为自行编写的解析代码,若存在问题或bug请留言或与我联系,万分感谢~

mot_file_info.c

/*** @file mot_file_info.c* @brief  MOT文件数据解析模块* @author fangye (fangye945@qq.com)* @date 2020-07-14*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mot_file_info.h"static MOT_INFO_HEAD *s_mot_info_head = NULL;
static MOT_INFO_NODE *s_node_ptr = NULL;/*** @brief 获取MOT文件链表信息指针* @return 链表头指针 */
MOT_INFO_HEAD * get_mot_info()
{return s_mot_info_head;
}/*** @brief 初始化链表头*/
static void init_mot_info_list()
{s_mot_info_head = (MOT_INFO_HEAD *)malloc(sizeof(MOT_INFO_HEAD));s_mot_info_head->run_addr = 0;s_mot_info_head->node_num = 0;s_mot_info_head->next = NULL;
}/*** @brief 添加数据至链表中* 连续的数据块存储在同一节点上* @param  data_addr        数据写入地址* @param  data             数据内容* @param  len              数据长度* @return int * - -1:失败* - 0:成功*/
static int add_data_info_to_list(unsigned int data_addr, char *data, unsigned int len)
{if( data == NULL )return -1;if(s_mot_info_head == NULL)init_mot_info_list();if(s_mot_info_head->next == NULL)     //如果头节点为空{s_mot_info_head->next = (MOT_INFO_NODE *)malloc(sizeof(MOT_INFO_NODE));s_mot_info_head->next->write_addr = data_addr;s_mot_info_head->next->data_len = len;s_mot_info_head->next->data = (char *)malloc(len*sizeof(char));memcpy(s_mot_info_head->next->data, data, len);              //保存数据s_mot_info_head->next->next = NULL;s_mot_info_head->node_num++;       //节点数增加}else                    //节点有数据{s_node_ptr = s_mot_info_head->next;while(s_node_ptr->next != NULL){s_node_ptr = s_node_ptr->next;       //找到最新的数据节点}if(data_addr == s_node_ptr->write_addr + s_node_ptr->data_len)     //如果为连续数据{s_node_ptr->data = (char *)realloc(s_node_ptr->data, (s_node_ptr->data_len + len)*sizeof(char));   //重新申请内存memcpy(&s_node_ptr->data[s_node_ptr->data_len], data, len);   //拷贝数据至末尾s_node_ptr->data_len += len;}else //如果为不连续数据{ s_node_ptr->next = (MOT_INFO_NODE *)malloc(sizeof(MOT_INFO_NODE));if(s_node_ptr->next == NULL)printf("malloc next fail!\n");s_node_ptr = s_node_ptr->next;s_mot_info_head->node_num++;      //节点数增加s_node_ptr->write_addr = data_addr;s_node_ptr->data_len = len;s_node_ptr->data = (char *)malloc(s_node_ptr->data_len*sizeof(char));if(s_node_ptr->data == NULL)printf("malloc data fail!\n");memcpy(s_node_ptr->data, data, len);               ///< 保存数据s_node_ptr->next = NULL;}
#if 0printf("data_len[%d]  addr[0x%08X]: ",len, data_addr);int i = 0;for(i = 0; i<len; i++){printf("%02X ",(unsigned char)data[i]);}printf("\n");
#endif}return 0;
}/*** @brief 添加运行信息至链表头* @param  run_addr         起始运行地址* @return int */
static int add_run_info_to_head(unsigned int run_addr)
{if(s_mot_info_head == NULL)init_mot_info_list();s_mot_info_head->run_addr = run_addr;return 0;
}/*** @brief 单字节hex字符转数字* @param  hex              hex字符* @return int * - -1:失败* - >=0:成功*/
static int CharToInt(char hex)
{if (hex>='0' && hex <='9')return hex - '0';if (hex>='A' && hex <= 'F')return hex-'A'+10;if(hex>='a' && hex <= 'f')return hex-'a'+10;return -1;
}/*** @brief 两字节hex字符串转数字* @param  hex              两字节hex字符串* @return int * - >=0:成功* - <0:失败*/
static int StringToInt(const char *hex)
{int high =  CharToInt(hex[0]);int low = CharToInt(hex[1]);if(high != -1 && low != -1)return high*0x10 + low;else{printf("---StringToInt error!! %s\n",hex);return -1;}
}/*** @brief 字符串hex数据转字节数组* @param  mot_line_buff    Mot文件字符串数据* @param  type             数据类型* @param  data             转换后数据内容* @param  data_len         转换后数据内容长度* @return int * - -1:转换失败* - 0:转换成功*/
static int str2bytes(const char *mot_line_buff, int *type, char *data, int *data_len)
{if( mot_line_buff == NULL)return -1;int len = strlen(mot_line_buff);if(len %2 != 0)return -1;*type = mot_line_buff[1] - '0';int i = 0;int length = 0;len -= 2; ///< 减去换行符/r/n两个字节for(i = 2; i < len; i += 2 ){int ret  = StringToInt(&mot_line_buff[i]);if(ret >= 0){data[length] = ret;length++;}else{return -1;}}*data_len = length;return 0;
}/*** @brief 检测数据合法性* @param  data             数据内容* @param  len              数据长度* @return int * - 0:非法* - 1:合法*/
static int is_data_avaliable(unsigned char *data, int len)
{if(data == NULL)return 0;int i = 0;unsigned char add_sum = data[0];for(i=1; i<len-1; i++){add_sum += data[i];}add_sum = ~add_sum;if(add_sum == data[len-1])return 1;        //校验通过else {printf("add_sum = %d  data[%d]=%d\n",add_sum, len-1, data[len-1]);return 0;     //校验未通过}
}/*** @brief 解析一行数据* @param  line_data        源数据内容* @param  line_data_len    源数据长度* @param  data_type        源数据类型* @param  addr             数据写入地址或运行地址* @param  bin_data         解析后的数据内容* @param  data_len         解析后的数据内容长度* @return int * - 0:失败* - 非0:成功*/
static int parse_a_line(char *line_data, int line_data_len, int data_type, unsigned int *addr, char *bin_data, int *data_len)
{if(line_data == NULL || addr == NULL || bin_data == NULL || data_len == NULL)return 0;
#if 0int i = 0;for(i = 0; i<line_data_len; i++){printf("%02X ",(unsigned char)line_data[i]);}printf("\n");
#endifswitch(data_type){case 1:case 2:case 3:{int data_addr_byte_len = 1 + data_type; ///< 数据地址域长度int i = 0;for(int i=1; i<data_addr_byte_len; i++){*addr += (unsigned char)line_data[i];*addr = (*addr) << 8;if(i+1 == data_addr_byte_len)*addr += (unsigned char)line_data[i+1];}//printf("-- data addr = %08X\n",*addr);*data_len = line_data_len - data_addr_byte_len - 2;memcpy(bin_data, &line_data[data_addr_byte_len+1], *data_len);}break;case 7:case 8:case 9:{int run_addr_byte_len = 11 - data_type;   //运行地址域长度int i = 0;for(int i=1; i<run_addr_byte_len; i++){*addr += (unsigned char)line_data[i];*addr = (*addr) << 8;if(i+1 == run_addr_byte_len)*addr += (unsigned char)line_data[i+1];}//printf("-- run addr = %08X\n",*addr);}break;default:break;}return 1;
}/*** @brief 释放所有节点* @param  node             数据块节点* @return int */
static int free_all_node(MOT_INFO_NODE *node)
{if (node->next != NULL){free_all_node(node->next);}free(node->data);node->data = NULL;free(node);node = NULL;
}/*** @brief 释放mot信息链表* @param  header           链表头指针*/
void free_mot_info_list(MOT_INFO_HEAD *header)
{if( header->next ){free_all_node(header->next);}free(header);header = NULL;
}/*** @brief 加载mot文件信息* @param  mot_filepath     mot文件路径* @return int * - 0: 成功* - -1:失败*/
int load_mot_file(const char *mot_filepath)
{if( mot_filepath == NULL)return -1;FILE *fp = fopen(mot_filepath,"r");if(fp){char buff[512] = {0};while( fgets(buff, sizeof(buff), fp) != NULL) //每次读取一行{char line_data[512]={0};int line_data_len = 0;int type = 0;if(0 == str2bytes(buff, &type, line_data, &line_data_len)) //转为数组{if( is_data_avaliable(line_data, line_data_len) )    //校验数据合法性{unsigned int addr = 0;char bin_data[512]={0};int data_len = 0;if(parse_a_line(line_data, line_data_len, type, &addr, bin_data, &data_len))//解析一行数据{if(type == 1 || type == 2 || type == 3)   //数据地址及数据内容{add_data_info_to_list(addr, bin_data, data_len);}else if(type == 7 || type == 8 || type == 9)  //运行地址{add_run_info_to_head(addr);}}else   //解析失败{printf("parse a line data fail!\n");return -1;}}else //数据校验失败{printf("mot data is error!\n");return -1;}}else    //转换为数组失败{printf("a line str2bytes error!\n");return -1;}memset(buff,0,sizeof(buff));}fclose(fp);fp = NULL;}else{printf("open mot file %s fail!\n",mot_filepath);return -1;}return 0;
}

mot_file_info.h

/*** @file mot_file_info.h* @brief .MOT文件数据解析模块头文件* @author fangye (fangye945@qq.com)* @date 2020-07-14*/#ifndef __MOT_FILE_INFO_H__
#define __MOT_FILE_INFO_H__#ifdef __cplusplus
extern "C"{
#endif /* __cplusplus *//*** @brief mot文件数据块节点*/
typedef struct _MOT_INFO_NODE
{unsigned int write_addr;           ///< 数据写入地址unsigned int data_len;                ///< 数据长度char *data;                         ///< 数据内容struct _MOT_INFO_NODE *next;        ///< 下一段地址不连续的数据内容
}MOT_INFO_NODE;/*** @brief mot文件信息链表头*/
typedef struct _MOT_INFO_HEAD
{unsigned int run_addr;         ///< 程序运行地址unsigned int node_num;            ///< 地址段节点个数struct _MOT_INFO_NODE *next; ///< 链表头节点指针
}MOT_INFO_HEAD;extern int load_mot_file(const char *mot_filepath);extern MOT_INFO_HEAD *get_mot_info();extern void free_mot_info_list(MOT_INFO_HEAD *header);#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __MOT_FILE_INFO_H__ */

main.c

#include <stdio.h>
#include <string.h>
#include "mot_file_info.h"int main(int argc, char *argv[])
{if(argc != 2)return 0;int ret = load_mot_file(argv[1]);if(ret == 0){printf("load mot file success!!\n");MOT_INFO_HEAD *mot_info = get_mot_info();//获取mot文件信息printf("--- run_addr = 0x%08X  node_num = %d ---\n", mot_info->run_addr, mot_info->node_num);MOT_INFO_NODE *node_ptr = mot_info->next;if(node_ptr){do{printf("write_addr = 0x%08X  data_len = 0x%08X\n", node_ptr->write_addr, node_ptr->data_len);node_ptr = node_ptr->next;}while(node_ptr);}free_mot_info_list(mot_info);    ///< 释放链表}return 0;
}

执行结果:

如图所示上图所示:

能够直接链表头获取到整个程序运行的起始地址、不连续数据块个数 、每个数据块的大小和写入的起始地址。

C语言之mot文件解析相关推荐

  1. mot文件解析成bin

    mot固件文件转成bin文件 mot文件介绍 开始解析 mot文件介绍 mot s19 bin hex都可以用于固件文件的存储,其中bin文件就是固件原始数据,只记录固件的二进制数据流,mot文件实际 ...

  2. dbc文件c语言解析标准,DBC文件解析CAN信息

    <DBC文件解析CAN信息>由会员分享,可在线阅读,更多相关<DBC文件解析CAN信息(15页珍藏版)>请在人人文库网上搜索. 1.DBCCAN数据包-基于CANAPE,打开C ...

  3. BIN,S19,M0T,SREC,HEX文件解析;FileParse(二)之源码解析

    简介 一.摘要 1.描述 2.关键字 二.为何选择C#解析 三.BIN文件解析 四.BIN文件生成 五.S19,M0T,SREC文件解析 六.S19,M0T,SREC文件生成 七.HEX文件解析 八. ...

  4. BIN,S19,M0T,SREC,HEX文件解析;FileParse(一)之文件详解

    简介 一.摘要 1.描述 2.关键字 二.为什么要文件解析 三.BIN文件格式 四.S19,M0T,SREC文件格式 五.HEX文件格式 六.源码下载 七.其他 八.参考 一.摘要 1.描述 本文主要 ...

  5. java解析五元组_pcap文件解析,并且按照五元组分类

    [实例简介] pcap文件解析,并按照五元组分包,全部用java语言实现. [实例截图] [核心代码] PcapTestZZ ├── PcapTestZ │   ├── 111.206.37.1930 ...

  6. C语言关于static的解析

    C语言关于static的解析 #include<stdio.h> static int j; void fun1(void) { int i = 0; i ++; } void fun2( ...

  7. java怎么xml文件解析_Java对Xml文件解析

    JAVA 解析 XML 通常有两种方式,DOM 和 SAX. DOM 虽然是 W3C 的标准,提供了标准的解析方式,但它的解析效率一直不尽如人意,因为使用DOM解析XML时,解析器读入整个文档并构建一 ...

  8. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  9. 2020-10-27(dex文件解析)

    一张图搞懂dex 大图这里 当然也可以通过下面的图12 DexFile的文件格式,了解更清楚. DEX文件详解 什么是dex文件? 如何生成一个dex文件 dex文件的作用 dex文件格式详解 什么是 ...

最新文章

  1. 5.Ubuntu下的GIF录制软件peek安装
  2. 儿童版「微信」要来了?
  3. [optee]-optee的加解密接口的介绍
  4. java 重写方法 访问权限_为何Java中子类重写方法的访问权限不能低于父类中权限(内含里氏替换原则)...
  5. Using dbms_shared_pool.purge to remove a single task from the library cache
  6. 含根号的导数怎么求_数学分析Mathematical Analysis笔记整理 第四章 导数与微分
  7. 如何提高英文的科研写作能力
  8. ios 监听一个控制器的属性_ios - kvo观察者示例(监听类的属性变化)
  9. ajax post 与get方法 data写法
  10. eclipse的自动检查语法错误功能让我有点烦,能不能关掉,或者,只是10秒检查一次。。...
  11. 三阶实对称矩阵的秩一分解(快速计算三阶矩阵特征值特征向量的方法)
  12. Android报unable to instantiate application怎么解决
  13. HTML文本格式化标签详解
  14. pwnable-passcode
  15. mysql uftb8mb4 储存 emoji 表情失败
  16. python 正则表达式 断言 不定长表达式_【教程】详解Python正则表达式之: (?!…) negative lookahead assertion 前向否定匹配 /前向否定断言...
  17. 2023年,莫荒废了时光。
  18. 数据集分布评估-KDE (核密度估计)、KS检验
  19. 编写html获取天气(数据来源theamp;nbs…
  20. 2021最新 阿里云ECS搭建我的世界服务器

热门文章

  1. 海淀育新学校2021高考成绩查询,首师附育新“加工能力”不容小觑!海淀7000名以内可“签约”实验班...
  2. sde无法连接oracle,SDE无法连接问题处理过程
  3. 【结构光三维重建标定学习】左超论文之Triangular stereo model
  4. Java运算符与Scanner键盘输入
  5. 详细教您台式电脑如何组装
  6. (8)打鸡儿教你Vue.js
  7. com.mysql.cj.exceptions.CJCommunicationsException
  8. 2017百度校园招聘编程题
  9. SAP 批量打开生产工单
  10. android 11 机型,安卓11支持哪些机型,Android11适配机型一览