Skip to content

Commit c877176

Browse files
committed
refactor: feature flags
1 parent 4adbfe0 commit c877176

File tree

3 files changed

+100
-93
lines changed

3 files changed

+100
-93
lines changed

src/network/connection.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ bool Connection::beginBundle() {
118118
memset(m_BundledPacket, 0, sizeof(m_BundledPacket));
119119
m_BundlePacketInnerCount = 0;
120120

121-
MUST_TRANSFER_BOOL(m_ServerFeatures.has(ServerFeatures::PROTOCOL_BUNDLE_SUPPORT));
121+
MUST_TRANSFER_BOOL(m_ServerFeatures.has(EServerFeatureFlags::PROTOCOL_BUNDLE_SUPPORT
122+
));
122123
MUST_TRANSFER_BOOL(m_Connected);
123124
MUST_TRANSFER_BOOL(!m_IsBundle);
124125
MUST_TRANSFER_BOOL(beginPacket());
@@ -378,7 +379,8 @@ void Connection::sendFeatureFlags() {
378379

379380
MUST(sendPacketType(PACKET_FEATURE_FLAGS));
380381
MUST(sendPacketNumber());
381-
MUST(write(FirmwareFeatures::flags.data(), FirmwareFeatures::flags.size()));
382+
auto packedFeatures = m_FirmwareFeatures.pack();
383+
MUST(write(packedFeatures.data(), packedFeatures.size()));
382384

383385
MUST(endPacket());
384386
}
@@ -577,7 +579,7 @@ void Connection::searchForServer() {
577579
m_Connected = true;
578580

579581
m_FeatureFlagsRequestAttempts = 0;
580-
m_ServerFeatures = ServerFeatures{};
582+
m_ServerFeatures = FeatureFlags<EServerFeatureFlags>();
581583

582584
statusManager.setStatus(SlimeVR::Status::SERVER_CONNECTING, false);
583585
ledManager.off();
@@ -711,11 +713,13 @@ void Connection::update() {
711713

712714
bool hadFlags = m_ServerFeatures.isAvailable();
713715
uint32_t flagsLength = len - 12;
714-
m_ServerFeatures = ServerFeatures::from(&m_Packet[12], flagsLength);
716+
m_ServerFeatures
717+
= FeatureFlags<EServerFeatureFlags>(&m_Packet[12], flagsLength);
715718

716719
if (!hadFlags) {
717720
#if PACKET_BUNDLING != PACKET_BUNDLING_DISABLED
718-
if (m_ServerFeatures.has(ServerFeatures::PROTOCOL_BUNDLE_SUPPORT)) {
721+
if (m_ServerFeatures.has(EServerFeatureFlags::PROTOCOL_BUNDLE_SUPPORT
722+
)) {
719723
m_Logger.debug("Server supports packet bundling");
720724
}
721725
#endif

src/network/connection.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ namespace Network {
3737

3838
class Connection {
3939
public:
40+
Connection()
41+
: m_FirmwareFeatures(m_EnabledFirmwareFeatures) {}
42+
4043
void searchForServer();
4144
void update();
4245
void reset();
@@ -107,7 +110,7 @@ class Connection {
107110
);
108111
#endif
109112

110-
const ServerFeatures& getServerFeatureFlags() { return m_ServerFeatures; }
113+
const auto getServerFeatureFlags() { return m_ServerFeatures; }
111114

112115
bool beginBundle();
113116
bool endBundle();
@@ -166,7 +169,11 @@ class Connection {
166169

167170
uint8_t m_FeatureFlagsRequestAttempts = 0;
168171
unsigned long m_FeatureFlagsRequestTimestamp = millis();
169-
ServerFeatures m_ServerFeatures{};
172+
FeatureFlags<EServerFeatureFlags> m_ServerFeatures;
173+
std::unordered_map<EFirmwareFeatureFlags, bool, EnumClassHash>
174+
m_EnabledFirmwareFeatures
175+
= {{EFirmwareFeatureFlags::B64_WIFI_SCANNING, true}};
176+
FeatureFlags<EFirmwareFeatureFlags> m_FirmwareFeatures;
170177

171178
bool m_IsBundle = false;
172179
bool m_BundleFinished = false;

src/network/featureflags.h

Lines changed: 82 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,99 @@
1+
12
/*
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.
2223
*/
2324

2425
#ifndef SLIMEVR_FEATURE_FLAGS_H_
2526
#define SLIMEVR_FEATURE_FLAGS_H_
2627

27-
#include <cstring>
2828
#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+
}
7039
};
7140

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,
8244

83-
// Flags to send
84-
static constexpr const std::initializer_list<EFirmwareFeatureFlags> flagsEnabled = {
85-
// EXAMPLE_FEATURE,
86-
B64_WIFI_SCANNING,
45+
BITS_TOTAL,
46+
};
8747

88-
// Add enabled flags here
89-
};
48+
enum class EFirmwareFeatureFlags : uint32_t {
49+
// EXAMPLE_FEATURE,
50+
B64_WIFI_SCANNING = 1,
9051

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+
};
9454

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; }
9893

99-
return packed;
100-
}();
94+
private:
95+
bool m_Available = false;
96+
std::unordered_map<Flags, bool, EnumClassHash> m_Flags{};
10197
};
10298

10399
#endif

0 commit comments

Comments
 (0)