代码——IMX6UL烧录工具及其使用

一、简介

        在此感谢正点原子官方提供的IMX6UL烧录代码,本篇是在正点原子给的代码基础上修改的,增加了些许功能,可根据自己的需求更改。此外代码难免有疏漏之处,还望见谅

 

二、源代码的使用

1,库和工具的安装

        安装库和工具前,记得更新apt

sudo apt-get update
sudo apt-get upgrade

        由于使用的是C++并且使用CMake管理工程,所以需要有g++编译器和cmake。编译器一定是没有前缀的,不需要使用交叉编译器

sudo apt-get install g++
sudo apt-get install cmake

        代码中用到了Boost库,所以也要安装

sudo apt-get install boost

         由于使用到来pv命令,所以也要安装

sudo apt-get install pv

         可能还有一些库忘记说了,可自行根据报错提示查找

 

 2,项目的编译

        如果你使用的是CLion,那么只需要点击右上方的小锤子构建即可(不需要运行)

9bdc41e892d04f93bf3ddc9df1b3188d.png

         如果没有CLion的话,可以使用终端来构建。首先需要创建一个目录(示例目录为imx_download),然后把项目文件添加进去(一共有三个)

b0112e69691e42d996b10825637e7913.png

        然后在当前目录下打开终端,输入命令,CMake一下,点表示当前目录

cmake .

        之后会在当前目录下生成Makefile

fb51a43d9e52492597a83c081f8da5d3.png

         然后再输入make命令,编译项目,即可生成程序(左上方带“?”的那个文件)

make

bfe15a2ed1db4c6abb5c3093a52d77ce.png

 

 

三、程序的使用

1,形式

        程序仿照一般工具的使用,通过 -【options】 【parameter】或者 --【options'】 【parameter】的形式来使用

        为了方便沿用传统,就把所有代码写到了一个cpp文件,不过这样的代码风格很糟糕,如有需要最好自己分多个文件模块化开发

 

①在程序运行前需要赋予其权限(1次即可)

 chmod 777 ./imx_download 

486ef8a28bdf4fa498a67b1a57f3de76.png

 

 ②无参运行

        无参运行时如下图所示,这是由于下面代码所决定的,该main函数里有两个参数,一个是argc,另一个是argv。前者表示输入的参数个数,后者表示指向字符串的指针,与参数个数对应。

        传入的第一个参数是程序自身的名字,所以参数个数argc为1,第一个字符串argv[0]为程序的名字

8f6e07cc69bc464e8070e8413ce36fa1.png

3002db1c08614a5ba995f12d14749e31.png

 

③含参运行

        通过在选项后面追加参数来执行相应功能,这里是通过Boost库来完成的,之所以使用Boost库而不是进行普通的字符串检查,是为了减少工作量,不过编译出的程序有点大,足足近1MB

        如果你想要追加选项,可以仿照下面,括号内的第一个参数分成全称和缩写,比如"help,p",意为可以通过“--help”或“-h”来使用

f4038ae3f98d40228567fe8e2f77a660.png

         具体执行“-h”或“--help”的代码在下面,通过count函数来判断有没有选项“help”来执行括号内代码。

bb60b238721c413b97333dbe96d09ea5.png

        使用示例:

a2536daef55b45ef8e2c5373f83c7f0b.png

 

④具体烧录过程

        我把烧录分为了两种情况,同时添加了进度条和一些容错判断。

