diff --git a/configure.ac b/configure.ac index 056b6357..70174b30 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,48 @@ else AC_MSG_ERROR([argp library not found, specify argp-standalone location in --with-argp-lib= and --with-argp-include= options.]) fi +AC_MSG_CHECKING([for direct float format conversion]) +AC_TRY_RUN( + [ +#include +int main() { + union { + uint32_t i; + float f; + } test; + test.f = 0.15; + return test.i == 0x3e19999a ? 0 : 1; +} + ], + [direct_float=1], + [direct_float=], + [direct_float=no], +) +if [[ "x$direct_float" == "x" ]]; then +AC_TRY_RUN( + [ +#include +int main() { + union { + uint32_t i; + float f; + } test; + test.f = 0.15; + return test.i == 0x9a99193e ? 0 : 1; +} + ], + [direct_float=2], + [direct_float=no], + [direct_float=no], +) +fi +if [[ "x$direct_float" == "xno" ]]; then + AC_MSG_RESULT([no]) +else + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED([HAVE_DIRECT_FLOAT_FORMAT], $direct_float, [Define for direct conversion from float to int (2 for swapped by order).]) +fi + AC_CONFIG_SRCDIR([src/ebusd/main.cpp]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([Makefile diff --git a/src/lib/ebus/data.cpp b/src/lib/ebus/data.cpp index dcec3a80..2557dbba 100644 --- a/src/lib/ebus/data.cpp +++ b/src/lib/ebus/data.cpp @@ -16,6 +16,10 @@ * along with this program. If not, see . */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include "data.h" #include #include @@ -813,7 +817,7 @@ result_t StringDataField::writeSymbols(istringstream& input, t.tm_mon = last-1; // January=0 t.tm_year = (value < 100 ? value + 2000 : value) - 1900; t.tm_isdst = 0; // automatic - if (mktime(&t) < 0) + if (mktime(&t) == -1) return RESULT_ERR_INVALID_NUM; // invalid date unsigned char daysSinceSunday = (unsigned char)t.tm_wday; // Sun=0 if ((m_dataType.flags & BCD) != 0) @@ -1116,7 +1120,12 @@ result_t NumberDataField::readSymbols(SymbolString& input, const unsigned char b if (m_bitCount == 32) { if ((m_dataType.flags & EXP) != 0) { // IEEE 754 binary32 float val; - /*int exp = (value >> 23) & 0xff; // 8 bits, signed +#ifdef HAVE_DIRECT_FLOAT_FORMAT +# if HAVE_DIRECT_FLOAT_FORMAT == 2 + value = __builtin_bswap32(value); +# endif +#else + int exp = (value >> 23) & 0xff; // 8 bits, signed if (exp == 0) { val = 0.0; } else { @@ -1131,9 +1140,7 @@ result_t NumberDataField::readSymbols(SymbolString& input, const unsigned char b } else if (m_divisor > 1) { val /= (float)m_divisor; } - }*/ -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - value = __builtin_bswap32(value); + } #endif unsigned char* pval = (unsigned char*)&value; val = *((float*)pval); @@ -1189,13 +1196,45 @@ result_t NumberDataField::writeSymbols(istringstream& input, unsigned int value; const char* str = input.str().c_str(); - if ((m_dataType.flags & REQ) == 0 && (isIgnored() || strcasecmp(str, NULL_VALUE) == 0)) + if ((m_dataType.flags & REQ) == 0 && (isIgnored() || strcasecmp(str, NULL_VALUE) == 0)) { value = m_dataType.replacement; // replacement value - else if (str == NULL || *str == 0) + } else if (str == NULL || *str == 0) { return RESULT_ERR_EOF; // input too short - else { + } else if ((m_dataType.flags & EXP) != 0) { // IEEE 754 binary32 char* strEnd = NULL; - if (m_divisor == 1 && (m_dataType.flags & EXP) == 0) { + double dvalue = strtod(str, &strEnd); + if (strEnd == NULL || strEnd == str || *strEnd != 0) { + return RESULT_ERR_INVALID_NUM; // invalid value + } +#ifdef HAVE_DIRECT_FLOAT_FORMAT + float val = (float)dvalue; + unsigned char* pval = (unsigned char*)&val; + value = *((int32_t*)pval); +# if HAVE_DIRECT_FLOAT_FORMAT == 2 + value = __builtin_bswap32(value); +# endif +#else + value = 0; + if (dvalue != 0) { + bool negative = dvalue < 0; + if (negative) { + dvalue = -dvalue; + } + int exp = ilogb(dvalue); + if (exp < -126 || exp > 127) + return RESULT_ERR_INVALID_NUM; // invalid value + dvalue = scalbln(dvalue, -exp) - 1.0; + unsigned int sig = (unsigned int)(dvalue * exp2(23)); + exp += 127; + value = (exp << 23) | sig; + if (negative) { + value |= 0x80000000; + } + } +#endif + } else { + char* strEnd = NULL; + if (m_divisor == 1) { if ((m_dataType.flags & SIG) != 0) { long int signedValue = strtol(str, &strEnd, 10); if (signedValue < 0 && m_bitCount != 32) @@ -1213,46 +1252,20 @@ result_t NumberDataField::writeSymbols(istringstream& input, if (strEnd == NULL || strEnd == str || *strEnd != 0) return RESULT_ERR_INVALID_NUM; // invalid value if (m_divisor < 0) - dvalue /= -m_divisor; + dvalue = round(dvalue / -m_divisor); else - dvalue *= m_divisor; - if ((m_dataType.flags & EXP) != 0) { // IEEE 754 binary32 - /*value = 0; - if (dvalue != 0) { - bool negative = dvalue < 0; - if (negative) { - dvalue = -dvalue; - } - int exp = ilogb(dvalue); - if (exp < -126 || exp > 127) - return RESULT_ERR_INVALID_NUM; // invalid value - dvalue = scalbln(dvalue, -exp) - 1.0; - unsigned int sig = (unsigned int)(dvalue * exp2(23)); - exp += 127; - value = (exp << 23) | sig; - if (negative) { - value |= 0x80000000; - } - }*/ - float val = (float)dvalue; - unsigned char* pval = (unsigned char*)&val; - value = *((int32_t*)pval); -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - value = __builtin_bswap32(value); -#endif - } else if ((m_dataType.flags & SIG) != 0) { - dvalue = round(dvalue); + dvalue = round(dvalue * m_divisor); + if ((m_dataType.flags & SIG) != 0) { if (dvalue < -(1LL << (8 * m_length)) || dvalue >= (1LL << (8 * m_length))) return RESULT_ERR_OUT_OF_RANGE; // value out of range if (dvalue < 0 && m_bitCount != 32) - value = (unsigned int)(dvalue + (1 << m_bitCount)); + value = (int)(dvalue + (1 << m_bitCount)); else - value = (unsigned int)dvalue; + value = (int)dvalue; } else { - dvalue = round(dvalue); if (dvalue < 0.0 || dvalue >= (1LL << (8 * m_length))) return RESULT_ERR_OUT_OF_RANGE; // value out of range - value = (unsigned int) dvalue; + value = (unsigned int)dvalue; } }