#ifndef RS485CONTROLLER_H
#define RS485CONTROLLER_H

#include <QObject>
#include <QSerialPort>
#include <QTimer>

namespace RS485Error {
    constexpr int SUCCESS = 0;
    constexpr int INIT_FAILED = -1;
    constexpr int PORT_OPEN_FAILED = -2;
    constexpr int SEND_FAILED = -3;
    constexpr int TIMEOUT = -4;
    constexpr int INVALID_PORT = -5;
    constexpr int DEVICE_ERROR = -6;
}

/**
 * @brief RS485控制器类，用于通过RS485串口进行通信。
 * 
 * 该类封装了RS485串口的打开、关闭、数据发送和接收功能。它继承自QObject，可以用于Qt应用程序中。
 * 
 * 核心功能包括：
 * - 打开和关闭RS485串口
 * - 发送数据并等待响应
 * - 获取最后一次错误信息
 * - 配置RS485模式
 * 
 * 使用示例：
 * @code
 * RS485Controller controller;
 * controller.openPort("/dev/ttyS2", QSerialPort::Baud9600);
 * QByteArray data = "Hello, RS485!";
 * QByteArray reply;
 * if (controller.sendData(data, reply, 3000)) {
 *     qDebug() << "Received reply:" << reply;
 * } else {
 *     qDebug() << "Timeout or error occurred.";
 * }
 * controller.closePort();
 * @endcode
 * 
 * @param parent 父对象指针，用于QObject的继承
 */
class RS485Controller : public QObject
{
    Q_OBJECT
public:
    /**
     * @brief 构造函数，创建RS485Controller对象。
     * 
     * @param parent 父对象指针，用于QObject的继承
     */
    explicit RS485Controller(QObject *parent = nullptr);

    /**
     * @brief 析构函数，销毁RS485Controller对象。
     */
    ~RS485Controller();

    /**
     * @brief 打开RS485串口。
     * 
     * @param portName 串口名称，默认为"/dev/ttyS2"
     * @param baudRate 波特率，默认为9600
     * @param dataBits 数据位，默认为8位
     * @param parity 奇偶校验，默认为无校验
     * @param stopBits 停止位，默认为1位
     * @param flowControl 流控制，默认为无流控制
     * @return 是否成功打开串口
     */
    bool openPort(const QString& portName = "/dev/ttyS2",
                  qint32 baudRate = QSerialPort::Baud9600,
                  QSerialPort::DataBits dataBits = QSerialPort::Data8,
                  QSerialPort::Parity parity = QSerialPort::NoParity,
                  QSerialPort::StopBits stopBits = QSerialPort::OneStop,
                  QSerialPort::FlowControl flowControl = QSerialPort::NoFlowControl);

    /**
     * @brief 关闭RS485串口。
     */
    void closePort();

    /**
     * @brief 检查RS485串口是否已打开。
     * 
     * @return 串口是否已打开
     */
    bool isPortOpen() const;

    /**
     * @brief 发送数据并等待响应。
     * 
     * 该方法会阻塞发送数据，并等待指定超时时间内的响应。如果超时或发生错误，返回false。
     * 
     * @param data 要发送的数据
     * @param reply 接收到的响应数据
     * @param timeoutMs 超时时间，单位为毫秒，默认为3000毫秒
     * @return 是否成功接收到响应
     */
    bool sendData(const QByteArray& data, QByteArray& reply, int timeoutMs = 3000);

    /**
     * @brief 获取最后一次发生的错误信息。
     * 
     * @return 错误信息字符串
     */
    QString getLastError() const;

    /**
     * @brief 配置RS485模式。
     * 
     * @return 是否成功配置RS485模式
     */
    bool configureRS485Mode();

signals:
    /**
     * @brief 数据接收信号，当接收到数据时触发。
     * 
     * @param data 接收到的数据
     */
    void dataReceived(const QByteArray& data);

    /**
     * @brief 串口关闭信号，当串口关闭时触发。
     */
    void serialPortClosed();

    /**
     * @brief 错误发生信号，当发生错误时触发。
     * 
     * @param errorString 错误信息字符串
     */
    void errorOccurred(const QString& errorString);

private slots:
    /**
     * @brief 处理串口数据可读事件。
     */
    void handleReadyRead();

    /**
     * @brief 处理串口错误事件。
     * 
     * @param error 发生的错误
     */
    void handleError(QSerialPort::SerialPortError error);

private:
    /**
     * @brief 串口对象指针
     */
    QSerialPort* m_serialPort = nullptr;

    /**
     * @brief 最后一次错误信息
     */
    QString m_lastError;

    /**
     * @brief 最后一次接收到的响应数据
     */
    QByteArray m_lastReply;

    /**
     * @brief 是否已接收到响应
     */
    bool m_replyReceived = false;
};

#endif // RS485CONTROLLER_H