其一:指定bin文件,再指定SD设备

        原理很简单,根据bin文件大小,程序会动态创建一个缓冲区,把bin文件拷到缓冲区里面,不过前面空了3KB用于存放IVT DCD表信息。接下来就是根据所选的DDR大小把相应的表存入缓冲区的前面

        然后又创建了一个imx文件,再把缓冲区里的数据写入进去。

        最后通过dd命令把刚才的imx文件烧录到SD设备里,并且是从SD设备的第二个分区开始写入

        详情可自行查看代码,下面以烧录一个uboot为例,由于使用C++新建文件可能需要权限,所以在前面加了sudo。执行烧录SD卡的命令是下面代码,用了pv命令(显示进度条)和dd命令(烧录)。

        dd命令后面的不同参数代表了不同含义,bs=512是设置块大小为 512 字节、seek=2是从输出设备的第 2 个 512 字节块开始写入数据、iflag=dsync和oflag=dsync分别是使用同步 I/O 操作读取和写入数据、conv=fsync是在dd命令完成所有操作后强制将所有缓存的数据写入磁盘等等,同步读取写入是为了保持数据的完整性与一致性。

        至于参数为什么这般设置,这篇博客给了很详细的解释imx6ull - 制作烧录SD卡

e3558c1cdf954a1d952d0498a57191b4.png

09b5e9a8a7c34e0db26d04b4bd79f3a4.png

        这里为了速度,把iflag=dsync和oflag=dsync都给去了,把烧录速度从一百多KB每秒提到了2MB/s以上,下面拿了一个104MB的文件测试了一下速度,可以达到2MB/s以上。如果传输的数据出错了,可以尝试把“iflag=dsync和oflag=dsync”那行注释取消掉

0eebe073d8b340cf9da2bf2cfe824032.png

         小文件快的时候可以达到11MB/s,并且可以正常使用。如果出现了传输速度达到几百兆每秒,那么就是传输出错了,可以尝试重启虚拟机、插拔U盘或重启电脑32cf7d6169554fe1a3fd9fd706b35fbd.png

 

其二:未指定bin文件,指定SD设备

        原理同上,只不过少了添加表头信息的步骤。

        烧录时指定SD设备但没指定bin文件时,会自动在当前目录下搜寻所有.imx文件并列出来,然后由用户输入指定文件编号进行烧录。如果当前目录只有一个.imx文件,则自动烧录到SD设备上

effd67f764f147c3abc9cc291b0a3f95.png

        为了防止烧录错,增加了下面判断,只不过这个只能判断所选块设备是否存在。如果需要的话,可自己设置一个“禁止名单”,当指定的SD卡在名单上时,就停止烧录

1643612a89fd4621b052a2fc88e9c307.png

 

 

四、源代码

        共有三个文件:imxdownload.himxdownload.cppCMakeLists.txt

1,imxdownload.h

#ifndef _IMXDOWNLOAD_H
#define _IMXDOWNLOAD_H
/* IMX6U IVT DCD表信息  暂时定义为1K Bytes,此表是读取的u-boot.imx前1K Bytes
 * imx6_ivedcd_table[9]是指明代码长度的,本应该根据实际的代码长度来修改
 * 这里为了方便,就直接定义为2M Bytes,即
 */

const unsigned int imx6_512mb_ivtdcd_table[256] = {
0X402000D1,0X87800000,0X00000000,0X877FF42C,0X877FF420,0X877FF400,0X00000000,0X00000000,
0X877FF000,0X00200000,0X00000000,0X40E801D2,0X04E401CC,0X68400C02,0XFFFFFFFF,0X6C400C02,
0XFFFFFFFF,0X70400C02,0XFFFFFFFF,0X74400C02,0XFFFFFFFF,0X78400C02,0XFFFFFFFF,0X7C400C02,
0XFFFFFFFF,0X80400C02,0XFFFFFFFF,0XB4040E02,0X00000C00,0XAC040E02,0X00000000,0X7C020E02,
0X30000000,0X50020E02,0X30000000,0X4C020E02,0X30000000,0X90040E02,0X30000000,0X88020E02,
0X30000C00,0X70020E02,0X00000000,0X60020E02,0X30000000,0X64020E02,0X30000000,0XA0040E02,
0X30000000,0X94040E02,0X00000200,0X80020E02,0X30000000,0X84020E02,0X30000000,0XB0040E02,
0X00000200,0X98040E02,0X30000000,0XA4040E02,0X30000000,0X44020E02,0X30000000,0X48020E02,
0X30000000,0X1C001B02,0X00800000,0X00081B02,0X030039A1,0X0C081B02,0X0B000300,0X3C081B02,
0X44014801,0X48081B02,0X302C4040,0X50081B02,0X343E4040,0X1C081B02,0X33333333,0X20081B02,
0X33333333,0X2C081B02,0X333333F3,0X30081B02,0X333333F3,0XC0081B02,0X09409400,0XB8081B02,
0X00080000,0X04001B02,0X2D000200,0X08001B02,0X3030331B,0X0C001B02,0XF3526B67,0X10001B02,
0X630B6DB6,0X14001B02,0XDB00FF01,0X18001B02,0X40172000,0X1C001B02,0X00800000,0X2C001B02,
0XD2260000,0X30001B02,0X23106B00,0X40001B02,0X4F000000,0X00001B02,0X00001884,0X90081B02,
0X00004000,0X1C001B02,0X32800002,0X1C001B02,0X33800000,0X1C001B02,0X31800400,0X1C001B02,
0X30802015,0X1C001B02,0X40800004,0X20001B02,0X00080000,0X18081B02,0X27020000,0X04001B02,
0X2D550200,0X04041B02,0X06100100,0X1C001B02,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000
};

