From f6f72e8c166d6382a13a5ce96f12aae42776ce69 Mon Sep 17 00:00:00 2001 From: Carsten Schmiemann Date: Tue, 1 Nov 2022 14:28:10 +0100 Subject: [PATCH] Original project changes: Vehicle - Add buffer handling tools to ovms utils --- OVMS.V3/main/ovms_utils.cpp | 16 ++++ OVMS.V3/main/ovms_utils.h | 183 ++++++++++++++++++++++++++++++++++-- 2 files changed, 193 insertions(+), 6 deletions(-) diff --git a/OVMS.V3/main/ovms_utils.cpp b/OVMS.V3/main/ovms_utils.cpp index 88589fa..5a75a30 100644 --- a/OVMS.V3/main/ovms_utils.cpp +++ b/OVMS.V3/main/ovms_utils.cpp @@ -612,3 +612,19 @@ std::string idtag(const char* tag, void* instance) std::string res = buf.str(); return res; } + +/** + * get_buff_string: Helper function to get at string value from sized buffer. + */ +bool get_buff_string(const uint8_t *data, uint32_t size, uint32_t index, uint32_t len, std::string &strret) + { + int remain = size - index; + if (remain < 0) + return false; + if (remain < len) + len = remain; + const char *begin = reinterpret_cast(data + index) ; + const char *end = begin + len; + strret.assign(begin, end); + return true; + } diff --git a/OVMS.V3/main/ovms_utils.h b/OVMS.V3/main/ovms_utils.h index cae50ed..6bf8b2f 100644 --- a/OVMS.V3/main/ovms_utils.h +++ b/OVMS.V3/main/ovms_utils.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "ovms.h" // Macro utils: @@ -339,17 +340,187 @@ std::string idtag(const char* tag, void* instance); #define IDTAG idtag(TAG,this) /** - * sign_extend: Sign extend an unsigned to a signed integer of the same size. + * sign_extend: Sign extend an unsigned to a signed integer of the same or bigger size. + * Sign bit is not known at compile time. */ -template -INT sign_extend(UINT uvalue, uint8_t signbit) +template +INT sign_extend( UINT uvalue, uint8_t signbit) { typedef typename std::make_unsigned::type uint_t; uint_t newuvalue = uvalue; - if (newuvalue & (UINT(1U) << signbit)) { - newuvalue |= ~((uint_t(1U) << signbit) - 1); + UINT signmask = UINT(1U) << signbit; + if ( newuvalue & signmask) + newuvalue |= ~ (static_cast(signmask) - 1); + return reinterpret_cast(uvalue); } - return reinterpret_cast(newuvalue); + +/** + * sign_extend: Sign extend an unsigned to a signed integer of the same or bigger size. + * Sign bit is known at compile time. + */ +template +INT sign_extend( UINT uvalue) + { + typedef typename std::make_unsigned::type uint_t; + uint_t newuvalue = uvalue; + if ( newuvalue & ( UINT(1U) << SIGNBIT) ) + newuvalue |= ~((uint_t(1U) << SIGNBIT) - 1); + return reinterpret_cast(uvalue); + } + +/** + * get_bit: Get at a specific (compile-time defined) bit in a byte. + */ +template +bool get_bit(uint8_t data) +{ + return (0 != (data & (1 << BIT))); +} + +// helper to provide a big endian integer from a given number of bytes. +// The helper function checks the length before using this. +template +struct ovms_bytes_impl_t + { + static uint32_t get_bytes_int(const uint8_t *data, uint32_t index) + { + return (data[index + (BYTES - 1)]) + | (ovms_bytes_impl_t < BYTES - 1 >::get_bytes_int(data, index) << 8); + } + }; +template<> +struct ovms_bytes_impl_t<1> + { + static uint32_t get_bytes_int(const uint8_t *data, uint32_t index) + { + return (data[index]); + } + }; + +// Helper Class to access Little-Endian values. +template +struct get_bytes_le_impl_t + { + static uint32_t get_bytes_int( const uint8_t *data, uint32_t index) + { + return ((data[index + (BYTES - 1)]) << (8 * (BYTES - 1))) + | get_bytes_le_impl_t < BYTES - 1 >::get_bytes_int(data, index); + } + }; +template<> +struct get_bytes_le_impl_t<1> + { + static uint32_t get_bytes_int(const uint8_t *data, uint32_t index) + { + return (data[index]); + } + }; + +/** + * get_uint_bytes_be: Access to unsigned integer (big-endian) in a data buffer. + * + * @return true If within bounds + */ +template +bool get_uint_bytes_be(const uint8_t *data, uint32_t index, uint32_t length, uint32_t &res) +{ + if ((index + (BYTES - 1)) >= length) { + return false; + } + res = ovms_bytes_impl_t::get_bytes_int(data, index); + return true; +} + +/** + * get_int_bytes_be: Access to signed integer (big-endian) in a data buffer. + * @return true If within bounds + */ +template +bool get_int_bytes_be(const uint8_t *data, uint32_t index, uint32_t length, int32_t &res) + { + if ((index + (BYTES - 1)) >= length) + return false; + + uint32_t uresult = ovms_bytes_impl_t::get_bytes_int(data, index); + res = reinterpret_cast(uresult); + return true; + } + +/** + * get_uint_buff_be: Access to unsigned integer (big-endian) in a vector data buffer. + * @return true If successful + */ +template +bool get_uint_buff_be(const std::string &data, uint32_t index, uint32_t &ures) + { + if ((index + (BYTES - 1)) >= data.size()) + return false; + ures = ovms_bytes_impl_t::get_bytes_int(reinterpret_cast(data.data()), index); + return true; + } + +/** + * get_buff_int_be: Access to signed integer (big-endian) in a std::string data buffer. + * @return true If successful + */ +template +bool get_buff_int_be(const std::string &data, uint32_t index, int32_t &res) + { + if ((index + (BYTES - 1)) >= data.size()) + return false; + uint32_t ures = ovms_bytes_impl_t::get_bytes_int(reinterpret_cast(data.data()), index); + + res = sign_extend < uint32_t, int32_t, BYTES * 8 - 1 > (ures); + return true; + } + +/** + * get_bytes_uint_le: Access to unsigned integer (little-endian) in a data buffer. + * @return true If within bounds + */ +template +bool get_bytes_uint_le(const uint8_t *data, uint32_t index, uint32_t length, uint32_t &res) + { + if ((index + (BYTES - 1)) >= length) + return false; + res = get_bytes_le_impl_t::get_bytes_int(data, index); + return true; + } + +/** Access to unsigned integer (little-endian) in a vector data buffer. + * @return true If within bounds + */ +template +bool get_buff_uint_le(const std::string &data, uint32_t index, uint32_t &res) + { + if ((index + (BYTES - 1)) >= data.size()) + return false; + res = get_bytes_le_impl_t::get_bytes_int(reinterpret_cast(data.data()), index); + return true; + } + +/** Access to signed integer (little-endian) in a vector data buffer. + * @return true If within bounds + */ +template +bool get_buff_int_le(const std::string &data, uint32_t index, int32_t &res) + { + if ((index + (BYTES - 1)) >= data.size()) + return false; + uint32_t uresult = ovms_bytes_impl_t::get_bytes_int(reinterpret_cast(data.data()), index); + res = sign_extend < uint32_t, int32_t, BYTES * 8 - 1 > (uresult); + return true; + } + + +/** Access a string portion in a vector data buffer. + * @return true if start is within bounds. + */ +bool get_buff_string(const uint8_t *data, uint32_t size, uint32_t index, uint32_t len, std::string &strret); + +inline bool get_buff_string(const std::string &data, uint32_t index, uint32_t len, std::string &strret) + { + return get_buff_string(reinterpret_cast(data.data()), data.size(), index, len, strret); } #endif // __OVMS_UTILS_H__