|
| 1 | + |
1 | 2 | /*
|
2 |
| - SlimeVR Code is placed under the MIT license |
3 |
| - Copyright (c) 2023 SlimeVR Contributors |
4 |
| -
|
5 |
| - Permission is hereby granted, free of charge, to any person obtaining a copy |
6 |
| - of this software and associated documentation files (the "Software"), to deal |
7 |
| - in the Software without restriction, including without limitation the rights |
8 |
| - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
9 |
| - copies of the Software, and to permit persons to whom the Software is |
10 |
| - furnished to do so, subject to the following conditions: |
11 |
| -
|
12 |
| - The above copyright notice and this permission notice shall be included in |
13 |
| - all copies or substantial portions of the Software. |
14 |
| -
|
15 |
| - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 |
| - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 |
| - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
18 |
| - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
19 |
| - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
20 |
| - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
21 |
| - THE SOFTWARE. |
| 3 | + SlimeVR Code is placed under the MIT license |
| 4 | + Copyright (c) 2023 SlimeVR Contributors |
| 5 | +
|
| 6 | + Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | + of this software and associated documentation files (the "Software"), to deal |
| 8 | + in the Software without restriction, including without limitation the rights |
| 9 | + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | + copies of the Software, and to permit persons to whom the Software is |
| 11 | + furnished to do so, subject to the following conditions: |
| 12 | +
|
| 13 | + The above copyright notice and this permission notice shall be included in |
| 14 | + all copies or substantial portions of the Software. |
| 15 | +
|
| 16 | + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | + THE SOFTWARE. |
22 | 23 | */
|
23 | 24 |
|
24 | 25 | #ifndef SLIMEVR_FEATURE_FLAGS_H_
|
25 | 26 | #define SLIMEVR_FEATURE_FLAGS_H_
|
26 | 27 |
|
27 |
| -#include <cstring> |
28 | 28 | #include <algorithm>
|
29 |
| - |
30 |
| -/** |
31 |
| - * Bit packed flags, enum values start with 0 and indicate which bit it is. |
32 |
| - * |
33 |
| - * Change the enums and `flagsEnabled` inside to extend. |
34 |
| -*/ |
35 |
| -struct ServerFeatures { |
36 |
| -public: |
37 |
| - enum EServerFeatureFlags: uint32_t { |
38 |
| - // Server can parse bundle packets: `PACKET_BUNDLE` = 100 (0x64). |
39 |
| - PROTOCOL_BUNDLE_SUPPORT, |
40 |
| - |
41 |
| - // Add new flags here |
42 |
| - |
43 |
| - BITS_TOTAL, |
44 |
| - }; |
45 |
| - |
46 |
| - bool has(EServerFeatureFlags flag) { |
47 |
| - uint32_t bit = static_cast<uint32_t>(flag); |
48 |
| - return m_Available && (m_Flags[bit / 8] & (1 << (bit % 8))); |
49 |
| - } |
50 |
| - |
51 |
| - /** |
52 |
| - * Whether the server supports the "feature flags" feature, |
53 |
| - * set to true when we've received flags packet from the server. |
54 |
| - */ |
55 |
| - bool isAvailable() { |
56 |
| - return m_Available; |
57 |
| - } |
58 |
| - |
59 |
| - static ServerFeatures from(uint8_t* received, uint32_t length) { |
60 |
| - ServerFeatures res; |
61 |
| - res.m_Available = true; |
62 |
| - memcpy(res.m_Flags, received, std::min(static_cast<uint32_t>(sizeof(res.m_Flags)), length)); |
63 |
| - return res; |
64 |
| - } |
65 |
| - |
66 |
| -private: |
67 |
| - bool m_Available = false; |
68 |
| - |
69 |
| - uint8_t m_Flags[static_cast<uint32_t>(EServerFeatureFlags::BITS_TOTAL) / 8 + 1]; |
| 29 | +#include <cinttypes> |
| 30 | +#include <cstring> |
| 31 | +#include <unordered_map> |
| 32 | + |
| 33 | +// I hate C++11 - they fixed this in C++14, but our compilers are old as the iceage |
| 34 | +struct EnumClassHash { |
| 35 | + template <typename T> |
| 36 | + std::size_t operator()(T t) const { |
| 37 | + return static_cast<std::size_t>(t); |
| 38 | + } |
70 | 39 | };
|
71 | 40 |
|
72 |
| -class FirmwareFeatures { |
73 |
| -public: |
74 |
| - enum EFirmwareFeatureFlags: uint32_t { |
75 |
| - // EXAMPLE_FEATURE, |
76 |
| - B64_WIFI_SCANNING = 1, |
77 |
| - |
78 |
| - // Add new flags here |
79 |
| - |
80 |
| - BITS_TOTAL, |
81 |
| - }; |
| 41 | +enum EServerFeatureFlags : uint32_t { |
| 42 | + // Server can parse bundle packets: `PACKET_BUNDLE` = 100 (0x64). |
| 43 | + PROTOCOL_BUNDLE_SUPPORT, |
82 | 44 |
|
83 |
| - // Flags to send |
84 |
| - static constexpr const std::initializer_list<EFirmwareFeatureFlags> flagsEnabled = { |
85 |
| - // EXAMPLE_FEATURE, |
86 |
| - B64_WIFI_SCANNING, |
| 45 | + BITS_TOTAL, |
| 46 | +}; |
87 | 47 |
|
88 |
| - // Add enabled flags here |
89 |
| - }; |
| 48 | +enum class EFirmwareFeatureFlags : uint32_t { |
| 49 | + // EXAMPLE_FEATURE, |
| 50 | + B64_WIFI_SCANNING = 1, |
90 | 51 |
|
91 |
| - static constexpr auto flags = []{ |
92 |
| - constexpr uint32_t flagsLength = EFirmwareFeatureFlags::BITS_TOTAL / 8 + 1; |
93 |
| - std::array<uint8_t, flagsLength> packed{}; |
| 52 | + BITS_TOTAL, |
| 53 | +}; |
94 | 54 |
|
95 |
| - for (uint32_t bit : flagsEnabled) { |
96 |
| - packed[bit / 8] |= 1 << (bit % 8); |
97 |
| - } |
| 55 | +template <typename Flags> |
| 56 | +class FeatureFlags { |
| 57 | +public: |
| 58 | + static constexpr auto FLAG_BYTES |
| 59 | + = ((static_cast<size_t>(Flags::BITS_TOTAL)) + 7) / 8; |
| 60 | + |
| 61 | + FeatureFlags() |
| 62 | + : m_Available(false) {} |
| 63 | + FeatureFlags(uint8_t* packed, uint32_t length) |
| 64 | + : m_Available(true) { |
| 65 | + for (uint32_t bit = 0; bit < length * 8; bit++) { |
| 66 | + auto posInPacked = bit / 8; |
| 67 | + auto posInByte = bit % 8; |
| 68 | + |
| 69 | + m_Flags[static_cast<Flags>(bit)] = packed[posInPacked] & (1 << posInByte); |
| 70 | + } |
| 71 | + } |
| 72 | + FeatureFlags(std::unordered_map<Flags, bool, EnumClassHash> flags) |
| 73 | + : m_Available(true) |
| 74 | + , m_Flags(flags) {} |
| 75 | + |
| 76 | + std::array<uint8_t, FLAG_BYTES> pack() { |
| 77 | + std::array<uint8_t, FLAG_BYTES> packed{}; |
| 78 | + |
| 79 | + for (auto& [flag, value] : m_Flags) { |
| 80 | + auto posInPacked = static_cast<size_t>(flag) / 8; |
| 81 | + auto posInByte = static_cast<size_t>(flag) % 8; |
| 82 | + |
| 83 | + if (value) { |
| 84 | + packed[posInPacked] |= 1 << posInByte; |
| 85 | + } |
| 86 | + } |
| 87 | + |
| 88 | + return packed; |
| 89 | + }; |
| 90 | + |
| 91 | + bool has(Flags flag) { return m_Flags[flag]; } |
| 92 | + bool isAvailable() { return m_Available; } |
98 | 93 |
|
99 |
| - return packed; |
100 |
| - }(); |
| 94 | +private: |
| 95 | + bool m_Available = false; |
| 96 | + std::unordered_map<Flags, bool, EnumClassHash> m_Flags{}; |
101 | 97 | };
|
102 | 98 |
|
103 | 99 | #endif
|
0 commit comments