#pragma once #include "efi_scaled_channel.h" #include "rusefi_types.h" #include #include struct Writer; class LogField { public: // Scaled channels, memcpys data directly and describes format in header template constexpr LogField(const scaled_channel& toRead, const char* name, const char* units, int8_t digits, const char* category = "none") : m_multiplier(float(TDiv) / TMult) , m_addr(toRead.getFirstByteAddr()) , m_type(resolveType()) , m_digits(digits) , m_size(sizeForType(resolveType())) , m_name(name) , m_units(units) , m_category(category) { } // Non-scaled channel, works for plain arithmetic types (int, float, uint8_t, etc) template >::type> constexpr LogField(TValue& toRead, const char* name, const char* units, int8_t digits, const char* category = "none") : m_multiplier(1) , m_addr(&toRead) , m_type(resolveType()) , m_digits(digits) , m_size(sizeForType(resolveType())) , m_name(name) , m_units(units) , m_category(category) { } enum class Type : uint8_t { U08 = 0, S08 = 1, U16 = 2, S16 = 3, U32 = 4, S32 = 5, S64 = 6, F32 = 7, }; constexpr size_t getSize() const { return m_size; } // Write the header data describing this field. void writeHeader(Writer& outBuffer) const; // Write the field's data to the buffer. // Returns the number of bytes written. size_t writeData(char* buffer) const; private: template static constexpr Type resolveType(); static constexpr size_t sizeForType(Type t) { switch (t) { case Type::U08: case Type::S08: return 1; case Type::U16: case Type::S16: return 2; default: // float, uint32, int32 return 4; } } const float m_multiplier; const void* const m_addr; const Type m_type; const int8_t m_digits; const uint8_t m_size; const char* const m_name; const char* const m_units; const char* const m_category; }; template<> constexpr LogField::Type LogField::resolveType() { return Type::U08; } template<> constexpr LogField::Type LogField::resolveType() { return Type::S08; } template<> constexpr LogField::Type LogField::resolveType() { return Type::U16; } template<> constexpr LogField::Type LogField::resolveType() { return Type::S16; } template<> constexpr LogField::Type LogField::resolveType() { return Type::U32; } #if EFI_PROD_CODE // we allow both 'int' and 'int32_t' just to allow extra flexibility in headers // https://stackoverflow.com/questions/55782246/why-is-uint32-t-typedeffed-to-unsigned-long-on-arm-none-eabi-gcc-and-how-to template<> constexpr LogField::Type LogField::resolveType() { return Type::S32; } #endif template<> constexpr LogField::Type LogField::resolveType() { return Type::S32; } template<> constexpr LogField::Type LogField::resolveType() { return Type::F32; }