mot固件文件转成bin文件

  • mot文件介绍
  • 开始解析

mot文件介绍

mot s19 bin hex都可以用于固件文件的存储,其中bin文件就是固件原始数据,只记录固件的二进制数据流,mot文件实际上就是Motorola S-records文件,是摩托罗拉公司定义的一种S开头的数据记录文件格式。mot文件不需要记录固件中每一个地址的数据,它可以按照地址和数据来记录固件信息,固件中没有使用的地址将不会记录,这样也使得mot文件相对于bin文件,体积会小很多。jflash是支持各种固件的文件,我们用就flash打开.mot文件,就可以看到真实的固件信息,包括固件的起始地址,真实数据,结束地址等等。
我们可以用文本工具打开mot文件,可以看出它是以字符的方式进行数据的记录的

可以看到文件都是以S开头的,而且是每一行作为一个单位长度。每一行数据都包含 数据类型 数据长度 地址域数据 数据域数据 CRC这5个部分。
每一行开头的S0 S3 S7为头部信息,下面用一个表格来解释每一行数据的意义:

数据类型 数据长度 地址域数据 数据域数据 CRC校验

S0:标题信息

S1:地址域为2字节,数据域为要写入的数据

S2:地址域为3字节,数据域为要写入的数据

S3:地址域为4字节,数据域为要写入的数据

S5:地址域做2字节整形值,代表之前传输的S1,S2,S3记录的总数,无数据域数据

S7:地址域为4字节,代表代码起始运行地址,无数据域数据

S8:地址域为3字节,代表代码起始运行地址,无数据域数据

S9:地址域为2字节,代表代码起始运行地址,无数据域数据

2个字符,占1个字节,代表地址域数据到CRC的长度 数据长度由数据类型决定 数据长度由数据类型和实际数据大小决定 占1个字节,数据长度,地址域数据,数据域数据中对应的所有字节值相加后按位取反得到的值

我们截取几行数据来进行分析下
S0030000FC S0标题信息
S30D00000000015A015A0000813C7F
数据类型为S3
数据长度0X0D
地址0X0000
该地址的数据01 5A 01 5A 00 00 81 3C
CRC校验 7F

我们用jflash打开该mot文件 发现跟我们解析的是一致的

注意:mot文件并不会从程序的起始地址一直记录到程序的结束地址,而是只记录有效数据,无效数据(全是0XFF的数据)是不会被记录的,我们在转换成bin的时候需要注意,如果传输整个固件的话,mot没有记录的地址我们需要按照0XFF传输并且烧写,如果单片机支持分地址烧写,那么只需要解析地址和数据然后烧写即可。

开始解析

首先需要几个string转int的函数

/*** @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  hex  hex字符串,除去空格后字符串长度必须是偶数*         byte_array  存放转换后数据的数组*         len 需要转换的字节数,这个参数是实际转换后数组的长度,必须确保小于hex数组长度的一半*              -1表示整个hex字符串都转换* @return int* - >=0:成功,返回值代表转换后数组的长度* - <0:失败*/
static int StringToByteArray(char *hex,uint8_t *byte_array,int len)
{if(hex==NULL || byte_array==NULL)return -1;/* 删除所有空格 */char *str_hex = hex;int i,j=0;int high=0,low=0;int byte = 0;for(i=0;hex[i]!='\0';i++){if(CharToInt(hex[i])>=0)str_hex[j++]=hex[i];}str_hex[j]='\0';if(len == 0)return 0;else if(len > 0){for(i=0,j=0;i<len;i++){if((str_hex[i*2]!='\0'&&str_hex[i*2+1]!='\0')){byte = StringToInt(&str_hex[i*2]);if(byte != -1 ){byte_array[j++] = (uint8_t)byte;}else{return -1;}}else{break;}}}else if(len < 0){for(i=0,j=0;(str_hex[i]!='\0'&&str_hex[i+1]!='\0');i+=2){byte = StringToInt(&str_hex[i]);if(byte != -1 ){byte_array[j++] = (uint8_t)byte;}else {return -1;}}}return j;}

