Archive some files

This commit is contained in:
GuanYuankai 2025-10-11 17:30:02 +08:00
parent ea76e7ee28
commit e2a5918a2c
3 changed files with 232 additions and 137 deletions

View File

@ -1,60 +1,59 @@
#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
// === 可配置参数结束 ===
// 波特率
const speed_t BAUD_RATE = B9600;
// 功能码定义
#define READ_HOLDING_REGISTERS 0x03
#define READ_INPUT_REGISTERS 0x04
#define WRITE_SINGLE_REGISTER 0x06
// 要发送的原始十六进制数据 (不带空格)
const char* HEX_STRING_TO_SEND = "010300000001840A";
// --- 配置结束 ---
// 寄存器地址
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};
/**
* @brief
* @param hex_str "010203"
* @param data
* @return int -1
*/
int hexStringToBytes(const std::string& hex_str, std::vector<uint8_t>& data) {
if (hex_str.length() % 2 != 0) {
std::cerr << "Error: Hex string length must be even." << std::endl;
return -1;
}
data.clear();
for (size_t i = 0; i < hex_str.length(); i += 2) {
std::string byte_str = hex_str.substr(i, 2);
try {
int8_t byte = static_cast<uint8_t>(std::stoul(byte_str, nullptr, 16));
data.push_back(byte);
} catch (const std::invalid_argument& e) {
std::cerr << "Error: Invalid hex character '" << byte_str << "'" << std::endl;
return -1;
} catch (const std::out_of_range& e) {
std::cerr << "Error: Hex value '" << byte_str << "' is out of range." << std::endl;
return -1;
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 data.size();
return crc;
}
/**
* @brief
* @param port_name
* @param baudrate
* @return int -1
*/
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;
@ -63,139 +62,235 @@ int openSerialPort(const char* port_name, speed_t baudrate) {
termios options;
tcgetattr(fd, &options);
// 设置波特率
cfsetispeed(&options, baudrate);
cfsetospeed(&options, baudrate);
// 8N1
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_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
// 设置超时 (VTIME=5 表示 5 * 0.1s = 0.5s)
options.c_cc[VMIN] = 0; // 不阻塞,只要有数据就读
options.c_cc[VTIME] = 5; // 超时时间
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 15;
tcsetattr(fd, TCSANOW, &options);
tcflush(fd, TCIOFLUSH);
std::cout << "Serial port " << port_name << " opened successfully." << std::endl;
std::cout << "Successfully opened and configured serial port: " << port_name << std::endl;
return fd;
}
int main() {
std::cout << "--- Simple Serial Port Test for /dev/ttyS7 ---" << std::endl;
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);
// 1. 转换十六进制字符串为数据
std::vector<uint8_t> data_to_send;
int bytes_converted = hexStringToBytes(HEX_STRING_TO_SEND, data_to_send);
if (bytes_converted < 0) {
return 1;
}
uint16_t crc = calculateCRC16(request.data(), request.size());
request.push_back(crc & 0xFF);
request.push_back(crc >> 8);
std::cout << "Data to send (" << data_to_send.size() << " bytes): ";
for (auto byte : data_to_send) {
std::cout << "Sending request: ";
for (auto byte : request) {
printf("%02X ", byte);
}
std::cout << std::endl;
// 2. 打开串口
int serial_fd = openSerialPort(SERIAL_PORT, BAUD_RATE);
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 湿 (1610)
* @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;
}
// 3. 发送数据
std::cout << "\n>>> Sending data..." << std::endl;
if (write(serial_fd, data_to_send.data(), data_to_send.size()) != data_to_send.size()) {
std::cerr << "Error writing to serial port: " << strerror(errno) << std::endl;
close(serial_fd);
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;
}
std::cout << "Data sent." << std::endl;
// 4. 尝试读取响应
std::cout << "\n<<< Waiting for response... (will timeout after 3 seconds)" << std::endl;
std::vector<uint8_t> received_data;
fd_set read_fds;
struct timeval timeout;
ssize_t bytes_read;
// 总超时设置为 3 秒
int total_timeout_sec = 3;
time_t start_time = time(nullptr);
while (difftime(time(nullptr), start_time) < total_timeout_sec) {
FD_ZERO(&read_fds);
FD_SET(serial_fd, &read_fds);
// 每次循环都设置一个0.5秒的select超时
timeout.tv_sec = 0;
timeout.tv_usec = 500000; // 0.5s
int ready = select(serial_fd + 1, &read_fds, NULL, NULL, &timeout);
if (ready < 0) {
perror("select error");
break;
} else if (ready == 0) {
// select 超时,继续循环直到总超时
continue;
}
// 有数据可读
uint8_t buffer[256];
bytes_read = read(serial_fd, buffer, sizeof(buffer));
if (bytes_read < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue; // 没有新数据,继续循环
}
perror("read error");
break;
} else if (bytes_read == 0) {
// 连接关闭
break;
}
// 将读取到的数据追加到结果向量
for (int i = 0; i < bytes_read; ++i) {
received_data.push_back(buffer[i]);
}
// 打印新收到的数据
std::cout << "Received " << bytes_read << " new bytes: ";
for (int i = 0; i < bytes_read; ++i) {
printf("%02X ", buffer[i]);
}
std::cout << 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;
}
// 总超时结束
if (!received_data.empty()) {
std::cout << "\n--- Total Received Data (" << received_data.size() << " bytes) ---" << std::endl;
for (auto byte : received_data) {
printf("%02X ", byte);
}
std::cout << 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::cout << "\n--- No data received within the 3-second timeout. ---" << std::endl;
std::cerr << "Failed to read temperature alarm status." << std::endl;
}
// 5. 关闭串口
// 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 << "\nSerial port closed." << std::endl;
std::cout << "\n==================== Test Finished. ====================" << std::endl;
return 0;
}