Skip to content

Commit

Permalink
Updated to a more modern implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
barakwei committed Aug 14, 2016
1 parent 03495b4 commit 9186af1
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 102 deletions.
210 changes: 134 additions & 76 deletions IRelectra.cpp
Original file line number Diff line number Diff line change
@@ -1,106 +1,59 @@
/*
* IRelectra
* Version 0.8
* Copyrights 2014 Barak Weiss
* Copyrights 2016 Barak Weiss
*
* Many thanks to Chris from AnalysIR
*/

#include "IRelectra.h"
#include <stdint.h>
#include <vector>

#define UNIT 1000
using std::vector;

#define UNIT 992
#define NUM_BITS 34

IRelectra::IRelectra(IRsend* remote) : _remote(remote)
{}

// Add bit b to array p at index i
// This function is used to convert manchester encoding to MARKs and SPACEs
// p is the pointer to the start of the MARK, SPACE array
// i is the current index
// b is the bit we want to add to the MARK, SPACE array
// A zero bit is one unit MARK and one unit SPACE
// a one bit is one unit SPACE and one unit MARK
void IRelectra::addBit(unsigned int* p, int* i, char b)
// Sends the specified configuration to the IR led
bool IRelectra::sendElectra(bool power, IRElectraMode mode, IRElectraFan fan, int temperature, bool swing, bool sleep)
{
if (((*i) & 1) == 1)
{
// current index is SPACE
if ((b & 1) == 1)
{
// one is one unit low, then one unit up
// since we're pointing at SPACE, we should increase it byte a unit
// then add another MARK unit
*(p+*i) += UNIT;
(*i)++;
*(p+*i) = UNIT;
}
if ((b & 1) == 0)
{
// we need a MARK unit, then SPACE unit
(*i)++;
*(p+*i) = UNIT;
(*i)++;
*(p+*i) = UNIT;
}
}
else if (((*i) & 1) == 0)
{
// current index is MARK
if ((b & 1) == 1)
{
(*i)++;
*(p+*i) = UNIT;
(*i)++;
*(p+*i) = UNIT;
}
if ((b & 1) == 0)
{
*(p+*i) += UNIT;
(*i)++;
*(p+*i) = UNIT;
}
}

// get the data representing the configuration
uint64_t code = encodeElectra(power, mode, fan, temperature, swing, sleep);

// get the raw data itself with headers, repetition, etc.
std::vector<unsigned int> data = generateSignal(code);

// send using HW.
_remote->sendRaw(data.data(), data.size(), 33);

return true;
}

// Sends the specified configuration to the IR led using IRremote
// 1. Get the numeric value of the configuration
// 2. Convert to IRremote compatible array (MARKS and SPACES)
// 3. Send to IRremote
bool IRelectra::SendElectra(int power, int mode, int fan, int temperature, int swing, int sleep)
std::vector<unsigned int> IRelectra::generateSignal(uint64_t code)
{
unsigned int data[200]; //~maximum size of the IR packet
int i = 0;

// get the data representing the configuration
uint64_t code = EncodeElectra(power, mode, fan, temperature, swing, sleep);

MarkSpaceArray markspace(UNIT);

// The whole packet looks this:
// 3 Times:
// 3000 usec MARK
// 3000 used SPACE
// Maxchester encoding of the data, clock is ~1000usec
// 4000 usec MARK
for (int k = 0; k<3; k++)
for (int k =0; k<3; k++)
{
data[i] = 3 * UNIT; //mark
i++;
data[i] = 3 * UNIT;
for (int j = NUM_BITS - 1; j >= 0; j--)
{
addBit(data, &i, (code >> j) & 1);
}
i++;
markspace.addMark(3); //mark
markspace.addSpace(3); //space
markspace.addNumberWithManchesterCode(code, NUM_BITS);
}
data[i] = 4 * UNIT;

_remote->sendRaw(data, i + 1, 38);
return true;
markspace.addMark(4);
return markspace.data();
}

