bonus-edge-proxy/src/test.cc

297 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <vector>
#include <string>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <cmath>
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <sys/select.h>
// === 可配置参数 ===
const char* SERIAL_PORT = "/dev/ttyS7";
const int DEFAULT_BAUDRATE = B9600;
const unsigned char DEFAULT_SLAVE_ADDR = 0x01; // 虽然读取地址寄存器返回0x2但测试用的初始地址是0x1
// === 可配置参数结束 ===
// 功能码定义
#define READ_HOLDING_REGISTERS 0x03
#define READ_INPUT_REGISTERS 0x04
#define WRITE_SINGLE_REGISTER 0x06
// 寄存器地址
enum RegisterAddress {
REG_TEMP = 0x0000,
REG_HUMI = 0x0001,
REG_TEMP_ALARM = 0x0030,
REG_HUMI_ALARM = 0x0031,
REG_DEVICE_ADDR = 0x0002,
REG_BAUDRATE_CODE = 0x0003
};
// 波特率码映射 (用于设置,读取时用不同的方式)
const int BAUDRATES[] = {1200, 2400, 4800, 9600, 19200, 38400, 57600};
const unsigned char BAUDRATE_CODES[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
uint16_t calculateCRC16(const uint8_t *data, size_t length) {
uint16_t crc = 0xFFFF;
for (size_t i = 0; i < length; ++i) {
crc ^= data[i];
for (int j = 0; j < 8; ++j) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
int openSerialPort(const char* port_name, speed_t baudrate) {
std::cout << "Attempting to open serial port: " << port_name << " at " << baudrate << std::endl;
int fd = open(port_name, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
std::cerr << "Error opening serial port " << port_name << ": " << strerror(errno) << std::endl;
return -1;
}
termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, baudrate);
cfsetospeed(&options, baudrate);
options.c_cflag &= ~PARENB; // 无校验
options.c_cflag &= ~CSTOPB; // 1位停止位
options.c_cflag &= ~CSIZE; // 清除数据位设置
options.c_cflag |= CS8; // 8位数据位
options.c_cflag |= (CLOCAL | CREAD);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 15;
tcsetattr(fd, TCSANOW, &options);
tcflush(fd, TCIOFLUSH);
std::cout << "Successfully opened and configured serial port: " << port_name << std::endl;
return fd;
}
std::vector<uint8_t> readRegister(int fd, uint8_t slave_addr, uint8_t function_code, uint16_t reg_addr, uint16_t reg_count) {
std::cout << "\n--- Reading Register 0x" << std::hex << reg_addr
<< " (Count: " << std::dec << reg_count << ") from Slave 0x"
<< std::hex << (int)slave_addr << " using FC=" << (int)function_code << std::dec << " ---" << std::endl;
std::vector<uint8_t> request;
request.push_back(slave_addr);
request.push_back(function_code);
request.push_back(reg_addr >> 8);
request.push_back(reg_addr & 0xFF);
request.push_back(reg_count >> 8);
request.push_back(reg_count & 0xFF);
uint16_t crc = calculateCRC16(request.data(), request.size());
request.push_back(crc & 0xFF);
request.push_back(crc >> 8);
std::cout << "Sending request: ";
for (auto byte : request) {
printf("%02X ", byte);
}
std::cout << std::endl;
tcflush(fd, TCIFLUSH);
if (write(fd, request.data(), request.size()) != request.size()) {
std::cerr << "Error: Failed to write request to serial port." << std::endl;
return {};
}
const size_t expected_response_size = 5 + reg_count * 2;
std::vector<uint8_t> response;
response.reserve(expected_response_size);
fd_set read_fds;
struct timeval timeout;
ssize_t bytes_read;
size_t total_bytes_received = 0;
int total_timeout_sec = 2;
time_t start_time = time(nullptr);
while (total_bytes_received < expected_response_size) {
if (difftime(time(nullptr), start_time) > total_timeout_sec) {
std::cerr << "Error: Total read timeout." << std::endl;
return {};
}
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
int ready = select(fd + 1, &read_fds, NULL, NULL, &timeout);
if (ready < 0) { perror("select() error"); return {}; }
if (ready == 0) continue;
size_t bytes_to_read = expected_response_size - total_bytes_received;
uint8_t temp_buffer[256];
bytes_read = read(fd, temp_buffer, bytes_to_read);
if (bytes_read < 0) continue;
if (bytes_read > 0) {
total_bytes_received += bytes_read;
for (int i = 0; i < bytes_read; ++i) {
response.push_back(temp_buffer[i]);
}
}
}
std::cout << "Received response (" << response.size() << " bytes): ";
for (auto byte : response) {
printf("%02X ", byte);
}
std::cout << std::endl;
if (response.size() != expected_response_size) {
std::cerr << "Error: Incomplete response. Expected " << expected_response_size << " bytes, got " << response.size() << "." << std::endl;
return {};
}
if (response[0] != slave_addr || response[1] != function_code) {
std::cerr << "Error: Invalid response header." << std::endl;
return {};
}
uint16_t received_crc = (response[expected_response_size - 1] << 8) | response[expected_response_size - 2];
uint16_t calculated_crc = calculateCRC16(response.data(), expected_response_size - 2);
if (received_crc != calculated_crc) {
std::cerr << "Error: CRC check failed." << std::endl;
return {};
}
return std::vector<uint8_t>(response.begin() + 2, response.end() - 2);
}
/**
* @brief 修正:正确解析温湿度数据 (根据手册数据本身是16位无符号整数然后除以10)
* @param data 两个字节的原始数据
* @return float 解析后的温湿度值
*/
float parseSensorData(const std::vector<uint8_t>& data) {
if (data.size() < 2) return NAN;
// 根据手册数据是16位无符号整数
uint16_t raw_value = (data[0] << 8) | data[1];
// 然后除以10得到最终值
return static_cast<float>(raw_value) / 10.0f;
}
/**
* @brief 根据设备返回的值解析实际波特率
* @param baud_data 寄存器0x0003返回的两个字节数据
* @return int 实际波特率 (1200, 2400, ...)
*/
int parseBaudrate(const std::vector<uint8_t>& baud_data) {
if (baud_data.size() < 2) return -1;
uint16_t baud_value = (baud_data[0] << 8) | baud_data[1];
// 手册上的映射: 0->1200, 1->2400, ..., 6->57600
// 因为数组索引从0开始直接返回即可
if (baud_value < sizeof(BAUDRATES) / sizeof(BAUDRATES[0])) {
return BAUDRATES[baud_value];
} else {
std::cerr << "Warning: Unknown baudrate value from device: " << baud_value << std::endl;
return -1;
}
}
void printAlarmStatus(uint8_t alarm_status_byte) {
switch (alarm_status_byte) {
case 0x00: std::cout << "None"; break;
case 0x01: std::cout << "High Alarm"; break;
case 0x02: std::cout << "Low Alarm"; break;
default: std::cout << "Unknown (0x" << std::hex << (int)alarm_status_byte << std::dec << ")"; break;
}
std::cout << std::endl;
}
int main() {
std::cout << "--- JWST-20 Sensor Test (Final Corrected Version) ---" << std::endl;
int serial_fd = openSerialPort(SERIAL_PORT, DEFAULT_BAUDRATE);
if (serial_fd < 0) {
return 1;
}
std::cout << "\n==================== Reading Sensor Data ====================" << std::endl;
// 1. 读取温度
auto temp_data = readRegister(serial_fd, DEFAULT_SLAVE_ADDR, READ_HOLDING_REGISTERS, REG_TEMP, 1);
float temperature = NAN;
if (!temp_data.empty()) {
temperature = parseSensorData(temp_data);
std::cout << "Temperature: " << temperature << " °C" << std::endl;
} else {
std::cerr << "Failed to read temperature." << std::endl;
}
// 2. 读取湿度
auto humi_data = readRegister(serial_fd, DEFAULT_SLAVE_ADDR, READ_HOLDING_REGISTERS, REG_HUMI, 1);
float humidity = NAN;
if (!humi_data.empty()) {
humidity = parseSensorData(humi_data);
std::cout << "Humidity: " << humidity << " %RH" << std::endl;
} else {
std::cerr << "Failed to read humidity." << std::endl;
}
// 3. 读取温度报警状态
auto temp_alarm_data = readRegister(serial_fd, DEFAULT_SLAVE_ADDR, READ_INPUT_REGISTERS, REG_TEMP_ALARM, 1);
if (!temp_alarm_data.empty()) {
std::cout << "Temperature Alarm Status: 0x" << std::hex << (int)temp_alarm_data[0] << " -> ";
printAlarmStatus(temp_alarm_data[0]);
} else {
std::cerr << "Failed to read temperature alarm status." << std::endl;
}
// 4. 读取湿度报警状态
auto humi_alarm_data = readRegister(serial_fd, DEFAULT_SLAVE_ADDR, READ_INPUT_REGISTERS, REG_HUMI_ALARM, 1);
if (!humi_alarm_data.empty()) {
std::cout << "Humidity Alarm Status: 0x" << std::hex << (int)humi_alarm_data[0] << " -> ";
printAlarmStatus(humi_alarm_data[0]);
} else {
std::cerr << "Failed to read humidity alarm status." << std::endl;
}
// 5. 读取设备地址 (虽然地址是0x1但寄存器内容可能不是这里只是读取寄存器内容)
auto addr_data = readRegister(serial_fd, DEFAULT_SLAVE_ADDR, READ_HOLDING_REGISTERS, REG_DEVICE_ADDR, 1);
if (!addr_data.empty()) {
std::cout << "Address Register Value: 0x" << std::hex << (int)addr_data[0] << std::dec << std::endl;
}
// 6. 读取波特率寄存器值并解析
auto baud_data = readRegister(serial_fd, DEFAULT_SLAVE_ADDR, READ_HOLDING_REGISTERS, REG_BAUDRATE_CODE, 1);
int current_baudrate = -1;
if (!baud_data.empty()) {
uint16_t baud_val = (baud_data[0] << 8) | baud_data[1]; // 手册: 00 03 means 9600
std::cout << "Baudrate Register Value: " << std::hex << "0x" << (int)baud_data[0] << " 0x" << (int)baud_data[1]
<< " (Value: " << std::dec << baud_val << ")" << std::endl;
current_baudrate = parseBaudrate(baud_data); // 使用新的解析函数
if (current_baudrate != -1) {
std::cout << "Current Baudrate: " << current_baudrate << " bps" << std::endl;
}
} else {
std::cerr << "Failed to read baudrate register." << std::endl;
}
close(serial_fd);
std::cout << "\n==================== Test Finished. ====================" << std::endl;
return 0;
}