/* * Copyright 2019-2023 PixlOne * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef LOGID_BACKEND_HIDPP_DEVICE_H #define LOGID_BACKEND_HIDPP_DEVICE_H #include #include #include #include #include #include #include #include #include #include namespace logid::backend::hidpp10 { // Need to define here for a constructor class Receiver; } namespace logid::backend::hidpp { struct DeviceConnectionEvent; namespace { template class DeviceWrapper : public T { friend class Device; public: template explicit DeviceWrapper(Args... args) : T(std::forward(args)...) { } template static std::shared_ptr make(Args... args) { return std::make_shared(std::forward(args)...); } }; } class Device { template friend class DeviceWrapper; public: struct EventHandler { std::function condition; std::function callback; }; class InvalidDevice : std::exception { public: enum Reason { NoHIDPPReport, InvalidRawDevice, Asleep, VirtualNode }; explicit InvalidDevice(Reason reason) : _reason(reason) {} [[nodiscard]] const char* what() const noexcept override; [[nodiscard]] virtual Reason code() const noexcept; private: Reason _reason; }; [[nodiscard]] const std::string& devicePath() const; [[nodiscard]] DeviceIndex deviceIndex() const; [[nodiscard]] const std::tuple& version() const; [[nodiscard]] const std::string& name() const; [[nodiscard]] uint16_t pid() const; EventHandlerLock addEventHandler(EventHandler handler); virtual Report sendReport(const Report& report); virtual void sendReportNoACK(const Report& report); void handleEvent(Report& report); [[nodiscard]] const std::shared_ptr& rawDevice() const; Device(const Device&) = delete; Device(Device&&) = delete; virtual ~Device() = default; protected: Device(const std::string& path, DeviceIndex index, const std::shared_ptr& monitor, double timeout); Device(std::shared_ptr raw_device, DeviceIndex index, double timeout); Device(const std::shared_ptr& receiver, hidpp::DeviceConnectionEvent event, double timeout); Device(const std::shared_ptr& receiver, DeviceIndex index, double timeout); // Returns whether the report is a response virtual bool responseReport(const Report& report); bool isStable20(); bool isStable10(); void _sendReport(Report report); void reportFixup(Report& report) const; const std::chrono::milliseconds io_timeout; uint8_t supported_reports{}; std::mutex _response_mutex; std::condition_variable _response_cv; private: void _setupReportsAndInit(); void _init(); std::shared_ptr _raw_device; EventHandlerLock _raw_handler; std::shared_ptr _receiver; std::string _path; DeviceIndex _index; std::tuple _version; uint16_t _pid{}; std::string _name; std::mutex _send_mutex; typedef std::variant Response; std::optional _response; std::optional _sent_sub_id{}; std::shared_ptr> _event_handlers; std::weak_ptr _self; protected: template static std::shared_ptr makeDerived(Args... args) { auto device = DeviceWrapper::make(std::forward(args)...); device->_self = device; device->_setupReportsAndInit(); return device; } public: template static std::shared_ptr make(Args... args) { return makeDerived(std::forward(args)...); } }; typedef Device::EventHandler EventHandler; } #endif //LOGID_BACKEND_HIDPP_DEVICE_H