bug_fix 界面显示部分
This commit is contained in:
parent
709ea0f6fd
commit
091257d18e
629
Makefile.Debug
629
Makefile.Debug
File diff suppressed because one or more lines are too long
629
Makefile.Release
629
Makefile.Release
File diff suppressed because one or more lines are too long
34
camera.cpp
34
camera.cpp
@ -548,12 +548,20 @@ MIL_INT ProcessingFunction1(MIL_INT HookType, MIL_ID HookId, void *HookDataPtr)
|
||||
//将mask扩展到合适发送的大小
|
||||
std::vector<std::vector<uint8_t>> mask_Total = expandArray(mask_expaned,64);
|
||||
|
||||
|
||||
if(!g_lower_machine_connected.load())
|
||||
{
|
||||
qWarning() << "下位机未连接";
|
||||
#if(GlobalDebug && DebugDetectionTime)
|
||||
call_back_timer1.printElapsedTime("CallBack2: Total time spent: ");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
// 发送到下位机
|
||||
bool result_Low = get_valve_data(mask_Total);
|
||||
if(!result_Low)
|
||||
{
|
||||
qWarning()<<"下位机发送失败";
|
||||
g_lower_machine_connected.store(result_Low);
|
||||
qWarning() << "下位机发送失败";
|
||||
}
|
||||
|
||||
|
||||
@ -797,7 +805,6 @@ bool iniColor()
|
||||
|
||||
bool iniOnnx()
|
||||
{
|
||||
|
||||
std::string modelPath = (getConfigDirectory() + "/dimo_369_640.onnx").toStdString();
|
||||
|
||||
runner.load(modelPath);
|
||||
@ -823,7 +830,7 @@ bool iniLowMac()
|
||||
|
||||
if(is_timeout)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
#if(GlobalDebug && DebugLowerMacCOM)
|
||||
qDebug()<<"4/4. Connection Established no timeout";
|
||||
@ -837,13 +844,13 @@ bool iniLowMac()
|
||||
|
||||
if (lower_machine == nullptr || !lower_machine->isWritable()) {
|
||||
cout << "Error: Lower machine is not available or writable." << endl;
|
||||
return 0 ;
|
||||
return false ;
|
||||
}
|
||||
return setLowMacParam();
|
||||
}
|
||||
|
||||
|
||||
bool setLowMacParam(){
|
||||
try {
|
||||
// 计算 Y = 100000000 / X
|
||||
int divide_camera = (file_encoder != 0) ? 100000000 / file_encoder : 0; // 防止除以零的情况
|
||||
int divide_valve = (file_valve != 0) ? 100000000 / file_valve : 0; // 防止除以零的情况
|
||||
@ -1039,7 +1046,10 @@ bool setLowMacParam(){
|
||||
cout << "Error: Unable to write to lower machine for td parameter." << endl;
|
||||
}
|
||||
delete[] td_buf;
|
||||
|
||||
} catch (...) {
|
||||
qWarning() << "Set lower machine parameters failed!!!";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1067,13 +1077,13 @@ bool DestoryLowMac()
|
||||
is_running = false;
|
||||
}
|
||||
|
||||
|
||||
bool get_valve_data(std::vector<std::vector<uint8_t>> mask)
|
||||
{
|
||||
if (mask[0].size() % 8 != 0) {
|
||||
std::cerr << "Error: mask 的第 0 行的列数应该为 8 的倍数。" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t* mask_buf = new uint8_t[4096 + 8]; // 创建缓冲区,大小为3072 + 8
|
||||
mask_buf[0] = 0xAA; // 起始标志
|
||||
mask_buf[1] = 0x10; // 高位数据长度 (352 字节 -> 0x0160)
|
||||
@ -1126,12 +1136,10 @@ bool get_valve_data(std::vector<std::vector<uint8_t>> mask)
|
||||
else
|
||||
{
|
||||
std::cout << "*** lower machine connect failed! *** " << std::endl;
|
||||
// ui->lab_lowermachine_isconnect->setStyleSheet("QLabel{background-color: rgb(237, 212, 0);}"); // 显示连接失败
|
||||
// ui->lab_lowermachine_isconnect->repaint(); // 强制刷新UI
|
||||
}
|
||||
|
||||
delete[] mask_buf; // 释放内存
|
||||
|
||||
return false;
|
||||
}
|
||||
delete[] mask_buf; // 释放内存
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -5,33 +5,50 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
CONFIG += c++17
|
||||
CONFIG += console
|
||||
|
||||
DEFINES += WIN32_LEAN_AND_MEAN
|
||||
DEFINES += _WINSOCKAPI_
|
||||
|
||||
|
||||
# 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 += \
|
||||
countdown_dialog.cpp \
|
||||
libmodbus/modbus-data.c \
|
||||
libmodbus/modbus-rtu.c \
|
||||
libmodbus/modbus-tcp.c \
|
||||
libmodbus/modbus.c \
|
||||
camera.cpp \
|
||||
color_algorithms.cpp \
|
||||
countdowndialog.cpp \
|
||||
detectionworker.cpp \
|
||||
detection_worker.cpp \
|
||||
globals.cpp \
|
||||
img_utils.cpp \
|
||||
lower_machine.cpp \
|
||||
main.cpp \
|
||||
onnxrunner.cpp \
|
||||
storageworker.cpp \
|
||||
plc_connector.cpp \
|
||||
storage_worker.cpp \
|
||||
widget.cpp
|
||||
|
||||
HEADERS += \
|
||||
countdown_dialog.h \
|
||||
libmodbus/modbus-version.h \
|
||||
libmodbus/modbus.h \
|
||||
libmodbus/modbus-private.h \
|
||||
libmodbus/modbus-tcp.h \
|
||||
libmodbus/modbus-tcp-private.h \
|
||||
libmodbus/modbus-rtu.h \
|
||||
libmodbus/modbus-rtu-private.h \
|
||||
camera.h \
|
||||
color_algorithms.h \
|
||||
countdowndialog.h \
|
||||
detectionworker.h \
|
||||
detection_worker.h \
|
||||
globals.h \
|
||||
img_utils.h \
|
||||
lower_machine.h \
|
||||
onnxrunner.h \
|
||||
storageworker.h \
|
||||
plc_connector.h \
|
||||
storage_worker.h \
|
||||
widget.h
|
||||
|
||||
FORMS += \
|
||||
@ -47,8 +64,7 @@ DEPENDPATH += $${PWD}/Include
|
||||
LIBS += -L$${PWD}/LIB -lmil
|
||||
LIBS += -L$${PWD}/LIB -lMilim
|
||||
LIBS += -L$${PWD}/LIB -lmilblob
|
||||
|
||||
|
||||
# LIBS += -Ldll -lws2_32
|
||||
|
||||
LIBS += \
|
||||
# $${PWD}/opencv410-vs22/x64/vc17/lib/*.lib
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 15.0.0, 2025-01-04T20:22:11. -->
|
||||
<!-- Written by QtCreator 15.0.0, 2025-01-08T14:41:38. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// detection_worker.cpp
|
||||
#include "detectionworker.h"
|
||||
#include "detection_worker.h"
|
||||
#include "globals.h"
|
||||
#include <QDebug>
|
||||
#include "onnxrunner.h"
|
||||
@ -5,6 +5,8 @@
|
||||
long long g_valveActionCount = 0;
|
||||
std::atomic<bool> g_camera_error(false);
|
||||
|
||||
std::atomic<bool> g_lower_machine_connected(false);
|
||||
|
||||
// 初始化图片显示互斥锁和MIL_ID
|
||||
QMutex gDispPicMutex0;
|
||||
MIL_ID gDispCurrentPicId0 = 0;
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
// 计数喷阀次数
|
||||
extern long long g_valveActionCount;
|
||||
extern std::atomic<bool> g_camera_error;
|
||||
extern std::atomic<bool> g_lower_machine_connected;
|
||||
|
||||
// 图片显示0
|
||||
extern QMutex gDispPicMutex0;
|
||||
|
||||
233
libmodbus/modbus-data.c
Normal file
233
libmodbus/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
libmodbus/modbus-private.h
Normal file
116
libmodbus/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
libmodbus/modbus-rtu-private.h
Normal file
76
libmodbus/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
libmodbus/modbus-rtu.c
Normal file
1299
libmodbus/modbus-rtu.c
Normal file
File diff suppressed because it is too large
Load Diff
42
libmodbus/modbus-rtu.h
Normal file
42
libmodbus/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
libmodbus/modbus-tcp-private.h
Normal file
44
libmodbus/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
libmodbus/modbus-tcp.c
Normal file
929
libmodbus/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
libmodbus/modbus-tcp.h
Normal file
52
libmodbus/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
libmodbus/modbus-version.h
Normal file
53
libmodbus/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
libmodbus/modbus.c
Normal file
1911
libmodbus/modbus.c
Normal file
File diff suppressed because it is too large
Load Diff
293
libmodbus/modbus.h
Normal file
293
libmodbus/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 */
|
||||
@ -1,5 +1,5 @@
|
||||
// storageworker.cpp
|
||||
#include "storageworker.h"
|
||||
#include "storage_worker.h"
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
@ -1,6 +1,6 @@
|
||||
// storageworker.h
|
||||
#ifndef STORAGEWORKER_H
|
||||
#define STORAGEWORKER_H
|
||||
#ifndef STORAGE_WORKER_H
|
||||
#define STORAGE_WORKER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <opencv2/opencv.hpp>
|
||||
@ -20,4 +20,4 @@ private:
|
||||
QString getSaveDirectory(); // 获取保存目录的函数
|
||||
};
|
||||
|
||||
#endif // STORAGEWORKER_H
|
||||
#endif // STORAGE_WORKER_H
|
||||
224
ui_widget.h
224
ui_widget.h
@ -42,6 +42,9 @@ public:
|
||||
QFrame *frame_7;
|
||||
QVBoxLayout *verticalLayout_3;
|
||||
QLabel *lab_machine_num;
|
||||
QHBoxLayout *horizontalLayout_35;
|
||||
QLabel *lab_plc;
|
||||
QLabel *lab_fpga;
|
||||
QLabel *lab_info;
|
||||
QPushButton *btn_start;
|
||||
QPushButton *btn_stop;
|
||||
@ -302,9 +305,8 @@ public:
|
||||
frame_7->setObjectName("frame_7");
|
||||
frame_7->setMinimumSize(QSize(0, 0));
|
||||
verticalLayout_3 = new QVBoxLayout(frame_7);
|
||||
verticalLayout_3->setSpacing(20);
|
||||
verticalLayout_3->setSpacing(16);
|
||||
verticalLayout_3->setObjectName("verticalLayout_3");
|
||||
verticalLayout_3->setContentsMargins(9, 9, 9, -1);
|
||||
lab_machine_num = new QLabel(frame_7);
|
||||
lab_machine_num->setObjectName("lab_machine_num");
|
||||
lab_machine_num->setStyleSheet(QString::fromUtf8("font: 24pt \"Microsoft YaHei UI\";\n"
|
||||
@ -312,6 +314,34 @@ public:
|
||||
|
||||
verticalLayout_3->addWidget(lab_machine_num, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
horizontalLayout_35 = new QHBoxLayout();
|
||||
horizontalLayout_35->setObjectName("horizontalLayout_35");
|
||||
lab_plc = new QLabel(frame_7);
|
||||
lab_plc->setObjectName("lab_plc");
|
||||
QSizePolicy sizePolicy1(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Preferred);
|
||||
sizePolicy1.setHorizontalStretch(0);
|
||||
sizePolicy1.setVerticalStretch(0);
|
||||
sizePolicy1.setHeightForWidth(lab_plc->sizePolicy().hasHeightForWidth());
|
||||
lab_plc->setSizePolicy(sizePolicy1);
|
||||
lab_plc->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";\n"
|
||||
"background-color: rgb(255, 0, 0);\n"
|
||||
"color: rgb(255, 255, 255);"));
|
||||
|
||||
horizontalLayout_35->addWidget(lab_plc, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
lab_fpga = new QLabel(frame_7);
|
||||
lab_fpga->setObjectName("lab_fpga");
|
||||
sizePolicy1.setHeightForWidth(lab_fpga->sizePolicy().hasHeightForWidth());
|
||||
lab_fpga->setSizePolicy(sizePolicy1);
|
||||
lab_fpga->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";\n"
|
||||
"background-color: rgb(255, 0, 0);\n"
|
||||
"color: rgb(255, 255, 255);"));
|
||||
|
||||
horizontalLayout_35->addWidget(lab_fpga, 0, Qt::AlignmentFlag::AlignHCenter);
|
||||
|
||||
|
||||
verticalLayout_3->addLayout(horizontalLayout_35);
|
||||
|
||||
lab_info = new QLabel(frame_7);
|
||||
lab_info->setObjectName("lab_info");
|
||||
lab_info->setEnabled(true);
|
||||
@ -328,11 +358,11 @@ public:
|
||||
|
||||
btn_start = new QPushButton(frame_7);
|
||||
btn_start->setObjectName("btn_start");
|
||||
QSizePolicy sizePolicy1(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Preferred);
|
||||
sizePolicy1.setHorizontalStretch(0);
|
||||
sizePolicy1.setVerticalStretch(0);
|
||||
sizePolicy1.setHeightForWidth(btn_start->sizePolicy().hasHeightForWidth());
|
||||
btn_start->setSizePolicy(sizePolicy1);
|
||||
QSizePolicy sizePolicy2(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Preferred);
|
||||
sizePolicy2.setHorizontalStretch(0);
|
||||
sizePolicy2.setVerticalStretch(0);
|
||||
sizePolicy2.setHeightForWidth(btn_start->sizePolicy().hasHeightForWidth());
|
||||
btn_start->setSizePolicy(sizePolicy2);
|
||||
btn_start->setMinimumSize(QSize(0, 120));
|
||||
btn_start->setStyleSheet(QString::fromUtf8("/* btn_start \346\240\267\345\274\217 */\n"
|
||||
"QPushButton#btn_start {\n"
|
||||
@ -368,8 +398,8 @@ public:
|
||||
|
||||
btn_stop = new QPushButton(frame_7);
|
||||
btn_stop->setObjectName("btn_stop");
|
||||
sizePolicy1.setHeightForWidth(btn_stop->sizePolicy().hasHeightForWidth());
|
||||
btn_stop->setSizePolicy(sizePolicy1);
|
||||
sizePolicy2.setHeightForWidth(btn_stop->sizePolicy().hasHeightForWidth());
|
||||
btn_stop->setSizePolicy(sizePolicy2);
|
||||
btn_stop->setMinimumSize(QSize(0, 120));
|
||||
btn_stop->setStyleSheet(QString::fromUtf8("/* btn_stop \346\240\267\345\274\217 */\n"
|
||||
"QPushButton#btn_stop\n"
|
||||
@ -407,8 +437,8 @@ public:
|
||||
|
||||
btn_take_photos = new QPushButton(frame_7);
|
||||
btn_take_photos->setObjectName("btn_take_photos");
|
||||
sizePolicy1.setHeightForWidth(btn_take_photos->sizePolicy().hasHeightForWidth());
|
||||
btn_take_photos->setSizePolicy(sizePolicy1);
|
||||
sizePolicy2.setHeightForWidth(btn_take_photos->sizePolicy().hasHeightForWidth());
|
||||
btn_take_photos->setSizePolicy(sizePolicy2);
|
||||
btn_take_photos->setMinimumSize(QSize(0, 120));
|
||||
btn_take_photos->setStyleSheet(QString::fromUtf8("/* btn_take_photos \346\240\267\345\274\217 */\n"
|
||||
"QPushButton#btn_take_photos {\n"
|
||||
@ -580,11 +610,11 @@ public:
|
||||
|
||||
camera_1_img = new QLabel(frame_6);
|
||||
camera_1_img->setObjectName("camera_1_img");
|
||||
QSizePolicy sizePolicy2(QSizePolicy::Policy::Ignored, QSizePolicy::Policy::Ignored);
|
||||
sizePolicy2.setHorizontalStretch(0);
|
||||
sizePolicy2.setVerticalStretch(0);
|
||||
sizePolicy2.setHeightForWidth(camera_1_img->sizePolicy().hasHeightForWidth());
|
||||
camera_1_img->setSizePolicy(sizePolicy2);
|
||||
QSizePolicy sizePolicy3(QSizePolicy::Policy::Ignored, QSizePolicy::Policy::Ignored);
|
||||
sizePolicy3.setHorizontalStretch(0);
|
||||
sizePolicy3.setVerticalStretch(0);
|
||||
sizePolicy3.setHeightForWidth(camera_1_img->sizePolicy().hasHeightForWidth());
|
||||
camera_1_img->setSizePolicy(sizePolicy3);
|
||||
camera_1_img->setStyleSheet(QString::fromUtf8("background-color: rgb(129, 129, 129);\n"
|
||||
"border: 4px solid black;\n"
|
||||
"\n"
|
||||
@ -649,8 +679,8 @@ public:
|
||||
|
||||
camera_0_img = new QLabel(frame_6);
|
||||
camera_0_img->setObjectName("camera_0_img");
|
||||
sizePolicy2.setHeightForWidth(camera_0_img->sizePolicy().hasHeightForWidth());
|
||||
camera_0_img->setSizePolicy(sizePolicy2);
|
||||
sizePolicy3.setHeightForWidth(camera_0_img->sizePolicy().hasHeightForWidth());
|
||||
camera_0_img->setSizePolicy(sizePolicy3);
|
||||
camera_0_img->setStyleSheet(QString::fromUtf8("background-color: rgb(129, 129, 129);\n"
|
||||
"border: 4px solid black;\n"
|
||||
" border-radius: 12px; /* \345\234\206\350\247\222\345\215\212\345\276\204 */"));
|
||||
@ -897,11 +927,11 @@ public:
|
||||
horizontalLayout_19->setObjectName("horizontalLayout_19");
|
||||
btn_tab3_backtab2_2 = new QPushButton(tab_3);
|
||||
btn_tab3_backtab2_2->setObjectName("btn_tab3_backtab2_2");
|
||||
QSizePolicy sizePolicy3(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Minimum);
|
||||
sizePolicy3.setHorizontalStretch(0);
|
||||
sizePolicy3.setVerticalStretch(0);
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_2->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_2->setSizePolicy(sizePolicy3);
|
||||
QSizePolicy sizePolicy4(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Minimum);
|
||||
sizePolicy4.setHorizontalStretch(0);
|
||||
sizePolicy4.setVerticalStretch(0);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_2->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_2->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_2->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_2->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -909,8 +939,8 @@ public:
|
||||
|
||||
btn_tab3_backtab2 = new QPushButton(tab_3);
|
||||
btn_tab3_backtab2->setObjectName("btn_tab3_backtab2");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -918,8 +948,8 @@ public:
|
||||
|
||||
btn_tab_color = new QPushButton(tab_3);
|
||||
btn_tab_color->setObjectName("btn_tab_color");
|
||||
sizePolicy3.setHeightForWidth(btn_tab_color->sizePolicy().hasHeightForWidth());
|
||||
btn_tab_color->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab_color->sizePolicy().hasHeightForWidth());
|
||||
btn_tab_color->setSizePolicy(sizePolicy4);
|
||||
btn_tab_color->setMinimumSize(QSize(200, 130));
|
||||
btn_tab_color->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -927,8 +957,8 @@ public:
|
||||
|
||||
btn_tab3_backtab2_4 = new QPushButton(tab_3);
|
||||
btn_tab3_backtab2_4->setObjectName("btn_tab3_backtab2_4");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_4->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_4->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_4->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_4->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_4->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_4->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -947,16 +977,16 @@ public:
|
||||
btn_add_color = new QPushButton(tab_color);
|
||||
btn_add_color->setObjectName("btn_add_color");
|
||||
btn_add_color->setGeometry(QRect(140, 310, 250, 100));
|
||||
sizePolicy3.setHeightForWidth(btn_add_color->sizePolicy().hasHeightForWidth());
|
||||
btn_add_color->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_add_color->sizePolicy().hasHeightForWidth());
|
||||
btn_add_color->setSizePolicy(sizePolicy4);
|
||||
btn_add_color->setMinimumSize(QSize(250, 50));
|
||||
btn_add_color->setMaximumSize(QSize(16777215, 100));
|
||||
btn_add_color->setStyleSheet(QString::fromUtf8("font: 700 40pt \"Microsoft YaHei UI\";"));
|
||||
btn_del_color = new QPushButton(tab_color);
|
||||
btn_del_color->setObjectName("btn_del_color");
|
||||
btn_del_color->setGeometry(QRect(140, 180, 250, 100));
|
||||
sizePolicy3.setHeightForWidth(btn_del_color->sizePolicy().hasHeightForWidth());
|
||||
btn_del_color->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_del_color->sizePolicy().hasHeightForWidth());
|
||||
btn_del_color->setSizePolicy(sizePolicy4);
|
||||
btn_del_color->setMinimumSize(QSize(250, 100));
|
||||
btn_del_color->setMaximumSize(QSize(250, 100));
|
||||
btn_del_color->setStyleSheet(QString::fromUtf8("font: 700 40pt \"Microsoft YaHei UI\";"));
|
||||
@ -998,11 +1028,11 @@ public:
|
||||
|
||||
spinBox_L_max = new QSpinBox(frame_9);
|
||||
spinBox_L_max->setObjectName("spinBox_L_max");
|
||||
QSizePolicy sizePolicy4(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Preferred);
|
||||
sizePolicy4.setHorizontalStretch(0);
|
||||
sizePolicy4.setVerticalStretch(0);
|
||||
sizePolicy4.setHeightForWidth(spinBox_L_max->sizePolicy().hasHeightForWidth());
|
||||
spinBox_L_max->setSizePolicy(sizePolicy4);
|
||||
QSizePolicy sizePolicy5(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Preferred);
|
||||
sizePolicy5.setHorizontalStretch(0);
|
||||
sizePolicy5.setVerticalStretch(0);
|
||||
sizePolicy5.setHeightForWidth(spinBox_L_max->sizePolicy().hasHeightForWidth());
|
||||
spinBox_L_max->setSizePolicy(sizePolicy5);
|
||||
spinBox_L_max->setMinimumSize(QSize(100, 80));
|
||||
spinBox_L_max->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";"));
|
||||
spinBox_L_max->setMinimum(0);
|
||||
@ -1018,8 +1048,8 @@ public:
|
||||
|
||||
spinBox_L_min = new QSpinBox(frame_9);
|
||||
spinBox_L_min->setObjectName("spinBox_L_min");
|
||||
sizePolicy4.setHeightForWidth(spinBox_L_min->sizePolicy().hasHeightForWidth());
|
||||
spinBox_L_min->setSizePolicy(sizePolicy4);
|
||||
sizePolicy5.setHeightForWidth(spinBox_L_min->sizePolicy().hasHeightForWidth());
|
||||
spinBox_L_min->setSizePolicy(sizePolicy5);
|
||||
spinBox_L_min->setMinimumSize(QSize(100, 80));
|
||||
spinBox_L_min->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";"));
|
||||
spinBox_L_min->setMinimum(0);
|
||||
@ -1040,8 +1070,8 @@ public:
|
||||
|
||||
spinBox_A_max = new QSpinBox(frame_9);
|
||||
spinBox_A_max->setObjectName("spinBox_A_max");
|
||||
sizePolicy4.setHeightForWidth(spinBox_A_max->sizePolicy().hasHeightForWidth());
|
||||
spinBox_A_max->setSizePolicy(sizePolicy4);
|
||||
sizePolicy5.setHeightForWidth(spinBox_A_max->sizePolicy().hasHeightForWidth());
|
||||
spinBox_A_max->setSizePolicy(sizePolicy5);
|
||||
spinBox_A_max->setMinimumSize(QSize(100, 80));
|
||||
spinBox_A_max->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";"));
|
||||
spinBox_A_max->setMinimum(-128);
|
||||
@ -1057,8 +1087,8 @@ public:
|
||||
|
||||
spinBox_A_min = new QSpinBox(frame_9);
|
||||
spinBox_A_min->setObjectName("spinBox_A_min");
|
||||
sizePolicy4.setHeightForWidth(spinBox_A_min->sizePolicy().hasHeightForWidth());
|
||||
spinBox_A_min->setSizePolicy(sizePolicy4);
|
||||
sizePolicy5.setHeightForWidth(spinBox_A_min->sizePolicy().hasHeightForWidth());
|
||||
spinBox_A_min->setSizePolicy(sizePolicy5);
|
||||
spinBox_A_min->setMinimumSize(QSize(100, 80));
|
||||
spinBox_A_min->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";"));
|
||||
spinBox_A_min->setMinimum(-128);
|
||||
@ -1079,8 +1109,8 @@ public:
|
||||
|
||||
spinBox_B_max = new QSpinBox(frame_9);
|
||||
spinBox_B_max->setObjectName("spinBox_B_max");
|
||||
sizePolicy4.setHeightForWidth(spinBox_B_max->sizePolicy().hasHeightForWidth());
|
||||
spinBox_B_max->setSizePolicy(sizePolicy4);
|
||||
sizePolicy5.setHeightForWidth(spinBox_B_max->sizePolicy().hasHeightForWidth());
|
||||
spinBox_B_max->setSizePolicy(sizePolicy5);
|
||||
spinBox_B_max->setMinimumSize(QSize(100, 80));
|
||||
spinBox_B_max->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";"));
|
||||
spinBox_B_max->setMinimum(-128);
|
||||
@ -1096,8 +1126,8 @@ public:
|
||||
|
||||
spinBox_B_min = new QSpinBox(frame_9);
|
||||
spinBox_B_min->setObjectName("spinBox_B_min");
|
||||
sizePolicy4.setHeightForWidth(spinBox_B_min->sizePolicy().hasHeightForWidth());
|
||||
spinBox_B_min->setSizePolicy(sizePolicy4);
|
||||
sizePolicy5.setHeightForWidth(spinBox_B_min->sizePolicy().hasHeightForWidth());
|
||||
spinBox_B_min->setSizePolicy(sizePolicy5);
|
||||
spinBox_B_min->setMinimumSize(QSize(100, 80));
|
||||
spinBox_B_min->setStyleSheet(QString::fromUtf8("font: 20pt \"Microsoft YaHei UI\";"));
|
||||
spinBox_B_min->setMinimum(-128);
|
||||
@ -1238,8 +1268,8 @@ public:
|
||||
horizontalLayout_20->setObjectName("horizontalLayout_20");
|
||||
btn_tab3_backtab2_3 = new QPushButton(frame_9);
|
||||
btn_tab3_backtab2_3->setObjectName("btn_tab3_backtab2_3");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_3->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_3->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_3->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_3->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_3->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_3->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1247,8 +1277,8 @@ public:
|
||||
|
||||
btn_tab3_backtab2_5 = new QPushButton(frame_9);
|
||||
btn_tab3_backtab2_5->setObjectName("btn_tab3_backtab2_5");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_5->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_5->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_5->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_5->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_5->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_5->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1256,8 +1286,8 @@ public:
|
||||
|
||||
btn_tab_color_2 = new QPushButton(frame_9);
|
||||
btn_tab_color_2->setObjectName("btn_tab_color_2");
|
||||
sizePolicy3.setHeightForWidth(btn_tab_color_2->sizePolicy().hasHeightForWidth());
|
||||
btn_tab_color_2->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab_color_2->sizePolicy().hasHeightForWidth());
|
||||
btn_tab_color_2->setSizePolicy(sizePolicy4);
|
||||
btn_tab_color_2->setMinimumSize(QSize(200, 130));
|
||||
btn_tab_color_2->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1265,8 +1295,8 @@ public:
|
||||
|
||||
btn_tab3_backtab2_6 = new QPushButton(frame_9);
|
||||
btn_tab3_backtab2_6->setObjectName("btn_tab3_backtab2_6");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_6->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_6->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_6->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_6->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_6->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_6->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1411,8 +1441,8 @@ public:
|
||||
horizontalLayout_31->setObjectName("horizontalLayout_31");
|
||||
btn_reset_polar = new QPushButton(tab_6);
|
||||
btn_reset_polar->setObjectName("btn_reset_polar");
|
||||
sizePolicy3.setHeightForWidth(btn_reset_polar->sizePolicy().hasHeightForWidth());
|
||||
btn_reset_polar->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_reset_polar->sizePolicy().hasHeightForWidth());
|
||||
btn_reset_polar->setSizePolicy(sizePolicy4);
|
||||
btn_reset_polar->setMinimumSize(QSize(400, 130));
|
||||
btn_reset_polar->setMaximumSize(QSize(600, 400));
|
||||
btn_reset_polar->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
@ -1421,8 +1451,8 @@ public:
|
||||
|
||||
btn_save_polar = new QPushButton(tab_6);
|
||||
btn_save_polar->setObjectName("btn_save_polar");
|
||||
sizePolicy3.setHeightForWidth(btn_save_polar->sizePolicy().hasHeightForWidth());
|
||||
btn_save_polar->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_save_polar->sizePolicy().hasHeightForWidth());
|
||||
btn_save_polar->setSizePolicy(sizePolicy4);
|
||||
btn_save_polar->setMinimumSize(QSize(400, 130));
|
||||
btn_save_polar->setMaximumSize(QSize(600, 400));
|
||||
btn_save_polar->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
@ -1437,8 +1467,8 @@ public:
|
||||
horizontalLayout_22->setObjectName("horizontalLayout_22");
|
||||
btn_tab3_backtab2_7 = new QPushButton(tab_6);
|
||||
btn_tab3_backtab2_7->setObjectName("btn_tab3_backtab2_7");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_7->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_7->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_7->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_7->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_7->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_7->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1446,8 +1476,8 @@ public:
|
||||
|
||||
btn_tab3_backtab2_8 = new QPushButton(tab_6);
|
||||
btn_tab3_backtab2_8->setObjectName("btn_tab3_backtab2_8");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_8->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_8->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_8->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_8->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_8->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_8->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1455,8 +1485,8 @@ public:
|
||||
|
||||
btn_tab_color_3 = new QPushButton(tab_6);
|
||||
btn_tab_color_3->setObjectName("btn_tab_color_3");
|
||||
sizePolicy3.setHeightForWidth(btn_tab_color_3->sizePolicy().hasHeightForWidth());
|
||||
btn_tab_color_3->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab_color_3->sizePolicy().hasHeightForWidth());
|
||||
btn_tab_color_3->setSizePolicy(sizePolicy4);
|
||||
btn_tab_color_3->setMinimumSize(QSize(200, 130));
|
||||
btn_tab_color_3->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1464,8 +1494,8 @@ public:
|
||||
|
||||
btn_tab3_backtab2_9 = new QPushButton(tab_6);
|
||||
btn_tab3_backtab2_9->setObjectName("btn_tab3_backtab2_9");
|
||||
sizePolicy3.setHeightForWidth(btn_tab3_backtab2_9->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_9->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(btn_tab3_backtab2_9->sizePolicy().hasHeightForWidth());
|
||||
btn_tab3_backtab2_9->setSizePolicy(sizePolicy4);
|
||||
btn_tab3_backtab2_9->setMinimumSize(QSize(200, 130));
|
||||
btn_tab3_backtab2_9->setStyleSheet(QString::fromUtf8("font: 700 48pt \"Microsoft YaHei UI\";"));
|
||||
|
||||
@ -1515,8 +1545,8 @@ public:
|
||||
|
||||
btn_settings = new QPushButton(frame_4);
|
||||
btn_settings->setObjectName("btn_settings");
|
||||
sizePolicy4.setHeightForWidth(btn_settings->sizePolicy().hasHeightForWidth());
|
||||
btn_settings->setSizePolicy(sizePolicy4);
|
||||
sizePolicy5.setHeightForWidth(btn_settings->sizePolicy().hasHeightForWidth());
|
||||
btn_settings->setSizePolicy(sizePolicy5);
|
||||
btn_settings->setMinimumSize(QSize(0, 0));
|
||||
btn_settings->setStyleSheet(QString::fromUtf8("/* btn_start \346\240\267\345\274\217 */\n"
|
||||
"QPushButton#btn_settings {\n"
|
||||
@ -1551,8 +1581,8 @@ public:
|
||||
|
||||
btn_live = new QPushButton(frame_4);
|
||||
btn_live->setObjectName("btn_live");
|
||||
sizePolicy4.setHeightForWidth(btn_live->sizePolicy().hasHeightForWidth());
|
||||
btn_live->setSizePolicy(sizePolicy4);
|
||||
sizePolicy5.setHeightForWidth(btn_live->sizePolicy().hasHeightForWidth());
|
||||
btn_live->setSizePolicy(sizePolicy5);
|
||||
btn_live->setMinimumSize(QSize(0, 0));
|
||||
btn_live->setStyleSheet(QString::fromUtf8("/* btn_start \346\240\267\345\274\217 */\n"
|
||||
"QPushButton#btn_live {\n"
|
||||
@ -1602,11 +1632,11 @@ public:
|
||||
horizontalLayout_16->setContentsMargins(38, 20, 38, 20);
|
||||
frame_running_time = new QFrame(frame_5);
|
||||
frame_running_time->setObjectName("frame_running_time");
|
||||
QSizePolicy sizePolicy5(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Expanding);
|
||||
sizePolicy5.setHorizontalStretch(0);
|
||||
sizePolicy5.setVerticalStretch(0);
|
||||
sizePolicy5.setHeightForWidth(frame_running_time->sizePolicy().hasHeightForWidth());
|
||||
frame_running_time->setSizePolicy(sizePolicy5);
|
||||
QSizePolicy sizePolicy6(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Expanding);
|
||||
sizePolicy6.setHorizontalStretch(0);
|
||||
sizePolicy6.setVerticalStretch(0);
|
||||
sizePolicy6.setHeightForWidth(frame_running_time->sizePolicy().hasHeightForWidth());
|
||||
frame_running_time->setSizePolicy(sizePolicy6);
|
||||
frame_running_time->setMinimumSize(QSize(346, 0));
|
||||
frame_running_time->setMaximumSize(QSize(16777215, 16777215));
|
||||
frame_running_time->setStyleSheet(QString::fromUtf8("QFrame#frame_running_time{\n"
|
||||
@ -1656,8 +1686,8 @@ public:
|
||||
|
||||
label_hourUnit = new QLabel(frame_running_time);
|
||||
label_hourUnit->setObjectName("label_hourUnit");
|
||||
sizePolicy3.setHeightForWidth(label_hourUnit->sizePolicy().hasHeightForWidth());
|
||||
label_hourUnit->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(label_hourUnit->sizePolicy().hasHeightForWidth());
|
||||
label_hourUnit->setSizePolicy(sizePolicy4);
|
||||
label_hourUnit->setStyleSheet(QString::fromUtf8("font: 700 20pt \"Microsoft YaHei UI\";\n"
|
||||
"color:rgb(105,186,210);\n"
|
||||
"background-color: #2d2d2d;;\n"
|
||||
@ -1676,8 +1706,8 @@ public:
|
||||
|
||||
label_minuteUnit = new QLabel(frame_running_time);
|
||||
label_minuteUnit->setObjectName("label_minuteUnit");
|
||||
sizePolicy3.setHeightForWidth(label_minuteUnit->sizePolicy().hasHeightForWidth());
|
||||
label_minuteUnit->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(label_minuteUnit->sizePolicy().hasHeightForWidth());
|
||||
label_minuteUnit->setSizePolicy(sizePolicy4);
|
||||
label_minuteUnit->setStyleSheet(QString::fromUtf8("font: 700 20pt \"Microsoft YaHei UI\";\n"
|
||||
"color:rgb(105,186,210);\n"
|
||||
"background-color: #2d2d2d;;\n"
|
||||
@ -1712,11 +1742,11 @@ public:
|
||||
|
||||
progressBar = new QProgressBar(frame_running_time);
|
||||
progressBar->setObjectName("progressBar");
|
||||
QSizePolicy sizePolicy6(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Fixed);
|
||||
sizePolicy6.setHorizontalStretch(0);
|
||||
sizePolicy6.setVerticalStretch(0);
|
||||
sizePolicy6.setHeightForWidth(progressBar->sizePolicy().hasHeightForWidth());
|
||||
progressBar->setSizePolicy(sizePolicy6);
|
||||
QSizePolicy sizePolicy7(QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Fixed);
|
||||
sizePolicy7.setHorizontalStretch(0);
|
||||
sizePolicy7.setVerticalStretch(0);
|
||||
sizePolicy7.setHeightForWidth(progressBar->sizePolicy().hasHeightForWidth());
|
||||
progressBar->setSizePolicy(sizePolicy7);
|
||||
progressBar->setStyleSheet(QString::fromUtf8("/* \350\277\233\345\272\246\346\235\241\346\240\267\345\274\217 */\n"
|
||||
"QProgressBar {\n"
|
||||
" background: #444;\n"
|
||||
@ -1751,8 +1781,8 @@ public:
|
||||
|
||||
frame_valve = new QFrame(frame_5);
|
||||
frame_valve->setObjectName("frame_valve");
|
||||
sizePolicy5.setHeightForWidth(frame_valve->sizePolicy().hasHeightForWidth());
|
||||
frame_valve->setSizePolicy(sizePolicy5);
|
||||
sizePolicy6.setHeightForWidth(frame_valve->sizePolicy().hasHeightForWidth());
|
||||
frame_valve->setSizePolicy(sizePolicy6);
|
||||
frame_valve->setMaximumSize(QSize(16777215, 16777215));
|
||||
frame_valve->setStyleSheet(QString::fromUtf8("QFrame#frame_valve{\n"
|
||||
"background: #2d2d2d;\n"
|
||||
@ -1801,8 +1831,8 @@ public:
|
||||
|
||||
label_17 = new QLabel(frame_valve);
|
||||
label_17->setObjectName("label_17");
|
||||
sizePolicy3.setHeightForWidth(label_17->sizePolicy().hasHeightForWidth());
|
||||
label_17->setSizePolicy(sizePolicy3);
|
||||
sizePolicy4.setHeightForWidth(label_17->sizePolicy().hasHeightForWidth());
|
||||
label_17->setSizePolicy(sizePolicy4);
|
||||
label_17->setStyleSheet(QString::fromUtf8("font: 700 20pt \"Microsoft YaHei UI\";\n"
|
||||
"color:rgb(105,186,210);\n"
|
||||
"background-color: #2d2d2d;;\n"
|
||||
@ -1858,11 +1888,11 @@ public:
|
||||
|
||||
frame_history = new QFrame(frame_5);
|
||||
frame_history->setObjectName("frame_history");
|
||||
QSizePolicy sizePolicy7(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
|
||||
sizePolicy7.setHorizontalStretch(0);
|
||||
sizePolicy7.setVerticalStretch(0);
|
||||
sizePolicy7.setHeightForWidth(frame_history->sizePolicy().hasHeightForWidth());
|
||||
frame_history->setSizePolicy(sizePolicy7);
|
||||
QSizePolicy sizePolicy8(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
|
||||
sizePolicy8.setHorizontalStretch(0);
|
||||
sizePolicy8.setVerticalStretch(0);
|
||||
sizePolicy8.setHeightForWidth(frame_history->sizePolicy().hasHeightForWidth());
|
||||
frame_history->setSizePolicy(sizePolicy8);
|
||||
frame_history->setMaximumSize(QSize(16777215, 16777215));
|
||||
frame_history->setStyleSheet(QString::fromUtf8("QFrame#frame_history{\n"
|
||||
"background: #2d2d2d;\n"
|
||||
@ -2001,6 +2031,8 @@ public:
|
||||
label_3->setText(QCoreApplication::translate("Widget", "\347\261\275\346\243\211\345\274\202\347\272\244\346\235\202\350\264\250\345\210\206\351\200\211\346\234\272", nullptr));
|
||||
tabWidget->setTabText(tabWidget->indexOf(tab), QCoreApplication::translate("Widget", "Tab 1", nullptr));
|
||||
lab_machine_num->setText(QCoreApplication::translate("Widget", "0\345\217\267\346\234\272", nullptr));
|
||||
lab_plc->setText(QCoreApplication::translate("Widget", "PLC", nullptr));
|
||||
lab_fpga->setText(QCoreApplication::translate("Widget", "FPGA", nullptr));
|
||||
lab_info->setText(QCoreApplication::translate("Widget", "\347\212\266\346\200\201", nullptr));
|
||||
btn_start->setText(QCoreApplication::translate("Widget", "\345\274\200\345\247\213\345\210\206\351\200\211", nullptr));
|
||||
btn_stop->setText(QCoreApplication::translate("Widget", "\345\201\234\346\255\242\345\210\206\351\200\211", nullptr));
|
||||
@ -2014,7 +2046,7 @@ public:
|
||||
dl_1_overlay->setText(QCoreApplication::translate("Widget", "\346\231\272\346\243\200\347\273\223\346\236\234", nullptr));
|
||||
img_1_mirror->setText(QCoreApplication::translate("Widget", "\345\233\276\347\211\207\351\225\234\345\203\217", nullptr));
|
||||
camera_1_img->setText(QString());
|
||||
label_4->setText(QCoreApplication::translate("Widget", "\345\207\272\351\243\216\345\217\243\344\276\247-\347\233\270\346\234\2720", nullptr));
|
||||
label_4->setText(QCoreApplication::translate("Widget", "\351\243\216\345\217\243\344\276\247-\347\233\270\346\234\2720", nullptr));
|
||||
dl_enable_0->setText(QCoreApplication::translate("Widget", "\345\261\217\350\224\275\346\267\261\345\272\246\345\255\246\344\271\240", nullptr));
|
||||
tra_enable_0->setText(QCoreApplication::translate("Widget", "\345\261\217\350\224\275\350\211\263\344\270\275\346\243\200\346\265\213", nullptr));
|
||||
mtx_0_overlay->setText(QCoreApplication::translate("Widget", "\350\211\262\346\243\200\347\273\223\346\236\234", nullptr));
|
||||
|
||||
127
widget.cpp
127
widget.cpp
@ -14,7 +14,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QTabBar>
|
||||
#include <img_utils.h>
|
||||
#include <detectionworker.h>
|
||||
#include <detection_worker.h>
|
||||
#include <Qstring>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
@ -64,20 +64,17 @@ Widget::Widget(QWidget *parent)
|
||||
iniOnnx();
|
||||
// iniColor();
|
||||
loadConfig(getConfigDirectory()+"/color_range_config.txt"); // 读取配置文件
|
||||
iniLowMac();
|
||||
check_lower_machine();
|
||||
iniCamera();
|
||||
|
||||
|
||||
// 更新界面
|
||||
update_main_settings(); // 更新主要设定
|
||||
update_colorlist(); // 更新色彩列表
|
||||
update_polar(); // 更新偏振相机界面
|
||||
|
||||
|
||||
// 初始化存储工作者和线程
|
||||
storageWorker = new StorageWorker();
|
||||
storageWorker->moveToThread(&storageThread);
|
||||
|
||||
connect(&storageThread, &QThread::started, storageWorker, &StorageWorker::process);
|
||||
connect(this, &Widget::destroyed, &storageThread, &QThread::quit);
|
||||
connect(&storageThread, &QThread::finished, storageWorker, &QObject::deleteLater);
|
||||
@ -89,12 +86,116 @@ Widget::Widget(QWidget *parent)
|
||||
connect(timer, &QTimer::timeout, this, &Widget::refreshImage);
|
||||
timer->start(40); // 每40毫秒秒刷新一次界面
|
||||
|
||||
// 启动PLC定时器,每秒检查一次
|
||||
plc_connector = std::make_unique<PLCConnector>(params["machine_num"]);
|
||||
QTimer* timer_plc = new QTimer(this);
|
||||
connect(timer_plc, &QTimer::timeout, this, &Widget::heart_beat);
|
||||
heart_beat();
|
||||
timer_plc->start(30000); // 每30秒发送一次心跳包
|
||||
|
||||
// 启动PLC定时器,每秒检查一次
|
||||
QTimer* timer_lower = new QTimer(this);
|
||||
connect(timer_lower, &QTimer::timeout, this, &Widget::check_lower_machine);
|
||||
timer_lower->start(10000); // 每10秒检查一次FPGA的状态
|
||||
|
||||
ui->tabWidget->setCurrentIndex(1);
|
||||
// on_btn_start_clicked();
|
||||
// 显示启动倒计时
|
||||
showStartupCountdown();
|
||||
}
|
||||
|
||||
void Widget::check_lower_machine(){
|
||||
if(g_lower_machine_connected.load()){
|
||||
return;
|
||||
}
|
||||
bool temp_status = iniLowMac();
|
||||
g_lower_machine_connected.store(temp_status);
|
||||
if(temp_status)
|
||||
{ this->ui->lab_fpga->setStyleSheet(
|
||||
"QLabel{"
|
||||
"background-color: green;"
|
||||
"color: white;"
|
||||
"border: 1px solid black;"
|
||||
"padding: 5px;"
|
||||
"border-radius: 5px;"
|
||||
"font: 20pt \"Microsoft YaHei UI\";"
|
||||
"}"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ui->lab_plc->setStyleSheet(
|
||||
"QLabel{"
|
||||
"background-color: red;"
|
||||
"color: white;"
|
||||
"border: 1px solid black;"
|
||||
"padding: 5px;"
|
||||
"border-radius: 5px;"
|
||||
"font: 20pt \"Microsoft YaHei UI\";"
|
||||
"}"
|
||||
);
|
||||
qWarning() << "FPGA Disconnected!";
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::heart_beat()
|
||||
{
|
||||
QMutexLocker locker(&plc_mutex); // 锁住互斥锁,自动解锁
|
||||
if(this->plc_connector == nullptr)
|
||||
{
|
||||
qDebug() << "plc_connector is null!";
|
||||
return;
|
||||
}
|
||||
if(!this->plc_connector->is_connected())
|
||||
{
|
||||
if(!this->plc_connector->try_connect()){
|
||||
// 未连接的情况下尝试连接失败,设置 lab_plc 为红色
|
||||
this->ui->lab_plc->setStyleSheet(
|
||||
"QLabel{"
|
||||
"background-color: red;"
|
||||
"color: white;"
|
||||
"border: 1px solid black;"
|
||||
"padding: 5px;"
|
||||
"border-radius: 5px;"
|
||||
"font: 20pt \"Microsoft YaHei UI\";"
|
||||
"}"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(this->plc_connector->send_heart_beat())
|
||||
{
|
||||
// 心跳发送成功,保持绿色
|
||||
this->ui->lab_plc->setStyleSheet(
|
||||
"QLabel{"
|
||||
"background-color: green;"
|
||||
"color: white;"
|
||||
"border: 1px solid black;"
|
||||
"padding: 5px;"
|
||||
"border-radius: 5px;"
|
||||
"font: 20pt \"Microsoft YaHei UI\";"
|
||||
"}"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 心跳发送失败,设置为红色
|
||||
this->ui->lab_plc->setStyleSheet(
|
||||
"QLabel{"
|
||||
"background-color: red;"
|
||||
"color: white;"
|
||||
"border: 1px solid black;"
|
||||
"padding: 5px;"
|
||||
"border-radius: 5px;"
|
||||
"font: 20pt \"Microsoft YaHei UI\";"
|
||||
"}"
|
||||
);
|
||||
qWarning() << "Connection established but write to PLC Failed!";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Widget::showStartupCountdown()
|
||||
{
|
||||
CountdownDialog* countdown = new CountdownDialog(10, this);
|
||||
@ -155,12 +256,15 @@ Widget::~Widget()
|
||||
storageThread.quit();
|
||||
storageThread.wait();
|
||||
|
||||
|
||||
// 现有清理代码...
|
||||
DestoryCamera();
|
||||
DestoryLowMac();
|
||||
|
||||
delete ui;
|
||||
|
||||
// 重启电脑
|
||||
QProcess::startDetached("shutdown", QStringList() << "/r" << "/f" << "/t" << "0");
|
||||
}
|
||||
|
||||
void Widget::refreshImage()
|
||||
@ -172,6 +276,7 @@ void Widget::refreshImage()
|
||||
this->ui->btn_start->setEnabled(!this->isCamRunning);
|
||||
this->ui->btn_stop->setEnabled(this->isCamRunning);
|
||||
this->ui->btn_take_photos->setEnabled(this->isCamRunning);
|
||||
|
||||
// refresh checkouts
|
||||
this->ui->dl_enable_0->setEnabled(!this->isCamRunning);
|
||||
this->ui->dl_enable_1->setEnabled(!this->isCamRunning);
|
||||
@ -465,6 +570,7 @@ void Widget::on_btn_quit_clicked()
|
||||
|
||||
void Widget::on_btn_set_lower_clicked()
|
||||
{
|
||||
|
||||
// 硬编码参数值
|
||||
lowmac_sm = ui->spinbox_maintime->value();
|
||||
params["lowmac_sm"]=lowmac_sm;
|
||||
@ -475,6 +581,13 @@ void Widget::on_btn_set_lower_clicked()
|
||||
// 两个过去的参量不支持读取配置文件
|
||||
file_encoder = ui->spinbox_encoder->text().toInt(); // 编码器值++
|
||||
file_valve = ui->spinbox_valve->text().toInt(); // 阀门通道
|
||||
// 重新初始化 PLCConnector
|
||||
{
|
||||
QMutexLocker locker(&plc_mutex);
|
||||
plc_connector = std::make_unique<PLCConnector>(params["machine_num"]);
|
||||
}
|
||||
// 可选:立即更新 PLC 连接状态
|
||||
heart_beat();
|
||||
}
|
||||
|
||||
void Widget::update_main_settings()
|
||||
@ -749,6 +862,10 @@ void Widget::update_colorlist()
|
||||
{
|
||||
ui->comboBox_colorlist->addItem(QString::fromStdString(color));
|
||||
}
|
||||
ui->spinbox_delaytime->setValue(params["file_delay"]);
|
||||
ui->spb_saturation->setValue(params["saturation_threshold"]);
|
||||
ui->spinbox_msize_color->setValue(params["sizeThreshold"]);
|
||||
ui->spb_expandsize->setValue(params["expansionRaidus"]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
13
widget.h
13
widget.h
@ -1,14 +1,16 @@
|
||||
#ifndef WIDGET_H
|
||||
#define WIDGET_H
|
||||
#include <windows.h>
|
||||
#include <QProcess>
|
||||
#include <QThread>
|
||||
#include <QWidget>
|
||||
#include <camera.h>
|
||||
#include <QTcpServer>
|
||||
#include <QPushButton>
|
||||
#include "globals.h"
|
||||
#include "storageworker.h"
|
||||
#include "countdowndialog.h"
|
||||
#include "storage_worker.h"
|
||||
#include "countdown_dialog.h"
|
||||
#include "plc_connector.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
@ -27,6 +29,10 @@ public:
|
||||
public slots:
|
||||
void refreshImage(); // 刷新图片的槽函数
|
||||
|
||||
void heart_beat();
|
||||
|
||||
void check_lower_machine(); // 检查下位机状态
|
||||
|
||||
private slots:
|
||||
|
||||
void onCountdownFinished();
|
||||
@ -110,6 +116,9 @@ private:
|
||||
|
||||
bool isCamRunning;
|
||||
|
||||
std::unique_ptr<PLCConnector> plc_connector;
|
||||
QMutex plc_mutex; // 添加互斥锁
|
||||
|
||||
QDateTime startTime; // 记录点“开始分选”的时间,用于计算总运行时长
|
||||
|
||||
QThread storageThread; // 存储线程
|
||||
|
||||
53
widget.ui
53
widget.ui
@ -104,16 +104,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
<number>16</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QLabel" name="lab_machine_num">
|
||||
@ -126,6 +117,46 @@ color: rgb(34, 40, 49);</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_35">
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QLabel" name="lab_plc">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 20pt "Microsoft YaHei UI";
|
||||
background-color: rgb(255, 0, 0);
|
||||
color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>PLC</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QLabel" name="lab_fpga">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">font: 20pt "Microsoft YaHei UI";
|
||||
background-color: rgb(255, 0, 0);
|
||||
color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FPGA</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QLabel" name="lab_info">
|
||||
<property name="enabled">
|
||||
@ -535,7 +566,7 @@ border: 4px solid black;
|
||||
<string notr="true">font: 18pt "Microsoft YaHei UI";</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>出风口侧-相机0</string>
|
||||
<string>风口侧-相机0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user