From a8b6f137250a2913150b18c1483936ebe14f9be3 Mon Sep 17 00:00:00 2001 From: Bengt Martensson Date: Sat, 6 Feb 2021 11:26:56 +0100 Subject: [PATCH] Misc fixes and modernizations. --- Makefile | 1 + .../IrReceiverSampler/IrReceiverSampler.ino | 28 ++---- .../IrReceiverSampler_SenderPwm.ino | 89 +++++++++++++++++++ examples/IrSenderNonMod/IrSenderNonMod.ino | 8 +- examples/IrSenderPwm/IrSenderPwm.ino | 11 ++- .../IrSenderPwmSoftDelay.ino | 13 ++- .../IrSenderPwmSpinWait.ino | 19 ++-- .../LearningHashDecoder.ino | 17 ++-- examples/MicroGirs/MicroGirs.ino | 6 +- examples/MultiDecoder/MultiDecoder.ino | 4 +- examples/Nec1Decoder/Nec1Decoder.ino | 12 +-- examples/OneButtonRemote/OneButtonRemote.ino | 12 +-- examples/Pronto/Pronto.ino | 2 + examples/allreaders/allreaders.ino | 20 ++--- src/HashDecoder.cpp | 4 - src/HashDecoder.h | 9 +- src/IrDecoder.h | 10 ++- src/IrReader.h | 8 ++ src/IrReceiver.h | 6 +- src/IrSender.cpp | 12 ++- src/IrSenderNonMod.cpp | 5 ++ src/IrSenderNonMod.h | 3 +- src/IrSenderSimulator.cpp | 3 + src/IrSequence.cpp | 12 +-- src/IrSequence.h | 6 ++ src/IrSequenceReader.h | 2 +- src/IrSignal.h | 25 +++--- src/MultiDecoder.cpp | 10 +-- src/Nec1Decoder.cpp | 2 - src/Nec1Decoder.h | 1 + src/PinModeStatus.h | 11 +-- src/Pronto.cpp | 72 ++++++++------- src/Pronto.h | 16 ++-- src/Rc5Decoder.cpp | 2 - src/Rc5Decoder.h | 3 +- src/boards/NoBoard.h | 2 + tests/test1.cpp | 15 ++-- 37 files changed, 301 insertions(+), 180 deletions(-) create mode 100644 examples/IrReceiverSampler_SenderPwm/IrReceiverSampler_SenderPwm.ino diff --git a/Makefile b/Makefile index 7c5ad01..fb59476 100644 --- a/Makefile +++ b/Makefile @@ -94,6 +94,7 @@ version: $(VERSION_H) $(VERSION_H): library.properties Makefile echo "Creating $(VERSION_H)" @echo "// This file was automatically generated from $<; do not edit." > $@ + @echo "#pragma once" >> $@ @echo "/**" >> $@ @echo " * Version of the current library." >> $@ @echo " * Taken from the version in $<." >> $@ diff --git a/examples/IrReceiverSampler/IrReceiverSampler.ino b/examples/IrReceiverSampler/IrReceiverSampler.ino index 6f86318..a0fd3db 100644 --- a/examples/IrReceiverSampler/IrReceiverSampler.ino +++ b/examples/IrReceiverSampler/IrReceiverSampler.ino @@ -13,9 +13,7 @@ #endif #define BUFFERSIZE 200U -#define BAUD 115200 - -//#define DEBUG +#define BAUD 115200UL #ifdef ARDUINO_AVR_NANO #define IRRECEIVER_1_GND 6U @@ -26,7 +24,7 @@ #define IRRECEIVER_1_VCC 14 #endif -IrReceiver *receiver; +static IrReceiver *receiver; void setup() { #ifdef IRRECEIVER_1_GND @@ -45,24 +43,12 @@ void setup() { receiver = IrReceiverSampler::newIrReceiverSampler(BUFFERSIZE, RECEIVE_PIN); Serial.print("Listening on pin "); Serial.println(receiver->getPin(), DEC); - receiver->enable(); -#ifdef DEBUG_PIN - Serial.print(F("Debug pin = ")); - Serial.println(DEBUG_PIN, DEC); -#endif } void loop() { - if (receiver->isReady()) { - if (receiver->isEmpty()) - Serial.println("timeout"); - else - receiver->dump(Serial); - receiver->reset(); - } else { -#ifdef DEBUG - Serial.println("listening"); - delay(2000); -#endif - } + receiver->receive(); // combines enable, loop, disable + if (receiver->isEmpty()) + Serial.println("timeout"); + else + receiver->dump(Serial); } diff --git a/examples/IrReceiverSampler_SenderPwm/IrReceiverSampler_SenderPwm.ino b/examples/IrReceiverSampler_SenderPwm/IrReceiverSampler_SenderPwm.ino new file mode 100644 index 0000000..5b0031a --- /dev/null +++ b/examples/IrReceiverSampler_SenderPwm/IrReceiverSampler_SenderPwm.ino @@ -0,0 +1,89 @@ +// This sketch combines sending and receiving. + +#include +#include +#include + +#ifdef ESP32 +#define RECEIVE_PIN 4U +#elif defined(ESP8266) +#define RECEIVE_PIN 2U +#elif defined(ARDUINO_AVR_MICRO) +#define RECEIVE_PIN 10 +#elif defined (ARDUINO_TEENSY32) // Teenex 3.1-3.2 +#define RECEIVE_PIN 7U +#else +#define RECEIVE_PIN 5U +#endif + +#define BUFFERSIZE 200U +#define BAUD 115200 + +#ifdef ARDUINO_AVR_NANO +#define IRRECEIVER_1_GND 6U +#define IRRECEIVER_1_VCC 7U +#endif + +#ifdef ARDUINO_AVR_MICRO +#define IRRECEIVER_1_GND 16U +#define IRRECEIVER_1_VCC 14U +#endif + +static constexpr frequency_t necFrequency = 38400U; + +// NEC(1) 122 29 with no repetition; powers on many Yamaha receivers +static const microseconds_t array[] +#if HAS_FLASH_READ + PROGMEM +#endif + = { + 9024, 4512, 564, 564, 564, 1692, 564, 564, 564, 1692, 564, 1692, + 564, 1692, 564, 1692, 564, 564, 564, 1692, 564, 564, 564, 1692, + 564, 564, 564, 564, 564, 564, 564, 564, 564, 1692, 564, 1692, 564, + 564, 564, 1692, 564, 1692, 564, 1692, 564, 564, 564, 564, 564, 564, + 564, 564, 564, 1692, 564, 564, 564, 564, 564, 564, 564, 1692, 564, + 1692, 564, 1692, 564, 39756 +}; + +static const IrSequence* irSequence = +#if HAS_FLASH_READ + IrSequence::readFlash(array, sizeof (array) / sizeof (microseconds_t)); +#else + new IrSequence(array, sizeof (array) / sizeof (microseconds_t)); +#endif +static IrReceiver *receiver; + +void setup() { +#ifdef IRRECEIVER_1_GND + pinMode(IRRECEIVER_1_GND, OUTPUT); + digitalWrite(IRRECEIVER_1_GND, LOW); +#endif + +#ifdef IRRECEIVER_1_VCC + pinMode(IRRECEIVER_1_VCC, OUTPUT); + digitalWrite(IRRECEIVER_1_VCC, HIGH); +#endif + + Serial.begin(BAUD); + while(!Serial) + ; +#if HAS_FLASH_READ + Serial.println(F("Sending a signal from PROGMEM!")); +#else + Serial.println(F("Sending a signal!")); +#endif + IrSender *sender = IrSenderPwm::getInstance(true); + sender->send(*irSequence, necFrequency); + + receiver = IrReceiverSampler::newIrReceiverSampler(BUFFERSIZE, RECEIVE_PIN); + Serial.println(F("Listening!")); + receiver->enable(); +} + +void loop() { + receiver->receive(); // combines enable, loop, disable + if (receiver->isEmpty()) { + Serial.println("timeout"); + } else + receiver->dump(Serial); +} diff --git a/examples/IrSenderNonMod/IrSenderNonMod.ino b/examples/IrSenderNonMod/IrSenderNonMod.ino index d695aab..4ba8f1f 100644 --- a/examples/IrSenderNonMod/IrSenderNonMod.ino +++ b/examples/IrSenderNonMod/IrSenderNonMod.ino @@ -5,7 +5,7 @@ #include -#define NON_MOD_PIN 10U +static constexpr pin_t NON_MOD_PIN = 10U; // Arctech D=13, S=8, F=0 (Generated by IrScrutinizer) static const microseconds_t offData[] = { @@ -33,10 +33,8 @@ void setup() { void loop() { // send it twice, since Intertechno devices seems to need that // for reliability - sender.sendNonModulated(on); - sender.sendNonModulated(on); + sender.sendNonModulated(on, 2); delay(2000); - sender.sendNonModulated(off); - sender.sendNonModulated(off); + sender.sendNonModulated(off, 2); delay(2000); } diff --git a/examples/IrSenderPwm/IrSenderPwm.ino b/examples/IrSenderPwm/IrSenderPwm.ino index 8b7e6b5..a43409e 100644 --- a/examples/IrSenderPwm/IrSenderPwm.ino +++ b/examples/IrSenderPwm/IrSenderPwm.ino @@ -5,9 +5,9 @@ #include -static const frequency_t necFrequency = 38400U; -static const unsigned long BAUD = 115200U; -static const pin_t PIN = 3U; +static constexpr frequency_t necFrequency = 38400U; +static constexpr unsigned long BAUD = 115200UL; +static constexpr pin_t PIN = 3U; // NEC(1) 122 29 with no repetition; powers on many Yamaha receivers static const microseconds_t array[] = { @@ -20,8 +20,7 @@ static const microseconds_t array[] = { }; static const IrSequence irSequence(array, sizeof(array) / sizeof(microseconds_t)); -static dutycycle_t dutyCycle; -IrSender* irSender; +static IrSender* irSender; void setup() { Serial.begin(BAUD); @@ -32,11 +31,11 @@ void setup() { else Serial.println(F("Hardware PWM NOT available, will be emulated in software.")); randomSeed(analogRead(A0)); - dutyCycle = (dutycycle_t) random(20,80); irSender = IrSenderPwm::getInstance(true, PIN); } void loop() { + dutycycle_t dutyCycle;dutyCycle = static_cast(random(20,80)); Serial.print(F("Shooting @ pin ")); Serial.print(irSender->getPin(), DEC); Serial.print(F(" with duty cycle ")); diff --git a/examples/IrSenderPwmSoftDelay/IrSenderPwmSoftDelay.ino b/examples/IrSenderPwmSoftDelay/IrSenderPwmSoftDelay.ino index e273dc8..6e1209d 100644 --- a/examples/IrSenderPwmSoftDelay/IrSenderPwmSoftDelay.ino +++ b/examples/IrSenderPwmSoftDelay/IrSenderPwmSoftDelay.ino @@ -3,9 +3,14 @@ #include -static const frequency_t necFrequency = 38400U; -static const pin_t pin = 4U; // D2 on ESP8266 -static const uint32_t BAUD = 115200UL; +static constexpr frequency_t necFrequency = 38400U; +static constexpr pin_t pin = +#ifdef ESP8266 + 4U; // D2 on ESP8266 +#else + 3U; +#endif +static constexpr uint32_t BAUD = 115200UL; // NEC(1) 122 29 with no repetition; powers on many Yamaha receivers static const microseconds_t array[] = { @@ -18,7 +23,7 @@ static const microseconds_t array[] = { }; static const IrSequence irSequence(array, sizeof(array) / sizeof(microseconds_t)); -IrSender* irSender; +static IrSender* irSender; void setup() { Serial.begin(BAUD); diff --git a/examples/IrSenderPwmSpinWait/IrSenderPwmSpinWait.ino b/examples/IrSenderPwmSpinWait/IrSenderPwmSpinWait.ino index 2d08ff2..3482322 100644 --- a/examples/IrSenderPwmSpinWait/IrSenderPwmSpinWait.ino +++ b/examples/IrSenderPwmSpinWait/IrSenderPwmSpinWait.ino @@ -1,11 +1,18 @@ // This sketch sends a raw signal using the soft PWM sender every 5 seconds. // It requires an IR-Led connected to the sending pin +// On slow processors, it may produce erroneous result, +// in particular modulation frequency. #include -static const frequency_t necFrequency = 38400U; -static const pin_t pin = 4U; // D2 on ESP8266 -static const unsigned long BAUD = 115200UL; +static constexpr frequency_t necFrequency = 38400U; +static constexpr pin_t pin = +#ifdef ESP8266 + 4U; // D2 on ESP8266 +#else + 3U; +#endif +static constexpr uint32_t BAUD = 115200UL; // NEC(1) 122 29 with no repetition; powers on many Yamaha receivers static const microseconds_t array[] = { @@ -18,7 +25,7 @@ static const microseconds_t array[] = { }; static const IrSequence irSequence(array, sizeof(array) / sizeof(microseconds_t)); -IrSender* irSender; +static IrSender* irSender; void setup() { Serial.begin(BAUD); @@ -28,8 +35,8 @@ void setup() { } void loop() { - Serial.print("sending on pin "); + Serial.print(F(" sending @ pin ")); Serial.println(pin, DEC); - irSender->send(irSequence, necFrequency, 33U); + irSender->send(irSequence, necFrequency); delay(5000); } diff --git a/examples/LearningHashDecoder/LearningHashDecoder.ino b/examples/LearningHashDecoder/LearningHashDecoder.ino index fefa918..858a456 100644 --- a/examples/LearningHashDecoder/LearningHashDecoder.ino +++ b/examples/LearningHashDecoder/LearningHashDecoder.ino @@ -1,9 +1,10 @@ #include #include -#define RECEIVE_PIN 5U -#define BUFFERSIZE 200U -#define BAUD 115200 +static constexpr pin_t RECEIVE_PIN = 5U; +static constexpr size_t BUFFERSIZE = 200U; +static constexpr uint32_t BAUD = 115200UL; +static constexpr uint32_t NecRepeatHash = 84696351UL; //#define DEBUG @@ -24,11 +25,9 @@ public : Command(const char* n, uint32_t c) : name(n),code(c) {} }; -unsigned numberCommands = sizeof (names) / sizeof (const char*); - +static constexpr unsigned numberCommands = sizeof(names) / sizeof(const char*); static Command *learnedCommands; - -IrReceiver *receiver; +static IrReceiver *receiver; void setup() { Serial.begin(BAUD); @@ -80,14 +79,14 @@ void setup() { void loop() { do - receiver->receive(); + receiver->receive(); while (receiver->isEmpty()); uint32_t hash = HashDecoder::decodeHash(*receiver); #ifdef DEBUG Serial.println(hash); #endif - if (hash == 84696351) // NEC1 repeat, discard + if (hash == NecRepeatHash) // NEC1 repeat, discard return; for (unsigned i = 0; i < numberCommands; i++) { diff --git a/examples/MicroGirs/MicroGirs.ino b/examples/MicroGirs/MicroGirs.ino index 23439fc..2f5e1ea 100644 --- a/examples/MicroGirs/MicroGirs.ino +++ b/examples/MicroGirs/MicroGirs.ino @@ -377,9 +377,9 @@ static bool processCommand(const String& line, Stream& stream) { uint16_t introLength = (uint16_t) tokenizer.getInt(); uint16_t repeatLength = (uint16_t) tokenizer.getInt(); uint16_t endingLength = (uint16_t) tokenizer.getInt(); - microseconds_t intro[introLength]; - microseconds_t repeat[repeatLength]; - microseconds_t ending[endingLength]; + microseconds_t *intro = new microseconds_t[introLength]; + microseconds_t *repeat = new microseconds_t[repeatLength]; + microseconds_t *ending = new microseconds_t[endingLength]; for (uint16_t i = 0; i < introLength; i++) intro[i] = tokenizer.getMicroseconds(); for (uint16_t i = 0; i < repeatLength; i++) diff --git a/examples/MultiDecoder/MultiDecoder.ino b/examples/MultiDecoder/MultiDecoder.ino index cfa08fb..6e54ecf 100644 --- a/examples/MultiDecoder/MultiDecoder.ino +++ b/examples/MultiDecoder/MultiDecoder.ino @@ -6,7 +6,7 @@ #define RECEIVE_PIN 5U #define BUFFERSIZE 200U -#define BAUD 115200 +#define BAUD 115200UL IrReceiver *receiver; @@ -22,7 +22,7 @@ void loop() { Serial.println(F("timeout")); else { MultiDecoder decoder(*receiver); - if (decoder.isValid()) + if (decoder) decoder.printDecode(Serial); else Serial.println(F("No decode")); diff --git a/examples/Nec1Decoder/Nec1Decoder.ino b/examples/Nec1Decoder/Nec1Decoder.ino index 2817ff4..84dbe11 100644 --- a/examples/Nec1Decoder/Nec1Decoder.ino +++ b/examples/Nec1Decoder/Nec1Decoder.ino @@ -1,17 +1,19 @@ // This sketch uses the IrReceiveSampler to receive a signal, and tries to -// decode it as a NEC1 signal +// decode it as a NEC signal #include #include #define RECEIVE_PIN 5U #define BUFFERSIZE 200U -#define BAUD 115200 +#define BAUD 115200UL -IrReceiver *receiver; +static IrReceiver *receiver; void setup() { Serial.begin(BAUD); + while (!Serial) + ; receiver = IrReceiverSampler::newIrReceiverSampler(BUFFERSIZE, RECEIVE_PIN); } @@ -22,9 +24,9 @@ void loop() { Serial.println(F("timeout")); else { Nec1Decoder decoder(*receiver); - if (decoder.isValid()) + if (decoder) decoder.printDecode(Serial); else - Serial.println(F("No decode")); + Serial.println(F("No decode as NEC")); } } diff --git a/examples/OneButtonRemote/OneButtonRemote.ino b/examples/OneButtonRemote/OneButtonRemote.ino index ff3572f..8341a82 100644 --- a/examples/OneButtonRemote/OneButtonRemote.ino +++ b/examples/OneButtonRemote/OneButtonRemote.ino @@ -9,22 +9,22 @@ #include // where the switch is connected -const pin_t button = 4; +static constexpr pin_t button = 4U; -const IrSignal *irSignal; -const IrSender *irSender; +static const IrSignal *irSignal; +static const IrSender *irSender; -bool buttonIsPressed() { +static bool buttonIsPressed() { return digitalRead(button) == LOW; } void setup() { // Define switch as input, using pullup to Vcc pinMode(button, INPUT_PULLUP); - + // Set up the sender irSender = IrSenderPwm::getInstance(true); - + // Set up the signal irSignal = Nec1Renderer::newIrSignal(122, 27); // volume_down for Yamaha receivers } diff --git a/examples/Pronto/Pronto.ino b/examples/Pronto/Pronto.ino index 75bcef5..611d744 100644 --- a/examples/Pronto/Pronto.ino +++ b/examples/Pronto/Pronto.ino @@ -32,6 +32,8 @@ void setup() { irSignal = Nec1Renderer::newIrSignal(122, 27); // volume_down for Yahama receivers Serial.println(Pronto::toProntoHex(*irSignal)); + Pronto::dump(Serial, *irSignal); + Serial.println(); } void loop() { diff --git a/examples/allreaders/allreaders.ino b/examples/allreaders/allreaders.ino index c17e636..e4aab6a 100644 --- a/examples/allreaders/allreaders.ino +++ b/examples/allreaders/allreaders.ino @@ -3,26 +3,26 @@ #include #include -IrReader *reader; -const unsigned int captureLength = 200; -const pin_t receiverPin = 5; -const microseconds_t markExcess = 50; +static IrReader *reader; +constexpr unsigned int captureLength = 200U; +constexpr pin_t receiverPin = 5U; +constexpr microseconds_t markExcess = 50U; void setup() { - Serial.begin(115200); - Serial.setTimeout(10000); + Serial.begin(115200UL); + Serial.setTimeout(10000U); Serial.flush(); Serial.println(F("Enter s for sampler, p for poll, w for widget")); String line = Serial.readStringUntil('\r'); char ch = line.charAt(0); Serial.println(F("Enter beginning timeout in milliseconds (default 5000)")); long beginningTimeout = Serial.parseInt(); - if (beginningTimeout == 0) - beginningTimeout = 5000; + if (beginningTimeout == 0U) + beginningTimeout = 5000U; Serial.println(F("Enter ending timeout in milliseconds (default 30)")); long endingTimeout = Serial.parseInt(); - if (endingTimeout == 0) - endingTimeout = 30; + if (endingTimeout == 0U) + endingTimeout = 30U; reader = ch == 's' ? (IrReader*) IrReceiverSampler::newIrReceiverSampler(captureLength, receiverPin, diff --git a/src/HashDecoder.cpp b/src/HashDecoder.cpp index d4781db..790b6c3 100644 --- a/src/HashDecoder.cpp +++ b/src/HashDecoder.cpp @@ -1,9 +1,5 @@ #include "HashDecoder.h" -const char *HashDecoder::format = "%0x"; - -constexpr unsigned int offset = 2; - uint32_t HashDecoder::compare(microseconds_t oldVal, microseconds_t newVal) { return newVal < 3 * (oldVal / 4) ? 0 diff --git a/src/HashDecoder.h b/src/HashDecoder.h index 89ef464..de2537e 100644 --- a/src/HashDecoder.h +++ b/src/HashDecoder.h @@ -38,7 +38,8 @@ class HashDecoder : public IrDecoder { decode(irSignal.getEnding()); } - static const char *format; + static constexpr unsigned int offset = 2; + static constexpr const char *format = "%0lx"; static constexpr uint32_t FNVprime = 16777619UL; static constexpr uint32_t FNVoffsetBasis = 2166136261UL; static constexpr unsigned int minMeaningfulLength = 4U; @@ -61,7 +62,7 @@ class HashDecoder : public IrDecoder { */ HashDecoder(const IrReader& irReader) : IrDecoder(),hash(FNVoffsetBasis) { decode(irReader); - sprintf(decodeBuffer, format, hash); + sprintf(decodeBuffer, format, static_cast(hash)); } /** @@ -70,12 +71,12 @@ class HashDecoder : public IrDecoder { */ HashDecoder(const IrSequence& irSequence) : IrDecoder(),hash(FNVoffsetBasis) { decode(irSequence); - sprintf(decodeBuffer, format, hash); + sprintf(decodeBuffer, format, static_cast(hash)); } HashDecoder(const IrSignal& irSignal) : IrDecoder(),hash(FNVoffsetBasis) { decode(irSignal); - sprintf(decodeBuffer, format, hash); + sprintf(decodeBuffer, format, static_cast(hash)); } /** diff --git a/src/IrDecoder.h b/src/IrDecoder.h index 6c7ab23..4c7507d 100644 --- a/src/IrDecoder.h +++ b/src/IrDecoder.h @@ -32,6 +32,14 @@ class IrDecoder { return valid; } + /** + * Same as isValid(). + * @return + */ + operator bool() const { + return isValid(); + } + /** * If valid, prints the decode to the stream. * @param stream where the output is generated @@ -44,7 +52,7 @@ class IrDecoder { } private: - constexpr static uint32_t endingMin = 20000U; + static constexpr uint32_t endingMin = 20000UL; bool valid = false; protected: diff --git a/src/IrReader.h b/src/IrReader.h index ef76125..0b917cd 100644 --- a/src/IrReader.h +++ b/src/IrReader.h @@ -105,6 +105,14 @@ class IrReader { */ virtual bool isReady() const = 0; + /** + * Same as isReady() + * @return + */ + operator bool() const { + return isReady(); + } + /** * Returns the number of collected durations. * @return number durations diff --git a/src/IrReceiver.h b/src/IrReceiver.h index cbcb1f0..e11ac3d 100644 --- a/src/IrReceiver.h +++ b/src/IrReceiver.h @@ -16,11 +16,11 @@ class IrReceiver : public IrReader { public: // Default values - static const pin_t defaultPin = 5; - static const microseconds_t defaultMarkExcess = 50U; + static constexpr pin_t defaultPin = 5; + static constexpr microseconds_t defaultMarkExcess = 50U; /** Are we using inverting sensor, like most TSOPs? */ - static const bool invertingSensor = true; + static constexpr bool invertingSensor = true; /** * Constructor. diff --git a/src/IrSender.cpp b/src/IrSender.cpp index c0446f9..b74fd04 100644 --- a/src/IrSender.cpp +++ b/src/IrSender.cpp @@ -28,12 +28,10 @@ IrSender::~IrSender() { } void IrSender::sendIrSignal(const IrSignal& irSignal, unsigned int noSends) { - if (!irSignal.getIntro().isEmpty()) - send(irSignal.getIntro(), irSignal.getFrequency()); + send(irSignal.getIntro(), irSignal.getFrequency()); for (unsigned int i = 0; i < irSignal.noRepetitions(noSends); i++) send(irSignal.getRepeat(), irSignal.getFrequency()); - if (!irSignal.getEnding().isEmpty()) - send(irSignal.getEnding(), irSignal.getFrequency()); + send(irSignal.getEnding(), irSignal.getFrequency()); } void IrSender::sendWhile(const IrSignal& irSignal, bool(*trigger)()) { @@ -63,14 +61,14 @@ void IrSender::send(const IrSequence& irSequence, frequency_t frequency, dutycyc #endif for (unsigned int i = 0U; i < irSequence.getLength(); i++) { #ifdef CONSIDER_COMPUTATIONAL_DELAYS -#error dssdfsdfsdf - microseconds_t duration = irSequence.getDurations()[i]; +#error not tested + microseconds_t duration = irSequence[i]; refTime += duration; int32_t delay = refTime - micros(); // TODO verify overflow if (delay <= 0) return; #else - microseconds_t delay = irSequence.getDurations()[i]; + microseconds_t delay = irSequence[i]; #endif if (i & 1U) sendSpace(delay); diff --git a/src/IrSenderNonMod.cpp b/src/IrSenderNonMod.cpp index 5f5f2fe..2a1f2db 100644 --- a/src/IrSenderNonMod.cpp +++ b/src/IrSenderNonMod.cpp @@ -20,6 +20,11 @@ this program. If not, see http://www.gnu.org/licenses/. IrSenderNonMod::IrSenderNonMod(pin_t pin, bool _invert) : IrSender(pin),invert(_invert) { } +void IrSenderNonMod::sendNonModulated(const IrSequence& irSequence, unsigned int times) { + for (unsigned int i = 0; i < times; i++) + send(irSequence); +} + void IrSenderNonMod::sendSpace(microseconds_t time) { if (invert) writeHigh(); diff --git a/src/IrSenderNonMod.h b/src/IrSenderNonMod.h index a03aae7..a3db6a9 100644 --- a/src/IrSenderNonMod.h +++ b/src/IrSenderNonMod.h @@ -39,6 +39,7 @@ class IrSenderNonMod : public IrSender { /** * Sends the IrSequence as argument. * @param irSequence + * @param times Number of times to send, default 1. */ - void sendNonModulated(const IrSequence& irSequence) { send(irSequence); } + void sendNonModulated(const IrSequence& irSequence, unsigned int times = 1U); }; diff --git a/src/IrSenderSimulator.cpp b/src/IrSenderSimulator.cpp index 976556a..4cd25fe 100644 --- a/src/IrSenderSimulator.cpp +++ b/src/IrSenderSimulator.cpp @@ -1,6 +1,9 @@ #include "IrSenderSimulator.h" void IrSenderSimulator::send(const IrSequence& irSequence, frequency_t frequency, dutycycle_t dutyCycle) { + if (! irSequence) + return; + stream.print(F("IrSenderSimulator: ")); bool printedSomething = IrSignal::dumpFrequency(stream, frequency); if (printedSomething) diff --git a/src/IrSequence.cpp b/src/IrSequence.cpp index dac4830..bdf121c 100644 --- a/src/IrSequence.cpp +++ b/src/IrSequence.cpp @@ -18,11 +18,13 @@ IrSequence::IrSequence(const IrSequence& orig) : length(orig.length) { } IrSequence& IrSequence::operator=(IrSequence&& rhs) { - delete [] durations; - durations = rhs.durations; - length = rhs.length; - rhs.durations = nullptr; - rhs.length = 0; + if (this != &rhs) { + delete [] durations; + durations = rhs.durations; + length = rhs.length; + rhs.durations = nullptr; + rhs.length = 0; + } return *this; } diff --git a/src/IrSequence.h b/src/IrSequence.h index 3866e79..206a9bc 100644 --- a/src/IrSequence.h +++ b/src/IrSequence.h @@ -52,6 +52,12 @@ class IrSequence { static const IrSequence emptyInstance; + /** + * True if and only if non-empty. + * @return + */ + operator bool() const { return ! isEmpty(); } + /** * Returns the number of durations. * @return length diff --git a/src/IrSequenceReader.h b/src/IrSequenceReader.h index 67d3168..0cf1389 100644 --- a/src/IrSequenceReader.h +++ b/src/IrSequenceReader.h @@ -43,6 +43,6 @@ class IrSequenceReader : public IrReader { }; microseconds_t getDuration(unsigned int index) const { - return irSequence.getDurations()[index]; + return irSequence[index]; }; }; diff --git a/src/IrSignal.h b/src/IrSignal.h index 865a584..d2d09ba 100644 --- a/src/IrSignal.h +++ b/src/IrSignal.h @@ -2,6 +2,7 @@ #include "InfraredTypes.h" #include "IrSequence.h" +#include "version.h" /** * This class models an IR signal with intro-, repeat-, and ending sequences. @@ -9,10 +10,11 @@ */ class IrSignal { public: - static const frequency_t defaultFrequency = 38000U; - static const frequency_t invalidFrequency = static_cast(-1); - static const dutycycle_t noDutyCycle = static_cast(-1); - static const dutycycle_t defaultDutyCycle = noDutyCycle; + static constexpr frequency_t defaultFrequency = 38000U; + static constexpr frequency_t invalidFrequency = static_cast(-1); + static constexpr dutycycle_t noDutyCycle = static_cast(-1); + static constexpr dutycycle_t defaultDutyCycle = noDutyCycle; + static constexpr const char *version = VERSION; private: // Maintainer note: the members being const prohibits assignment operators. @@ -30,11 +32,8 @@ class IrSignal { IrSignal() {}; IrSignal(const IrSignal& orig) = default; IrSignal(IrSignal&& orig) = default; - -#ifndef DOXYGEN - IrSignal& operator=(const IrSignal& rhs) = delete; - IrSignal& operator=(IrSignal&& rhs) = delete; -#endif // ! DOXYGEN + IrSignal& operator=(const IrSignal& rhs) = default; + IrSignal& operator=(IrSignal&& rhs) = default; virtual ~IrSignal() {}; @@ -152,6 +151,12 @@ class IrSignal { return intro; } + /** + * True if and only if at least one of the sequences is true (= non-empty). + * @return + */ + operator bool() const { return intro || repeat || ending; } + /** * Print a human readable representation of the IrSignal on the Stream supplied. * @param stream Stream onto the output is printed. @@ -207,6 +212,6 @@ class IrSignal { */ unsigned int noRepetitions(unsigned int noSends) const { return noSends == 0 ? 0 - : getIntro().isEmpty() ? noSends : noSends - 1; + : intro ? noSends -1 : noSends; } }; diff --git a/src/MultiDecoder.cpp b/src/MultiDecoder.cpp index 477e46d..f844360 100644 --- a/src/MultiDecoder.cpp +++ b/src/MultiDecoder.cpp @@ -3,20 +3,20 @@ #include "Rc5Decoder.h" #include -MultiDecoder::MultiDecoder(const IrReader &IrReader) { - if (IrReader.isEmpty()) { +MultiDecoder::MultiDecoder(const IrReader &irReader) { + if (! irReader) { type = timeout; strcpy(decode, "."); return; } - if (IrReader.getDataLength() < 3) { + if (irReader.getDataLength() < 3) { type = noise; strcpy(decode, ":"); return; } - Nec1Decoder nec1decoder(IrReader); + Nec1Decoder nec1decoder(irReader); if (nec1decoder.isValid()) { strcpy(decode, nec1decoder.getDecode()); type = nec1decoder.isDitto() ? nec_ditto : nec; @@ -24,7 +24,7 @@ MultiDecoder::MultiDecoder(const IrReader &IrReader) { return; } - Rc5Decoder rc5decoder(IrReader); + Rc5Decoder rc5decoder(irReader); if (rc5decoder.isValid()) { strcpy(decode, rc5decoder.getDecode()); type = rc5; diff --git a/src/Nec1Decoder.cpp b/src/Nec1Decoder.cpp index cb98f48..821c256 100644 --- a/src/Nec1Decoder.cpp +++ b/src/Nec1Decoder.cpp @@ -5,8 +5,6 @@ //{38.4k,564}<1,-1|1,-3>(16,-8,D:8,S:8,F:8,~F:8,1,^108m,(16,-4,1,^108m)*) [D:0..255,S:0..255=255-D,F:0..255] -static const char nec1DittoLiteral[] = "NEC1 ditto"; - int Nec1Decoder::decodeFlashGap(microseconds_t flash, microseconds_t gap) { bool result = getDuration(flash, 1); if (!result) diff --git a/src/Nec1Decoder.h b/src/Nec1Decoder.h index 1974054..6e6af57 100644 --- a/src/Nec1Decoder.h +++ b/src/Nec1Decoder.h @@ -26,6 +26,7 @@ class Nec1Decoder : public IrDecoder { } static int decodeParameter(const IrReader &irCapturer, unsigned int index); static int decodeFlashGap(microseconds_t flash, microseconds_t gap); + static constexpr const char *nec1DittoLiteral = "NEC1 ditto"; public: Nec1Decoder(); diff --git a/src/PinModeStatus.h b/src/PinModeStatus.h index d51af07..383ee0b 100644 --- a/src/PinModeStatus.h +++ b/src/PinModeStatus.h @@ -16,14 +16,15 @@ this program. If not, see http://www.gnu.org/licenses/. */ /** - * TODO + * This file defines the enums PinStatus and PinMode unless already known. */ #pragma once -#if !defined(ARDUINO) || defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_SAMD) \ - || defined(ARDUINO_ARCH_SAM) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_ESP32) \ - || defined(ARDUINO_ARCH_ESP8266) +//#if defined(ARDUINO) && defined(ARDUINO_ARCH_AVR) +//// PinStatus and PinMode already defined in +//// ~/.arduino15/packages/arduino/hardware/megaavr/*/cores/arduino/api/Common.h +//#else #ifdef LOW #undef LOW @@ -76,4 +77,4 @@ typedef enum { INPUT_PULLDOWN = 0x3, } PinMode; -#endif +//#endif diff --git a/src/Pronto.cpp b/src/Pronto.cpp index 1f6ddba..045391f 100644 --- a/src/Pronto.cpp +++ b/src/Pronto.cpp @@ -3,6 +3,10 @@ #include "Board.h" // for HAS_FLASH_READ #include +inline uint16_t divRound(microseconds_t duration, microseconds_t timebase) { + return static_cast((static_cast(duration) + timebase / 2) / timebase); +} + IrSignal *Pronto::parse(const uint16_t *data, size_t size) { microseconds_t timebase = (microsecondsInSeconds * data[1] + referenceFrequency/2) / referenceFrequency; frequency_t frequency; @@ -21,15 +25,10 @@ IrSignal *Pronto::parse(const uint16_t *data, size_t size) { if (numbersInPreamble + 2*(introPairs + repetitionPairs) != size) // inconsistent sizes return nullptr; - IrSequence *intro = mkSequence(data + numbersInPreamble, introPairs, timebase); - IrSequence *repeat = mkSequence(data + numbersInPreamble + 2*introPairs, repetitionPairs, timebase); - - IrSignal *code = new IrSignal(*intro, *repeat, frequency); + microseconds_t* intro = mkSequence(data + numbersInPreamble, introPairs, timebase); + microseconds_t* repeat = mkSequence(data + numbersInPreamble + 2*introPairs, repetitionPairs, timebase); - delete intro; - delete repeat; - - return code; + return new IrSignal(intro, 2*introPairs, repeat, 2*repetitionPairs, frequency); } IrSignal *Pronto::parse(const char *str) { @@ -69,13 +68,13 @@ IrSignal *Pronto::parse(const __FlashStringHelper *str) { } #endif -IrSequence *Pronto::mkSequence(const uint16_t* data, size_t noPairs, microseconds_t timebase) { +microseconds_t* Pronto::mkSequence(const uint16_t* data, size_t noPairs, microseconds_t timebase) { microseconds_t *durations = new microseconds_t[2*noPairs]; for (unsigned int i = 0; i < 2*noPairs; i++) { uint32_t duration = static_cast(data[i]) * timebase; durations[i] = (duration <= MICROSECONDS_T_MAX) ? duration : MICROSECONDS_T_MAX; } - return new IrSequence(durations, 2*noPairs); + return durations; } frequency_t Pronto::toFrequency(uint16_t code) { @@ -102,45 +101,43 @@ char Pronto::hexDigit(unsigned int x) { return x <= 9 ? ('0' + x) : ('A' + (x - 10)); } -unsigned int Pronto::appendChar(char *result, unsigned int index, char ch) { +void Pronto::appendChar(char *result, unsigned int& index, char ch) { result[index] = ch; index++; - return index; } -unsigned int Pronto::appendDigit(char *result, unsigned int index, unsigned int number) { - return appendChar(result, index, hexDigit(number)); +void Pronto::appendDigit(char *result, unsigned int& index, unsigned int number) { + appendChar(result, index, hexDigit(number)); } -unsigned int Pronto::appendNumber(char *result, unsigned int index, uint16_t number) { +void Pronto::appendNumber(char *result, unsigned int& index, uint16_t number) { for (unsigned int i = 0; i < digitsInProntoNumber; i++) { unsigned int shifts = bitsInHexadecimal * (digitsInProntoNumber - 1 - i); - index = appendDigit(result, index, (number >> shifts) & hexMask); + appendDigit(result, index, (number >> shifts) & hexMask); } - return appendChar(result, index, ' '); + appendChar(result, index, ' '); } -unsigned int Pronto::appendDuration(char *result, unsigned int index, microseconds_t duration, microseconds_t timebase) { - return appendNumber(result, index, (duration + timebase/2) / timebase); +void Pronto::appendDuration(char *result, unsigned int& index, microseconds_t duration, microseconds_t timebase) { + appendNumber(result, index, divRound(duration, timebase)); } -unsigned int Pronto::appendSequence(char *result, unsigned int index, const microseconds_t *data, size_t length, microseconds_t timebase) { +void Pronto::appendSequence(char *result, unsigned int& index, const microseconds_t *data, size_t length, microseconds_t timebase) { for (unsigned int i = 0; i < length; i++) - index = appendDuration(result, index, data[i], timebase); - return index; + appendDuration(result, index, data[i], timebase); } -unsigned int Pronto::appendSequence(char *result, unsigned int index, const IrSequence& irSequence, microseconds_t timebase) { - return appendSequence(result, index, irSequence.getDurations(), irSequence.getLength(), timebase); +void Pronto::appendSequence(char *result, unsigned int& index, const IrSequence& irSequence, microseconds_t timebase) { + appendSequence(result, index, irSequence.getDurations(), irSequence.getLength(), timebase); } char* Pronto::prelude(frequency_t frequency, size_t introLength, size_t repeatLength) { char *result = new char[lengthHexString(introLength, repeatLength)]; unsigned int index = 0; - index = appendNumber(result, index, frequency > 0 ? learnedToken : learnedNonModulatedToken); - index = appendNumber(result, index, toFrequencyCode(frequency)); - index = appendNumber(result, index, introLength / 2); - index = appendNumber(result, index, repeatLength / 2); + appendNumber(result, index, frequency > 0 ? learnedToken : learnedNonModulatedToken); + appendNumber(result, index, toFrequencyCode(frequency)); + appendNumber(result, index, introLength / 2); + appendNumber(result, index, repeatLength / 2); return result; } @@ -148,29 +145,37 @@ char* Pronto::toProntoHex(const microseconds_t* introData, size_t introLength, c char *result = prelude(frequency, introLength, repeatLength); unsigned int index = numbersInPreamble * (digitsInProntoNumber + 1); microseconds_t timebase = toTimebase(frequency); - index = appendSequence(result, index, introData, introLength, timebase); - index = appendSequence(result, index, repeatData, repeatLength, timebase); - appendChar(result, index - 1, '\0'); + appendSequence(result, index, introData, introLength, timebase); + appendSequence(result, index, repeatData, repeatLength, timebase); + result[index - 1] = '\0'; return result; } void Pronto::dump(Stream& stream, const microseconds_t* introData, size_t introLength, const microseconds_t* repeatData, size_t repeatLength, frequency_t frequency) { dumpNumber(stream, frequency > 0 ? learnedToken : learnedNonModulatedToken); + stream.print(' '); dumpNumber(stream, toFrequencyCode(frequency)); + stream.print(' '); dumpNumber(stream, introLength / 2); + stream.print(' '); dumpNumber(stream, repeatLength / 2); + stream.print(' '); microseconds_t timebase = toTimebase(frequency); dumpSequence(stream, introData, introLength, timebase); + stream.print(' '); dumpSequence(stream, repeatData, repeatLength, timebase); } void Pronto::dumpSequence(Stream& stream, const microseconds_t *data, size_t length, microseconds_t timebase) { - for (unsigned int i = 0; i < length; i++) + for (unsigned int i = 0; i < length; i++) { dumpDuration(stream, data[i], timebase); + if (i < length - 1) + stream.print(' '); + } } void Pronto::dumpDuration(Stream& stream, microseconds_t duration, microseconds_t timebase) { - dumpNumber(stream, (duration + timebase / 2) / timebase); + dumpNumber(stream, divRound(duration, timebase)); } void Pronto::dumpNumber(Stream& stream, uint16_t number) { @@ -178,7 +183,6 @@ void Pronto::dumpNumber(Stream& stream, uint16_t number) { unsigned int shifts = bitsInHexadecimal * (digitsInProntoNumber - 1 - i); dumpDigit(stream, (number >> shifts) & hexMask); } - stream.print(' '); } void Pronto::dumpDigit(Stream& stream, unsigned int number) { diff --git a/src/Pronto.h b/src/Pronto.h index 4ddf5e8..83ddfd2 100644 --- a/src/Pronto.h +++ b/src/Pronto.h @@ -30,9 +30,9 @@ class Pronto { static constexpr frequency_t fallbackFrequency = 64767U; // To use with frequency = 0; static constexpr uint32_t microsecondsInSeconds = 1000000UL; - Pronto() {}; + Pronto() = delete; - static IrSequence *mkSequence(const uint16_t *data, size_t pairs, microseconds_t timebase); + static microseconds_t* mkSequence(const uint16_t *data, size_t pairs, microseconds_t timebase); static frequency_t toFrequency(uint16_t code); @@ -48,17 +48,17 @@ class Pronto { static char hexDigit(unsigned int x); - static unsigned int appendChar(char *result, unsigned int index, char ch); + static void appendChar(char *result, unsigned int& index, char ch); - static unsigned int appendDuration(char *result, unsigned int index, uint16_t duration, microseconds_t timebase); + static void appendDuration(char *result, unsigned int& index, uint16_t duration, microseconds_t timebase); - static unsigned int appendDigit(char *result, unsigned int index, unsigned int number); + static void appendDigit(char *result, unsigned int& index, unsigned int number); - static unsigned int appendNumber(char *result, unsigned int index, uint16_t number); + static void appendNumber(char *result, unsigned int& index, uint16_t number); - static unsigned int appendSequence(char *result, unsigned int index, const microseconds_t *data, size_t length, microseconds_t timebase); + static void appendSequence(char *result, unsigned int& index, const microseconds_t *data, size_t length, microseconds_t timebase); - static unsigned int appendSequence(char *result, unsigned int index, const IrSequence& irSequence, microseconds_t timebase); + static void appendSequence(char *result, unsigned int& index, const IrSequence& irSequence, microseconds_t timebase); static void dumpSequence(Stream& stream, const microseconds_t *data, size_t length, microseconds_t timebase); diff --git a/src/Rc5Decoder.cpp b/src/Rc5Decoder.cpp index bb8731d..b5897bd 100644 --- a/src/Rc5Decoder.cpp +++ b/src/Rc5Decoder.cpp @@ -1,8 +1,6 @@ #include "Rc5Decoder.h" #include -const char *Rc5Decoder::format = "RC5 %d %d %d"; - Rc5Decoder::Length Rc5Decoder::decodeDuration(microseconds_t t) { Length len = (t < timebaseLower) ? invalid : (t <= timebaseUpper) ? half diff --git a/src/Rc5Decoder.h b/src/Rc5Decoder.h index 132afde..26639ef 100644 --- a/src/Rc5Decoder.h +++ b/src/Rc5Decoder.h @@ -71,7 +71,8 @@ class Rc5Decoder : public IrDecoder { full = 2 }; + static constexpr const char *format = "RC5 %d %d %d"; + static Length decodeDuration(microseconds_t t); static unsigned int decodeFlashGap(microseconds_t flash, microseconds_t gap); - static const char *format; }; diff --git a/src/boards/NoBoard.h b/src/boards/NoBoard.h index 53d2a56..efb879b 100644 --- a/src/boards/NoBoard.h +++ b/src/boards/NoBoard.h @@ -19,6 +19,8 @@ this program. If not, see http://www.gnu.org/licenses/. #include "Board.h" +#include "PinModeStatus.h" + #define CURRENT_CLASS NoBoard #define HAS_FLASH_READ 0 diff --git a/tests/test1.cpp b/tests/test1.cpp index 620085f..6eb6b3d 100644 --- a/tests/test1.cpp +++ b/tests/test1.cpp @@ -158,24 +158,19 @@ static bool testPronto(bool verbose) { sig->dump(stdout, true); } return checkIrSignalDump(*sig, "f=38380 " -#ifdef USE_DOUBLE_IN_PRONTO - "+9040 -4507 +573 -573 +573 -1693 +573 -573 +573 -1693 +573 -1693 +573 -1693 +573 -1693 +573 -573 +573 -1693 +573 -573 +573 -1693 +573 -573 +573 -573 +573 -573 +573 -573 +573 -1693 +573 -1693 +573 -573 +573 -1693 +573 -1693 +573 -1693 +573 -573 +573 -573 +573 -573 +573 -573 +573 -1693 +573 -573 +573 -573 +573 -573 +573 -1693 +573 -1693 +573 -1693 +573 -39785\n" - "+9040 -2266 +573 -65535\n\n" -#else "+9022 -4498 +572 -572 +572 -1690 +572 -572 +572 -1690 +572 -1690 +572 -1690 +572 -1690 +572 -572 +572 -1690 +572 -572 +572 -1690 +572 -572 +572 -572 +572 -572 +572 -572 +572 -1690 +572 -1690 +572 -572 +572 -1690 +572 -1690 +572 -1690 +572 -572 +572 -572 +572 -572 +572 -572 +572 -1690 +572 -572 +572 -572 +572 -572 +572 -1690 +572 -1690 +572 -1690 +572 -39702\n" "+9022 -2262 +572 -65535\n\n" -#endif ); } static bool testToProntoHex(bool verbose) { - const char prontoHex[] = "0000 006C 0022 0000 015C 00AD 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 05FA"; - microseconds_t data[] = - { + const char prontoHex[] = "0000 006C 0022 0002 015C 00AD 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 05FA 015C 0057 0016 09D9"; + microseconds_t intro[] = { 9040, 4507, 573, 573, 573, 1693, 573, 573, 573, 1693, 573, 1693, 573, 1693, 573, 1693, 573, 573, 573, 1693, 573, 573, 573, 1693, 573, 573, 573, 573, 573, 573, 573, 573, 573, 1693, 573, 1693, 573, 573, 573, 1693, 573, 1693, 573, 1693, 573, 573, 573, 573, 573, 573, 573, 573, 573, 1693, 573, 573, 573, 573, 573, 573, 573, 1693, 573, 1693, 573, 1693, 573, 39785, //9040, 2266, 573, 65535 }; - char *result = Pronto::toProntoHex(data, sizeof (data) / sizeof (microseconds_t), 38380); + microseconds_t repeat[] = { 9040, 2266, 573, 65535}; + char *result = Pronto::toProntoHex(intro, sizeof (intro) / sizeof (microseconds_t), repeat, sizeof(repeat)/sizeof(microseconds_t), 38380); if (verbose) std::cout << result << std::endl; @@ -200,7 +195,7 @@ static bool testProntoDump(bool verbose) { std::ostringstream oss; Stream ss(oss); Pronto::dump(ss, *nec1); - return oss.str() == std::string("0000 006B 0022 0002 015B 00AE 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 05F9 015B 0057 0016 09D9 "); + return oss.str() == std::string("0000 006B 0022 0002 015B 00AE 0016 0016 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0041 0016 0016 0016 0041 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0016 0016 0041 0016 0041 0016 0041 0016 0016 0016 0016 0016 0016 0016 0016 0016 0041 0016 0016 0016 0016 0016 0016 0016 0041 0016 0041 0016 0041 0016 05F9 015B 0057 0016 09D9"); } #define TEST(f) if (f(verbose)) {successes++;} else {std::cout << #f << " failed!" << std::endl; fails++;}