first_version

This commit is contained in:
Hr_adore_me 2024-06-17 13:30:41 +08:00
commit 5d577cb2a3
33 changed files with 9340 additions and 0 deletions

BIN
._thread.h Normal file

Binary file not shown.

236
camera.cpp Normal file
View File

@ -0,0 +1,236 @@
#include "camera.h"
#define FIRST_DEVICE_INDEX 1
//#define SETTING_PATH "C:/Program Files/Teledyne DALSA/Sapera/CamFiles/User/202298_first.ccf"
#define SETTING_PATH "C:/Program Files/Teledyne DALSA/Sapera/CamFiles/User/abc.ccf"
extern void onImageDataCallback(SapXferCallbackInfo *pInfo);
extern void onImageCorrectCallback(SapXferCallbackInfo *pInfo);
camera::camera()
{
}
bool camera::enumDevic(char *serverName)
{
int devicecount = SapManager::GetServerCount();
if(devicecount < 1)
{
qDebug() << "no device found";
return false;
}
SapManager::GetServerName(FIRST_DEVICE_INDEX, serverName, CORSERVER_MAX_STRLEN);
qDebug() << serverName;
return true;
}
bool camera::creatObjects(char *serverName)
{
m_loc = new SapLocation(serverName, 1);
m_pAcq = new SapAcquisition(*m_loc, SETTING_PATH);
m_buffer = new SapBuffer(1, m_pAcq);
// m_trans = new SapAcqToBuf(m_pAcq, m_buffer, onImageDataCallback, NULL);
if(false == m_pAcq->Create())
{
destroyObjects();
qDebug() << "create pAcq device failed";
return false;
}
if(false == m_buffer->Create())
{
destroyObjects();
qDebug() << "create buff failed";
return false;
}
// if(false == m_trans->Create())
// {
// destroyObjects();
// qDebug() << "create transport failed";
// return false;
// }
qDebug() << "create object success";
return true;
}
void camera::destroyObjects()
{
if(m_trans && *m_trans)
{
m_trans->Destroy();
qDebug() << "1";
}
if(c_trans && *c_trans)
{
c_trans->Destroy();
qDebug() << "2";
}
if(m_buffer && *m_buffer)
{
m_buffer->Destroy();
qDebug() << "3";
}
if(m_pAcq && *m_pAcq)
{
m_pAcq->Destroy();
qDebug() << "4";
}
}
bool camera::openCamera()
{
char serverName[CORSERVER_MAX_STRLEN];
if(!enumDevic(serverName))
{
qDebug() << "enum device failed";
return false;
}
if(!creatObjects(serverName))
return false;
qDebug() << "open device success";
return true;
}
void camera::closeCamera()
{
destroyObjects();
if(m_trans)
{
delete m_trans;
qDebug() << "5";
}
if(c_trans)
{
delete c_trans;
qDebug() << "6";
}
if(m_buffer)
{
delete m_buffer;
qDebug() << "7";
}
if(m_pAcq)
{
delete m_pAcq;
qDebug() << "8";
}
}
bool camera::startCapture()
{
bool success;
m_trans = new SapAcqToBuf(m_pAcq, m_buffer, onImageDataCallback, NULL);
if(false == m_trans->Create())
{
destroyObjects();
if(m_trans && *m_trans)
{
m_trans->Destroy();
}
qDebug() << "create transport failed";
return false;
}
success = m_trans->Grab();
if(success == false)
{
qDebug() << "grab failed";
return false;
}
return true;
}
bool camera::stopCapture()
{
bool success;
success = m_trans->Freeze();
if(success == false)
{
qDebug() << "stop capture failed";
return false;
}
m_trans->Wait(5000);
if(m_trans && *m_trans)
{
m_trans->Destroy();
}
return true;
}
bool camera::startCorrect()
{
bool success;
qDebug() << "start correct";
c_trans = new SapAcqToBuf(m_pAcq, m_buffer, onImageCorrectCallback, NULL);
if(false == c_trans->Create())
{
destroyObjects();
if(c_trans && *c_trans)
{
c_trans->Destroy();
}
qDebug() << "create c_transport failed";
return false;
}
qDebug() << "create c_trans";
success = c_trans->Grab();
if(success == false)
{
qDebug() << "start correct failed";
return false;
}
qDebug() << "c_trans grab";
return true;
}
bool camera::stopCorrect()
{
bool success;
success = c_trans->Freeze();
if(success == false)
{
qDebug() << "stop correct failed";
return false;
}
c_trans->Wait(5000);
if(c_trans && *c_trans)
{
c_trans->Destroy();
}
return true;
}
//没用
bool camera::interTricapture()
{
m_pAcq->SetParameter(CORACQ_PRM_INT_LINE_TRIGGER_FREQ, 8, TRUE);//内触发信号频率
m_pAcq->SetParameter(CORACQ_PRM_INT_LINE_TRIGGER_ENABLE, TRUE, TRUE);//内触发
bool success;
success = m_trans->Grab();
if(success == false)
{
qDebug() << "inter trigger capture failed";
return false;
}
m_trans->Wait(5000);
return true;
}

48
camera.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef CAMERA_H
#define CAMERA_H
#include <QDebug>
#include "SapClassBasic.h"
#include <opencv2/opencv.hpp>
#include "thread.h"
class camera
{
public:
camera();
bool enumDevic(char* serverName);
bool creatObjects(char* serverName);
void destroyObjects();
bool openCamera();
void closeCamera();
bool startCapture();
bool stopCapture();
bool interTricapture();
bool startCorrect();
bool stopCorrect();
bool capture_black_flag = false;
bool capture_white_flag = false;
bool ret_SCaptrue = false;
bool ret_SCorrect = false;
cv::Mat white_mat;
cv::Mat black_mat;
cv::Mat eps;
SapTransfer *c_trans;
float* white_buf = nullptr;
float* black_buf = nullptr;
SapLocation *m_loc;
SapAcquisition *m_pAcq;
SapBuffer *m_buffer;
SapTransfer *m_trans;
SapTransfer *l_trans;
std::queue<cv::Mat> imgqueue;
cv::Mat calibrated_img;
int rgb_height;
private:
};
#endif // CAMERA_H

49
correct.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "correct.h"
correct::correct()
{
is_corrected = false;
correction_ratio_r = 1;
correction_ratio_g = 1;
correction_ratio_b = 1;
}
void correct::get_rgb(cv::Mat img)
{
int b_temp = 0;
int g_temp = 0;
int r_temp = 0;
for(int i=0; i<img.rows; i++)
{
for(int j=0; j<img.cols; j++)
{
b_temp += (int)img.at<cv::Vec3b>(i, j)[0];
g_temp += (int)img.at<cv::Vec3b>(i, j)[1];
r_temp += (int)img.at<cv::Vec3b>(i, j)[2];
}
}
b = b_temp / (img.cols * img.rows);
g = g_temp / (img.cols * img.rows);
r = r_temp / (img.cols * img.rows);
}
void correct::cal_correction_ratio()
{
correction_ratio_b = b / b_base;
correction_ratio_g = g / g_base;
correction_ratio_r = r / r_base;
qDebug() << "correction ratio" << correction_ratio_b << correction_ratio_g << correction_ratio_r;
}
void correct::correct_img(cv::Mat img)
{
for(int i=0; i<img.cols; i++)
{
for(int j=0; j<img.rows; j++)
{
(img.at<cv::Vec3b>(j, i)[0] * correction_ratio_b) > 255 ? img.at<cv::Vec3b>(j, i)[0] = 255 : img.at<cv::Vec3b>(j, i)[0] *= correction_ratio_b;
(img.at<cv::Vec3b>(j, i)[1] * correction_ratio_b) > 255 ? img.at<cv::Vec3b>(j, i)[1] = 255 : img.at<cv::Vec3b>(j, i)[1] *= correction_ratio_b;
(img.at<cv::Vec3b>(j, i)[2] * correction_ratio_b) > 255 ? img.at<cv::Vec3b>(j, i)[2] = 255 : img.at<cv::Vec3b>(j, i)[2] *= correction_ratio_b;
}
}
}

29
correct.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef CORRECT_H
#define CORRECT_H
#include "opencv2/opencv.hpp"
#include <QDebug>
class correct
{
private:
float correction_ratio;
float r;
float g;
float b;
float correction_ratio_r;
float correction_ratio_g;
float correction_ratio_b;
int b_base = 125.0f;
int g_base = 125.0f;
int r_base = 125.0f;
public:
correct();
bool is_corrected;
void get_rgb(cv::Mat img);
void cal_correction_ratio();
void correct_img(cv::Mat img);
};
#endif // CORRECT_H

30
imagewin.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "imagewin.h"
#include "ui_imagewin.h"
# pragma execution_character_set("utf-8")
imageWin::imageWin(ListWidgetItemChild *item, QRect rect, QWidget *parent) :
QWidget(parent),
ui(new Ui::imageWin)
{
ui->setupUi(this);
qApp->installEventFilter(this);
this->setGeometry(rect);//设置显示图片窗口的x、y、w、h
this->setFixedSize(rect.width(), rect.height());//设置窗口固定大小
this->setWindowIcon(item->icon());
this->setWindowTitle("查看图片");
this->setWindowModality(Qt::ApplicationModal);//阻塞除当前窗体外的其他所有窗体
//通过QLabel加载item上的图片
QLabel *lab = new QLabel(this);
lab->setFixedSize(this->width(), this->height());
lab->setPixmap(item->icon().pixmap(QSize(this->width(), this->height())).scaled(lab->width(),lab->height()));
}
imageWin::~imageWin()
{
delete ui;
}

26
imagewin.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef IMAGEWIN_H
#define IMAGEWIN_H
#include <QWidget>
#include <QListWidget>
#include <QRect>
#include <QLabel>
#include "relistwidget_item.h"
namespace Ui {
class imageWin;
}
class imageWin : public QWidget
{
Q_OBJECT
public:
explicit imageWin(ListWidgetItemChild *item, QRect rect, QWidget *parent = 0);
~imageWin();
private:
Ui::imageWin *ui;
};
#endif // IMAGEWIN_H

21
imagewin.ui Normal file
View File

@ -0,0 +1,21 @@
<ui version="4.0">
<author/>
<comment/>
<exportmacro/>
<class>imageWin</class>
<widget class="QWidget" name="imageWin">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
</widget>
<pixmapfunction/>
<connections/>
</ui>

11
main.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

23
relistwidget_item.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "relistwidget_item.h"
ListWidgetItemChild::ListWidgetItemChild(QListWidget *parent) :
QListWidgetItem(parent)
{
}
ListWidgetItemChild::~ListWidgetItemChild()
{
}
ListWidgetRe::ListWidgetRe(QWidget *parent) :
QListWidget(parent)
{
}
ListWidgetRe::~ListWidgetRe()
{
}

42
relistwidget_item.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef RELISTWIDGET_ITEM_H
#define RELISTWIDGET_ITEM_H
#include <QListView>
#include <QListWidget>
#include <QListWidgetItem>
class ListWidgetItemChild : public QListWidgetItem
{
public:
explicit ListWidgetItemChild(QListWidget *parent = 0);
~ListWidgetItemChild();
QString LBrightnessValue;
QString ARedGreenValue;
QString BYellowBlueValue;
bool operator<(const QListWidgetItem &other) const
{
int a, b;
a = this->text().mid(9,3).toInt();
b = other.text().mid(9,3).toInt();
return a < b;
}
};
class ListWidgetRe : public QListWidget
{
Q_OBJECT
friend class ListWidgetItemChild;
public:
explicit ListWidgetRe(QWidget *parent = nullptr);
~ListWidgetRe();
Q_SIGNALS:
// void itemDoubleClicked(ListWidgetItemChild *item);
};
#endif // RELISTWIDGET_ITEM_H

647
showpic.cpp Normal file
View File

