#ifndef DEVICE_CTRL_SERIAL_PORT_H
#define DEVICE_CTRL_SERIAL_PORT_H
#include <QCoreApplication>
#include <QObject>
#include <QSerialPort>
#include <QSharedPointer.h>
#include <shared_mutex>
#include <utility>

namespace zsy
{
    /**
     * 串口处理器
     */
    template<typename F>
    concept SerialPortProcessor = std::invocable<F, const QByteArray &> &&
                                  std::convertible_to<
                                      std::invoke_result_t<F, const QByteArray &>,
                                      int32_t
                                  >;

    class SerialPort final : public QObject
    {
        Q_OBJECT

    public:
        enum SerialPortStatus : uint8_t
        {
            // 不可用
            Unavailable,
            Available,
            Stopped,
        };

        struct DCB
        {
            /**
             * 串口号
             */
            const QString portName;
            /**
             * 波特率
             */
            const QSerialPort::BaudRate baudRate;
            /**
             * 数据位
             */
            const QSerialPort::DataBits dataBits;
            /**
             * 停止位
             */
            const QSerialPort::StopBits stopBits;
            /**
             * 校验位
             */
            const QSerialPort::Parity parity;
            /**
             * 流控
             */
            const QSerialPort::FlowControl flowControl;

            explicit DCB(const std::string &portName,
                         int32_t baudRate = QSerialPort::Baud9600,
                         int32_t dataBits = QSerialPort::Data8,
                         int32_t stopBits = QSerialPort::OneStop,
                         int32_t parity = QSerialPort::NoParity,
                         int32_t flowControl = QSerialPort::NoFlowControl);
        };

        explicit SerialPort(DCB dcb, const std::function<int32_t(const QByteArray & buf)> &processor, QObject *parent = nullptr);


        ~SerialPort() override;

    private:
        std::atomic_bool stopped;

        DCB dcb;

        std::shared_ptr<QByteArray> buf;

        std::function<int32_t(const QByteArray & buf)> processor;

        QSharedPointer<QSerialPort> port;

        void close();

        void open();

    public:
        bool canUse();

        Q_SIGNALS:
        

        void sperr();

    private
        Q_SLOTS:
        

        void onData() const;

        void onError(QSerialPort::SerialPortError error);
    };
} // zsy

#endif // DEVICE_CTRL_SERIAL_PORT_H