From c94a815540f694e4cfe6a65a9f22919d8ab75da2 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 11 Jun 2015 18:02:37 +0200 Subject: [PATCH 1/3] Allow XBeeAddress64 to work with uint64_t variables This adds: - A constructor that takes a single uint64_t variable. This allows implicitly converting integers to XBeeAddress64 values, so these will work: XBeeAddress64 dest = 0x0; request.setAddress64(0x0013A21234567890); (note that the latter also requires some const-correctness fixes in methods taking XBeeAddress64 arguments). - A get() and set() method for getting and setting the address as a uint64_t. - A operator uint64_t() which allows the XBeeAddress64 to be implicitely converted to a uint64_t. E.g.: uint64_t address = resp.getRemoteAddress64(); But also comparison: resp.getRemoteAddress64() == XBeeAddress64(0, 0) resp.getRemoteAddress64() == 0x0013A21234567890); Note that both comparisons above work by converting to uint64_t and comparing those. Because this removes the need for separate comparison operators, the ones that were there (but still commented out) were removed. Note that avr-gcc doesn't currently optimize uint64_t values very well, so the storage is still left as two separate uint32_t values. If you use the msb/lsb accessors, code should be unchanged compared to before, but if you use the uint64_t accessors or compare addresses, code will be less efficient. This will hopefully be fixed in a future compiler version, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66511. --- XBee.cpp | 22 +++++++++++++++------- XBee.h | 12 ++++++++++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/XBee.cpp b/XBee.cpp index 20e60c7..6c3d5ea 100755 --- a/XBee.cpp +++ b/XBee.cpp @@ -1028,6 +1028,10 @@ XBeeAddress64::XBeeAddress64(uint32_t msb, uint32_t lsb) : XBeeAddress() { _lsb = lsb; } +XBeeAddress64::XBeeAddress64(uint64_t addr) : XBeeAddress() { + set(addr); +} + uint32_t XBeeAddress64::getMsb() { return _msb; } @@ -1044,14 +1048,18 @@ void XBeeAddress64::setLsb(uint32_t lsb) { _lsb = lsb; } -// contributed by user repat123 on issue tracker -//bool XBeeAddress64::operator==(XBeeAddress64 addr) { -// return ((_lsb == addr.getLsb()) && (_msb == addr.getMsb())); -//} +uint64_t XBeeAddress64::get() { + return (static_cast(_msb) << 32) | _lsb; +} -//bool XBeeAddress64::operator!=(XBeeAddress64 addr) { -// return !(*this == addr); -//} +void XBeeAddress64::set(uint64_t addr) { + _msb = addr >> 32; + _lsb = addr; +} + +XBeeAddress64::operator uint64_t() { + return get(); +} #ifdef SERIES_2 diff --git a/XBee.h b/XBee.h index ccbfc23..d422d27 100755 --- a/XBee.h +++ b/XBee.h @@ -292,18 +292,26 @@ class XBeeAddress { /** * Represents a 64-bit XBee Address + * + * Note that avr-gcc as of 4.9 doesn't optimize uint64_t very well, so + * for the smallest and fastest code, use msb and lsb separately. See + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66511 */ class XBeeAddress64 : public XBeeAddress { public: + XBeeAddress64(uint64_t addr); XBeeAddress64(uint32_t msb, uint32_t lsb); XBeeAddress64(); uint32_t getMsb(); uint32_t getLsb(); + uint64_t get(); + operator uint64_t(); void setMsb(uint32_t msb); void setLsb(uint32_t lsb); - //bool operator==(XBeeAddress64 addr); - //bool operator!=(XBeeAddress64 addr); + void set(uint64_t addr); private: + // Once https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66511 is + // fixed, it might make sense to merge these into a uint64_t. uint32_t _msb; uint32_t _lsb; }; From 50ef472ee3982b731c946dcb714aa243fe625a20 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 11 Jun 2015 19:32:14 +0200 Subject: [PATCH 2/3] Define all of XBeeAddress64 in XBee.h Since this is a utility class that should really be a very thin wrapper around the actual data, the compiler should be able to inline all operations, instead of having to do a full function call just to load or store a few bytes. This removes the explicit super-constructor calls and rewrites the constructors to use initializer lists instead of assigning values in the body (which is more consise, and allows for constexpr next) This saves up to a 30 bytes of program spaces on the supplied examples, probably more for more complex programs. --- XBee.cpp | 47 ----------------------------------------------- XBee.h | 25 ++++++++++++++----------- 2 files changed, 14 insertions(+), 58 deletions(-) diff --git a/XBee.cpp b/XBee.cpp index 6c3d5ea..10aae03 100755 --- a/XBee.cpp +++ b/XBee.cpp @@ -1014,53 +1014,6 @@ void PayloadRequest::setPayloadLength(uint8_t payloadLength) { _payloadLength = payloadLength; } - -XBeeAddress::XBeeAddress() { - -} - -XBeeAddress64::XBeeAddress64() : XBeeAddress() { - -} - -XBeeAddress64::XBeeAddress64(uint32_t msb, uint32_t lsb) : XBeeAddress() { - _msb = msb; - _lsb = lsb; -} - -XBeeAddress64::XBeeAddress64(uint64_t addr) : XBeeAddress() { - set(addr); -} - -uint32_t XBeeAddress64::getMsb() { - return _msb; -} - -void XBeeAddress64::setMsb(uint32_t msb) { - _msb = msb; -} - -uint32_t XBeeAddress64::getLsb() { - return _lsb; -} - -void XBeeAddress64::setLsb(uint32_t lsb) { - _lsb = lsb; -} - -uint64_t XBeeAddress64::get() { - return (static_cast(_msb) << 32) | _lsb; -} - -void XBeeAddress64::set(uint64_t addr) { - _msb = addr >> 32; - _lsb = addr; -} - -XBeeAddress64::operator uint64_t() { - return get(); -} - #ifdef SERIES_2 ZBTxRequest::ZBTxRequest() : PayloadRequest(ZB_TX_REQUEST, DEFAULT_FRAME_ID, NULL, 0) { diff --git a/XBee.h b/XBee.h index d422d27..761cdad 100755 --- a/XBee.h +++ b/XBee.h @@ -287,7 +287,7 @@ class XBeeResponse { class XBeeAddress { public: - XBeeAddress(); + XBeeAddress() {}; }; /** @@ -299,16 +299,19 @@ class XBeeAddress { */ class XBeeAddress64 : public XBeeAddress { public: - XBeeAddress64(uint64_t addr); - XBeeAddress64(uint32_t msb, uint32_t lsb); - XBeeAddress64(); - uint32_t getMsb(); - uint32_t getLsb(); - uint64_t get(); - operator uint64_t(); - void setMsb(uint32_t msb); - void setLsb(uint32_t lsb); - void set(uint64_t addr); + XBeeAddress64(uint64_t addr) : _msb(addr >> 32), _lsb(addr) {} + XBeeAddress64(uint32_t msb, uint32_t lsb) : _msb(msb), _lsb(lsb) {} + XBeeAddress64() {} + uint32_t getMsb() {return _msb;} + uint32_t getLsb() {return _lsb;} + uint64_t get() {return (static_cast(_msb) << 32) | _lsb;} + operator uint64_t() {return get();} + void setMsb(uint32_t msb) {_msb = msb;} + void setLsb(uint32_t lsb) {_lsb = lsb;} + void set(uint64_t addr) { + _msb = addr >> 32; + _lsb = addr; + } private: // Once https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66511 is // fixed, it might make sense to merge these into a uint64_t. From 289db61fe374b679f819f6dd3c57fa11b1d825f5 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 11 Jun 2015 19:45:21 +0200 Subject: [PATCH 3/3] Introduce constexpr for the XBeeAddress64 constructors This allows the compiler to better optimize (global) XBeeAdress64 instances. With the examples sketches, this saves between 44 and 114 bytes of program space, compiling for the Uno. Even sketches that do not directly use any addresses shrink, because the initialization of RemoteAtCommandRequest::broadcastAddress64 can be simplified. This feature requires C++11 to be enabled. This isn't currently the case (with Arduino 1.6.4), but is expected to be enabled in a future release. A preprocessor check is used to ensure that the code compiles with and without C++11. --- XBee.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/XBee.h b/XBee.h index 761cdad..06761e5 100755 --- a/XBee.h +++ b/XBee.h @@ -142,6 +142,20 @@ #define PACKET_EXCEEDS_BYTE_ARRAY_LENGTH 2 #define UNEXPECTED_START_BYTE 3 +/** + * C++11 introduced the constexpr as a hint to the compiler that things + * can be evaluated at compiletime. This can help to remove + * startup code for global objects, or otherwise help the compiler to + * optimize. Since the keyword is introduced in C++11, but supporting + * older compilers is a matter of removing the keyword, we use a macro + * for this. + */ +#if __cplusplus >= 201103L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + /** * The super class of all XBee responses (RX packets) * Users should never attempt to create an instance of this class; instead @@ -287,7 +301,7 @@ class XBeeResponse { class XBeeAddress { public: - XBeeAddress() {}; + CONSTEXPR XBeeAddress() {}; }; /** @@ -299,9 +313,9 @@ class XBeeAddress { */ class XBeeAddress64 : public XBeeAddress { public: - XBeeAddress64(uint64_t addr) : _msb(addr >> 32), _lsb(addr) {} - XBeeAddress64(uint32_t msb, uint32_t lsb) : _msb(msb), _lsb(lsb) {} - XBeeAddress64() {} + CONSTEXPR XBeeAddress64(uint64_t addr) : _msb(addr >> 32), _lsb(addr) {} + CONSTEXPR XBeeAddress64(uint32_t msb, uint32_t lsb) : _msb(msb), _lsb(lsb) {} + CONSTEXPR XBeeAddress64() : _msb(0), _lsb(0) {} uint32_t getMsb() {return _msb;} uint32_t getLsb() {return _lsb;} uint64_t get() {return (static_cast(_msb) << 32) | _lsb;}