一、简介
在此感谢正点原子官方提供的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,那么只需要点击右上方的小锤子构建即可(不需要运行)
如果没有CLion的话,可以使用终端来构建。首先需要创建一个目录(示例目录为imx_download),然后把项目文件添加进去(一共有三个)
然后在当前目录下打开终端,输入命令,CMake一下,点表示当前目录
cmake .
之后会在当前目录下生成Makefile
然后再输入make命令,编译项目,即可生成程序(左上方带“?”的那个文件)
make
三、程序的使用
1,形式
程序仿照一般工具的使用,通过 -【options】 【parameter】或者 --【options'】 【parameter】的形式来使用
为了方便沿用传统,就把所有代码写到了一个cpp文件,不过这样的代码风格很糟糕,如有需要最好自己分多个文件模块化开发
①在程序运行前需要赋予其权限(1次即可)
chmod 777 ./imx_download
②无参运行
无参运行时如下图所示,这是由于下面代码所决定的,该main函数里有两个参数,一个是argc,另一个是argv。前者表示输入的参数个数,后者表示指向字符串的指针,与参数个数对应。
传入的第一个参数是程序自身的名字,所以参数个数argc为1,第一个字符串argv[0]为程序的名字
③含参运行
通过在选项后面追加参数来执行相应功能,这里是通过Boost库来完成的,之所以使用Boost库而不是进行普通的字符串检查,是为了减少工作量,不过编译出的程序有点大,足足近1MB
如果你想要追加选项,可以仿照下面,括号内的第一个参数分成全称和缩写,比如"help,p",意为可以通过“--help”或“-h”来使用
具体执行“-h”或“--help”的代码在下面,通过count函数来判断有没有选项“help”来执行括号内代码。
使用示例:
④具体烧录过程
我把烧录分为了两种情况,同时添加了进度条和一些容错判断。
其一:指定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卡
这里为了速度,把iflag=dsync和oflag=dsync都给去了,把烧录速度从一百多KB每秒提到了2MB/s以上,下面拿了一个104MB的文件测试了一下速度,可以达到2MB/s以上。如果传输的数据出错了,可以尝试把“iflag=dsync和oflag=dsync”那行注释取消掉
小文件快的时候可以达到11MB/s,并且可以正常使用。如果出现了传输速度达到几百兆每秒,那么就是传输出错了,可以尝试重启虚拟机、插拔U盘或重启电脑
其二:未指定bin文件,指定SD设备
原理同上,只不过少了添加表头信息的步骤。
烧录时指定SD设备但没指定bin文件时,会自动在当前目录下搜寻所有.imx文件并列出来,然后由用户输入指定文件编号进行烧录。如果当前目录只有一个.imx文件,则自动烧录到SD设备上
为了防止烧录错,增加了下面判断,只不过这个只能判断所选块设备是否存在。如果需要的话,可自己设置一个“禁止名单”,当指定的SD卡在名单上时,就停止烧录
四、源代码
共有三个文件:imxdownload.h、imxdownload.cpp和CMakeLists.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()
# 其他配置...