| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIBTOUCHRAW_PARSER_H_ |
| #define LIBTOUCHRAW_PARSER_H_ |
| |
| #include <memory> |
| #include <optional> |
| #include <span> |
| #include <utility> |
| #include <vector> |
| |
| #include <linux/hidraw.h> |
| |
| #include <base/task/sequenced_task_runner.h> |
| #include <brillo/udev/udev_device.h> |
| #include <gtest/gtest_prod.h> |
| |
| #include "libtouchraw/consumer_interface.h" |
| #include "libtouchraw/touchraw.h" |
| #include "libtouchraw/touchraw_export.h" |
| |
| namespace touchraw { |
| |
| // Please refer to |
| // https://www.usb.org/document-library/device-class-definition-hid-111 for HID |
| // report item format. |
| struct Item { |
| std::span<const uint8_t> data; |
| uint8_t data_size; // Specify size of data. Based on the device class |
| // definition doc section 6.2.2.3, long items may contain |
| // up to 256 bytes of data. So 8 bits is enough here. |
| uint16_t size; // Specify total size of an item. |
| uint8_t prefix; // All items have a one-byte prefix that contains the item |
| // tag, item type, and item size. |
| }; |
| |
| // Describe a main item of report descriptor. |
| struct MainItem { |
| uint16_t usage_page; |
| uint16_t usage; |
| uint8_t report_id; |
| uint32_t data_size; // Size of the data field in bytes. |
| }; |
| |
| // Necessary information to create a main item. |
| struct MainItemInfo { |
| uint16_t usage_page; |
| uint16_t usage; |
| uint8_t report_id; |
| uint32_t report_size; |
| uint32_t report_count; |
| }; |
| |
| class ReportDescriptor { |
| public: |
| explicit ReportDescriptor(const hidraw_report_descriptor* rpt_desc); |
| |
| ReportDescriptor(const ReportDescriptor&) = delete; |
| ReportDescriptor& operator=(const ReportDescriptor&) = delete; |
| |
| // True if the internal index has not reached the end of the report |
| // descriptor; False otherwise. |
| bool HasNextItem(); |
| // Return the next item. |
| Item GetNextItem(); |
| // Reset the internal index. |
| void Reset(); |
| |
| private: |
| const hidraw_report_descriptor* rpt_desc_; |
| uint16_t next_item_idx_; // Starting index of the next item to be processed. |
| }; |
| |
| class LIBTOUCHRAW_EXPORT Parser : public HIDDataConsumerInterface { |
| public: |
| /** |
| * Factory method: creates and returns a Parser. |
| * May return null on failure cases that it fails to get a report descriptor |
| * or the report descriptor does not support heat map. |
| * |
| * @param fd File descriptor. |
| * @param q HeatmapChunk consumer queue for tasks to be posted. |
| * @return Unique pointer of Parser if create succeeds, null pointer |
| * otherwise. |
| */ |
| static std::unique_ptr<Parser> Create( |
| const int fd, std::unique_ptr<HeatmapChunkConsumerInterface> q); |
| |
| static std::unique_ptr<Parser> CreateForTesting( |
| std::unique_ptr<HeatmapChunkConsumerInterface> q); |
| |
| Parser(const Parser&) = delete; |
| Parser& operator=(const Parser&) = delete; |
| |
| void Push(std::unique_ptr<const HIDData> data) override { |
| base::SequencedTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, base::BindOnce(&Parser::ParseHIDData, base::Unretained(this), |
| std::move(data))); |
| } |
| |
| protected: |
| /** |
| * Parse HID data read from the file descriptor. |
| * |
| * @param hid_data |
| */ |
| void ParseHIDData(std::unique_ptr<const HIDData> hid_data); |
| |
| private: |
| FRIEND_TEST(ParserTest, ValidReportDescriptorWithHeatmap); |
| FRIEND_TEST(ParserTest, ValidReportDescriptorWithoutHeatmap); |
| FRIEND_TEST(ParserTest, UnknownHidType); |
| |
| /** |
| * Parser constructor. |
| * This class retrieves the input device report descriptor and parses HID data |
| * into heatmap chunks. |
| * |
| * @param q HeatmapChunk consumer queue for tasks to be posted. |
| */ |
| explicit Parser(std::unique_ptr<HeatmapChunkConsumerInterface> q); |
| |
| /** |
| * Get report descriptor from ioctl. |
| * |
| * @return Usually, on success zero is returned. On error, -1 is returned, and |
| * errno is set to indicate the error. |
| */ |
| int GetReportDescriptorIoctl(const int fd, |
| hidraw_report_descriptor* rpt_desc); |
| |
| /** |
| * Helper function to create a udev device. |
| * |
| * @return Unique pointer of UdevDevice if create succeeds, null pointer |
| * otherwise. |
| */ |
| std::unique_ptr<brillo::UdevDevice> CreateUdevDevice(const int fd); |
| |
| /** |
| * Get report descriptor from sysfs. |
| * |
| * @return Usually, on success zero is returned. On error, -1 is returned, and |
| * errno is set to indicate the error. |
| */ |
| int GetReportDescriptorSysfs(const int fd, |
| hidraw_report_descriptor* rpt_desc); |
| // TODO: b/317990775 - Extract descriptor parsing into a sub-library of |
| // libtouchraw. |
| bool ParseHeatmapReportsFromDescriptor( |
| const hidraw_report_descriptor* rpt_desc); |
| |
| /** |
| * Helper function to get data field value. |
| * |
| * @param index Data field index. |
| * @param size Data field size. |
| * @return Data field value. |
| */ |
| uint32_t GetDataField(int index, int size, std::span<const uint8_t> payload); |
| |
| // Helper function to process items and save report data fields into the |
| // usages table. |
| void ProcessItem(Item& item); |
| // Helper function to get the value of the data field of a report. |
| uint32_t GetPropValue(std::span<const uint8_t> data, int data_size); |
| |
| // Usages table that contains each usage item from the report descriptor. |
| std::vector<MainItem> usages_; |
| // Stores the information of each usage item. |
| MainItemInfo info_; |
| // Offset index of usages table for the first chunk of heat map input report |
| // type. |
| std::optional<uint16_t> sync_report_offset_; |
| // Offset index of usages table for the subsequent chunks of heat map input |
| // report type. |
| std::optional<uint16_t> sub_report_offset_; |
| |
| // Task queue. |
| const std::unique_ptr<HeatmapChunkConsumerInterface> q_; |
| }; |
| |
| } // namespace touchraw |
| |
| #endif // LIBTOUCHRAW_PARSER_H_ |