New classes/macros:

* a class Bitfield that does the general bit handling.
    * a utility function generateBitfield that simplifies bitfield
creation
    * function macros KEYMAP_BITFIELD and KEYMAP_BITFIELD_STACKED that
enable definitions of keymap bitfields in the same way as keymaps are
defined

    All exported functions live in namespace kaleidoscope::bitfields.

    Please note, that KEYMAP_BITFIELD is only defined if a keyboard
hardware defines a
    KEYMAP_GENERIC macro and KEYMAP_BITFIELD_STACKED only if the
hardware header defines
    KEYMAP_STACKED_GENERIC (not all keyboard hardwares define both).

    Expected side effects:

    As all symbols and macros are newly introduced, nothing is expected
to break.

Signed-off-by: Jesse Vincent <jesse@keyboard.io>
pull/645/head
Florian Fleissner 5 years ago committed by Jesse Vincent
parent ea052183be
commit f764a78ecd

@ -0,0 +1,53 @@
/* Kaleidoscope - Firmware for computer input devices
* Copyright (C) 2013-2018 Keyboard.io, Inc.
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Kaleidoscope.h"
#include "bitfields.h"
namespace kaleidoscope {
namespace bitfields {
namespace internal {
bool _BaseBitfield::isBitSetP(const void *bit_field, uint8_t raw_pos) {
uint8_t byte_id = raw_pos >> 3;
uint8_t bit_pos = raw_pos & 0x7;
const uint8_t *bytes = reinterpret_cast<const uint8_t *>(bit_field);
return bytes[byte_id] & (0x1 << bit_pos);
}
void _BaseBitfield::setBitP(void *bit_field, uint8_t raw_pos, uint8_t val) {
uint8_t byte_id = raw_pos >> 3;
uint8_t bit_pos = raw_pos & 0x7;
uint8_t *bytes = reinterpret_cast<uint8_t *>(bit_field);
if (val) {
bytes[byte_id] |= (0x1 << bit_pos);
} else {
bytes[byte_id] &= ~(0x1 << bit_pos);
}
}
bool _BaseBitfield::isBitSetPROGMEM_P(const void *bit_field, uint8_t raw_pos) {
uint8_t byte_id = raw_pos >> 3;
uint8_t bit_pos = raw_pos & 0x7;
const uint8_t *bytes = reinterpret_cast<const uint8_t *>(bit_field);
uint8_t byte = pgm_read_byte(&(bytes[byte_id]));
return byte & (0x1 << bit_pos);
}
} // end namespace internal
} // end namespace bitfields
} // end namespace kaleidoscope

@ -0,0 +1,200 @@
/* Kaleidoscope - Firmware for computer input devices
* Copyright (C) 2013-2018 Keyboard.io, Inc.
*
* 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, version 3.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
namespace kaleidoscope {
namespace bitfields {
namespace internal {
// To store the bitfield we use a recursively defined template struct.
// It contains one byte of storage and a nested template struct
// that wraps the remaining bytes. A specialization of the template
// is used to end the recursion.
//
// By tagging the struct with __attribute__((packed)), we make sure
// that no padding bytes are added between the struct instances
// if the struct is used on non-8 bit architectures. This is important
// to ensure that all bytes are stored contiguously like it is the
// case in an intrinsic array.
//
template<uint8_t Byte_Count__>
struct _Bitfield {
uint8_t byte_;
_Bitfield < Byte_Count__ - 1 > more_bytes_;
// The constructor initializes the first eight bits that are stored
// in this struct and passes the remaining bits on to the nested
// more_bytes_ struct.
//
template<typename ... Bits__>
constexpr _Bitfield(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3,
uint8_t b4, uint8_t b5, uint8_t b6, uint8_t b7,
Bits__ ... bits)
: byte_(b0 << 0
| b1 << 1
| b2 << 2
| b3 << 3
| b4 << 4
| b5 << 5
| b6 << 6
| b7 << 7),
more_bytes_(bits...)
{}
} __attribute__((packed));
// A specialization that stores any remaining 1 to 8 bits. Any bits that
// are unused are zeroed by default.
//
template<>
struct _Bitfield<1 /* the last byte */> {
uint8_t byte_;
constexpr _Bitfield(uint8_t b0 = 0, uint8_t b1 = 0, uint8_t b2 = 0, uint8_t b3 = 0,
uint8_t b4 = 0, uint8_t b5 = 0, uint8_t b6 = 0, uint8_t b7 = 0)
: byte_(b0 << 0
| b1 << 1
| b2 << 2
| b3 << 3
| b4 << 4
| b5 << 5
| b6 << 6
| b7 << 7)
{}
} __attribute__((packed));
// A common base class that provides methods to access the bits in
// a _Bitfield instance by treating it as a raw array.
//
class _BaseBitfield {
protected:
static bool isBitSetP(const void *bit_field, uint8_t raw_pos);
static void setBitP(void *bit_field, uint8_t raw_pos, uint8_t val);
static bool isBitSetPROGMEM_P(const void *bit_field, uint8_t raw_pos);
};
} // end namespace internal
// This is the actual user class.
//
template<size_t BitCount__>
class Bitfield : public internal::_BaseBitfield {
public:
static constexpr size_t nBytesForBits(size_t n_bits) {
return (n_bits % 8) ? n_bits / 8 + 1 : n_bits / 8;
}
static constexpr size_t n_bits_ = BitCount__;
static constexpr size_t n_bytes_ = nBytesForBits(BitCount__);
template<typename ... Bits__>
constexpr Bitfield(Bits__...bits) : bits_(bits...) {
static_assert(sizeof...(Bits__) == n_bits_,
"Invalid number of bits supplied to Bitfield<BitCount__> constructor. \n"
"Compare the number of bits supplied with the provided template \n"
"parameter BitCount__ to find out what went wrong.\n");
}
bool isBitSet(uint8_t raw_pos) const {
return isBitSetP(&bits_, raw_pos);
}
bool isBitSetPROGMEM(uint8_t raw_pos) const {
return isBitSetPROGMEM_P(&bits_, raw_pos);
}
void setBit(uint8_t raw_pos, uint8_t val) {
setBitP(&bits_, raw_pos, val);
}
// An operator to query bits.
// Note: This assumes bitfield to be stored in PROGMEM. Use the
// access method isBitSet(raw_pos) otherwise.
//
constexpr bool operator[](uint8_t raw_pos) const {
return this->isBitSetPROGMEM_P(raw_pos);
}
private:
internal::_Bitfield<n_bytes_> bits_;
};
// The method generateBitfield may be used to conveniently create bitfields.
//
// auto my_bitfield = generateBitfield(1, 2, 3);
//
// Note: Due to a restriction in all gcc versions < 6.0
// this function cannot be called with the output of KEYMAP_STACKED(...)
// or KEYMAP(...) as its arguments.
//
template<typename...Bits__>
constexpr Bitfield<sizeof...(Bits__)> generateBitfield(Bits__...bits) {
return Bitfield<sizeof...(Bits__)>(bits...);
}
// This auxiliary method determines the number of entries in a list.
//
namespace internal {
template<typename...Args__>
constexpr size_t nListEntries(Args__...) {
return sizeof...(Args__);
}
} // end namespace internal
// Defines a bitfield named VAR_NAME. Applies MODIFIER (could e.g. set to const PROGMEM).
//
#define BITFIELD__(VAR_NAME, MODIFIER, ...) \
constexpr size_t VAR_NAME##_n_bits __NL__ \
= kaleidoscope::bitfields::internal::nListEntries(__VA_ARGS__);__NL__ \
__NL__ \
MODIFIER kaleidoscope::bitfields::Bitfield<VAR_NAME##_n_bits> __NL__ \
VAR_NAME{__VA_ARGS__};
#define BITFIELD(VAR_NAME, ...) BITFIELD__(VAR_NAME,, __VA_ARGS__)
#define BITFIELD_PROGMEM(VAR_NAME, ...) BITFIELD__(VAR_NAME, const PROGMEM, __VA_ARGS__)
#ifdef KEYMAP_GENERIC
#define KEYMAP_BITFIELD(VAR_NAME, ...) \
BITFIELD(VAR_NAME, KEYMAP_GENERIC(0 /*default for non-existent keys*/, __VA_ARGS__))
#define KEYMAP_BITFIELD_PROGMEM(VAR_NAME, ...) \
BITFIELD_PROGMEM(VAR_NAME, KEYMAP_GENERIC(0 /*default for non-existent keys*/, __VA_ARGS__))
#endif
#ifdef KEYMAP_STACKED_GENERIC
#define KEYMAP_BITFIELDK_STACKED(VAR_NAME, ...) \
BITFIELD(VAR_NAME, KEYMAP_STACKED_GENERIC(0 /*default for non-existent keys*/, __VA_ARGS__))
#define KEYMAP_BITFIELD_STACKED_PROGMEM(VAR_NAME, ...) \
BITFIELD_PROGMEM(VAR_NAME, KEYMAP_STACKED_GENERIC(0 /*default for non-existent keys*/, __VA_ARGS__))
#endif
} // end namespace bitfields
} // end namespace kaleidoscope
Loading…
Cancel
Save