diff --git a/src/server_heartbeat.cc b/src/archive/server_heartbeat.cc similarity index 100% rename from src/server_heartbeat.cc rename to src/archive/server_heartbeat.cc diff --git a/src/server_heartbeat.h b/src/archive/server_heartbeat.h similarity index 100% rename from src/server_heartbeat.h rename to src/archive/server_heartbeat.h diff --git a/src/test.cc b/src/test.cc index 664ac25..8cb157b 100644 --- a/src/test.cc +++ b/src/test.cc @@ -1,60 +1,59 @@ #include #include +#include #include #include #include #include #include +#include +#include +#include #include -// --- 配置 --- -// 要打开的串口 +// === 可配置参数 === 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& 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(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 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 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 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 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(response.begin() + 2, response.end() - 2); +} + +/** + * @brief 修正:正确解析温湿度数据 (根据手册,数据本身是16位无符号整数,然后除以10) + * @param data 两个字节的原始数据 + * @return float 解析后的温湿度值 + */ +float parseSensorData(const std::vector& data) { + if (data.size() < 2) return NAN; + + // 根据手册,数据是16位无符号整数 + uint16_t raw_value = (data[0] << 8) | data[1]; + + // 然后除以10得到最终值 + return static_cast(raw_value) / 10.0f; +} + +/** + * @brief 根据设备返回的值解析实际波特率 + * @param baud_data 寄存器0x0003返回的两个字节数据 + * @return int 实际波特率 (1200, 2400, ...) + */ +int parseBaudrate(const std::vector& 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 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; }