// serial_port.cpp (修改版)
#include "serial_port.hpp"
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <cerrno>
#include <cstring>

// ... 构造函数、析构函数、open、close、isOpen、send、crc16函数保持不变 ...
// ... (为了简洁，这里省略了未改动的代码，请保留您文件中的这些部分) ...

SerialPort::SerialPort(const std::string& port_name)
    : port_name_(port_name), 
      fd_(-1), 
      is_open_(false), 
      stop_listener_(false) {}

SerialPort::~SerialPort() {
    close();
}

bool SerialPort::open(speed_t baud_rate) {
    if (is_open_) {
        std::cerr << "Warning: Port " << port_name_ << " is already open." << std::endl;
        return true;
    }

    fd_ = ::open(port_name_.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd_ == -1) {
        std::cerr << "Error: Failed to open serial port " << port_name_ 
                  << " - " << strerror(errno) << std::endl;
        return false;
    }

    fcntl(fd_, F_SETFL, 0);

    struct termios options;
    if (tcgetattr(fd_, &options) != 0) {
        std::cerr << "Error: tcgetattr failed - " << strerror(errno) << std::endl;
        ::close(fd_);
        fd_ = -1;
        return false;
    }

    cfsetispeed(&options, baud_rate);
    cfsetospeed(&options, baud_rate);

    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;
    options.c_cflag |= (CLOCAL | CREAD);
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    options.c_oflag &= ~OPOST;
    options.c_cc[VMIN] = 0;
    options.c_cc[VTIME] = 0;

    if (tcsetattr(fd_, TCSANOW, &options) != 0) {
        std::cerr << "Error: tcsetattr failed - " << strerror(errno) << std::endl;
        ::close(fd_);
        fd_ = -1;
        return false;
    }
    
    tcflush(fd_, TCIOFLUSH);
    is_open_ = true;
    std::cout << "Serial port " << port_name_ << " opened successfully." << std::endl;
    return true;
}

void SerialPort::close() {
    stopListening();
    if (is_open_) {
        is_open_ = false;
        ::close(fd_);
        fd_ = -1;
        std::cout << "Serial port " << port_name_ << " closed." << std::endl;
    }
}

bool SerialPort::isOpen() const {
    return is_open_;
}

bool SerialPort::send(const std::vector<uint8_t>& data) {
    if (!is_open_) {
        std::cerr << "Error: Port is not open. Cannot send data." << std::endl;
        return false;
    }

    uint16_t crc = crc16(data.data(), data.size());
    std::vector<uint8_t> data_with_crc = data;
    data_with_crc.push_back(crc & 0xFF);
    data_with_crc.push_back((crc >> 8) & 0xFF);

        
    ssize_t written = ::write(fd_, data_with_crc.data(), data_with_crc.size());

    if (written < 0) {
        std::cerr << "Error: Failed to write to serial port - " << strerror(errno) << std::endl;
        return false;
    }
    if (static_cast<size_t>(written) != data_with_crc.size()) {
        std::cerr << "Warning: Not all bytes were written to serial port." << std::endl;
    }

    return true;
}

void SerialPort::startListening(MessageHandler handler) {
    if (!is_open_) {
        std::cerr << "Error: Cannot start listening, port is not open." << std::endl;
        return;
    }
    if (listener_thread_.joinable()) {
        std::cerr << "Warning: Listener is already running." << std::endl;
        return;
    }

    message_handler_ = handler;
    stop_listener_ = false;
    listener_thread_ = std::thread(&SerialPort::listenerLoop, this);
}

void SerialPort::stopListening() {
    stop_listener_ = true;
    if (listener_thread_.joinable()) {
        listener_thread_.join();
    }
}


// 【新增】辅助函数：根据Modbus协议解析消息长度
// 返回值：>0 表示预期的消息长度，0 表示数据不足无法判断
size_t parseMessageLength(const std::vector<uint8_t>& buffer) {
    // 异常响应帧长度固定为5
    if (buffer.size() >= 2 && (buffer[1] & 0x80)) {
        return 5;
    }

    // 正常响应帧
    if (buffer.size() >= 3) {
        uint8_t func_code = buffer[1];
        if (func_code == 0x03 || func_code == 0x04) { // 读寄存器
            uint8_t byte_count = buffer[2];
            // 总长度 = 地址(1) + 功能码(1) + 字节数(1) + 数据(N) + CRC(2)
            return 3 + byte_count + 2;
        } else if (func_code == 0x06 || func_code == 0x10) { // 写寄存器
            // 写响应固定为8字节
            return 8;
        }
    }
    
    // 数据不足或功能码不识别，无法判断长度
    return 0;
}

// 【重大修改】监听线程的主循环函数
void SerialPort::listenerLoop() {
    std::vector<uint8_t> msg_buffer;
    uint8_t rx_buffer[256];

    while (!stop_listener_) {
        fd_set read_fds;
        FD_ZERO(&read_fds);
        FD_SET(fd_, &read_fds);

        // 使用一个较短的超时，避免长时间阻塞，以便能及时检查 stop_listener_
        struct timeval timeout;
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        int activity = select(fd_ + 1, &read_fds, nullptr, nullptr, &timeout);

        if (activity < 0 && errno != EINTR) {
            if (!stop_listener_) std::cerr << "Error: select() failed." << std::endl;
            break;
        }

        // 如果有数据可读
        if (FD_ISSET(fd_, &read_fds)) {
            ssize_t bytes_read = ::read(fd_, rx_buffer, sizeof(rx_buffer));
            if (bytes_read > 0) {
                // 将新数据追加到缓冲区
                msg_buffer.insert(msg_buffer.end(), rx_buffer, rx_buffer + bytes_read);
            } else if (bytes_read < 0) {
                 if (!stop_listener_) std::cerr << "Error: read() failed." << std::endl;
                 break;
            }
        }
        
        // 【核心逻辑】循环处理缓冲区中的数据，直到数据不够一帧
        while (true) {
            size_t expected_len = parseMessageLength(msg_buffer);

            // 如果能确定预期长度，并且缓冲区数据足够
            if (expected_len > 0 && msg_buffer.size() >= expected_len) {
                // 提取一个完整的消息
                std::vector<uint8_t> complete_msg(msg_buffer.begin(), msg_buffer.begin() + expected_len);
                
                // 调用回调函数处理消息
                if (message_handler_) {
                    message_handler_(complete_msg);
                }
                
                // 从缓冲区头部删除已处理的消息
                msg_buffer.erase(msg_buffer.begin(), msg_buffer.begin() + expected_len);
                
            } else {
                // 数据不够一帧，或无法判断帧长，跳出内层循环，等待更多数据
                break;
            }
        }
    }
}

uint16_t SerialPort::crc16(const uint8_t *data, size_t len) {
    uint16_t crc = 0xFFFF;
    for (size_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    return crc;
}