@ -0,0 +1,647 @@
#include "showpic.h"
#include "ui_showpic.h"
# pragma execution_character_set("utf-8")
using namespace std;
void deleteImage(QString folderPath, QString imageName);
QString FindImage(QString folderPath, QString imageName);
extern QString DirPath;
//QString DirPath = "D:/picture/524test";
QStringList GetFileNameList(const QString &strDirpath)//该函数的作用是获取一个目录下所有的文件名并将文件名存储在QStringList中返回。
{
QDir dir(strDirpath);
QFileInfoList Info_list = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
QListIterator<QFileInfo> Iterator(Info_list);
QStringList strFileNameList;
QFileInfo Info;
while (Iterator.hasNext())
{
Info = Iterator.next();
if (Info.isFile())
{
strFileNameList << Info.fileName();
}
}
//排序3.28
qSort(strFileNameList.begin(), strFileNameList.end(), [](const QString& s1, const QString& s2){
return s1.mid(3,2).toInt() < s2.mid(3,2).toInt(); });
return strFileNameList;
}
showpic::showpic(char* buf1, QWidget *parent) :
QWidget(parent),
//showpic::showpic(QWidget *parent) :
// QWidget(parent),
ui(new Ui::showpic)
{
ui->setupUi(this);
//切割char数组
const char split[] = ",";
char* res = strtok(buf1, split);//image_name必须为char[]
while (res != NULL)//切割buf,将有用的数据全部在res_split内可通过res_split.at(i)调用
{
// qDebug() << "res" << res;
res_split.push_back(res);//??
res = strtok(NULL, split);//??
}
qDebug() << "res_split.size()" << res_split.size();
LightPath = DirPath +"/light/";
MiddlePath = DirPath +"/Middle/";
DarkPath = DirPath +"/dark/";
QStringList listLight = GetFileNameList(LightPath);//应该是一个全局变量3.28
QStringList listMiddle = GetFileNameList(MiddlePath);
QStringList listDark = GetFileNameList(DarkPath);
// QStringList listLight = GetFileNameList("D:/wood_color317/data/2023318/light/");//应该是一个全局变量3.28
// QStringList listMiddle = GetFileNameList("D:/wood_color317/data/2023318/middle/");
// QStringList listDark = GetFileNameList("D:/wood_color317/data/2023318/dark/");
//将90个lab值分三类
QVector<char*> Light_lab;
QVector<char*> Middle_lab;
QVector<char*> Dark_lab;
/* for(int i = 0; i < 90; i++)
{
if(i < 30)
{
Light_lab.append(res_split.at(i));
// qDebug() << Light_lab.at(i) << i;
}
else if(i > 29 && i < 60)
{
Middle_lab.append(res_split.at(i));
// qDebug() << Middle_lab.at(i-30) << i;
}
else if(i > 59 && i < 90)
{
Dark_lab.append(res_split.at(i));
// qDebug() << Dark_lab.at(i-60) << i;
}
}
*/
for(int i = 0; i < (listLight.size() + listMiddle.size() + listDark.size()); i++)
{
if(i < listLight.size())
{
Light_lab.append(res_split.at(i));
qDebug() << Light_lab.at(i) << i;
}
else if(i > (listLight.size() - 1) && i < (listLight.size() + listMiddle.size()))
{
Middle_lab.append(res_split.at(i));
qDebug() << Middle_lab.at(i-listLight.size()) << i;
}
else /*if(i > (listLight.size() + listMiddle.size() - 1) && i < 90)*/
{
Dark_lab.append(res_split.at(i));
qDebug() << Dark_lab.at(i-listLight.size() - listMiddle.size()) << i;
}
}
listWidget = new ListWidgetRe(this);
listWidget->setViewMode(QListWidget::IconMode);//显示模式
listWidget->setIconSize(QSize(400, 90));//设置图片大小
listWidget->setSpacing(10);//间距
listWidget->setResizeMode(QListView::Adjust);//适应布局调整
listWidget->setMovement(QListView::Static);//不能移动
// QString file = "D:/wood_color317/data/2023318/light/";
QString file = LightPath;
LoadPicture(file, listLight, Light_lab);
// QListWidgetItem *separate0 = new QListWidgetItem;
// separate0->setText("之后为中色");
// separate0->setFlags(separate0->flags() & ~Qt::ItemIsEnabled & ~Qt::ItemIsSelectable);
// listWidget->addItem(separate0);
// file = "D:/wood_color317/data/2023318/middle/";
file = MiddlePath;
LoadPicture(file, listMiddle, Middle_lab);
// QListWidgetItem *separate1 = new QListWidgetItem;
// separate1->setFlags(separate0->flags() & ~Qt::ItemIsEnabled & ~Qt::ItemIsSelectable);
// separate1->setText("之后为深色");
// listWidget->addItem(separate1);
// file = "D:/wood_color317/data/2023318/dark/";
file = DarkPath;
LoadPicture(file, listDark, Dark_lab);
listWidget->sortItems();
listWidget->setSelectionMode(QAbstractItemView::MultiSelection);//设置多选模式
QVBoxLayout* VBox = new QVBoxLayout;
QHBoxLayout* HBox = new QHBoxLayout;
ui->pushButton->setFixedSize(140,70);
ui->pushButton_2->setFixedSize(140,70);
ui->pushButton_3->setFixedSize(140,70);
ui->pushButton_light->setFixedSize(140,70);
ui->pushButton_middle->setFixedSize(140,70);
ui->pushButton_dark->setFixedSize(140,70);
HBox->addWidget(ui->pushButton);
HBox->addWidget(ui->pushButton_2);
HBox->addWidget(ui->pushButton_3);
HBox->addWidget(ui->pushButton_light);
HBox->addWidget(ui->pushButton_middle);
HBox->addWidget(ui->pushButton_dark);
VBox->addWidget(listWidget);
VBox->addLayout(HBox);
this->setLayout(VBox);
connect(listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(enlargeImage(QListWidgetItem*)));
qDebug() << "showpic ready";
emit PictureReady();
}
showpic::~showpic()
{
delete ui;
}
void showpic::enlargeImage(QListWidgetItem *item)
{
QRect rect = this->geometry();//获取当前窗口坐标及大小 x、y、w、h
// static_cast<ListWidgetItemChild*>(listWidget->itemWidget(item));
ListWidgetItemChild *item0 = static_cast<ListWidgetItemChild *>(item);
//通过自定义的窗口显示图片
// imageWin *showImageWidget = new imageWin(item , QRect(rect.x(), rect.y()+rect.y()*1/4, rect.width(), rect.height()*2/3));
imageWin *showImageWidget = new imageWin(item0 , QRect(rect.x(), rect.y()+rect.y()*1/4, rect.width(), rect.height()*1.7/3));
showImageWidget->show();
//显示条目名称
qDebug() << item0->text();
QString item_name = item0->text();
if(item_name.at(4) != '.')
{
QString a = item_name.at(3);
a.append(item_name.at(4));
qDebug() << "a" << a.toInt();
// int b = a.toInt();
int L = item0->LBrightnessValue.toInt();
int A = item0->ARedGreenValue.toInt();
int B = item0->BYellowBlueValue.toInt();
qDebug() << "LAB" << L << A << B;
//显示色块
cv::Mat mat = cv::Mat(100, 100, CV_8UC3, cv::Scalar(L, A, B));
cv::cvtColor(mat, mat, cv::COLOR_Lab2BGR);
cv::imshow("sekuai", mat);
}
else
{
qDebug() << "--";
}
}
//rgb00.png175136163QQ
//拼图片路径并添加到imageItem再添加到listWidget
void showpic::LoadPicture(QString file, QStringList list, QVector<char*> lab)
{
for(int i = 0; i < list.size(); i++)
{
qDebug() << lab.at(i) << i;
QString LAB = lab.at(i);
QString tmp = file + list.at(i);//拼出图片绝对路径
ListWidgetItemChild *imageItem = new ListWidgetItemChild;
imageItem->LBrightnessValue =LAB.mid(0,3);
imageItem->ARedGreenValue = LAB.mid(3,3);
imageItem->BYellowBlueValue = LAB.mid(6,3);
imageItem->setIcon(QIcon(tmp));
imageItem->setText(list.at(i) + LAB.mid(0,3) + LAB.mid(9,2));
// qDebug() << "luminance1" << lab.at(i) << i;
if(LAB.mid(9,1) == LAB.mid(10,1))
{
}
else
{
imageItem->setTextColor(Qt::red);
}
imageItem->setSizeHint(QSize(400, 120));
listWidget->addItem(imageItem);
}
}
//rgb00.png000
//bool showpic::CompareItem(ListWidgetItemChild *item1, ListWidgetItemChild *item2)
//{
// int luminance1 = item1->text().mid(9,3).toInt();
// qDebug() << "luminance1" << luminance1;
// int luminance2 = item2->text().mid(9,3).toInt();
// qDebug() << "luminance2" << luminance2;
// return luminance1 < luminance2;
//}
void showpic::on_pushButton_clicked()
{
// 获取选中的item
QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
// QListWidgetItem *selectedItem = listWidget->currentItem();
if (selectedItems.size() != 1) {
// 如果选中的item数量不等于2则弹出提示框并返回
QMessageBox::warning(this, "Error", "请至少选择一张图片");
return;
}
//并从文件夹中删除
QListWidgetItem* item1 = selectedItems[0];
QString DelPicName = item1->text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
deleteImage(DirPath, DelPicName);
// 如果有选中的item则删除它
if (item1 != nullptr) {
delete item1;
}
}
void showpic::on_pushButton_2_clicked()
{
// 获取选中的两个item
QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
if (selectedItems.size() != 2) {
// 如果选中的item数量不等于2则弹出提示框并返回
QMessageBox::warning(this, "Error", "请选中2张图片进行操作先选的图片插入到后选的后面");
return;
}
QListWidgetItem* item1 = selectedItems[0];
QListWidgetItem* item2 = selectedItems[1];
// 获取它们在listWidget中的位置
int index1 = listWidget->row(item1);
int index2 = listWidget->row(item2);
qDebug() << "index1" << index1;
qDebug() << "index2" << index2;
// 交换它们的位置,!!!!!!!!!有点问题
listWidget->takeItem(index1);
listWidget->takeItem(index2);
listWidget->insertItem(index1, item2);
listWidget->insertItem(index2, item1);
index1 = listWidget->row(item1);
index2 = listWidget->row(item2);
qDebug() << "index1new" << index1;
qDebug() << "index2new" << index2;
// 取消选中状态
item1->setSelected(false);
item2->setSelected(false);
}
void showpic::on_pushButton_3_clicked()
{
if(listWidget->currentItem() == nullptr)
{
QMessageBox::warning(this, "Error", "请点击一个图片进行操作");
return;
}
QListWidgetItem *selectedItem = listWidget->currentItem();
QString PicNamePath = FindImage(DirPath, selectedItem->text().mid(0, 9));//
// sprintf(PicNamePath, PicNamePath);
cv::Mat Pic = cv::imread(PicNamePath.toLatin1().data());// .toLatin1().data(): string转char*
QInputDialog *inputDialog_item=new QInputDialog(this);
QStringList list;
list<<"浅色"<<"中色"<<"深色";
bool getItem;
QString season = inputDialog_item->getItem(this,"选择文件夹","文件夹类别",list,0,false,&getItem);
if(getItem)
{
if("浅色" == season)
{
QString RePicName = LightPath + selectedItem->text().mid(0,9);
// PicImg.save(RePicName, "PNG", -1);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = selectedItem->text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
deleteImage(MiddlePath, DelPicName);
deleteImage(DarkPath, DelPicName);
if (selectedItem != nullptr) {
delete selectedItem;
}
}
if("中色" == season)
{
QString RePicName = MiddlePath + selectedItem->text().mid(0,9);
// PicImg.save(RePicName, "PNG", -1);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = selectedItem->text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
deleteImage(LightPath, DelPicName);
deleteImage(DarkPath, DelPicName);
if (selectedItem != nullptr) {
delete selectedItem;
}
}
if("深色" == season)
{
QString RePicName = DarkPath + selectedItem->text().mid(0,9);
// PicImg.save(RePicName, "PNG", -1);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = selectedItem->text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
deleteImage(LightPath, DelPicName);
deleteImage(MiddlePath, DelPicName);
if (selectedItem != nullptr) {
delete selectedItem;
}
}
}
}
//按键多选移动rgb00.png000QQ
void showpic::on_pushButton_light_clicked()
{
QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
int Numbers = selectedItems.size();
QListWidgetItem* Item = new QListWidgetItem[Numbers];
for(int i = 0; i < Numbers; i++)
{
// qDebug() <<
Item[i] = *selectedItems[i];
if(Item[i].text().mid(12, 1) == 'Q')
{
return;
}
if(Item[i].text().mid(12, 1) == 'S')
{
// QString PicNamePath = FindImage("D:/2023/wooden/2023318/", Item[i].text().mid(0,9));
QString PicNamePath = FindImage(DirPath, Item[i].text().mid(0,9));
cv::Mat Pic = cv::imread(PicNamePath.toLatin1().data());
// QString RePicName = "D:/2023/wooden/2023318/light/" + Item[i].text().mid(0,9);
QString RePicName = LightPath + Item[i].text().mid(0,9);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = Item[i].text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
// deleteImage("D:/2023/wooden/2023318/dark/", DelPicName);
deleteImage(DarkPath, DelPicName);
if (selectedItems[i] != nullptr) {
delete selectedItems[i];
}
}
if(Item[i].text().mid(12, 1) == 'Z')
{
// QString PicNamePath = FindImage("D:/2023/wooden/2023318/", Item[i].text().mid(0,9));
QString PicNamePath = FindImage(DirPath, Item[i].text().mid(0,9));
cv::Mat Pic = cv::imread(PicNamePath.toLatin1().data());
// QString RePicName = "D:/2023/wooden/2023318/light/" + Item[i].text().mid(0,9);
QString RePicName = LightPath + Item[i].text().mid(0,9);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = Item[i].text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
// deleteImage("D:/2023/wooden/2023318/middle/", DelPicName);
deleteImage(MiddlePath, DelPicName);
if (selectedItems[i] != nullptr) {
delete selectedItems[i];
}
}
}
}
void showpic::on_pushButton_middle_clicked()
{
QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
int Numbers = selectedItems.size();
QListWidgetItem* Item = new QListWidgetItem[Numbers];
for(int i = 0; i < Numbers; i++)
{
Item[i] = *selectedItems[i];
if(Item[i].text().mid(12, 1) == 'Z')
{
return;
}
if(Item[i].text().mid(12, 1) == 'S')
{
// QString PicNamePath = FindImage("D:/2023/wooden/2023318/", Item[i].text().mid(0,9));
QString PicNamePath = FindImage(DirPath, Item[i].text().mid(0,9));
cv::Mat Pic = cv::imread(PicNamePath.toLatin1().data());
// QString RePicName = "D:/2023/wooden/2023318/middle/" + Item[i].text().mid(0,9);
QString RePicName = MiddlePath + Item[i].text().mid(0,9);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = Item[i].text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
// deleteImage("D:/2023/wooden/2023318/dark/", DelPicName);
deleteImage(DarkPath, DelPicName);
if (selectedItems[i] != nullptr) {
delete selectedItems[i];
}
}
if(Item[i].text().mid(12, 1) == 'Q')
{
// QString PicNamePath = FindImage("D:/2023/wooden/2023318/", Item[i].text().mid(0,9));
QString PicNamePath = FindImage(DirPath, Item[i].text().mid(0,9));
cv::Mat Pic = cv::imread(PicNamePath.toLatin1().data());
// QString RePicName = "D:/2023/wooden/2023318/middle/" + Item[i].text().mid(0,9);
QString RePicName = MiddlePath + Item[i].text().mid(0,9);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = Item[i].text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
// deleteImage("D:/2023/wooden/2023318/light/", DelPicName);
deleteImage(LightPath, DelPicName);
if (selectedItems[i] != nullptr) {
delete selectedItems[i];
}
}
}
}
void showpic::on_pushButton_dark_clicked()
{
QList<QListWidgetItem*> selectedItems = listWidget->selectedItems();
int Numbers = selectedItems.size();
QListWidgetItem* Item = new QListWidgetItem[Numbers];
for(int i = 0; i < Numbers; i++)
{
Item[i] = *selectedItems[i];
if(Item[i].text().mid(12, 1) == 'S')
{
return;
}
if(Item[i].text().mid(12, 1) == 'Q')
{
// QString PicNamePath = FindImage("D:/2023/wooden/2023318/", Item[i].text().mid(0,9));
QString PicNamePath = FindImage(DirPath, Item[i].text().mid(0,9));
cv::Mat Pic = cv::imread(PicNamePath.toLatin1().data());
// QString RePicName = "D:/2023/wooden/2023318/dark/" + Item[i].text().mid(0,9);
QString RePicName = DarkPath + Item[i].text().mid(0,9);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = Item[i].text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
// deleteImage("D:/2023/wooden/2023318/light/", DelPicName);
deleteImage(LightPath, DelPicName);
if (selectedItems[i] != nullptr) {
delete selectedItems[i];
}
}
if(Item[i].text().mid(12, 1) == 'Z')
{
// QString PicNamePath = FindImage("D:/2023/wooden/2023318/", Item[i].text().mid(0,9));
QString PicNamePath = FindImage(DirPath, Item[i].text().mid(0,9));
cv::Mat Pic = cv::imread(PicNamePath.toLatin1().data());
// QString RePicName = "D:/2023/wooden/2023318/dark/" + Item[i].text().mid(0,9);
QString RePicName = DarkPath + Item[i].text().mid(0,9);
cv::imwrite(RePicName.toLatin1().data(), Pic);
//调用删除图片函数
QString DelPicName = Item[i].text().mid(0,9);
qDebug() << "DelPicName" << DelPicName;
// deleteImage("D:/2023/wooden/2023318/middle/", DelPicName);
deleteImage(MiddlePath, DelPicName);
if (selectedItems[i] != nullptr) {
delete selectedItems[i];
}
}
}
}
//从文件夹中删除图片
void deleteImage(QString folderPath, QString imageName) {
QDir folder(folderPath);
QFileInfoList entries = folder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
for (const QFileInfo &entry : entries) {
if (entry.isFile() && entry.fileName() == imageName) {
// 找到了指定图片,删除它
qDebug() << "entry.absoluteFilePath()" << entry.absoluteFilePath();
if (QFile::remove(entry.absoluteFilePath())) {
QMessageBox::information(nullptr, "Success", "Image deleted successfully");
} else {
// QMessageBox::warning(nullptr, "Error", "Failed to delete image");
}
return;
} else if (entry.isDir()) {
// 递归进入子文件夹查找图片
deleteImage(entry.absoluteFilePath(), imageName);
}
}
// 如果遍历完当前文件夹和子文件夹都没有找到指定图片,则弹出失败提示框
// QMessageBox::warning(nullptr, "Error", "Failed to find image");
}
QString FindImage(QString folderPath, QString imageName)
{
QDir folderDir(folderPath);
// 获取文件夹中的所有文件和文件夹
QStringList entries = folderDir.entryList();
// 遍历文件夹中的所有文件和文件夹
foreach(QString entry, entries)
{
QString entryPath = folderPath + "/" + entry;
// 如果是子文件夹,进入子文件夹查找图片
if(QFileInfo(entryPath).isDir())
{
QDir subFolderDir(entryPath);
QStringList subEntries = subFolderDir.entryList();
// 遍历子文件夹中的所有文件
foreach(QString subEntry, subEntries)
{
QString subEntryPath = entryPath + "/" + subEntry;
// 如果是目标图片,返回其绝对路径
if(subEntry == imageName)
{
QString imagePath = QFileInfo(subEntryPath).absoluteFilePath();
return imagePath;
}
}
}
// 如果是目标图片,返回其绝对路径
else if(entry == imageName)
{
QString imagePath = QFileInfo(entryPath).absoluteFilePath();
return imagePath;
}
}
// 如果未找到目标图片,返回空字符串
return "";
}

69
showpic.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef SHOWPIC_H
#define SHOWPIC_H
#include <QWidget>
#include <QListWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/types_c.h"
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>
#include <QFile>
#include <QInputDialog>
#include "relistwidget_item.h"
#include "imagewin.h"
#include <QVBoxlayout>
namespace Ui {
class showpic;
}
class showpic : public QWidget
{
Q_OBJECT
public:
explicit showpic(char*, QWidget *parent = 0);
// explicit showpic(QWidget *parent = 0);
~showpic();
QVector<char*> res_split;//存储分割后的字符串
ListWidgetRe *listWidget;
QString LightPath;
QString MiddlePath;
QString DarkPath;
void LoadPicture(QString file, QStringList list, QVector<char*>);
// bool CompareItem(ListWidgetItemChild* item1, ListWidgetItemChild* item2);
public slots:
void enlargeImage(QListWidgetItem *item);//放大图片
signals:
void PictureReady();
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_light_clicked();
void on_pushButton_middle_clicked();
void on_pushButton_dark_clicked();
private:
Ui::showpic *ui;
};
#endif // SHOWPIC_H

127
showpic.ui Normal file
View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>showpic</class>
<widget class="QWidget" name="showpic">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1126</width>
<height>668</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>60</x>
<y>540</y>
<width>141</width>
<height>71</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>19</pointsize>
</font>
</property>
<property name="text">
<string>删除</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>290</x>
<y>540</y>
<width>181</width>
<height>71</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>19</pointsize>
</font>
</property>
<property name="text">
<string>移动</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>530</x>
<y>540</y>
<width>131</width>
<height>71</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>改变所属分类</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_light">
<property name="geometry">
<rect>
<x>700</x>
<y>540</y>
<width>131</width>
<height>71</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>移入浅色</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_middle">
<property name="geometry">
<rect>
<x>850</x>
<y>540</y>
<width>131</width>
<height>71</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>移入中色</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_dark">
<property name="geometry">
<rect>
<x>990</x>
<y>540</y>
<width>131</width>
<height>71</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>移入深色</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

233
src/modbus-data.c Normal file
View File

@ -0,0 +1,233 @@
/*
* Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include <stdlib.h>
#ifndef _MSC_VER
# include <stdint.h>
#else
# include "stdint.h"
#endif
#include <string.h>
#include <assert.h>
#if defined(_WIN32)
# include <winsock2.h>
#else
# include <arpa/inet.h>
#endif
//#include <config.h>
#include "modbus.h"
#if defined(HAVE_BYTESWAP_H)
# include <byteswap.h>
#endif
#if defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# define bswap_16 OSSwapInt16
# define bswap_32 OSSwapInt32
# define bswap_64 OSSwapInt64
#endif
#if defined(__GNUC__)
# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10)
# if GCC_VERSION >= 430
// Since GCC >= 4.30, GCC provides __builtin_bswapXX() alternatives so we switch to them
# undef bswap_32
# define bswap_32 __builtin_bswap32
# endif
# if GCC_VERSION >= 480
# undef bswap_16
# define bswap_16 __builtin_bswap16
# endif
#endif
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
# define bswap_32 _byteswap_ulong
# define bswap_16 _byteswap_ushort
#endif
#if !defined(bswap_16)
# warning "Fallback on C functions for bswap_16"
static inline uint16_t bswap_16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
#endif
#if !defined(bswap_32)
# warning "Fallback on C functions for bswap_32"
static inline uint32_t bswap_32(uint32_t x)
{
return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
}
#endif
/* Sets many bits from a single byte value (all 8 bits of the byte value are
set) */
void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value)
{
int i;
for (i=0; i < 8; i++) {
dest[idx+i] = (value & (1 << i)) ? 1 : 0;
}
}
/* Sets many bits from a table of bytes (only the bits between idx and
idx + nb_bits are set) */
void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
const uint8_t *tab_byte)
{
unsigned int i;
int shift = 0;
for (i = idx; i < idx + nb_bits; i++) {
dest[i] = tab_byte[(i - idx) / 8] & (1 << shift) ? 1 : 0;
/* gcc doesn't like: shift = (++shift) % 8; */
shift++;
shift %= 8;
}
}
/* Gets the byte value from many bits.
To obtain a full byte, set nb_bits to 8. */
uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx,
unsigned int nb_bits)
{
unsigned int i;
uint8_t value = 0;
if (nb_bits > 8) {
/* Assert is ignored if NDEBUG is set */
assert(nb_bits < 8);
nb_bits = 8;
}
for (i=0; i < nb_bits; i++) {
value |= (src[idx+i] << i);
}
return value;
}
/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */
float modbus_get_float_abcd(const uint16_t *src)
{
float f;
uint32_t i;
i = ntohl(((uint32_t)src[0] << 16) + src[1]);
memcpy(&f, &i, sizeof(float));
return f;
}
/* Get a float from 4 bytes (Modbus) in inversed format (DCBA) */
float modbus_get_float_dcba(const uint16_t *src)
{
float f;
uint32_t i;
i = ntohl(bswap_32((((uint32_t)src[0]) << 16) + src[1]));
memcpy(&f, &i, sizeof(float));
return f;
}
/* Get a float from 4 bytes (Modbus) with swapped bytes (BADC) */
float modbus_get_float_badc(const uint16_t *src)
{
float f;
uint32_t i;
i = ntohl((uint32_t)(bswap_16(src[0]) << 16) + bswap_16(src[1]));
memcpy(&f, &i, sizeof(float));
return f;
}
/* Get a float from 4 bytes (Modbus) with swapped words (CDAB) */
float modbus_get_float_cdab(const uint16_t *src)
{
float f;
uint32_t i;
i = ntohl((((uint32_t)src[1]) << 16) + src[0]);
memcpy(&f, &i, sizeof(float));
return f;
}
/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
float modbus_get_float(const uint16_t *src)
{
float f;
uint32_t i;
i = (((uint32_t)src[1]) << 16) + src[0];
memcpy(&f, &i, sizeof(float));
return f;
}
/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
void modbus_set_float_abcd(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = htonl(i);
dest[0] = (uint16_t)(i >> 16);
dest[1] = (uint16_t)i;
}
/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
void modbus_set_float_dcba(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = bswap_32(htonl(i));
dest[0] = (uint16_t)(i >> 16);
dest[1] = (uint16_t)i;
}
/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
void modbus_set_float_badc(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = htonl(i);
dest[0] = (uint16_t)bswap_16(i >> 16);
dest[1] = (uint16_t)bswap_16(i & 0xFFFF);
}
/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
void modbus_set_float_cdab(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
i = htonl(i);
dest[0] = (uint16_t)i;
dest[1] = (uint16_t)(i >> 16);
}
/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
void modbus_set_float(float f, uint16_t *dest)
{
uint32_t i;
memcpy(&i, &f, sizeof(uint32_t));
dest[0] = (uint16_t)i;
dest[1] = (uint16_t)(i >> 16);
}

116
src/modbus-private.h Normal file
View File

@ -0,0 +1,116 @@
/*
* Copyright © 2010-2012 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_PRIVATE_H
#define MODBUS_PRIVATE_H
#ifndef _MSC_VER
# include <stdint.h>
# include <sys/time.h>
#else
# include "stdint.h"
# include <time.h>
typedef int ssize_t;
#endif
#include <sys/types.h>
//#include <config.h>
#include "modbus.h"
MODBUS_BEGIN_DECLS
/* It's not really the minimal length (the real one is report slave ID
* in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP
* communications to read many values or write a single one.
* Maximum between :
* - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2)
* - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2)
*/
#define _MIN_REQ_LENGTH 12
#define _REPORT_SLAVE_ID 180
#define _MODBUS_EXCEPTION_RSP_LENGTH 5
/* Timeouts in microsecond (0.5 s) */
#define _RESPONSE_TIMEOUT 500000
#define _BYTE_TIMEOUT 500000
typedef enum {
_MODBUS_BACKEND_TYPE_RTU=0,
_MODBUS_BACKEND_TYPE_TCP
} modbus_backend_type_t;
/*
* ---------- Request Indication ----------
* | Client | ---------------------->| Server |
* ---------- Confirmation Response ----------
*/
typedef enum {
/* Request message on the server side */
MSG_INDICATION,
/* Request message on the client side */
MSG_CONFIRMATION
} msg_type_t;
/* This structure reduces the number of params in functions and so
* optimizes the speed of execution (~ 37%). */
typedef struct _sft {
int slave;
int function;
int t_id;
} sft_t;
typedef struct _modbus_backend {
unsigned int backend_type;
unsigned int header_length;
unsigned int checksum_length;
unsigned int max_adu_length;
int (*set_slave) (modbus_t *ctx, int slave);
int (*build_request_basis) (modbus_t *ctx, int function, int addr,
int nb, uint8_t *req);
int (*build_response_basis) (sft_t *sft, uint8_t *rsp);
int (*prepare_response_tid) (const uint8_t *req, int *req_length);
int (*send_msg_pre) (uint8_t *req, int req_length);
ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);
int (*receive) (modbus_t *ctx, uint8_t *req);
ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);
int (*check_integrity) (modbus_t *ctx, uint8_t *msg,
const int msg_length);
int (*pre_check_confirmation) (modbus_t *ctx, const uint8_t *req,
const uint8_t *rsp, int rsp_length);
int (*connect) (modbus_t *ctx);
void (*close) (modbus_t *ctx);
int (*flush) (modbus_t *ctx);
int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
void (*free) (modbus_t *ctx);
} modbus_backend_t;
struct _modbus {
/* Slave address */
int slave;
/* Socket or file descriptor */
int s;
int debug;
int error_recovery;
struct timeval response_timeout;
struct timeval byte_timeout;
struct timeval indication_timeout;
const modbus_backend_t *backend;
void *backend_data;
};
void _modbus_init_common(modbus_t *ctx);
void _error_print(modbus_t *ctx, const char *context);
int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type);
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dest, const char *src, size_t dest_size);
#endif
MODBUS_END_DECLS
#endif /* MODBUS_PRIVATE_H */

76
src/modbus-rtu-private.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_RTU_PRIVATE_H
#define MODBUS_RTU_PRIVATE_H
#ifndef _MSC_VER
#include <stdint.h>
#else
#include "stdint.h"
#endif
#if defined(_WIN32)
#include <windows.h>
#else
#include <termios.h>
#endif
#define _MODBUS_RTU_HEADER_LENGTH 1
#define _MODBUS_RTU_PRESET_REQ_LENGTH 6
#define _MODBUS_RTU_PRESET_RSP_LENGTH 2
#define _MODBUS_RTU_CHECKSUM_LENGTH 2
#if defined(_WIN32)
#if !defined(ENOTSUP)
#define ENOTSUP WSAEOPNOTSUPP
#endif
/* WIN32: struct containing serial handle and a receive buffer */
#define PY_BUF_SIZE 512
struct win32_ser {
/* File handle */
HANDLE fd;
/* Receive buffer */
uint8_t buf[PY_BUF_SIZE];
/* Received chars */
DWORD n_bytes;
};
#endif /* _WIN32 */
typedef struct _modbus_rtu {
/* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" on Mac OS X. */
char *device;
/* Bauds: 9600, 19200, 57600, 115200, etc */
int baud;
/* Data bit */
uint8_t data_bit;
/* Stop bit */
uint8_t stop_bit;
/* Parity: 'N', 'O', 'E' */
char parity;
#if defined(_WIN32)
struct win32_ser w_ser;
DCB old_dcb;
#else
/* Save old termios settings */
struct termios old_tios;
#endif
#if HAVE_DECL_TIOCSRS485
int serial_mode;
#endif
#if HAVE_DECL_TIOCM_RTS
int rts;
int rts_delay;
int onebyte_time;
void (*set_rts) (modbus_t *ctx, int on);
#endif
/* To handle many slaves on the same link */
int confirmation_to_ignore;
} modbus_rtu_t;
#endif /* MODBUS_RTU_PRIVATE_H */

1299
src/modbus-rtu.c Normal file

File diff suppressed because it is too large Load Diff

42
src/modbus-rtu.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_RTU_H
#define MODBUS_RTU_H
#include "modbus.h"
MODBUS_BEGIN_DECLS
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
* RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes
*/
#define MODBUS_RTU_MAX_ADU_LENGTH 256
MODBUS_API modbus_t* modbus_new_rtu(const char *device, int baud, char parity,
int data_bit, int stop_bit);
#define MODBUS_RTU_RS232 0
#define MODBUS_RTU_RS485 1
MODBUS_API int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode);
MODBUS_API int modbus_rtu_get_serial_mode(modbus_t *ctx);
#define MODBUS_RTU_RTS_NONE 0
#define MODBUS_RTU_RTS_UP 1
#define MODBUS_RTU_RTS_DOWN 2
MODBUS_API int modbus_rtu_set_rts(modbus_t *ctx, int mode);
MODBUS_API int modbus_rtu_get_rts(modbus_t *ctx);
MODBUS_API int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts) (modbus_t *ctx, int on));
MODBUS_API int modbus_rtu_set_rts_delay(modbus_t *ctx, int us);
MODBUS_API int modbus_rtu_get_rts_delay(modbus_t *ctx);
MODBUS_END_DECLS
#endif /* MODBUS_RTU_H */

44
src/modbus-tcp-private.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_TCP_PRIVATE_H
#define MODBUS_TCP_PRIVATE_H
#define _MODBUS_TCP_HEADER_LENGTH 7
#define _MODBUS_TCP_PRESET_REQ_LENGTH 12
#define _MODBUS_TCP_PRESET_RSP_LENGTH 8
#define _MODBUS_TCP_CHECKSUM_LENGTH 0
/* In both structures, the transaction ID must be placed on first position
to have a quick access not dependant of the TCP backend */
typedef struct _modbus_tcp {
/* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b
(page 23/46):
The transaction identifier is used to associate the future response
with the request. This identifier is unique on each TCP connection. */
uint16_t t_id;
/* TCP port */
int port;
/* IP address */
char ip[16];
} modbus_tcp_t;
#define _MODBUS_TCP_PI_NODE_LENGTH 1025
#define _MODBUS_TCP_PI_SERVICE_LENGTH 32
typedef struct _modbus_tcp_pi {
/* Transaction ID */
uint16_t t_id;
/* TCP port */
int port;
/* Node */
char node[_MODBUS_TCP_PI_NODE_LENGTH];
/* Service */
char service[_MODBUS_TCP_PI_SERVICE_LENGTH];
} modbus_tcp_pi_t;
#endif /* MODBUS_TCP_PRIVATE_H */

929
src/modbus-tcp.c Normal file
View File

@ -0,0 +1,929 @@
/*
* Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#if defined(_WIN32)
# define OS_WIN32
/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
* minwg32 headers check WINVER before allowing the use of these */
# ifndef WINVER
# define WINVER 0x0501
# endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <signal.h>
#include <sys/types.h>
#if defined(_WIN32)
/* Already set in modbus-tcp.h but it seems order matters in VS2005 */
# include <winsock2.h>
# include <ws2tcpip.h>
# define SHUT_RDWR 2
# define close closesocket
#else
# include <sys/socket.h>
# include <sys/ioctl.h>
#if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ < 5)
# define OS_BSD
# include <netinet/in_systm.h>
#endif
# include <netinet/in.h>
# include <netinet/ip.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <netdb.h>
#endif
#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
#if defined(_AIX) && !defined(MSG_DONTWAIT)
#define MSG_DONTWAIT MSG_NONBLOCK
#endif
#include "modbus-private.h"
#include "modbus-tcp.h"
#include "modbus-tcp-private.h"
#ifdef OS_WIN32
static int _modbus_tcp_init_win32(void)
{
/* Initialise Windows Socket API */
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
fprintf(stderr, "WSAStartup() returned error code %d\n",
(unsigned int)GetLastError());
errno = EIO;
return -1;
}
return 0;
}
#endif
static int _modbus_set_slave(modbus_t *ctx, int slave)
{
/* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
if (slave >= 0 && slave <= 247) {
ctx->slave = slave;
} else if (slave == MODBUS_TCP_SLAVE) {
/* The special value MODBUS_TCP_SLAVE (0xFF) can be used in TCP mode to
* restore the default value. */
ctx->slave = slave;
} else {
errno = EINVAL;
return -1;
}
return 0;
}
/* Builds a TCP request header */
static int _modbus_tcp_build_request_basis(modbus_t *ctx, int function,
int addr, int nb,
uint8_t *req)
{
modbus_tcp_t *ctx_tcp = ctx->backend_data;
/* Increase transaction ID */
if (ctx_tcp->t_id < UINT16_MAX)
ctx_tcp->t_id++;
else
ctx_tcp->t_id = 0;
req[0] = ctx_tcp->t_id >> 8;
req[1] = ctx_tcp->t_id & 0x00ff;
/* Protocol Modbus */
req[2] = 0;
req[3] = 0;
/* Length will be defined later by set_req_length_tcp at offsets 4
and 5 */
req[6] = ctx->slave;
req[7] = function;
req[8] = addr >> 8;
req[9] = addr & 0x00ff;
req[10] = nb >> 8;
req[11] = nb & 0x00ff;
return _MODBUS_TCP_PRESET_REQ_LENGTH;
}
/* Builds a TCP response header */
static int _modbus_tcp_build_response_basis(sft_t *sft, uint8_t *rsp)
{
/* Extract from MODBUS Messaging on TCP/IP Implementation
Guide V1.0b (page 23/46):
The transaction identifier is used to associate the future
response with the request. */
rsp[0] = sft->t_id >> 8;
rsp[1] = sft->t_id & 0x00ff;
/* Protocol Modbus */
rsp[2] = 0;
rsp[3] = 0;
/* Length will be set later by send_msg (4 and 5) */
/* The slave ID is copied from the indication */
rsp[6] = sft->slave;
rsp[7] = sft->function;
return _MODBUS_TCP_PRESET_RSP_LENGTH;
}
static int _modbus_tcp_prepare_response_tid(const uint8_t *req, int *req_length)
{
return (req[0] << 8) + req[1];
}
static int _modbus_tcp_send_msg_pre(uint8_t *req, int req_length)
{
/* Substract the header length to the message length */
int mbap_length = req_length - 6;
req[4] = mbap_length >> 8;
req[5] = mbap_length & 0x00FF;
return req_length;
}
static ssize_t _modbus_tcp_send(modbus_t *ctx, const uint8_t *req, int req_length)
{
/* MSG_NOSIGNAL
Requests not to send SIGPIPE on errors on stream oriented
sockets when the other end breaks the connection. The EPIPE
error is still returned. */
return send(ctx->s, (const char *)req, req_length, MSG_NOSIGNAL);
}
static int _modbus_tcp_receive(modbus_t *ctx, uint8_t *req) {
return _modbus_receive_msg(ctx, req, MSG_INDICATION);
}
static ssize_t _modbus_tcp_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length) {
return recv(ctx->s, (char *)rsp, rsp_length, 0);
}
static int _modbus_tcp_check_integrity(modbus_t *ctx, uint8_t *msg, const int msg_length)
{
return msg_length;
}
static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, const uint8_t *req,
const uint8_t *rsp, int rsp_length)
{
/* Check transaction ID */
if (req[0] != rsp[0] || req[1] != rsp[1]) {
if (ctx->debug) {
fprintf(stderr, "Invalid transaction ID received 0x%X (not 0x%X)\n",
(rsp[0] << 8) + rsp[1], (req[0] << 8) + req[1]);
}
errno = EMBBADDATA;
return -1;
}
/* Check protocol ID */
if (rsp[2] != 0x0 && rsp[3] != 0x0) {
if (ctx->debug) {
fprintf(stderr, "Invalid protocol ID received 0x%X (not 0x0)\n",
(rsp[2] << 8) + rsp[3]);
}
errno = EMBBADDATA;
return -1;
}
return 0;
}
static int _modbus_tcp_set_ipv4_options(int s)
{
int rc;
int option;
/* Set the TCP no delay flag */
/* SOL_TCP = IPPROTO_TCP */
option = 1;
rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
(const void *)&option, sizeof(int));
if (rc == -1) {
return -1;
}
/* If the OS does not offer SOCK_NONBLOCK, fall back to setting FIONBIO to
* make sockets non-blocking */
/* Do not care about the return value, this is optional */
#if !defined(SOCK_NONBLOCK) && defined(FIONBIO)
#ifdef OS_WIN32
{
/* Setting FIONBIO expects an unsigned long according to MSDN */
u_long loption = 1;
ioctlsocket(s, FIONBIO, &loption);
}
#else
option = 1;
ioctl(s, FIONBIO, &option);
#endif
#endif
#ifndef OS_WIN32
/**
* Cygwin defines IPTOS_LOWDELAY but can't handle that flag so it's
* necessary to workaround that problem.
**/
/* Set the IP low delay option */
option = IPTOS_LOWDELAY;
rc = setsockopt(s, IPPROTO_IP, IP_TOS,
(const void *)&option, sizeof(int));
if (rc == -1) {
return -1;
}
#endif
return 0;
}
static int _connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen,
const struct timeval *ro_tv)
{
int rc = connect(sockfd, addr, addrlen);
#ifdef OS_WIN32
int wsaError = 0;
if (rc == -1) {
wsaError = WSAGetLastError();
}
if (wsaError == WSAEWOULDBLOCK || wsaError == WSAEINPROGRESS) {
#else
if (rc == -1 && errno == EINPROGRESS) {
#endif
fd_set wset;
int optval;
socklen_t optlen = sizeof(optval);
struct timeval tv = *ro_tv;
/* Wait to be available in writing */
FD_ZERO(&wset);
FD_SET(sockfd, &wset);
rc = select(sockfd + 1, NULL, &wset, NULL, &tv);
if (rc <= 0) {
/* Timeout or fail */
return -1;
}
/* The connection is established if SO_ERROR and optval are set to 0 */
rc = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen);
if (rc == 0 && optval == 0) {
return 0;
} else {
errno = ECONNREFUSED;
return -1;
}
}
return rc;
}
/* Establishes a modbus TCP connection with a Modbus server. */
static int _modbus_tcp_connect(modbus_t *ctx)
{
int rc;
/* Specialized version of sockaddr for Internet socket address (same size) */
struct sockaddr_in addr;
modbus_tcp_t *ctx_tcp = ctx->backend_data;
int flags = SOCK_STREAM;
#ifdef OS_WIN32
if (_modbus_tcp_init_win32() == -1) {
return -1;
}
#endif
#ifdef SOCK_CLOEXEC
flags |= SOCK_CLOEXEC;
#endif
#ifdef SOCK_NONBLOCK
flags |= SOCK_NONBLOCK;
#endif
ctx->s = socket(PF_INET, flags, 0);
if (ctx->s == -1) {
return -1;
}
rc = _modbus_tcp_set_ipv4_options(ctx->s);
if (rc == -1) {
close(ctx->s);
ctx->s = -1;
return -1;
}
if (ctx->debug) {
printf("Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(ctx_tcp->port);
addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
rc = _connect(ctx->s, (struct sockaddr *)&addr, sizeof(addr), &ctx->response_timeout);
if (rc == -1) {
close(ctx->s);
ctx->s = -1;
return -1;
}
return 0;
}
/* Establishes a modbus TCP PI connection with a Modbus server. */
static int _modbus_tcp_pi_connect(modbus_t *ctx)
{
int rc;
struct addrinfo *ai_list;
struct addrinfo *ai_ptr;
struct addrinfo ai_hints;
modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data;
#ifdef OS_WIN32
if (_modbus_tcp_init_win32() == -1) {
return -1;
}
#endif
memset(&ai_hints, 0, sizeof(ai_hints));
#ifdef AI_ADDRCONFIG
ai_hints.ai_flags |= AI_ADDRCONFIG;
#endif
ai_hints.ai_family = AF_UNSPEC;
ai_hints.ai_socktype = SOCK_STREAM;
ai_hints.ai_addr = NULL;
ai_hints.ai_canonname = NULL;
ai_hints.ai_next = NULL;
ai_list = NULL;
rc = getaddrinfo(ctx_tcp_pi->node, ctx_tcp_pi->service,
&ai_hints, &ai_list);
if (rc != 0) {
if (ctx->debug) {
fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc));
}
errno = ECONNREFUSED;
return -1;
}
for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
int flags = ai_ptr->ai_socktype;
int s;
#ifdef SOCK_CLOEXEC
flags |= SOCK_CLOEXEC;
#endif
#ifdef SOCK_NONBLOCK
flags |= SOCK_NONBLOCK;
#endif
s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol);
if (s < 0)
continue;
if (ai_ptr->ai_family == AF_INET)
_modbus_tcp_set_ipv4_options(s);
if (ctx->debug) {
printf("Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service);
}
rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout);
if (rc == -1) {
close(s);
continue;
}
ctx->s = s;
break;
}
freeaddrinfo(ai_list);
if (ctx->s < 0) {
return -1;
}
return 0;
}
/* Closes the network connection and socket in TCP mode */
static void _modbus_tcp_close(modbus_t *ctx)
{
if (ctx->s != -1) {
shutdown(ctx->s, SHUT_RDWR);
close(ctx->s);
ctx->s = -1;
}
}
static int _modbus_tcp_flush(modbus_t *ctx)
{
int rc;
int rc_sum = 0;
do {
/* Extract the garbage from the socket */
char devnull[MODBUS_TCP_MAX_ADU_LENGTH];
#ifndef OS_WIN32
rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, MSG_DONTWAIT);
#else
/* On Win32, it's a bit more complicated to not wait */
fd_set rset;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rset);
FD_SET(ctx->s, &rset);
rc = select(ctx->s+1, &rset, NULL, NULL, &tv);
if (rc == -1) {
return -1;
}
if (rc == 1) {
/* There is data to flush */
rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, 0);
}
#endif
if (rc > 0) {
rc_sum += rc;
}
} while (rc == MODBUS_TCP_MAX_ADU_LENGTH);
return rc_sum;
}
/* Listens for any request from one or many modbus masters in TCP */
int modbus_tcp_listen(modbus_t *ctx, int nb_connection)
{
int new_s;
int enable;
int flags;
struct sockaddr_in addr;
modbus_tcp_t *ctx_tcp;
if (ctx == NULL) {
errno = EINVAL;
return -1;
}
ctx_tcp = ctx->backend_data;
#ifdef OS_WIN32
if (_modbus_tcp_init_win32() == -1) {
return -1;
}
#endif
flags = SOCK_STREAM;
#ifdef SOCK_CLOEXEC
flags |= SOCK_CLOEXEC;
#endif
new_s = socket(PF_INET, flags, IPPROTO_TCP);
if (new_s == -1) {
return -1;
}
enable = 1;
if (setsockopt(new_s, SOL_SOCKET, SO_REUSEADDR,
(char *)&enable, sizeof(enable)) == -1) {
close(new_s);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
/* If the modbus port is < to 1024, we need the setuid root. */
addr.sin_port = htons(ctx_tcp->port);
if (ctx_tcp->ip[0] == '0') {
/* Listen any addresses */
addr.sin_addr.s_addr = htonl(INADDR_ANY);
} else {
/* Listen only specified IP address */
addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
}
if (bind(new_s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
close(new_s);
return -1;
}
if (listen(new_s, nb_connection) == -1) {
close(new_s);
return -1;
}
return new_s;
}
int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection)
{
int rc;
struct addrinfo *ai_list;
struct addrinfo *ai_ptr;
struct addrinfo ai_hints;
const char *node;
const char *service;
int new_s;
modbus_tcp_pi_t *ctx_tcp_pi;
if (ctx == NULL) {
errno = EINVAL;
return -1;
}
ctx_tcp_pi = ctx->backend_data;
#ifdef OS_WIN32
if (_modbus_tcp_init_win32() == -1) {
return -1;
}
#endif
if (ctx_tcp_pi->node[0] == 0) {
node = NULL; /* == any */
} else {
node = ctx_tcp_pi->node;
}
if (ctx_tcp_pi->service[0] == 0) {
service = "502";
} else {
service = ctx_tcp_pi->service;
}
memset(&ai_hints, 0, sizeof (ai_hints));
/* If node is not NULL, than the AI_PASSIVE flag is ignored. */
ai_hints.ai_flags |= AI_PASSIVE;
#ifdef AI_ADDRCONFIG
ai_hints.ai_flags |= AI_ADDRCONFIG;
#endif
ai_hints.ai_family = AF_UNSPEC;
ai_hints.ai_socktype = SOCK_STREAM;
ai_hints.ai_addr = NULL;
ai_hints.ai_canonname = NULL;
ai_hints.ai_next = NULL;
ai_list = NULL;
rc = getaddrinfo(node, service, &ai_hints, &ai_list);
if (rc != 0) {
if (ctx->debug) {
fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc));
}
errno = ECONNREFUSED;
return -1;
}
new_s = -1;
for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
int flags = ai_ptr->ai_socktype;
int s;
#ifdef SOCK_CLOEXEC
flags |= SOCK_CLOEXEC;
#endif
s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol);
if (s < 0) {
if (ctx->debug) {
perror("socket");
}
continue;
} else {
int enable = 1;
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(void *)&enable, sizeof (enable));
if (rc != 0) {
close(s);
if (ctx->debug) {
perror("setsockopt");
}
continue;
}
}
rc = bind(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (rc != 0) {
close(s);
if (ctx->debug) {
perror("bind");
}
continue;
}
rc = listen(s, nb_connection);
if (rc != 0) {
close(s);
if (ctx->debug) {
perror("listen");
}
continue;
}
new_s = s;
break;
}
freeaddrinfo(ai_list);
if (new_s < 0) {
return -1;
}
return new_s;
}
int modbus_tcp_accept(modbus_t *ctx, int *s)
{
struct sockaddr_in addr;
socklen_t addrlen;
if (ctx == NULL) {
errno = EINVAL;
return -1;
}
addrlen = sizeof(addr);
#ifdef HAVE_ACCEPT4
/* Inherit socket flags and use accept4 call */
ctx->s = accept4(*s, (struct sockaddr *)&addr, &addrlen, SOCK_CLOEXEC);
#else
ctx->s = accept(*s, (struct sockaddr *)&addr, &addrlen);
#endif
if (ctx->s == -1) {
return -1;
}
if (ctx->debug) {
printf("The client connection from %s is accepted\n",
inet_ntoa(addr.sin_addr));
}
return ctx->s;
}
int modbus_tcp_pi_accept(modbus_t *ctx, int *s)
{
struct sockaddr_storage addr;
socklen_t addrlen;
if (ctx == NULL) {
errno = EINVAL;
return -1;
}
addrlen = sizeof(addr);
#ifdef HAVE_ACCEPT4
/* Inherit socket flags and use accept4 call */
ctx->s = accept4(*s, (struct sockaddr *)&addr, &addrlen, SOCK_CLOEXEC);
#else
ctx->s = accept(*s, (struct sockaddr *)&addr, &addrlen);
#endif
if (ctx->s == -1) {
return -1;
}
if (ctx->debug) {
printf("The client connection is accepted.\n");
}
return ctx->s;
}
static int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read)
{
int s_rc;
while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) {
if (errno == EINTR) {
if (ctx->debug) {
fprintf(stderr, "A non blocked signal was caught\n");
}
/* Necessary after an error */
FD_ZERO(rset);
FD_SET(ctx->s, rset);
} else {
return -1;
}
}
if (s_rc == 0) {
errno = ETIMEDOUT;
return -1;
}
return s_rc;
}
static void _modbus_tcp_free(modbus_t *ctx) {
free(ctx->backend_data);
free(ctx);
}
const modbus_backend_t _modbus_tcp_backend = {
_MODBUS_BACKEND_TYPE_TCP,
_MODBUS_TCP_HEADER_LENGTH,
_MODBUS_TCP_CHECKSUM_LENGTH,
MODBUS_TCP_MAX_ADU_LENGTH,
_modbus_set_slave,
_modbus_tcp_build_request_basis,
_modbus_tcp_build_response_basis,
_modbus_tcp_prepare_response_tid,
_modbus_tcp_send_msg_pre,
_modbus_tcp_send,
_modbus_tcp_receive,
_modbus_tcp_recv,
_modbus_tcp_check_integrity,
_modbus_tcp_pre_check_confirmation,
_modbus_tcp_connect,
_modbus_tcp_close,
_modbus_tcp_flush,
_modbus_tcp_select,
_modbus_tcp_free
};
const modbus_backend_t _modbus_tcp_pi_backend = {
_MODBUS_BACKEND_TYPE_TCP,
_MODBUS_TCP_HEADER_LENGTH,
_MODBUS_TCP_CHECKSUM_LENGTH,
MODBUS_TCP_MAX_ADU_LENGTH,
_modbus_set_slave,
_modbus_tcp_build_request_basis,
_modbus_tcp_build_response_basis,
_modbus_tcp_prepare_response_tid,
_modbus_tcp_send_msg_pre,
_modbus_tcp_send,
_modbus_tcp_receive,
_modbus_tcp_recv,
_modbus_tcp_check_integrity,
_modbus_tcp_pre_check_confirmation,
_modbus_tcp_pi_connect,
_modbus_tcp_close,
_modbus_tcp_flush,
_modbus_tcp_select,
_modbus_tcp_free
};
modbus_t* modbus_new_tcp(const char *ip, int port)
{
modbus_t *ctx;
modbus_tcp_t *ctx_tcp;
size_t dest_size;
size_t ret_size;
#if defined(OS_BSD)
/* MSG_NOSIGNAL is unsupported on *BSD so we install an ignore
handler for SIGPIPE. */
struct sigaction sa;
sa.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &sa, NULL) < 0) {
/* The debug flag can't be set here... */
fprintf(stderr, "Could not install SIGPIPE handler.\n");
return NULL;
}
#endif
ctx = (modbus_t *)malloc(sizeof(modbus_t));
if (ctx == NULL) {
return NULL;
}
_modbus_init_common(ctx);
/* Could be changed after to reach a remote serial Modbus device */
ctx->slave = MODBUS_TCP_SLAVE;
ctx->backend = &_modbus_tcp_backend;
ctx->backend_data = (modbus_tcp_t *)malloc(sizeof(modbus_tcp_t));
if (ctx->backend_data == NULL) {
modbus_free(ctx);
errno = ENOMEM;
return NULL;
}
ctx_tcp = (modbus_tcp_t *)ctx->backend_data;
if (ip != NULL) {
dest_size = sizeof(char) * 16;
ret_size = strlcpy(ctx_tcp->ip, ip, dest_size);
if (ret_size == 0) {
fprintf(stderr, "The IP string is empty\n");
modbus_free(ctx);
errno = EINVAL;
return NULL;
}
if (ret_size >= dest_size) {
fprintf(stderr, "The IP string has been truncated\n");
modbus_free(ctx);
errno = EINVAL;
return NULL;
}
} else {
ctx_tcp->ip[0] = '0';
}
ctx_tcp->port = port;
ctx_tcp->t_id = 0;
return ctx;
}
modbus_t* modbus_new_tcp_pi(const char *node, const char *service)
{
modbus_t *ctx;
modbus_tcp_pi_t *ctx_tcp_pi;
size_t dest_size;
size_t ret_size;
ctx = (modbus_t *)malloc(sizeof(modbus_t));
if (ctx == NULL) {
return NULL;
}
_modbus_init_common(ctx);
/* Could be changed after to reach a remote serial Modbus device */
ctx->slave = MODBUS_TCP_SLAVE;
ctx->backend = &_modbus_tcp_pi_backend;
ctx->backend_data = (modbus_tcp_pi_t *)malloc(sizeof(modbus_tcp_pi_t));
if (ctx->backend_data == NULL) {
modbus_free(ctx);
errno = ENOMEM;
return NULL;
}
ctx_tcp_pi = (modbus_tcp_pi_t *)ctx->backend_data;
if (node == NULL) {
/* The node argument can be empty to indicate any hosts */
ctx_tcp_pi->node[0] = 0;
} else {
dest_size = sizeof(char) * _MODBUS_TCP_PI_NODE_LENGTH;
ret_size = strlcpy(ctx_tcp_pi->node, node, dest_size);
if (ret_size == 0) {
fprintf(stderr, "The node string is empty\n");
modbus_free(ctx);
errno = EINVAL;
return NULL;
}
if (ret_size >= dest_size) {
fprintf(stderr, "The node string has been truncated\n");
modbus_free(ctx);
errno = EINVAL;
return NULL;
}
}
if (service != NULL) {
dest_size = sizeof(char) * _MODBUS_TCP_PI_SERVICE_LENGTH;
ret_size = strlcpy(ctx_tcp_pi->service, service, dest_size);
} else {
/* Empty service is not allowed, error catched below. */
ret_size = 0;
}
if (ret_size == 0) {
fprintf(stderr, "The service string is empty\n");
modbus_free(ctx);
errno = EINVAL;
return NULL;
}
if (ret_size >= dest_size) {
fprintf(stderr, "The service string has been truncated\n");
modbus_free(ctx);
errno = EINVAL;
return NULL;
}
ctx_tcp_pi->t_id = 0;
return ctx;
}

52
src/modbus-tcp.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright © 2001-2010 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_TCP_H
#define MODBUS_TCP_H
#include "modbus.h"
MODBUS_BEGIN_DECLS
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Win32 with MinGW, supplement to <errno.h> */
#include <winsock2.h>
#if !defined(ECONNRESET)
#define ECONNRESET WSAECONNRESET
#endif
#if !defined(ECONNREFUSED)
#define ECONNREFUSED WSAECONNREFUSED
#endif
#if !defined(ETIMEDOUT)
#define ETIMEDOUT WSAETIMEDOUT
#endif
#if !defined(ENOPROTOOPT)
#define ENOPROTOOPT WSAENOPROTOOPT
#endif
#if !defined(EINPROGRESS)
#define EINPROGRESS WSAEINPROGRESS
#endif
#endif
#define MODBUS_TCP_DEFAULT_PORT 502
#define MODBUS_TCP_SLAVE 0xFF
/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
* TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes
*/
#define MODBUS_TCP_MAX_ADU_LENGTH 260
MODBUS_API modbus_t* modbus_new_tcp(const char *ip_address, int port);
MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s);
MODBUS_API modbus_t* modbus_new_tcp_pi(const char *node, const char *service);
MODBUS_API int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection);
MODBUS_API int modbus_tcp_pi_accept(modbus_t *ctx, int *s);
MODBUS_END_DECLS
#endif /* MODBUS_TCP_H */

53
src/modbus-version.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MODBUS_VERSION_H
#define MODBUS_VERSION_H
/* The major version, (1, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MAJOR (3)
/* The minor version (2, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MINOR (1)
/* The micro version (3, if %LIBMODBUS_VERSION is 1.2.3) */
#define LIBMODBUS_VERSION_MICRO (6)
/* The full version, like 1.2.3 */
#define LIBMODBUS_VERSION 3.1.6
/* The full version, in string form (suited for string concatenation)
*/
#define LIBMODBUS_VERSION_STRING "3.1.6"
/* Numerically encoded version, eg. v1.2.3 is 0x010203 */
#define LIBMODBUS_VERSION_HEX ((LIBMODBUS_VERSION_MAJOR << 16) | \
(LIBMODBUS_VERSION_MINOR << 8) | \
(LIBMODBUS_VERSION_MICRO << 0))
/* Evaluates to True if the version is greater than @major, @minor and @micro
*/
#define LIBMODBUS_VERSION_CHECK(major,minor,micro) \
(LIBMODBUS_VERSION_MAJOR > (major) || \
(LIBMODBUS_VERSION_MAJOR == (major) && \
LIBMODBUS_VERSION_MINOR > (minor)) || \
(LIBMODBUS_VERSION_MAJOR == (major) && \
LIBMODBUS_VERSION_MINOR == (minor) && \
LIBMODBUS_VERSION_MICRO >= (micro)))
#endif /* MODBUS_VERSION_H */

1911
src/modbus.c Normal file

File diff suppressed because it is too large Load Diff

293
src/modbus.h Normal file
View File

@ -0,0 +1,293 @@
/*
* Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#ifndef MODBUS_H
#define MODBUS_H
/* Add this for macros that defined unix flavor */
#if (defined(__unix__) || defined(unix)) && !defined(USG)
#include <sys/param.h>
#endif
#ifndef _MSC_VER
#include <stdint.h>
#else
#include "stdint.h"
#endif
#include "modbus-version.h"
#if defined(_MSC_VER)
# if defined(DLLBUILD)
/* define DLLBUILD when building the DLL */
# define MODBUS_API __declspec(dllexport)
# else
# define MODBUS_API __declspec(dllimport)
# endif
#else
# define MODBUS_API
#endif
#ifdef __cplusplus
# define MODBUS_BEGIN_DECLS extern "C" {
# define MODBUS_END_DECLS }
#else
# define MODBUS_BEGIN_DECLS
# define MODBUS_END_DECLS
#endif
MODBUS_BEGIN_DECLS
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef OFF
#define OFF 0
#endif
#ifndef ON
#define ON 1
#endif
/* Modbus function codes */
#define MODBUS_FC_READ_COILS 0x01
#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
#define MODBUS_FC_READ_HOLDING_REGISTERS 0x03
#define MODBUS_FC_READ_INPUT_REGISTERS 0x04
#define MODBUS_FC_WRITE_SINGLE_COIL 0x05
#define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06
#define MODBUS_FC_READ_EXCEPTION_STATUS 0x07
#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
#define MODBUS_FC_REPORT_SLAVE_ID 0x11
#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
#define MODBUS_BROADCAST_ADDRESS 0
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
* Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
* (chapter 6 section 11 page 29)
* Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0)
*/
#define MODBUS_MAX_READ_BITS 2000
#define MODBUS_MAX_WRITE_BITS 1968
/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
* Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
* (chapter 6 section 12 page 31)
* Quantity of Registers to write (2 bytes) 1 to 123 (0x7B)
* (chapter 6 section 17 page 38)
* Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79)
*/
#define MODBUS_MAX_READ_REGISTERS 125
#define MODBUS_MAX_WRITE_REGISTERS 123
#define MODBUS_MAX_WR_WRITE_REGISTERS 121
#define MODBUS_MAX_WR_READ_REGISTERS 125
/* The size of the MODBUS PDU is limited by the size constraint inherited from
* the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256
* bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server
* address (1 byte) - CRC (2 bytes) = 253 bytes.
*/
#define MODBUS_MAX_PDU_LENGTH 253
/* Consequently:
* - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256
* bytes.
* - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
* so the maximum of both backend in 260 bytes. This size can used to allocate
* an array of bytes to store responses and it will be compatible with the two
* backends.
*/
#define MODBUS_MAX_ADU_LENGTH 260
/* Random number to avoid errno conflicts */
#define MODBUS_ENOBASE 112345678
/* Protocol exceptions */
enum {
MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
MODBUS_EXCEPTION_ACKNOWLEDGE,
MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
MODBUS_EXCEPTION_MEMORY_PARITY,
MODBUS_EXCEPTION_NOT_DEFINED,
MODBUS_EXCEPTION_GATEWAY_PATH,
MODBUS_EXCEPTION_GATEWAY_TARGET,
MODBUS_EXCEPTION_MAX
};
#define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
#define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
#define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
#define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
#define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
#define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
#define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
#define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
#define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
/* Native libmodbus error codes */
#define EMBBADCRC (EMBXGTAR + 1)
#define EMBBADDATA (EMBXGTAR + 2)
#define EMBBADEXC (EMBXGTAR + 3)
#define EMBUNKEXC (EMBXGTAR + 4)
#define EMBMDATA (EMBXGTAR + 5)
#define EMBBADSLAVE (EMBXGTAR + 6)
extern const unsigned int libmodbus_version_major;
extern const unsigned int libmodbus_version_minor;
extern const unsigned int libmodbus_version_micro;
typedef struct _modbus modbus_t;
typedef struct _modbus_mapping_t {
int nb_bits;
int start_bits;
int nb_input_bits;
int start_input_bits;
int nb_input_registers;
int start_input_registers;
int nb_registers;
int start_registers;
uint8_t *tab_bits;
uint8_t *tab_input_bits;
uint16_t *tab_input_registers;
uint16_t *tab_registers;
} modbus_mapping_t;
typedef enum
{
MODBUS_ERROR_RECOVERY_NONE = 0,
MODBUS_ERROR_RECOVERY_LINK = (1<<1),
MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
} modbus_error_recovery_mode;
MODBUS_API int modbus_set_slave(modbus_t* ctx, int slave);
MODBUS_API int modbus_get_slave(modbus_t* ctx);
MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
MODBUS_API int modbus_get_socket(modbus_t *ctx);
MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_indication_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
MODBUS_API int modbus_set_indication_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
MODBUS_API int modbus_get_header_length(modbus_t *ctx);
MODBUS_API int modbus_connect(modbus_t *ctx);
MODBUS_API void modbus_close(modbus_t *ctx);
MODBUS_API void modbus_free(modbus_t *ctx);
MODBUS_API int modbus_flush(modbus_t *ctx);
MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);
MODBUS_API const char *modbus_strerror(int errnum);
MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
MODBUS_API int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, const uint16_t value);
MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,
const uint16_t *src, int read_addr, int read_nb,
uint16_t *dest);
MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address(
unsigned int start_bits, unsigned int nb_bits,
unsigned int start_input_bits, unsigned int nb_input_bits,
unsigned int start_registers, unsigned int nb_registers,
unsigned int start_input_registers, unsigned int nb_input_registers);
MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
int nb_registers, int nb_input_registers);
MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
MODBUS_API int modbus_send_raw_request(modbus_t *ctx, const uint8_t *raw_req, int raw_req_length);
MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);
MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req,
int req_length, modbus_mapping_t *mb_mapping);
MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
unsigned int exception_code);
/**
* UTILS FUNCTIONS
**/
#define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
#define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
#define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
(((int64_t)tab_int16[(index) ] << 48) + \
((int64_t)tab_int16[(index) + 1] << 32) + \
((int64_t)tab_int16[(index) + 2] << 16) + \
(int64_t)tab_int16[(index) + 3])
#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
#define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
#define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
do { \
tab_int8[(index)] = (value) >> 8; \
tab_int8[(index) + 1] = (value) & 0xFF; \
} while (0)
#define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
do { \
tab_int16[(index) ] = (value) >> 16; \
tab_int16[(index) + 1] = (value); \
} while (0)
#define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
do { \
tab_int16[(index) ] = (value) >> 48; \
tab_int16[(index) + 1] = (value) >> 32; \
tab_int16[(index) + 2] = (value) >> 16; \
tab_int16[(index) + 3] = (value); \
} while (0)
MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value);
MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
const uint8_t *tab_byte);
MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits);
MODBUS_API float modbus_get_float(const uint16_t *src);
MODBUS_API float modbus_get_float_abcd(const uint16_t *src);
MODBUS_API float modbus_get_float_dcba(const uint16_t *src);
MODBUS_API float modbus_get_float_badc(const uint16_t *src);
MODBUS_API float modbus_get_float_cdab(const uint16_t *src);
MODBUS_API void modbus_set_float(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest);
MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest);
#include "modbus-tcp.h"
#include "modbus-rtu.h"
MODBUS_END_DECLS
#endif /* MODBUS_H */

BIN
src/modbus.lib Normal file

Binary file not shown.

457
thread.cpp Normal file
View File

@ -0,0 +1,457 @@

#include "thread.h"
#include <QModbusRtuSerialMaster>
#include <QModbusDataUnit>
#include <QModbusReply>
#include <QVariant>
#include <QSerialPort>
int index = 0;
extern camera *m_camera;
extern correct *m_correct;
extern uint8_t learning_flag;
extern Process_img * process_img;
cv::Mat mat_1;
cv::Mat mat_2;
cv::Mat img_pop;
extern int save_flag;
int m_index1;
QSemaphore usebuff(0);
QSemaphore read_to_send(0);
//unsigned char *send_buf;
char *recv_buf;
extern uint8_t adjust_correct_flag;
#define WHITE_IMAGE_PATH "C:/Users/USER/Desktop/wood_aduiduiduiplus/build-wooden-Desktop_Qt_5_9_5_MSVC2017_64bit-Release/white"
#define BLACK_IMAGE_PATH "C:/Users/USER/Desktop/wood_aduiduiduiplus/build-wooden-Desktop_Qt_5_9_5_MSVC2017_64bit-Release/black"
#define correct_path "D:/correct.png"
int get_height(cv::Mat img)
{
int b_temp = 0;
float b_avg = 0.0;
int i, j;
for(i = 0; i < img.rows; i++)
{
for(j = 0; j < img.cols; j++)
{
b_temp += (int)img.at<cv::Vec3b>(i, j)[0];
}
b_avg = b_temp / 4096.0f;
if(b_avg == 0)
{
// qDebug() << i;
return i;
}
b_temp = 0;
}
return -1;
}
//采集
void onImageDataCallback(SapXferCallbackInfo *pInfo)
{
qDebug() << "enter to calback" ;
if(pInfo)
{
unsigned char *pData;
int width = m_camera->m_buffer->GetWidth();
int height = m_camera->m_buffer->GetHeight();
qDebug() << "enter to calback: limian";
m_camera->m_buffer->GetAddress((void**)&pData);
cv::Mat img(height, width, CV_8UC3, pData);
img.convertTo(img, CV_32FC3);
m_camera->calibrated_img = (img - m_camera->black_mat) / (m_camera->white_mat - m_camera->black_mat + m_camera->eps);
m_camera->calibrated_img *= 255;
m_camera->calibrated_img.convertTo(m_camera->calibrated_img, CV_8UC3);
m_camera->rgb_height = get_height(img);
// qDebug() << "rgb_height: " << rgb_height;
if(m_camera->rgb_height < 3000 && m_camera->rgb_height > 500 && !adjust_correct_flag)
{
m_camera->imgqueue.push(m_camera->calibrated_img);
// m_camera->imgqueue.push(mat_2);
// emit process_img->show_img(mat_1);
// usebuff.release();
// if(!learning_flag)
// read_to_send.release();
}
else if(adjust_correct_flag)
{
img.convertTo(img, CV_8UC3);
mat_1 = img;
usebuff.release();
}
else if(m_camera->rgb_height == 0 || m_camera->rgb_height == -1)
{
m_camera->m_buffer->Clear();
return;
}
}
}
//校正
void onImageCorrectCallback(SapXferCallbackInfo *pInfo)
{
qDebug() <<"11111111222222222333333333";
qDebug() << " onImageCorrectCallback start ";
//采集黑白帧
if(pInfo)
{
qDebug() << "pInfo";
if( m_camera->capture_black_flag || m_camera->capture_white_flag )
{
qDebug() << "flag";
unsigned char pdata_rgb;
void* pDataAddr_rgb = &pdata_rgb;
m_camera->m_buffer->GetAddress(&pDataAddr_rgb);
cv::Mat img(4096, 3000, CV_8UC3,pDataAddr_rgb);
img.convertTo(img, CV_32FC3);
if( m_camera->capture_black_flag )
{
qDebug() << "capture_black_flag";
m_camera->capture_black_flag = false;
m_camera->black_mat = img;
qDebug() << "img";
FILE* fp = fopen(BLACK_IMAGE_PATH, "wb");
fwrite(m_camera->black_mat.data, 4096*3000*3*4, 1, fp);
fclose(fp);
qDebug() << "black frame acquisition OK!";
}
else if( m_camera->capture_white_flag )
{
m_camera->capture_white_flag = false;
m_camera->white_mat = img;
FILE* fp = fopen(WHITE_IMAGE_PATH, "wb");
fwrite(m_camera->white_mat.data, 4096*3000*3*4, 1, fp);
fclose(fp);
qDebug() << " white frame acquisition OK!";
}
}
}
// Widget::getInstance()->set();
}
Process_img::Process_img(QObject *parent) : QThread(parent), m_stop(false)
{
}
void Process_img::run()
{
qDebug() << "process_imgID: " << currentThreadId();
while(1)
{
stop_mutex.lock();
if(m_stop)
{
stop_mutex.unlock();
qDebug() << "process thread quit______________________";
return;
}
stop_mutex.unlock();
if(m_camera->imgqueue.size()>1)
{
// read_to_send.acquire(); //没有mat_2就阻塞
m_camera->imgqueue.pop();
qDebug()<<"the wood image's queue size: "<<m_camera->imgqueue.size();
img_pop = m_camera->imgqueue.front();
img_pop = m_camera->calibrated_img(cv::Rect(0, 0, 4096, m_camera->rgb_height)); //4096
int save_count = 0;
save_count++;
if(save_flag && save_count == 1)
{
qDebug() << "1111111111111";
// QDateTime time = QDateTime::currentDateTime();
// QString str = time.toString("yyyyMMddhhmmss");
// QString filepath = SAVE_IMAGE_PATH + str + ".png";
// qDebug() << filepath;
// cv::imwrite(filepath.toLatin1().data(), img);
char fileName[64];
sprintf(fileName, "D:/save_image/rgb%d.bmp", m_index1);
m_index1++;
qDebug() << fileName;
cv::imwrite(fileName, img_pop);
save_count = 0;
}
emit process_img->show_img(img_pop);
usebuff.release();
if(!learning_flag)
read_to_send.release();
}
// if(!usebuff.tryAcquire())
// continue;
}
}
void Process_img::exitThread()
{
stop_mutex.lock();
m_stop = true;
stop_mutex.unlock();
}
Adjust_para::Adjust_para(QObject *parent) : QThread(parent), is_stop(false), correct_flag(false)
{
}
void Adjust_para::run()
{
while(1)
{
stop_mutex.lock();
if(is_stop)
{
stop_mutex.unlock();
qDebug() << "adjust thread qiut_______________________";
return;
}
stop_mutex.unlock();
if(!usebuff.tryAcquire())
continue;
qDebug() << "234";
emit(send_image_debug(mat_1));
correct_mutex.lock();
qDebug() << "aabbbbbbbcccccc";
if(correct_flag)
{
cv::imwrite(correct_path, mat_1);
correct_flag = false;
}
correct_mutex.unlock();
}
}
void Adjust_para::get_correct_signal()
{
correct_mutex.lock();
correct_flag = true;
// qDebug() << "llllllllllll";
correct_mutex.unlock();
}
void Adjust_para::exitThread()
{
stop_mutex.lock();
is_stop = true;
stop_mutex.unlock();
}
SendThread::SendThread(QObject *parent) : QThread(parent)
{
}
void SendThread::run()
{
bool is_timeout;
cv::Mat temp_img;
unsigned char* send_buf;
send_server = new QTcpServer();
send_server->listen(QHostAddress::Any, 21122);
qDebug() << "sendthread waiting connect.....";
send_server->waitForNewConnection(50000, &is_timeout);
if(is_timeout)
{
qDebug() << "sendthread time out";
return;
}
send_socket = send_server->nextPendingConnection();
qDebug() << "sendsocket new connection";
while(1)
{
if(!usebuff.tryAcquire())
continue;
read_to_send.acquire();
temp_img = img_pop;
// emit process_img->show_img(img_pop);
send_buf = (uint8_t*)malloc(temp_img.cols * temp_img.rows * 3 + 16);
memset(send_buf, 0, temp_img.cols * temp_img.rows * 3 + 16);
uint16_t width = temp_img.cols;
uint16_t height = temp_img.rows;
uint32_t data_len = width * height * 3 + 8;
//协议
send_buf[0] = 0xAA;
// 总体报文长度
for(int i = 1; i<= 4; i++)
send_buf[i] = (uint8_t)(data_len >> 8 * (4 - i));
// 数据和指令部分
send_buf[5] = ' ';
send_buf[6] = ' ';
send_buf[7] = 'I';
send_buf[8] = 'M';
send_buf[9] = (uint8_t)(height>>8) & 0xFF;
send_buf[10] = (uint8_t)height;
send_buf[11] = (uint8_t)(width>>8) & 0xFF;
send_buf[12] = (uint8_t)width;
memcpy(send_buf + 13, temp_img.data, temp_img.cols*temp_img.rows*3+4);
// 末尾校验位、协议位
send_buf[temp_img.cols * temp_img.rows*3 + 13] = 0xFF;
send_buf[temp_img.cols * temp_img.rows*3 + 14] = 0xFF;
send_buf[temp_img.cols * temp_img.rows*3 + 15] = 0xBB;
send_socket->write((const char*)send_buf, (temp_img.cols * temp_img.rows * 3 + 16)*sizeof(unsigned char));
send_socket->flush();
qDebug() << "====send success====";
free(send_buf);
}
//
}
RecvThread::RecvThread(QObject *parent) : QThread(parent)
{
}
void RecvThread::run()
{
bool is_timeout;
char buf[1100] = {0};
int len = 0;
recv_server = new QTcpServer();
recv_server->listen(QHostAddress::Any, 21123);
qDebug() << "recvthread waiting connect.....";
recv_server->waitForNewConnection(50000, &is_timeout);
if(is_timeout == true)
{
qDebug() << "recvthread time out";
return;
}
recv_socket = recv_server->nextPendingConnection();
qDebug() << "recvthread new connection";
while(1)
{
/***
// memset(buf, 0, 10);
// recv_socket->waitForReadyRead(-1); //没有东西就阻塞
// len = recv_socket->read(buf, 10);
//// emit read_plc();
// if(len < 0)
// {
// qDebug() << "receive data error";
// }
// else
// {
// qDebug() << "receive :" << len;
// FILE* fp;
// fp = fopen("C:/Users/USER/Desktop/1.txt", "a+");
// fwrite(buf, 1, 1, fp);
// fclose(fp);
// }
// emit send_sortingResult(buf);
***/
memset(buf, 0, 1100);//初始化为0
recv_socket->waitForReadyRead(-1);//阻塞
qDebug() << "======receive success======";
len = recv_socket->read(buf, 1100);
qDebug() << "len" << len;
char buf1[1100] = {0};
for(int i = 0; i < 1080; i++)
{
// qDebug() << "buf" << buf[i] << i;
buf1[i] = buf[i+6];
}
if(len < 0)
{
// qDebug() << "receiv data error";
}
else if(len < 10)
{
// qDebug() << "receive:" << len;
emit send_sortingResult(buf);
}
else
{
qDebug() << "KM";
//需要把获得的buf数据发送到showpic里
emit SendPicInfo(buf1);
}
}
}
RestartThread::RestartThread(QObject *parent) : QThread(parent), restr_flag(false)
{
}
void RestartThread::run()
{
while(1)
{
restr_mutex.lock();
if(restr_flag)
{
// restr_mutex.unlock();
m_camera->openCamera();
qDebug() << "aa";
restr_flag = false;
qDebug() << "bb";
}
msleep(1);
restr_mutex.unlock();
msleep(1);
}
}
void RestartThread::restr_fun()
{
restr_mutex.lock();
restr_flag = true;
restr_mutex.unlock();
}

129
thread.h Normal file
View File

@ -0,0 +1,129 @@
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include "opencv2/opencv.hpp"
#include <QDebug>
#include "SapClassBasic.h"
#include "camera.h"
#include <QMutex>
#include <QSemaphore>
#include "correct.h"
#include <QTcpServer>
#include <QTcpSocket>
//#define REALWIDTH 500
//#define READHEIGHT real_height
//#define HEIGHT 500
class QModbusClient;
class QModbusReply;
static int count;
void onImageDataCallback(SapXferCallbackInfo *pInfo);
void onImageCorrectCallback(SapXferCallbackInfo *pInfo);
class Process_img : public QThread
{
Q_OBJECT
private:
QMutex stop_mutex;
bool m_stop;
protected:
void run();
public:
explicit Process_img(QObject *parent = nullptr);
void exitThread();
signals:
void show_img(cv::Mat);
public slots:
};
class Adjust_para: public QThread
{
Q_OBJECT
private:
QMutex stop_mutex;
bool is_stop;
bool correct_flag;
QMutex correct_mutex;
protected:
void run();
public:
explicit Adjust_para(QObject *parent = nullptr);
void exitThread();
signals:
void send_image_debug(cv::Mat);
public slots:
void get_correct_signal();
};
class SendThread: public QThread
{
Q_OBJECT
protected:
void run();
public:
explicit SendThread(QObject *parent = NULL);
QTcpServer *send_server;
QTcpSocket *send_socket;
};
class RecvThread: public QThread
{
Q_OBJECT
protected:
void run();
public:
explicit RecvThread(QObject *parent = NULL);
QTcpServer *recv_server;
QTcpSocket *recv_socket;
public slots:
signals:
void send_sortingResult(char*);
void SendPicInfo(char*);
// void read_plc();
};
class RestartThread: public QThread
{
Q_OBJECT
private:
QMutex restr_mutex;
bool restr_flag;
protected:
void run();
public:
explicit RestartThread(QObject *parent = NULL);
void restr_fun();
};
#endif // THREAD_H

1054
widget.cpp Normal file

File diff suppressed because it is too large Load Diff

109
widget.h Normal file
View File

@ -0,0 +1,109 @@
#ifndef WIDGET_H
#define WIDGET_H
#define WIN32_LEAN_AND_MEAN
#include <QWidget>
#include "camera.h"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/types_c.h"
#include <QPixmap>
#include "correct.h"
#include <QTimer>
#include <QDateTime>
#include <winsock2.h>
#include <iostream>
#include <QVector>
#include "showpic.h"
#pragma comment(lib,"ws2_32.lib")
class QModbusClient;
class QModbusReply;
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void plc_connect();
private slots:
//button
//Tab_1
void btn_Tab1_1_click();
void btn_Tab1_2_click();
//Tab_2
void showlabel(cv::Mat);
void btn_Tab2_start_click();
void btn_Tab2_stop_click();
void btn_Tab2_mainMenu_click();
void showlabelSorting(char*);
void btn_Tab2_autoLearning_click();
void btn_Tab2_light_click();
void btn_Tab2_middle_click();
void btn_Tab2_dark_click();
void on_btn_Tab2_Preprocessing_clicked();
void on_btn_Tab2_show_clicked();
void btn_Tab2_train_click();
void showPic(char*);
//Tab_3
void btn_Tab3_cameraParasettings_click();
void btn_Tab3_mainMenu_click();
void showimage_test(cv::Mat);
void btn_Tab3_saveImg_click();
void btn_Tab3_changeModel_click();
//Tab_4
void btn_Tab4_return_click();
void btn_Tab4_getCorrect_click();
void btn_Tab4_black_click();
void btn_Tab4_white_click();
void btn_Tab4_wbcorrect_click();
void on_btn_Tab2_start_2_clicked();
void on_btn_Tab2_start_3_clicked();
void on_btn_Tab2_start_4_clicked();
void dafei_slot();
//Tab_5
void btn_Tab5_skip_click();
void skip_Notime();
void on_btn_Tab4_exit_clicked();
//picture
void PictureProcess();
private:
Ui::Widget *ui;
Adjust_para * adjust_para;
QPixmap pix;
QPixmap pix_test;
SendThread *send_thread = nullptr;
RecvThread *recv_thread = nullptr;
QTimer *skip;
QTimer* dafei = new QTimer;
void connect_signals();
void init_window();
RestartThread *restart_thread = nullptr;
showpic *pic = nullptr;
signals:
void correct_signal();
};
#endif // WIDGET_H

776
widget.ui Normal file
View File

@ -0,0 +1,776 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1038</width>
<height>701</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<widget class="QTabWidget" name="tabWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1041</width>
<height>701</height>
</rect>
</property>
<property name="font">
<font>
<family>Arial</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(218, 239, 252);</string>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
<widget class="QLabel" name="label_show_welcome">
<property name="geometry">
<rect>
<x>200</x>
<y>90</y>
<width>631</width>
<height>121</height>
</rect>
</property>
<property name="font">
<font>
<family>Arial</family>
<pointsize>72</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color:rgb(0, 0, 0);
background-color: rgb(153, 204, 153);
border-radius: 50px;</string>
</property>
<property name="text">
<string>木地板分选</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab1_1">
<property name="geometry">
<rect>
<x>190</x>
<y>440</y>
<width>211</width>
<height>81</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>36</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(153, 102, 51);
border-radius:20px;
background-color:rgb(170, 214, 255);
border-width:4px; </string>
</property>
<property name="text">
<string>分选页面</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab1_2">
<property name="geometry">
<rect>
<x>630</x>
<y>440</y>
<width>211</width>
<height>81</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>36</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(153, 102, 51);
border-radius:20px;
background-color:rgb(170, 214, 255);
border-width:4px; </string>
</property>
<property name="text">
<string>详细设置</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Tab 2</string>
</attribute>
<widget class="QLabel" name="showlabel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>611</width>
<height>431</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(0, 0, 0);</string>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_start">
<property name="geometry">
<rect>
<x>670</x>
<y>498</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>开始</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_stop">
<property name="geometry">
<rect>
<x>870</x>
<y>498</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>结束</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_mainMenu">
<property name="geometry">
<rect>
<x>40</x>
<y>498</y>
<width>150</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(238, 238, 236);
border-radius:15px;
background-color: rgb(136, 138, 133);
border-width:4px; </string>
</property>
<property name="text">
<string>主菜单</string>
</property>
</widget>
<widget class="QLabel" name="label_showSorting">
<property name="geometry">
<rect>
<x>0</x>
<y>430</y>
<width>611</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<family>Arial</family>
<pointsize>33</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color:rgb(0, 0, 0);
background-color: rgb(153, 204, 153);
border-radius: 50px;</string>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>640</x>
<y>20</y>
<width>381</width>
<height>381</height>
</rect>
</property>
<property name="title">
<string>自学习</string>
</property>
<widget class="QPushButton" name="btn_Tab2_autoLearning">
<property name="geometry">
<rect>
<x>30</x>
<y>50</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>自学习</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_light">
<property name="geometry">
<rect>
<x>30</x>
<y>140</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>保存花纹</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_middle">
<property name="geometry">
<rect>
<x>220</x>
<y>140</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>保存直纹</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_dark">
<property name="geometry">
<rect>
<x>30</x>
<y>230</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>保存深色</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_train">
<property name="geometry">
<rect>
<x>220</x>
<y>310</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>训练模型</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_Preprocessing">
<property name="geometry">
<rect>
<x>220</x>
<y>230</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>17</pointsize>
</font>
</property>
<property name="text">
<string>图片预处理</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_show">
<property name="geometry">
<rect>
<x>30</x>
<y>310</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>17</pointsize>
</font>
</property>
<property name="text">
<string>图片展示</string>
</property>
</widget>
</widget>
<widget class="QPushButton" name="btn_Tab2_start_2">
<property name="geometry">
<rect>
<x>520</x>
<y>580</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>light</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_start_3">
<property name="geometry">
<rect>
<x>670</x>
<y>580</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>middle</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab2_start_4">
<property name="geometry">
<rect>
<x>820</x>
<y>580</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>dark</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>页</string>
</attribute>
<widget class="QLabel" name="label_detailedSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>180</width>
<height>58</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>30</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(238, 238, 236);
background-color: rgb(204, 0, 0);
border-radius:10px;</string>
</property>
<property name="text">
<string>详细设置</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab3_cameraParasettings">
<property name="geometry">
<rect>
<x>210</x>
<y>140</y>
<width>211</width>
<height>61</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(238, 238, 236);
border-radius:10px;
background-color: rgb(136, 138, 133);
font: 24pt &quot;Ubuntu&quot;;
border-width:4px; </string>
</property>
<property name="text">
<string>相机校正</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab3_mainMenu">
<property name="geometry">
<rect>
<x>820</x>
<y>560</y>
<width>150</width>
<height>61</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(238, 238, 236);
border-radius:10px;
background-color: rgb(136, 138, 133);
font: 24pt &quot;Ubuntu&quot;;
border-width:4px; </string>
</property>
<property name="text">
<string>主菜单</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab3_saveImg">
<property name="geometry">
<rect>
<x>570</x>
<y>140</y>
<width>211</width>
<height>61</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(238, 238, 236);
border-radius:10px;
background-color: rgb(136, 138, 133);
font: 24pt &quot;Ubuntu&quot;;
border-width:4px; </string>
</property>
<property name="text">
<string>保存图片</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab3_changeModel">
<property name="geometry">
<rect>
<x>210</x>
<y>260</y>
<width>211</width>
<height>61</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(238, 238, 236);
border-radius:10px;
background-color: rgb(136, 138, 133);
font: 24pt &quot;Ubuntu&quot;;
border-width:4px; </string>
</property>
<property name="text">
<string>切换模型</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>页</string>
</attribute>
<widget class="QPushButton" name="btn_Tab4_return">
<property name="geometry">
<rect>
<x>730</x>
<y>560</y>
<width>261</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(238, 238, 236);
background-color: rgb(136, 138, 133);
border-radius:10px;</string>
</property>
<property name="text">
<string>返回</string>
</property>
</widget>
<widget class="QLabel" name="showlabel_set">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>591</width>
<height>401</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(0, 0, 0);</string>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QLabel" name="label_Tab4_1">
<property name="geometry">
<rect>
<x>150</x>
<y>530</y>
<width>281</width>
<height>101</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>17</pointsize>
</font>
</property>
<property name="text">
<string>亮度值</string>
</property>
</widget>
<widget class="QLabel" name="label_Tab4_2">
<property name="geometry">
<rect>
<x>250</x>
<y>550</y>
<width>141</width>
<height>71</height>
</rect>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab4_black">
<property name="geometry">
<rect>
<x>660</x>
<y>130</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>黑场采集</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab4_white">
<property name="geometry">
<rect>
<x>810</x>
<y>130</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>白场采集</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab4_wbcorrect">
<property name="geometry">
<rect>
<x>810</x>
<y>210</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>黑白校正</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab4_exit">
<property name="geometry">
<rect>
<x>310</x>
<y>430</y>
<width>211</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>停止显示</string>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab4_getCorrect">
<property name="geometry">
<rect>
<x>30</x>
<y>430</y>
<width>211</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>显示图像亮度</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_5">
<attribute name="title">
<string>页</string>
</attribute>
<widget class="QLabel" name="label_show_welcome_2">
<property name="geometry">
<rect>
<x>30</x>
<y>90</y>
<width>971</width>
<height>121</height>
</rect>
</property>
<property name="font">
<font>
<family>Arial</family>
<pointsize>64</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color:rgb(0, 0, 0);
background-color: rgb(153, 204, 153);
border-radius: 50px;</string>
</property>
<property name="text">
<string>木地板颜色分选系统</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_showSorting_2">
<property name="geometry">
<rect>
<x>270</x>
<y>310</y>
<width>441</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<family>Arial</family>
<pointsize>33</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color:rgb(0, 0, 0);
background-color: rgb(255, 192, 203);
border-radius: 50px;</string>
</property>
<property name="text">
<string>光源预热中...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QPushButton" name="btn_Tab5_skip">
<property name="geometry">
<rect>
<x>840</x>
<y>540</y>
<width>121</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>22</pointsize>
</font>
</property>
<property name="text">
<string>忽略</string>
</property>
</widget>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

91
wooden.pro Normal file
View File

@ -0,0 +1,91 @@
#-------------------------------------------------
#
# Project created by QtCreator 2022-03-18T10:12:37
#
#-------------------------------------------------
QT += core gui network serialbus serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = wooden
TEMPLATE = app
LIBS += -Ldll -lws2_32
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp \
camera.cpp \
thread.cpp \
correct.cpp \
src/modbus.c \
src/modbus-data.c \
src/modbus-rtu.c \
src/modbus-tcp.c \
showpic.cpp \
relistwidget_item.cpp \
imagewin.cpp
HEADERS += \
widget.h \
camera.h \
thread.h \
correct.h \
src/modbus.h \
src/modbus-private.h \
src/modbus-rtu.h \
src/modbus-rtu-private.h \
src/modbus-tcp.h \
src/modbus-tcp-private.h \
src/modbus-version.h \
showpic.h \
relistwidget_item.h \
imagewin.h
FORMS += \
widget.ui \
showpic.ui \
imagewin.ui
#LIBS += -LC:/opencv/build/x64/vc15/lib -lopencv_world453
#INCLUDEPATH += C:/opencv/build/include \
# += C:/opencv/build/include/opencv2
#LIBS += -LC:/Users/lzy/Downloads/opencv/build/x64/vc15/lib -lopencv_world453
#INCLUDEPATH += C:/Users/lzy/Downloads/opencv/build/include \
# += C:/Users/lzy/Downloads/opencv/build/include/opencv2
LIBS += -LC:/Users/USER/Downloads/opencv/build/x64/vc15/lib -lopencv_world453
INCLUDEPATH += C:/Users/USER/Downloads/opencv/build/include \
+= C:/Users/USER/Downloads/opencv/build/include/opencv2
LIBS += -L'C:/Program Files/Teledyne DALSA/Sapera/Lib/Win64' -lSapClassBasic
LIBS += -L'C:/Program Files/Teledyne DALSA/Sapera/Lib/Win64' -lcorapi
INCLUDEPATH += 'C:/Program Files/Teledyne DALSA/Sapera/Include'
DEPENDPATH += 'C:/Program Files/Teledyne DALSA/Sapera/Include'
INCLUDEPATH += 'C:/Program Files/Teledyne DALSA/Sapera/Classes/Basic'
DEPENDPATH += 'C:/Program Files/Teledyne DALSA/Sapera/Classes/Basic'
DISTFILES += \
src/modbus.lib

318
wooden.pro.user Normal file
View File

@ -0,0 +1,318 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.5.2, 2024-05-15T16:13:05. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{9e31907b-3cc3-479e-b8f2-f24c1d383612}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt 5.9.5 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt 5.9.5 MSVC2017 64bit</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">qt.595.win64_msvc2017_64_kit</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">1</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/USER/Desktop/wood9.3/build-wooden-Desktop_Qt_5_9_5_MSVC2017_64bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清理</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">D:/522/wood_aduiduiduiplus</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清理</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">C:/Users/USER/Desktop/wood9.3/build-wooden-Desktop_Qt_5_9_5_MSVC2017_64bit-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">构建</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments"/>
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">清理</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">部署</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">在本地部署</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">wooden</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:D:/522/wood_aduiduiduiplus/wooden/wooden.pro</value>
<value type="bool" key="QmakeProjectManager.QmakeRunConfiguration.UseLibrarySearchPath">true</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.CommandLineArguments"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.ProFile">wooden.pro</value>
<value type="bool" key="Qt4ProjectManager.Qt4RunConfiguration.UseDyldImageSuffix">false</value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory.default">D:/522/wood_aduiduiduiplus</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">18</value>
</data>
<data>
<variable>Version</variable>
<value type="int">18</value>
</data>
</qtcreator>