Skip to content
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
206fc4a
Use different RGB patterns for Active Clearing vs Awaiting Release EStop
nullstalgia Jan 9, 2026
9e4cf09
Use Yellow for Active Clearing.
nullstalgia Jan 9, 2026
a9b66ef
Bruteforcing Arduino 3.0 support
nullstalgia Jan 23, 2026
08897d4
fix captiveportal include path and config struct construction
hhvrc Jan 23, 2026
4096bfc
Rename OpenShock::Serial -> OpenShock::SerialCmds
nullstalgia Jan 24, 2026
67c4e31
Use Arduino 3.0 WiFi AP class
nullstalgia Jan 24, 2026
55000a5
Captive portal: fix use-after-free and DNS Server not being invoked
nullstalgia Jan 24, 2026
50c8320
Captive portal: Pause scan on user websocket connect to reduce d/c risk
nullstalgia Jan 24, 2026
71c3128
Fix template deduction errs
nullstalgia Jan 24, 2026
5b2bdf6
Temporarily comment out IPv6 logic (as type now has combined v4 and v6)
nullstalgia Jan 24, 2026
4f83d81
Temporarily comment out error pragma
nullstalgia Jan 24, 2026
d87d300
Captive portal: Samsung devices beginning to respond correctly
nullstalgia Jan 24, 2026
cb06a40
Captive portal: non-empty redirect
nullstalgia Jan 24, 2026
5490510
Add xtensa-esp-elf-gdb and openocd-esp32 to platform_packages
nullstalgia Jan 24, 2026
b731c74
Improve GPIO LED EStop interaction blink patterns
nullstalgia Jan 25, 2026
8edc45e
Merge branch 'feat/estop-activeclearing-awaitingrelease-patterns' int…
nullstalgia Jan 25, 2026
b82600f
Merge branch 'develop' into feat/arduino-3.0
hhvrc Feb 16, 2026
51596b2
Fix more stuff
hhvrc Feb 16, 2026
b84dccc
Merge branch 'develop' into feat/arduino-3.0
hhvrc Feb 16, 2026
72b491a
More fixes
hhvrc Feb 16, 2026
3d3460d
Merge branch 'develop' into feat/arduino-3.0
hhvrc Feb 16, 2026
babac53
Merge branch 'develop' into feat/arduino-3.0
hhvrc Mar 27, 2026
c2c4a87
wip: merge develop and fix span migration for Arduino 3.0
hhvrc Mar 27, 2026
bac7630
Merge branch 'develop' into feat/arduino-3.0
hhvrc Apr 20, 2026
350bd74
Bump platform version
hhvrc Apr 20, 2026
1fe26ec
Merge remote-tracking branch 'origin/develop' into feat/arduino-3.0
hhvrc Apr 22, 2026
83e7a8c
Start modularizing firmware
hhvrc Apr 23, 2026
8cdbed1
Move more stuff
hhvrc Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 27 additions & 21 deletions include/Checksum.h
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
#pragma once

#include <bit>
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <memory>

#if __cplusplus >= 202'002L
#error Take into use C++20 std::integral instead of this macro logic
#endif

#define SUM8_INT_FN(Type) \
constexpr uint8_t Sum8(Type data) \
{ \
uint8_t result = 0; \
for (int i = 0; i < sizeof(Type); ++i) { \
result += static_cast<uint8_t>((data >> (i * 8)) & 0xFF); \
} \
return result; \
}

