mot文件解析成bin

mot固件文件转成bin文件

mot文件介绍

mot s19 bin hex都可以用于固件文件的存储,其中bin文件就是固件原始数据,只记录固件的二进制数据流,mot文件实际上就是Motorola S-records文件,是摩托罗拉公司定义的一种S开头的数据记录文件格式。mot文件不需要记录固件中每一个地址的数据,它可以按照地址和数据来记录固件信息,固件中没有使用的地址将不会记录,这样也使得mot文件相对于bin文件,体积会小很多。jflash是支持各种固件的文件,我们用就flash打开.mot文件,就可以看到真实的固件信息,包括固件的起始地址,真实数据,结束地址等等。
我们可以用文本工具打开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数组长度)
        else
            return -1;  //如果数据长度错误也返回错误
    }
    else
        return -1;



}

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

    #define MOT_LINE_DATA_MAX_LEN   256
    /* MOT文件控制变量 */
    typedef struct{
        uint8_t type;     //数据类型
        uint8_t length;   //数据长度
        uint8_t addr_byte_length;   //数据域长度1-4
        uint8_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文件的控制变量清除为ff
    uint32_t current_addr = 0;  //从一行数据里面解析出来的地址加上实际地址后的偏移
    uint32_t new_line_addr_offset = 0;  //最新解析一行的数据的地址跟上一行地址的偏移
    QByteArray file_line_bytearray; //单行文件的bytearray
    uint32_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));	//先校验CRC
    if(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文件进行比对。

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 将Mot文件转为Bin文件是一种常见的数据文件格式转换过程。Mot文件中包含了一系列的二进制码,而Bin文件是一种二进制文件格式,它包含了计算机系统可直接识别和处理的数据。 为了将Mot文件转为Bin文件,可以使用特定的转换工具。这个工具可以读取Mot文件中的二进制数据,并按照特定的规则将其转换为与计算机系统兼容的Bin文件格式。通常,这个工具提供了用户界面,用户可以选择Mot文件并指定所需的转换选项。转换完后,工具会生一个新的Bin文件。 这个工具支持的Mot文件格式通常是行业标准格式,例如Motorola S记录(S-Records)或Intel HEX格式。这些格式将二进制数据划分为地址、数据和校验和等不同部分,并使用特定的开始和结束标记标识文件的开头和结尾。 在转换过程中,工具会读取Mot文件中的记录,并将其转换为二进制数据。它还会执行一些校验和验证的操作,以确保数据的完整性和准确性。转换完后,生Bin文件可以被其他计算机系统直接载入和处理,用于诸如固件更新、设备编程或数据分析等应用。 总之,将Mot文件转为Bin文件是通过特定的转换工具实现的。这个工具可以读取Mot文件的二进制数据,并将其转换为与计算机系统兼容的Bin文件格式。这种转换使得Mot文件中的数据可以方便地被计算机系统识别和处理。 ### 回答2: mot文件是一种特殊的文件格式,通常用于存储和传输嵌入式系统的程序代码和数据。而bin文件是一种二进制文件,它包含了机器语言代码和数据,用于直接加载到计算机的内存中执行。 要将mot文件转换为bin文件,需要使用特定的工具。以下是一种可能的转换方法: 首先,我们需要一个称为mot2bin的工具,通常可以在嵌入式系统的开发环境中找到。这个工具可以将mot文件转换为bin文件。 运行mot2bin工具时,需要提供输入和输出文件的路径。输入文件路径是mot文件的位置,输出文件路径是要生bin文件的位置。 在执行转换命令后,mot2bin工具会读取mot文件中的内容,并将其解析为适当的二进制格式。然后,将解析后的二进制数据写入到输出文件中,生相应的bin文件。 完转换后,您就可以使用生bin文件。通常,bin文件可以通过串口、网络或存储媒体等方式加载到目标硬件的内存中,然后由处理器执行。 需要注意的是,mot文件bin文件的确切格式可能因开发环境和特定嵌入式系统而异。因此,在进行转换之前,最好查阅相关文档或咨询开发人员,以确保使用正确的工具和参数来执行转换操作。 总而言之,将mot文件转换为bin文件可以通过使用特定的工具来实现,这样可以将嵌入式系统的程序代码和数据从一种文件格式转换为另一种文件格式,以便加载和执行。 ### 回答3: mot文件是一种通常用于嵌入式系统的文件格式,通常用于存储固件、程序或者数据。而bin文件是一种二进制文件,存储了计算机可直接执行的机器码,可以在嵌入式系统中运行。所以,将mot文件转换为bin文件是为了能够将固件或者程序直接加载到嵌入式系统中执行。 要将mot文件转换为bin文件,可以使用一些专门的转换工具。比如,可以使用Motorola S-record格式转换器工具,它可以将mot文件转换为bin文件或其他格式。该工具可以识别mot文件中的S-record记录,并将其转换为二进制机器码。 使用该工具,打开mot文件,选择转换为bin文件的选项,并指定转换后的bin文件的保存路径和文件名。执行转换操作后,工具会将mot文件中的S-record记录转换为机器码,并保存为bin文件。 转换完后,可以将生bin文件加载到嵌入式系统中进行运行。在加载之前,需要确认目标系统与生bin文件的兼容性,以确保程序能够正常运行。 总之,将mot文件转换为bin文件可以通过使用Motorola S-record格式转换器工具或其他类似工具完。这样可以将mot文件中的S-record记录转换为机器码,从而在嵌入式系统中执行。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值