const unsigned int imx6_256mb_ivtdcd_table[256] = {
0X402000D1,0X87800000,0X00000000,0X877FF42C,0X877FF420,0X877FF400,0X00000000,0X00000000,
0X877FF000,0X00076000,0X00000000,0X40E801D2,0X04E401CC,0X68400C02,0XFFFFFFFF,0X6C400C02,
0XFFFFFFFF,0X70400C02,0XFFFFFFFF,0X74400C02,0XFFFFFFFF,0X78400C02,0XFFFFFFFF,0X7C400C02,
0XFFFFFFFF,0X80400C02,0XFFFFFFFF,0XB4040E02,0X00000C00,0XAC040E02,0X00000000,0X7C020E02,
0X30000000,0X50020E02,0X30000000,0X4C020E02,0X30000000,0X90040E02,0X30000000,0X88020E02,
0X30000C00,0X70020E02,0X00000000,0X60020E02,0X30000000,0X64020E02,0X30000000,0XA0040E02,
0X30000000,0X94040E02,0X00000200,0X80020E02,0X30000000,0X84020E02,0X30000000,0XB0040E02,
0X00000200,0X98040E02,0X30000000,0XA4040E02,0X30000000,0X44020E02,0X30000000,0X48020E02,
0X30000000,0X1C001B02,0X00800000,0X00081B02,0X030039A1,0X0C081B02,0X04000000,0X3C081B02,
0X3C013C01,0X48081B02,0X38324040,0X50081B02,0X28304040,0X1C081B02,0X33333333,0X20081B02,
0X33333333,0X2C081B02,0X333333F3,0X30081B02,0X333333F3,0XC0081B02,0X09409400,0XB8081B02,
0X00080000,0X04001B02,0X2D000200,0X08001B02,0X3030331B,0X0C001B02,0XF352433F,0X10001B02,
0X630B6DB6,0X14001B02,0XDB00FF01,0X18001B02,0X40172000,0X1C001B02,0X00800000,0X2C001B02,
0XD2260000,0X30001B02,0X23104300,0X40001B02,0X47000000,0X00001B02,0X00001883,0X90081B02,
0X00004000,0X1C001B02,0X32800002,0X1C001B02,0X33800000,0X1C001B02,0X31800400,0X1C001B02,
0X30802015,0X1C001B02,0X40800004,0X20001B02,0X00080000,0X18081B02,0X27020000,0X04001B02,
0X2D550200,0X04041B02,0X06100100,0X1C001B02,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
};

#endif

 

2,imxdownload.cpp

// 可以自行决定用C++还是Linux命令来完成数据流的复制
// 如果选择后者,那么需要安装pv,命令为:sudo apt-get install pv

#include "imxdownload.h"
#include <boost/program_options.hpp>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <memory>
#include <regex>
#include <string>