namespace OpenShock::Checksum {

// ------------------------------------------------------------
// Raw byte span checksum
// ------------------------------------------------------------
constexpr uint8_t Sum8(const uint8_t* data, std::size_t size)
{
uint8_t checksum = 0;
Expand All @@ -26,21 +19,34 @@ namespace OpenShock::Checksum {
}
return checksum;
}

// ------------------------------------------------------------
// Generic integral overload (C++20 concepts)
// ------------------------------------------------------------
template<std::integral T>
constexpr uint8_t Sum8(T value)
{
uint8_t result = 0;

for (std::size_t i = 0; i < sizeof(T); ++i) {
result += static_cast<uint8_t>((value >> (i * 8)) & 0xFF);
}

return result;
}

// ------------------------------------------------------------
// Generic trivially copyable object overload
// ------------------------------------------------------------
template<typename T>
requires(!std::integral<T> && std::is_trivially_copyable_v<T>)
constexpr uint8_t Sum8(const T& data)
{
static_assert(std::is_trivially_copyable_v<T>, "Sum8 only supports trivially copyable types");

return Sum8(reinterpret_cast<const uint8_t*>(std::addressof(data)), sizeof(T));
}

SUM8_INT_FN(int16_t)
SUM8_INT_FN(uint16_t)
SUM8_INT_FN(int32_t)
SUM8_INT_FN(uint32_t)
SUM8_INT_FN(int64_t)
SUM8_INT_FN(uint64_t)

/**
* Make sure the uint8 only has its high bits (0x0F) set before using this function
*/
Expand Down
14 changes: 7 additions & 7 deletions include/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,19 @@
#if __cplusplus >= 202302L
#warning "C++23 compiler detected"
#elif __cplusplus >= 202002L
#warning "C++20 compiler detected"
// C++20 :3
#elif __cplusplus >= 201703L
// C++17 :3
#error "C++17 compiler detected, OpenShock requires a C++20 compliant compiler"
#elif __cplusplus >= 201402L
#error "C++14 compiler detected, OpenShock requires a C++17 compliant compiler"
#error "C++14 compiler detected, OpenShock requires a C++20 compliant compiler"
#elif __cplusplus >= 201103L
#error "C++11 compiler detected, OpenShock requires a C++17 compliant compiler"
#error "C++11 compiler detected, OpenShock requires a C++20 compliant compiler"
#elif __cplusplus >= 199711L
#error "C++98 compiler detected, OpenShock requires a C++17 compliant compiler"
#error "C++98 compiler detected, OpenShock requires a C++20 compliant compiler"
#elif __cplusplus == 1
#error "Pre-C++98 compiler detected, OpenShock requires a C++17 compliant compiler"
#error "Pre-C++98 compiler detected, OpenShock requires a C++20 compliant compiler"
#else
#error "Unknown C++ standard detected, OpenShock requires a C++17 compliant compiler"
#error "Unknown C++ standard detected, OpenShock requires a C++20 compliant compiler"
#endif

namespace OpenShock::Constants {
Expand Down
4 changes: 2 additions & 2 deletions include/GatewayClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

#include "Common.h"
#include "GatewayClientState.h"
#include "span.h"

#include <WebSocketsClient.h>

#include <cstdint>
#include <span>
#include <string>
#include <string_view>
#include <unordered_map>
Expand All @@ -26,7 +26,7 @@ namespace OpenShock {
void disconnect();

bool sendMessageTXT(std::string_view data);
bool sendMessageBIN(tcb::span<const uint8_t> data);
bool sendMessageBIN(std::span<const uint8_t> data);

bool loop();

Expand Down
4 changes: 2 additions & 2 deletions include/GatewayConnectionManager.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#pragma once

#include "AccountLinkResultCode.h"
#include "span.h"

#include <cstdint>
#include <functional>
#include <span>
#include <string_view>

namespace OpenShock::GatewayConnectionManager {
Expand All @@ -17,7 +17,7 @@ namespace OpenShock::GatewayConnectionManager {
void UnLink();

bool SendMessageTXT(std::string_view data);
bool SendMessageBIN(tcb::span<const uint8_t> data);
bool SendMessageBIN(std::span<const uint8_t> data);

void Update();
} // namespace OpenShock::GatewayConnectionManager
18 changes: 9 additions & 9 deletions include/Hashing.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ namespace OpenShock {
MD5() { mbedtls_md5_init(&ctx); }
~MD5() { mbedtls_md5_free(&ctx); }

inline bool begin() { return mbedtls_md5_starts_ret(&ctx) == 0; }
inline bool update(const uint8_t* data, std::size_t dataLen) { return mbedtls_md5_update_ret(&ctx, data, dataLen) == 0; }
inline bool begin() { return mbedtls_md5_starts(&ctx) == 0; }
inline bool update(const uint8_t* data, std::size_t dataLen) { return mbedtls_md5_update(&ctx, data, dataLen) == 0; }
inline bool update(std::string_view data) { return update(reinterpret_cast<const uint8_t*>(data.data()), data.length()); }
inline bool finish(std::array<uint8_t, 16>& hash) { return mbedtls_md5_finish_ret(&ctx, hash.data()) == 0; }
inline bool finish(std::array<uint8_t, 16>& hash) { return mbedtls_md5_finish(&ctx, hash.data()) == 0; }

private:
mbedtls_md5_context ctx;
Expand All @@ -35,10 +35,10 @@ namespace OpenShock {
SHA1() { mbedtls_sha1_init(&ctx); }
~SHA1() { mbedtls_sha1_free(&ctx); }

inline bool begin() { return mbedtls_sha1_starts_ret(&ctx) == 0; }
inline bool update(const uint8_t* data, std::size_t dataLen) { return mbedtls_sha1_update_ret(&ctx, data, dataLen) == 0; }
inline bool begin() { return mbedtls_sha1_starts(&ctx) == 0; }
inline bool update(const uint8_t* data, std::size_t dataLen) { return mbedtls_sha1_update(&ctx, data, dataLen) == 0; }
inline bool update(std::string_view data) { return update(reinterpret_cast<const uint8_t*>(data.data()), data.length()); }
inline bool finish(std::array<uint8_t, 20>& hash) { return mbedtls_sha1_finish_ret(&ctx, hash.data()) == 0; }
inline bool finish(std::array<uint8_t, 20>& hash) { return mbedtls_sha1_finish(&ctx, hash.data()) == 0; }

private:
mbedtls_sha1_context ctx;
Expand All @@ -51,10 +51,10 @@ namespace OpenShock {
SHA256() { mbedtls_sha256_init(&ctx); }
~SHA256() { mbedtls_sha256_free(&ctx); }

inline bool begin() { return mbedtls_sha256_starts_ret(&ctx, 0) == 0; }
inline bool update(const uint8_t* data, std::size_t dataLen) { return mbedtls_sha256_update_ret(&ctx, data, dataLen) == 0; }
inline bool begin() { return mbedtls_sha256_starts(&ctx, 0) == 0; }
inline bool update(const uint8_t* data, std::size_t dataLen) { return mbedtls_sha256_update(&ctx, data, dataLen) == 0; }
inline bool update(std::string_view data) { return update(reinterpret_cast<const uint8_t*>(data.data()), data.length()); }
inline bool finish(std::array<uint8_t, 32>& hash) { return mbedtls_sha256_finish_ret(&ctx, hash.data()) == 0; }
inline bool finish(std::array<uint8_t, 32>& hash) { return mbedtls_sha256_finish(&ctx, hash.data()) == 0; }

private:
mbedtls_sha256_context ctx;
Expand Down
10 changes: 9 additions & 1 deletion include/TinyVec.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <cstring>
#include <limits>
#include <new>
#include <span.h>
#include <span>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -68,6 +68,14 @@ class TinyVec {
T& operator[](SizeType i) noexcept { return _data[i]; }
const T& operator[](SizeType i) const noexcept { return _data[i]; }

T* begin() noexcept { return _data; }
const T* begin() const noexcept { return _data; }
T* end() noexcept { return _data + _len; }
const T* end() const noexcept { return _data + _len; }

operator std::span<T>() noexcept { return {_data, static_cast<std::size_t>(_len)}; }
operator std::span<const T>() const noexcept { return {_data, static_cast<std::size_t>(_len)}; }

void reserve(SizeType new_cap)
{
if (new_cap <= _cap) return;
Expand Down
4 changes: 2 additions & 2 deletions include/WebSocketDeFragger.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once

#include "Common.h"
#include "span.h"
#include "TinyVec.h"
#include "WebSocketMessageType.h"

Expand All @@ -10,14 +9,15 @@
#include <cstdint>
#include <functional>
#include <map>
#include <span>

namespace OpenShock {
class WebSocketDeFragger {
DISABLE_COPY(WebSocketDeFragger);
DISABLE_MOVE(WebSocketDeFragger);

public:
typedef std::function<void(uint8_t socketId, WebSocketMessageType type, tcb::span<const uint8_t> data)> EventCallback;
typedef std::function<void(uint8_t socketId, WebSocketMessageType type, std::span<const uint8_t> data)> EventCallback;

WebSocketDeFragger(EventCallback callback);
~WebSocketDeFragger();
Expand Down
8 changes: 4 additions & 4 deletions include/captiveportal/CaptivePortalInstance.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "Common.h"
#include "span.h"
#include <span>
#include "WebSocketDeFragger.h"

#include <DNSServer.h>
Expand All @@ -25,16 +25,16 @@ namespace OpenShock::CaptivePortal {
~CaptivePortalInstance();

bool sendMessageTXT(uint8_t socketId, std::string_view data) { return m_socketServer.sendTXT(socketId, data.data(), data.length()); }
bool sendMessageBIN(uint8_t socketId, tcb::span<const uint8_t> data) { return m_socketServer.sendBIN(socketId, data.data(), data.size()); }
bool sendMessageBIN(uint8_t socketId, std::span<const uint8_t> data) { return m_socketServer.sendBIN(socketId, data.data(), data.size()); }
bool broadcastMessageTXT(std::string_view data) { return m_socketServer.broadcastTXT(data.data(), data.length()); }
bool broadcastMessageBIN(tcb::span<const uint8_t> data) { return m_socketServer.broadcastBIN(data.data(), data.size()); }
bool broadcastMessageBIN(std::span<const uint8_t> data) { return m_socketServer.broadcastBIN(data.data(), data.size()); }
bool hasClients() { return m_socketServer.connectedClients() > 0; }

private:
void task();
void handleWebSocketClientConnected(uint8_t socketId);
void handleWebSocketClientDisconnected(uint8_t socketId);
void handleWebSocketEvent(uint8_t socketId, WebSocketMessageType type, tcb::span<const uint8_t> payload);
void handleWebSocketEvent(uint8_t socketId, WebSocketMessageType type, std::span<const uint8_t> payload);

AsyncWebServer m_webServer;
WebSocketsServer m_socketServer;
Expand Down
7 changes: 3 additions & 4 deletions include/captiveportal/Manager.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#pragma once

#include <cstdint>
#include <span>
#include <string_view>

#include "span.h"

namespace OpenShock::CaptivePortal {
[[nodiscard]] bool Init();

Expand All @@ -19,8 +18,8 @@ namespace OpenShock::CaptivePortal {
bool IsRunning();

bool SendMessageTXT(uint8_t socketId, std::string_view data);
bool SendMessageBIN(uint8_t socketId, tcb::span<const uint8_t> data);
bool SendMessageBIN(uint8_t socketId, std::span<const uint8_t> data);

bool BroadcastMessageTXT(std::string_view data);
bool BroadcastMessageBIN(tcb::span<const uint8_t> data);
bool BroadcastMessageBIN(std::span<const uint8_t> data);
} // namespace OpenShock::CaptivePortal
17 changes: 12 additions & 5 deletions include/http/HTTPRequestManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

#include <functional>
#include <map>
#include <span>
#include <string>
#include <string_view>

#include "span.h"

namespace OpenShock::HTTP {
enum class RequestResult : uint8_t {
InternalError, // Internal error
Expand All @@ -29,6 +29,13 @@ namespace OpenShock::HTTP {
int code;
T data;

Response(RequestResult r, int c, T d)
: result(r)
, code(c)
, data(std::move(d))
{
}

inline const char* ResultToString() const
{
switch (result) {
Expand Down Expand Up @@ -61,11 +68,11 @@ namespace OpenShock::HTTP {
using GotContentLengthCallback = std::function<bool(int contentLength)>;
using DownloadCallback = std::function<bool(std::size_t offset, const uint8_t* data, std::size_t len)>;

Response<std::size_t> Download(std::string_view url, const std::map<String, String>& headers, GotContentLengthCallback contentLengthCallback, DownloadCallback downloadCallback, tcb::span<const uint16_t> acceptedCodes, uint32_t timeoutMs = 10'000);
Response<std::string> GetString(std::string_view url, const std::map<String, String>& headers, tcb::span<const uint16_t> acceptedCodes, uint32_t timeoutMs = 10'000);
Response<std::size_t> Download(std::string_view url, const std::map<String, String>& headers, GotContentLengthCallback contentLengthCallback, DownloadCallback downloadCallback, std::span<const uint16_t> acceptedCodes, uint32_t timeoutMs = 10'000);
Response<std::string> GetString(std::string_view url, const std::map<String, String>& headers, std::span<const uint16_t> acceptedCodes, uint32_t timeoutMs = 10'000);

template<typename T>
Response<T> GetJSON(std::string_view url, const std::map<String, String>& headers, JsonParser<T> jsonParser, tcb::span<const uint16_t> acceptedCodes, uint32_t timeoutMs = 10'000)
Response<T> GetJSON(std::string_view url, const std::map<String, String>& headers, JsonParser<T> jsonParser, std::span<const uint16_t> acceptedCodes, uint32_t timeoutMs = 10'000)
{
auto response = GetString(url, headers, acceptedCodes, timeoutMs);
if (response.result != RequestResult::Success) {
Expand Down
7 changes: 3 additions & 4 deletions include/message_handlers/WebSocket.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#pragma once

#include "span.h"

#include <cstdint>
#include <span>

namespace OpenShock::MessageHandlers::WebSocket {
void HandleGatewayBinary(tcb::span<const uint8_t> data);
void HandleLocalBinary(uint8_t socketId, tcb::span<const uint8_t> data);
void HandleGatewayBinary(std::span<const uint8_t> data);
void HandleLocalBinary(uint8_t socketId, std::span<const uint8_t> data);
}
3 changes: 1 addition & 2 deletions include/radio/RFTransmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace OpenShock {

inline gpio_num_t GetTxPin() const { return m_txPin; }

inline bool ok() const { return m_rmtHandle != nullptr && m_queueHandle != nullptr && m_taskHandle != nullptr; }
inline bool ok() const { return m_txPin != GPIO_NUM_NC && m_queueHandle != nullptr && m_taskHandle != nullptr; }

bool SendCommand(ShockerModelType model, uint16_t shockerId, ShockerCommandType type, uint8_t intensity, uint16_t durationMs, bool overwriteExisting = true);
void ClearPendingCommands();
Expand All @@ -35,7 +35,6 @@ namespace OpenShock {
struct Command;

gpio_num_t m_txPin;
rmt_obj_t* m_rmtHandle;
QueueHandle_t m_queueHandle;
TaskHandle_t m_taskHandle;
};
Expand Down
4 changes: 2 additions & 2 deletions include/serial/command_handlers/CommandEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <string_view>
#include <vector>

namespace OpenShock::Serial {
namespace OpenShock::SerialCmds {
typedef void (*CommandHandler)(std::string_view arg, bool isAutomated);

class CommandArgument {
Expand Down Expand Up @@ -53,4 +53,4 @@ namespace OpenShock::Serial {
std::string_view m_name;
std::vector<CommandEntry> m_commands;
};
} // namespace OpenShock::Serial
} // namespace OpenShock::SerialCmds
5 changes: 2 additions & 3 deletions include/serialization/CallbackFn.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

#include <cstdint>
#include <functional>

#include "span.h"
#include <span>

namespace OpenShock::Serialization::Common {
typedef std::function<bool(tcb::span<const uint8_t> data)> SerializationCallbackFn;
typedef std::function<bool(std::span<const uint8_t> data)> SerializationCallbackFn;
}
Loading
Loading