From 24000c64a4a86caf94e8c2df605a29b541f250b6 Mon Sep 17 00:00:00 2001 From: OmniaX-Dev Date: Sat, 16 May 2026 12:22:16 +0200 Subject: [PATCH] First sketch of new ostd::Serial class --- other/build.nr | 2 +- src/tools/Serial.cpp | 463 +++++++++++++++++++++++++++++++++++++++++++ src/tools/Serial.hpp | 109 ++++++++-- 3 files changed, 551 insertions(+), 23 deletions(-) diff --git a/other/build.nr b/other/build.nr index 7f8f011..45a4fb7 100644 --- a/other/build.nr +++ b/other/build.nr @@ -1 +1 @@ -7 +8 diff --git a/src/tools/Serial.cpp b/src/tools/Serial.cpp index 14142b8..c666d39 100644 --- a/src/tools/Serial.cpp +++ b/src/tools/Serial.cpp @@ -17,3 +17,466 @@ You should have received a copy of the GNU General Public License along with OmniaFramework. If not, see . */ + +#include "Serial.hpp" + +namespace ostd +{ + bool Serial::isValidAddress(u64 addr, u32 size) + { + return ((addr + size - 1) < s_openStream.size()); + } + + Serial::ReadResult Serial::read::int8(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + if (!isValidAddress(addr, tTypeSize::INT8)) return { 0, true }; + return { s_openStream[addr], false }; + } + + Serial::ReadResult Serial::read::uint8(u64 addr) + { + auto res = int8(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::int16(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + if (!isValidAddress(addr, tTypeSize::INT16)) return { 0, true }; + i16 val = 0; + if (isLittleEndian()) + { + val = ((s_openStream[addr + 0] ) & 0x00FFU) + | ((s_openStream[addr + 1] << 8) & 0xFF00U); + } + else if (isBigEndian()) + { + val = ((s_openStream[addr + 0] << 8) & 0xFF00U) + | ( s_openStream[addr + 1] & 0x00FFU); + } + else return { 0, true }; + return { val, false }; + } + + Serial::ReadResult Serial::read::uint16(u64 addr) + { + auto res = int16(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::int32(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + if (!isValidAddress(addr, tTypeSize::INT32)) return { 0, true }; + i32 val = 0; + if (isLittleEndian()) + { + val = ((s_openStream[addr + 0] ) & 0x000000FF) + | ((s_openStream[addr + 1] << 8) & 0x0000FF00) + | ((s_openStream[addr + 2] << 16) & 0x00FF0000) + | ((s_openStream[addr + 3] << 24) & 0xFF000000); + } + else if (isBigEndian()) + { + val = ((s_openStream[addr + 0] << 24) & 0xFF000000U) + | ((s_openStream[addr + 1] << 16) & 0x00FF0000U) + | ((s_openStream[addr + 2] << 8) & 0x0000FF00U) + | ( s_openStream[addr + 3] & 0x000000FFU); + } + else return { 0, true }; + return { val, false }; + } + + Serial::ReadResult Serial::read::uint32(u64 addr) + { + auto res = int32(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::int64(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + if (!isValidAddress(addr, tTypeSize::INT64)) return { 0, true }; + i64 val = 0; + if (isLittleEndian()) + { + val = ( s_openStream[addr + 7] & 0x00000000000000FFU) + | (( s_openStream[addr + 6] << 8) & 0x000000000000FF00U) + | (( s_openStream[addr + 5] << 16) & 0x0000000000FF0000U) + | (( s_openStream[addr + 4] << 24) & 0x00000000FF000000U) + | (((i64)s_openStream[addr + 3] << 32) & 0x000000FF00000000U) + | (((i64)s_openStream[addr + 2] << 40) & 0x0000FF0000000000U) + | (((i64)s_openStream[addr + 1] << 48) & 0x00FF000000000000U) + | (((i64)s_openStream[addr + 0] << 56) & 0xFF00000000000000U); + } + else if (isBigEndian()) + { + val = (((i64)s_openStream[addr + 0] << 56) & 0xFF00000000000000U) + | (((i64)s_openStream[addr + 1] << 48) & 0x00FF000000000000U) + | (((i64)s_openStream[addr + 2] << 40) & 0x0000FF0000000000U) + | (((i64)s_openStream[addr + 3] << 32) & 0x000000FF00000000U) + | (( s_openStream[addr + 4] << 24) & 0x00000000FF000000U) + | (( s_openStream[addr + 5] << 16) & 0x0000000000FF0000U) + | (( s_openStream[addr + 6] << 8) & 0x000000000000FF00U) + | ( s_openStream[addr + 7] & 0x00000000000000FFU); + } + else return { 0, true }; + return { val, false }; + } + + Serial::ReadResult Serial::read::uint64(u64 addr) + { + auto res = int64(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::float32(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + if (!isValidAddress(addr, tTypeSize::FLOAT32)) return { 0, true }; + __float_parser fp; + if (isLittleEndian()) + { + fp.data[3] = s_openStream[addr + 0]; + fp.data[2] = s_openStream[addr + 1]; + fp.data[1] = s_openStream[addr + 2]; + fp.data[0] = s_openStream[addr + 3]; + } + else if (isBigEndian()) + { + fp.data[0] = s_openStream[addr + 0]; + fp.data[1] = s_openStream[addr + 1]; + fp.data[2] = s_openStream[addr + 2]; + fp.data[3] = s_openStream[addr + 3]; + } + else return { 0, true }; + return { fp.val, false }; + } + + Serial::ReadResult Serial::read::float64(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + if (!isValidAddress(addr, tTypeSize::FLOAT64)) return { 0, true }; + __double_parser dp; + if (isLittleEndian()) + { + dp.data[7] = s_openStream[addr++]; + dp.data[6] = s_openStream[addr++]; + dp.data[5] = s_openStream[addr++]; + dp.data[4] = s_openStream[addr++]; + dp.data[3] = s_openStream[addr++]; + dp.data[2] = s_openStream[addr++]; + dp.data[1] = s_openStream[addr++]; + dp.data[0] = s_openStream[addr ]; + } + else if (isBigEndian()) + { + dp.data[0] = s_openStream[addr++]; + dp.data[1] = s_openStream[addr++]; + dp.data[2] = s_openStream[addr++]; + dp.data[3] = s_openStream[addr++]; + dp.data[4] = s_openStream[addr++]; + dp.data[5] = s_openStream[addr++]; + dp.data[6] = s_openStream[addr++]; + dp.data[7] = s_openStream[addr ]; + } + else return { 0, true }; + return { dp.val, false }; + } + + bool Serial::read::stream(u64 addr, Stream& outStream, bool sizeStored, u32 size_if_not_stored) + { + if (!isStreamAttached()) return false; + if (!sizeStored && size_if_not_stored < 1) return false; + u32 size = size_if_not_stored; + if (sizeStored) + { + auto tmp = uint32(addr); + if (tmp.error) return false; + addr += tTypeSize::UINT32; + size = tmp.value; + } + Endianness endianness; + { + auto tmp = uint8(addr); + if (tmp.error) return false; + addr += tTypeSize::UINT8; + if (tmp.value == cast(Endianness::LittleEndian)) + endianness = Endianness::LittleEndian; + else if (tmp.value == cast(Endianness::BigEndian)) + endianness = Endianness::BigEndian; + else return false; + } + if (!isValidAddress(addr, size)) return false; + Serial::Stream data = { size, endianness }; + StreamEdit edit = data.data(); + for (u64 i = addr; i < (addr + size); i++) + { + edit[i - addr] = s_openStream[i]; + } + outStream = std::move(data); + return true; + } + + bool Serial::read::string(u64 addr, String& outString, bool sizeStored, u32 size_if_not_stored, bool null_terminated) + { + if (!isStreamAttached()) return false; + if (!null_terminated || sizeStored) // I want null_terminated to have the lowest priority + { + if (!sizeStored && size_if_not_stored < 1) return false; + u32 size = size_if_not_stored; + if (sizeStored) + { + auto tmp = uint32(addr); + if (tmp.error) return false; + addr += tTypeSize::UINT32; + size = tmp.value; + } + if (!isValidAddress(addr, size)) return false; + for (u64 i = addr; i < (addr + size); i++) + { + outString += cast(s_openStream[i]); + } + return true; + } + else + { + String out = ""; + auto tmp = int8(addr); + if (tmp.error) return false; + addr += tTypeSize::INT8; + while (tmp.value != '\0') + { + out += cast(tmp.value); + tmp = int8(addr); + if (tmp.error) return false; + addr += tTypeSize::INT8; + } + outString = out; + return true; + } + } + + bool Serial::read::object(u64 addr, __i_serializable& outObject) + { + Serial::Stream objData(0); + if (!stream(addr, objData, true, 0)) + return false; + return outObject.deserialize(objData); + } + + + + bool Serial::write::int8(u64 addr, i8 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::INT8)) return false; + s_openStream[addr] = value; + return true; + } + + bool Serial::write::uint8(u64 addr, u8 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::UINT8)) return false; + return int8(addr, cast(value)); + } + + bool Serial::write::int16(u64 addr, i16 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::INT16)) return false; + if (isLittleEndian()) + { + s_openStream[addr + 0] = value & 0xFF; + s_openStream[addr + 1] = (value >> 8) & 0xFF; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = (value >> 8) & 0xFF; + s_openStream[addr + 1] = value & 0xFF; + } + else return false; + return true; + } + + bool Serial::write::uint16(u64 addr, u16 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::UINT16)) return false; + return int16(addr, cast(value)); + } + + bool Serial::write::int32(u64 addr, i32 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::INT32)) return false; + if (isLittleEndian()) + { + s_openStream[addr + 0] = value & 0xFF; + s_openStream[addr + 1] = (value >> 8) & 0xFF; + s_openStream[addr + 2] = (value >> 16) & 0xFF; + s_openStream[addr + 3] = (value >> 24) & 0xFF; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = (value >> 24) & 0xFF; + s_openStream[addr + 1] = (value >> 16) & 0xFF; + s_openStream[addr + 2] = (value >> 8) & 0xFF; + s_openStream[addr + 3] = value & 0xFF; + } + else return false; + return true; + } + + bool Serial::write::uint32(u64 addr, u32 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::UINT32)) return false; + return int32(addr, cast(value)); + } + + bool Serial::write::int64(u64 addr, i64 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::INT64)) return false; + if (isLittleEndian()) + { + s_openStream[addr + 0] = value & 0xFF; + s_openStream[addr + 1] = (value >> 8) & 0xFF; + s_openStream[addr + 2] = (value >> 16) & 0xFF; + s_openStream[addr + 3] = (value >> 24) & 0xFF; + s_openStream[addr + 4] = (value >> 32) & 0xFF; + s_openStream[addr + 5] = (value >> 40) & 0xFF; + s_openStream[addr + 6] = (value >> 48) & 0xFF; + s_openStream[addr + 7] = (value >> 56) & 0xFF; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = (value >> 56) & 0xFF; + s_openStream[addr + 1] = (value >> 48) & 0xFF; + s_openStream[addr + 2] = (value >> 40) & 0xFF; + s_openStream[addr + 3] = (value >> 32) & 0xFF; + s_openStream[addr + 4] = (value >> 24) & 0xFF; + s_openStream[addr + 5] = (value >> 16) & 0xFF; + s_openStream[addr + 6] = (value >> 8) & 0xFF; + s_openStream[addr + 7] = value & 0xFF; + } + else return false; + return true; + } + + bool Serial::write::uint64(u64 addr, u64 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::UINT64)) return false; + return int64(addr, cast(value)); + } + + bool Serial::write::float32(u64 addr, f32 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::FLOAT32)) return false; + __float_parser fp; + fp.val = value; + if (isLittleEndian()) + { + s_openStream[addr + 0] = fp.data[3]; + s_openStream[addr + 1] = fp.data[2]; + s_openStream[addr + 2] = fp.data[1]; + s_openStream[addr + 3] = fp.data[0]; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = fp.data[0]; + s_openStream[addr + 1] = fp.data[1]; + s_openStream[addr + 2] = fp.data[2]; + s_openStream[addr + 3] = fp.data[3]; + } + else return false; + return true; + } + + bool Serial::write::float64(u64 addr, f64 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::FLOAT64)) return false; + __double_parser dp; + dp.val = value; + if (isLittleEndian()) + { + s_openStream[addr++] = dp.data[7]; + s_openStream[addr++] = dp.data[6]; + s_openStream[addr++] = dp.data[5]; + s_openStream[addr++] = dp.data[4]; + s_openStream[addr++] = dp.data[3]; + s_openStream[addr++] = dp.data[2]; + s_openStream[addr++] = dp.data[1]; + s_openStream[addr ] = dp.data[0]; + } + else if (isBigEndian()) + { + s_openStream[addr++] = dp.data[0]; + s_openStream[addr++] = dp.data[1]; + s_openStream[addr++] = dp.data[2]; + s_openStream[addr++] = dp.data[3]; + s_openStream[addr++] = dp.data[4]; + s_openStream[addr++] = dp.data[5]; + s_openStream[addr++] = dp.data[6]; + s_openStream[addr ] = dp.data[7]; + } + else return false; + return true; + } + + bool Serial::write::stream(u64 addr, const Stream& value, bool storeSize) + { + if (!isStreamAttached()) return false; + u32 size = value.size(); + if (size < 1) return false; + if (storeSize) + { + if (!uint32(addr, size)) return false; + addr += tTypeSize::UINT32; + } + if (!isValidAddress(addr, size)) return false; + StreamView view = value.data(); + for (u64 i = addr; i < addr + size; i++) + s_openStream[i] = view[i - addr]; + return true; + } + + bool Serial::write::string(u64 addr, const String& value, bool storeSize, bool null_terminated) + { + if (!isStreamAttached()) return false; + u32 size = value.len(); + if (size < 1) return false; + if (storeSize) + { + null_terminated = false; + if (!uint32(addr, value.len())) return false; + addr += tTypeSize::UINT32; + } + size += (null_terminated ? 1 : 0); + if (!isValidAddress(addr, size)) + return false; + for (u64 i = addr; i < addr + size; i++) + { + i8 c = cast(value[i - addr]); + if (null_terminated && i == addr + size - 1) + c = '\0'; + s_openStream[i] = c; + } + return true; + } + + bool Serial::write::object(u64 addr, const __i_serializable& value) + { + if (!isStreamAttached()) return false; + const Serial::Stream data = value.serialize(); + if (data.size() < 1) return false; + if (!isValidAddress(addr, data.size() + tTypeSize::UINT32)) return false; + return stream(addr, data, true); + } +} diff --git a/src/tools/Serial.hpp b/src/tools/Serial.hpp index bfc1e91..a8364e4 100644 --- a/src/tools/Serial.hpp +++ b/src/tools/Serial.hpp @@ -20,19 +20,23 @@ #pragma once -#include +#include #include namespace ostd { + class __i_serializable; class Serial { + public: template struct ReadResult { T value; bool error { false }; }; public: enum class Endianness : u8 { LittleEndian = 0, BigEndian }; public: using StreamEdit = std::span; public: using StreamView = std::span; public: class Stream { public: + Stream(const Stream&) = delete; + Stream& operator=(const Stream&) = delete; inline Stream(u64 size, Endianness endianness = Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) { if (size < 1) return; if constexpr (sizeof(size_t) < sizeof(uint64_t)) @@ -49,14 +53,31 @@ namespace ostd m_data[i] = initialValue; } } - inline ~Stream(void) { - if (isValid()) - { + inline Stream(Stream&& other) noexcept : m_data(other.m_data), m_size(other.m_size) { + other.m_data = nullptr; + other.m_size = 0; + m_endianness = other.m_endianness; + } + inline Stream& operator=(Stream&& other) noexcept { + if (this != &other) { delete[] m_data; - m_data = nullptr; + m_data = other.m_data; + m_size = other.m_size; + m_endianness = other.m_endianness; + other.m_data = nullptr; + other.m_size = 0; } + return *this; + } + inline ~Stream(void) { + delete[] m_data; + m_data = nullptr; } inline bool isValid(void) const { return m_size > 0 && m_data != nullptr; } + inline u64 size(void) const { return isValid() ? m_size : 0; } + inline bool isLittleEndian(void) const { return m_endianness == Endianness::LittleEndian; } + inline bool isBigEndian(void) const { return m_endianness == Endianness::BigEndian; } + inline Endianness getEndianness(void) const { return m_endianness; } inline StreamEdit data() { if (isValid()) return { m_data, cast(m_size) }; @@ -75,40 +96,84 @@ namespace ostd }; public: - inline static void attachStream(Stream& stream) { s_openStream = stream.data(); } + inline static void attachStream(Stream& stream) { s_openStream = stream.data(); s_endianness = stream.getEndianness(); } inline static void detachStrean(void) { s_openStream = {}; } inline static bool isStreamAttached(void) { return !s_openStream.empty(); } + inline static bool isLittleEndian(void) { return s_endianness == Endianness::LittleEndian; } + inline static bool isBigEndian(void) { return s_endianness == Endianness::BigEndian; } + static bool isValidAddress(u64 addr, u32 size = 1); public: struct read { - std::pair int8(u64 addr); - inline i8 int8d(u64 addr, bool* outError = nullptr) { auto val = int8(addr); if (outError) *outError = val.second; return val.first; } - std::pair uint8(u64 addr); - inline u8 uint8d(u64 addr, bool* outError = nullptr) { auto val = uint8(addr); if (outError) *outError = val.second; return val.first; } + ReadResult int8(u64 addr); + inline i8 int8d(u64 addr, bool* outError = nullptr) { auto val = int8(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint8(u64 addr); + inline u8 uint8d(u64 addr, bool* outError = nullptr) { auto val = uint8(addr); if (outError) *outError = val.error; return val.value; } - std::pair int16(u64 addr); - inline i16 int16d(u64 addr, bool* outError = nullptr) { auto val = int16(addr); if (outError) *outError = val.second; return val.first; } - std::pair uint16(u64 addr); - inline u16 uint16d(u64 addr, bool* outError = nullptr) { auto val = uint16(addr); if (outError) *outError = val.second; return val.first; } + ReadResult int16(u64 addr); + inline i16 int16d(u64 addr, bool* outError = nullptr) { auto val = int16(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint16(u64 addr); + inline u16 uint16d(u64 addr, bool* outError = nullptr) { auto val = uint16(addr); if (outError) *outError = val.error; return val.value; } - std::pair int32(u64 addr); - inline i32 int32d(u64 addr, bool* outError = nullptr) { auto val = int32(addr); if (outError) *outError = val.second; return val.first; } - std::pair uint32(u64 addr); - inline u32 uint32d(u64 addr, bool* outError = nullptr) { auto val = uint32(addr); if (outError) *outError = val.second; return val.first; } + ReadResult int32(u64 addr); + inline i32 int32d(u64 addr, bool* outError = nullptr) { auto val = int32(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint32(u64 addr); + inline u32 uint32d(u64 addr, bool* outError = nullptr) { auto val = uint32(addr); if (outError) *outError = val.error; return val.value; } - std::pair int64(u64 addr); - inline i64 int64d(u64 addr, bool* outError = nullptr) { auto val = int64(addr); if (outError) *outError = val.second; return val.first; } - std::pair uint64(u64 addr); - inline u64 uint64d(u64 addr, bool* outError = nullptr) { auto val = uint64(addr); if (outError) *outError = val.second; return val.first; } + ReadResult int64(u64 addr); + inline i64 int64d(u64 addr, bool* outError = nullptr) { auto val = int64(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint64(u64 addr); + inline u64 uint64d(u64 addr, bool* outError = nullptr) { auto val = uint64(addr); if (outError) *outError = val.error; return val.value; } + + ReadResult float32(u64 addr); + inline f32 float32d(u64 addr, bool* outError = nullptr) { auto val = float32(addr); if (outError) *outError = val.error; return val.value; } + ReadResult float64(u64 addr); + inline f64 float64d(u64 addr, bool* outError = nullptr) { auto val = float64(addr); if (outError) *outError = val.error; return val.value; } + + bool stream(u64 addr, Stream& outStream, bool sizeStored = true, u32 size_if_not_stored = 0); + bool string(u64 addr, String& outString, bool sizeStored = true, u32 size_if_not_stored = 0, bool null_terminated = false); + bool object(u64 addr, __i_serializable& outObject); private: read(void) = default; }; + public: struct write + { + bool int8(u64 addr, i8 value); + bool uint8(u64 addr, u8 value); + + bool int16(u64 addr, i16 value); + bool uint16(u64 addr, u16 value); + + bool int32(u64 addr, i32 value); + bool uint32(u64 addr, u32 value); + + bool int64(u64 addr, i64 value); + bool uint64(u64 addr, u64 value); + + bool float32(u64 addr, f32 value); + bool float64(u64 addr, f64 value); + + bool stream(u64 addr, const Stream& value, bool storeSize = true); + bool string(u64 addr, const String& value, bool storeSize = true, bool null_terminated = false); // if sizeStored, null_terminated will be ignored + bool object(u64 addr, const __i_serializable& value); + + private: + write(void) = default; + }; + private: Serial(void) = default; private: inline static StreamEdit s_openStream { }; + inline static Endianness s_endianness { Endianness::LittleEndian }; + }; + class __i_serializable + { + public: + virtual Serial::Stream serialize(void) const = 0; + virtual bool deserialize(const Serial::Stream& data) = 0; }; }