#define BIN_OFFSET (3072)

#define DDR_512MB 0
#define DDR_256MB 1

// 0: 默认使用C++进行数据流的传输 1: 使用Linux命令行进行数据流的传输
// 不过目前C++方式还不能使用,只有后者可以
#define DOWNLOAD_MODE 1

namespace po = boost::program_options;
namespace fs = std::filesystem;// 使用文件系统命名空间

bool isBinFile(const std::string &filename)
{
    return filename.substr(filename.find_last_of('.') + 1) == "bin";
}


// 显示进度条
void showProgress(double progress, int totalLength = 50)
{
    int pos = static_cast<int>(progress * totalLength);
    std::cout << "\r[" << std::string(pos, '=') << std::string(totalLength - pos, ' ') << "] "
              << std::fixed << std::setprecision(2) << (progress * 100) << "%";
    std::cout.flush();
}


int main(int argc, char *argv[])
{
    std::cout << "I.MX6ULL烧写工具(源于正点原子)\r\n\n";

    // clang-format off
    po::options_description desc("允许的选项");
    desc.add_options()
        ("help,h", "显示帮助信息")
        ("verbose,v", "显示详细信息")
        ("print,p", "打印IVT DCD表信息")
        ("name,n", po::value<std::string>()->default_value("load"), "指定生成文件的名称")
        ("ddr-size,d", po::value<int>()->default_value(-1),
         "设置 DDR 大小 (512m or 256m)")
        ("source-bin,b", po::value<std::string>(), "指定源二进制文件")
        ("sd-device,s", po::value<std::string>(), "指定 SD 设备");
    // clang-format on

    po::variables_map vm;
    try
    {
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);
    }
    catch (const std::exception &e)
    {
        std::cerr << "错误: " << e.what() << std::endl;
        std::cout << desc << "\n";// 显示帮助信息
        return -1;
    }

    // 参数为空时
    if (argc == 1)
    {
        std::cout << "更新时间:2024-9-19 04:04\n";
    }

    bool verbose = vm.count("verbose") > 0;
    if (verbose)
    {
        std::cout << "该程序通过参数进行操作,详情请输入-h或者--help\n";
        std::cout << "1: 不指定SD卡设备时,不会进行烧录\n";
        std::cout << "2: 不指定bin文件时会自动搜寻当前目录下的唯一imx文件\n";
        std::cout << "3: 可以自定义生成文件名称\n";
    }

    if (vm.count("help"))
    {
        std::cout << desc << "\n";// 显示所有选项
    }

    int ddrSize = vm["ddr-size"].as<int>();
    std::string sourceFileName;
    std::string sdDevice;
    std::string outputFileName = vm["name"].as<std::string>() + ".imx";

    // 若未指定SD设备,则不进行烧录;
    // 若指定SD设备未指定二进制文件,则会在当前目录中寻找唯一的一个*.imx
    bool sourceBinSpecified = vm.count("source-bin");
    bool sdDeviceSpecified = vm.count("sd-device");
    bool isImxFileSpecified = false;// 是否找到了唯一的imx文件

    if (sourceBinSpecified)
    {
        sourceFileName = vm["source-bin"].as<std::string>();
        std::cout << "指定二进制文件: " << sourceFileName << std::endl;

        // 检查文件扩展名是否为 .bin
        if (!isBinFile(sourceFileName))
        {
            std::cout << "警告: 指定的文件不是 .bin 文件。是否继续使用此文件? (y/n): ";
            char response;
            std::cin >> response;
            if (response != 'y' && response != 'Y')
            {
                std::cerr << "取消操作。" << std::endl;
                return -1;
            }
        }

        if (!sdDeviceSpecified)
        {
            std::cout << "由于未指定SD卡设备,将不进行烧录" << std::endl;
        }
    }
    else if (sdDeviceSpecified)
    {
        // 查找当前目录下所有的 .imx 文件
        std::vector<std::string> imxFiles;
        for (const auto &entry: fs::directory_iterator("."))
        {
            if (entry.path().extension() == ".imx")
            {
                imxFiles.push_back(entry.path().string());
            }
        }

        if (imxFiles.empty())
        {
            std::cerr << "找不到任何 .imx 文件,请指定 --source-bin 参数" << std::endl;
            std::cout << "详情请输入 --help 或 -h 进行查看" << "\n";
            return -1;
        }
        else if (imxFiles.size() > 1)
        {
            std::cout << "找到多个 .imx 文件,请选择一个:" << std::endl;
            for (size_t i = 0; i < imxFiles.size(); ++i)
            {
                imxFiles[i] = imxFiles[i].substr(2);// 去掉 ./
                std::cout << i + 1 << ": " << imxFiles[i] << std::endl;
            }

            int choice;
            std::cout << "请输入文件编号: ";
            std::cin >> choice;

            if (choice < 1 || choice > static_cast<int>(imxFiles.size()))
            {
                std::cerr << "无效的选择,请重新运行程序并正确选择文件。" << std::endl;
                return -1;
            }

            isImxFileSpecified = true;
            outputFileName = imxFiles[choice - 1];
            sourceFileName = outputFileName;
            std::cout << "选择了文件: " << outputFileName << std::endl;
        }
        else
        {
            isImxFileSpecified = true;
            outputFileName = imxFiles[0].substr(2);// 去掉 ./
            sourceFileName = outputFileName;
            std::cout << "找到唯一的imx 文件: " << outputFileName << std::endl;
        }
    }

    // 检查SD卡设备
    if (sdDeviceSpecified)
    {
        sdDevice = vm["sd-device"].as<std::string>();

        // 检查设备是否符合 /dev/sd* 的格式
        std::regex sdRegex("^/dev/sd[a-z]+$");
        if (!std::regex_match(sdDevice, sdRegex))
        {
            std::cout << "警告: " << sdDevice << " 指定SD设备可能未挂载到/dev上。是否继续? (y/n): ";
            std::cout << "当前SD设备有:" << std::endl;
            system("ls /dev/sd*");
            char response;
            std::cin >> response;
            if (response != 'y' && response != 'Y')
            {
                std::cerr << "取消操作。" << std::endl;
                return -1;
            }
        }

        // 检查SD设备是否存在
        FILE *pipe = popen(("ls /dev/ | grep -w " + sdDevice.substr(5)).c_str(), "r");
        if (pipe == nullptr)
        {
            std::cerr << "无法执行ls命令来检查设备 " << sdDevice << "。" << std::endl;
            return -1;
        }

        std::cout << "当前SD设备有:" << std::endl;
        system("ls /dev/sd*");

        char buffer[256];
        if (fgets(buffer, 255, pipe) == nullptr)
        {
            pclose(pipe);
            std::cout << "警告: " << sdDevice << " 不存在。" << std::endl;
            std::cout << "是否继续? (y/n): ";
            char response;
            std::cin >> response;
            if (response != 'y' && response != 'Y')
            {
                std::cerr << "取消操作。" << std::endl;
                return -1;
            }
        }
        pclose(pipe);
    }
    else
    {
        // 未指定则不进行后续操作
        return 0;
    }

    if (ddrSize == -1)
    {
        std::cout << "DDR 大小未指定,默认使用 512MB"
                  << std::endl;
        ddrSize = DDR_512MB;
    }

    /**
     * 若指定bin文件,则将其转为imx文件
     */
    long fileLen;
    long outputFileSize;
    std::ifstream sourceFile(sourceFileName, std::ios::binary);
    /* 打开bin文件 */
    if (!sourceFile.is_open())
    {
        std::cerr << "无法打开文件 " << sourceFileName
                  << std::endl;
        return -1;
    }

    /* 获取资源文件长度 */
    sourceFile.seekg(0, std::ios::end);
    fileLen = static_cast<int>(sourceFile.tellg());
    sourceFile.seekg(0, std::ios::beg);
    std::cout << "文件 " << sourceFileName
              << " 大小 = " << fileLen << " 字节";
    if (!isImxFileSpecified)
    {
        std::cout << " 烧录镜像总大小 = " << fileLen + BIN_OFFSET << " 字节"
                  << std::endl;

        /* 读取bin文件到缓冲区buf中 */
        outputFileSize = fileLen + BIN_OFFSET;
    }
    else
    {
        std::cout << " 烧录镜像总大小 = " << fileLen << " 字节"
                  << std::endl;

        /* 读取bin文件到缓冲区buf中 */
        outputFileSize = fileLen;
    }

    // 创建一个buf缓冲区,用于存储生成的imx文件
    std::unique_ptr<unsigned char[]> buf(new unsigned char[outputFileSize]);
    if (buf == nullptr)
    {
        std::cerr << "内存分配失败!" << std::endl;
        return -1;
    }
    memset(buf.get(), 0, outputFileSize); /* 清零 */

    /* 读取bin文件到缓冲区buf中 */
    if (!isImxFileSpecified)
    {
        /* 读取bin源码文件 */
        // 将bin文件读入buf中,且偏移buf起始地址BIN_OFFSET
        sourceFile.read(reinterpret_cast<char *>(buf.get() + BIN_OFFSET), fileLen);
    }
    else// 直接将imx文件直接拷贝到buf中
    {
        sourceFile.read(reinterpret_cast<char *>(buf.get()), fileLen);
    }
    sourceFile.close();


    // 打印IVT DCD表
    if (vm.count("print"))
    {
        std::cout << "IVT DCD Table:" << std::endl;
        for (int i = 0; i < 1024 / 32; i++)
        {
            for (int j = 0; j < 8; j++)
            {
                std::cout << "0X" << std::hex
                          << *(int *) (buf.get() + BIN_OFFSET + (((i * 8) + j) * 4))
                          << ",";
            }
            std::cout << std::endl;
        }
        return 0;
    }


    /* 添加IVT DCD等表信息到bin文件里面 */
    if (!isImxFileSpecified)
    {
        switch (ddrSize)
        {
            default:
                std::cout << "内存参数输入错误!将默认为512MB"
                          << std::endl;
                ddrSize = DDR_512MB;
            case DDR_256MB:
                std::cout << "Board DDR SIZE: 256MB"
                          << std::endl;
                // 假设 imx6_256mb_ivtdcd_table 已定义
                memcpy(buf.get(), imx6_256mb_ivtdcd_table, sizeof(imx6_256mb_ivtdcd_table));
                break;

            case DDR_512MB:
                std::cout << "Board DDR SIZE: 512MB"
                          << std::endl;
                // 假设 imx6_512mb_ivtdcd_table 已定义
                memcpy(buf.get(), imx6_512mb_ivtdcd_table, sizeof(imx6_512mb_ivtdcd_table));
                break;
        }
        /* 现在我们已经在buf中构建好了可以用于下载的bin文件,将buf中的数据保存到
        * 到一个文件中,文件默认命名为load.imx
        */
        std::cout << "准备创建 " << outputFileName << " 文件..." << std::endl;

        std::ofstream outputFile(outputFileName, std::ios::binary);
        if (!outputFile.is_open())
        {
            std::cerr << "打开 " << outputFileName << " 失败!" << std::endl;
            std::cout << "可能是权限不够,尝试用sudo命令来执行本程序\r\n";
            return -1;
        }
        /* 把缓冲区数据写入imx文件中 */
        outputFile.write(reinterpret_cast<const char *>(buf.get()), outputFileSize);
        if (!outputFile)
        {
            std::cerr << "文件写入错误!" << std::endl;
            return -1;
        }
        outputFile.close();
    }


    // 再次判定,防止后续开发中遗忘了检测
    // 只有当用户指定了 `-s` 参数时才执行烧录
