blob: ae08415dc4e28d4534dc94e62dd7bd26a501a081 [file] [log] [blame] [edit]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fbl/type_support.h>
#include <hid-parser/report.h>
namespace hid {
namespace {
inline bool FieldFits(const Report& report, const Attributes& attr) {
return (attr.offset + attr.bit_sz) <= (report.len * 8);
}
// Extracts bits from a byte and returns them
// Begin is the starting bit: it starts at 0 and counts from LSB to MSB
// The bits are placed at the beginning of return value.
// Make sure when this is called that (begin + count) <= 8
// Eg: ExtractBitsFromByte(1b00010100, 2, 3) returns 1b101
inline uint8_t ExtractBitsFromByte(uint8_t val, uint32_t begin, uint8_t count) {
uint8_t mask = static_cast<uint8_t>((0xFF >> (8 - count)) << begin);
return static_cast<uint8_t>((val & mask) >> begin);
}
} // namespace
#define MIN(a, b) (a) < (b) ? (a) : (b)
template <typename T>
bool ExtractUint(const Report& report, const hid::Attributes& attr, T* value_out) {
static_assert(fbl::is_pod<T>::value, "not POD");
if (attr.bit_sz > sizeof(T) * 8) {
return false;
}
if (!FieldFits(report, attr)) {
return false;
}
T val = 0;
const uint32_t start_bit = attr.offset;
const uint32_t end_bit = start_bit + attr.bit_sz;
uint32_t index_bit = attr.offset;
while (index_bit < end_bit) {
uint8_t bits_till_byte_end = static_cast<uint8_t>(8u - (index_bit % 8u));
uint8_t bit_count = static_cast<uint8_t>(MIN(bits_till_byte_end, end_bit - index_bit));
uint8_t extracted_bits = ExtractBitsFromByte(report.data[index_bit / 8u], index_bit % 8u, bit_count);
val = static_cast<T>(val | (extracted_bits << (index_bit - start_bit)));
index_bit += bit_count;
}
*value_out = val;
return true;
}
#undef MIN
bool ExtractUint(const Report& report, const hid::Attributes& attr, uint8_t* value_out) {
return ExtractUint<uint8_t>(report, attr, value_out);
}
bool ExtractUint(const Report& report, const hid::Attributes& attr, uint16_t* value_out) {
return ExtractUint<uint16_t>(report, attr, value_out);
}
bool ExtractUint(const Report& report, const hid::Attributes& attr, uint32_t* value_out) {
return ExtractUint<uint32_t>(report, attr, value_out);
}
} // namespace hid