// Encodes specific A/C configuration to a number that describes
#pragma pack(1)

// That configuration has a total of 34 bits
// 33: Power bit, if this bit is ON, the A/C will toggle it's power.
// 32-30: Mode - Cool, heat etc.
Expand All @@ -113,7 +66,42 @@ bool IRelectra::SendElectra(int power, int mode, int fan, int temperature, int s
// 17- 2: Zeros
// 1: One
// 0: Zero
uint64_t IRelectra::EncodeElectra(int power, int mode, int fan, int temperature, int swing, int sleep)
typedef union ElectraCode {
uint64_t num;
struct {
uint8_t zeros1 : 1;
uint8_t ones1 : 1;
uint16_t zeros2 : 16;
uint8_t sleep : 1;
uint8_t temperature : 4;
uint8_t zeros3 : 2;
uint8_t swing : 1;
uint8_t zeros4 : 2;
uint8_t fan : 2;
uint8_t mode : 3;
uint8_t power : 1;
};
} ElectraUnion;

#pragma pack()


uint64_t IRelectra::encodeElectra(bool power, IRElectraMode mode, IRElectraFan fan, int temperature, bool swing, bool sleep)
{
temperature -= 15;
ElectraCode code = { 0 };
code.ones1 = 1;
code.sleep = sleep ? 1 : 0;
code.temperature = temperature;
code.swing = swing ? 1 : 0;
code.fan = fan;
code.mode = mode;
code.power = power ? 1 : 0;

return code.num;
}

uint64_t encodeElectra2(bool power, IRElectraMode mode, IRElectraFan fan, int temperature, bool swing, bool sleep)
{
uint64_t num = 0;
uint64_t power64 = power;
Expand All @@ -136,3 +124,73 @@ uint64_t IRelectra::EncodeElectra(int power, int mode, int fan, int temperature,

return num;
}

///
/// Mark Space Array
///
MarkSpaceArray::MarkSpaceArray(uint16_t unitLengthInUsec) : _unitLength(unitLengthInUsec)
{ }

void MarkSpaceArray::MarkSpaceArray::addMark(uint16_t units)
{
if (currentState())
{
addUnitsToCurrentState(units);
}
else
{
addUnitsToNextState(units);
}
}

void MarkSpaceArray::addSpace(uint16_t units)
{
if (!currentState())
{
addUnitsToCurrentState(units);
}
else
{
addUnitsToNextState(units);
}}

void MarkSpaceArray::addBitWithManchesterCode(uint8_t bit)
{
if (currentState() == (bit & 1))
{
addUnitsToNextState(1);
}
else
{
addUnitsToCurrentState(1);
}
addUnitsToNextState(1);
}

void MarkSpaceArray::addNumberWithManchesterCode(uint64_t code, uint8_t numberOfBits)
{
for (int j = numberOfBits - 1; j>=0; j--)
{
addBitWithManchesterCode((code >> j) & 1);
}
}

void MarkSpaceArray::addUnitsToCurrentState(uint16_t units)
{
_data.back() += _unitLength * units;
}

void MarkSpaceArray::addUnitsToNextState(uint16_t units)
{
_data.emplace_back(_unitLength * units);
}

const std::vector<unsigned int> MarkSpaceArray::data()
{
return _data;
}

uint8_t MarkSpaceArray::currentState()
{
return _data.size() % 2;
}
103 changes: 77 additions & 26 deletions IRelectra.h
Original file line number Diff line number Diff line change
@@ -1,51 +1,102 @@
/*
* IRelectra
* Version 0.8
* Copyrights 2014 Barak Weiss
* Copyrights 2016 Barak Weiss
*
* Many thanks to Chris from AnalysIR
*/

#ifndef IRelectra_h
#define IRelectra_h

#include <stdint.h>

#include "IRremote.h"

#define POWER_OFF 0
#define POWER_ON 1

#define MODE_COOL 0b001
#define MODE_HEAT 0b010
#define MODE_AUTO 0b011
#define MODE_DRY 0b100
#define MODE_FAN 0b101

#define FAN_LOW 0b00
#define FAN_MED 0b01
#define FAN_HIGH 0b10
#define FAN_AUTO 0b11
#include <stdint.h>
#include <vector>

#define SWING_OFF 0b0
#define SWING_ON 0b1
typedef enum IRElectraMode {
IRElectraModeCool = 0b001,
IRElectraModeHeat = 0b010,
IRElectraModeAuto = 0b011,
IRElectraModeDry = 0b100,
IRElectraModeFan = 0b101
} IRElectraMode;

#define SLEEP_OFF 0b0
#define SLEEP_ON 0b1
typedef enum IRElectraFan {
IRElectraFanLow = 0b00,
IRElectraFanMedium = 0b01,
IRElectraFanHigh = 0b10,
IRElectraFanAuto = 0b11
} IRElectraFan;

class IRelectra
{
public:
// Ctor, remote will be used to send the raw IR data
// Initialize
IRelectra(IRsend* remote);

// Sends the specified configuration to the IR led using IRremote
bool SendElectra(int power, int mode, int fan, int temperature, int swing, int sleep);
// Send an IR packet with the given parameters.
bool sendElectra(bool power, IRElectraMode mode, IRElectraFan fan, int temperature, bool swing, bool sleep);

private:
IRsend* _remote;
uint64_t EncodeElectra(int power, int mode, int fan, int temperature, int swing, int sleep);
void addBit(unsigned int* p, int* i, char b);

// Encodes specific A/C configuration to a number that describes
uint64_t encodeElectra(bool power, IRElectraMode mode, IRElectraFan fan, int temperature, bool swing, bool sleep);

// Create the entire MARK-SPACE array containing the entire packet to send to the A/C
std::vector<unsigned int> generateSignal(uint64_t code);
};

// Class to create MARK-SPACE array. An IR code is a digital signal, which
// means it's made out of 0's (space) and 1's (mark). This class helps
// create these kinds of signals. It has the ability to add marks and spaces
// at any time, and to add single bit using Manchester code to the signal.
// Once you added enough data to the array use the data() methods to get
// the raw data. Make sure that the first think you add to the array is
// at least one mark.
class MarkSpaceArray
{
public:
// Initialize the array with a specific unit length. This is the clock used
// in the Manchester code.
MarkSpaceArray(uint16_t unitLengthInUsec);

// Add a number of time units with mark.
void addMark(uint16_t units);

// Add a number of time units with space.
void addSpace(uint16_t units);

// Encodes the bit with IEEE 802.3 Manchester coding and adds it to the array
// A zero bit is one unit MARK and one unit SPACE
// a one bit is one unit SPACE and one unit MARK
void addBitWithManchesterCode(uint8_t bit);

// Encodes a given number of bits from the given number bit by bit with
// IEEE 802.3 Manchester coding and adds it to the array. MSB first.
void addNumberWithManchesterCode(uint64_t bit, uint8_t numberOfBits);

// Array containing timing for marks and spaces, starts with marks.
const std::vector<unsigned int> data();

private:
// Add more time units to the current state. For example, if the array
// looks like this: { 1*UNIT, 1*UNIT } (equal to calling addMark(1)
// followed by addSpace(1), the current state is SPACE (currentState()==0)
// calling this function will change the array to { 1*UNIT, 2*UNIT }.
void addUnitsToCurrentState(uint16_t units);

// Add more time to the other state. For example, if the array
// looks like this: { 1*UNIT, 1*UNIT } (equal to calling addMark(1)
// followed by addSpace(1), the current state is SPACE (currentState()==0)
// calling this function will change the array to { 1*UNIT, 1*UNIT, 1*UNIT }
void addUnitsToNextState(uint16_t units);

// Returns 1 for mark, 0 for space.
uint8_t currentState();

uint16_t _unitLength;
std::vector<unsigned int> _data;
};

#endif

0 comments on commit 9186af1

Please sign in to comment.