#if !DOWNLOAD_MODE
    if (vm.count("sd-device"))
    {
        std::cout << "开始烧录 load.imx 到 " << sdDevice << " ..." << std::endl;

        /* 使用C++方式模拟dd命令行为 */
        std::ifstream inFile(outputFileName, std::ios::binary);
        if (!inFile.is_open())
        {
            std::cerr << "打开 load.imx 失败!" << std::endl;
            std::cout << "可能是权限不够,尝试用sudo命令来执行本程序\r\n";
            return -1;
        }

        std::ofstream outDevice(sdDevice, std::ios::binary | std::ios::out);
        if (!outDevice.is_open())
        {
            std::cerr << "打开设备 " << sdDevice << " 失败!C++模式下需要您有正确的权限并且设备可用。" << std::endl
                      << "参考命令为sudo ./imxdownload -[options] [parameter]" << std::endl;

            inFile.close();
            return -1;
        }

        const int bufferSize = 512;// 模拟512字节的块大小
        unsigned char buffer[bufferSize];
        long totalBytesRead = 0;
        long totalBytesToRead = fileLen + BIN_OFFSET;

        while (inFile.read(reinterpret_cast<char *>(buffer), bufferSize))
        {
            long bytesRead = inFile.gcount();
            totalBytesRead += bytesRead;
            outDevice.write(reinterpret_cast<const char *>(buffer), bytesRead);

            double progress = static_cast<double>(totalBytesRead) / totalBytesToRead;
            showProgress(progress);// 显示进度条
        }

        if (inFile.eof())
        {
            std::cout << std::endl
                      << "烧录完成。" << std::endl;
        }
        else
        {
            std::cerr << "读取文件时发生错误。" << std::endl;
            std::cout << "可能是权限不够,尝试用sudo命令来执行本程序\r\n";
            std::cout<<"例如:sudo ./imx_download -s /dev/sdx\r\n";
        }

        inFile.close();
        outDevice.close();
    }
