1 Star 0 Fork 1

龙卷风/download_bin_tool

forked from ZX/download_bin_tool 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
mainwindow.cpp 17.28 KB
一键复制 编辑 原始数据 按行查看 历史
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QtSerialPort>
#include <QMessageBox>
#include <QDateTime>
#include <QFileDialog> //打开文件头文件
#include <QStandardPaths> //文件路径
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
init();
/*将信号ackOK与槽函数sendOnceData绑定*/
connect(this, &MainWindow::ackOK, this, &MainWindow::sendOnceData);
}
MainWindow::~MainWindow()
{
delete ui;
}
/*初始化界面*/
void MainWindow::init()
{
setWindowFlags(windowFlags()& ~Qt::WindowMaximizeButtonHint);//禁止窗口最大化
setFixedSize(this->width(), this->height()); //禁止改变窗口大小
ui->startDownloadBtn->setDisabled(true); //初始化是不允许点击下载按钮
ui->downloadingBar->setValue(0); //设置进度条0%
ui->sendSizeEdt->setValidator(new QIntValidator(1, 65535, this)); //限制输入大小,最大64k
ui->sendSizeEdt->setText(QString::number(2048)); //设置一次默认发送1k数据
/*获取有用的串口*/
auto portsInof = QSerialPortInfo::availablePorts();
for(auto & info : portsInof)
{
qInfo()<<info.description()<<info.portName()<<info.systemLocation();
/*将可用端口显示在下拉列表中*/
ui->portSelectCmd->addItem(info.portName(),info.portName());
}
/*获取标准的波特率*/
auto baudRates = QSerialPortInfo::standardBaudRates();
for(auto rate : baudRates)
{
/*将波特率显示在下拉列表中*/
ui->baudRateCmd->addItem(QString::number(rate), rate);
}
/*设置默认波特率*/
ui->baudRateCmd->setCurrentText("9600");
downloadState = DOWNLOAD_INVALID; //初始化下载状态
undownloadByte = 0;
downloadedByte = 0;
QByteArray t;
char tbcc = 0;
t.append("\xC5");
t.append("\x5C");
t.append("\x00");
t.append("\x00");
t.append("\x01");
t.append("\xff");
/*求异或校验位*/
for(int i = 2; i < t.size(); i ++)
{
tbcc ^= t.at(i) & 0xff;
}
// for(int i = 2; i < sendBuf.size(); i++)
// {
// bcc ^= sendBuf.at(i) & 0xff;
// }
t.append(tbcc);
qInfo()<<"0x"<<t.toHex();
if(tbcc != (t.at(t.size() - 1)))
{
qInfo()<<"!=";
}
else
{
qInfo()<<"=";
}
}
/*清空发送信息日志*/
void MainWindow::on_clearSendMsgBtn_released()
{
ui->sendMsgDisEdt->clear();
}
/*清空接收信息日志*/
void MainWindow::on_clearAckBtn_released()
{
ui->receiveAckEdt->clear();
}
/*打开串口按钮*/
void MainWindow::on_openPortBtn_released()
{
/*判断串口是否已打开,如果已打开就关闭串口*/
if(mySerialPort.isOpen())
{
mySerialPort.close();
ui->openPortBtn->setText("打开串口");
QDateTime current_date_time = QDateTime::currentDateTime();//获取系统时间
QString current_time = current_date_time.toString("hh:mm:ss");
ui->sendMsgDisEdt->append(current_time + " : " + mySerialPort.portName() + " already close");
ui->startDownloadBtn->setDisabled(true); //关闭串口禁止下载
undownloadByte = 0;
downloadedByte = 0;
curDownloadDataLen = 0;
return;
}
auto portName = ui->portSelectCmd->currentData().toString(); //获取串口名称
auto baundRate = ui->baudRateCmd->currentData().value<QSerialPort::BaudRate>(); //获取波特率
mySerialPort.setPortName(portName);
mySerialPort.setBaudRate(baundRate);
/*以下标志位采用默认值*/
mySerialPort.setDataBits(QSerialPort::Data8); //数据位
mySerialPort.setFlowControl(QSerialPort::NoFlowControl);//无流控制
mySerialPort.setParity(QSerialPort::NoParity); //校验位
mySerialPort.setStopBits(QSerialPort::OneStop); //停止位
/*打开串口(以读写的方式)*/
if(!mySerialPort.open(QIODevice::ReadWrite))
{
/*/打开失败*/
QDateTime current_date_time = QDateTime::currentDateTime();//获取系统时间
QString current_time = current_date_time.toString("hh:mm:ss");
ui->sendMsgDisEdt->append(current_time + " : " + portName + " open failed," + mySerialPort.errorString());
QMessageBox::warning(this, "warning", portName + " open failed:" + mySerialPort.errorString());
}
else
{
/*打开成功*/
QDateTime current_date_time = QDateTime::currentDateTime();//获取系统时间
QString current_time = current_date_time.toString("hh:mm:ss");
ui->sendMsgDisEdt->append(current_time + " : " + portName + " open success");
ui->openPortBtn->setText("关闭串口");
ui->startDownloadBtn->setDisabled(false); //允许下载
/*关联接收函数*/
connect(&mySerialPort, &QSerialPort::readyRead, this, &MainWindow::onReadyReadCom);
}
}
/*下载按钮*/
void MainWindow::on_startDownloadBtn_released()
{
QDateTime current_date_time = QDateTime::currentDateTime();//获取系统时间
QString current_time = current_date_time.toString("hh:mm:ss");
dataOnceLen = ui->sendSizeEdt->text().toInt();
qInfo()<<"once len"<<dataOnceLen;
ui->hasSendSizeLab->clear();
if((dataOnceLen < 1) || (dataOnceLen > 65536))
{
ui->sendMsgDisEdt->append(current_time + " : 单次发送数据大小有误(0<x<65536)");
QMessageBox::warning(this, "warning", " 单次发送数据大小有误(0<x<65536)");
}
else
{
ui->sendMsgDisEdt->append(current_time + " : start send data, once data len:" + QString::number(dataOnceLen));
send_start_signal();
}
}
/*发送开始数据帧
开始帧:0xC5 0x5C 0x01 0x00 0x00 bcc 0x5C 0xC5
*/
void MainWindow::send_start_signal()
{
QByteArray sendBuf;
char bcc = 0x00;
sendBuf.append("\xC5\x5C");
sendBuf.append(static_cast<char>(1)); //开始帧标志位
sendBuf.append(static_cast<char>(0)); //帧数据长度高字节
sendBuf.append(static_cast<char>(0)); //帧数据长度底字节
for(int i = 2; i < sendBuf.size(); i++)
{
bcc ^= sendBuf.at(i) & 0xff;
}
sendBuf.append(bcc); //校验位
sendBuf.append("\x5C\xC5");
mySerialPort.write(sendBuf); //发送数据
downloadState = DOWNLOAD_START_WAIT_ACK;//发送标志位
}
/*发送结束数据帧
开始帧:0xC5 0x5C 0x01 0x00 0x00 bcc 0x5C 0xC5
*/
void MainWindow::send_end_signal()
{
QByteArray sendBuf;
char bcc = 0x00;
sendBuf.append("\xC5\x5C");
sendBuf.append(static_cast<char>(2)); //结束帧标志位
sendBuf.append(static_cast<char>(0)); //帧数据长度高字节
sendBuf.append(static_cast<char>(0)); //帧数据长度底字节
for(int i = 2; i < sendBuf.size(); i++)
{
bcc ^= sendBuf.at(i) & 0xff;
}
sendBuf.append(bcc); //校验位
sendBuf.append("\x5C\xC5");
mySerialPort.write(sendBuf); //发送数据
}
/*打开文件*/
void MainWindow::on_openFileBtn_released()
{
QSettings setting("./lastopenFile.ini", QSettings::IniFormat);
QString lastPath = setting.value("LastFilePath").toString();
/*默认打开文件的路径为桌面*/
auto openFileName = QFileDialog::getOpenFileName(this, "bin file", lastPath, "bin File(*.bin)");
QDateTime current_date_time = QDateTime::currentDateTime();//获取系统时间
QString current_time = current_date_time.toString("hh:mm:ss");
if(!openFileName.isEmpty())
{
setting.setValue("LastFilePath", openFileName);
QFile file(openFileName);
//以只读的方式打开文件
if(file.open(QIODevice::ReadOnly))
{
ui->openFileEdt->setText(openFileName);
ui->sendMsgDisEdt->append(current_time + " : open file " + openFileName );
ui->sendMsgDisEdt->append(current_time + " : bin file size " + QString::number(file.size()) + "Byte");
ui->dataSizeLab->setText(QString::number(file.size())); //显示文件大小
binDataArray.clear();//先清空上次留下的数据
binDataArray = file.readAll();//读取数据
binDataLen = file.size(); //获取bin文件的大小
undownloadByte = binDataLen;
}
else
{
ui->sendMsgDisEdt->append(current_time + " : open file failed");
ui->startDownloadBtn->setDisabled(true);
}
}
else
{
ui->sendMsgDisEdt->append(current_time + " : open file failed, the file isEmpty");
ui->startDownloadBtn->setDisabled(true);
}
}
/*读取串口发送的数据
err code
0x01:帧头错误
0x02:校验错误
0x04:帧尾错误
0x08:数据长度错误
*/
void MainWindow::onReadyReadCom()
{
QByteArray comData = mySerialPort.readAll();//读取串口中的二进制文件
uint16_t len;
char bcc = 0;
uint8_t err = 0x00;
QDateTime current_date_time = QDateTime::currentDateTime();//获取系统时间
QString current_time = current_date_time.toString("hh:mm:ss");
if(!comData.isEmpty())
{
// qInfo()<<"receive data size "<< comData.size();
// for(int temp = 0; temp < comData.size(); temp++)
// {
// qInfo()<<"0x"<<comData.toHex();
// }
/*判断帧头是否有误*/
if((comData.at(0) & 0xff) != 0xC5)
{
err |=0x01;
}
if((comData.at(1) & 0xff) != 0x5C)
{
err |=0x01;
}
/*读取帧数据长度*/
len = (comData.at(3) & 0xff) * 0xff + (comData.at(4) & 0xff);
// qInfo()<<"receive data len "<< len;
if(len > comData.size())//数据长度大于包的长度,说明解析有误
{
err |=0x08;
}
else
{
/*求异或校验位*/
for(int i = 2; i < 5 + len; i ++)
{
bcc ^= (comData.at(i) & 0xff);
}
if(bcc != (comData.at(5 + len)))// & 0xff
{
err |= 0x02;//校验出错
}
/*判断帧尾是否有误*/
if((comData.at(6 + len) & 0xff) != 0x5C)
{
err |=0x04;
}
if((comData.at(7 + len) & 0xff) != 0xC5)
{
err |=0x04;
}
}
if(err != 0)
{ qInfo()<<"err code: "<< err;
if(err & 0x01)
{
ui->receiveAckEdt->append(current_time + " : 帧头错误!");
}
else if(err & 0x02)
{
ui->receiveAckEdt->append(current_time + " : 校验错误!");
qInfo()<<"接收到 bcc: "<<QString::number(comData.at(5 + len)&0xFF) <<"计算 bcc: "<<QString::number(bcc);
}
else if(err & 0x04)
{
ui->receiveAckEdt->append(current_time + " : 帧尾错误!");
}
else if(err & 0x08)
{
ui->receiveAckEdt->append(current_time + " : 数据包长度错误");
}
else
{
ui->receiveAckEdt->append(current_time + " : 未知错误!err code:" + QString::number(err));
}
return;
}
switch(comData.at(2) & 0xFF)
{
case 0x00://数据ack
if(!(comData.at(5) & 0xFF))
{//数据正确发送,现在发送下一帧
downloadedByte += curDownloadDataLen;
undownloadByte -= curDownloadDataLen;
if(undownloadByte == 0)//下载完成
{
/*发送结束指令*/
send_end_signal();
}
else
{
ui->downloadingBar->setValue((downloadedByte * 100) / binDataLen); //设置进度条
ui->hasSendSizeLab->setText(QString::number(downloadedByte)); //显示已发送大小
emit(ackOK());
}
}
else//校验有误,重新发送当前数据
{
sendErrTimes++;
qInfo()<<"发送的数据有未知错误,现在重新发送";
ui->sendMsgDisEdt->append(QString("发送 地址[ %1 ] to [ %2 ] 的数据出错!现在重新发送").arg(downloadedByte).arg(downloadedByte + curDownloadDataLen - 1));
emit(ackOK());//此处不改变downloadedByte和undownloadByte的值直接重新发送
}
break;
case 0x01://开始信号ack
if(!(comData.at(5) & 0xFF))
{
ui->receiveAckEdt->append(current_time + " : 下位机已准备好,可以开始传输bin");
downloadState = DOWNLOAD_START_ACK;
ui->startDownloadBtn->setDisabled(true);
/*重置一些数据*/
undownloadByte = binDataLen;
downloadedByte = 0;
sendErrTimes = 0;
ui->downloadingBar->setValue((downloadedByte * 100) / binDataLen);
emit(ackOK());
}
else
{
downloadState = DOWNLOAD_INVALID;//下载状态置位无效
if((comData.at(5) & 0xFF) == 0x01)//硬件出错
{
ui->receiveAckEdt->append(current_time + " :开始下载数据(硬件出错)");
}
else if((comData.at(5) & 0xFF) == 0x02)//校验码出错
{
ui->receiveAckEdt->append(current_time + " : 开始下载数据(校验码出错)");
}
else if((comData.at(5) & 0xFF) == 0x03)//数据长度有误
{
ui->receiveAckEdt->append(current_time + " : 开始下载数据(数据长度有误)");
}
else
{
ui->receiveAckEdt->append(current_time + " : 开始下载数据(未知错误)");
}
}
break;
case 0x02: //结束
if(!(comData.at(5) & 0xFF))
{
sendDataFinish();
downloadState = DOWNLOAD_FINISH;
}
break;
case 0xff: //未知错误
qInfo()<<"err code:0XFF ";
sendErrTimes++;
ui->sendMsgDisEdt->append(QString("发送 地址[ %1 ] to [ %2 ] 的数据出错!现在重新发送").arg(downloadedByte).arg(downloadedByte + curDownloadDataLen - 1));
emit(ackOK());//此处不改变downloadedByte和undownloadByte的值直接重新发送
break;
default:
qInfo()<<"err code:default ";
break;
}
}
}
/*发送一次固定大小的数据包*/
void MainWindow::sendOnceData()
{
QByteArray dataBuf, sendBuf;
uint8_t fileSizeHigh = 0,fileSizeLow = 0;
uint8_t bcc = 0x00;
QString showStr;
// qInfo()<<"send once data,size:"<<dataOnceLen<<"(Byte) dowloaded :"<<downloadedByte<<"(Byte) residue:"<<undownloadByte<<"(Byte)";
if(undownloadByte > dataOnceLen)
{
dataBuf = binDataArray.mid(downloadedByte, dataOnceLen);//读取一段数据
curDownloadDataLen = dataOnceLen;
}
else//发送最后一点不足一个数据包大小的数据
{
dataBuf = binDataArray.mid(downloadedByte, dataOnceLen);//读取一段数据
curDownloadDataLen = undownloadByte;
}
sendBuf.clear();
sendBuf.append("\xC5\x5C"); //添加数据头
// sendBuf.append("\x00"); //00表示传输的是数据
sendBuf.append(static_cast<char>(0)); //00表示传输的是数据
fileSizeHigh = curDownloadDataLen / 256;
fileSizeLow = curDownloadDataLen % 256;
sendBuf.append(fileSizeHigh);//添加数据长度
sendBuf.append(fileSizeLow);
sendBuf.append(dataBuf); //要发送的数据
/*求校验位*/
for(int i = 2; i < sendBuf.size(); i++)
{
bcc ^= sendBuf[i];
}
sendBuf.append(bcc); //添加校验位
sendBuf.append("\x5C\xC5"); //添加数据尾
mySerialPort.write(sendBuf);//发送数据
for(int i = 0; i < sendBuf.size(); i++){
showStr.append((QString("%1 ").arg(sendBuf.at(i) & 0xff, 2, 16, QLatin1Char('0')).toUpper()));
}
ui->sendMsgDisEdt->append("---------------------------------------");
ui->sendMsgDisEdt->append(QString("地址[ %1 ] to [ %2 ] 的数据:").arg(downloadedByte).arg(downloadedByte + curDownloadDataLen - 1));
ui->sendMsgDisEdt->append(showStr);
ui->sendMsgDisEdt->append(QString("--- BCC校验码: %1 ---").arg(bcc & 0xff, 2, 16, QLatin1Char('0')).toUpper());
ui->sendMsgDisEdt->append(QString("send [ %1 ] to [ %2 ] Data ...").arg(downloadedByte).arg(downloadedByte + curDownloadDataLen - 1));
downloadState = DOWNLOAD_DATA_WAIT_ACK;
}
/*发送结束*/
void MainWindow::sendDataFinish()
{
QDateTime current_date_time = QDateTime::currentDateTime();//获取系统时间
QString current_time = current_date_time.toString("hh:mm:ss");
ui->startDownloadBtn->setDisabled(false);
ui->downloadingBar->setValue(100);
ui->receiveAckEdt->append(current_time + QString("下载结束,共发送 %1 Byte 错误次数:%2").arg(downloadedByte).arg(sendErrTimes));
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/tornado/download_bin_tool.git
git@gitee.com:tornado/download_bin_tool.git
tornado
download_bin_tool
download_bin_tool
master

搜索帮助