First draft of new ostd::Serial class
This commit is contained in:
parent
72f2a0285f
commit
14cb854387
6 changed files with 709 additions and 30 deletions
|
|
@ -12,7 +12,7 @@ set(CMAKE_C_COMPILER "clang")
|
|||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(${PROJ_NAME} LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
file(STRINGS "./other/build.nr" BUILD_NUMBER)
|
||||
#-----------------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2087
|
||||
2090
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <ostd/string/String.hpp>
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include <functional>
|
||||
|
||||
namespace ostd
|
||||
{
|
||||
class OutputHandlerBase;
|
||||
struct Signal;
|
||||
class BaseObject : public __i_stringeable
|
||||
class BaseObject : public __i_stringeable, public __i_serializable
|
||||
{
|
||||
public: using SignalCallback = std::function<void(Signal&)>;
|
||||
public:
|
||||
|
|
@ -60,9 +60,11 @@ namespace ostd
|
|||
virtual inline String toString(void) const override { return getObjectHeaderString(); };
|
||||
virtual void print(bool newLine = true, OutputHandlerBase* __destination = nullptr) const;
|
||||
|
||||
virtual inline Serial::Stream serialize(void) const override { return { 0 }; };
|
||||
virtual inline bool deserialize(const Serial::Stream& data) override { return false; };
|
||||
|
||||
virtual inline void handleSignal(Signal& signal) { }
|
||||
void connectSignal(u32 signal_id);
|
||||
|
||||
void __handle_signal(Signal& signal);
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -97,6 +97,17 @@ namespace ostd
|
|||
static inline const u8 ADDR = 4;
|
||||
static inline const u8 FLOAT = 4;
|
||||
static inline const u8 DOUBLE = 8;
|
||||
|
||||
static inline const u8 INT8 = 1;
|
||||
static inline const u8 UINT8 = 1;
|
||||
static inline const u8 INT16 = 2;
|
||||
static inline const u8 UINT16 = 2;
|
||||
static inline const u8 INT32 = 4;
|
||||
static inline const u8 UINT32 = 4;
|
||||
static inline const u8 INT64 = 8;
|
||||
static inline const u8 UINT64 = 8;
|
||||
static inline const u8 FLOAT32 = 4;
|
||||
static inline const u8 FLOAT64 = 8;
|
||||
};
|
||||
|
||||
typedef stdvec<i8> ByteStream;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,496 @@
|
|||
|
||||
namespace ostd
|
||||
{
|
||||
bool Serial::isValidAddress(u64 addr, u32 size)
|
||||
{
|
||||
if (addr == 0) return false;
|
||||
if (size == 0) return false;
|
||||
if (addr > u64Range::max() - size) return false; // u64 overflow check
|
||||
return (addr + size - 1) < s_openStream.size();
|
||||
}
|
||||
|
||||
Serial::ReadResult<i8> Serial::read::int8(u64 addr)
|
||||
{
|
||||
if (!isStreamAttached()) return { 0, true };
|
||||
managed_address_check(addr);
|
||||
if (!isValidAddress(addr, tTypeSize::INT8)) return { 0, true };
|
||||
i8 val = s_openStream[addr];
|
||||
s_addr += tTypeSize::INT8;
|
||||
return { val, false };
|
||||
}
|
||||
|
||||
Serial::ReadResult<u8> Serial::read::uint8(u64 addr)
|
||||
{
|
||||
auto res = int8(addr);
|
||||
return { cast<u8>(res.value), res.error };
|
||||
}
|
||||
|
||||
Serial::ReadResult<i16> Serial::read::int16(u64 addr)
|
||||
{
|
||||
if (!isStreamAttached()) return { 0, true };
|
||||
managed_address_check(addr);
|
||||
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 };
|
||||
s_addr += tTypeSize::INT16;
|
||||
return { val, false };
|
||||
}
|
||||
|
||||
Serial::ReadResult<u16> Serial::read::uint16(u64 addr)
|
||||
{
|
||||
auto res = int16(addr);
|
||||
return { cast<u16>(res.value), res.error };
|
||||
}
|
||||
|
||||
Serial::ReadResult<i32> Serial::read::int32(u64 addr)
|
||||
{
|
||||
if (!isStreamAttached()) return { 0, true };
|
||||
managed_address_check(addr);
|
||||
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 };
|
||||
s_addr += tTypeSize::INT32;
|
||||
return { val, false };
|
||||
}
|
||||
|
||||
Serial::ReadResult<u32> Serial::read::uint32(u64 addr)
|
||||
{
|
||||
auto res = int32(addr);
|
||||
return { cast<u32>(res.value), res.error };
|
||||
}
|
||||
|
||||
Serial::ReadResult<i64> Serial::read::int64(u64 addr)
|
||||
{
|
||||
if (!isStreamAttached()) return { 0, true };
|
||||
managed_address_check(addr);
|
||||
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 };
|
||||
s_addr += tTypeSize::INT64;
|
||||
return { val, false };
|
||||
}
|
||||
|
||||
Serial::ReadResult<u64> Serial::read::uint64(u64 addr)
|
||||
{
|
||||
auto res = int64(addr);
|
||||
return { cast<u64>(res.value), res.error };
|
||||
}
|
||||
|
||||
Serial::ReadResult<f32> Serial::read::float32(u64 addr)
|
||||
{
|
||||
if (!isStreamAttached()) return { 0, true };
|
||||
managed_address_check(addr);
|
||||
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 };
|
||||
s_addr += tTypeSize::FLOAT32;
|
||||
return { fp.val, false };
|
||||
}
|
||||
|
||||
Serial::ReadResult<f64> Serial::read::float64(u64 addr)
|
||||
{
|
||||
if (!isStreamAttached()) return { 0, true };
|
||||
managed_address_check(addr);
|
||||
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 };
|
||||
s_addr += tTypeSize::FLOAT64;
|
||||
return { dp.val, false };
|
||||
}
|
||||
|
||||
bool Serial::read::stream(Stream& outStream, u64 addr, bool sizeStored, u32 size_if_not_stored)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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<u8>(Endianness::LittleEndian))
|
||||
endianness = Endianness::LittleEndian;
|
||||
else if (tmp.value == cast<u8>(Endianness::BigEndian))
|
||||
endianness = Endianness::BigEndian;
|
||||
else return false;
|
||||
}
|
||||
if (!isValidAddress(addr, size)) return false;
|
||||
Serial::Stream data = { size, endianness };
|
||||
StreamEdit edit = data.data();
|
||||
std::copy_n(s_openStream.begin() + addr, size, edit.begin());
|
||||
outStream = std::move(data);
|
||||
s_addr = addr + size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::read::string(String& outString, u64 addr, bool sizeStored, u32 size_if_not_stored, bool null_terminated)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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<char>(s_openStream[i]);
|
||||
}
|
||||
s_addr = addr + size;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
String out = "";
|
||||
auto tmp = int8(addr);
|
||||
if (tmp.error) return false;
|
||||
addr += tTypeSize::INT8;
|
||||
while (tmp.value != '\0')
|
||||
{
|
||||
out += cast<char>(tmp.value);
|
||||
tmp = int8(addr);
|
||||
if (tmp.error) return false;
|
||||
addr += tTypeSize::INT8;
|
||||
}
|
||||
outString = out;
|
||||
s_addr = addr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Serial::read::object(__i_serializable& outObject, u64 addr)
|
||||
{
|
||||
Serial::Stream objData(0);
|
||||
if (!stream(objData, addr, true, 0))
|
||||
return false;
|
||||
return outObject.deserialize(objData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Serial::write::int8(u64 addr, i8 value)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
if (!isValidAddress(addr, tTypeSize::INT8)) return false;
|
||||
s_openStream[addr] = value;
|
||||
s_addr += tTypeSize::INT8;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::write::uint8(u64 addr, u8 value)
|
||||
{
|
||||
return int8(addr, cast<i8>(value));
|
||||
}
|
||||
|
||||
bool Serial::write::int16(u64 addr, i16 value)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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;
|
||||
s_addr += tTypeSize::INT16;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::write::uint16(u64 addr, u16 value)
|
||||
{
|
||||
return int16(addr, cast<i16>(value));
|
||||
}
|
||||
|
||||
bool Serial::write::int32(u64 addr, i32 value)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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;
|
||||
s_addr += tTypeSize::INT32;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::write::uint32(u64 addr, u32 value)
|
||||
{
|
||||
return int32(addr, cast<i32>(value));
|
||||
}
|
||||
|
||||
bool Serial::write::int64(u64 addr, i64 value)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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;
|
||||
s_addr += tTypeSize::INT64;
|
||||
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<i64>(value));
|
||||
}
|
||||
|
||||
bool Serial::write::float32(u64 addr, f32 value)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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;
|
||||
s_addr += tTypeSize::FLOAT32;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::write::float64(u64 addr, f64 value)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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;
|
||||
s_addr += tTypeSize::FLOAT64;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::write::stream(u64 addr, const Stream& value, bool storeSize)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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];
|
||||
s_addr = addr + size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Serial::write::string(u64 addr, const String& value, bool storeSize, bool null_terminated)
|
||||
{
|
||||
if (!isStreamAttached()) return false;
|
||||
managed_address_check(addr);
|
||||
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<i8>(value[i - addr]);
|
||||
if (null_terminated && i == addr + size - 1)
|
||||
c = '\0';
|
||||
s_openStream[i] = c;
|
||||
}
|
||||
s_addr = addr + size;
|
||||
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;
|
||||
return stream(addr, data, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// =============================================== OLD VERSION ===============================================
|
||||
namespace serial
|
||||
{
|
||||
bool SerialIO::init(u64 size, u8 endianness)
|
||||
|
|
@ -20,10 +510,10 @@ namespace ostd
|
|||
if (!is_validAddr(addr, tTypeSize::QWORD)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
outVal = ( m_data[addr + 7] & 0x00000000000000FFU)
|
||||
| (( m_data[addr + 6] << 8) & 0x000000000000FF00U)
|
||||
| (( m_data[addr + 5] << 16) & 0x0000000000FF0000U)
|
||||
| (( m_data[addr + 4] << 24) & 0x00000000FF000000U)
|
||||
outVal = ( m_data[addr + 7] & 0x00000000000000FFU)
|
||||
| (( m_data[addr + 6] << 8) & 0x000000000000FF00U)
|
||||
| (( m_data[addr + 5] << 16) & 0x0000000000FF0000U)
|
||||
| (( m_data[addr + 4] << 24) & 0x00000000FF000000U)
|
||||
| (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U)
|
||||
| (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U)
|
||||
| (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U)
|
||||
|
|
@ -35,10 +525,10 @@ namespace ostd
|
|||
| (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U)
|
||||
| (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U)
|
||||
| (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U)
|
||||
| (( m_data[addr + 4] << 24) & 0x00000000FF000000U)
|
||||
| (( m_data[addr + 5] << 16) & 0x0000000000FF0000U)
|
||||
| (( m_data[addr + 6] << 8) & 0x000000000000FF00U)
|
||||
| ( m_data[addr + 7] & 0x00000000000000FFU);
|
||||
| (( m_data[addr + 4] << 24) & 0x00000000FF000000U)
|
||||
| (( m_data[addr + 5] << 16) & 0x0000000000FF0000U)
|
||||
| (( m_data[addr + 6] << 8) & 0x000000000000FF00U)
|
||||
| ( m_data[addr + 7] & 0x00000000000000FFU);
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,209 @@
|
|||
/*
|
||||
OmniaFramework - A collection of useful functionality
|
||||
Copyright (C) 2026 OmniaX-Dev
|
||||
OmniaFramework - A collection of useful functionality
|
||||
Copyright (C) 2026 OmniaX-Dev
|
||||
|
||||
This file is part of OmniaFramework.
|
||||
This file is part of OmniaFramework.
|
||||
|
||||
OmniaFramework 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, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OmniaFramework 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, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OmniaFramework 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.
|
||||
OmniaFramework 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 OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostd/data/Types.hpp>
|
||||
#include <ostd/data/Bitfields.hpp>
|
||||
#include <ostd/data/BaseObject.hpp>
|
||||
#include <ostd/string/String.hpp>
|
||||
#include <span>
|
||||
|
||||
namespace ostd
|
||||
{
|
||||
class OutputHandlerBase;
|
||||
class __i_serializable;
|
||||
class Serial
|
||||
{
|
||||
public: template<typename T> struct ReadResult { T value; bool error { false }; };
|
||||
public: enum class Endianness : u8 { LittleEndian = 0, BigEndian };
|
||||
public: using StreamEdit = std::span<int8_t>;
|
||||
public: using StreamView = std::span<const int8_t>;
|
||||
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))
|
||||
{
|
||||
if (size > std::numeric_limits<size_t>::max())
|
||||
throw "Serial::Stream size can't excede UINT32_MAX on a 32bit system.";
|
||||
}
|
||||
m_data = new i8[size];
|
||||
m_size = size;
|
||||
m_endianness = endianness;
|
||||
if (preInitialize)
|
||||
{
|
||||
for (u64 i = 0; i < size; i++)
|
||||
m_data[i] = initialValue;
|
||||
}
|
||||
}
|
||||
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 = 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<std::size_t>(m_size) };
|
||||
return {};
|
||||
}
|
||||
inline StreamView data() const {
|
||||
if (isValid())
|
||||
return { m_data, cast<std::size_t>(m_size) };
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
i8* m_data { nullptr };
|
||||
u64 m_size { 0 };
|
||||
Endianness m_endianness { Endianness::LittleEndian };
|
||||
};
|
||||
|
||||
public:
|
||||
inline static void attachStream(Stream& stream) { s_openStream = stream.data(); s_endianness = stream.getEndianness(); disableManagedAddress(); }
|
||||
inline static void detachStrean(void) { s_openStream = {}; }
|
||||
inline static bool setManagedAddress(u64 addr) { if (!isManagedAddressEnabled() || !isValidAddress(addr)) return false; s_addr = addr; return true; }
|
||||
inline static bool isManagedAddressEnabled(void) { return s_managedAddress; }
|
||||
inline static void enableManagedAddress(bool enable = true) { s_managedAddress = enable; s_addr = 0; }
|
||||
inline static void disableManagedAddress(void) { enableManagedAddress(false); }
|
||||
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
|
||||
{
|
||||
ReadResult<i8> int8(u64 addr = 0);
|
||||
inline i8 int8d(u64 addr = 0, bool* outError = nullptr) { auto val = int8(addr); if (outError) *outError = val.error; return val.value; }
|
||||
ReadResult<u8> uint8(u64 addr = 0);
|
||||
inline u8 uint8d(u64 addr = 0, bool* outError = nullptr) { auto val = uint8(addr); if (outError) *outError = val.error; return val.value; }
|
||||
|
||||
ReadResult<i16> int16(u64 addr = 0);
|
||||
inline i16 int16d(u64 addr = 0, bool* outError = nullptr) { auto val = int16(addr); if (outError) *outError = val.error; return val.value; }
|
||||
ReadResult<u16> uint16(u64 addr = 0);
|
||||
inline u16 uint16d(u64 addr = 0, bool* outError = nullptr) { auto val = uint16(addr); if (outError) *outError = val.error; return val.value; }
|
||||
|
||||
ReadResult<i32> int32(u64 addr = 0);
|
||||
inline i32 int32d(u64 addr = 0, bool* outError = nullptr) { auto val = int32(addr); if (outError) *outError = val.error; return val.value; }
|
||||
ReadResult<u32> uint32(u64 addr = 0);
|
||||
inline u32 uint32d(u64 addr = 0, bool* outError = nullptr) { auto val = uint32(addr); if (outError) *outError = val.error; return val.value; }
|
||||
|
||||
ReadResult<i64> int64(u64 addr = 0);
|
||||
inline i64 int64d(u64 addr = 0, bool* outError = nullptr) { auto val = int64(addr); if (outError) *outError = val.error; return val.value; }
|
||||
ReadResult<u64> uint64(u64 addr = 0);
|
||||
inline u64 uint64d(u64 addr = 0, bool* outError = nullptr) { auto val = uint64(addr); if (outError) *outError = val.error; return val.value; }
|
||||
|
||||
ReadResult<f32> float32(u64 addr = 0);
|
||||
inline f32 float32d(u64 addr = 0, bool* outError = nullptr) { auto val = float32(addr); if (outError) *outError = val.error; return val.value; }
|
||||
ReadResult<f64> float64(u64 addr = 0);
|
||||
inline f64 float64d(u64 addr = 0, bool* outError = nullptr) { auto val = float64(addr); if (outError) *outError = val.error; return val.value; }
|
||||
|
||||
bool stream(Stream& outStream, u64 addr = 0, bool sizeStored = true, u32 size_if_not_stored = 0);
|
||||
bool string(String& outString, u64 addr = 0, bool sizeStored = true, u32 size_if_not_stored = 0, bool null_terminated = false);
|
||||
bool object(__i_serializable& outObject, u64 addr = 0);
|
||||
|
||||
private:
|
||||
read(void) = default;
|
||||
};
|
||||
|
||||
public: struct write
|
||||
{
|
||||
bool int8(u64 addr, i8 value);
|
||||
inline bool int8(i8 value) { return int8(0, value); }
|
||||
bool uint8(u64 addr, u8 value);
|
||||
inline bool uint8(i8 value) { return uint8(0, value); }
|
||||
|
||||
bool int16(u64 addr, i16 value);
|
||||
inline bool int16(i8 value) { return int16(0, value); }
|
||||
bool uint16(u64 addr, u16 value);
|
||||
inline bool uint16(i8 value) { return uint16(0, value); }
|
||||
|
||||
bool int32(u64 addr, i32 value);
|
||||
inline bool int32(i8 value) { return int32(0, value); }
|
||||
bool uint32(u64 addr, u32 value);
|
||||
inline bool uint32(i8 value) { return uint32(0, value); }
|
||||
|
||||
bool int64(u64 addr, i64 value);
|
||||
inline bool int64(i8 value) { return int64(0, value); }
|
||||
bool uint64(u64 addr, u64 value);
|
||||
inline bool uint64(i8 value) { return uint64(0, value); }
|
||||
|
||||
bool float32(u64 addr, f32 value);
|
||||
inline bool float32(i8 value) { return float32(0, value); }
|
||||
bool float64(u64 addr, f64 value);
|
||||
inline bool float64(i8 value) { return float64(0, value); }
|
||||
|
||||
bool stream(u64 addr, const Stream& value, bool storeSize = true);
|
||||
inline bool stream(const Stream& value, bool storeSize = true) { return stream(0, value, storeSize); }
|
||||
bool string(u64 addr, const String& value, bool storeSize = true, bool null_terminated = false); // if sizeStored, null_terminated will be ignored
|
||||
inline bool string(const String& value, bool storeSize = true, bool null_terminated = false) { return string(0, value, storeSize, null_terminated); }
|
||||
bool object(u64 addr, const __i_serializable& value);
|
||||
inline bool object(const __i_serializable& value) { return object(0, value); }
|
||||
|
||||
private:
|
||||
write(void) = default;
|
||||
};
|
||||
|
||||
private:
|
||||
Serial(void) = default;
|
||||
inline static void managed_address_check(u64& addr) { if (isManagedAddressEnabled()) addr = s_addr; }
|
||||
|
||||
private:
|
||||
inline static StreamEdit s_openStream { };
|
||||
inline static Endianness s_endianness { Endianness::LittleEndian };
|
||||
|
||||
inline static u64 s_addr { 0 };
|
||||
inline static bool s_managedAddress { false };
|
||||
};
|
||||
class __i_serializable
|
||||
{
|
||||
public:
|
||||
virtual Serial::Stream serialize(void) const = 0;
|
||||
virtual bool deserialize(const Serial::Stream& data) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// =============================================== OLD VERSION ===============================================
|
||||
class OutputHandlerBase;
|
||||
namespace serial
|
||||
{
|
||||
class SerialIO
|
||||
|
|
|
|||
Loading…
Reference in a new issue