#else
    if (vm.count("sd-device"))
    {
        /* 构建烧写的shell命令 */
        std::string cmd = "pv " + outputFileName + " | sudo dd of=" + sdDevice;// pv前面也加sudo,那么进度条就不会显示了
//        cmd+=" iflag=dsync oflag=dsync";  // 如果数据在传输中出现问题,请尝试取消本行注释,不过传输速度会下降至一百多kb每秒
        cmd += " bs=512 seek=2  conv=fsync && sync";

        std::cout << "\n开始烧录 " << outputFileName << " 到 " << sdDevice
                  << " ..." << std::endl;

        /* 执行上面的shell命令,并捕获输出 */
        int result = system((cmd + " 2>&1").c_str());// 将错误输出也重定向到标准输出

        if (result == 0)
        {
            std::cout << "烧录成功" << std::endl;
        }
        else
        {
            std::cerr << "烧录失败,返回值: " << result << std::endl;
//            std::cout << "可能是权限不够,尝试用sudo命令来执行本程序\r\n";
//            std::cout<<"例如:sudo ./imx_download -s /dev/sdx\r\n";
        }
    }

#endif
    return 0;
}

 

3,CMakeLists.txt

        注意CMake版本,这里设置的最低版本是3.28,根据自己需要设置

#cmake_minimum_required(VERSION 3.29)
#project(imxdownload)
#
## 查找 Boost 库
#find_package(Boost REQUIRED program_options)
#
#set(CMAKE_CXX_STANDARD 20)
#
#add_executable(imx_download imxdownload.h imxdownload.cpp)
#target_link_libraries(${PROJECT_NAME} PRIVATE ${Boost_LIBRARIES})

cmake_minimum_required(VERSION 3.28)
project(imx_download VERSION 1.0)

# 查找 Boost 库
find_package(Boost REQUIRED program_options)

# 设置源文件
set(SOURCE_FILES
        imxdownload.cpp
)

# 添加可执行文件,并链接 Boost 库
add_executable(${PROJECT_NAME} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} PRIVATE ${Boost_LIBRARIES})

# 设置编译标志
#if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
#    target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
#endif()

# 其他配置...

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值