diff --git a/examples/IRMQTTServer/IRMQTTServer.ino b/examples/IRMQTTServer/IRMQTTServer.ino index a685f8615..a9517e89b 100644 --- a/examples/IRMQTTServer/IRMQTTServer.ino +++ b/examples/IRMQTTServer/IRMQTTServer.ino @@ -107,6 +107,7 @@ #include #include #include +#include #ifdef MQTT_ENABLE // -------------------------------------------------------------------- // * * * IMPORTANT * * * @@ -129,7 +130,7 @@ // Set if your MQTT server requires a Username & Password to connect. const char* mqtt_user = ""; const char* mqtt_password = ""; -#define MQTT_RECONNECT_TIME 5000 // Delay between reconnect tries. +#define MQTT_RECONNECT_TIME 5000 // Delay(ms) between reconnect tries. #define MQTTprefix "ir_server" #define MQTTack MQTTprefix "/sent" // Topic we send back acknowledgements on @@ -710,24 +711,15 @@ void sendIRCode(int const ir_type, uint64_t const code, char const * code_str, #endif break; default: - debug("Code: 0x" + - String((uint32_t) (code >> 32), 16) + - String((uint32_t) (code & UINT32_MAX), 16)); + debug("Code: 0x" + uint64ToString(code, 16)); debug("Bits: " + String(bits)); debug("Repeats: " + String(repeat)); #ifdef MQTT_ENABLE - if (code >> 32) // Are we dealing with a value larger than UINT32_MAX? - mqtt_client.publish(MQTTack, (String(ir_type) + "," + - String((uint32_t) (code >> 32), 16) + - String((uint32_t) (code & UINT32_MAX), 16) - + "," + String(bits) + "," + - String(repeat)).c_str()); - else - mqtt_client.publish(MQTTack, (String(ir_type) + "," + - String((uint32_t) (code & UINT32_MAX), 16) - + "," + String(bits) + "," + - String(repeat)).c_str()); + mqtt_client.publish(MQTTack, (String(ir_type) + "," + + uint64ToString(code, 16) + + "," + String(bits) + "," + + String(repeat)).c_str()); #endif } } diff --git a/src/IRutils.cpp b/src/IRutils.cpp index ba3bb75a8..22b4bb3b7 100644 --- a/src/IRutils.cpp +++ b/src/IRutils.cpp @@ -4,9 +4,13 @@ #ifndef UNIT_TEST #include #endif + #define __STDC_LIMIT_MACROS #include #include +#ifndef ARDUINO +#include +#endif #include "IRrecv.h" // Reverse the order of the requested least significant nr. of bits. @@ -30,30 +34,49 @@ uint64_t reverseBits(uint64_t input, uint16_t nbits) { return (input << nbits) | output; } -// Print a uint64_t/unsigned long long to the Serial port -// Serial.print() can't handle printing long longs. (uint64_t) +// Convert a uint64_t (unsigned long long) to a string. +// Arduino String/toInt/Serial.print() can't handle printing 64 bit values. // // Args: // input: The value to print -// base: The output base. +// base: The output base. +// Returns: +// A string representation of the integer. // Note: Based on Arduino's Print::printNumber() -void serialPrintUint64(uint64_t input, uint8_t base) { - char buf[8 * sizeof(input) + 1]; // Assumes 8-bit chars plus zero byte. - char *str = &buf[sizeof(buf) - 1]; - - *str = '\0'; - - // prevent crash if called with base == 1 +#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist. +String uint64ToString(uint64_t input, uint8_t base) { + String result = ""; +#else +std::string uint64ToString(uint64_t input, uint8_t base) { + std::string result = ""; +#endif + // prevent issues if called with base <= 1 if (base < 2) base = 10; + // Check we have a base that we can actually print. + // i.e. [0-9A-Z] == 36 + if (base > 36) base = 10; do { char c = input % base; input /= base; - *--str = c < 10 ? c + '0' : c + 'A' - 10; + if (c < 10) + c +='0'; + else + c += 'A' - 10; + result = c + result; } while (input); + return result; +} -#ifndef UNIT_TEST - Serial.print(str); -#endif +#ifdef ARDUINO +// Print a uint64_t/unsigned long long to the Serial port +// Serial.print() can't handle printing long longs. (uint64_t) +// +// Args: +// input: The value to print +// base: The output base. +void serialPrintUint64(uint64_t input, uint8_t base) { + Serial.print(uint64ToString(input, base)); } +#endif diff --git a/src/IRutils.h b/src/IRutils.h index e333fe471..eb3f1d8ee 100644 --- a/src/IRutils.h +++ b/src/IRutils.h @@ -3,10 +3,21 @@ // Copyright 2017 David Conran +#ifndef UNIT_TEST +#include +#endif #define __STDC_LIMIT_MACROS #include +#ifndef ARDUINO +#include +#endif uint64_t reverseBits(uint64_t input, uint16_t nbits); -void serialPrintUint64(uint64_t input, uint8_t base); +#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist. +String uint64ToString(uint64_t input, uint8_t base = 10); +#else +std::string uint64ToString(uint64_t input, uint8_t base = 10); +#endif +void serialPrintUint64(uint64_t input, uint8_t base = 10); #endif // IRUTILS_H_ diff --git a/test/IRutils_test.cpp b/test/IRutils_test.cpp index 2225022f0..3b4c4145a 100644 --- a/test/IRutils_test.cpp +++ b/test/IRutils_test.cpp @@ -1,6 +1,7 @@ // Copyright 2017 David Conran #include "IRutils.h" +#include #include "gtest/gtest.h" // Tests reverseBits(). @@ -33,3 +34,58 @@ TEST(ReverseBitsTest, LessBitsReversedThanInputHasSet) { EXPECT_EQ(0xF5, reverseBits(0xFA, 4)); EXPECT_EQ(0x12345678FFFF0000, reverseBits(0x123456780000FFFF, 32)); } + +// Tests for uint64ToString() + +TEST(TestUint64ToString, TrivialCases) { + EXPECT_EQ("0", uint64ToString(0)); // Default base (10) + EXPECT_EQ("0", uint64ToString(0, 2)); // Base-2 + EXPECT_EQ("0", uint64ToString(0, 8)); // Base-8 + EXPECT_EQ("0", uint64ToString(0, 10)); // Base-10 + EXPECT_EQ("0", uint64ToString(0, 16)); // Base-16 + + EXPECT_EQ("1", uint64ToString(1, 2)); // Base-2 + EXPECT_EQ("2", uint64ToString(2, 8)); // Base-8 + EXPECT_EQ("3", uint64ToString(3, 10)); // Base-10 + EXPECT_EQ("4", uint64ToString(4, 16)); // Base-16 +} + +TEST(TestUint64ToString, NormalUse) { + EXPECT_EQ("12345", uint64ToString(12345)); + EXPECT_EQ("100", uint64ToString(4, 2)); + EXPECT_EQ("3039", uint64ToString(12345, 16)); + EXPECT_EQ("123456", uint64ToString(123456)); + EXPECT_EQ("1E240", uint64ToString(123456, 16)); + EXPECT_EQ("FEEDDEADBEEF", uint64ToString(0xfeeddeadbeef, 16)); +} + +TEST(TestUint64ToString, Max64Bit) { + EXPECT_EQ("18446744073709551615", uint64ToString(UINT64_MAX)); // Default + EXPECT_EQ("1111111111111111111111111111111111111111111111111111111111111111", + uint64ToString(UINT64_MAX, 2)); // Base-2 + EXPECT_EQ("1777777777777777777777", uint64ToString(UINT64_MAX, 8)); // Base-8 + EXPECT_EQ("18446744073709551615", uint64ToString(UINT64_MAX, 10)); // Base-10 + EXPECT_EQ("FFFFFFFFFFFFFFFF", uint64ToString(UINT64_MAX, 16)); // Base-16 +} + +TEST(TestUint64ToString, Max32Bit) { + EXPECT_EQ("4294967295", uint64ToString(UINT32_MAX)); // Default + EXPECT_EQ("37777777777", uint64ToString(UINT32_MAX, 8)); // Base-8 + EXPECT_EQ("4294967295", uint64ToString(UINT32_MAX, 10)); // Base-10 + EXPECT_EQ("FFFFFFFF", uint64ToString(UINT32_MAX, 16)); // Base-16 +} + +TEST(TestUint64ToString, InterestingCases) { + // Previous hacky-code didn't handle leading zeros in the lower 32 bits. + EXPECT_EQ("100000000", uint64ToString(0x100000000, 16)); + EXPECT_EQ("100000001", uint64ToString(0x100000001, 16)); +} + +TEST(TestUint64ToString, SillyBases) { + // If we are given a silly base, we should defer to Base-10. + EXPECT_EQ("12345", uint64ToString(12345, 0)); // Super silly, makes no sense. + EXPECT_EQ("12345", uint64ToString(12345, 1)); // We don't do unary. + EXPECT_EQ("12345", uint64ToString(12345, 100)); // We can't print base-100. + EXPECT_EQ("12345", uint64ToString(12345, 37)); // Base-37 is one to far. + EXPECT_EQ("9IX", uint64ToString(12345, 36)); // But we *can* do base-36. +}