Improved LG protocol and added class Aircondition_LG. Improved ir_DistanceProtocol.cpp to support more than 32 bits.
This commit is contained in:
parent
ed948955e8
commit
94fa49a0f8
|
@ -112,12 +112,12 @@ jobs:
|
|||
|
||||
- arduino-boards-fqbn: megaTinyCore:megaavr:atxy4:chip=1604,clock=16internal
|
||||
platform-url: http://drazzy.com/package_drazzy.com_index.json
|
||||
sketches-exclude: MinimalReceiver,IRDispatcherDemo,MicroGirs # digitalWriteFast.h not available for this board
|
||||
sketches-exclude: MinimalReceiver,IRDispatcherDemo,MicroGirs,UnitTest # digitalWriteFast.h not available for this board
|
||||
|
||||
- arduino-boards-fqbn: digistump:avr:digispark-tiny:clock=clock16
|
||||
platform-url: https://raw.githubusercontent.com/ArminJo/DigistumpArduino/master/package_digistump_index.json
|
||||
required-libraries: ATtinySerialOut
|
||||
sketch-names: MinimalReceiver.ino,IRremoteInfo.ino,SimpleReceiver.ino,ReceiveDemo.ino,ControlRelay.ino,SimpleSender.ino,SendDemo.ino,SendRawDemo.ino,SendAndReceive.ino
|
||||
sketch-names: MinimalReceiver.ino,IRremoteInfo.ino,SimpleReceiver.ino,ControlRelay.ino,SimpleSender.ino,SendDemo.ino,SendRawDemo.ino,SendAndReceive.ino
|
||||
|
||||
- arduino-boards-fqbn: ATTinyCore:avr:attinyx5micr:LTO=enable,sketchclock=16pll
|
||||
platform-url: http://drazzy.com/package_drazzy.com_index.json
|
||||
|
|
38
README.md
38
README.md
|
@ -50,14 +50,17 @@ If you use an (old) Arduino core that does not use the `-flto` flag for compile,
|
|||
- Now there is an **IRreceiver** and **IRsender** object like the well known Arduino **Serial** object.
|
||||
- Just remove the line `IRrecv IrReceiver(IR_RECEIVE_PIN);` and/or `IRsend IrSender;` in your program, and replace all occurrences of `IRrecv.` or `irrecv.` with `IrReceiver`.
|
||||
- Since the decoded values are now in `IrReceiver.decodedIRData` and not in `results` any more, remove the line `decode_results results` or similar.
|
||||
- Like for the Serial object, call [`IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);`](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/examples/ReceiveDemo/ReceiveDemo.ino#L38) or `IrReceiver.begin(IR_RECEIVE_PIN, DISABLE_LED_FEEDBACK);` instead of the `IrReceiver.enableIRIn();` or `irrecv.enableIRIn();` in setup().
|
||||
- Like for the Serial object, call [`IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);`](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/examples/ReceiveDemo/ReceiveDemo.ino#L38)
|
||||
or `IrReceiver.begin(IR_RECEIVE_PIN, DISABLE_LED_FEEDBACK);` instead of the `IrReceiver.enableIRIn();` or `irrecv.enableIRIn();` in setup().
|
||||
- Old `decode(decode_results *aResults)` function is replaced by simple `decode()`. So if you have a statement `if(irrecv.decode(&results))` replace it with `if (IrReceiver.decode())`.
|
||||
- The decoded result is now in in `IrReceiver.decodedIRData` and not in `results` any more, therefore replace any occurrences of `results.value` and `results.decode_type` (and similar) to `IrReceiver.decodedIRData.decodedRawData` and `IrReceiver.decodedIRData.protocol`.
|
||||
- The decoded result is now in in `IrReceiver.decodedIRData` and not in `results` any more, therefore replace any occurrences of `results.value` and `results.decode_type` (and similar) to
|
||||
`IrReceiver.decodedIRData.decodedRawData` and `IrReceiver.decodedIRData.protocol`.
|
||||
- Overflow, Repeat and other flags are now in [`IrReceiver.receivedIRData.flags`](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/IRremote.h#L126).
|
||||
- Seldom used: `results.rawbuf` and `results.rawlen` must be replaced by `IrReceiver.decodedIRData.rawDataPtr->rawbuf` and `IrReceiver.decodedIRData.rawDataPtr->rawlen`.
|
||||
|
||||
# Do not want to convert your 2.x program and use the 3.x library version?
|
||||
The 3.x versions try to be backwards compatible, so you can easily run your old examples. But some functions like e.g. `sendNEC()` -see below- could not made backwards compatible, so in this cases you must revisit your code and adapt it to the 3.x library.<br/>
|
||||
The 3.x versions try to be backwards compatible, so you can easily run your old examples. But some functions like e.g. `sendNEC()` -see below- could not made backwards compatible,
|
||||
so in this cases you must revisit your code and adapt it to the 3.x library.<br/>
|
||||
If you program look like:
|
||||
```
|
||||
IRrecv irrecv(RECV_PIN);
|
||||
|
@ -80,7 +83,8 @@ void loop() {
|
|||
```
|
||||
it runs on the 3.x version as before. But only the following decoders are available then: Denon, JVC, LG, NEC, Panasonic, RC5, RC6, Samsung, Sony.
|
||||
The `results.value` is set by the decoders for **NEC, Panasonic, Sony, Samsung and JVC** as MSB first like in 2.x!<br/>
|
||||
- The old functions `sendNEC()` and `sendJVC()` are deprecated and renamed to `sendNECMSB()` and `sendJVCMSB()` to make it clearer that they send data with MSB first, which is not the standard for NEC and JVC. Use them to send your **old MSB-first 32 bit IR data codes**.
|
||||
- The old functions `sendNEC()` and `sendJVC()` are deprecated and renamed to `sendNECMSB()` and `sendJVCMSB()` to make it clearer that they send data with MSB first,
|
||||
which is not the standard for NEC and JVC. Use them to send your **old MSB-first 32 bit IR data codes**.
|
||||
In the new version you will send NEC (and other) commands not by 32 bit codes but by a (constant) 8 bit address and an 8 bit command.
|
||||
|
||||
# How to convert old MSB first 32 bit IR data codes to new LSB first 32 bit IR data codes
|
||||
|
@ -98,7 +102,8 @@ Example:
|
|||
Please do not use the old send*Raw() functions for sending like e.g. `IrSender.sendNECRaw(0xE61957A8,2)`,
|
||||
even if this functions are used in a lot of **(old)** tutorials. They are only kept for backward compatibility and unsupported and error prone.<br/>
|
||||
**Much better** is to use the **new structured functions** with address and command parameters like e.g. `IrSender.sendNEC(0xA8, 0x19, 2)`.
|
||||
Especially if you are able to receive these remote codes and get the address and command values. You will discover that **the address is a constant** and the commands sometimes are sensibly grouped.
|
||||
Especially if you are able to receive these remote codes and get the address and command values.
|
||||
You will discover that **the address is a constant** and the commands sometimes are sensibly grouped.
|
||||
|
||||
# FAQ
|
||||
- IR does not work right when I use **Neopixels** (aka WS2811/WS2812/WS2812B) or other libraries blocking interrupts for a longer time (> 50 us).<br/>
|
||||
|
@ -112,7 +117,7 @@ In turn, this stops the IR interrupt handler from running when it needs to. Ther
|
|||
- The **minimal CPU frequency** for receiving is 4 MHz, since the 50 us timer ISR takes around 12 us on a 16 MHz ATmega.
|
||||
|
||||
# Minimal version
|
||||
For applications only requiring NEC protocol, there is a receiver which has very **small codesize of 500 bytes and does NOT require any timer**. See the MinimalReceiver and IRDispatcherDemo example how to use it. Mapping of pins to interrupts can be found [here](https://github.com/Arduino-IRremote/Arduino-IRremote/tree/master/src/TinyIRReceiver.hpp#L307).
|
||||
For applications only requiring NEC protocol, there is a receiver which has very **small code size of 500 bytes and does NOT require any timer**. See the MinimalReceiver and IRDispatcherDemo example how to use it. Mapping of pins to interrupts can be found [here](https://github.com/Arduino-IRremote/Arduino-IRremote/tree/master/src/TinyIRReceiver.hpp#L307).
|
||||
|
||||
# Handling unknown Protocols
|
||||
## Disclaimer
|
||||
|
@ -154,8 +159,11 @@ In order to fit the examples to the 8K flash of ATtiny85 and ATtiny88, the [Ardu
|
|||
### SimpleReceiver + SimpleSender
|
||||
This examples are a good starting point.
|
||||
|
||||
### ReceiveDemo + SendDemo
|
||||
More complete examples for the advanced user.
|
||||
### ReceiveDemo
|
||||
Receives all protocols and play a beep on each packet received. By connecting pin 5 to ground, you can see the raw values for each packet.
|
||||
|
||||
### SendDemo
|
||||
Sends all available protocols at least once.
|
||||
|
||||
### ReceiveAndSend + UnitTest
|
||||
ReceiveDemo + SendDemo in one program. **Receiving while sending**.
|
||||
|
@ -180,6 +188,12 @@ Control a relay (connected to an output pin) with your remote.
|
|||
### IRremoteExtensionTest
|
||||
Example for a user defined class, which itself uses the IRrecv class from IRremote.
|
||||
|
||||
### SendLGAirConditionerDemo
|
||||
Example for sending LG air conditioner IR codes controlled by Serial input.<br/>
|
||||
By just using the function `bool Aircondition_LG::sendCommandAndParameter(char aCommand, int aParameter)` you can control the air conditioner by any other command source.<br/>
|
||||
The file *acLG.h* contains the command documentation of the LG air conditioner IR protocol. Based on reverse engineering of the LG AKB73315611 remote.
|
||||
![LG AKB73315611 remote](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/pictures/LG_AKB73315611.jpg)
|
||||
|
||||
### ReceiverTimingAnalysis
|
||||
This example analyzes the signal delivered by your IR receiver module.
|
||||
Values can be used to determine the stability of the received signal as well as a hint for determining the protocol.<br/>
|
||||
|
@ -189,7 +203,8 @@ Click on the receiver while simulation is running to specify individual NEC IR c
|
|||
|
||||
# Compile options / macros for this library
|
||||
To customize the library to different requirements, there are some compile options / macros available.<br/>
|
||||
Modify it by commenting them out or in, or change the values if applicable. Or define the macro with the -D compiler option for global compile (the latter is not possible with the Arduino IDE, so consider using [Sloeber](https://eclipse.baeyens.it).
|
||||
Modify it by commenting them out or in, or change the values if applicable.
|
||||
Or define the macro with the -D compiler option for global compile (the latter is not possible with the Arduino IDE, so consider using [Sloeber](https://eclipse.baeyens.it).
|
||||
|
||||
| Name | File | Default value | Description |
|
||||
|-|-|-|-|
|
||||
|
@ -209,7 +224,6 @@ Modify it by commenting them out or in, or change the values if applicable. Or d
|
|||
| `IR_SEND_DUTY_CYCLE` | IRremoteInt.h | 30 | Duty cycle of IR send signal. |
|
||||
| `MICROS_PER_TICK` | IRremoteInt.h | 50 | Resolution of the raw input buffer data. |
|
||||
| `IR_USE_AVR_TIMER*` | private/IRTimer.hpp | | Selection of timer to be used for generating IR receiving sample interval. |
|
||||
|
||||
|-|-|-|-|
|
||||
| `IR_INPUT_PIN` | TinyIRReceiver.h | 2 | The pin number for TinyIRReceiver IR input, which gets compiled in. |
|
||||
| `IR_FEEDBACK_LED_PIN` | TinyIRReceiver.h | `LED_BUILTIN` | The pin number for TinyIRReceiver feedback LED, which gets compiled in. |
|
||||
|
@ -224,7 +238,7 @@ The modification must be renewed for each new IRremote library version!
|
|||
|
||||
### Modifying compile options with Sloeber IDE
|
||||
If you are using Sloeber as your IDE, you can easily define global symbols with *Properties > Arduino > CompileOptions*.<br/>
|
||||
![Sloeber settings](https://github.com/ArminJo/ServoEasing/blob/master/pictures/SloeberDefineSymbols.png)
|
||||
![Sloeber settings](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/pictures/SloeberDefineSymbols.png)
|
||||
|
||||
# Supported Boards
|
||||
Digispark boards are tested with the recommended [ATTinyCore](https://github.com/SpenceKonde/ATTinyCore) using `New Style` pin mapping for the pro board.
|
||||
|
@ -277,7 +291,7 @@ For the AVR platform the code to modify looks like:
|
|||
You **just have to modify the comments** of the current and desired timer line.
|
||||
But be aware that the new timer in turn might be incompatible with other libraries or commands.<br/>
|
||||
The modification must be renewed for each new IRremote library version, or you use an IDE like [Sloeber](https://github.com/Arduino-IRremote/Arduino-IRremote#modifying-compile-options-with-sloeber-ide).<br/>
|
||||
For other platforms you must modify the approriate section guarded by e.g. `#elif defined(ESP32)`.
|
||||
For other platforms you must modify the appropriate section guarded by e.g. `#elif defined(ESP32)`.
|
||||
|
||||
Another approach can be to share the timer **sequentially** if their functionality is used only for a short period of time like for the **Arduino tone() command**.
|
||||
An example can be seen [here](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/21b5747a58e9d47c9e3f1beb056d58c875a92b47/examples/ReceiveDemo/ReceiveDemo.ino#L159-L169), where the timer settings for IR receive are restored after the tone has stopped.
|
||||
|
|
|
@ -10,6 +10,8 @@ See also the commit log at github: https://github.com/Arduino-IRremote/Arduino-I
|
|||
- Compiler switch USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN added.
|
||||
- Moved blink13() back to IRrecv class.
|
||||
- Added Kaseikyo convenience functions like sendKaseikyo_Denon().
|
||||
- Improved LG protocol and added class Aircondition_LG based on real hardware supplied by makerspace 201 (https://wiki.hackerspaces.org/ZwoNullEins) from Cologne.
|
||||
- Improved universal decoder for pulse width or pulse distance protocols to support more than 32 bits.
|
||||
|
||||
## 3.3.0
|
||||
- Fix errors if LED_BUILTIN is not defined.
|
||||
|
|
|
@ -55,10 +55,11 @@
|
|||
|
||||
// MARK_EXCESS_MICROS is subtracted from all marks and added to all spaces before decoding,
|
||||
// to compensate for the signal forming of different IR receiver modules.
|
||||
#define MARK_EXCESS_MICROS 20 // 20 is recommended for the cheap VS1838 modules
|
||||
//#define MARK_EXCESS_MICROS 20 // 20 is recommended for the cheap VS1838 modules
|
||||
|
||||
#define RECORD_GAP_MICROS 12000 // Activate it for some LG air conditioner protocols
|
||||
//#define RECORD_GAP_MICROS 12000 // Activate it for some LG air conditioner protocols
|
||||
|
||||
//#define
|
||||
/*
|
||||
* First define macros for input and output pin etc.
|
||||
*/
|
||||
|
@ -134,8 +135,9 @@ void loop() {
|
|||
Serial.println();
|
||||
#if FLASHEND >= 0x3FFF // For 16k flash or more, like ATtiny1604
|
||||
if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_WAS_OVERFLOW) {
|
||||
IrReceiver.decodedIRData.flags = false; // yes we have recognized the flag :-)
|
||||
Serial.println(F("Overflow detected"));
|
||||
Serial.println(F("Try to increase the \"RAW_BUFFER_LENGTH\" value in IRremoteInt.h to 750."));
|
||||
// see also https://github.com/Arduino-IRremote/Arduino-IRremote#modifying-compile-options-with-sloeber-ide
|
||||
# if !defined(ESP32) && !defined(ESP8266) && !defined(NRF5)
|
||||
/*
|
||||
* do double beep
|
||||
|
@ -143,6 +145,9 @@ void loop() {
|
|||
IrReceiver.stop();
|
||||
tone(TONE_PIN, 1100, 10);
|
||||
delay(50);
|
||||
tone(TONE_PIN, 1100, 10);
|
||||
delay(50);
|
||||
IrReceiver.start(100000); // to compensate for 100 ms stop of receiver. This enables a correct gap measurement.
|
||||
# endif
|
||||
|
||||
} else {
|
||||
|
|
|
@ -131,24 +131,30 @@ void loop() {
|
|||
Serial.println(F("Send NEC 16 bit address=0xFB04 and command 0x08 with exact timing (16 bit array format)"));
|
||||
Serial.flush();
|
||||
const uint16_t irSignal[] = { 9000, 4500/*Start bit*/, 560, 560, 560, 560, 560, 1690, 560,
|
||||
560/*0010 0x4 of 16 bit address LSB first*/, 560, 560, 560, 560, 560, 560, 560, 560/*0000*/, 560, 1690, 560, 1690, 560,
|
||||
560, 560, 1690/*1101 0xB*/, 560, 1690, 560, 1690, 560, 1690, 560, 1690/*1111*/, 560, 560, 560, 560, 560, 560, 560,
|
||||
1690/*0001 0x08 of command LSB first*/, 560, 560, 560, 560, 560, 560, 560, 560/*0000 0x00*/, 560, 1690, 560, 1690, 560,
|
||||
1690, 560, 560/*1110 Inverted 8 of command*/, 560, 1690, 560, 1690, 560, 1690, 560, 1690/*1111 inverted 0 of command*/,
|
||||
560 /*stop bit*/}; // Using exact NEC timing
|
||||
560/*0010 0x4 of 16 bit address LSB first*/, 560, 560, 560, 560, 560, 560, 560, 560/*0000*/, 560, 1690, 560, 1690,
|
||||
560, 560, 560, 1690/*1101 0xB*/, 560, 1690, 560, 1690, 560, 1690, 560, 1690/*1111*/, 560, 560, 560, 560, 560, 560,
|
||||
560, 1690/*0001 0x08 of command LSB first*/, 560, 560, 560, 560, 560, 560, 560, 560/*0000 0x00*/, 560, 1690, 560,
|
||||
1690, 560, 1690, 560, 560/*1110 Inverted 8 of command*/, 560, 1690, 560, 1690, 560, 1690, 560,
|
||||
1690/*1111 inverted 0 of command*/, 560 /*stop bit*/}; // Using exact NEC timing
|
||||
IrSender.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), NEC_KHZ); // Note the approach used to automatically calculate the size of the array.
|
||||
delay(DELAY_AFTER_SEND);
|
||||
#endif
|
||||
/*
|
||||
* With sendNECRaw() you can send 32 bit combined codes
|
||||
*/
|
||||
Serial.println(
|
||||
F(
|
||||
"Send NEC / ONKYO with 16 bit address 0x0102 and 16 bit command 0x0304 with NECRaw(0x03040102)"));
|
||||
Serial.println(F("Send NEC / ONKYO with 16 bit address 0x0102 and 16 bit command 0x0304 with NECRaw(0x03040102)"));
|
||||
Serial.flush();
|
||||
IrSender.sendNECRaw(0x03040102, sRepeats);
|
||||
delay(DELAY_AFTER_SEND);
|
||||
|
||||
Serial.println(F("Send NEC with 16 bit address 0x0102 and 16 bit command 0x0304 with sendPulseDistanceWidthData()"));
|
||||
// Header
|
||||
IrSender.mark(9000);
|
||||
IrSender.space(4500);
|
||||
// LSB first + stop bit
|
||||
IrSender.sendPulseDistanceWidthData(560, 1680, 560, 560, 0x03040102, 32, PROTOCOL_IS_LSB_FIRST, SEND_STOP_BIT);
|
||||
delay(DELAY_AFTER_SEND);
|
||||
|
||||
/*
|
||||
* With Send sendNECMSB() you can send your old 32 bit codes.
|
||||
* To convert one into the other, you must reverse the byte positions and then reverse all positions of each byte.
|
||||
|
|
|
@ -32,8 +32,15 @@
|
|||
*/
|
||||
#include <Arduino.h>
|
||||
|
||||
// LG2 has different header timing and a shorter bit time
|
||||
/*
|
||||
* LG2 has different header timing and a shorter bit time
|
||||
* Known LG remote controls, which uses LG2 protocol are:
|
||||
* AKB75215403
|
||||
* AKB74955603
|
||||
* AKB73757604:
|
||||
*/
|
||||
//#define USE_LG2_PROTOCOL // Try it if you do not have success with the default LG protocol
|
||||
#define NUMBER_OF_COMMANDS_BETWEEN_PRINT_OF_MENU 5
|
||||
|
||||
/*
|
||||
* Define macros for input and output pin etc.
|
||||
|
@ -41,7 +48,7 @@
|
|||
#include "PinDefinitionsAndMore.h"
|
||||
|
||||
#include <IRremote.h>
|
||||
#include "LongUnion.h"
|
||||
#include "ac_LG.h"
|
||||
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
|
||||
#include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut"
|
||||
|
@ -52,140 +59,11 @@
|
|||
#define Serial SerialUSB
|
||||
#endif
|
||||
|
||||
bool ACIsWallType = false; // false : TOWER, true : WALL
|
||||
bool ACIsHeating = false; // false : cooling, true : heating
|
||||
bool ACPowerIsOn = false;
|
||||
bool ACStateIsAirClean = false; // false : off, 1 : true --> power on
|
||||
uint8_t ACRequestedFanIntensity = 1; // 0 : low, 1 : mid, 2 : high - if ACIsWallType==Wall then 3 -> cycle
|
||||
uint8_t ACRequestedTemperature = 25; // temperature : 18 ~ 30
|
||||
|
||||
const int AC_FAN_TOWER[3] = { 0, 4, 6 };
|
||||
const int AC_FAN_WALL[4] = { 0, 2, 4, 5 }; // 5 -> cycle
|
||||
|
||||
// from https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h
|
||||
union LGProtocol{
|
||||
uint32_t raw; ///< The state of the IR remote in IR code form.
|
||||
struct {
|
||||
uint32_t Sum :4;
|
||||
uint32_t Fan :3;
|
||||
uint32_t FanExt :1;
|
||||
uint32_t Temp :4;
|
||||
uint32_t Mode :3;
|
||||
uint32_t :3;
|
||||
uint32_t Power :2;
|
||||
uint32_t Signature :8; /*=0x88*/
|
||||
};
|
||||
};
|
||||
|
||||
void ACSendCode(uint16_t aCommand) {
|
||||
Serial.print(F("Send code="));
|
||||
Serial.print(aCommand, HEX);
|
||||
Serial.print(F(" | "));
|
||||
Serial.println(aCommand, BIN);
|
||||
Serial.flush();
|
||||
#if defined(USE_LG2_PROTOCOL)
|
||||
IrSender.sendLG((uint8_t) 0x88, aCommand, 0, true);
|
||||
#else
|
||||
IrSender.sendLG((uint8_t) 0x88, aCommand, 0, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void sendCommand(uint8_t aTemperature, uint8_t aFanIntensity) {
|
||||
|
||||
Serial.print(F("Send temperature="));
|
||||
Serial.print(aTemperature);
|
||||
Serial.print(F(" fan intensity="));
|
||||
Serial.println(aFanIntensity);
|
||||
|
||||
WordUnion tCommand;
|
||||
tCommand.UWord = 0;
|
||||
if (ACIsHeating) {
|
||||
// heating
|
||||
tCommand.UByte.HighByte = 0x4; // maybe cooling is 0x08????
|
||||
}
|
||||
// Temperature is coded in the upper nibble of the LowByte
|
||||
tCommand.UByte.LowByte = ((aTemperature - 15) << 4); // 16 -> 0x00, 18 -> 0x30, 30 -> 0xF0
|
||||
|
||||
// Fan intensity is coded in the lower nibble of the LowByte
|
||||
if (ACIsWallType) {
|
||||
tCommand.UByte.LowByte |= AC_FAN_WALL[aFanIntensity];
|
||||
} else {
|
||||
tCommand.UByte.LowByte |= AC_FAN_TOWER[aFanIntensity];
|
||||
}
|
||||
|
||||
ACSendCode(tCommand.UWord);
|
||||
ACPowerIsOn = true;
|
||||
ACRequestedTemperature = aTemperature;
|
||||
ACRequestedFanIntensity = aFanIntensity;
|
||||
}
|
||||
|
||||
void sendAirSwing(bool aSwing) {
|
||||
Serial.print(F("Send air swing="));
|
||||
Serial.println(aSwing);
|
||||
if (ACIsWallType) {
|
||||
if (aSwing) {
|
||||
ACSendCode(0x1314);
|
||||
} else {
|
||||
ACSendCode(0x1315);
|
||||
}
|
||||
} else {
|
||||
if (aSwing) {
|
||||
ACSendCode(0x1316);
|
||||
} else {
|
||||
ACSendCode(0x1317);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendPowerDown() {
|
||||
Serial.println(F("Send power down"));
|
||||
ACSendCode(0xC005);
|
||||
ACPowerIsOn = false;
|
||||
}
|
||||
|
||||
void sendAirClean(bool aStateAirClean) {
|
||||
Serial.print(F("Send air clean="));
|
||||
Serial.println(aStateAirClean);
|
||||
if (aStateAirClean) {
|
||||
ACSendCode(0xC000);
|
||||
} else {
|
||||
ACSendCode(0xC008);
|
||||
}
|
||||
ACStateIsAirClean = aStateAirClean;
|
||||
}
|
||||
|
||||
void sendJet(bool aJetOn) {
|
||||
Serial.print(F("Send jet on="));
|
||||
Serial.println(aJetOn);
|
||||
if (aJetOn) {
|
||||
ACSendCode(0x1008);
|
||||
} else {
|
||||
ACSendCode(0x0834);
|
||||
}
|
||||
}
|
||||
|
||||
void printMenu() {
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("Type command and optional parameter without a separator"));
|
||||
Serial.println(F("0 Off"));
|
||||
Serial.println(F("1 On"));
|
||||
Serial.println(F("s Swing <0 or 1>"));
|
||||
Serial.println(F("c Air clean <0 or 1>"));
|
||||
Serial.println(F("j Jet <0 or 1>"));
|
||||
Serial.println(F("f Fan <0 to 2 or 3 for cycle>"));
|
||||
Serial.println(F("t Temperature <18 to 30>"));
|
||||
Serial.println(F("+ Temperature + 1"));
|
||||
Serial.println(F("- Temperature - 1"));
|
||||
Serial.println(F("e.g. \"s1\" or \"t23\" or \"+\""));
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
#define SIZE_OF_RECEIVE_BUFFER 10
|
||||
|
||||
char sRequestString[SIZE_OF_RECEIVE_BUFFER];
|
||||
|
||||
Aircondition_LG MyLG_Aircondition;
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
|
@ -203,87 +81,70 @@ delay(4000); // To be able to connect Serial monitor after reset or power up and
|
|||
|
||||
Serial.print(F("Ready to send IR signals at pin "));
|
||||
Serial.println(IR_SEND_PIN);
|
||||
Serial.println();
|
||||
MyLG_Aircondition.setType(LG_IS_WALL_TYPE);
|
||||
MyLG_Aircondition.printMenu();
|
||||
|
||||
delay(1000);
|
||||
|
||||
// test
|
||||
// sendCommand(25, 1);
|
||||
// MyLG_Aircondition.sendCommandAndParameter('j', 1);
|
||||
// delay(5000);
|
||||
// sendCommand(27, 2);
|
||||
// MyLG_Aircondition.sendCommandAndParameter('f', 3);
|
||||
// delay(5000);
|
||||
|
||||
printMenu();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Test
|
||||
// sendCommand(25, 1);
|
||||
// delay(5000);
|
||||
// sendCommand(27, 0);
|
||||
// delay(5000);
|
||||
static uint8_t sShowmenuConter = 0;
|
||||
|
||||
if (Serial.available()) {
|
||||
/*
|
||||
* Get parameters from serial
|
||||
*/
|
||||
uint8_t tNumberOfBytesReceived = Serial.readBytesUntil('\n', sRequestString, SIZE_OF_RECEIVE_BUFFER - 1);
|
||||
// handle CR LF
|
||||
if (sRequestString[tNumberOfBytesReceived - 1] == '\r') {
|
||||
tNumberOfBytesReceived--;
|
||||
}
|
||||
sRequestString[tNumberOfBytesReceived] = '\0'; // terminate as string
|
||||
char tCommand = sRequestString[0];
|
||||
uint8_t tParameter = 0;
|
||||
|
||||
/*
|
||||
* Handle parameter numbers which can be greater 9
|
||||
*/
|
||||
int tParameter = 0;
|
||||
if (tNumberOfBytesReceived >= 2) {
|
||||
tParameter = sRequestString[1] - '0';
|
||||
if (tCommand == LG_COMMAND_TEMPERATURE || tCommand == LG_COMMAND_SWING || tCommand == LG_COMMAND_SLEEP
|
||||
|| tCommand == LG_COMMAND_TIMER_ON || tCommand == LG_COMMAND_TIMER_OFF) {
|
||||
tParameter = atoi(&sRequestString[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print command to send
|
||||
*/
|
||||
Serial.print(F("Command="));
|
||||
Serial.println(tCommand);
|
||||
Serial.print(tCommand);
|
||||
if (tParameter != 0) {
|
||||
Serial.print(F(" Parameter="));
|
||||
Serial.print(tParameter);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
switch (tCommand) {
|
||||
case 0: // off
|
||||
SendPowerDown();
|
||||
break;
|
||||
case 1: // on
|
||||
sendCommand(ACRequestedTemperature, ACRequestedFanIntensity);
|
||||
break;
|
||||
case 's':
|
||||
sendAirSwing(tParameter);
|
||||
break;
|
||||
case 'c': // 1 : clean on, power on
|
||||
sendAirClean(tParameter);
|
||||
break;
|
||||
case 'j':
|
||||
sendJet(tParameter);
|
||||
break;
|
||||
case 'f':
|
||||
if (tParameter <= 2) {
|
||||
sendCommand(ACRequestedTemperature, tParameter);
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
tParameter = atoi(&sRequestString[1]);
|
||||
if (18 <= tParameter && tParameter <= 30) {
|
||||
sendCommand(tParameter, ACRequestedFanIntensity);
|
||||
}
|
||||
break;
|
||||
case '+':
|
||||
if (18 <= ACRequestedTemperature && ACRequestedTemperature <= 29) {
|
||||
sendCommand((ACRequestedTemperature + 1), ACRequestedFanIntensity);
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (19 <= ACRequestedTemperature && ACRequestedTemperature <= 30) {
|
||||
sendCommand((ACRequestedTemperature - 1), ACRequestedFanIntensity);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Serial.print(F("Error: unknown command \""));
|
||||
if (!MyLG_Aircondition.sendCommandAndParameter(tCommand, tParameter)) {
|
||||
Serial.print(F("Error: unknown command or invalid parameter in \""));
|
||||
Serial.print(sRequestString);
|
||||
Serial.println('\"');
|
||||
}
|
||||
|
||||
if (tParameter != 0) {
|
||||
Serial.print(F("Parameter="));
|
||||
Serial.println(tParameter);
|
||||
if (sShowmenuConter == 0) {
|
||||
MyLG_Aircondition.printMenu();
|
||||
sShowmenuConter = NUMBER_OF_COMMANDS_BETWEEN_PRINT_OF_MENU;
|
||||
} else {
|
||||
sShowmenuConter--;
|
||||
}
|
||||
|
||||
printMenu();
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 336 KiB After Width: | Height: | Size: 336 KiB |
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -122,7 +122,7 @@ void IRrecv::start() {
|
|||
* Configures the timer and the state machine for IR reception.
|
||||
* @param aMicrosecondsToAddToGapCounter To compensate for microseconds the timer was stopped / disabled.
|
||||
*/
|
||||
void IRrecv::start(uint16_t aMicrosecondsToAddToGapCounter) {
|
||||
void IRrecv::start(uint32_t aMicrosecondsToAddToGapCounter) {
|
||||
enableIRIn();
|
||||
noInterrupts();
|
||||
irparams.TickCounterForISR += aMicrosecondsToAddToGapCounter / MICROS_PER_TICK;
|
||||
|
@ -197,7 +197,7 @@ void IRrecv::resume() {
|
|||
void IRrecv::initDecodedIRData() {
|
||||
|
||||
if (irparams.OverflowFlag) {
|
||||
// Copy overflow flag to decodedIRData.flags
|
||||
// Copy overflow flag to decodedIRData.flags and reset it
|
||||
irparams.OverflowFlag = false;
|
||||
irparams.rawlen = 0; // otherwise we have OverflowFlag again at next ISR call
|
||||
decodedIRData.flags = IRDATA_FLAGS_WAS_OVERFLOW;
|
||||
|
@ -689,8 +689,12 @@ bool IRrecv::decodeHash() {
|
|||
if (decodedIRData.rawDataPtr->rawlen < 6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 1; (i + 2) < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
#if RAW_BUFFER_LENGTH <= 254 // saves around 75 bytes program space and speeds up ISR
|
||||
uint8_t i;
|
||||
#else
|
||||
uint16_t i;
|
||||
#endif
|
||||
for (i = 1; (i + 2) < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
uint8_t value = compare(decodedIRData.rawDataPtr->rawbuf[i], decodedIRData.rawDataPtr->rawbuf[i + 2]);
|
||||
// Add value into the hash
|
||||
hash = (hash * FNV_PRIME_32) ^ value;
|
||||
|
@ -1007,8 +1011,12 @@ void IRrecv::printIRResultRawFormatted(Print *aSerial, bool aOutputMicrosecondsI
|
|||
}
|
||||
aSerial->print(F(" -"));
|
||||
aSerial->println(tDurationMicros, DEC);
|
||||
|
||||
for (uint8_t i = 1; i < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
#if RAW_BUFFER_LENGTH <= 254 // saves around 75 bytes program space and speeds up ISR
|
||||
uint8_t i;
|
||||
#else
|
||||
uint16_t i;
|
||||
#endif
|
||||
for (i = 1; i < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
if (aOutputMicrosecondsInsteadOfTicks) {
|
||||
tDurationMicros = decodedIRData.rawDataPtr->rawbuf[i] * MICROS_PER_TICK;
|
||||
} else {
|
||||
|
@ -1066,7 +1074,12 @@ void IRrecv::compensateAndPrintIRResultAsCArray(Print *aSerial, bool aOutputMicr
|
|||
aSerial->print(F("] = {")); // Start declaration
|
||||
|
||||
// Dump data
|
||||
for (unsigned int i = 1; i < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
#if RAW_BUFFER_LENGTH <= 254 // saves around 75 bytes program space and speeds up ISR
|
||||
uint8_t i;
|
||||
#else
|
||||
uint16_t i;
|
||||
#endif
|
||||
for (i = 1; i < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
uint32_t tDuration = decodedIRData.rawDataPtr->rawbuf[i] * MICROS_PER_TICK;
|
||||
|
||||
if (i & 1) {
|
||||
|
@ -1111,8 +1124,13 @@ void IRrecv::compensateAndPrintIRResultAsCArray(Print *aSerial, bool aOutputMicr
|
|||
*/
|
||||
void IRrecv::compensateAndStoreIRResultInArray(uint8_t *aArrayPtr) {
|
||||
|
||||
// Store data, skip leading space
|
||||
for (unsigned int i = 1; i < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
// Store data, skip leading space#
|
||||
#if RAW_BUFFER_LENGTH <= 254 // saves around 75 bytes program space and speeds up ISR
|
||||
uint8_t i;
|
||||
#else
|
||||
uint16_t i;
|
||||
#endif
|
||||
for (i = 1; i < decodedIRData.rawDataPtr->rawlen; i++) {
|
||||
uint32_t tDuration = decodedIRData.rawDataPtr->rawbuf[i] * MICROS_PER_TICK;
|
||||
if (i & 1) {
|
||||
// Mark
|
||||
|
@ -1312,7 +1330,7 @@ ISR () // for functions definitions which are called by separate (board specific
|
|||
irparams.TickCounterForISR = 0;// reset counter in both cases
|
||||
}
|
||||
|
||||
} else if (irparams.StateForISR == IR_REC_STATE_MARK) { // Timing Mark
|
||||
} else if (irparams.StateForISR == IR_REC_STATE_MARK) { // Timing mark
|
||||
if (tIRInputLevel != INPUT_MARK) { // Mark ended; Record time
|
||||
#if defined(IR_MEASURE_TIMING) && defined(IR_TIMING_TEST_PIN)
|
||||
// digitalWriteFast(IR_TIMING_TEST_PIN, HIGH); // 2 clock cycles
|
||||
|
@ -1322,10 +1340,10 @@ ISR () // for functions definitions which are called by separate (board specific
|
|||
irparams.TickCounterForISR = 0;
|
||||
}
|
||||
|
||||
} else if (irparams.StateForISR == IR_REC_STATE_SPACE) { // Timing Space
|
||||
} else if (irparams.StateForISR == IR_REC_STATE_SPACE) { // Timing space
|
||||
if (tIRInputLevel == INPUT_MARK) { // Space just ended; Record time
|
||||
if (irparams.rawlen >= RAW_BUFFER_LENGTH) {
|
||||
// Flag up a read OverflowFlag; Stop the State Machine
|
||||
// Flag up a read OverflowFlag; Stop the state machine
|
||||
irparams.OverflowFlag = true;
|
||||
irparams.StateForISR = IR_REC_STATE_STOP;
|
||||
} else {
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
/****************************************************
|
||||
* PROTOCOLS
|
||||
****************************************************/
|
||||
|
||||
/*
|
||||
* Supported IR protocols
|
||||
* Each protocol you include costs memory and, during decode, costs time
|
||||
|
@ -98,10 +97,10 @@
|
|||
|
||||
//#define DEBUG // Activate this for lots of lovely debug output from the IRremote core.
|
||||
|
||||
|
||||
/****************************************************
|
||||
* RECEIVING
|
||||
****************************************************/
|
||||
|
||||
/**
|
||||
* MARK_EXCESS_MICROS is subtracted from all marks and added to all spaces before decoding,
|
||||
* to compensate for the signal forming of different IR receiver modules
|
||||
|
@ -175,7 +174,6 @@
|
|||
* Attention, active state of open drain is LOW, so connect the send LED between positive supply and send pin!
|
||||
*/
|
||||
//#define USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN
|
||||
|
||||
/**
|
||||
* This amount is subtracted from the on-time of the pulses generated for software PWM generation.
|
||||
* It should be the time used for digitalWrite(sendPin, LOW) and the call to delayMicros()
|
||||
|
|
|
@ -34,8 +34,13 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if ! defined(RAW_BUFFER_LENGTH)
|
||||
/*
|
||||
* The length of the buffer where the IR timing data is stored before decoding
|
||||
* 100 is sufficient for most standard protocols, but air conditioners often send a longer protocol data stream
|
||||
*/
|
||||
#if !defined(RAW_BUFFER_LENGTH)
|
||||
#define RAW_BUFFER_LENGTH 100 ///< Maximum length of raw duration buffer. Must be even. 100 supports up to 48 bit codings inclusive 1 start and 1 stop bit.
|
||||
//#define RAW_BUFFER_LENGTH 750 // Value for air condition remotes.
|
||||
#endif
|
||||
#if RAW_BUFFER_LENGTH % 2 == 1
|
||||
#error RAW_BUFFER_LENGTH must be even, since the array consists of space / mark pairs.
|
||||
|
@ -63,7 +68,7 @@
|
|||
#define IR_REC_STATE_IDLE 0
|
||||
#define IR_REC_STATE_MARK 1
|
||||
#define IR_REC_STATE_SPACE 2
|
||||
#define IR_REC_STATE_STOP 3
|
||||
#define IR_REC_STATE_STOP 3 // set to IR_REC_STATE_IDLE only by resume()
|
||||
|
||||
/**
|
||||
* This struct contains the data and control used for receiver static functions and the ISR (interrupt service routine)
|
||||
|
@ -80,7 +85,7 @@ struct irparams_struct {
|
|||
uint16_t TickCounterForISR; ///< Counts 50uS ticks. The value is copied into the rawbuf array on every transition.
|
||||
|
||||
bool OverflowFlag; ///< Raw buffer OverflowFlag occurred
|
||||
#if RAW_BUFFER_LENGTH <= 255 // saves around 75 bytes program space and speeds up ISR
|
||||
#if RAW_BUFFER_LENGTH <= 254 // saves around 75 bytes program space and speeds up ISR
|
||||
uint8_t rawlen; ///< counter of entries in rawbuf
|
||||
#else
|
||||
unsigned int rawlen; ///< counter of entries in rawbuf
|
||||
|
@ -88,6 +93,24 @@ struct irparams_struct {
|
|||
uint16_t rawbuf[RAW_BUFFER_LENGTH]; ///< raw data / tick counts per mark/space, first entry is the length of the gap between previous and current command
|
||||
};
|
||||
|
||||
/*
|
||||
* Info directives
|
||||
* Can be disabled to save program space
|
||||
*/
|
||||
#ifdef INFO
|
||||
# define INFO_PRINT(...) Serial.print(__VA_ARGS__)
|
||||
# define INFO_PRINTLN(...) Serial.println(__VA_ARGS__)
|
||||
#else
|
||||
/**
|
||||
* If INFO, print the arguments, otherwise do nothing.
|
||||
*/
|
||||
# define INFO_PRINT(...) void()
|
||||
/**
|
||||
* If INFO, print the arguments as a line, otherwise do nothing.
|
||||
*/
|
||||
# define INFO_PRINTLN(...) void()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Debug directives
|
||||
*/
|
||||
|
@ -165,7 +188,7 @@ struct IRData {
|
|||
uint16_t address; ///< Decoded address
|
||||
uint16_t command; ///< Decoded command
|
||||
uint16_t extra; ///< Used by MagiQuest and for Kaseikyo unknown vendor ID. Ticks used for decoding Distance protocol.
|
||||
uint8_t numberOfBits; ///< Number of bits received for data (address + command + parity) - to determine protocol length if different length are possible.
|
||||
uint16_t numberOfBits; ///< Number of bits received for data (address + command + parity) - to determine protocol length if different length are possible.
|
||||
uint8_t flags; ///< See IRDATA_FLAGS_* definitions above
|
||||
uint32_t decodedRawData; ///< Up to 32 bit decoded raw data, used for sendRaw functions.
|
||||
irparams_struct *rawDataPtr; ///< Pointer of the raw timing data to be decoded. Mainly the data buffer filled by receiving ISR.
|
||||
|
@ -195,7 +218,7 @@ public:
|
|||
*/
|
||||
void begin(uint8_t aReceivePin, bool aEnableLEDFeedback = false, uint8_t aFeedbackLEDPin = USE_DEFAULT_FEEDBACK_LED_PIN);
|
||||
void start(); // alias for enableIRIn
|
||||
void start(uint16_t aMicrosecondsToAddToGapCounter);
|
||||
void start(uint32_t aMicrosecondsToAddToGapCounter);
|
||||
bool available();
|
||||
IRData* read(); // returns decoded data
|
||||
// write is a method of class IRsend below
|
||||
|
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
* ac_LG.cpp
|
||||
*
|
||||
* Contains functions for receiving and sending LG air conditioner IR Protocol
|
||||
* There is no state plausibility check, e.g. you can send fan speed in Mode D and change temperature in mode F
|
||||
*
|
||||
* This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
|
||||
*
|
||||
************************************************************************************
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 Armin Joachimsmeyer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
************************************************************************************
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
|
||||
#define INFO // Deactivate this to save program space and suppress info output.
|
||||
//#define DEBUG // Activate this for lots of lovely debug output from this decoder.
|
||||
#include "IRremoteInt.h"
|
||||
#include "ac_LG.h" // evaluates the DEBUG for DEBUG_PRINT
|
||||
#include "LongUnion.h"
|
||||
|
||||
/** \addtogroup Airconditoners Air conditioner special code
|
||||
* @{
|
||||
*/
|
||||
/*
|
||||
* LG remote measurements: Type AKB73315611, Ver1.1 from 2011.03.01
|
||||
* Internal crystal: 4 MHz
|
||||
* Header: 8.9 ms mark 4.15 ms space
|
||||
* Data: 500 / 540 and 500 / 1580;
|
||||
* Clock is nor synchronized with gate so you have 19 and sometimes 19 and a spike pulses for mark
|
||||
* Duty: 9 us on 17 us off => around 33 % duty
|
||||
* NO REPEAT: If value like temperature has changed during long press, the last value is send at button release
|
||||
* If you do a double press -tested with the fan button-, the next value can be sent after 118 ms
|
||||
*/
|
||||
|
||||
const int AC_FAN_TOWER[3] = { 0, 4, 6 };
|
||||
const int AC_FAN_WALL[4] = { 0, 2, 4, 5 }; // 0 -> low, 4 high, 5 -> cycle
|
||||
|
||||
void Aircondition_LG::setType(bool aIsWallType) {
|
||||
ACIsWallType = aIsWallType;
|
||||
}
|
||||
|
||||
void Aircondition_LG::printMenu() {
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("Type command and optional parameter without a separator"));
|
||||
Serial.println(F("0 Off"));
|
||||
Serial.println(F("1 On"));
|
||||
Serial.println(F("s Swing <0 or 1>"));
|
||||
Serial.println(F("a Auto clean <0 or 1>"));
|
||||
Serial.println(F("j Jet <0 or 1>"));
|
||||
Serial.println(F("e Energy saving <0 or 1>"));
|
||||
Serial.println(F("l Light"));
|
||||
Serial.println(F("f Fan speed <0 to 4 or 5 for cycle>"));
|
||||
Serial.println(F("t Temperature <18 to 30> degree"));
|
||||
Serial.println(F("+ Temperature + 1"));
|
||||
Serial.println(F("- Temperature - 1"));
|
||||
Serial.println(F("M <C(ool) or A(uto) or D(ehumidifying) or H(eating) or F(an) mode>"));
|
||||
Serial.println(F("S Sleep after <0 to 420> minutes"));
|
||||
Serial.println(F("T Timer on after <0 to 1439> minutes"));
|
||||
Serial.println(F("O Timer off after <0 to 1439> minutes"));
|
||||
Serial.println(F("C Clear all timer and sleep"));
|
||||
Serial.println(F("e.g. \"s1\" or \"t23\" or \"O60\" or \"+\""));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
/*
|
||||
* Send repeat
|
||||
* Repeat commands should be sent in a 110 ms raster.
|
||||
* @param aCommand one of LG_COMMAND_OFF, LG_COMMAND_ON etc.
|
||||
*/
|
||||
bool Aircondition_LG::sendCommandAndParameter(char aCommand, int aParameter) {
|
||||
// Commands without parameter
|
||||
switch (aCommand) {
|
||||
case LG_COMMAND_OFF: // off
|
||||
sendIRCommand(LG_POWER_DOWN);
|
||||
PowerIsOn = false;
|
||||
return true;
|
||||
|
||||
case LG_COMMAND_ON: // on
|
||||
PowerIsOn = false; // set to false in order to suppress on bit
|
||||
sendTemperatureFanSpeedAndMode();
|
||||
return true;
|
||||
|
||||
case LG_COMMAND_JET:
|
||||
DEBUG_PRINTLN(F("Send jet on"));
|
||||
sendIRCommand(LG_JET_ON);
|
||||
return true;
|
||||
|
||||
case LG_COMMAND_LIGHT:
|
||||
sendIRCommand(LG_LIGHT);
|
||||
return true;
|
||||
|
||||
case LG_COMMAND_CLEAR_ALL:
|
||||
sendIRCommand(LG_CLEAR_ALL);
|
||||
return true;
|
||||
|
||||
case LG_COMMAND_TEMPERATURE_PLUS:
|
||||
if (18 <= Temperature && Temperature <= 29) {
|
||||
Temperature++;
|
||||
sendTemperatureFanSpeedAndMode();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case LG_COMMAND_TEMPERATURE_MINUS:
|
||||
if (19 <= Temperature && Temperature <= 30) {
|
||||
Temperature--;
|
||||
sendTemperatureFanSpeedAndMode();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
PowerIsOn = true;
|
||||
|
||||
/*
|
||||
* Now the commands which require a parameter
|
||||
*/
|
||||
if (aParameter < 0) {
|
||||
DEBUG_PRINT(F("Error: Parameter is less than 0"));
|
||||
return false;
|
||||
}
|
||||
switch (aCommand) {
|
||||
|
||||
case LG_COMMAND_MODE:
|
||||
Mode = aParameter + '0';
|
||||
sendTemperatureFanSpeedAndMode();
|
||||
break;
|
||||
|
||||
case LG_COMMAND_SWING:
|
||||
DEBUG_PRINT(F("Send air swing="));
|
||||
DEBUG_PRINTLN(aParameter);
|
||||
if (ACIsWallType) {
|
||||
if (aParameter) {
|
||||
sendIRCommand(LG_WALL_SWING_ON);
|
||||
} else {
|
||||
sendIRCommand(LG_WALL_SWING_OFF);
|
||||
}
|
||||
} else {
|
||||
if (aParameter) {
|
||||
sendIRCommand(LG_SWING_ON);
|
||||
} else {
|
||||
sendIRCommand(LG_SWING_OFF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LG_COMMAND_AUTO_CLEAN:
|
||||
DEBUG_PRINT(F("Send auto clean="));
|
||||
DEBUG_PRINTLN(aParameter);
|
||||
if (aParameter) {
|
||||
sendIRCommand(LG_AUTO_CLEAN_ON);
|
||||
} else {
|
||||
sendIRCommand(LG_AUTO_CLEAN_OFF);
|
||||
}
|
||||
break;
|
||||
|
||||
case LG_COMMAND_ENERGY:
|
||||
DEBUG_PRINT(F("Send energy saving on="));
|
||||
DEBUG_PRINTLN(aParameter);
|
||||
if (aParameter) {
|
||||
sendIRCommand(LG_ENERGY_SAVING_ON);
|
||||
} else {
|
||||
sendIRCommand(LG_ENERGY_SAVING_OFF);
|
||||
}
|
||||
break;
|
||||
|
||||
case LG_COMMAND_FAN_SPEED:
|
||||
if (aParameter <= 3) {
|
||||
FanIntensity = aParameter;
|
||||
sendTemperatureFanSpeedAndMode();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LG_COMMAND_TEMPERATURE:
|
||||
if (18 <= aParameter && aParameter <= 30) {
|
||||
Temperature = aParameter;
|
||||
sendTemperatureFanSpeedAndMode();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LG_COMMAND_SLEEP:
|
||||
if (aParameter <= 420) {
|
||||
sendIRCommand(LG_SLEEP + aParameter);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LG_COMMAND_TIMER_ON:
|
||||
if (aParameter <= 1439) {
|
||||
sendIRCommand(LG_TIMER_ON + aParameter);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case LG_COMMAND_TIMER_OFF:
|
||||
if (aParameter <= 1439) {
|
||||
sendIRCommand(LG_TIMER_OFF + aParameter);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Aircondition_LG::sendIRCommand(uint16_t aCommand) {
|
||||
|
||||
INFO_PRINT(F("Send code=0x"));
|
||||
INFO_PRINT(aCommand, HEX);
|
||||
INFO_PRINT(F(" | 0b"));
|
||||
INFO_PRINTLN(aCommand, BIN);
|
||||
|
||||
IrSender.sendLG((uint8_t) LG_ADDRESS, aCommand, 0, false, useLG2Protocol);
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes values from static variables
|
||||
*/
|
||||
void Aircondition_LG::sendTemperatureFanSpeedAndMode() {
|
||||
|
||||
uint8_t tTemperature = Temperature;
|
||||
INFO_PRINT(F("Send temperature="));
|
||||
INFO_PRINT(tTemperature);
|
||||
INFO_PRINT(F(" fan intensity="));
|
||||
INFO_PRINT(FanIntensity);
|
||||
INFO_PRINT(F(" mode="));
|
||||
INFO_PRINTLN((char )Mode);
|
||||
|
||||
WordUnion tIRCommand;
|
||||
tIRCommand.UWord = 0;
|
||||
|
||||
// Temperature is coded in the upper nibble of the LowByte
|
||||
tIRCommand.UByte.LowByte = ((tTemperature - 15) << 4); // 16 -> 0x00, 18 -> 0x30, 30 -> 0xF0
|
||||
|
||||
// Fan intensity is coded in the lower nibble of the LowByte
|
||||
if (ACIsWallType) {
|
||||
tIRCommand.UByte.LowByte |= AC_FAN_WALL[FanIntensity];
|
||||
} else {
|
||||
tIRCommand.UByte.LowByte |= AC_FAN_TOWER[FanIntensity];
|
||||
}
|
||||
|
||||
switch (Mode) {
|
||||
case 'C':
|
||||
tIRCommand.UByte.HighByte = LG_MODE_COOLING >> 8;
|
||||
break;
|
||||
case 'H':
|
||||
tIRCommand.UByte.HighByte = LG_MODE_HEATING >> 8;
|
||||
break;
|
||||
case 'A':
|
||||
tIRCommand.UByte.HighByte = LG_MODE_AUTO >> 8;
|
||||
break;
|
||||
case 'F':
|
||||
tTemperature = 18;
|
||||
tIRCommand.UByte.HighByte = LG_MODE_FAN >> 8;
|
||||
break;
|
||||
case 'D':
|
||||
tIRCommand.UWord = LG_MODE_DEHUMIDIFIYING;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!PowerIsOn) {
|
||||
// switch on requires masked bit
|
||||
tIRCommand.UByte.HighByte &= ~(LG_SWITCH_ON_MASK >> 8);
|
||||
}
|
||||
PowerIsOn = true;
|
||||
|
||||
sendIRCommand(tIRCommand.UWord);
|
||||
}
|
||||
|
||||
/** @}*/
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* ac_LG.h
|
||||
*
|
||||
* Contains definitions for receiving and sending LG air conditioner IR Protocol
|
||||
*
|
||||
* This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
|
||||
*
|
||||
************************************************************************************
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2021 Armin Joachimsmeyer
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is furnished
|
||||
* to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
************************************************************************************
|
||||
*/
|
||||
// see also: https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h
|
||||
#include <Arduino.h>
|
||||
|
||||
/** \addtogroup Airconditoners Air conditioner special code
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define LG_ADDRESS 0x88
|
||||
|
||||
/*
|
||||
* The basic IR command codes
|
||||
* Parts of the codes (especially the lower nibbles) may be modified to contain
|
||||
* additional information like temperature, fan speed and minutes.
|
||||
*/
|
||||
#define LG_SWITCH_ON_MASK 0x0800 // This bit is masked if we switch Power on
|
||||
#define LG_MODE_COOLING 0x0800 // Temperature and fan speed in lower nibbles
|
||||
#define LG_MODE_DEHUMIDIFIYING 0x0990 // sets also temperature to 24 and fan speed to 0
|
||||
#define LG_MODE_FAN 0x0A30 // sets also temperature to 18
|
||||
#define LG_MODE_AUTO 0x0B00 // The remote initially sets also temperature to 22 and fan speed to 4
|
||||
#define LG_MODE_HEATING 0x0C00 // Temperature and fan speed in lower nibbles
|
||||
#define LG_ENERGY_SAVING_ON 0x1004
|
||||
#define LG_ENERGY_SAVING_OFF 0x1005
|
||||
#define LG_JET_ON 0x1008
|
||||
#define LG_WALL_SWING_ON 0x1314
|
||||
#define LG_WALL_SWING_OFF 0x1315
|
||||
#define LG_SWING_ON 0x1316 // not verified, for AKB73757604
|
||||
#define LG_SWING_OFF 0x1317 // not verified, for AKB73757604
|
||||
#define LG_TIMER_ON 0x8000 // relative minutes in lower nibbles
|
||||
#define LG_TIMER_OFF 0x9000 // relative minutes in lower nibbles
|
||||
#define LG_SLEEP 0xA000 // relative minutes in lower nibbles
|
||||
#define LG_CLEAR_ALL 0xB000 // Timers and sleep
|
||||
#define LG_POWER_DOWN 0xC005
|
||||
#define LG_LIGHT 0xC00A
|
||||
#define LG_AUTO_CLEAN_ON 0xC00B
|
||||
#define LG_AUTO_CLEAN_OFF 0xC00C
|
||||
|
||||
/*
|
||||
* Commands as printed in menu and uses as first parameter for sendCommandAndParameter
|
||||
*/
|
||||
#define LG_COMMAND_OFF '0'
|
||||
#define LG_COMMAND_ON '1'
|
||||
#define LG_COMMAND_SWING 's'
|
||||
#define LG_COMMAND_AUTO_CLEAN 'a'
|
||||
#define LG_COMMAND_JET 'j'
|
||||
#define LG_COMMAND_ENERGY 'e'
|
||||
#define LG_COMMAND_LIGHT 'l'
|
||||
#define LG_COMMAND_FAN_SPEED 'f'
|
||||
#define LG_COMMAND_TEMPERATURE 't'
|
||||
#define LG_COMMAND_TEMPERATURE_PLUS '+'
|
||||
#define LG_COMMAND_TEMPERATURE_MINUS '-'
|
||||
#define LG_COMMAND_MODE 'M'
|
||||
#define LG_COMMAND_SLEEP 'S'
|
||||
#define LG_COMMAND_TIMER_ON 'T'
|
||||
#define LG_COMMAND_TIMER_OFF 'O'
|
||||
#define LG_COMMAND_CLEAR_ALL 'C'
|
||||
|
||||
/*
|
||||
* The modes are encoded as character values for easy printing :-)
|
||||
*/
|
||||
#define AC_MODE_COOLING 'C'
|
||||
#define AC_MODE_DEHUMIDIFIYING 'D'
|
||||
#define AC_MODE_FAN 'F'
|
||||
#define AC_MODE_AUTO 'A'
|
||||
#define AC_MODE_HEATING 'H'
|
||||
|
||||
// see https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h
|
||||
union LGProtocol {
|
||||
uint32_t raw; ///< The state of the IR remote in IR code form.
|
||||
struct {
|
||||
uint32_t Checksum :4;
|
||||
uint32_t Fan :3;
|
||||
uint32_t FanExt :1;
|
||||
uint32_t Temp :4;
|
||||
uint32_t Mode :4;
|
||||
uint32_t Function :3;
|
||||
uint32_t SwitchOnMask :1; /* Content is 0 when switching from off to on */
|
||||
uint32_t Signature :8; /* Content is 0x88, LG_ADDRESS */
|
||||
};
|
||||
};
|
||||
|
||||
class Aircondition_LG {
|
||||
public:
|
||||
bool sendCommandAndParameter(char aCommand, int aParameter);
|
||||
void setType(bool aIsWallType);
|
||||
void printMenu();
|
||||
void sendIRCommand(uint16_t aCommand);
|
||||
void sendTemperatureFanSpeedAndMode();
|
||||
/*
|
||||
* Internal state of the air condition
|
||||
*/
|
||||
#define LG_IS_WALL_TYPE true
|
||||
#define LG_IS_TOWER_TYPE false
|
||||
bool ACIsWallType; // false : TOWER, true : WALL
|
||||
bool PowerIsOn;
|
||||
|
||||
// These value are encoded and sent by AC_LG_SendCommandAndParameter()
|
||||
uint8_t FanIntensity = 1; // 0 -> low, 4 high, 5 -> cycle
|
||||
uint8_t Temperature = 22; // temperature : 18 ~ 30
|
||||
uint8_t Mode = AC_MODE_COOLING;
|
||||
bool useLG2Protocol = false;
|
||||
};
|
||||
|
||||
/** @}*/
|
|
@ -1,6 +1,19 @@
|
|||
/*
|
||||
* ir_DistanceProtocol.cpp
|
||||
*
|
||||
* This decoder tries to decode a pulse width or pulse distance protocol.
|
||||
* 1. Analyze all space and mark length
|
||||
* 2. Decide if we have an pulse width or distance protocol
|
||||
* 3. Try to decode with the mark and space data found in step 1
|
||||
* No data and address decoding, only raw data as result.
|
||||
*
|
||||
* Pulse distance data can be sent with the generic function:
|
||||
* void sendPulseDistanceWidthData(unsigned int aOneMarkMicros, unsigned int aOneSpaceMicros, unsigned int aZeroMarkMicros,
|
||||
* unsigned int aZeroSpaceMicros, uint32_t aData, uint8_t aNumberOfBits, bool aMSBfirst, bool aSendStopBit = false)
|
||||
* The header must be sent manually with:
|
||||
* IrSender.mark(MarkMicros)
|
||||
* IrSender.space(SpaceMicros);
|
||||
* see also: SendDemo example line 150
|
||||
*
|
||||
* This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
|
||||
*
|
||||
|
@ -35,6 +48,7 @@
|
|||
#define DISTANCE_DO_MSB_DECODING PROTOCOL_IS_LSB_FIRST // this results in the same decodedRawData as e.g. the NEC and Kaseikyo/Panasonic decoder
|
||||
//#define DISTANCE_DO_MSB_DECODING PROTOCOL_IS_MSB_FIRST // this resembles the JVC, Denon
|
||||
|
||||
#define INFO // Deactivate this to save program space and suppress info output.
|
||||
//#define DEBUG // Activate this for lots of lovely debug output from this decoder.
|
||||
#include "IRremoteInt.h" // evaluates the DEBUG for DEBUG_PRINT
|
||||
//#include "LongUnion.h"
|
||||
|
@ -96,10 +110,10 @@ bool aggregateArrayCounts(uint8_t aArray[], uint8_t aMaxIndex, uint8_t *aShortIn
|
|||
|
||||
/*
|
||||
* Try to decode a pulse width or pulse distance protocol.
|
||||
* 1. analyze all space and mark length
|
||||
* 2. decide if we have an pulse width or distance protocol
|
||||
* 3. try to decode with the mark and space data found in step 1.
|
||||
* No data and address, only raw data as result.
|
||||
* 1. Analyze all space and mark length
|
||||
* 2. Decide if we have an pulse width or distance protocol
|
||||
* 3. Try to decode with the mark and space data found in step 1
|
||||
* No data and address decoding, only raw data as result.
|
||||
*/
|
||||
bool IRrecv::decodeDistance() {
|
||||
uint8_t tDurationArray[DURATION_ARRAY_SIZE];
|
||||
|
@ -172,15 +186,10 @@ bool IRrecv::decodeDistance() {
|
|||
printDurations(tDurationArray, tMaxDurationIndex);
|
||||
#endif
|
||||
// skip leading start and trailing stop bit.
|
||||
uint8_t tNumberOfBits = (decodedIRData.rawDataPtr->rawlen / 2) - 2;
|
||||
uint16_t tNumberOfBits = (decodedIRData.rawDataPtr->rawlen / 2) - 2;
|
||||
uint8_t tStartIndex = 3;
|
||||
decodedIRData.numberOfBits = tNumberOfBits;
|
||||
|
||||
// adjust for longer data like Kaseikyo
|
||||
if (tNumberOfBits > 32) {
|
||||
tNumberOfBits = 32;
|
||||
tStartIndex = decodedIRData.rawDataPtr->rawlen - 65;
|
||||
}
|
||||
uint8_t tNumberOfAdditionalLong = (tNumberOfBits - 1) / 32;
|
||||
|
||||
/*
|
||||
* decide, if we have an pulse width or distance protocol
|
||||
|
@ -196,23 +205,45 @@ bool IRrecv::decodeDistance() {
|
|||
// tMarkTicksShort * MICROS_PER_TICK, tSpaceTicksShort * MICROS_PER_TICK, DISTANCE_DO_MSB_DECODING)) {
|
||||
// tNumberOfBits++;
|
||||
// }
|
||||
// decode without leading start bit. Currently only seen for sony protocol
|
||||
if (!decodePulseWidthData(tNumberOfBits, tStartIndex, tMarkTicksLong * MICROS_PER_TICK,
|
||||
// decode without leading start bit. Currently only seen for sony protocol
|
||||
for (uint8_t i = 0; i <= tNumberOfAdditionalLong; ++i) {
|
||||
uint8_t tNumberOfBitsForOneDecode = tNumberOfBits;
|
||||
if (tNumberOfBitsForOneDecode > 32) {
|
||||
tNumberOfBitsForOneDecode = 32;
|
||||
}
|
||||
if (!decodePulseWidthData(tNumberOfBitsForOneDecode, tStartIndex, tMarkTicksLong * MICROS_PER_TICK,
|
||||
tMarkTicksShort * MICROS_PER_TICK, tSpaceTicksShort * MICROS_PER_TICK, DISTANCE_DO_MSB_DECODING)) {
|
||||
DEBUG_PRINT(F("PULSE_WIDTH: "));
|
||||
DEBUG_PRINTLN(F("Decode failed"));
|
||||
return false;
|
||||
}
|
||||
DEBUG_PRINT(F("PULSE_WIDTH: "));
|
||||
DEBUG_PRINT(F(" OneMarkMicros="));
|
||||
DEBUG_PRINT(tMarkTicksLong * MICROS_PER_TICK);
|
||||
DEBUG_PRINT(F(" ZeroMarkMicros="));
|
||||
DEBUG_PRINT(tMarkTicksShort* MICROS_PER_TICK);
|
||||
DEBUG_PRINT(F(" ZeroSpaceMicros="));
|
||||
DEBUG_PRINTLN(tSpaceTicksShort* MICROS_PER_TICK);
|
||||
// Store ticks used for decoding in extra
|
||||
decodedIRData.extra = (tMarkTicksShort << 8) | tMarkTicksLong;
|
||||
decodedIRData.protocol = PULSE_WIDTH;
|
||||
if (i == 0) {
|
||||
// Print protocol timing only once
|
||||
INFO_PRINTLN();
|
||||
INFO_PRINT(F("PULSE_WIDTH:"));
|
||||
INFO_PRINT(F(" HeaderMarkMicros="));
|
||||
INFO_PRINT(decodedIRData.rawDataPtr->rawbuf[1] * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" HeaderSpaceMicros="));
|
||||
INFO_PRINT(decodedIRData.rawDataPtr->rawbuf[2] * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" OneMarkMicros="));
|
||||
INFO_PRINT(tMarkTicksLong * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" ZeroMarkMicros="));
|
||||
INFO_PRINT(tMarkTicksShort * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" SpaceMicros="));
|
||||
INFO_PRINTLN(tSpaceTicksShort * MICROS_PER_TICK);
|
||||
}
|
||||
if (tNumberOfAdditionalLong > 0) {
|
||||
// print only if we have more than 32 bits for decode
|
||||
INFO_PRINT(F(" 0x"));
|
||||
INFO_PRINT(decodedIRData.decodedRawData, HEX);
|
||||
tStartIndex += 64;
|
||||
tNumberOfBits -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
// Store ticks used for decoding in extra
|
||||
decodedIRData.extra = (tMarkTicksShort << 8) | tMarkTicksLong;
|
||||
decodedIRData.protocol = PULSE_WIDTH;
|
||||
} else {
|
||||
// // check if last bit can be decoded as data or not, in this case take it as a stop bit
|
||||
// if (decodePulseDistanceData(1, decodedIRData.rawDataPtr->rawlen - 3, tMarkTicksShort * MICROS_PER_TICK,
|
||||
|
@ -221,19 +252,42 @@ bool IRrecv::decodeDistance() {
|
|||
// tNumberOfBits++;
|
||||
// }
|
||||
|
||||
if (!decodePulseDistanceData(tNumberOfBits, tStartIndex, tMarkTicksShort * MICROS_PER_TICK,
|
||||
tSpaceTicksLong * MICROS_PER_TICK, tSpaceTicksShort * MICROS_PER_TICK, DISTANCE_DO_MSB_DECODING)) {
|
||||
DEBUG_PRINT(F("PULSE_DISTANCE: "));
|
||||
DEBUG_PRINTLN(F("Decode failed"));
|
||||
return false;
|
||||
for (uint8_t i = 0; i <= tNumberOfAdditionalLong; ++i) {
|
||||
uint8_t tNumberOfBitsForOneDecode = tNumberOfBits;
|
||||
if (tNumberOfBitsForOneDecode > 32) {
|
||||
tNumberOfBitsForOneDecode = 32;
|
||||
}
|
||||
if (!decodePulseDistanceData(tNumberOfBitsForOneDecode, tStartIndex, tMarkTicksShort * MICROS_PER_TICK,
|
||||
tSpaceTicksLong * MICROS_PER_TICK, tSpaceTicksShort * MICROS_PER_TICK, DISTANCE_DO_MSB_DECODING)) {
|
||||
DEBUG_PRINT(F("PULSE_DISTANCE: "));
|
||||
DEBUG_PRINTLN(F("Decode failed"));
|
||||
return false;
|
||||
} else {
|
||||
if (i == 0) {
|
||||
// Print protocol timing only once
|
||||
INFO_PRINTLN();
|
||||
INFO_PRINT(F("PULSE_DISTANCE:"));
|
||||
INFO_PRINT(F(" HeaderMarkMicros="));
|
||||
INFO_PRINT(decodedIRData.rawDataPtr->rawbuf[1] * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" HeaderSpaceMicros="));
|
||||
INFO_PRINT(decodedIRData.rawDataPtr->rawbuf[2] * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" MarkMicros="));
|
||||
INFO_PRINT(tMarkTicksShort * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" OneSpaceMicros="));
|
||||
INFO_PRINT(tSpaceTicksLong * MICROS_PER_TICK);
|
||||
INFO_PRINT(F(" ZeroSpaceMicros="));
|
||||
INFO_PRINTLN(tSpaceTicksShort * MICROS_PER_TICK);
|
||||
}
|
||||
if (tNumberOfAdditionalLong > 0) {
|
||||
// print only if we have more than 32 bits for decode
|
||||
INFO_PRINT(F(" 0x"));
|
||||
INFO_PRINT(decodedIRData.decodedRawData, HEX);
|
||||
tStartIndex += 64;
|
||||
tNumberOfBits -= 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
DEBUG_PRINT(F("PULSE_DISTANCE: "));
|
||||
DEBUG_PRINT(F("BitMarkMicros="));
|
||||
DEBUG_PRINT(tMarkTicksShort* MICROS_PER_TICK);
|
||||
DEBUG_PRINT(F(" OneSpaceMicros="));
|
||||
DEBUG_PRINT(tSpaceTicksLong* MICROS_PER_TICK);
|
||||
DEBUG_PRINT(F(" ZeroSpaceMicros="));
|
||||
DEBUG_PRINTLN(tSpaceTicksShort* MICROS_PER_TICK);
|
||||
|
||||
// Store ticks used for decoding in extra
|
||||
decodedIRData.extra = (tSpaceTicksShort << 8) | tSpaceTicksLong;
|
||||
decodedIRData.protocol = PULSE_DISTANCE;
|
||||
|
|
|
@ -50,29 +50,34 @@
|
|||
// MSB first, 1 start bit + 8 bit address + 16 bit command + 4 bit checksum + 1 stop bit (28 data bits).
|
||||
// Bit and repeat timing is like NEC
|
||||
// LG2 has different header timing and a shorter bit time
|
||||
/*
|
||||
* LG remote measurements: Type AKB73315611, Ver1.1 from 2011.03.01
|
||||
* Internal crystal: 4 MHz
|
||||
* Header: 8.9 ms mark 4.15 ms space
|
||||
* Data: 500 / 540 and 500 / 1580;
|
||||
* Clock is nor synchronized with gate so you have 19 and sometimes 19 and a spike pulses for mark
|
||||
* Duty: 9 us on 17 us off => around 33 % duty
|
||||
* NO REPEAT: If value like temperature has changed during long press, the last value is send at button release
|
||||
* If you do a double press -tested with the fan button-, the next value can be sent after 118 ms
|
||||
*
|
||||
* The codes of the LG air conditioner are documented in https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/ac_LG.cpp
|
||||
*/
|
||||
#define LG_ADDRESS_BITS 8
|
||||
#define LG_COMMAND_BITS 16
|
||||
#define LG_CHECKSUM_BITS 4
|
||||
#define LG_BITS (LG_ADDRESS_BITS + LG_COMMAND_BITS + LG_CHECKSUM_BITS) // 28
|
||||
|
||||
#define LG_UNIT 560 // like NEC
|
||||
#define LG_UNIT 500 // 19 periods of 38 kHz
|
||||
|
||||
#define LG_HEADER_MARK (16 * LG_UNIT) // 9000
|
||||
#define LG_HEADER_SPACE (8 * LG_UNIT) // 4500
|
||||
#define LG_HEADER_MARK (18 * LG_UNIT) // 9000
|
||||
#define LG_HEADER_SPACE 4200
|
||||
|
||||
// used for some LG air conditioners e.g. AKB75215403
|
||||
#define LG2_UNIT 500 // 19 periods of 38 kHz
|
||||
|
||||
#define LG2_HEADER_MARK (6 * LG2_UNIT) // 3000
|
||||
#define LG2_HEADER_SPACE (19 * LG2_UNIT) // 9500
|
||||
#define LG2_HEADER_MARK (6 * LG_UNIT) // 3000
|
||||
#define LG2_HEADER_SPACE (19 * LG_UNIT) // 9500
|
||||
|
||||
#define LG_BIT_MARK LG_UNIT
|
||||
#define LG_ONE_SPACE (3 * LG_UNIT) // 1690
|
||||
#define LG_ZERO_SPACE LG_UNIT
|
||||
|
||||
#define LG2_BIT_MARK LG2_UNIT
|
||||
#define LG2_ONE_SPACE (3 * LG2_UNIT) // 1500
|
||||
#define LG2_ZERO_SPACE LG2_UNIT
|
||||
#define LG_ONE_SPACE 1580 // 60 periods of 38 kHz
|
||||
#define LG_ZERO_SPACE 550
|
||||
|
||||
#define LG_REPEAT_HEADER_SPACE (4 * LG_UNIT) // 2250
|
||||
#define LG_AVERAGE_DURATION 58000 // LG_HEADER_MARK + LG_HEADER_SPACE + 32 * 2,5 * LG_UNIT) + LG_UNIT // 2.5 because we assume more zeros than ones
|
||||
|
@ -133,7 +138,7 @@ void IRsend::sendLGRaw(uint32_t aRawData, uint_fast8_t aNumberOfRepeats, bool aI
|
|||
mark(LG2_HEADER_MARK);
|
||||
space(LG2_HEADER_SPACE);
|
||||
// MSB first
|
||||
sendPulseDistanceWidthData(LG2_BIT_MARK, LG2_ONE_SPACE, LG2_BIT_MARK, LG2_ZERO_SPACE, aRawData, LG_BITS, PROTOCOL_IS_MSB_FIRST,
|
||||
sendPulseDistanceWidthData(LG_BIT_MARK, LG_ONE_SPACE, LG_BIT_MARK, LG_ZERO_SPACE, aRawData, LG_BITS, PROTOCOL_IS_MSB_FIRST,
|
||||
SEND_STOP_BIT);
|
||||
} else {
|
||||
mark(LG_HEADER_MARK);
|
||||
|
@ -167,7 +172,6 @@ void IRsend::sendLGRaw(uint32_t aRawData, uint_fast8_t aNumberOfRepeats, bool aI
|
|||
bool IRrecv::decodeLG() {
|
||||
decode_type_t tProtocol = LG;
|
||||
uint16_t tHeaderSpace = LG_HEADER_SPACE;
|
||||
uint16_t tUnit = LG_UNIT;
|
||||
|
||||
// Check we have the right amount of data (60). The +4 is for initial gap, start bit mark and space + stop bit mark.
|
||||
if (decodedIRData.rawDataPtr->rawlen != ((2 * LG_BITS) + 4) && (decodedIRData.rawDataPtr->rawlen != 4)) {
|
||||
|
@ -187,7 +191,6 @@ bool IRrecv::decodeLG() {
|
|||
} else {
|
||||
tProtocol = LG2;
|
||||
tHeaderSpace = LG2_HEADER_SPACE;
|
||||
tUnit = LG2_UNIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,15 +216,14 @@ bool IRrecv::decodeLG() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// if (!decodePulseDistanceData(LG_BITS, 3, LG_BIT_MARK, LG_ONE_SPACE, LG_ZERO_SPACE, PROTOCOL_IS_MSB_FIRST)) {
|
||||
if (!decodePulseDistanceData(LG_BITS, 3, tUnit, 3 * tUnit, tUnit, PROTOCOL_IS_MSB_FIRST)) { // costs 20 bytes program space, compared with using constants for 1 protocol
|
||||
if (!decodePulseDistanceData(LG_BITS, 3, LG_BIT_MARK, LG_ONE_SPACE, LG_ZERO_SPACE, PROTOCOL_IS_MSB_FIRST)) {
|
||||
DEBUG_PRINT(F("LG: "));
|
||||
DEBUG_PRINTLN(F("Decode failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stop bit
|
||||
if (!matchMark(decodedIRData.rawDataPtr->rawbuf[3 + (2 * LG_BITS)], tUnit)) {
|
||||
if (!matchMark(decodedIRData.rawDataPtr->rawbuf[3 + (2 * LG_BITS)], LG_BIT_MARK)) {
|
||||
DEBUG_PRINT(F("LG: "));
|
||||
DEBUG_PRINTLN(F("Stop bit mark length is wrong"));
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue