first commit20240712
This commit is contained in:
commit
829412b834
665
camera.cpp
Normal file
665
camera.cpp
Normal file
@ -0,0 +1,665 @@
|
||||
#include "camera.h"
|
||||
#include "thread.h"
|
||||
#include <vector>
|
||||
// 使用std::vector存储所有帧的数据
|
||||
|
||||
//外部引用的标志位 save_flag 存图标志位 RGB 光谱是否需要保存图 (不能单独存一个 RGB 或 光谱 , 只能要存全存 除非再加标志位)
|
||||
//spec_flag 没用到
|
||||
extern int save_flag;
|
||||
extern bool spec_flag;
|
||||
tomato tomato;
|
||||
|
||||
//RGB相机的回调函数
|
||||
void __stdcall onImageDataCallBackFunc(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser);
|
||||
void __stdcall onOfflineCallBackFunc(unsigned int nMsgType, void* pUser);
|
||||
void __stdcall onImageDataCallBackFunc1(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser);
|
||||
void __stdcall onOfflineCallBackFunc1(unsigned int nMsgType, void* pUser);
|
||||
void __stdcall onImageDataCallBackFunc2(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser);
|
||||
void __stdcall onOfflineCallBackFunc2(unsigned int nMsgType, void* pUser);
|
||||
|
||||
//光谱相机的回调函数
|
||||
extern void __stdcall RTRGBViewCallback(void* pContext, unsigned char* pRData, unsigned char* pGData, unsigned char* pBData, unsigned long dataLength);
|
||||
extern void __stdcall RTSpecStreamingCallback(void *pContext, unsigned char *pData, unsigned long dataLength);
|
||||
|
||||
//三个相机是否连接上的标志位 在 initcamera 里面的 opencamera 函数有返回值 负责修改 ui界面的 "是否连接" 标志位
|
||||
int camStatusret;
|
||||
int camStatusret1;
|
||||
int camStatusret2;
|
||||
|
||||
//果蔬标志位
|
||||
extern int fruit_flag;
|
||||
CameraL::CameraL(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
//初始化相机
|
||||
bool CameraL::initCameraL()
|
||||
{
|
||||
/*
|
||||
* 枚举设备
|
||||
* */
|
||||
int device_num = enum_device();
|
||||
qDebug()<<"找到相机: "<<device_num;
|
||||
if(device_num == -1)
|
||||
{
|
||||
qDebug()<<"enum device failed";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(device_num == 0)
|
||||
{
|
||||
qDebug()<<"no camera found";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//print_device_info();
|
||||
bool isOk = select_device();
|
||||
if(!isOk)
|
||||
{
|
||||
qDebug()<<"create handle failed";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
if(camera_handle1 != NULL)
|
||||
{
|
||||
destroy_handle1();
|
||||
}
|
||||
if(camera_handle2 != NULL)
|
||||
{
|
||||
destroy_handle2();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 开启相机
|
||||
* */
|
||||
isOk = open_camera();
|
||||
|
||||
if(!isOk)
|
||||
{
|
||||
qDebug()<<"open camera failed";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
return false;
|
||||
}else{
|
||||
qDebug()<<"打开相机: "<<"isOk: "<<isOk;
|
||||
}
|
||||
|
||||
// set_ROI(0, 0, 2448, 2048);
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//下面是所有 initcamera 函数内调用的函数的具体内容
|
||||
uint32_t CameraL::enum_device()
|
||||
{
|
||||
int ret = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &device_list);
|
||||
if(ret != MV_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return device_list.nDeviceNum;
|
||||
}
|
||||
|
||||
//这里需要注意 因为是三个相机 且有位置顺序 所以需要根据相机的第四位 ip 来确定 (所有相机都必须分配固定ip)
|
||||
//比如相机 ip 为 192.168.2.10 10 则为相机的第四位 ip 如果发现顺序不对,使用MVS软件重新分配固定 ip
|
||||
//200顶部相机 100右侧相机 150左侧相机
|
||||
bool CameraL::select_device()
|
||||
{
|
||||
MV_CC_DEVICE_INFO* pstDeviceInfo;
|
||||
|
||||
|
||||
for(i=0;i<=2;i++)
|
||||
{
|
||||
|
||||
pstDeviceInfo = device_list.pDeviceInfo[i];
|
||||
if (NULL == pstDeviceInfo)
|
||||
{
|
||||
printf("The Pointer of pstMVDevInfo is NULL!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ip4 = pstDeviceInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff;
|
||||
//根据第四位 ip 来创建 camera_handle
|
||||
//camera_handle 相当于 一个指向相机的指针 这个指针就代表相机
|
||||
switch (ip4)
|
||||
{
|
||||
case 100:
|
||||
MV_CC_CreateHandle(&camera_handle1, device_list.pDeviceInfo[i]);
|
||||
break;
|
||||
case 150:
|
||||
MV_CC_CreateHandle(&camera_handle, device_list.pDeviceInfo[i]);
|
||||
break;
|
||||
case 200:
|
||||
MV_CC_CreateHandle(&camera_handle2, device_list.pDeviceInfo[i]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pstDeviceInfo++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::open_camera()
|
||||
{
|
||||
int ret = MV_CC_OpenDevice(camera_handle);
|
||||
int ret1 = MV_CC_OpenDevice(camera_handle1);
|
||||
int ret2 = MV_CC_OpenDevice(camera_handle2);
|
||||
camStatusret2=0;
|
||||
camStatusret1=0;
|
||||
camStatusret=0;
|
||||
if(ret != MV_OK||ret1 != MV_OK||ret2 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
camStatusret2=0;
|
||||
camStatusret1=0;
|
||||
camStatusret=0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::open_camera2()
|
||||
{
|
||||
/*
|
||||
* 导入配置文件(相机)
|
||||
**/
|
||||
bool isOk = import_config_file();
|
||||
// set_ROI(0, 668, 1000, 2448);
|
||||
if(!isOk)
|
||||
{
|
||||
qDebug()<<"import config file failed";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
if(camera_handle1 != NULL)
|
||||
{
|
||||
destroy_handle1();
|
||||
}
|
||||
if(camera_handle2 != NULL)
|
||||
{
|
||||
destroy_handle2();
|
||||
}
|
||||
return false;;
|
||||
}
|
||||
|
||||
isOk = register_image_callback(onImageDataCallBackFunc,onImageDataCallBackFunc1,onImageDataCallBackFunc2);
|
||||
qDebug()<<"注册回调成功: "<<"isOk: "<<isOk;
|
||||
if(!isOk)
|
||||
{
|
||||
qDebug()<<"register image callback function failed";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
if(camera_handle1 != NULL)
|
||||
{
|
||||
destroy_handle1();
|
||||
}
|
||||
if(camera_handle2 != NULL)
|
||||
{
|
||||
destroy_handle2();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isOk = register_offline_callback(onOfflineCallBackFunc,onOfflineCallBackFunc1,onOfflineCallBackFunc2);
|
||||
qDebug()<<"取消注册回调成功: "<<"isOk: "<<isOk;
|
||||
if(!isOk)
|
||||
{
|
||||
qDebug()<<"register offline callback function failed";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
if(camera_handle1 != NULL)
|
||||
{
|
||||
destroy_handle1();
|
||||
}
|
||||
if(camera_handle2 != NULL)
|
||||
{
|
||||
destroy_handle2();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
isOk = set_acquisition_mode();
|
||||
qDebug()<<"设置触发成功: "<<"isOk: "<<isOk;
|
||||
if(!isOk)
|
||||
{
|
||||
qDebug()<<"set acquistion mode failed";
|
||||
if(camera_handle != NULL)
|
||||
{
|
||||
destroy_handle();
|
||||
}
|
||||
if(camera_handle1 != NULL)
|
||||
{
|
||||
destroy_handle1();
|
||||
}
|
||||
if(camera_handle2 != NULL)
|
||||
{
|
||||
destroy_handle2();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// MV_CC_SetBalanceWhiteAuto(camera_handle, 0);
|
||||
// MV_CC_SetBalanceWhiteAuto(camera_handle1, 0);
|
||||
// MV_CC_SetBalanceWhiteAuto(camera_handle2, 0);
|
||||
// MV_CC_SetIntValue(camera_handle, "LineDebouncerTime", 100);
|
||||
// MV_CC_SetIntValue(camera_handle1, "LineDebouncerTime", 100);
|
||||
// MV_CC_SetIntValue(camera_handle2, "LineDebouncerTime", 100);
|
||||
}
|
||||
|
||||
bool CameraL::start_capture()
|
||||
{
|
||||
int ret2 = MV_CC_StartGrabbing(camera_handle2);
|
||||
|
||||
int ret1 = MV_CC_StartGrabbing(camera_handle1);
|
||||
|
||||
int ret = MV_CC_StartGrabbing(camera_handle);
|
||||
if (ret != MV_OK||ret1 != MV_OK||ret2 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::register_image_callback(imageCallbackFunc onImageDataCallBackFunc,imageCallbackFunc onImageDataCallBackFunc1,imageCallbackFunc onImageDataCallBackFunc2)
|
||||
{
|
||||
int ret2 = MV_CC_RegisterImageCallBackForBGR(camera_handle1, onImageDataCallBackFunc1, NULL); //100 right
|
||||
|
||||
int ret1 = MV_CC_RegisterImageCallBackForBGR(camera_handle, onImageDataCallBackFunc2, NULL); //150 left
|
||||
|
||||
int ret = MV_CC_RegisterImageCallBackForBGR(camera_handle2, onImageDataCallBackFunc, NULL); //200 top
|
||||
if (ret != MV_OK||ret1 != MV_OK||ret2 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::register_offline_callback(exceptionCallbackFunc onOfflineCallBackFunc, exceptionCallbackFunc onOfflineCallBackFunc1, exceptionCallbackFunc onOfflineCallBackFunc2)
|
||||
{
|
||||
int nRet1 = MV_CC_RegisterExceptionCallBack(camera_handle, onOfflineCallBackFunc2, NULL);
|
||||
|
||||
int nRet = MV_CC_RegisterExceptionCallBack(camera_handle2, onOfflineCallBackFunc1, NULL);
|
||||
int nRet2 = MV_CC_RegisterExceptionCallBack(camera_handle1, onOfflineCallBackFunc, NULL);
|
||||
if (nRet != MV_OK||nRet1 != MV_OK||nRet2 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::destroy_handle()
|
||||
{
|
||||
int ret = MV_CC_DestroyHandle(camera_handle);
|
||||
if (MV_OK != ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::destroy_handle1()
|
||||
{
|
||||
int ret = MV_CC_DestroyHandle(camera_handle1);
|
||||
if (MV_OK != ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::destroy_handle2()
|
||||
{
|
||||
int ret = MV_CC_DestroyHandle(camera_handle2);
|
||||
if (MV_OK != ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//前面的两个标志位决定导入哪一个相机配置文件
|
||||
bool CameraL::import_config_file()
|
||||
{
|
||||
if(fruit_flag) //百香果
|
||||
{
|
||||
qDebug()<<"import passion camera ini";
|
||||
int ret = MV_CC_FeatureLoad(camera_handle, CAMERApassion_left_config);
|
||||
if(ret != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int ret2 = MV_CC_FeatureLoad(camera_handle2, CAMERAtoppassion_top2_config);
|
||||
if(ret2 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int ret1 = MV_CC_FeatureLoad(camera_handle1, CAMERApassion_right_config);
|
||||
if(ret1 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else //西红柿
|
||||
{
|
||||
qDebug()<<"import tomato camera ini";
|
||||
|
||||
int ret = MV_CC_FeatureLoad(camera_handle, CAMERA_CONFIG_PATH);
|
||||
if(ret != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int ret2 = MV_CC_FeatureLoad(camera_handle2, CAMERA2_CONFIG_PATH);
|
||||
if(ret2 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int ret1 = MV_CC_FeatureLoad(camera_handle1, CAMERAtop_CONFIG_PATH);
|
||||
if(ret1 != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::save_config_file()
|
||||
{
|
||||
int ret = MV_CC_FeatureSave(camera_handle, CAMERA_CONFIG_PATH);
|
||||
if(ret != MV_OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::set_param(Camera_param param_struct)
|
||||
{
|
||||
camera_param = param_struct;
|
||||
int ret = MV_CC_SetIntValue(camera_handle, "BalanceRatio", camera_param.white_balance_ratio);
|
||||
if (ret != MV_OK)
|
||||
{
|
||||
qDebug()<<"white balance ration set failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = MV_CC_SetFloatValue(camera_handle, "ExposureTime", camera_param.exposure_time);
|
||||
if(ret != MV_OK)
|
||||
{
|
||||
qDebug()<<"exposure time set failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = MV_CC_SetFloatValue(camera_handle, "Gain", camera_param.gain);
|
||||
if(ret != MV_OK)
|
||||
{
|
||||
qDebug()<<"gain set failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Camera_param CameraL::get_param()
|
||||
{
|
||||
MVCC_INTVALUE BalanceRatio = {0};
|
||||
int ret = MV_CC_GetIntValue(camera_handle, "BalanceRatio", &BalanceRatio);
|
||||
if (ret == MV_OK)
|
||||
{
|
||||
camera_param.white_balance_ratio = BalanceRatio.nCurValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug()<<"get white balance ratio failed";
|
||||
}
|
||||
|
||||
|
||||
MVCC_FLOATVALUE ExposureTime = {0};
|
||||
ret = MV_CC_GetFloatValue(camera_handle, "ExposureTime", &ExposureTime);
|
||||
if(ret == MV_OK)
|
||||
{
|
||||
camera_param.exposure_time = ExposureTime.fCurValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug()<<"get exposure time failed";
|
||||
}
|
||||
|
||||
MVCC_FLOATVALUE Gain = {0};
|
||||
ret = MV_CC_GetFloatValue(camera_handle, "Gain", &Gain);
|
||||
if(ret == MV_OK)
|
||||
{
|
||||
camera_param.gain = Gain.fCurValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug()<<"get gain failed";
|
||||
}
|
||||
|
||||
#if 1
|
||||
qDebug()<< camera_param.white_balance_ratio;
|
||||
qDebug()<<camera_param.exposure_time;
|
||||
qDebug()<<camera_param.gain;
|
||||
|
||||
#endif
|
||||
|
||||
return camera_param;
|
||||
}
|
||||
/*
|
||||
* TriggerMode 0 OFF
|
||||
* 1 ON
|
||||
*
|
||||
* TriggerSource Line0 0
|
||||
* Line1 1
|
||||
* Line2 2
|
||||
* Line3 3
|
||||
* Counter0 4
|
||||
* Software 7
|
||||
* FrequencyConverter 8
|
||||
*TriggerActivation 0:RisingEdge
|
||||
1:FallingEdge
|
||||
2:LevelHigh
|
||||
3:LevelLow
|
||||
AcquisitionMode 0:SingleFrame
|
||||
1:MultiFrame
|
||||
2:Continuous
|
||||
* */
|
||||
bool CameraL::set_acquisition_mode()
|
||||
{
|
||||
int ret = MV_CC_SetEnumValue(camera_handle, "TriggerMode", 1);
|
||||
int ret1 = MV_CC_SetEnumValue(camera_handle1, "TriggerMode",1);
|
||||
int ret2 = MV_CC_SetEnumValue(camera_handle2, "TriggerMode", 1);
|
||||
if(MV_OK != ret || MV_OK != ret1 ||MV_OK != ret2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret3 = MV_CC_SetEnumValue(camera_handle, "TriggerSource",0);
|
||||
int ret4 = MV_CC_SetEnumValue(camera_handle1, "TriggerSource", 0);
|
||||
int ret5 = MV_CC_SetEnumValue(camera_handle2, "TriggerSource", 0);
|
||||
if(MV_OK != ret3 || MV_OK != ret4 ||MV_OK != ret5)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret6 = MV_CC_SetEnumValue(camera_handle, "TriggerActivation", 0);
|
||||
int ret7 = MV_CC_SetEnumValue(camera_handle1, "TriggerActivation", 0);
|
||||
int ret8 = MV_CC_SetEnumValue(camera_handle2, "TriggerActivation", 0);
|
||||
if(MV_OK != ret6 || MV_OK != ret7 ||MV_OK != ret8)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret9 = MV_CC_SetEnumValue(camera_handle, "AcquisitionMode", 2); //采集模式连续
|
||||
int ret10 = MV_CC_SetEnumValue(camera_handle1, "AcquisitionMode", 2);
|
||||
int ret11 = MV_CC_SetEnumValue(camera_handle2, "AcquisitionMode", 2);
|
||||
if(MV_OK != ret9 || MV_OK != ret10 ||MV_OK != ret11)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CameraL::stop_capture()
|
||||
{
|
||||
int ret = MV_CC_StopGrabbing(camera_handle);
|
||||
int ret1 = MV_CC_StopGrabbing(camera_handle1);
|
||||
int ret2 = MV_CC_StopGrabbing(camera_handle2);
|
||||
if(MV_OK!=ret){
|
||||
destroy_handle();
|
||||
}
|
||||
if(MV_OK!=ret1){
|
||||
destroy_handle1();
|
||||
}
|
||||
if(MV_OK!=ret2){
|
||||
destroy_handle2();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//光谱相机的所有函数
|
||||
SpecCamera::SpecCamera(QObject *parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//初始化相机
|
||||
bool SpecCamera::init_SpecCamera()
|
||||
{
|
||||
//打开相机
|
||||
int ires = RTOpenCamera();
|
||||
qDebug()<<"ires: "<<ires;
|
||||
if (ires != 1)
|
||||
{
|
||||
printf("Open Camera failed!");
|
||||
return false;
|
||||
}
|
||||
//获取当前系统相机参数
|
||||
m_uiDepth = RTGetCameraDepth(); //获取相机图像最大值(256/4096/65536)
|
||||
RTGetImageProperty(m_iWidth, m_iHeight); //获取图像宽、高
|
||||
m_pusSaveBuffer = new unsigned short[m_iHeight*((m_iWidth * 3 + 3) / 4 * 4)];
|
||||
m_pRefreshBuffer = new unsigned char[m_iHeight*((m_iWidth * 3 + 3) / 4 * 4)];
|
||||
|
||||
|
||||
RTGetCameraGain(m_fGain);
|
||||
RTGetExposure(m_fExpTime);
|
||||
RTGetCameraFrameRate(m_iFrameRate);
|
||||
RTGetMinAndMaxWavelength(m_fWaveLengthMin, m_fWaveLengthMax);
|
||||
|
||||
RTGetRGBselect(m_cslRed, m_cslGreen, m_cslBlue);
|
||||
|
||||
|
||||
RTSetExposure(m_fExpTime);
|
||||
RTSetCameraGain(m_fGain);
|
||||
RTSetCameraFrameRate(m_iFrameRate);
|
||||
RTApplyCameraParam();
|
||||
if (m_cslRed > m_iHeight || m_cslGreen > m_iHeight || m_cslBlue > m_iHeight
|
||||
|| m_cslRed <= 0 || m_cslGreen <= 0 || m_cslBlue <= 0)
|
||||
{
|
||||
m_cslRed = m_iHeight * 3 / 4;
|
||||
m_cslGreen = m_iHeight / 2;
|
||||
m_cslBlue = m_iHeight / 4;
|
||||
}
|
||||
RTSetRGBselect(m_cslRed, m_cslGreen, m_cslBlue);
|
||||
RTAddRGBCallback(RTRGBViewCallback, nullptr);
|
||||
RTAddStreamingCallback(RTSpecStreamingCallback,nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
//这个 cal 函数 是光谱相机的回调函数内触发的一个槽函数 可以在 thread 里面的光谱相机的回调找到
|
||||
bool SpecCamera::cal(unsigned char *pData)
|
||||
{
|
||||
test_count++;
|
||||
//假设筛选后的ROI 为 30 * 100 宽 * 谱段数
|
||||
//按右上角为数据初始点 900像素点 每一行第 900 个像素点 第 73 个谱段
|
||||
|
||||
|
||||
|
||||
unsigned short* spec_total_data = new unsigned short[30 * 13]; //宽 * 谱段数
|
||||
|
||||
unsigned short* spec_short_data = (unsigned short *)pData;
|
||||
int Band[13]={8,9,10,48,49,50,77,80,103,108,115,143,145};
|
||||
for(int k=0;k<13;k++)
|
||||
{
|
||||
memcpy(spec_total_data + k * 30, spec_short_data + 900 + (Band[k] - 1) * 2048, 30 * sizeof(unsigned short));
|
||||
}
|
||||
if (test_count < 26)
|
||||
{
|
||||
SpecData_vector.push_back(spec_total_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] spec_total_data; // 释放内存以防止内存泄漏
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//光谱相机内置函数 不用管
|
||||
bool SpecCamera::stop_capture()
|
||||
{
|
||||
if (RTIsCameraWorking())
|
||||
{
|
||||
RTStopSingleCapture();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpecCamera::trigger_open()
|
||||
{
|
||||
bool ret = RT_SetBool(L"Camera.TriggerIn", true); //设置相机外触发
|
||||
|
||||
if(ret==false)
|
||||
{
|
||||
qDebug()<<"trigger is not open:"<<ret;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug()<<"trigger is open:"<<ret;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpecCamera::start_capture()
|
||||
{
|
||||
trigger_open();
|
||||
bool flag = RTStartSingleCapture(false, false, "E:/QT/projects/tomato20240415/tomato04150955/image/newdata.raw");
|
||||
if (!flag)
|
||||
{
|
||||
printf("erro to start capture");
|
||||
return 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
179
camera.h
Normal file
179
camera.h
Normal file
@ -0,0 +1,179 @@
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include <QObject>
|
||||
#include "MvCameraControl.h"
|
||||
#include "SpectrolDll.h"
|
||||
#include "QDebug"
|
||||
#include "QImage"
|
||||
#include <queue>
|
||||
typedef void(*imageCallbackFunc)(unsigned char * , MV_FRAME_OUT_INFO_EX* , void* );
|
||||
typedef void(*exceptionCallbackFunc)(unsigned int , void* );
|
||||
|
||||
//三个相机的配置文件位置 也是绝对路径
|
||||
//三个相机用6个配置文件原因 :百香果的相机参数是700曝光 番茄的相机参数是1500曝光 所以不同的果蔬对应不同的相机参数
|
||||
#define CAMERApassion_left_config "./CameraConfig/PFleft.mfs"
|
||||
#define CAMERApassion_right_config "./CameraConfig/PFright.mfs"
|
||||
#define CAMERAtoppassion_top2_config "./CameraConfig/PFtop.mfs"
|
||||
|
||||
#define CAMERA_CONFIG_PATH "./CameraConfig/tomatoLeft.mfs"
|
||||
#define CAMERA2_CONFIG_PATH "./CameraConfig/tomatoTop.mfs"
|
||||
#define CAMERAtop_CONFIG_PATH "./CameraConfig/tomatoRight.mfs"
|
||||
|
||||
class tomato
|
||||
{
|
||||
public:
|
||||
unsigned int count=0;
|
||||
QImage img1;
|
||||
QImage img2;
|
||||
QImage img3;
|
||||
QImage img4;
|
||||
QImage img5;
|
||||
};
|
||||
|
||||
//相机的参数
|
||||
struct Camera_param //相机参数在此添加,在构造函数中给出默认值,设置参数需要刷新,左侧
|
||||
{
|
||||
float exposure_time;
|
||||
float gain;
|
||||
int white_balance_ratio;
|
||||
//... other params
|
||||
};
|
||||
|
||||
struct Camera_paramR //相机参数在此添加,在构造函数中给出默认值,设置参数需要刷新,右侧
|
||||
{
|
||||
float exposure_time;
|
||||
float gain;
|
||||
int white_balance_ratio;
|
||||
//... other params
|
||||
};
|
||||
|
||||
struct Camera_paramTop //相机参数在此添加,在构造函数中给出默认值,设置参数需要刷新,顶部
|
||||
{
|
||||
float exposure_time;
|
||||
float gain;
|
||||
int white_balance_ratio;
|
||||
//... other params
|
||||
};
|
||||
|
||||
//创建相机类 所有相机有关的函数、参数都在这里
|
||||
class CameraL : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
void* camera_handle; //设备句柄
|
||||
void* camera_handle1;
|
||||
void* camera_handle2;
|
||||
MV_CC_DEVICE_INFO_LIST device_list; //设备列表
|
||||
Camera_param camera_param;
|
||||
unsigned int ip4; //用于保存ipv4地址的第4位,即192.168.0.100中的100
|
||||
int i;
|
||||
public:
|
||||
explicit CameraL(QObject *parent = nullptr);
|
||||
bool initCameraL();
|
||||
uint32_t enum_device();
|
||||
bool print_device_info();
|
||||
bool select_device();
|
||||
|
||||
|
||||
bool destroy_handle();
|
||||
bool destroy_handle1();
|
||||
bool destroy_handle2();
|
||||
|
||||
|
||||
|
||||
bool open_camera(); //初始化中的打开
|
||||
|
||||
bool open_camera2(); //与开始采集关联
|
||||
bool start_capture();
|
||||
bool close_camera();
|
||||
bool set_acquisition_mode();
|
||||
bool set_test_acquisition_mode();
|
||||
bool set_ROI(int offset_x, int offset_y, int width, int height);
|
||||
bool stop_capture();
|
||||
bool register_image_callback(imageCallbackFunc onImageDataCallBackFunc,imageCallbackFunc onImageDataCallBackFunc1,imageCallbackFunc onImageDataCallBackFunc2);
|
||||
bool register_offline_callback(exceptionCallbackFunc onOfflineCallBackFunc,exceptionCallbackFunc onOfflineCallBackFunc1,exceptionCallbackFunc onOfflineCallBackFunc2);
|
||||
|
||||
bool import_config_file();
|
||||
bool save_config_file();
|
||||
bool set_param(Camera_param value);
|
||||
Camera_param get_param();
|
||||
std::queue<QImage> leftImgQueue;
|
||||
std::queue<QImage> rightImgQueue;
|
||||
std::queue<QImage> topImgQueue;
|
||||
std::queue<QImage> topImgTQueue;
|
||||
std::queue<QImage> topImgMQueue;
|
||||
std::queue<QImage> topImgBQueue;
|
||||
std::queue<tomato> tomatoQueue;
|
||||
|
||||
//信号 信号跟槽函数
|
||||
signals:
|
||||
// void send_RgbimageL(cv::Mat img,unsigned int count);
|
||||
void send_Rgbimage(QImage& img);
|
||||
void send_Rgbimage1(QImage& img);
|
||||
|
||||
void send_Rgbimage2(QImage& img,QImage& img1,QImage& img2);
|
||||
|
||||
void send_camerastatus(int ret,int ret1,int ret2);
|
||||
|
||||
|
||||
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
//光谱相机类
|
||||
class SpecCamera : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpecCamera(QObject *parent = nullptr);
|
||||
bool init_SpecCamera();
|
||||
bool cal(unsigned char* pData);
|
||||
bool stop_capture();
|
||||
bool trigger_open();
|
||||
int m_iWidth; //相机采集数据宽度
|
||||
int m_iHeight; //相机采集数据高度
|
||||
unsigned short* specfullImage;
|
||||
const int totalFrames = 30; // 假设需要拼接30帧来形成一张图
|
||||
// std::vector<unsigned short*> frameData;
|
||||
int vector_flag;
|
||||
// int nsize = 35*25*13;
|
||||
std::vector<unsigned short*> SpecData_vector;//给容器开辟空间
|
||||
int test_count = 0;
|
||||
//CameraSetting
|
||||
float m_fWaveLengthMin; //起点光谱波长
|
||||
float m_fWaveLengthMax; //终点光谱波长
|
||||
float m_fExpTime; //曝光时间
|
||||
float m_fGain; //增益
|
||||
|
||||
float m_iFrameRate; //帧速
|
||||
|
||||
//GenralSetting
|
||||
int m_cslRed; //红色波长序号
|
||||
int m_cslGreen; //绿色波长序号
|
||||
int m_cslBlue; //蓝色波长序号
|
||||
unsigned int m_uiDepth;
|
||||
|
||||
unsigned short* m_pusSaveBuffer;
|
||||
unsigned char* m_pRefreshBuffer; //RGB
|
||||
|
||||
unsigned char* m_specBuffer; //光谱
|
||||
|
||||
long m_iDrawCount = 0;
|
||||
|
||||
|
||||
bool start_capture();
|
||||
std::queue<unsigned short*> specImgQueue;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
signals:
|
||||
void show_SpecImg(QImage);
|
||||
|
||||
|
||||
|
||||
};
|
||||
#endif // CAMERA_H
|
||||
BIN
debug/tomato1227.exe
Normal file
BIN
debug/tomato1227.exe
Normal file
Binary file not shown.
16
main.cpp
Normal file
16
main.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "widget.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
try {
|
||||
Widget w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
} catch (const ExpiredException& e) {
|
||||
QMessageBox::critical(nullptr, "程序过期", e.what());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
233
src/modbus-data.c
Normal file
233
src/modbus-data.c
Normal 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
116
src/modbus-private.h
Normal 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
76
src/modbus-rtu-private.h
Normal 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
1299
src/modbus-rtu.c
Normal file
File diff suppressed because it is too large
Load Diff
42
src/modbus-rtu.h
Normal file
42
src/modbus-rtu.h
Normal 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
44
src/modbus-tcp-private.h
Normal 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
929
src/modbus-tcp.c
Normal 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
52
src/modbus-tcp.h
Normal 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
53
src/modbus-version.h
Normal 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
1911
src/modbus.c
Normal file
File diff suppressed because it is too large
Load Diff
293
src/modbus.h
Normal file
293
src/modbus.h
Normal 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 */
|
||||
716
thread.cpp
Normal file
716
thread.cpp
Normal file
@ -0,0 +1,716 @@
|
||||
#include "thread.h"
|
||||
#include "camera.h"
|
||||
#include "QMutex"
|
||||
#include "QSemaphore"
|
||||
#include <QtEndian> // 引入Qt处理字节序的头文件
|
||||
#include <QBuffer>
|
||||
#include "QTimer"
|
||||
#include <QTime>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
QImage image[5];
|
||||
|
||||
//三个线程实例化对象
|
||||
ProcessImg *processimg;
|
||||
SendThread *sendthread;
|
||||
RecvThread *recvthread;
|
||||
|
||||
QMutex judge_connect_mutex;
|
||||
|
||||
//RGB相机类跟光谱相机类实例化对象
|
||||
CameraL *cameraL;
|
||||
SpecCamera *speccamera;
|
||||
|
||||
bool is_connected;
|
||||
extern tomato tomato;
|
||||
|
||||
//TCP协议
|
||||
extern QTcpServer server;
|
||||
extern QTcpSocket *clientSocket;
|
||||
extern int start_flag;
|
||||
|
||||
bool spec_flag = 0;
|
||||
extern bool is_timeout;
|
||||
extern modbus_t* CZ;
|
||||
QMutex imgR_muex;
|
||||
|
||||
//外部引用管道
|
||||
HANDLE hPipe;
|
||||
HANDLE specPipe;
|
||||
HANDLE RPipe;
|
||||
QString pipeName = "\\\\.\\pipe\\rgb_receive";
|
||||
QString pipeName2 = "\\\\.\\pipe\\spec_receive";
|
||||
QString rePipe = "\\\\.\\pipe\\rgb_send";
|
||||
|
||||
extern int save_flag;
|
||||
extern int fruit_flag;
|
||||
uint countimgR = 1;
|
||||
uint countimgL = 1;
|
||||
uint countimgTopT = 1;
|
||||
uint countimgTopM = 1;
|
||||
uint countimgTopB = 1;
|
||||
|
||||
int ImgQueue_Alignment = 1;
|
||||
//右侧相机回调
|
||||
extern void __stdcall onImageDataCallBackFunc1(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser)
|
||||
{
|
||||
|
||||
if (pFrameInfo) //帧信息有效
|
||||
{
|
||||
|
||||
|
||||
|
||||
//img 原始图
|
||||
QImage img(pData,pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888); //构造图像
|
||||
//复制临时图 为了后续处理
|
||||
QImage tempimg = img;
|
||||
tempimg = tempimg.rgbSwapped();
|
||||
QImage queueImg = tempimg;
|
||||
QString filePath = "./image/R";
|
||||
QString imagePath = QString("%1/%2.bmp").arg(filePath).arg(countimgR);
|
||||
if(save_flag)
|
||||
{
|
||||
tempimg.save(imagePath);
|
||||
}
|
||||
|
||||
emit cameraL->send_Rgbimage(tempimg);
|
||||
countimgR++;
|
||||
// cameraL->rightImgQueue.push(queueImg);
|
||||
// qDebug()<<"右侧相机队列长度: "<<cameraL->rightImgQueue.size();
|
||||
|
||||
}
|
||||
return ;
|
||||
|
||||
}
|
||||
|
||||
extern void __stdcall onOfflineCallBackFunc1(unsigned int nMsgType, void* pUser)
|
||||
{
|
||||
//qDebug()<<"camera offline";
|
||||
judge_connect_mutex.lock();
|
||||
is_connected = false;
|
||||
judge_connect_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
//左侧相机回调
|
||||
extern void __stdcall onImageDataCallBackFunc2(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser)
|
||||
{
|
||||
if (pFrameInfo)
|
||||
{
|
||||
// qDebug()<<"左侧相机帧号: "<<pFrameInfo->nFrameNum;
|
||||
QImage imgL(pData,pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888);
|
||||
|
||||
QImage tempimg = imgL;
|
||||
tempimg = tempimg.rgbSwapped();
|
||||
QImage queueImg = tempimg;
|
||||
QString filePath = "./image/L";
|
||||
QString imagePath = QString("%1/%2.bmp").arg(filePath).arg(countimgL);
|
||||
if(save_flag)
|
||||
{
|
||||
tempimg.save(imagePath);
|
||||
}
|
||||
|
||||
countimgL++;
|
||||
|
||||
emit cameraL->send_Rgbimage1(tempimg);
|
||||
|
||||
// cameraL->leftImgQueue.push(queueImg);
|
||||
// qDebug()<<"左侧相机队列长度: "<<cameraL->leftImgQueue.size();
|
||||
|
||||
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
extern void __stdcall onOfflineCallBackFunc2(unsigned int nMsgType, void* pUser)
|
||||
{
|
||||
judge_connect_mutex.lock();
|
||||
is_connected = false;
|
||||
judge_connect_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
//顶部相机回调(ip[4] 200) 数据指针 数据是8位 图像默认格式是BGR 当前帧的结构体
|
||||
extern void __stdcall onImageDataCallBackFunc(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser)
|
||||
{
|
||||
|
||||
if (pFrameInfo) //帧信息有效
|
||||
{
|
||||
qDebug()<<"彩色相机触发次数:"<<countimgTopT;
|
||||
|
||||
QImage imgT(pData,pFrameInfo->nWidth,pFrameInfo->nHeight,QImage::Format_RGB888); //构造图像
|
||||
|
||||
/*
|
||||
* 裁切图片三等分
|
||||
* */
|
||||
int width = imgT.width();
|
||||
int height = imgT.height();
|
||||
int partHeight = height / 3;
|
||||
|
||||
QImage topPart = imgT.copy(0, 0, width, partHeight);
|
||||
QImage middlePart = imgT.copy(0, partHeight, width, partHeight);
|
||||
QImage bottomPart = imgT.copy(0, 2 * partHeight, width, partHeight);
|
||||
|
||||
/*
|
||||
* 颜色转换+存图
|
||||
* */
|
||||
QImage tempimg = bottomPart;
|
||||
tempimg = tempimg.rgbSwapped();
|
||||
QImage queueImg = tempimg;
|
||||
QString filePath = "./image/T/bottom";
|
||||
QString imagePath = QString("%1/%2.bmp").arg(filePath).arg(countimgTopB);
|
||||
if(save_flag)
|
||||
{
|
||||
tempimg.save(imagePath);
|
||||
|
||||
}
|
||||
countimgTopB++;
|
||||
|
||||
QImage tempimg1 = middlePart;
|
||||
tempimg1 = tempimg1.rgbSwapped();
|
||||
QImage queueImg1 = tempimg1;
|
||||
QString filePath1 = "./image/T/middle";
|
||||
QString imagePath1 = QString("%1/%2.bmp").arg(filePath1).arg(countimgTopM);
|
||||
if(save_flag)
|
||||
{
|
||||
tempimg1.save(imagePath1);
|
||||
}
|
||||
|
||||
countimgTopM++;
|
||||
|
||||
QImage tempimg2 = topPart;
|
||||
tempimg2 = tempimg2.rgbSwapped();
|
||||
QImage queueImg2 = tempimg2;
|
||||
QString filePath2 = "./image/T/top";
|
||||
QString imagePath2 = QString("%1/%2.bmp").arg(filePath2).arg(countimgTopT);
|
||||
if(save_flag)
|
||||
{
|
||||
tempimg2.save(imagePath2);
|
||||
}
|
||||
|
||||
countimgTopT++;
|
||||
|
||||
emit cameraL->send_Rgbimage2(tempimg,tempimg1,tempimg2);
|
||||
|
||||
cameraL->topImgTQueue.push(queueImg);
|
||||
cameraL->topImgMQueue.push(queueImg1);
|
||||
cameraL->topImgBQueue.push(queueImg2);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
extern void __stdcall onOfflineCallBackFunc(unsigned int nMsgType, void* pUser)
|
||||
{
|
||||
//qDebug()<<"camera offline";
|
||||
judge_connect_mutex.lock();
|
||||
is_connected = false;
|
||||
judge_connect_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
int spec_count;
|
||||
//光谱相机的回调函数 拿到数据后触发信号 并转到曹函数 cal() 处理数据 如果放在回调处理数据会很慢
|
||||
void __stdcall RTSpecStreamingCallback(void *pContext, unsigned char *pData, unsigned long dataLength)
|
||||
{
|
||||
if(pData)
|
||||
{
|
||||
// spec_count++;
|
||||
// qDebug()<<"光谱相机触发次数:"<<spec_count;
|
||||
if(fruit_flag)
|
||||
{
|
||||
speccamera->cal(pData);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
pData = nullptr;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//显示光谱伪彩色 不用管
|
||||
void __stdcall RTRGBViewCallback(void* pContext, unsigned char* pRData, unsigned char* pGData, unsigned char* pBData, unsigned long dataLength)
|
||||
{
|
||||
unsigned short* pShortRData = (unsigned short*)pRData;
|
||||
unsigned short* pShortGData = (unsigned short*)pGData;
|
||||
unsigned short* pShortBData = (unsigned short*)pBData;
|
||||
|
||||
unsigned short m_usCurrentMax = 1;
|
||||
unsigned short m_usCurrentMin = 65535;
|
||||
|
||||
for (int i = 0; i < speccamera->m_iWidth; i++) //拉伸
|
||||
{
|
||||
if (pShortRData[i] > m_usCurrentMax)
|
||||
m_usCurrentMax = pShortRData[i];
|
||||
if (pShortGData[i] > m_usCurrentMax)
|
||||
m_usCurrentMax = pShortGData[i];
|
||||
if (pShortBData[i] > m_usCurrentMax)
|
||||
m_usCurrentMax = pShortBData[i];
|
||||
if (pShortRData[i] < m_usCurrentMin)
|
||||
m_usCurrentMin = pShortRData[i];
|
||||
if (pShortGData[i] < m_usCurrentMin)
|
||||
m_usCurrentMin = pShortGData[i];
|
||||
if (pShortBData[i] < m_usCurrentMin)
|
||||
m_usCurrentMin = pShortBData[i];
|
||||
}
|
||||
int iLineByte = (speccamera->m_iWidth * 3 + 3) / 4 * 4; //字节对齐
|
||||
memcpy(speccamera->m_pusSaveBuffer, speccamera->m_pusSaveBuffer + iLineByte, (speccamera->m_iHeight - 1)*iLineByte*sizeof(unsigned short));
|
||||
for (int i = speccamera->m_iWidth - 1; i >= 0; i = i - 1)
|
||||
{
|
||||
int sel = (speccamera->m_iHeight - 1)* iLineByte + i * 3;
|
||||
if (sel < iLineByte * speccamera->m_iHeight )
|
||||
{
|
||||
speccamera->m_pusSaveBuffer[sel + 2] = pShortRData[i];
|
||||
speccamera->m_pusSaveBuffer[sel + 1] = pShortGData[i];
|
||||
speccamera->m_pusSaveBuffer[sel + 0] = pShortBData[i];
|
||||
}
|
||||
} //拷贝
|
||||
speccamera->m_iDrawCount++;
|
||||
|
||||
|
||||
// qDebug()<<"speccamera->m_iDrawCount: "<<speccamera->m_iDrawCount;
|
||||
for (int i = 0; i < speccamera->m_iHeight; i++)
|
||||
{
|
||||
for (int j = 0; j < speccamera->m_iWidth; j++)
|
||||
{
|
||||
if (m_usCurrentMax - m_usCurrentMin*0.9 == 0)
|
||||
{
|
||||
speccamera->m_pRefreshBuffer[i*iLineByte+j*3 + 0] = 0;
|
||||
speccamera->m_pRefreshBuffer[i*iLineByte+j*3 + 1] = 0;
|
||||
speccamera->m_pRefreshBuffer[i*iLineByte+j*3 + 2] = 0;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
speccamera->m_pRefreshBuffer[i*iLineByte+j*3 + 0] = (speccamera->m_pusSaveBuffer[i*iLineByte+j*3 + 2]-m_usCurrentMin*0.9)*255.0/(m_usCurrentMax-m_usCurrentMin*0.9);
|
||||
speccamera->m_pRefreshBuffer[i*iLineByte+j*3 + 1] = (speccamera->m_pusSaveBuffer[i*iLineByte+j*3 + 1]-m_usCurrentMin*0.9)*255.0/(m_usCurrentMax-m_usCurrentMin*0.9);
|
||||
speccamera->m_pRefreshBuffer[i*iLineByte+j*3 + 2] = (speccamera->m_pusSaveBuffer[i*iLineByte+j*3 + 0]-m_usCurrentMin*0.9)*255.0/(m_usCurrentMax-m_usCurrentMin*0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QImage image(speccamera->m_pRefreshBuffer,speccamera->m_iWidth, speccamera->m_iHeight, QImage::Format_RGB888);
|
||||
// speccamera->specImgQueue.push(speccamera->m_pRefreshBuffer);
|
||||
|
||||
emit speccamera->show_SpecImg(image);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ProcessImg::ProcessImg(QObject *parent) : QThread(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ProcessImg::~ProcessImg()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ProcessImg::exitThread()
|
||||
{
|
||||
stop_mutex.lock();
|
||||
m_stop = true;
|
||||
stop_mutex.unlock();
|
||||
}
|
||||
|
||||
//光谱数据处理线程 当 槽函数 cal() 收集到指定数量的照片 也就是 满足 if (speccamera->frameData.size() == speccamera->totalFrames)
|
||||
//就会进行处理
|
||||
void ProcessImg::run()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
// 检查是否已收集到足够的帧
|
||||
if (speccamera->SpecData_vector.size() == 25)
|
||||
{
|
||||
// 处理这些帧,例如拼接成一张大图
|
||||
// qDebug()<<"25行光谱图开始拼接、存队列";
|
||||
spec_count++;
|
||||
msleep(100);
|
||||
speccamera->test_count = 0;
|
||||
// qDebug()<<"光谱相机触发次数"<<spec_count;
|
||||
|
||||
speccamera->specfullImage = new unsigned short[30 * 25 * 13];//宽 * 高 * 谱段数
|
||||
|
||||
|
||||
for (int i = 0; i < 25; i++)
|
||||
{
|
||||
// qDebug()<<"容量:"<<speccamera->SpecData_vector.capacity();
|
||||
// qDebug()<<"容量实际大小:"<<speccamera->SpecData_vector.size();
|
||||
memcpy(speccamera->specfullImage + i * 30 * 13, speccamera->SpecData_vector[i], 30 * 13 * sizeof(unsigned short));
|
||||
}
|
||||
speccamera->specImgQueue.push(speccamera->specfullImage);
|
||||
// qDebug()<<"光谱入队成功";
|
||||
|
||||
if(save_flag)
|
||||
{
|
||||
static int file_index = 1;
|
||||
std::string spec_filename = "./image/specImg/spec" + std::to_string(file_index);
|
||||
FILE *fp = fopen(spec_filename.c_str(), "wb");
|
||||
int ret = fwrite(speccamera->specfullImage, 1, 30 * 25 * 13 * sizeof(unsigned short), fp);
|
||||
std::fflush(fp);
|
||||
fclose(fp);
|
||||
file_index++;
|
||||
qDebug()<<"save img success";
|
||||
qDebug()<<"test_count: "<<speccamera->test_count;
|
||||
}
|
||||
|
||||
speccamera->SpecData_vector.clear();
|
||||
speccamera->test_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//接收线程
|
||||
RecvThread::RecvThread(QObject *parent) : QThread(parent)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
RecvThread::~RecvThread()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//通过 pipe 管道 从python端读取数据
|
||||
void RecvThread::run()
|
||||
{
|
||||
|
||||
|
||||
|
||||
while (1)
|
||||
{
|
||||
// 读取4字节的数据长度信息
|
||||
DWORD bytesRead;
|
||||
quint32 dataLength;
|
||||
QByteArray lengthBytes(4, 0);
|
||||
|
||||
|
||||
|
||||
BOOL success = ReadFile(RPipe, lengthBytes.data(), 4, &bytesRead, NULL);
|
||||
if (!success || bytesRead != 4)
|
||||
{
|
||||
qDebug() << "Failed to read length from pipe:" << GetLastError();
|
||||
CloseHandle(RPipe);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QDataStream lengthStream(lengthBytes);
|
||||
lengthStream.setByteOrder(QDataStream::BigEndian);
|
||||
lengthStream >> dataLength;
|
||||
|
||||
// qDebug() << "应该接收到的数据长度:" << dataLength;
|
||||
|
||||
// 根据读取到的数据长度,读取对应长度的数据
|
||||
QByteArray data(dataLength, 0);
|
||||
success = ReadFile(RPipe, data.data(), dataLength, &bytesRead, NULL);
|
||||
if (!success || bytesRead != dataLength) {
|
||||
qDebug() << "Failed to read data from pipe:" << GetLastError();
|
||||
CloseHandle(RPipe);
|
||||
return;
|
||||
}
|
||||
|
||||
// qDebug() << "接收到的数据长度:" << bytesRead;
|
||||
|
||||
// 解析数据
|
||||
QDataStream dataStream(data);
|
||||
dataStream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
// 解析命令和其他数据
|
||||
QString cmd;
|
||||
quint16 brix, diameter, defectNum, height, width;
|
||||
quint8 greenPercentage, weight;
|
||||
quint32 totalDefectArea;
|
||||
|
||||
char cmdChars[2];
|
||||
dataStream.readRawData(cmdChars, 2);
|
||||
cmd = QString::fromLatin1(cmdChars, 2).trimmed().toUpper();
|
||||
|
||||
// 判断指令是否为 "RE"
|
||||
if (cmd == "RE")
|
||||
{
|
||||
// qDebug() << "Received 'RE' command. Processing accordingly.";
|
||||
// 继续解析其他数据
|
||||
dataStream >> brix >> greenPercentage >> diameter >> weight >> defectNum >> totalDefectArea >> height >> width;
|
||||
|
||||
// qDebug() << "命令:" << cmd;
|
||||
// qDebug() << "Brix:" << brix << ", Green Percentage:" << greenPercentage << ", Diameter:" << diameter;
|
||||
// qDebug() << "Weight:" << weight << ", Defect Number:" << defectNum << ", Total Defect Area:" << totalDefectArea;
|
||||
// qDebug() << "Height:" << height << ", Width:" << width;
|
||||
// // 剩余的数据为图像数据
|
||||
// qDebug() << "data: " <<data.size() <<"Current position in data stream:" << dataStream.device()->pos();
|
||||
|
||||
QByteArray imageData = data.right(data.size() - dataStream.device()->pos());
|
||||
// qDebug() << "imageData size: " << imageData.size();
|
||||
|
||||
QImage imageResult((uchar*)imageData.constData(), width, height, QImage::Format_RGB888);
|
||||
if (!imageResult.isNull()) {
|
||||
// qDebug() << "Image loaded successfully";
|
||||
QImage swappedImage = imageResult.rgbSwapped();
|
||||
emit recv_Data(brix,greenPercentage,diameter,weight,defectNum,totalDefectArea,height,width,swappedImage);
|
||||
// imageResult.save("D:/WeChat Files/wxid_jjgh0jfum83v12/FileStorage/File/2024-06/1.png");
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Error: Failed to load image from raw data";
|
||||
}
|
||||
// qDebug() << "接收并处理完成";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
SendThread::SendThread(QObject *parent) : QThread(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SendThread::~SendThread()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool SendThread::sendData(HANDLE &hPipe, const QByteArray &data)
|
||||
{
|
||||
DWORD bytesWritten;
|
||||
if (!WriteFile(hPipe, data.constData(), static_cast<DWORD>(data.size()), &bytesWritten, nullptr) || bytesWritten == 0) {
|
||||
DWORD dwError = GetLastError();
|
||||
qDebug()<<"第"<<countimgTopT<<"次"<<"发送失败时字节数: "<<data.size();
|
||||
qDebug() << "Failed to write to pipe or no bytes written. Error:" << dwError;
|
||||
return false;
|
||||
}
|
||||
// qDebug()<<"第"<<countimgTopT<<"次"<<"发送成功字节数: "<<data.size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE SendThread::reconnect(const QString &pipeName)
|
||||
{
|
||||
CloseHandle(hPipe); // Close the old handle before reconnecting
|
||||
HANDLE hPipe = CreateFile((LPCWSTR)pipeName.utf16(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hPipe == INVALID_HANDLE_VALUE) {
|
||||
qWarning() << "Failed to connect to pipe:" << GetLastError();
|
||||
}
|
||||
return hPipe;
|
||||
}
|
||||
|
||||
void SendThread::SendImgToPython()
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//通过 pipe 管道 给python端发送数据
|
||||
void SendThread::run()
|
||||
{
|
||||
|
||||
|
||||
|
||||
if(Yure_Flag && (hPipe != INVALID_HANDLE_VALUE))
|
||||
{
|
||||
// qDebug() << "预热前";
|
||||
|
||||
QByteArray dataToSend;
|
||||
QDataStream dataStream(&dataToSend, QIODevice::WriteOnly);
|
||||
dataStream.setByteOrder(QDataStream::BigEndian);
|
||||
quint32 lenth = 2;
|
||||
dataStream << lenth;
|
||||
// 添加命令
|
||||
QString cmd = "YR";
|
||||
dataStream.writeRawData(cmd.toLocal8Bit().constData(), 2);
|
||||
// 发送数据
|
||||
DWORD yr_Written;
|
||||
if (!WriteFile(hPipe, dataToSend, 6, &yr_Written, nullptr) || yr_Written != 6) {
|
||||
DWORD dwError = GetLastError();
|
||||
qDebug() << "Failed to write to pipe or incorrect number of bytes written. Error:" << dwError;
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "预热成功" ;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
//读取五个RGB队列的队首数据
|
||||
if(cameraL->topImgTQueue.size()>15)
|
||||
{
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
//数据对齐
|
||||
if(ImgQueue_Alignment)
|
||||
{
|
||||
cameraL->topImgMQueue.pop();
|
||||
cameraL->topImgMQueue.pop();
|
||||
|
||||
cameraL->topImgBQueue.pop();
|
||||
cameraL->topImgBQueue.pop();
|
||||
cameraL->topImgBQueue.pop();
|
||||
|
||||
cameraL->topImgTQueue.pop();
|
||||
|
||||
ImgQueue_Alignment = 0;
|
||||
}
|
||||
|
||||
QImage temp[5];
|
||||
temp[0] = cameraL->topImgTQueue.front();
|
||||
cameraL->topImgTQueue.pop();
|
||||
qDebug()<<"顶部相机顶队列大小:"<<cameraL->topImgTQueue.size();
|
||||
temp[1] = cameraL->topImgMQueue.front();
|
||||
cameraL->topImgMQueue.pop();
|
||||
qDebug()<<"顶部相机中队列大小:"<<cameraL->topImgMQueue.size();
|
||||
temp[2] = cameraL ->topImgBQueue.front();
|
||||
cameraL -> topImgBQueue.pop();
|
||||
qDebug()<<"顶部相机下队列大小:"<<cameraL->topImgBQueue.size();
|
||||
// temp[3] = cameraL->leftImgQueue.front();
|
||||
// cameraL->leftImgQueue.pop();
|
||||
// qDebug()<<"左侧相机队列大小:"<<cameraL->leftImgQueue.size();
|
||||
// temp[4] = cameraL->rightImgQueue.front();
|
||||
// cameraL->rightImgQueue.pop();
|
||||
// qDebug()<<"右侧相机队列大小:"<<cameraL->rightImgQueue.size();
|
||||
//循环五次 将 temp[5] 中的所有图像数据转换为字节流 用于 pipe 管道发送
|
||||
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
// Qt_image_count ++;
|
||||
// QString filePath = "C:/Users/succtech/Desktop/Qt_image";
|
||||
// QString imagePath = QString("%1/%2.bmp").arg(filePath).arg(Qt_image_count);
|
||||
// temp[i].save(imagePath);
|
||||
int width = temp[i].width();
|
||||
int height = temp[i].height();
|
||||
// qDebug()<<"原始图像字节: "<<temp[i].byteCount();
|
||||
QByteArray imgData(reinterpret_cast<const char*>(temp[i].bits()), temp[i].byteCount());
|
||||
// qDebug()<<"现在图像字节: "<<imgData.size();
|
||||
QDataStream stream(&imgData, QIODevice::ReadWrite);
|
||||
stream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
|
||||
QByteArray dataToSend;
|
||||
QDataStream dataStream(&dataToSend, QIODevice::WriteOnly);
|
||||
dataStream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
|
||||
quint32 length = static_cast<quint32>(imgData.size() + 6);
|
||||
dataStream << length;
|
||||
|
||||
if(fruit_flag) //百香果
|
||||
{
|
||||
// 添加命令
|
||||
QString cmd = "PF";
|
||||
dataStream.writeRawData(cmd.toLocal8Bit().constData(), 2);
|
||||
// Dimensions
|
||||
dataStream << static_cast<quint16>(height);
|
||||
dataStream << static_cast<quint16>(width);
|
||||
|
||||
// Image data
|
||||
dataStream.writeRawData(imgData.constData(), imgData.size());
|
||||
|
||||
if (!sendData(hPipe, dataToSend))
|
||||
{
|
||||
qWarning() << "Failed to send data, attempting to reconnect...";
|
||||
specPipe = reconnect(pipeName2);
|
||||
if (specPipe == INVALID_HANDLE_VALUE) return;
|
||||
if (!sendData(specPipe, dataToSend)) return;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//当第五张RGB图发送完之后,发送光谱图
|
||||
if(i==2)
|
||||
{
|
||||
unsigned short* specTemp = speccamera->specImgQueue.front();
|
||||
// qDebug()<<"光谱数据大小:"<<specTemp;
|
||||
speccamera->specImgQueue.pop();
|
||||
// qDebug() << "光谱队列长度: " << speccamera->specImgQueue.size();
|
||||
|
||||
int specWidth = 30;
|
||||
int specHeight = 25;
|
||||
int specBands = 13;
|
||||
|
||||
QByteArray specByte,specByte_tosend;
|
||||
specByte.append(reinterpret_cast<const char*>(specTemp), specWidth * specHeight * specBands * sizeof(unsigned short));
|
||||
qDebug()<<"specByte: "<<specByte.size();
|
||||
QDataStream spec_stream(&specByte_tosend, QIODevice::ReadWrite);
|
||||
spec_stream.setByteOrder(QDataStream::BigEndian);
|
||||
|
||||
quint32 length = static_cast<quint32>(specByte.size() + 8);
|
||||
spec_stream << length;
|
||||
|
||||
// 添加命令
|
||||
QString cmd = "PF";
|
||||
spec_stream.writeRawData(cmd.toLocal8Bit().constData(), 2);
|
||||
|
||||
// Dimensions
|
||||
spec_stream << static_cast<quint16>(specHeight);
|
||||
spec_stream << static_cast<quint16>(specWidth);
|
||||
spec_stream << static_cast<quint16>(specBands);
|
||||
specByte_tosend.append(specByte);
|
||||
if (!sendData(specPipe, specByte_tosend))
|
||||
{
|
||||
qWarning() << "Failed to send data, attempting to reconnect...";
|
||||
specPipe = reconnect(pipeName2);
|
||||
if (specPipe == INVALID_HANDLE_VALUE) return;
|
||||
if (!sendData(specPipe, specByte_tosend)) return;
|
||||
return;
|
||||
}
|
||||
// qDebug() << "write to spec_pipe." << specByte_tosend.size();
|
||||
msleep(10);
|
||||
// qDebug() << "发送完成:";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else //番茄
|
||||
{
|
||||
// 添加命令
|
||||
QString cmd = "TO";
|
||||
dataStream.writeRawData(cmd.toLocal8Bit().constData(), 2);
|
||||
// Dimensions
|
||||
dataStream << static_cast<quint16>(height);
|
||||
dataStream << static_cast<quint16>(width);
|
||||
|
||||
// Image data
|
||||
dataStream.writeRawData(imgData.constData(), imgData.size());
|
||||
|
||||
if (!sendData(hPipe, dataToSend))
|
||||
{
|
||||
qWarning() << "Failed to send data, attempting to reconnect...";
|
||||
specPipe = reconnect(pipeName2);
|
||||
if (specPipe == INVALID_HANDLE_VALUE) return;
|
||||
if (!sendData(specPipe, dataToSend)) return;
|
||||
return;
|
||||
}
|
||||
// if(i == 2)
|
||||
// {
|
||||
// // qDebug() << "光谱队列长度: " << speccamera->specImgQueue.size();
|
||||
// speccamera->specImgQueue.pop();
|
||||
// qDebug() << "发送完成:";
|
||||
|
||||
// }
|
||||
}
|
||||
// qint64 elapsed = timer.elapsed();
|
||||
// qDebug()<<"间隔时间"<<elapsed;
|
||||
// msleep(100);
|
||||
}
|
||||
// qint64 elapsed = timer.elapsed();
|
||||
// qDebug()<<"间隔时间"<<elapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
101
thread.h
Normal file
101
thread.h
Normal file
@ -0,0 +1,101 @@
|
||||
#ifndef THREAD_H
|
||||
#define THREAD_H
|
||||
#include "QThread"
|
||||
#include "QFile"
|
||||
#include <queue>
|
||||
#include <QFileDialog>
|
||||
#include "camera.h"
|
||||
#include "queue"
|
||||
#include "QMutex"
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
#include "src/modbus.h"
|
||||
#include <QImage>
|
||||
|
||||
//处理线程 负责光谱相机的完整数据拼接
|
||||
class ProcessImg : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProcessImg(QObject *parent = nullptr);
|
||||
~ProcessImg();
|
||||
|
||||
|
||||
void exitThread();
|
||||
QMutex stop_mutex;
|
||||
|
||||
int spec_count;
|
||||
|
||||
|
||||
protected:
|
||||
void run();
|
||||
private:
|
||||
bool m_stop;
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
//发送线程 负责使用管道 pipe 给python端发送五张图片
|
||||
//五张图片分别为 顶部 上、中、下三张 左 右 两张
|
||||
//待修改:
|
||||
//1、数据对齐
|
||||
class SendThread: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
public:
|
||||
explicit SendThread(QObject *parent = NULL);
|
||||
~SendThread();
|
||||
|
||||
bool sendData(HANDLE &hPipe, const QByteArray &data);
|
||||
|
||||
HANDLE reconnect(const QString &pipeName);
|
||||
|
||||
int Yure_Flag = 1;
|
||||
|
||||
int Qt_image_count = 0;
|
||||
private:
|
||||
|
||||
void SendImgToPython();
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
//void sendimg_topySlots(cv::Mat img1,cv::Mat img2,cv::Mat img3,cv::Mat img4,cv::Mat img5);
|
||||
};
|
||||
|
||||
//接收线程 负责接收python端通过 pipe 返回的数据 长径 短径 缺陷数量 缺陷面积 并在窗口展示
|
||||
//待修改:
|
||||
//1、具体返回值放在哪里 窗口位置需要调整
|
||||
//2、判断条件写死 具体数据写活
|
||||
class RecvThread: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
public:
|
||||
explicit RecvThread(QObject *parent = NULL);
|
||||
~RecvThread();
|
||||
|
||||
public slots:
|
||||
|
||||
signals:
|
||||
|
||||
void recv_Data(quint16,quint8,quint16,quint8,quint16,quint32,quint16,quint16,QImage);
|
||||
|
||||
};
|
||||
|
||||
#endif // THREAD_H
|
||||
59
tomato1227.pro
Normal file
59
tomato1227.pro
Normal file
@ -0,0 +1,59 @@
|
||||
QT += core gui network
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
camera.cpp \
|
||||
main.cpp \
|
||||
src/modbus-data.c \
|
||||
src/modbus-rtu.c \
|
||||
src/modbus-tcp.c \
|
||||
src/modbus.c \
|
||||
thread.cpp \
|
||||
widget.cpp
|
||||
|
||||
HEADERS += \
|
||||
camera.h \
|
||||
src/modbus-private.h \
|
||||
src/modbus-rtu-private.h \
|
||||
src/modbus-rtu.h \
|
||||
src/modbus-tcp-private.h \
|
||||
src/modbus-tcp.h \
|
||||
src/modbus-version.h \
|
||||
src/modbus.h \
|
||||
thread.h \
|
||||
widget.h
|
||||
|
||||
FORMS += \
|
||||
widget.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
|
||||
DISTFILES += \
|
||||
src/modbus.lib
|
||||
LIBS += -Ldll -lws2_32
|
||||
|
||||
#查看所有路径知否正确 RGB opencv 光谱相机
|
||||
#建议改成绝对路径
|
||||
# rgb camera SDK
|
||||
LIBS += -LD:/porject/20240425/rgbcamera_sdk/Libraries/win64 -lMvCameraControl
|
||||
INCLUDEPATH += D:/porject/20240425/rgbcamera_sdk/Includes
|
||||
DEPENDPATH += D:/porject/20240425/rgbcamera_sdk/Includes
|
||||
|
||||
|
||||
|
||||
# spec
|
||||
INCLUDEPATH += D:/porject/20240425/RT_SDK/SDK/include
|
||||
DEPENDPATH += D:/porject/20240425/RT_SDK/SDK/include
|
||||
LIBS += -LD:/porject/20240425/RT_SDK/SDK/lib -lSpectrolDll
|
||||
|
||||
863
ui_widget.h
Normal file
863
ui_widget.h
Normal file
@ -0,0 +1,863 @@
|
||||
/********************************************************************************
|
||||
** Form generated from reading UI file 'widget.ui'
|
||||
**
|
||||
** Created by: Qt User Interface Compiler version 5.15.2
|
||||
**
|
||||
** WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef UI_WIDGET_H
|
||||
#define UI_WIDGET_H
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QGridLayout>
|
||||
#include <QtWidgets/QGroupBox>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QPlainTextEdit>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QSpinBox>
|
||||
#include <QtWidgets/QTabWidget>
|
||||
#include <QtWidgets/QVBoxLayout>
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Ui_Widget
|
||||
{
|
||||
public:
|
||||
QGridLayout *gridLayout_10;
|
||||
QTabWidget *tabWidget;
|
||||
QWidget *tab_3;
|
||||
QGridLayout *gridLayout_12;
|
||||
QLabel *label;
|
||||
QLabel *label_23;
|
||||
QWidget *tab;
|
||||
QGroupBox *groupBox_9;
|
||||
QGridLayout *gridLayout_11;
|
||||
QGroupBox *groupBox;
|
||||
QLabel *label_14;
|
||||
QWidget *layoutWidget_2;
|
||||
QHBoxLayout *horizontalLayout_14;
|
||||
QLabel *label_RGB;
|
||||
QLabel *RGBstatus;
|
||||
QLabel *label_RGB_3;
|
||||
QLabel *RGBstatus_1;
|
||||
QLabel *label_RGB_2;
|
||||
QLabel *RGBstatus_2;
|
||||
QLabel *label_9;
|
||||
QLabel *spec_camera_status;
|
||||
QLabel *label_11;
|
||||
QLabel *plc_status;
|
||||
QLabel *label_17;
|
||||
QLabel *jxs_status;
|
||||
QWidget *layoutWidget;
|
||||
QVBoxLayout *verticalLayout_5;
|
||||
QWidget *layoutWidget1;
|
||||
QHBoxLayout *horizontalLayout_8;
|
||||
QVBoxLayout *verticalLayout;
|
||||
QHBoxLayout *horizontalLayout;
|
||||
QLabel *label_26;
|
||||
QPushButton *passionBtn;
|
||||
QPushButton *tomatoBtn;
|
||||
QPushButton *btn_start;
|
||||
QPushButton *show_resoult;
|
||||
QPushButton *btn_setparam;
|
||||
QPushButton *btn_save;
|
||||
QPushButton *view_results;
|
||||
QPushButton *btn_quit;
|
||||
QVBoxLayout *verticalLayout_2;
|
||||
QGroupBox *groupBox_4;
|
||||
QGridLayout *gridLayout_2;
|
||||
QGroupBox *groupBox_2;
|
||||
QGridLayout *gridLayout;
|
||||
QLabel *label_topL;
|
||||
QGroupBox *groupBox_3;
|
||||
QGridLayout *gridLayout_3;
|
||||
QLabel *label_topM;
|
||||
QGroupBox *groupBox_5;
|
||||
QGridLayout *gridLayout_4;
|
||||
QLabel *label_topR;
|
||||
QGroupBox *groupBox_6;
|
||||
QGridLayout *gridLayout_5;
|
||||
QLabel *showimg_right;
|
||||
QGroupBox *groupBox_7;
|
||||
QGridLayout *gridLayout_6;
|
||||
QLabel *showimg_left;
|
||||
QGroupBox *groupBox_8;
|
||||
QGridLayout *gridLayout_7;
|
||||
QLabel *spec_camera_show;
|
||||
QWidget *tab_2;
|
||||
QGroupBox *groupBox_11;
|
||||
QGridLayout *gridLayout_13;
|
||||
QLabel *label_28;
|
||||
QSpinBox *exSpinBox_left;
|
||||
QLabel *label_29;
|
||||
QSpinBox *wbSpinBox_left_2;
|
||||
QLabel *label_30;
|
||||
QSpinBox *GainSpinBox_left;
|
||||
QGroupBox *groupBox_13;
|
||||
QGridLayout *gridLayout_16;
|
||||
QLabel *label_38;
|
||||
QSpinBox *exspinBox_top;
|
||||
QLabel *label_39;
|
||||
QSpinBox *wbspinBox_top;
|
||||
QLabel *label_40;
|
||||
QSpinBox *GainspinBox_top;
|
||||
QGroupBox *groupBox_15;
|
||||
QGridLayout *gridLayout_18;
|
||||
QLabel *label_46;
|
||||
QSpinBox *exspinBox_right;
|
||||
QLabel *label_47;
|
||||
QSpinBox *wbspinBox_right;
|
||||
QLabel *label_48;
|
||||
QSpinBox *GainspinBox_right;
|
||||
QPushButton *btn_enterparam;
|
||||
QPushButton *tab3_ReturnToMain;
|
||||
QPushButton *choose_to;
|
||||
QPushButton *choose_pa;
|
||||
QLineEdit *InputNum1;
|
||||
QLineEdit *InputNum5;
|
||||
QLabel *label_5;
|
||||
QLineEdit *InputNum4;
|
||||
QPushButton *set_threshoid;
|
||||
QLabel *label_32;
|
||||
QLineEdit *InputNum3;
|
||||
QLabel *label_33;
|
||||
QLabel *label_10;
|
||||
QLabel *label_18;
|
||||
QLineEdit *InputNum2;
|
||||
QLabel *label_12;
|
||||
QLabel *label_21;
|
||||
QWidget *tab_4;
|
||||
QLabel *show_resultsImg;
|
||||
QLabel *label_3;
|
||||
QPushButton *tab4_ReturnToMain;
|
||||
QPlainTextEdit *resoult_info_label;
|
||||
QPushButton *choose_pa_2;
|
||||
QLabel *label_13;
|
||||
QPushButton *choose_to_2;
|
||||
|
||||
void setupUi(QWidget *Widget)
|
||||
{
|
||||
if (Widget->objectName().isEmpty())
|
||||
Widget->setObjectName(QString::fromUtf8("Widget"));
|
||||
Widget->resize(2000, 1038);
|
||||
gridLayout_10 = new QGridLayout(Widget);
|
||||
gridLayout_10->setObjectName(QString::fromUtf8("gridLayout_10"));
|
||||
tabWidget = new QTabWidget(Widget);
|
||||
tabWidget->setObjectName(QString::fromUtf8("tabWidget"));
|
||||
tabWidget->setStyleSheet(QString::fromUtf8(""));
|
||||
tab_3 = new QWidget();
|
||||
tab_3->setObjectName(QString::fromUtf8("tab_3"));
|
||||
gridLayout_12 = new QGridLayout(tab_3);
|
||||
gridLayout_12->setObjectName(QString::fromUtf8("gridLayout_12"));
|
||||
label = new QLabel(tab_3);
|
||||
label->setObjectName(QString::fromUtf8("label"));
|
||||
QFont font;
|
||||
font.setPointSize(36);
|
||||
font.setBold(false);
|
||||
label->setFont(font);
|
||||
label->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
label->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
|
||||
|
||||
gridLayout_12->addWidget(label, 1, 1, 2, 2);
|
||||
|
||||
label_23 = new QLabel(tab_3);
|
||||
label_23->setObjectName(QString::fromUtf8("label_23"));
|
||||
label_23->setPixmap(QPixmap(QString::fromUtf8("H:/\351\241\271\347\233\256\344\273\243\347\240\201/tobacco/uppermachine-tobacco/image/njfu.jpg")));
|
||||
|
||||
gridLayout_12->addWidget(label_23, 0, 0, 1, 1);
|
||||
|
||||
tabWidget->addTab(tab_3, QString());
|
||||
tab = new QWidget();
|
||||
tab->setObjectName(QString::fromUtf8("tab"));
|
||||
groupBox_9 = new QGroupBox(tab);
|
||||
groupBox_9->setObjectName(QString::fromUtf8("groupBox_9"));
|
||||
groupBox_9->setGeometry(QRect(9, 9, 20, 20));
|
||||
gridLayout_11 = new QGridLayout(groupBox_9);
|
||||
gridLayout_11->setObjectName(QString::fromUtf8("gridLayout_11"));
|
||||
groupBox = new QGroupBox(tab);
|
||||
groupBox->setObjectName(QString::fromUtf8("groupBox"));
|
||||
groupBox->setGeometry(QRect(10, -20, 1961, 161));
|
||||
QFont font1;
|
||||
font1.setPointSize(12);
|
||||
groupBox->setFont(font1);
|
||||
label_14 = new QLabel(groupBox);
|
||||
label_14->setObjectName(QString::fromUtf8("label_14"));
|
||||
label_14->setGeometry(QRect(330, 40, 511, 51));
|
||||
QFont font2;
|
||||
font2.setFamily(QString::fromUtf8("\345\215\216\346\226\207\346\245\267\344\275\223"));
|
||||
font2.setPointSize(36);
|
||||
font2.setBold(false);
|
||||
font2.setItalic(false);
|
||||
label_14->setFont(font2);
|
||||
label_14->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);\n"
|
||||
"font: 36pt \"\345\215\216\346\226\207\346\245\267\344\275\223\";"));
|
||||
label_14->setTextFormat(Qt::PlainText);
|
||||
layoutWidget_2 = new QWidget(groupBox);
|
||||
layoutWidget_2->setObjectName(QString::fromUtf8("layoutWidget_2"));
|
||||
layoutWidget_2->setGeometry(QRect(2, 90, 841, 61));
|
||||
horizontalLayout_14 = new QHBoxLayout(layoutWidget_2);
|
||||
horizontalLayout_14->setObjectName(QString::fromUtf8("horizontalLayout_14"));
|
||||
horizontalLayout_14->setContentsMargins(0, 0, 0, 0);
|
||||
label_RGB = new QLabel(layoutWidget_2);
|
||||
label_RGB->setObjectName(QString::fromUtf8("label_RGB"));
|
||||
QFont font3;
|
||||
font3.setPointSize(12);
|
||||
font3.setBold(true);
|
||||
label_RGB->setFont(font3);
|
||||
label_RGB->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(label_RGB);
|
||||
|
||||
RGBstatus = new QLabel(layoutWidget_2);
|
||||
RGBstatus->setObjectName(QString::fromUtf8("RGBstatus"));
|
||||
RGBstatus->setStyleSheet(QString::fromUtf8("color: rgb(255, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(RGBstatus);
|
||||
|
||||
label_RGB_3 = new QLabel(layoutWidget_2);
|
||||
label_RGB_3->setObjectName(QString::fromUtf8("label_RGB_3"));
|
||||
label_RGB_3->setFont(font3);
|
||||
label_RGB_3->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(label_RGB_3);
|
||||
|
||||
RGBstatus_1 = new QLabel(layoutWidget_2);
|
||||
RGBstatus_1->setObjectName(QString::fromUtf8("RGBstatus_1"));
|
||||
RGBstatus_1->setStyleSheet(QString::fromUtf8("color: rgb(255, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(RGBstatus_1);
|
||||
|
||||
label_RGB_2 = new QLabel(layoutWidget_2);
|
||||
label_RGB_2->setObjectName(QString::fromUtf8("label_RGB_2"));
|
||||
label_RGB_2->setFont(font3);
|
||||
label_RGB_2->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(label_RGB_2);
|
||||
|
||||
RGBstatus_2 = new QLabel(layoutWidget_2);
|
||||
RGBstatus_2->setObjectName(QString::fromUtf8("RGBstatus_2"));
|
||||
RGBstatus_2->setStyleSheet(QString::fromUtf8("color: rgb(255, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(RGBstatus_2);
|
||||
|
||||
label_9 = new QLabel(layoutWidget_2);
|
||||
label_9->setObjectName(QString::fromUtf8("label_9"));
|
||||
label_9->setFont(font3);
|
||||
label_9->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(label_9);
|
||||
|
||||
spec_camera_status = new QLabel(layoutWidget_2);
|
||||
spec_camera_status->setObjectName(QString::fromUtf8("spec_camera_status"));
|
||||
spec_camera_status->setStyleSheet(QString::fromUtf8("color: rgb(255, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(spec_camera_status);
|
||||
|
||||
label_11 = new QLabel(layoutWidget_2);
|
||||
label_11->setObjectName(QString::fromUtf8("label_11"));
|
||||
label_11->setFont(font3);
|
||||
label_11->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(label_11);
|
||||
|
||||
plc_status = new QLabel(layoutWidget_2);
|
||||
plc_status->setObjectName(QString::fromUtf8("plc_status"));
|
||||
plc_status->setStyleSheet(QString::fromUtf8("color: rgb(255, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(plc_status);
|
||||
|
||||
label_17 = new QLabel(layoutWidget_2);
|
||||
label_17->setObjectName(QString::fromUtf8("label_17"));
|
||||
label_17->setFont(font3);
|
||||
label_17->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(label_17);
|
||||
|
||||
jxs_status = new QLabel(layoutWidget_2);
|
||||
jxs_status->setObjectName(QString::fromUtf8("jxs_status"));
|
||||
jxs_status->setStyleSheet(QString::fromUtf8("color: rgb(255, 0, 0);"));
|
||||
|
||||
horizontalLayout_14->addWidget(jxs_status);
|
||||
|
||||
layoutWidget = new QWidget(groupBox);
|
||||
layoutWidget->setObjectName(QString::fromUtf8("layoutWidget"));
|
||||
layoutWidget->setGeometry(QRect(790, 220, 574, 356));
|
||||
verticalLayout_5 = new QVBoxLayout(layoutWidget);
|
||||
verticalLayout_5->setObjectName(QString::fromUtf8("verticalLayout_5"));
|
||||
verticalLayout_5->setContentsMargins(0, 0, 0, 0);
|
||||
layoutWidget1 = new QWidget(tab);
|
||||
layoutWidget1->setObjectName(QString::fromUtf8("layoutWidget1"));
|
||||
layoutWidget1->setGeometry(QRect(10, 140, 1951, 791));
|
||||
horizontalLayout_8 = new QHBoxLayout(layoutWidget1);
|
||||
horizontalLayout_8->setObjectName(QString::fromUtf8("horizontalLayout_8"));
|
||||
horizontalLayout_8->setContentsMargins(0, 0, 0, 0);
|
||||
verticalLayout = new QVBoxLayout();
|
||||
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
|
||||
horizontalLayout = new QHBoxLayout();
|
||||
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
|
||||
label_26 = new QLabel(layoutWidget1);
|
||||
label_26->setObjectName(QString::fromUtf8("label_26"));
|
||||
label_26->setFont(font3);
|
||||
label_26->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout->addWidget(label_26);
|
||||
|
||||
passionBtn = new QPushButton(layoutWidget1);
|
||||
passionBtn->setObjectName(QString::fromUtf8("passionBtn"));
|
||||
passionBtn->setFont(font3);
|
||||
passionBtn->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout->addWidget(passionBtn);
|
||||
|
||||
tomatoBtn = new QPushButton(layoutWidget1);
|
||||
tomatoBtn->setObjectName(QString::fromUtf8("tomatoBtn"));
|
||||
tomatoBtn->setFont(font3);
|
||||
tomatoBtn->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
horizontalLayout->addWidget(tomatoBtn);
|
||||
|
||||
|
||||
verticalLayout->addLayout(horizontalLayout);
|
||||
|
||||
btn_start = new QPushButton(layoutWidget1);
|
||||
btn_start->setObjectName(QString::fromUtf8("btn_start"));
|
||||
QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
sizePolicy.setHeightForWidth(btn_start->sizePolicy().hasHeightForWidth());
|
||||
btn_start->setSizePolicy(sizePolicy);
|
||||
QFont font4;
|
||||
font4.setFamily(QString::fromUtf8("\345\256\213\344\275\223"));
|
||||
font4.setPointSize(30);
|
||||
font4.setBold(false);
|
||||
font4.setItalic(false);
|
||||
btn_start->setFont(font4);
|
||||
btn_start->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);\n"
|
||||
"font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
|
||||
verticalLayout->addWidget(btn_start);
|
||||
|
||||
show_resoult = new QPushButton(layoutWidget1);
|
||||
show_resoult->setObjectName(QString::fromUtf8("show_resoult"));
|
||||
sizePolicy.setHeightForWidth(show_resoult->sizePolicy().hasHeightForWidth());
|
||||
show_resoult->setSizePolicy(sizePolicy);
|
||||
show_resoult->setFont(font4);
|
||||
show_resoult->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);\n"
|
||||
"font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
|
||||
verticalLayout->addWidget(show_resoult);
|
||||
|
||||
btn_setparam = new QPushButton(layoutWidget1);
|
||||
btn_setparam->setObjectName(QString::fromUtf8("btn_setparam"));
|
||||
sizePolicy.setHeightForWidth(btn_setparam->sizePolicy().hasHeightForWidth());
|
||||
btn_setparam->setSizePolicy(sizePolicy);
|
||||
btn_setparam->setFont(font4);
|
||||
btn_setparam->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);\n"
|
||||
"font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
|
||||
verticalLayout->addWidget(btn_setparam);
|
||||
|
||||
btn_save = new QPushButton(layoutWidget1);
|
||||
btn_save->setObjectName(QString::fromUtf8("btn_save"));
|
||||
sizePolicy.setHeightForWidth(btn_save->sizePolicy().hasHeightForWidth());
|
||||
btn_save->setSizePolicy(sizePolicy);
|
||||
btn_save->setFont(font4);
|
||||
btn_save->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);\n"
|
||||
"font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
|
||||
verticalLayout->addWidget(btn_save);
|
||||
|
||||
view_results = new QPushButton(layoutWidget1);
|
||||
view_results->setObjectName(QString::fromUtf8("view_results"));
|
||||
sizePolicy.setHeightForWidth(view_results->sizePolicy().hasHeightForWidth());
|
||||
view_results->setSizePolicy(sizePolicy);
|
||||
view_results->setFont(font4);
|
||||
view_results->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);\n"
|
||||
"font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
|
||||
verticalLayout->addWidget(view_results);
|
||||
|
||||
btn_quit = new QPushButton(layoutWidget1);
|
||||
btn_quit->setObjectName(QString::fromUtf8("btn_quit"));
|
||||
sizePolicy.setHeightForWidth(btn_quit->sizePolicy().hasHeightForWidth());
|
||||
btn_quit->setSizePolicy(sizePolicy);
|
||||
btn_quit->setFont(font4);
|
||||
btn_quit->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);\n"
|
||||
"font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
|
||||
verticalLayout->addWidget(btn_quit);
|
||||
|
||||
|
||||
horizontalLayout_8->addLayout(verticalLayout);
|
||||
|
||||
verticalLayout_2 = new QVBoxLayout();
|
||||
verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2"));
|
||||
groupBox_4 = new QGroupBox(layoutWidget1);
|
||||
groupBox_4->setObjectName(QString::fromUtf8("groupBox_4"));
|
||||
groupBox_4->setFont(font3);
|
||||
groupBox_4->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
gridLayout_2 = new QGridLayout(groupBox_4);
|
||||
gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2"));
|
||||
groupBox_2 = new QGroupBox(groupBox_4);
|
||||
groupBox_2->setObjectName(QString::fromUtf8("groupBox_2"));
|
||||
groupBox_2->setFont(font3);
|
||||
gridLayout = new QGridLayout(groupBox_2);
|
||||
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
|
||||
label_topL = new QLabel(groupBox_2);
|
||||
label_topL->setObjectName(QString::fromUtf8("label_topL"));
|
||||
label_topL->setStyleSheet(QString::fromUtf8("background-color: rgb(170, 170, 255);"));
|
||||
|
||||
gridLayout->addWidget(label_topL, 0, 0, 1, 1);
|
||||
|
||||
|
||||
gridLayout_2->addWidget(groupBox_2, 0, 0, 1, 1);
|
||||
|
||||
groupBox_3 = new QGroupBox(groupBox_4);
|
||||
groupBox_3->setObjectName(QString::fromUtf8("groupBox_3"));
|
||||
groupBox_3->setFont(font3);
|
||||
gridLayout_3 = new QGridLayout(groupBox_3);
|
||||
gridLayout_3->setObjectName(QString::fromUtf8("gridLayout_3"));
|
||||
label_topM = new QLabel(groupBox_3);
|
||||
label_topM->setObjectName(QString::fromUtf8("label_topM"));
|
||||
label_topM->setStyleSheet(QString::fromUtf8("background-color: rgb(170, 170, 255);"));
|
||||
|
||||
gridLayout_3->addWidget(label_topM, 0, 1, 1, 1);
|
||||
|
||||
|
||||
gridLayout_2->addWidget(groupBox_3, 0, 1, 1, 1);
|
||||
|
||||
groupBox_5 = new QGroupBox(groupBox_4);
|
||||
groupBox_5->setObjectName(QString::fromUtf8("groupBox_5"));
|
||||
groupBox_5->setFont(font3);
|
||||
gridLayout_4 = new QGridLayout(groupBox_5);
|
||||
gridLayout_4->setObjectName(QString::fromUtf8("gridLayout_4"));
|
||||
label_topR = new QLabel(groupBox_5);
|
||||
label_topR->setObjectName(QString::fromUtf8("label_topR"));
|
||||
label_topR->setStyleSheet(QString::fromUtf8("background-color: rgb(170, 170, 255);"));
|
||||
|
||||
gridLayout_4->addWidget(label_topR, 0, 0, 1, 1);
|
||||
|
||||
|
||||
gridLayout_2->addWidget(groupBox_5, 0, 2, 1, 1);
|
||||
|
||||
groupBox_6 = new QGroupBox(groupBox_4);
|
||||
groupBox_6->setObjectName(QString::fromUtf8("groupBox_6"));
|
||||
groupBox_6->setFont(font3);
|
||||
gridLayout_5 = new QGridLayout(groupBox_6);
|
||||
gridLayout_5->setObjectName(QString::fromUtf8("gridLayout_5"));
|
||||
showimg_right = new QLabel(groupBox_6);
|
||||
showimg_right->setObjectName(QString::fromUtf8("showimg_right"));
|
||||
showimg_right->setStyleSheet(QString::fromUtf8("background-color: rgb(170, 170, 255);"));
|
||||
|
||||
gridLayout_5->addWidget(showimg_right, 0, 0, 1, 1);
|
||||
|
||||
|
||||
gridLayout_2->addWidget(groupBox_6, 1, 0, 1, 1);
|
||||
|
||||
groupBox_7 = new QGroupBox(groupBox_4);
|
||||
groupBox_7->setObjectName(QString::fromUtf8("groupBox_7"));
|
||||
groupBox_7->setFont(font3);
|
||||
gridLayout_6 = new QGridLayout(groupBox_7);
|
||||
gridLayout_6->setObjectName(QString::fromUtf8("gridLayout_6"));
|
||||
showimg_left = new QLabel(groupBox_7);
|
||||
showimg_left->setObjectName(QString::fromUtf8("showimg_left"));
|
||||
showimg_left->setStyleSheet(QString::fromUtf8("background-color: rgb(170, 170, 255);"));
|
||||
|
||||
gridLayout_6->addWidget(showimg_left, 0, 0, 1, 1);
|
||||
|
||||
|
||||
gridLayout_2->addWidget(groupBox_7, 1, 1, 1, 1);
|
||||
|
||||
groupBox_8 = new QGroupBox(groupBox_4);
|
||||
groupBox_8->setObjectName(QString::fromUtf8("groupBox_8"));
|
||||
groupBox_8->setFont(font3);
|
||||
gridLayout_7 = new QGridLayout(groupBox_8);
|
||||
gridLayout_7->setObjectName(QString::fromUtf8("gridLayout_7"));
|
||||
spec_camera_show = new QLabel(groupBox_8);
|
||||
spec_camera_show->setObjectName(QString::fromUtf8("spec_camera_show"));
|
||||
spec_camera_show->setStyleSheet(QString::fromUtf8("background-color: rgb(170, 170, 255);"));
|
||||
|
||||
gridLayout_7->addWidget(spec_camera_show, 0, 0, 1, 1);
|
||||
|
||||
|
||||
gridLayout_2->addWidget(groupBox_8, 1, 2, 1, 1);
|
||||
|
||||
|
||||
verticalLayout_2->addWidget(groupBox_4);
|
||||
|
||||
|
||||
horizontalLayout_8->addLayout(verticalLayout_2);
|
||||
|
||||
horizontalLayout_8->setStretch(1, 1);
|
||||
tabWidget->addTab(tab, QString());
|
||||
tab_2 = new QWidget();
|
||||
tab_2->setObjectName(QString::fromUtf8("tab_2"));
|
||||
groupBox_11 = new QGroupBox(tab_2);
|
||||
groupBox_11->setObjectName(QString::fromUtf8("groupBox_11"));
|
||||
groupBox_11->setGeometry(QRect(40, 50, 531, 231));
|
||||
QFont font5;
|
||||
font5.setPointSize(16);
|
||||
font5.setBold(true);
|
||||
groupBox_11->setFont(font5);
|
||||
groupBox_11->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
gridLayout_13 = new QGridLayout(groupBox_11);
|
||||
gridLayout_13->setObjectName(QString::fromUtf8("gridLayout_13"));
|
||||
label_28 = new QLabel(groupBox_11);
|
||||
label_28->setObjectName(QString::fromUtf8("label_28"));
|
||||
label_28->setFont(font5);
|
||||
label_28->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_13->addWidget(label_28, 0, 0, 1, 1);
|
||||
|
||||
exSpinBox_left = new QSpinBox(groupBox_11);
|
||||
exSpinBox_left->setObjectName(QString::fromUtf8("exSpinBox_left"));
|
||||
QFont font6;
|
||||
font6.setBold(true);
|
||||
exSpinBox_left->setFont(font6);
|
||||
exSpinBox_left->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_13->addWidget(exSpinBox_left, 0, 1, 1, 1);
|
||||
|
||||
label_29 = new QLabel(groupBox_11);
|
||||
label_29->setObjectName(QString::fromUtf8("label_29"));
|
||||
label_29->setFont(font5);
|
||||
label_29->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_13->addWidget(label_29, 1, 0, 1, 1);
|
||||
|
||||
wbSpinBox_left_2 = new QSpinBox(groupBox_11);
|
||||
wbSpinBox_left_2->setObjectName(QString::fromUtf8("wbSpinBox_left_2"));
|
||||
wbSpinBox_left_2->setFont(font6);
|
||||
wbSpinBox_left_2->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_13->addWidget(wbSpinBox_left_2, 1, 1, 1, 1);
|
||||
|
||||
label_30 = new QLabel(groupBox_11);
|
||||
label_30->setObjectName(QString::fromUtf8("label_30"));
|
||||
label_30->setFont(font5);
|
||||
label_30->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_13->addWidget(label_30, 2, 0, 1, 1);
|
||||
|
||||
GainSpinBox_left = new QSpinBox(groupBox_11);
|
||||
GainSpinBox_left->setObjectName(QString::fromUtf8("GainSpinBox_left"));
|
||||
GainSpinBox_left->setFont(font6);
|
||||
GainSpinBox_left->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_13->addWidget(GainSpinBox_left, 2, 1, 1, 1);
|
||||
|
||||
groupBox_13 = new QGroupBox(tab_2);
|
||||
groupBox_13->setObjectName(QString::fromUtf8("groupBox_13"));
|
||||
groupBox_13->setGeometry(QRect(40, 350, 531, 231));
|
||||
groupBox_13->setFont(font5);
|
||||
groupBox_13->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
gridLayout_16 = new QGridLayout(groupBox_13);
|
||||
gridLayout_16->setObjectName(QString::fromUtf8("gridLayout_16"));
|
||||
label_38 = new QLabel(groupBox_13);
|
||||
label_38->setObjectName(QString::fromUtf8("label_38"));
|
||||
label_38->setFont(font5);
|
||||
label_38->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_16->addWidget(label_38, 0, 0, 1, 1);
|
||||
|
||||
exspinBox_top = new QSpinBox(groupBox_13);
|
||||
exspinBox_top->setObjectName(QString::fromUtf8("exspinBox_top"));
|
||||
exspinBox_top->setFont(font6);
|
||||
exspinBox_top->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_16->addWidget(exspinBox_top, 0, 1, 1, 1);
|
||||
|
||||
label_39 = new QLabel(groupBox_13);
|
||||
label_39->setObjectName(QString::fromUtf8("label_39"));
|
||||
label_39->setFont(font5);
|
||||
label_39->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_16->addWidget(label_39, 1, 0, 1, 1);
|
||||
|
||||
wbspinBox_top = new QSpinBox(groupBox_13);
|
||||
wbspinBox_top->setObjectName(QString::fromUtf8("wbspinBox_top"));
|
||||
wbspinBox_top->setFont(font6);
|
||||
wbspinBox_top->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_16->addWidget(wbspinBox_top, 1, 1, 1, 1);
|
||||
|
||||
label_40 = new QLabel(groupBox_13);
|
||||
label_40->setObjectName(QString::fromUtf8("label_40"));
|
||||
label_40->setFont(font5);
|
||||
label_40->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_16->addWidget(label_40, 2, 0, 1, 1);
|
||||
|
||||
GainspinBox_top = new QSpinBox(groupBox_13);
|
||||
GainspinBox_top->setObjectName(QString::fromUtf8("GainspinBox_top"));
|
||||
GainspinBox_top->setFont(font6);
|
||||
GainspinBox_top->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_16->addWidget(GainspinBox_top, 2, 1, 1, 1);
|
||||
|
||||
groupBox_15 = new QGroupBox(tab_2);
|
||||
groupBox_15->setObjectName(QString::fromUtf8("groupBox_15"));
|
||||
groupBox_15->setGeometry(QRect(700, 60, 531, 231));
|
||||
groupBox_15->setFont(font5);
|
||||
groupBox_15->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
gridLayout_18 = new QGridLayout(groupBox_15);
|
||||
gridLayout_18->setObjectName(QString::fromUtf8("gridLayout_18"));
|
||||
label_46 = new QLabel(groupBox_15);
|
||||
label_46->setObjectName(QString::fromUtf8("label_46"));
|
||||
label_46->setFont(font5);
|
||||
label_46->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_18->addWidget(label_46, 0, 0, 1, 1);
|
||||
|
||||
exspinBox_right = new QSpinBox(groupBox_15);
|
||||
exspinBox_right->setObjectName(QString::fromUtf8("exspinBox_right"));
|
||||
exspinBox_right->setFont(font6);
|
||||
exspinBox_right->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_18->addWidget(exspinBox_right, 0, 1, 1, 1);
|
||||
|
||||
label_47 = new QLabel(groupBox_15);
|
||||
label_47->setObjectName(QString::fromUtf8("label_47"));
|
||||
label_47->setFont(font5);
|
||||
label_47->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_18->addWidget(label_47, 1, 0, 1, 1);
|
||||
|
||||
wbspinBox_right = new QSpinBox(groupBox_15);
|
||||
wbspinBox_right->setObjectName(QString::fromUtf8("wbspinBox_right"));
|
||||
wbspinBox_right->setFont(font6);
|
||||
wbspinBox_right->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_18->addWidget(wbspinBox_right, 1, 1, 1, 1);
|
||||
|
||||
label_48 = new QLabel(groupBox_15);
|
||||
label_48->setObjectName(QString::fromUtf8("label_48"));
|
||||
label_48->setFont(font5);
|
||||
label_48->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_18->addWidget(label_48, 2, 0, 1, 1);
|
||||
|
||||
GainspinBox_right = new QSpinBox(groupBox_15);
|
||||
GainspinBox_right->setObjectName(QString::fromUtf8("GainspinBox_right"));
|
||||
GainspinBox_right->setFont(font6);
|
||||
GainspinBox_right->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
|
||||
gridLayout_18->addWidget(GainspinBox_right, 2, 1, 1, 1);
|
||||
|
||||
btn_enterparam = new QPushButton(tab_2);
|
||||
btn_enterparam->setObjectName(QString::fromUtf8("btn_enterparam"));
|
||||
btn_enterparam->setGeometry(QRect(710, 380, 161, 91));
|
||||
btn_enterparam->setFont(font5);
|
||||
btn_enterparam->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
tab3_ReturnToMain = new QPushButton(tab_2);
|
||||
tab3_ReturnToMain->setObjectName(QString::fromUtf8("tab3_ReturnToMain"));
|
||||
tab3_ReturnToMain->setGeometry(QRect(1300, 820, 241, 91));
|
||||
tab3_ReturnToMain->setFont(font5);
|
||||
tab3_ReturnToMain->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
choose_to = new QPushButton(tab_2);
|
||||
choose_to->setObjectName(QString::fromUtf8("choose_to"));
|
||||
choose_to->setGeometry(QRect(340, 710, 241, 141));
|
||||
choose_to->setFont(font5);
|
||||
choose_to->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
choose_pa = new QPushButton(tab_2);
|
||||
choose_pa->setObjectName(QString::fromUtf8("choose_pa"));
|
||||
choose_pa->setGeometry(QRect(40, 710, 231, 141));
|
||||
choose_pa->setFont(font5);
|
||||
choose_pa->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
InputNum1 = new QLineEdit(tab_2);
|
||||
InputNum1->setObjectName(QString::fromUtf8("InputNum1"));
|
||||
InputNum1->setGeometry(QRect(774, 720, 81, 30));
|
||||
QFont font7;
|
||||
font7.setPointSize(16);
|
||||
font7.setBold(false);
|
||||
InputNum1->setFont(font7);
|
||||
InputNum5 = new QLineEdit(tab_2);
|
||||
InputNum5->setObjectName(QString::fromUtf8("InputNum5"));
|
||||
InputNum5->setGeometry(QRect(1050, 780, 94, 30));
|
||||
InputNum5->setFont(font7);
|
||||
label_5 = new QLabel(tab_2);
|
||||
label_5->setObjectName(QString::fromUtf8("label_5"));
|
||||
label_5->setGeometry(QRect(720, 630, 108, 21));
|
||||
label_5->setFont(font5);
|
||||
InputNum4 = new QLineEdit(tab_2);
|
||||
InputNum4->setObjectName(QString::fromUtf8("InputNum4"));
|
||||
InputNum4->setGeometry(QRect(820, 780, 81, 30));
|
||||
InputNum4->setFont(font7);
|
||||
set_threshoid = new QPushButton(tab_2);
|
||||
set_threshoid->setObjectName(QString::fromUtf8("set_threshoid"));
|
||||
set_threshoid->setGeometry(QRect(720, 830, 261, 91));
|
||||
set_threshoid->setStyleSheet(QString::fromUtf8("font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
label_32 = new QLabel(tab_2);
|
||||
label_32->setObjectName(QString::fromUtf8("label_32"));
|
||||
label_32->setGeometry(QRect(720, 780, 86, 31));
|
||||
label_32->setFont(font5);
|
||||
InputNum3 = new QLineEdit(tab_2);
|
||||
InputNum3->setObjectName(QString::fromUtf8("InputNum3"));
|
||||
InputNum3->setGeometry(QRect(1140, 720, 91, 28));
|
||||
InputNum3->setFont(font7);
|
||||
label_33 = new QLabel(tab_2);
|
||||
label_33->setObjectName(QString::fromUtf8("label_33"));
|
||||
label_33->setGeometry(QRect(940, 780, 86, 31));
|
||||
label_33->setFont(font5);
|
||||
label_10 = new QLabel(tab_2);
|
||||
label_10->setObjectName(QString::fromUtf8("label_10"));
|
||||
label_10->setGeometry(QRect(717, 720, 43, 31));
|
||||
label_10->setFont(font5);
|
||||
label_18 = new QLabel(tab_2);
|
||||
label_18->setObjectName(QString::fromUtf8("label_18"));
|
||||
label_18->setGeometry(QRect(870, 720, 43, 31));
|
||||
label_18->setFont(font5);
|
||||
InputNum2 = new QLineEdit(tab_2);
|
||||
InputNum2->setObjectName(QString::fromUtf8("InputNum2"));
|
||||
InputNum2->setGeometry(QRect(930, 720, 81, 30));
|
||||
InputNum2->setFont(font7);
|
||||
label_12 = new QLabel(tab_2);
|
||||
label_12->setObjectName(QString::fromUtf8("label_12"));
|
||||
label_12->setGeometry(QRect(40, 630, 141, 21));
|
||||
label_12->setFont(font5);
|
||||
label_21 = new QLabel(tab_2);
|
||||
label_21->setObjectName(QString::fromUtf8("label_21"));
|
||||
label_21->setGeometry(QRect(1030, 720, 91, 31));
|
||||
label_21->setFont(font5);
|
||||
tabWidget->addTab(tab_2, QString());
|
||||
tab_4 = new QWidget();
|
||||
tab_4->setObjectName(QString::fromUtf8("tab_4"));
|
||||
show_resultsImg = new QLabel(tab_4);
|
||||
show_resultsImg->setObjectName(QString::fromUtf8("show_resultsImg"));
|
||||
show_resultsImg->setGeometry(QRect(10, 60, 816, 683));
|
||||
show_resultsImg->setStyleSheet(QString::fromUtf8("background-color: rgb(0, 0, 0);"));
|
||||
label_3 = new QLabel(tab_4);
|
||||
label_3->setObjectName(QString::fromUtf8("label_3"));
|
||||
label_3->setGeometry(QRect(10, -10, 181, 81));
|
||||
label_3->setFont(font5);
|
||||
tab4_ReturnToMain = new QPushButton(tab_4);
|
||||
tab4_ReturnToMain->setObjectName(QString::fromUtf8("tab4_ReturnToMain"));
|
||||
tab4_ReturnToMain->setGeometry(QRect(1530, 830, 291, 101));
|
||||
tab4_ReturnToMain->setStyleSheet(QString::fromUtf8("font: 30pt \"\345\256\213\344\275\223\";"));
|
||||
resoult_info_label = new QPlainTextEdit(tab_4);
|
||||
resoult_info_label->setObjectName(QString::fromUtf8("resoult_info_label"));
|
||||
resoult_info_label->setGeometry(QRect(950, 60, 871, 681));
|
||||
resoult_info_label->setStyleSheet(QString::fromUtf8("font: 10pt \"\345\276\256\350\275\257\351\233\205\351\273\221\";"));
|
||||
choose_pa_2 = new QPushButton(tab_4);
|
||||
choose_pa_2->setObjectName(QString::fromUtf8("choose_pa_2"));
|
||||
choose_pa_2->setGeometry(QRect(10, 830, 161, 91));
|
||||
choose_pa_2->setFont(font5);
|
||||
choose_pa_2->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
label_13 = new QLabel(tab_4);
|
||||
label_13->setObjectName(QString::fromUtf8("label_13"));
|
||||
label_13->setGeometry(QRect(10, 750, 141, 21));
|
||||
label_13->setFont(font5);
|
||||
choose_to_2 = new QPushButton(tab_4);
|
||||
choose_to_2->setObjectName(QString::fromUtf8("choose_to_2"));
|
||||
choose_to_2->setGeometry(QRect(210, 830, 161, 91));
|
||||
choose_to_2->setFont(font5);
|
||||
choose_to_2->setStyleSheet(QString::fromUtf8("color: rgb(0, 0, 0);"));
|
||||
tabWidget->addTab(tab_4, QString());
|
||||
|
||||
gridLayout_10->addWidget(tabWidget, 0, 0, 1, 1);
|
||||
|
||||
|
||||
retranslateUi(Widget);
|
||||
|
||||
tabWidget->setCurrentIndex(2);
|
||||
|
||||
|
||||
QMetaObject::connectSlotsByName(Widget);
|
||||
} // setupUi
|
||||
|
||||
void retranslateUi(QWidget *Widget)
|
||||
{
|
||||
Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr));
|
||||
label->setText(QCoreApplication::translate("Widget", "\346\236\234\350\224\254\345\210\206\351\200\211\347\240\224\345\217\221\345\233\242\351\230\237", nullptr));
|
||||
label_23->setText(QString());
|
||||
tabWidget->setTabText(tabWidget->indexOf(tab_3), QCoreApplication::translate("Widget", "Tab1", nullptr));
|
||||
groupBox_9->setTitle(QString());
|
||||
groupBox->setTitle(QString());
|
||||
label_14->setText(QCoreApplication::translate("Widget", "\346\236\234\350\224\254\345\210\206\351\200\211\347\240\224\345\217\221\345\233\242\351\230\237", nullptr));
|
||||
label_RGB->setText(QCoreApplication::translate("Widget", "\345\267\246\344\276\247\347\233\270\346\234\272", nullptr));
|
||||
RGBstatus->setText(QCoreApplication::translate("Widget", "\346\234\252\350\277\236\346\216\245", nullptr));
|
||||
label_RGB_3->setText(QCoreApplication::translate("Widget", "\345\217\263\344\276\247\347\233\270\346\234\272", nullptr));
|
||||
RGBstatus_1->setText(QCoreApplication::translate("Widget", "\346\234\252\350\277\236\346\216\245", nullptr));
|
||||
label_RGB_2->setText(QCoreApplication::translate("Widget", "\351\241\266\351\203\250\347\233\270\346\234\272", nullptr));
|
||||
RGBstatus_2->setText(QCoreApplication::translate("Widget", "\346\234\252\350\277\236\346\216\245", nullptr));
|
||||
label_9->setText(QCoreApplication::translate("Widget", "\345\205\211\350\260\261\347\233\270\346\234\272", nullptr));
|
||||
spec_camera_status->setText(QCoreApplication::translate("Widget", "\346\234\252\350\277\236\346\216\245", nullptr));
|
||||
label_11->setText(QCoreApplication::translate("Widget", "PLC", nullptr));
|
||||
plc_status->setText(QCoreApplication::translate("Widget", "\346\234\252\350\277\236\346\216\245", nullptr));
|
||||
label_17->setText(QCoreApplication::translate("Widget", " \346\234\272\346\242\260\346\211\213", nullptr));
|
||||
jxs_status->setText(QCoreApplication::translate("Widget", "\346\234\252\350\277\236\346\216\245", nullptr));
|
||||
label_26->setText(QCoreApplication::translate("Widget", "\345\275\223\345\211\215\345\210\206\351\200\211\346\236\234\350\224\254\357\274\232", nullptr));
|
||||
passionBtn->setText(QCoreApplication::translate("Widget", "\347\231\276\351\246\231\346\236\234", nullptr));
|
||||
tomatoBtn->setText(QCoreApplication::translate("Widget", "\347\225\252\350\214\204", nullptr));
|
||||
btn_start->setText(QCoreApplication::translate("Widget", "\345\274\200\345\247\213\351\207\207\351\233\206", nullptr));
|
||||
show_resoult->setText(QCoreApplication::translate("Widget", "\345\210\206\351\200\211\347\225\214\351\235\242", nullptr));
|
||||
btn_setparam->setText(QCoreApplication::translate("Widget", "\350\256\276\347\275\256\345\217\202\346\225\260", nullptr));
|
||||
btn_save->setText(QCoreApplication::translate("Widget", "\344\277\235\345\255\230\345\233\276\347\211\207", nullptr));
|
||||
view_results->setText(QCoreApplication::translate("Widget", "\346\237\245\347\234\213\347\273\223\346\236\234", nullptr));
|
||||
btn_quit->setText(QCoreApplication::translate("Widget", "\351\200\200\345\207\272\347\263\273\347\273\237", nullptr));
|
||||
groupBox_4->setTitle(QCoreApplication::translate("Widget", "\347\233\270\346\234\272", nullptr));
|
||||
groupBox_2->setTitle(QCoreApplication::translate("Widget", "\351\241\266\351\203\250\344\270\213", nullptr));
|
||||
label_topL->setText(QString());
|
||||
groupBox_3->setTitle(QCoreApplication::translate("Widget", "\351\241\266\351\203\250\344\270\255", nullptr));
|
||||
label_topM->setText(QString());
|
||||
groupBox_5->setTitle(QCoreApplication::translate("Widget", "\351\241\266\351\203\250\344\270\212", nullptr));
|
||||
label_topR->setText(QString());
|
||||
groupBox_6->setTitle(QCoreApplication::translate("Widget", "\345\267\246\344\276\247", nullptr));
|
||||
showimg_right->setText(QString());
|
||||
groupBox_7->setTitle(QCoreApplication::translate("Widget", "\345\217\263\344\276\247", nullptr));
|
||||
showimg_left->setText(QString());
|
||||
groupBox_8->setTitle(QCoreApplication::translate("Widget", "\345\205\211\350\260\261\347\233\270\346\234\272", nullptr));
|
||||
spec_camera_show->setText(QString());
|
||||
tabWidget->setTabText(tabWidget->indexOf(tab), QCoreApplication::translate("Widget", "Tab2", nullptr));
|
||||
groupBox_11->setTitle(QCoreApplication::translate("Widget", "\345\267\246\344\276\247\347\233\270\346\234\272", nullptr));
|
||||
label_28->setText(QCoreApplication::translate("Widget", "\346\233\235\345\205\211\346\227\266\351\227\264\357\274\232", nullptr));
|
||||
label_29->setText(QCoreApplication::translate("Widget", "\347\231\275\345\271\263\350\241\241\357\274\232", nullptr));
|
||||
label_30->setText(QCoreApplication::translate("Widget", "\345\242\236\347\233\212\357\274\232", nullptr));
|
||||
groupBox_13->setTitle(QCoreApplication::translate("Widget", "\351\241\266\344\276\247\347\233\270\346\234\272", nullptr));
|
||||
label_38->setText(QCoreApplication::translate("Widget", "\346\233\235\345\205\211\346\227\266\351\227\264\357\274\232", nullptr));
|
||||
label_39->setText(QCoreApplication::translate("Widget", "\347\231\275\345\271\263\350\241\241\357\274\232", nullptr));
|
||||
label_40->setText(QCoreApplication::translate("Widget", "\345\242\236\347\233\212\357\274\232", nullptr));
|
||||
groupBox_15->setTitle(QCoreApplication::translate("Widget", "\345\217\263\344\276\247\347\233\270\346\234\272", nullptr));
|
||||
label_46->setText(QCoreApplication::translate("Widget", "\346\233\235\345\205\211\346\227\266\351\227\264\357\274\232", nullptr));
|
||||
label_47->setText(QCoreApplication::translate("Widget", "\347\231\275\345\271\263\350\241\241\357\274\232", nullptr));
|
||||
label_48->setText(QCoreApplication::translate("Widget", "\345\242\236\347\233\212\357\274\232", nullptr));
|
||||
btn_enterparam->setText(QCoreApplication::translate("Widget", "\350\256\276\347\275\256\347\233\270\346\234\272\345\217\202\346\225\260", nullptr));
|
||||
tab3_ReturnToMain->setText(QCoreApplication::translate("Widget", " \350\277\224\345\233\236\344\270\273\347\225\214\351\235\242", nullptr));
|
||||
choose_to->setText(QCoreApplication::translate("Widget", "\347\225\252\350\214\204", nullptr));
|
||||
choose_pa->setText(QCoreApplication::translate("Widget", " \347\231\276\351\246\231\346\236\234", nullptr));
|
||||
InputNum1->setText(QString());
|
||||
InputNum5->setText(QString());
|
||||
label_5->setText(QCoreApplication::translate("Widget", "\351\230\210\345\200\274\346\240\207\345\207\206\357\274\232", nullptr));
|
||||
InputNum4->setText(QString());
|
||||
set_threshoid->setText(QCoreApplication::translate("Widget", " \350\256\276\345\256\232\351\230\210\345\200\274", nullptr));
|
||||
label_32->setText(QCoreApplication::translate("Widget", "\347\274\272\351\231\267\346\225\260\351\207\217", nullptr));
|
||||
label_33->setText(QCoreApplication::translate("Widget", "\347\274\272\351\231\267\351\235\242\347\247\257", nullptr));
|
||||
label_10->setText(QCoreApplication::translate("Widget", "\347\263\226\345\272\246", nullptr));
|
||||
label_18->setText(QCoreApplication::translate("Widget", "\347\233\264\345\276\204", nullptr));
|
||||
InputNum2->setText(QString());
|
||||
label_12->setText(QCoreApplication::translate("Widget", "\350\257\267\351\200\211\346\213\251\346\236\234\350\224\254\357\274\232", nullptr));
|
||||
label_21->setText(QCoreApplication::translate("Widget", "\351\242\234\350\211\262\345\215\240\346\257\224", nullptr));
|
||||
tabWidget->setTabText(tabWidget->indexOf(tab_2), QCoreApplication::translate("Widget", "Tab3", nullptr));
|
||||
show_resultsImg->setText(QString());
|
||||
label_3->setText(QCoreApplication::translate("Widget", "\345\244\204\347\220\206\347\273\223\346\236\234\345\233\276\357\274\232", nullptr));
|
||||
tab4_ReturnToMain->setText(QCoreApplication::translate("Widget", "\350\277\224\345\233\236\344\270\273\347\225\214\351\235\242", nullptr));
|
||||
choose_pa_2->setText(QCoreApplication::translate("Widget", " \347\231\276\351\246\231\346\236\234", nullptr));
|
||||
label_13->setText(QCoreApplication::translate("Widget", "\345\275\223\345\211\215\345\210\206\347\261\273\346\236\234\350\224\254\357\274\232", nullptr));
|
||||
choose_to_2->setText(QCoreApplication::translate("Widget", "\347\225\252\350\214\204", nullptr));
|
||||
tabWidget->setTabText(tabWidget->indexOf(tab_4), QCoreApplication::translate("Widget", "Tab4", nullptr));
|
||||
} // retranslateUi
|
||||
|
||||
};
|
||||
|
||||
namespace Ui {
|
||||
class Widget: public Ui_Widget {};
|
||||
} // namespace Ui
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // UI_WIDGET_H
|
||||
663
widget.cpp
Normal file
663
widget.cpp
Normal file
@ -0,0 +1,663 @@
|
||||
#include "widget.h"
|
||||
#include "ui_widget.h"
|
||||
#include "camera.h"
|
||||
#include <QDateTime>
|
||||
#include "QSemaphore"
|
||||
#include "vector"
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
#define sys_file2 "./sys_daytime2.txt"
|
||||
//外部引用
|
||||
extern ProcessImg *processimg;
|
||||
extern SendThread *sendthread;
|
||||
extern RecvThread *recvthread;
|
||||
|
||||
extern CameraL *cameraL;
|
||||
extern SpecCamera *speccamera;
|
||||
|
||||
extern QSemaphore emptybuff;
|
||||
extern tomato tomato;
|
||||
|
||||
// c++的省略命名申明
|
||||
using namespace std;
|
||||
bool is_timeout;
|
||||
|
||||
int start_flag=1;
|
||||
int save_flag=0;
|
||||
|
||||
//0为番茄 1为百香果
|
||||
int fruit_flag;
|
||||
|
||||
int resoult_count = 1;
|
||||
|
||||
int i = 1;
|
||||
|
||||
|
||||
|
||||
//外部用用
|
||||
extern int camStatusret;
|
||||
extern int camStatusret1;
|
||||
extern int camStatusret2;
|
||||
|
||||
extern int img_count;
|
||||
extern int img_count1;
|
||||
extern int img_count2;
|
||||
//定义管道名称
|
||||
extern HANDLE hPipe;
|
||||
extern HANDLE specPipe;
|
||||
extern HANDLE RPipe;
|
||||
extern QString pipeName;
|
||||
extern QString pipeName2;
|
||||
extern QString rePipe;
|
||||
|
||||
int pipe_counter=1;
|
||||
|
||||
|
||||
//这是 Widge 的构造函数 在你点击运行之后 会执行
|
||||
Widget::Widget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::Widget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
//直接导入本地时间(方法二)
|
||||
|
||||
QFile daytime_file(sys_file2);
|
||||
QDateTime lastDateTime;
|
||||
if (daytime_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QString line;
|
||||
QTextStream in(&daytime_file);
|
||||
while (!in.atEnd()) {
|
||||
line = in.readLine();
|
||||
}
|
||||
QStringList parts = line.split(" - ");
|
||||
if (parts.size() > 0) {
|
||||
lastDateTime = QDateTime::fromString(parts.first(), "yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
daytime_file.close();
|
||||
}
|
||||
if (lastDateTime.isValid() && lastDateTime > QDateTime::currentDateTime()) {
|
||||
QMessageBox::about(this, "错误", "时间校验不通过");
|
||||
throw ExpiredException();
|
||||
}
|
||||
QDateTime expiryDate = QDateTime::fromString("2024-08-01 14:00:00", "yyyy-MM-dd HH:mm:ss");
|
||||
QDateTime currentDate = QDateTime::currentDateTime();
|
||||
if (currentDate >= expiryDate) {
|
||||
|
||||
throw ExpiredException();
|
||||
}
|
||||
|
||||
//处理光谱数据的线程
|
||||
processimg = new ProcessImg();
|
||||
//发送给python端线程
|
||||
sendthread = new SendThread();
|
||||
//接收python端线程
|
||||
recvthread = new RecvThread();
|
||||
//new 代表给三个线程开辟空间
|
||||
|
||||
initparam();
|
||||
|
||||
/**连接相机*/
|
||||
cameraL = new CameraL();
|
||||
//初始化RGB相机
|
||||
bool RGB_ret = cameraL->initCameraL();
|
||||
|
||||
if(camStatusret ==0 && RGB_ret)
|
||||
{
|
||||
ui->RGBstatus->setText("已连接");
|
||||
ui->RGBstatus->setStyleSheet("QLabel{color:rgb(0,255,0);}");
|
||||
}
|
||||
if(camStatusret1 ==0 && RGB_ret)
|
||||
{
|
||||
ui->RGBstatus_1->setText("已连接");
|
||||
ui->RGBstatus_1->setStyleSheet("QLabel{color:rgb(0,255,0);}");
|
||||
|
||||
}
|
||||
if(camStatusret2 ==0 && RGB_ret)
|
||||
{
|
||||
ui->RGBstatus_2->setText("已连接");
|
||||
ui->RGBstatus_2->setStyleSheet("QLabel{color:rgb(0,255,0);}");
|
||||
}
|
||||
|
||||
//初始化光谱相机
|
||||
speccamera = new SpecCamera();
|
||||
bool spec_ret = speccamera->init_SpecCamera();
|
||||
|
||||
if(spec_ret == true)
|
||||
{
|
||||
ui->spec_camera_status->setText("已连接");
|
||||
ui->spec_camera_status->setStyleSheet("QLabel{color:rgb(0,255,0);}");
|
||||
}
|
||||
|
||||
//初始化称重模块
|
||||
connectModbus_CZ();
|
||||
|
||||
//初始化机械手
|
||||
connect_socket_Jxs();
|
||||
|
||||
//管道建立连接
|
||||
connectPipe();
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
//初始话参数 并非实际相机的参数 而是 ui 界面上的 tab3 上的控件参数
|
||||
void Widget::initparam()
|
||||
{
|
||||
camStatusret=-1;
|
||||
camStatusret1=-1;
|
||||
camStatusret2=-1;
|
||||
ui->tabWidget->setCurrentIndex(2);
|
||||
setMinimumSize(QSize(1200, 600));
|
||||
setWindowState(Qt::WindowMaximized);
|
||||
}
|
||||
|
||||
void Widget::connectModbus_CZ()
|
||||
{
|
||||
//称重模块
|
||||
CZ = modbus_new_tcp("192.168.101.110",2000);
|
||||
modbus_set_slave(CZ, 1); //设置modbus从机地址
|
||||
int status = modbus_connect(CZ);
|
||||
if(status == -1)
|
||||
{
|
||||
qDebug() << "modbus connect failed";
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->plc_status->setStyleSheet("QLabel{color:rgb(0,255,0);}");
|
||||
ui->plc_status->setText("已连接");
|
||||
}
|
||||
modbus_set_response_timeout(CZ, 0, 1000000);
|
||||
}
|
||||
|
||||
void Widget::connect_socket_Jxs()
|
||||
{
|
||||
server = new QTcpServer();
|
||||
server->listen(QHostAddress::Any, 21123);
|
||||
|
||||
bool is_timeout;
|
||||
server->waitForNewConnection(5000, &is_timeout);
|
||||
|
||||
if(is_timeout == true)
|
||||
{
|
||||
qDebug() << "Jxs connect failed";
|
||||
return;
|
||||
}
|
||||
|
||||
socket = server->nextPendingConnection();
|
||||
|
||||
ui->jxs_status->setStyleSheet("QLabel{color:rgb(0,255,0);}");
|
||||
ui->jxs_status->setText("已连接");
|
||||
}
|
||||
|
||||
void Widget::connectPipe()
|
||||
{
|
||||
|
||||
// 创建并连接到命名管道
|
||||
hPipe = CreateFile(
|
||||
(LPCWSTR)pipeName.utf16(), // 管道名称
|
||||
GENERIC_WRITE, // 写入访问
|
||||
0, // 不共享
|
||||
NULL, // 默认安全属性
|
||||
OPEN_EXISTING, // 打开现有管道
|
||||
FILE_ATTRIBUTE_NORMAL, // 默认属性
|
||||
NULL // 没有模板文件
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
// 创建并连接到命名管道(光谱相机发送)
|
||||
specPipe = CreateFile(
|
||||
(LPCWSTR)pipeName2.utf16(), // 管道名称
|
||||
GENERIC_WRITE, // 写入访问
|
||||
0, // 不共享
|
||||
NULL, // 默认安全属性
|
||||
OPEN_EXISTING, // 打开现有管道
|
||||
FILE_ATTRIBUTE_NORMAL, // 默认属性
|
||||
NULL // 没有模板文件
|
||||
);
|
||||
|
||||
|
||||
// 创建并连接到命名管道
|
||||
RPipe = CreateFile(
|
||||
(LPCWSTR)rePipe.utf16(), // 管道名称
|
||||
GENERIC_READ, // 更改为读取访问
|
||||
0, // 不共享
|
||||
NULL, // 默认安全属性
|
||||
OPEN_EXISTING, // 打开现有管道
|
||||
FILE_ATTRIBUTE_NORMAL, // 默认属性
|
||||
NULL // 没有模板文件
|
||||
);
|
||||
|
||||
if (RPipe == INVALID_HANDLE_VALUE) {
|
||||
qWarning() << "Failed to open pipe for reading:" << GetLastError();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//点击 ui 界面的开始按钮
|
||||
void Widget::on_btn_start_clicked()
|
||||
{
|
||||
//start_flag 为 1
|
||||
if(start_flag)
|
||||
{
|
||||
QFile file(sys_file2);
|
||||
if (file.open(QIODevice::Append | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss") << " - " << "\n";
|
||||
file.close();
|
||||
}
|
||||
ui->btn_start->setStyleSheet("background-color: red;");
|
||||
|
||||
cameraL->open_camera2();
|
||||
cameraL->set_acquisition_mode();
|
||||
cameraL->start_capture();
|
||||
speccamera->start_capture();
|
||||
|
||||
//开启线程 也就是执行一次对应线程的 run() 函数 在 thread 里面有 即执行三个线程的 while(1) 死循环 一直监听
|
||||
processimg->start();
|
||||
sendthread->start();
|
||||
recvthread->start();
|
||||
|
||||
//连接信号跟槽函数
|
||||
connect(cameraL,SIGNAL(send_Rgbimage(QImage&)),this,SLOT(showimg(QImage&)),Qt::BlockingQueuedConnection);
|
||||
connect(cameraL,SIGNAL(send_Rgbimage1(QImage&)),this,SLOT(showimg1(QImage&)),Qt::BlockingQueuedConnection);
|
||||
connect(cameraL,SIGNAL(send_Rgbimage2(QImage&,QImage&,QImage&)),this,SLOT(showimg2(QImage&,QImage&,QImage&)),Qt::BlockingQueuedConnection);
|
||||
connect(speccamera,SIGNAL(show_SpecImg(QImage)),this,SLOT(show_specImgSlots(QImage)));
|
||||
connect(recvthread,SIGNAL(recv_Data(quint16,quint8,quint16,quint8,quint16,quint32,quint16,quint16,QImage)),this,SLOT(receiveDataSlots(quint16,quint8,quint16,quint8,quint16,quint32,quint16,quint16,QImage)));
|
||||
|
||||
|
||||
|
||||
start_flag=0;
|
||||
|
||||
ui->tabWidget->setCurrentIndex(3);
|
||||
|
||||
// qDebug()<<"Start Success!";
|
||||
}
|
||||
|
||||
//start_flag 为 0
|
||||
else
|
||||
{
|
||||
QFile file(sys_file2);
|
||||
if (file.open(QIODevice::Append | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss") << " - " << "\n";
|
||||
file.close();
|
||||
}
|
||||
ui->btn_start->setStyleSheet("background-color: white;");
|
||||
cameraL->stop_capture();
|
||||
speccamera->stop_capture();
|
||||
|
||||
disconnect(cameraL,SIGNAL(send_Rgbimage(QImage&)),this,SLOT(showimg(QImage&)));
|
||||
disconnect(cameraL,SIGNAL(send_Rgbimage1(QImage&)),this,SLOT(showimg1(QImage&)));
|
||||
disconnect(cameraL,SIGNAL(send_Rgbimage2(QImage&,QImage&,QImage&)),this,SLOT(showimg2(QImage&,QImage&,QImage&)));
|
||||
disconnect(speccamera,SIGNAL(show_SpecImg(QImage)),this,SLOT(show_specImgSlots(QImage)));
|
||||
disconnect(recvthread,SIGNAL(recv_Data(quint16,quint8,quint16,quint8,quint16,quint32,quint16,quint16,QImage)),this,SLOT(receiveDataSlots(quint16,quint8,quint16,quint8,quint16,quint32,quint16,quint16,QImage)));
|
||||
ui->showimg_left->clear();
|
||||
ui->showimg_right->clear();
|
||||
ui->label_topL->clear();
|
||||
ui->label_topM->clear();
|
||||
ui->label_topR->clear();
|
||||
|
||||
start_flag=1;
|
||||
|
||||
// qDebug() << "Stop Success!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//右侧
|
||||
void Widget::showimg(QImage& img)
|
||||
{
|
||||
|
||||
pix = QPixmap::fromImage(img.scaled(ui->showimg_left->width(),ui->showimg_left->height(),Qt::KeepAspectRatio));
|
||||
ui->showimg_left->setScaledContents(true);
|
||||
ui->showimg_left->setPixmap(pix);
|
||||
ui->showimg_left->show();
|
||||
}
|
||||
|
||||
//左侧
|
||||
void Widget::showimg1(QImage& img)
|
||||
{
|
||||
|
||||
pix = QPixmap::fromImage(img.scaled(ui->showimg_right->width(),ui->showimg_right->height(),Qt::KeepAspectRatio));
|
||||
ui->showimg_right->setScaledContents(true);
|
||||
ui->showimg_right->setPixmap(pix);
|
||||
ui->showimg_right->show();
|
||||
}
|
||||
|
||||
//顶部
|
||||
void Widget::showimg2(QImage& img,QImage& img1,QImage& img2)
|
||||
{
|
||||
pix = QPixmap::fromImage(img.scaled(ui->label_topL->width(),ui->label_topL->height(),Qt::KeepAspectRatio));
|
||||
ui->label_topL->setScaledContents(true);
|
||||
ui->label_topL->setPixmap(pix);
|
||||
ui->label_topL->show();
|
||||
|
||||
pix1 = QPixmap::fromImage(img1.scaled(ui->label_topM->width(),ui->label_topM->height(),Qt::KeepAspectRatio));
|
||||
ui->label_topM->setScaledContents(true);
|
||||
ui->label_topM->setPixmap(pix1);
|
||||
ui->label_topM->show();
|
||||
|
||||
pix2 = QPixmap::fromImage(img2.scaled(ui->label_topR->width(),ui->label_topR->height(),Qt::KeepAspectRatio));
|
||||
ui->label_topR->setScaledContents(true);
|
||||
ui->label_topR->setPixmap(pix2);
|
||||
ui->label_topR->show();
|
||||
}
|
||||
|
||||
void Widget::on_save_img_clicked()
|
||||
{
|
||||
save_flag=1;
|
||||
}
|
||||
|
||||
|
||||
//退出
|
||||
void Widget::on_btn_quit_clicked()
|
||||
{
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
|
||||
//保存图片按钮
|
||||
void Widget::on_btn_save_clicked()
|
||||
{
|
||||
if(!save_flag)
|
||||
{
|
||||
ui->btn_save->setStyleSheet("background-color: red;");
|
||||
save_flag=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->btn_save->setStyleSheet("background-color: white;");
|
||||
save_flag=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Widget::on_btn_setparam_clicked()
|
||||
{
|
||||
ui->tabWidget->setCurrentIndex(2);
|
||||
}
|
||||
|
||||
//导入参数 实际没用 因为相机参数会预先写死 并不会在运行途中更换
|
||||
void Widget::on_btn_enterparam_clicked()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//接受线程收到数据 长径、短径等等 在 ui 界面显示
|
||||
void Widget::receiveDataSlots(quint16 brix,quint8 greenPercentage,quint16 diameter,quint8 weight,quint16 defectNum,quint32 totalDefectArea,quint16 height,quint16 width,QImage img)
|
||||
{
|
||||
img = img.rgbSwapped();
|
||||
|
||||
pix = QPixmap::fromImage(img.scaled(ui->show_resultsImg->width(),ui->show_resultsImg->height(),Qt::KeepAspectRatio));
|
||||
ui->show_resultsImg->setScaledContents(true);
|
||||
ui->show_resultsImg->setPixmap(pix);
|
||||
ui->show_resultsImg->show();
|
||||
|
||||
float brix_float = brix;
|
||||
float totalDefectArea_float = totalDefectArea;
|
||||
float greenPercentage_float = greenPercentage;
|
||||
float diameter_float = diameter;
|
||||
// ui->Tdangdu_line->setText(QString::number(brix_float/1000)); //
|
||||
// ui->Zhijing_line->setText(QString::number(diameter_float/100)); //cm
|
||||
// ui->Shuliang_line->setText(QString::number(defectNum));
|
||||
// ui->Mianji_line->setText(QString::number(totalDefectArea_float/1000)); //cm^2
|
||||
// ui->Zhanbi_line->setText(QString::number(greenPercentage_float/100)); //
|
||||
|
||||
//重量是g
|
||||
//读取称重数据
|
||||
uint16_t read = 0;
|
||||
modbus_read_registers(CZ,0x40000,1,&read);
|
||||
qDebug()<<"称重数据"<<read;
|
||||
|
||||
int level = 5;
|
||||
//百香果
|
||||
if(fruit_flag)
|
||||
{
|
||||
if(diameter = 0)
|
||||
{
|
||||
level = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(defectNum = 0)
|
||||
{
|
||||
level = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(totalDefectArea_float/1000 > 2)
|
||||
{
|
||||
level = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(read > 90)
|
||||
{
|
||||
level = 1;
|
||||
}
|
||||
else if(read < 65)
|
||||
{
|
||||
level = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
level = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//番茄
|
||||
else
|
||||
{
|
||||
if(diameter == 0)
|
||||
{
|
||||
level = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(defectNum != 0)
|
||||
{
|
||||
level = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(totalDefectArea_float/1000 >= Quexianmianji)
|
||||
{
|
||||
level = 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(greenPercentage_float/100 >= Yansezhanbi)
|
||||
{
|
||||
if(diameter_float/100 >= Zhijing -2)
|
||||
{
|
||||
level = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
level = 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(diameter_float/100 >= Zhijing)
|
||||
{
|
||||
level = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
level = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ui->resoult_line->setText(QString::number(level));
|
||||
qDebug()<<"果子等级为:"<<level;
|
||||
|
||||
//窗口显示
|
||||
|
||||
if(resoult_count%25 == 0)
|
||||
{
|
||||
ui->resoult_info_label->clear();
|
||||
}
|
||||
|
||||
QString resout_info;
|
||||
QString fruit_resoult_flag;
|
||||
//百香果
|
||||
if(fruit_flag)
|
||||
{
|
||||
if(defectNum == 0)
|
||||
{
|
||||
fruit_resoult_flag = "有";
|
||||
}
|
||||
else
|
||||
{
|
||||
fruit_resoult_flag = "无";
|
||||
}
|
||||
resout_info = QString("当前百香果编号为:%1 糖度值为: %2 直径为: %3 %4皱缩 缺陷面积为: %5 最终识别结果为:%6 ").arg(resoult_count).arg(brix_float/1000).arg(diameter_float/100).arg(fruit_resoult_flag).arg(totalDefectArea_float/1000).arg(level);
|
||||
ui->resoult_info_label->appendPlainText(resout_info);
|
||||
}
|
||||
//番茄
|
||||
else
|
||||
{
|
||||
if(defectNum == 0)
|
||||
{
|
||||
fruit_resoult_flag = "无";
|
||||
}
|
||||
else
|
||||
{
|
||||
fruit_resoult_flag = "有";
|
||||
}
|
||||
resout_info = QString("当前番茄编号为:%1 直径为: %2 %3裂口 缺陷面积为: %4 绿色占比为: %5 最终识别结果为:%6 ").arg(resoult_count).arg(diameter_float/100).arg(fruit_resoult_flag).arg(totalDefectArea_float/1000).arg(greenPercentage_float/100).arg(level);
|
||||
ui->resoult_info_label->appendPlainText(resout_info);
|
||||
}
|
||||
|
||||
resoult_count++ ;
|
||||
QFile file("./image/output.txt");
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
|
||||
{
|
||||
QTextStream out(&file);
|
||||
out << resout_info << "\n";
|
||||
file.close();
|
||||
}
|
||||
i++;
|
||||
|
||||
// 给机械手发送信息
|
||||
QString txt = QString("[X:0;Y:0;A:0;ATTR:%1;ID:%2]").arg(level).arg(fruit_flag);
|
||||
QByteArray byteArray = txt.toUtf8();
|
||||
socket->write(byteArray);
|
||||
// qDebug()<<"发送机械手信息等级为:"<<level;
|
||||
|
||||
//给plc发送信息
|
||||
uint16_t write[2];
|
||||
write[0] = resoult_count;
|
||||
write[1] = level;
|
||||
modbus_write_registers(CZ,0x40001,2,write);
|
||||
// qDebug()<<"发送plc信息等级为:"<<level;
|
||||
|
||||
|
||||
|
||||
//称重数据在 read 里面
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//显示光谱伪彩色图 实际效果很差 就取消了
|
||||
//展示一条折线
|
||||
void Widget::show_specImgSlots(QImage img)
|
||||
{
|
||||
// qDebug()<<"2";
|
||||
QTransform transform;
|
||||
transform.rotate(90.0);
|
||||
img = img.transformed(transform, Qt::FastTransformation);
|
||||
|
||||
pix = QPixmap::fromImage(img.scaled(ui->spec_camera_show->width(),ui->spec_camera_show->height(),Qt::KeepAspectRatio));
|
||||
ui->spec_camera_show->setScaledContents(true);
|
||||
ui->spec_camera_show->setPixmap(pix);
|
||||
ui->spec_camera_show->show();
|
||||
}
|
||||
|
||||
|
||||
void Widget::on_view_results_clicked()
|
||||
{
|
||||
QString resoult_path = "C:/Users/succtech/Desktop/20240425/image";
|
||||
// 打开文件选择对话框,并设置默认路径
|
||||
QString filePath = QFileDialog::getOpenFileName(this, "查看结果", resoult_path);
|
||||
}
|
||||
|
||||
void Widget::on_tab4_ReturnToMain_clicked()
|
||||
{
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void Widget::on_choose_pa_clicked()
|
||||
{
|
||||
fruit_flag = 1;
|
||||
//tab2
|
||||
ui->passionBtn->setStyleSheet("background-color: red;");
|
||||
ui->tomatoBtn->setStyleSheet("background-color: white;");
|
||||
|
||||
//tab3
|
||||
ui->choose_pa->setStyleSheet("background-color: red;");
|
||||
ui->choose_to->setStyleSheet("background-color: white;");
|
||||
|
||||
//tab4
|
||||
ui->choose_pa_2->setStyleSheet("background-color: red;");
|
||||
ui->choose_to_2->setStyleSheet("background-color: white;");
|
||||
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void Widget::on_choose_to_clicked()
|
||||
{
|
||||
fruit_flag = 0;
|
||||
//tab2
|
||||
ui->tomatoBtn->setStyleSheet("background-color: red;");
|
||||
ui->passionBtn->setStyleSheet("background-color: white;");
|
||||
|
||||
//tab3
|
||||
ui->choose_to->setStyleSheet("background-color: red;");
|
||||
ui->choose_pa->setStyleSheet("background-color: white;");
|
||||
|
||||
//tab4
|
||||
ui->choose_to_2->setStyleSheet("background-color: red;");
|
||||
ui->choose_pa_2->setStyleSheet("background-color: white;");
|
||||
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void Widget::on_tab3_ReturnToMain_clicked()
|
||||
{
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
}
|
||||
|
||||
void Widget::on_show_resoult_clicked()
|
||||
{
|
||||
ui->tabWidget->setCurrentIndex(3);
|
||||
}
|
||||
|
||||
void Widget::on_set_threshoid_clicked()
|
||||
{
|
||||
Tangdu = ui->InputNum1->text().toInt();
|
||||
Zhijing = ui->InputNum2->text().toInt();
|
||||
Yansezhanbi = ui->InputNum3->text().toInt();
|
||||
Quexianshuliang = ui->InputNum4->text().toInt();
|
||||
Quexianmianji = ui->InputNum5->text().toInt();
|
||||
}
|
||||
|
||||
114
widget.h
Normal file
114
widget.h
Normal file
@ -0,0 +1,114 @@
|
||||
#ifndef WIDGET_H
|
||||
#define WIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "QMessageBox"
|
||||
#include "thread.h"
|
||||
#include <unistd.h>
|
||||
#include "QMessageBox"
|
||||
#include "src/modbus.h"
|
||||
|
||||
#include <QImage>
|
||||
#define SAVE_IMAGE_PATH "F:/tomato/tomato1227/image/left"
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
|
||||
//ui界面的类 窗口的各种控件(按钮、文字输入行、label等)
|
||||
namespace Ui { class Widget; }
|
||||
QT_END_NAMESPACE
|
||||
class ExpiredException : public std::exception {
|
||||
public:
|
||||
const char* what() const throw() {
|
||||
return "程序试用期已过,请联系供应商!";
|
||||
}
|
||||
};
|
||||
class Widget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Widget(QWidget *parent = nullptr);
|
||||
~Widget();
|
||||
|
||||
int Tangdu;
|
||||
int Zhijing = 7;
|
||||
float Yansezhanbi = 0.3;
|
||||
int Quexianshuliang = 0;
|
||||
float Quexianmianji = 0.5;
|
||||
|
||||
void initparam();
|
||||
|
||||
|
||||
|
||||
void connectModbus_CZ();
|
||||
|
||||
void connect_socket_Jxs();
|
||||
void connectPipe();
|
||||
|
||||
QTcpServer *server;
|
||||
QTcpSocket *socket;
|
||||
|
||||
modbus_t* CZ;
|
||||
|
||||
private slots:
|
||||
void on_btn_start_clicked();
|
||||
|
||||
void showimg1(QImage&);
|
||||
void showimg(QImage&);
|
||||
void showimg2(QImage&,QImage&,QImage&);
|
||||
|
||||
|
||||
void on_save_img_clicked();
|
||||
|
||||
void on_btn_quit_clicked();
|
||||
|
||||
void on_btn_save_clicked();
|
||||
|
||||
void on_btn_setparam_clicked();
|
||||
|
||||
void on_btn_enterparam_clicked();
|
||||
|
||||
void receiveDataSlots(quint16,quint8,quint16,quint8,quint16,quint32,quint16,quint16,QImage);
|
||||
|
||||
void show_specImgSlots(QImage);
|
||||
|
||||
void on_view_results_clicked();
|
||||
|
||||
void on_tab4_ReturnToMain_clicked();
|
||||
|
||||
void on_choose_pa_clicked();
|
||||
|
||||
void on_choose_to_clicked();
|
||||
|
||||
void on_tab3_ReturnToMain_clicked();
|
||||
|
||||
void on_show_resoult_clicked();
|
||||
|
||||
void on_set_threshoid_clicked();
|
||||
|
||||
private:
|
||||
Ui::Widget *ui;
|
||||
//画板 负责接收QImage并显示 不能直接显示QImage变量
|
||||
QPixmap pix;
|
||||
QPixmap pix1;
|
||||
QPixmap pix2;
|
||||
|
||||
int m_index;
|
||||
|
||||
|
||||
|
||||
//存图标志位
|
||||
int save_img=0;
|
||||
|
||||
//tcp变量
|
||||
|
||||
QTcpServer* server_to_lowermachine = nullptr;
|
||||
QTcpSocket* lower_machine = nullptr;
|
||||
volatile bool is_running = false;
|
||||
|
||||
|
||||
|
||||
};
|
||||
#endif // WIDGET_H
|
||||
Loading…
Reference in New Issue
Block a user