diff --git a/irsling.cpp b/irsling.cpp new file mode 100644 index 0000000..0d77f96 --- /dev/null +++ b/irsling.cpp @@ -0,0 +1,554 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "irslinger.h" + +// compile with: +// g++ irsling.cpp -lpigpio -lm -lpthread + +// LIRC config not supported: +// http://www.lirc.org/html/lircd.conf.html +// include +// manual_sort +// suppress_repeat +// flags RC6 / RC-MM / REVERSE / NO_HEAD_REP / NO_FOOT_REP / CONST_LENGTH / REPEAT_HEADER +// driver +// eps +// aeps +// three / two / RC-MM +// plead +// foot +// repeat +// toggle_bit +// toggle_bit_mask +// repeat_mask + +// read lirc config file +class remote_config { + public: + remote_config () + { + config["bits"] = 16; + config["frequency"] = 38000; + config["dutycycle"] = 50; + config["header.on"] = 9000; + config["header.off"] = 4500; + config["one.on"] = 562; + config["one.off"] = 1688; + config["zero.on"] = 562; + config["zero.off"] = 562; + config["ptrail"] = 562; + config["min_repeat"] = 0; + config["gap"] = 108000; + config["pre_data_bits"] = 0; + config["post_data_bits"] = 0; + }; + // config parameters: name -> value + std::unordered_map config; + // key codes: button label -> hex code + std::unordered_map codes; + // other arbitrary flags + std::unordered_set flags; + // raw codes + std::unordered_map > rawcodes; +}; + +// map of config for each known remote +std::unordered_map remotes; + +// statefulness while parsing remote +bool in_codes = false; +std::string remotename = "default"; +bool in_rawcodes = false; +std::string buttonname; + + +void tokenise(const std::string in, const char * delimiters, std::vector &out) +{ + size_t start = in.find_first_not_of(delimiters); + size_t end = start; + + while (start != std::string::npos){ + // Find next occurence of delimiter + end = in.find_first_of(delimiters, start); + // Push back the token found into vector + out.push_back(in.substr(start, end-start)); + // Skip all occurences of the delimiter to find new start + start = in.find_first_not_of(delimiters, end); + } +} + +const char * space_delimiters = " \t\r\n"; +int handle_line(const std::string & line) +{ + // tokenise the line + std::vector tokens; + tokenise(line, space_delimiters, tokens); + // bale if no tokens + if (tokens.empty()) + { return 0; } + if (tokens[0].at(0) == '#') + { return 0; } + // find number of valid tokens + size_t i=1; + size_t maxtoken = tokens.size()-1; + while (i < tokens.size()) + { + if (tokens[i].at(0) == '#') + { + maxtoken = i-1; + break; + } + ++i; + } + // all lines in >=2 tokens unless we are in raw codes + if ((maxtoken == 0) && (in_rawcodes == false)) + { + std::cerr << "Invalid line: "< fv; + tokenise(tokens[1],"| ", fv); + // convert to a set for easy reference + for (auto f:fv) + { + remote.flags.insert(f); + } + return 0; + } + try + { + if (tokens[0] == "header") + { + if (maxtoken == 1) + { + std::cerr << "Missing off time in line: "<first; + } + + if (dumpconfig) + { + for (auto r:remotes) + { + remote_config &remote(r.second); + std::cout <<"Config for remote "<>::iterator raw = remote.rawcodes.find(button); + if (raw == remote.rawcodes.end()) + { + std::cerr << "Button \"" << button << "\" is unknown on remote " << thisremote << std::endl; + result |= 1; + continue; + } + if (result == -1) { result = 0; } + int pulses[raw->second.size()]; + int j = 0; + for (auto r:raw->second) + { + pulses[j++] = r; + } + // ensure we always end in an off + if ((j % 2) == 1) + { + pulses[j] = pulses[j-1]; + } + if (irSlingPrepareRaw(irSignal, &pulseCount, + pin, + remote.config["frequency"], + double(remote.config["dutycycle"])/100, + pulses, + raw->second.size())) + { + std::cerr << "Failed to prepare signal" <::iterator code = remote.codes.find(button); + if (code == remote.codes.end()) + { + std::cerr << "Button \"" << button << "\" is unknown on remote " << thisremote << std::endl; + result |= 1; + continue; + } + if (result == -1) { result = 0; } + + // nec type + if (remote.flags.find("SPACE_ENC") != remote.flags.end()) + { + // insert the header + if (irSlingPrepare(irSignal, &pulseCount, + pin, + remote.config["frequency"], + double(remote.config["dutycycle"])/100, + remote.config["header.on"], + remote.config["header.off"], + 0, 0, 0, 0, 0, nullptr, 0)) // no more content + { + std::cerr << "Failed to prepare header" <second.c_str(), + remote.config["bits"])) + { + std::cerr << "Failed to prepare signal" < 0)) + { + snprintf(post_data_bits,post_len+3,"0x%0*x",post_len,remote.config["post_data"]); + } + if (irSlingPrepare(irSignal, &pulseCount, + pin, + remote.config["frequency"], + double(remote.config["dutycycle"])/100, + 0, 0, /* no header */ + remote.config["one.on"], + remote.config["zero.on"], + remote.config["one.off"], + remote.config["zero.off"], + remote.config["ptrail"], + post_data_bits, + remote.config["post_data_bits"])) + { + std::cerr << "Failed to prepare post_data" <second); + //std::cout << "pattern is "< #include #include +#include #define MAX_COMMAND_SIZE 512 #define MAX_PULSES 12000 -static inline void addPulse(uint32_t onPins, uint32_t offPins, uint32_t duration, gpioPulse_t *irSignal, int *pulseCount) +static inline void addPulse(uint32_t onPins, uint32_t offPins, uint32_t duration, gpioPulse_t *irSignal, unsigned int *pulseCount) { int index = *pulseCount; @@ -21,7 +22,7 @@ static inline void addPulse(uint32_t onPins, uint32_t offPins, uint32_t duration // Generates a square wave for duration (microseconds) at frequency (Hz) // on GPIO pin outPin. dutyCycle is a floating value between 0 and 1. -static inline void carrierFrequency(uint32_t outPin, double frequency, double dutyCycle, double duration, gpioPulse_t *irSignal, int *pulseCount) +static inline void carrierFrequency(uint32_t outPin, double frequency, double dutyCycle, double duration, gpioPulse_t *irSignal, unsigned int *pulseCount) { double oneCycleTime = 1000000.0 / frequency; // 1000000 microseconds in a second int onDuration = (int)round(oneCycleTime * dutyCycle); @@ -46,15 +47,63 @@ static inline void carrierFrequency(uint32_t outPin, double frequency, double du } } +// bitnum is 0 based +static inline int getbit(const char * code, int bitnum, int totalLength) +{ + if (code[0] == '0' && code[1] == 'x') { + size_t digitofs = strlen(code); + // find the character/nibble offset from the end of the string + // i.e. the final bit to transmit is the lsb of the final digit + int nibblebit = totalLength - 1 - bitnum; + digitofs -= 1+((nibblebit)/4); + // check the string is long enough + if (digitofs < 2) + { + printf("Code %s is not long enough for %d bits\n",code,totalLength); + return -1; + } + + char x = code[digitofs]; + int n; + if (x >= '0' && x<= '9') { + n=x - '0'; + } else if (x >= 'a' && x<='f') { + n=x - 'a' + 10; + } else if (x >= 'A' && x<='F') { + n=x - 'A' + 10; + } else { + printf("Character %c is not valid hex\n",x); + return -1; + } + int ret = (n & (1<<(nibblebit%4))); + //printf("code %s bitnum %d totlen %d => nibblebit %d digitofs %d => %d\n",code,bitnum,totalLength,nibblebit,digitofs,ret); + return (ret>0)?1:0; + } + if (code[bitnum] == '0') { + return 0; + } + if (code[bitnum] == '1') { + return 1; + } + printf("Do not recognise bit code %c at position %d\n",code[bitnum],bitnum); + return -1; +} + // Generates a low signal gap for duration, in microseconds, on GPIO pin outPin -static inline void gap(uint32_t outPin, double duration, gpioPulse_t *irSignal, int *pulseCount) +static inline void gap(uint32_t outPin, double duration, gpioPulse_t *irSignal, unsigned int *pulseCount) { addPulse(0, 0, duration, irSignal, pulseCount); } // Transmit generated wave -static inline int transmitWave(uint32_t outPin, gpioPulse_t *irSignal, unsigned int *pulseCount) +static inline int transmitWavePre(uint32_t outPin) { + if (outPin > 31) + { + // Invalid pin number + return 1; + } + // Init pigpio if (gpioInitialise() < 0) { @@ -65,22 +114,27 @@ static inline int transmitWave(uint32_t outPin, gpioPulse_t *irSignal, unsigned // Setup the GPIO pin as an output pin gpioSetMode(outPin, PI_OUTPUT); + return 0; +} +static inline int transmitWave(gpioPulse_t *irSignal, unsigned int pulseCount) +{ // Start a new wave gpioWaveClear(); - gpioWaveAddGeneric(*pulseCount, irSignal); + gpioWaveAddGeneric(pulseCount, irSignal); int waveID = gpioWaveCreate(); if (waveID >= 0) { int result = gpioWaveTxSend(waveID, PI_WAVE_MODE_ONE_SHOT); - printf("Result: %i\n", result); + //printf("Result: %i\n", result); } else { printf("Wave creation failure!\n %i", waveID); + return 1; } // Wait for the wave to finish transmitting @@ -94,64 +148,77 @@ static inline int transmitWave(uint32_t outPin, gpioPulse_t *irSignal, unsigned { gpioWaveDelete(waveID); } + return 0; +} +static inline int transmitWavePost() +{ // Cleanup gpioTerminate(); return 0; } -static inline int irSlingRC5(uint32_t outPin, +static inline int irSlingPrepareRC5(gpioPulse_t *irSignal, + unsigned int * pulseCount, + int outPin, int frequency, double dutyCycle, int pulseDuration, - const char *code) + const char *code, + size_t codeLen) { - if (outPin > 31) - { - // Invalid pin number - return 1; - } - - size_t codeLen = strlen(code); - - printf("code size is %zu\n", codeLen); - if (codeLen > MAX_COMMAND_SIZE) { // Command is too big return 1; } - gpioPulse_t irSignal[MAX_PULSES]; - int pulseCount = 0; - // Generate Code int i; for (i = 0; i < codeLen; i++) { - if (code[i] == '0') - { - carrierFrequency(outPin, frequency, dutyCycle, pulseDuration, irSignal, &pulseCount); - gap(outPin, pulseDuration, irSignal, &pulseCount); - } - else if (code[i] == '1') + switch (getbit(code,i,codeLen)) { - gap(outPin, pulseDuration, irSignal, &pulseCount); - carrierFrequency(outPin, frequency, dutyCycle, pulseDuration, irSignal, &pulseCount); - } - else - { - printf("Warning: Non-binary digit in command\n"); + case 0: + carrierFrequency(outPin, frequency, dutyCycle, pulseDuration, irSignal, pulseCount); + gap(outPin, pulseDuration, irSignal, pulseCount); + break; + case 1: + gap(outPin, pulseDuration, irSignal, pulseCount); + carrierFrequency(outPin, frequency, dutyCycle, pulseDuration, irSignal, pulseCount); + break; } } - printf("pulse count is %i\n", pulseCount); + //printf("pulse count is %i\n", *pulseCount); // End Generate Code +} - return transmitWave(outPin, irSignal, &pulseCount); +static inline int irSlingRC5(uint32_t outPin, + int frequency, + double dutyCycle, + int pulseDuration, + const char *code) +{ + gpioPulse_t irSignal[MAX_PULSES]; + unsigned int pulseCount = 0; + + size_t codeLen = strlen(code); + if (code[0]=='0' && code[1]=='x') { + codeLen=(codeLen-2)*4; + } + + printf("code size is %zu\n", codeLen); + + if (irSlingPrepareRC5(irSignal, &pulseCount, outPin, frequency, dutyCycle, pulseDuration, code, codeLen)) return 1; + int ret = 1; + if (transmitWavePre(outPin)) return 1; + ret = transmitWave(irSignal, pulseCount); + transmitWavePost(); + return ret; } -static inline int irSling(uint32_t outPin, +static inline int irSlingPrepare(gpioPulse_t *irSignal, unsigned int * pulseCount, uint32_t outPin, int frequency, double dutyCycle, int leadingPulseDuration, @@ -161,7 +228,8 @@ static inline int irSling(uint32_t outPin, int oneGap, int zeroGap, int sendTrailingPulse, - const char *code) + const char *code, + size_t codeLen) { if (outPin > 31) { @@ -169,54 +237,81 @@ static inline int irSling(uint32_t outPin, return 1; } - size_t codeLen = strlen(code); - - printf("code size is %zu\n", codeLen); - - if (codeLen > MAX_COMMAND_SIZE) + // Generate Code + // insert header + if (leadingPulseDuration > 0) { - // Command is too big - return 1; + carrierFrequency(outPin, frequency, dutyCycle, leadingPulseDuration, irSignal, pulseCount); + gap(outPin, leadingGapDuration, irSignal, pulseCount); } - gpioPulse_t irSignal[MAX_PULSES]; - int pulseCount = 0; - - // Generate Code - carrierFrequency(outPin, frequency, dutyCycle, leadingPulseDuration, irSignal, &pulseCount); - gap(outPin, leadingGapDuration, irSignal, &pulseCount); - int i; for (i = 0; i < codeLen; i++) { - if (code[i] == '0') - { - carrierFrequency(outPin, frequency, dutyCycle, zeroPulse, irSignal, &pulseCount); - gap(outPin, zeroGap, irSignal, &pulseCount); - } - else if (code[i] == '1') - { - carrierFrequency(outPin, frequency, dutyCycle, onePulse, irSignal, &pulseCount); - gap(outPin, oneGap, irSignal, &pulseCount); - } - else + switch (getbit(code,i,codeLen)) { - printf("Warning: Non-binary digit in command\n"); + case 0: + carrierFrequency(outPin, frequency, dutyCycle, zeroPulse, irSignal, pulseCount); + gap(outPin, zeroGap, irSignal, pulseCount); + break; + case 1: + carrierFrequency(outPin, frequency, dutyCycle, onePulse, irSignal, pulseCount); + gap(outPin, oneGap, irSignal, pulseCount); + break; } } - if (sendTrailingPulse) + if (sendTrailingPulse==1) + { + carrierFrequency(outPin, frequency, dutyCycle, onePulse, irSignal, pulseCount); + } + else if (sendTrailingPulse > 0) { - carrierFrequency(outPin, frequency, dutyCycle, onePulse, irSignal, &pulseCount); + carrierFrequency(outPin, frequency, dutyCycle, sendTrailingPulse, irSignal, pulseCount); } - printf("pulse count is %i\n", pulseCount); + //printf("pulse count is %i\n", *pulseCount); // End Generate Code + return 0; +} - return transmitWave(outPin, irSignal, &pulseCount); +static inline int irSling(uint32_t outPin, + int frequency, + double dutyCycle, + int leadingPulseDuration, + int leadingGapDuration, + int onePulse, + int zeroPulse, + int oneGap, + int zeroGap, + int sendTrailingPulse, + const char *code) +{ + size_t codeLen = strlen(code); + if (code[0]=='0' && code[1]=='x') { + codeLen=(codeLen-2)*4; + } + + printf("code size is %zu\n", codeLen); + + if (codeLen > MAX_COMMAND_SIZE) + { + // Command is too big + return 1; + } + + gpioPulse_t irSignal[MAX_PULSES]; + unsigned int pulseCount = 0; + + if (irSlingPrepare(irSignal, &pulseCount, outPin, frequency, dutyCycle, leadingPulseDuration, leadingGapDuration, onePulse, zeroPulse, oneGap, zeroGap, sendTrailingPulse, code, codeLen)) return 1; + int ret = 1; + if (transmitWavePre(outPin)) return 1; + ret = transmitWave(irSignal, pulseCount); + transmitWavePost(); + return ret; } -static inline int irSlingRaw(uint32_t outPin, +static inline int irSlingPrepareRaw(gpioPulse_t * irSignal, unsigned int * pulseCount, uint32_t outPin, int frequency, double dutyCycle, const int *pulses, @@ -228,24 +323,34 @@ static inline int irSlingRaw(uint32_t outPin, return 1; } - // Generate Code - gpioPulse_t irSignal[MAX_PULSES]; - int pulseCount = 0; - int i; for (i = 0; i < numPulses; i++) { if (i % 2 == 0) { - carrierFrequency(outPin, frequency, dutyCycle, pulses[i], irSignal, &pulseCount); + carrierFrequency(outPin, frequency, dutyCycle, pulses[i], irSignal, pulseCount); } else { - gap(outPin, pulses[i], irSignal, &pulseCount); + gap(outPin, pulses[i], irSignal, pulseCount); } } - printf("pulse count is %i\n", pulseCount); + //printf("pulse count is %i from %i\n", *pulseCount, numPulses); // End Generate Code - - return transmitWave(outPin, irSignal, &pulseCount); + return 0; +} +static inline int irSlingRaw(uint32_t outPin, + int frequency, + double dutyCycle, + const int *pulses, + int numPulses) +{ + gpioPulse_t irSignal[MAX_PULSES]; + unsigned int pulseCount = 0; + if (irSlingPrepareRaw(irSignal, &pulseCount, outPin, frequency, dutyCycle, pulses, numPulses)) return 1; + if (transmitWavePre(outPin)) return 1; + int ret = 1; + ret = transmitWave(irSignal, pulseCount); + transmitWavePost(); + return ret; } #endif