CRC校验函数
我们的校验函数做了十六进制字符串到二进制数组的转换 后面直接使用数组即可

//校验MOT文件的单行数据
//校验MOT文件的单行数据
//line_file 单行文件原始数据
//byte_array 十六进制字符转数组后的存储地址
//len 数组的长度
int mot_line_file_check_crc(uint8_t *line_file,uint8_t *byte_array,int len)
{if(line_file == NULL)return -1;uint8_t buf[256] = {0};uint8_t data_buf_len = 0;/* 转换成数组 最前面2个字符的S开头的头部信息,不做转换 */if((data_buf_len=StringToByteArray((char*)line_file+2,buf,sizeof(buf)))<0)return -1;/* 复制转换后的数组 */if(byte_array != NULL){memcpy(byte_array,buf,(len>data_buf_len?data_buf_len:len));}/* 校验CRC */uint8_t add_sum = 0;int i=0;for(i=0;i<data_buf_len-1;i++){add_sum += buf[i];}add_sum = ~add_sum;if(add_sum == buf[data_buf_len-1]){/* 检查数据长度 byte数组的第一个字节为剩余数据长度 *///qDebug("data_buf_len:%d buf[0]:%d",data_buf_len,buf[0]);if((data_buf_len-buf[0]) == 1)return data_buf_len;    //校验成功返回数组长度(一行数据除了2个字符头部后的byte数组长度)elsereturn -1;  //如果数据长度错误也返回错误}elsereturn -1;}

有了这些转换函数,我们才能更方便地将字符串表示地十六进制数转换成二进制数据。
然后我们需要实现文件的读取,这个过程需要根据实际的语言或者软件来实现,只要能将文件读取到内存即可。
我们需要一些结构体变量来记录单行文件和整个文件的信息

    #define MOT_LINE_DATA_MAX_LEN   256/* MOT文件控制变量 */typedef struct{uint8_t type;     //数据类型uint8_t length;   //数据长度uint8_t addr_byte_length;   //数据域长度1-4uint8_t data_addr[4];   //地址域数据uint32_t addr;          //地址域数据的变量值uint8_t data[MOT_LINE_DATA_MAX_LEN];    //地址域数据uint8_t data_byte_length;        //固件数据的长度 = 数据长度-(地址域数据占用的字节1-4)-(CRC占用的1字节)uint8_t crc;       //CRC}MOT_LINE_FILE_T;   //mot单行文件typedef struct{uint32_t start_addr;  //起始地址uint32_t end_addr;      //结束地址uint32_t program_addr;  //编程地址uint32_t firmware_length;   //固件长度(结束地址-起始地址)uint32_t program_memory_size;   //编程内存大小(结束地址-编程地址)}MOT_FILE_T;    //整个MOT文件的解析

然后就是按行读取文件,然后按行解析文件,将解析出来的固件数据填充到转换后的bin文件,下面展示用C++ QT写的文件解析代码

void MainWindow::on_pushButton_openfile_clicked()
{QString path = "D:/";QString fileName = QFileDialog::getOpenFileName(this,("打开固件文件"),path,tr("mot文件(*.mot)"));ui->lineEdit_file_path->setText(fileName);if(fileName.isEmpty())return;QFile file(fileName);QFileInfo fileinfo(fileName);if(!file.open(QIODevice::ReadOnly )){QMessageBox::warning(this,"error","打开文件失败",QMessageBox::Ok);app_info("打开文件失败");return;}MOT_LINE_FILE_T mot_line_file;  //单行文件的控制变量memset(&mot_file_control,0xff,sizeof(mot_file_control));    //将整个mot文件的控制变量清除为ffuint32_t current_addr = 0;  //从一行数据里面解析出来的地址加上实际地址后的偏移uint32_t new_line_addr_offset = 0;  //最新解析一行的数据的地址跟上一行地址的偏移QByteArray file_line_bytearray; //单行文件的bytearrayuint32_t line_index = 0;        //行号int i = 0;while(!(file_line_bytearray = file.readLine()).isEmpty())       //每次读取一行数据直到文件结束{mot_line_file_prase((uint8_t*)file_line_bytearray.data(),file_line_bytearray.length(),&mot_line_file);   //单行文件解析函数if(mot_line_file.type>=1 && mot_line_file.type<=3)      //只解析S123的{if(mot_file_control.start_addr == 0xffffffff)       //如果mot文件控制变量第一次使用 就记录固件文件的起始地址{mot_file_control.start_addr = mot_line_file.addr;   //起始地址mot_file_control.end_addr = mot_line_file.addr;     //结束地址 结束地址在每行解析后都会重新赋值}current_addr = mot_line_file.addr + mot_line_file.data_byte_length;   //一行文件的起始地址加上数据长度,得到偏移后地址new_line_addr_offset = current_addr-mot_file_control.end_addr;if(new_line_addr_offset == mot_line_file.data_byte_length)  //判断文件是否是连续地址{/* 文件是连续的 直接复制 */for(i=0;i<mot_line_file.data_byte_length;i++){firmware_array.append(mot_line_file.data[i]);}}else{/* 文件不是连续的 在中间追加0xff */for(i=0;i<(new_line_addr_offset-mot_line_file.data_byte_length);i++){firmware_array.append(0xff);}/* 填充固件数据 */for(i=0;i<mot_line_file.data_byte_length;i++){firmware_array.append(mot_line_file.data[i]);}}mot_file_control.end_addr = current_addr;       //记录固件文件的结束地址}}mot_file_control.firmware_length = mot_file_control.end_addr - mot_file_control.start_addr;     //固件的长度=结束地址-起始地址mot_file_control.program_addr = 0x8000; //固件的编程地址 在解析的时候用不到 根据协议拟定mot_file_control.program_memory_size = mot_file_control.end_addr - mot_file_control.program_addr;   //需要编程的固件长度=结束地址-编程地址/* 将bin文件保存 */QFile bin_file(fileinfo.path()+"/conversionQt.bin");bin_file.open(QIODevice::ReadWrite);bin_file.write(firmware_array);bin_file.close();qDebug()<<"写入完成";file.close();}//mot单行文件解析
int MainWindow::mot_line_file_prase(uint8_t *data, uint16_t len, MOT_LINE_FILE_T *t)
{if(data == NULL)return 0;if(t == NULL)return 0;uint8_t data_buffer[256] = {0}; //存储一行数据除了头部两个字符以外转换后的byte数据uint16_t data_len = 0;          //一行数据的byte数组的长度data_len = mot_line_file_check_crc(data,data_buffer,sizeof(data_buffer));    //先校验CRCif(data_len<=0)return 0;int temp = 0;temp = CharToInt(data[1]);   //数据类型if(temp < 0)return -1;t->type = (uint8_t)temp; //数据类型t->length = data_buffer[0];       //单行文件数据类型t->data_byte_length = 0;      //单行文件数据长度/* 根据类型进行解析 */switch (t->type) {case 0:qDebug("头部信息:%s",data);break;case 1:case 2:case 3:{t->addr_byte_length = 1 + t->type; // 数据地址域长度memcpy(t->data_addr,&data_buffer[1],t->addr_byte_length);   //单行文件的数据地址for(int i=0;i<t->addr_byte_length;i++)  //数据地址的数组形式转成uint格式{t->addr <<= 8;t->addr |= t->data_addr[i];}t->data_byte_length = t->length-t->addr_byte_length-1; //单行文件的数据域长度memcpy(t->data,&data_buffer[1+t->addr_byte_length],t->data_byte_length);  //复制固件数据}break;case 7:case 8:case 9:{    //程序运行地址t->addr_byte_length = 11 - t->type; // 数据地址域长度memcpy(t->data_addr,&data_buffer[1],t->addr_byte_length);for(int i=0;i<t->addr_byte_length;i++){t->addr <<= 8;t->addr |= t->data_addr[i];}t->data_byte_length = 0;qDebug("程序运行地址:%08X",t->addr);}break;default:break;}return 0;}

需要注意的是,要按单行解析,校验CRC,解析出固件的 地址 数据等信息,解析后判断固件是否连续,如果不连续,需要在中间空闲的空间增加0XFF的填充,解析后用jflash转换后的bin文件进行比对。

mot文件解析成bin相关推荐

  1. 自定义字体文件解析成人眼可识别文字

    # coding=utf-8 from fontTools.ttLib import TTFont from PIL import Image, ImageDraw, ImageFont #绘制图片 ...

  2. C#窗体应用(二) HEX文件转成BIN文件

    窗体界面 在窗体中加入两个button,三个textbox,OpenFileDialog,SaveFileDialog几个控件.如下图所示. hex文件分析 Intel HEX 文件是由一行行符合In ...

  3. C语言之mot文件解析

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

  4. java 文件解析成JSON数据(其三)

    个人用途,用于将数据解析成json格式使用 import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; ...

  5. 维基百科文件解析成中文遇到的变量类型、编码问题

    2019独角兽企业重金招聘Python工程师标准>>> 为了练习Gensim中文词向量建模,要用到wiki文件做语料库.因为这个文件是xml格式的,需要把它转成文本格式,所以有了下面 ...

  6. 将FPGA MCS 文件转成BIN (HEX or EXO) 文件

    使用TCL命令promgen,如: promgen -p bin -r test.mcs -o mytest.bin

  7. Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析

    转自:http://www.uml.org.cn/mobiledev/201211221.asp 今天,我着重讲解下如下三个内容: measure过程 WRAP_CONTENT.MATCH_PAREN ...

  8. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)

    在之前一篇博文中<< Android中View绘制流程以及invalidate()等相关方法分析>> ,简单的阐述 了 Android View 绘制流程的三个步骤,即: 1. ...

  9. Python3将xml文件解析为Python对象

    一.说明 从最开始写javascript开始,我就很烦感使用getElementById()等函数来获取节点的方法,获取了一个节点要访问其子孙节点要么child半天要么就再来一个getElementB ...

最新文章

  1. python使用matplotlib可视化条形图、使用barh函数可视化条形图(使用barh函数可视化多分类的并行条形图、side by side)
  2. 将选定的文本对象左对齐、右对齐或对中
  3. android 图片 编辑app,图片编辑工具手机版下载-图片编辑工具app下载8.33.107安卓官方版-西西软件下载...
  4. db first和code first
  5. 前端趋势榜:上周最实用和 yyds 的 10 大前端项目 - 211128
  6. css3小球坠落,CSS3 圆球体内的小球碰撞运动
  7. flume linux 命令,flume启动命令 · Mr.Deng’s Blog
  8. (Python)裁剪人脸图片获得人脸的嘴唇区域
  9. 项目经理必须知道什么是PERT网络分析(计划评审技术)
  10. 宿迁卫校计算机多少钱一年,江苏宿迁卫生中等专业学校2021年招生录取分数线...
  11. __gxx_personality_v0详解
  12. 王者荣耀KPL秋季赛总决赛预测(AG VS DYG)
  13. 图解IFRS9 金融工具(7)减值损失披露
  14. 纯净IP地址--跨境人的爱恨情仇
  15. Flink(1.12版本)
  16. 全国考研计算机成绩排名,全国33所计算机考研名校跨考难度系数排名
  17. 创新TX230音箱线控电位器维修记
  18. 用Python爬取彼岸图网图片
  19. 软件签名证书可以做哪些事
  20. 爱奇艺龚宇:从开源节流到冷静增长,将适当加大内容和市场投入

热门文章

  1. 【mybatis的复杂查询】
  2. 三维交互可视化平台(智慧海上牧场平台)学习开发之Vue(一)
  3. 指数法和Random Forest实现山东省丰水期地表水体信息
  4. 顺丰,披着快递马甲的科技公司?
  5. 老罗的获奖感言及经验转载
  6. WebTours示例程序的订票流程-脚本
  7. 公司招聘:33岁以上的和两年一跳的不要,开出工资我还以为看错了...
  8. java法师逃离_本性法师:逃离复杂 奔向简单的人生
  9. 《Java必须知道的300个问题》读书总结
  10. 网络营销专业计算机机房考试,中职网络营销期中考试试卷.doc