publish libraries to avoid users to have to download them one by one

This commit is contained in:
1technophile committed 2018-03-04 13:47:37 +01:00
1 parent 93c075e880
commit f0546fab8c
396 files changed
+536928

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
set noparent
root=src
linelength=80
+458
View File
@@ -0,0 +1,458 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
+71
View File
@@ -0,0 +1,71 @@
# IRremote ESP8266 Library
[![Build Status](https://travis-ci.org/markszabo/IRremoteESP8266.svg?branch=master)](https://travis-ci.org/markszabo/IRremoteESP8266)
This library enables you to **send and receive** infra-red signals on an ESP8266 using Arduino framework (https://github.com/esp8266/Arduino)
## v2.2 Now Available
Version 2.2 of the library is now available. This is a significant internal change to existing versions.
## Upgrading from versions prior to v2.0
You will need to change your pre-v2.0 code slightly to work with post-v2.0 versions of the library. You can read more about the changes on our [wiki](https://github.com/markszabo/IRremoteESP8266/wiki/Upgrading-to-v2.0) page.
Please [report an issue](https://github.com/markszabo/IRremoteESP8266/issues/new) if you find any problems with the documentation or the library itself.
## Troubleshooting
Before reporting an issue or asking for help, please try to follow our [Troubleshooting Guide](https://github.com/markszabo/IRremoteESP8266/wiki/Troubleshooting-Guide) first.
## Frequently Asked Questions
Some common answers to common questions and problems can be found on our [F.A.Q. wiki page](https://github.com/markszabo/IRremoteESP8266/wiki/Frequently-Asked-Questions).
## History
This library was originally based on Ken Shirriff's work (https://github.com/shirriff/Arduino-IRremote/)
[Mark Szabo](https://github.com/markszabo/IRremoteESP8266) has updated the IRsend class to work on ESP8266 and [Sebastien Warin](https://github.com/sebastienwarin/IRremoteESP8266) the receiving & decoding part (IRrecv class).
## Installation
1. Click "Download ZIP"
2. Extract the downloaded zip file
3. Rename the extracted folder to "IRremoteESP8266"
4. Move this folder to your libraries directory (under windows: C:\Users\YOURNAME\Documents\Arduino\libraries\)
5. Restart your Arduino ide
6. Check out the examples
###### Using Git to install library ( Linux )
```
cd ~/Arduino/libraries
git clone https://github.com/markszabo/IRremoteESP8266.git
```
###### To Update to the latest version of the library
`
cd ~/Arduino/libraries/IRremoteESP8266 && git pull
`
## Unit Tests
The [Unit Tests](https://en.wikipedia.org/wiki/Unit_testing) under the test/ directory are for a Unix machine, **not** the micro-controller (ESP8266).
This allows execution under Travis and on the developer's machine.
We can do this from v2.0 of the library onwards, as everything now uses c98-style type definitions.
e.g. uint16_t etc.
Any Arduino/ESP8266 specific code needs to be disabled using something similar to the following lines:
```
#ifndef UNIT_TEST
<Arduino specific code ...>
#endif
```
This is not a perfect situation as we can not obviously emulate hardware specific features and differences. e.g. Interrupts, GPIOs, CPU instruction timing etc, etc.
If you want to run all the tests yourself, try the following:
```
$ cd test
$ make run
```
## Contributing
If you want to [contribute](.github/CONTRIBUTING.md#how-can-i-contribute) to this project, consider:
- [Report](.github/CONTRIBUTING.md#reporting-bugs) bugs and errors
- Ask for enhancements
- [Create issues](.github/CONTRIBUTING.md#reporting-bugs) and [pull requests](.github/CONTRIBUTING.md#pull-requests)
- Tell other people about this library
## Contributors
Available [here](.github/Contributors.md)
@@ -0,0 +1,63 @@
/*
* IRremoteESP8266: IRsendGCDemo
* demonstrates sending Global Cache-formatted IR codes with IRsend
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*
* Version 0.2 June, 2017
* Added helpful comments
* Better includes files.
* Version 0.1 30 March, 2016
* Based on Ken Shirriff's IrsendDemo
* Version 0.1 July, 2009
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
// Codes are in Global Cache format less the emitter ID and request ID.
// These codes can be found in GC's Control Tower database.
uint16_t Samsung_power_toggle[71] = {
38000, 1, 1, 170, 170, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 63, 20, 63, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 63, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 63, 20,
20, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 63, 20, 1798};
IRsend irsend(4); // An IR LED is controlled by GPIO pin 4 (D2)
void setup() {
irsend.begin();
Serial.begin(115200);
}
void loop() {
Serial.println("Toggling power");
irsend.sendGC(Samsung_power_toggle, 71);
delay(10000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,129 @@
/*
* IRremoteESP8266: IRGCTCPServer - send Global Cache-formatted codes via TCP.
* An IR emitter must be connected to GPIO pin 4.
* Version 0.2 May, 2017
* Copyright 2016 Hisham Khalifa, http://www.hishamkhalifa.com
* Copyright 2017 David Conran
*
* Example command - Samsung TV power toggle: 38000,1,1,170,170,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,63,20,63,20,63,20,63,20,63,20,63,20,1798\r\n
* For more codes, visit: https://irdb.globalcache.com/
*
* How to use this program:
* 1) Update "ssid" and "password" below for your WIFI network.
* 2) Compile and upload the sketch to your ESP8266 module.
* 3) (Optional) Use the serial connection to confirm it started and get the
* IP address.
* 4) From a client machine, connect to port 4998 on the ESP8266, using
* 'telnet', 'nc' (netcat), 'putty' or similar command, etc.
* You may need to install one.
* Unix/OSX:
* Start a shell. Then type:
* telnet <esp8266deviceIPaddress> 4998
* Windows:
* Start a new CMD window, then type:
* telnet <esp8266deviceIPaddress> 4998
*
* 5) Enter a Global Cache-formatted code, starting at the frequency,
* and then a return/enter at the end. No spaces. e.g.:
*
* 38000,1,1,170,170,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,63,20,63,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,20,20,20,20,20,20,20,20,20,20,63,20,20,20,63,20,63,20,63,20,63,20,63,20,63,20,1798
*
* To exit the 'telnet' command:
* press <control> + <]> at the same time, then press 'q', and then <return>.
* or:
* <control> + <d> might work.
*
* This program will display the ESP's IP address on the serial console, or you
* can check your wifi router for it's address.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <ESP8266WiFi.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
const char* ssid = "..."; // Put your WIFI SSID here.
const char* password = "..."; // Put your WIFI password here.
WiFiServer server(4998); // Uses port 4998.
WiFiClient client;
uint16_t *code_array;
IRsend irsend(4); // An IR LED is controlled by GPIO pin 4 (D2)
void sendGCString(String str) {
int16_t index;
uint16_t count;
// Find out how many items there are in the string.
index = -1;
count = 1;
do {
index = str.indexOf(',', index + 1);
count++;
} while (index != -1);
// Now we know how many there are, allocate the memory to store them all.
code_array = reinterpret_cast<uint16_t*>(malloc(count * sizeof(uint16_t)));
// Check we malloc'ed successfully.
if (code_array == NULL) { // malloc failed, so give up.
Serial.printf("\nCan't allocate %d bytes. (%d bytes free)\n",
count * sizeof(uint16_t), ESP.getFreeHeap());
Serial.println("Giving up & forcing a reboot.");
ESP.restart(); // Reboot.
delay(500); // Wait for the restart to happen.
return; // Should never get here, but just in case.
}
// Now convert the strings to integers and place them in code_array.
count = 0;
uint16_t start_from = 0;
do {
index = str.indexOf(',', start_from);
code_array[count] = str.substring(start_from, index).toInt();
start_from = index + 1;
count++;
} while (index != -1);
irsend.sendGC(code_array, count); // All done. Send it.
free(code_array); // Free up the memory allocated.
}
void setup() {
// initialize serial:
Serial.begin(115200);
delay(100);
Serial.println(" ");
Serial.println("IR TCP Server");
while (WiFi.status() != WL_CONNECTED) {
delay(900);
Serial.print(".");
}
server.begin();
IPAddress myAddress = WiFi.localIP();
Serial.println(myAddress);
irsend.begin();
}
void loop() {
while (!client)
client = server.available();
while (!client.connected()) {
delay(900);
client = server.available();
}
if (client.available()) {
String ir_code_str = client.readStringUntil('\r'); // Exclusive of \r
client.readStringUntil('\n'); // Skip new line as well
client.flush();
sendGCString(ir_code_str);
}
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,121 @@
/*
* IRremoteESP8266: IRServer - demonstrates sending IR codes controlled from a webserver
* Version 0.2 June, 2017
* Copyright 2015 Mark Szabo
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <WiFiClient.h>
const char* ssid = ".....";
const char* password = ".....";
MDNSResponder mdns;
ESP8266WebServer server(80);
IRsend irsend(4); // An IR LED is controlled by GPIO pin 4 (D2)
void handleRoot() {
server.send(200, "text/html",
"<html>" \
"<head><title>ESP8266 Demo</title></head>" \
"<body>" \
"<h1>Hello from ESP8266, you can send NEC encoded IR" \
"signals from here!</h1>" \
"<p><a href=\"ir?code=16769055\">Send 0xFFE01F</a></p>" \
"<p><a href=\"ir?code=16429347\">Send 0xFAB123</a></p>" \
"<p><a href=\"ir?code=16771222\">Send 0xFFE896</a></p>" \
"</body>" \
"</html>");
}
void handleIr() {
for (uint8_t i = 0; i < server.args(); i++) {
if (server.argName(i) == "code") {
uint32_t code = strtoul(server.arg(i).c_str(), NULL, 10);
irsend.sendNEC(code, 32);
}
}
handleRoot();
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++)
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
server.send(404, "text/plain", message);
}
void setup(void) {
irsend.begin();
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (mdns.begin("esp8266", WiFi.localIP())) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/ir", handleIr);
server.on("/inline", [](){
server.send(200, "text/plain", "this works as well");
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,44 @@
/*
* IRremoteESP8266: IRrecvDemo - demonstrates receiving IR codes with IRrecv
* An IR detector/demodulator must be connected to the input RECV_PIN.
* Copyright 2009 Ken Shirriff, http://arcfn.com
* Example circuit diagram:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-receiving
* Changes:
* Version 0.2 June, 2017
* Changed GPIO pin to the same as other examples.
* Used our own method for printing a uint64_t.
* Changed the baud rate to 115200.
* Version 0.1 Sept, 2015
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRutils.h>
// An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU
// board).
uint16_t RECV_PIN = 14;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
Serial.begin(115200);
irrecv.enableIRIn(); // Start the receiver
}
void loop() {
if (irrecv.decode(&results)) {
// print() & println() can't handle printing long longs. (uint64_t)
serialPrintUint64(results.value, HEX);
Serial.println("");
irrecv.resume(); // Receive the next value
}
delay(100);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,90 @@
/*
* IRremoteESP8266: IRrecvDump - dump details of IR codes with IRrecv
* An IR detector/demodulator must be connected to the input RECV_PIN.
* Version 0.1 Sept, 2015
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009,
* Copyright 2009 Ken Shirriff, http://arcfn.com
* JVC and Panasonic protocol added by Kristian Lauszus
* (Thanks to zenwheel and other people at the original blog post)
* LG added by Darryl Smith (based on the JVC protocol)
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRutils.h>
// an IR detector/demodulator is connected to GPIO pin 2
uint16_t RECV_PIN = 2;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
Serial.begin(115200);
irrecv.enableIRIn(); // Start the receiver
}
void dump(decode_results *results) {
// Dumps out the decode_results structure.
// Call this after IRrecv::decode()
uint16_t count = results->rawlen;
if (results->decode_type == UNKNOWN) {
Serial.print("Unknown encoding: ");
} else if (results->decode_type == NEC) {
Serial.print("Decoded NEC: ");
} else if (results->decode_type == SONY) {
Serial.print("Decoded SONY: ");
} else if (results->decode_type == RC5) {
Serial.print("Decoded RC5: ");
} else if (results->decode_type == RC5X) {
Serial.print("Decoded RC5X: ");
} else if (results->decode_type == RC6) {
Serial.print("Decoded RC6: ");
} else if (results->decode_type == RCMM) {
Serial.print("Decoded RCMM: ");
} else if (results->decode_type == PANASONIC) {
Serial.print("Decoded PANASONIC - Address: ");
Serial.print(results->address, HEX);
Serial.print(" Value: ");
} else if (results->decode_type == LG) {
Serial.print("Decoded LG: ");
} else if (results->decode_type == JVC) {
Serial.print("Decoded JVC: ");
} else if (results->decode_type == AIWA_RC_T501) {
Serial.print("Decoded AIWA RC T501: ");
} else if (results->decode_type == WHYNTER) {
Serial.print("Decoded Whynter: ");
}
serialPrintUint64(results->value, 16);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
Serial.print("Raw (");
Serial.print(count, DEC);
Serial.print("): ");
for (uint16_t i = 1; i < count; i++) {
if (i % 100 == 0)
yield(); // Preemptive yield every 100th entry to feed the WDT.
if (i & 1) {
Serial.print(results->rawbuf[i] * RAWTICK, DEC);
} else {
Serial.write('-');
Serial.print((uint32_t) results->rawbuf[i] * RAWTICK, DEC);
}
Serial.print(" ");
}
Serial.println();
}
void loop() {
if (irrecv.decode(&results)) {
serialPrintUint64(results.value, 16);
dump(&results);
irrecv.resume(); // Receive the next value
}
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,198 @@
/*
* IRremoteESP8266: IRrecvDumpV2 - dump details of IR codes with IRrecv
* An IR detector/demodulator must be connected to the input RECV_PIN.
* Example circuit diagram:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-receiving
* Changes:
* Version 0.2 April, 2017
* - Decode from a copy of the data so we can start capturing faster thus
* reduce the likelihood of miscaptures.
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRutils.h>
// An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU
// board).
uint16_t RECV_PIN = 14;
// As this program is a special purpose capture/decoder, let us use a larger
// than normal buffer so we can handle Air Conditioner remote codes.
uint16_t CAPTURE_BUFFER_SIZE = 1024;
// Nr. of milli-Seconds of no-more-data before we consider a message ended.
// NOTE: Don't exceed MAX_TIMEOUT_MS. Typically 130ms.
#define TIMEOUT 15U // Suits most messages, while not swallowing repeats.
// #define TIMEOUT 90U // Suits messages with big gaps like XMP-1 & some aircon
// units, but can accidently swallow repeated messages
// in the rawData[] output.
// Use turn on the save buffer feature for more complete capture coverage.
IRrecv irrecv(RECV_PIN, CAPTURE_BUFFER_SIZE, TIMEOUT, true);
decode_results results; // Somewhere to store the results
void setup() {
// Status message will be sent to the PC at 115200 baud
Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
delay(500); // Wait a bit for the serial connection to be establised.
irrecv.enableIRIn(); // Start the receiver
}
// Display encoding type
//
void encoding(decode_results *results) {
switch (results->decode_type) {
default:
case UNKNOWN: Serial.print("UNKNOWN"); break;
case NEC: Serial.print("NEC"); break;
case NEC_LIKE: Serial.print("NEC (non-strict)"); break;
case SONY: Serial.print("SONY"); break;
case RC5: Serial.print("RC5"); break;
case RC5X: Serial.print("RC5X"); break;
case RC6: Serial.print("RC6"); break;
case RCMM: Serial.print("RCMM"); break;
case DISH: Serial.print("DISH"); break;
case SHARP: Serial.print("SHARP"); break;
case JVC: Serial.print("JVC"); break;
case SANYO: Serial.print("SANYO"); break;
case SANYO_LC7461: Serial.print("SANYO_LC7461"); break;
case MITSUBISHI: Serial.print("MITSUBISHI"); break;
case SAMSUNG: Serial.print("SAMSUNG"); break;
case LG: Serial.print("LG"); break;
case WHYNTER: Serial.print("WHYNTER"); break;
case AIWA_RC_T501: Serial.print("AIWA_RC_T501"); break;
case PANASONIC: Serial.print("PANASONIC"); break;
case DENON: Serial.print("DENON"); break;
case COOLIX: Serial.print("COOLIX"); break;
}
if (results->repeat) Serial.print(" (Repeat)");
}
// Dump out the decode_results structure.
//
void dumpInfo(decode_results *results) {
if (results->overflow)
Serial.printf("WARNING: IR code too big for buffer (>= %d). "
"These results shouldn't be trusted until this is resolved. "
"Edit & increase CAPTURE_BUFFER_SIZE.\n",
CAPTURE_BUFFER_SIZE);
// Show Encoding standard
Serial.print("Encoding : ");
encoding(results);
Serial.println("");
// Show Code & length
Serial.print("Code : ");
serialPrintUint64(results->value, 16);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
}
uint16_t getCookedLength(decode_results *results) {
uint16_t length = results->rawlen - 1;
for (uint16_t i = 0; i < results->rawlen - 1; i++) {
uint32_t usecs = results->rawbuf[i] * RAWTICK;
// Add two extra entries for multiple larger than UINT16_MAX it is.
length += (usecs / UINT16_MAX) * 2;
}
return length;
}
// Dump out the decode_results structure.
//
void dumpRaw(decode_results *results) {
// Print Raw data
Serial.print("Timing[");
Serial.print(results->rawlen - 1, DEC);
Serial.println("]: ");
for (uint16_t i = 1; i < results->rawlen; i++) {
if (i % 100 == 0)
yield(); // Preemptive yield every 100th entry to feed the WDT.
if (i % 2 == 0) { // even
Serial.print("-");
} else { // odd
Serial.print(" +");
}
Serial.printf("%6d", results->rawbuf[i] * RAWTICK);
if (i < results->rawlen - 1)
Serial.print(", "); // ',' not needed for last one
if (!(i % 8)) Serial.println("");
}
Serial.println(""); // Newline
}
// Dump out the decode_results structure.
//
void dumpCode(decode_results *results) {
// Start declaration
Serial.print("uint16_t "); // variable type
Serial.print("rawData["); // array name
Serial.print(getCookedLength(results), DEC); // array size
Serial.print("] = {"); // Start declaration
// Dump data
for (uint16_t i = 1; i < results->rawlen; i++) {
uint32_t usecs;
for (usecs = results->rawbuf[i] * RAWTICK;
usecs > UINT16_MAX;
usecs -= UINT16_MAX)
Serial.printf("%d, 0", UINT16_MAX);
Serial.print(usecs, DEC);
if (i < results->rawlen - 1)
Serial.print(", "); // ',' not needed on last one
if (i % 2 == 0) Serial.print(" "); // Extra if it was even.
}
// End declaration
Serial.print("};"); //
// Comment
Serial.print(" // ");
encoding(results);
Serial.print(" ");
serialPrintUint64(results->value, HEX);
// Newline
Serial.println("");
// Now dump "known" codes
if (results->decode_type != UNKNOWN) {
// Some protocols have an address &/or command.
// NOTE: It will ignore the atypical case when a message has been decoded
// but the address & the command are both 0.
if (results->address > 0 || results->command > 0) {
Serial.print("uint32_t address = 0x");
Serial.print(results->address, HEX);
Serial.println(";");
Serial.print("uint32_t command = 0x");
Serial.print(results->command, HEX);
Serial.println(";");
}
// All protocols have data
Serial.print("uint64_t data = 0x");
serialPrintUint64(results->value, 16);
Serial.println(";");
}
}
// The repeating section of the code
//
void loop() {
// Check if the IR code has been received.
if (irrecv.decode(&results)) {
dumpInfo(&results); // Output the results
dumpRaw(&results); // Output the results in RAW format
dumpCode(&results); // Output the results as source code
Serial.println(""); // Blank line between entries
}
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,62 @@
/* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend.
*
* Version 1.0 April, 2017
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009,
* Copyright 2009 Ken Shirriff, http://arcfn.com
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
IRsend irsend(4); // An IR LED is controlled by GPIO pin 4 (D2)
// Example of data captured by IRrecvDumpV2.ino
uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650,
600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650,
650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550,
650, 550, 650, 550, 600, 550, 650, 550, 650, 550,
650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
650, 1650, 650, 1650, 650, 1650, 600};
void setup() {
irsend.begin();
Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
}
void loop() {
Serial.println("NEC");
irsend.sendNEC(0x00FFE01FUL, 32);
delay(2000);
Serial.println("Sony");
irsend.sendSony(0xa90, 12, 2);
delay(2000);
Serial.println("a rawData capture from IRrecvDumpV2");
irsend.sendRaw(rawData, 67, 38); // Send a raw data capture at 38kHz.
delay(2000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,105 @@
/* IRremoteESP8266: IRsendProntoDemo
* Copyright 2017 David Conran
*
* Demonstrates sending Pronto codes with IRsend.
*
* Version 1.0 June, 2017
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2), unless you
* change the irsend() value below.
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
IRsend irsend(4); // An IR LED is controlled by GPIO pin 4 (D2)
// Panasonic Plasma TV Descrete code (Power On).
// Acquired from:
// https://irdb.globalcache.com/
// e.g.
// 0000 006D 0000 0022 00ac 00ac 0016 0040 0016 0040 0016 0040 0016 0015 0016
// 0015 0016 0015 0016 0015 0016 0015 0016 0040 0016 0040 0016 0040 0016 0015
// 0016 0015 0016 0015 0016 0015 0016 0015 0016 0040 0016 0015 0016 0015 0016
// 0040 0016 0040 0016 0015 0016 0015 0016 0040 0016 0015 0016 0040 0016 0040
// 0016 0015 0016 0015 0016 0040 0016 0040 0016 0015 0016 071c
//
// Or the equiv. of sendSamsung(0xE0E09966);
uint16_t samsungProntoCode[72] = {
0x0000, 0x006D, 0x0000, 0x0022,
0x00ac, 0x00ac, 0x0016, 0x0040, 0x0016, 0x0040, 0x0016, 0x0040,
0x0016, 0x0015, 0x0016, 0x0015, 0x0016, 0x0015, 0x0016, 0x0015,
0x0016, 0x0015, 0x0016, 0x0040, 0x0016, 0x0040, 0x0016, 0x0040,
0x0016, 0x0015, 0x0016, 0x0015, 0x0016, 0x0015, 0x0016, 0x0015,
0x0016, 0x0015, 0x0016, 0x0040, 0x0016, 0x0015, 0x0016, 0x0015,
0x0016, 0x0040, 0x0016, 0x0040, 0x0016, 0x0015, 0x0016, 0x0015,
0x0016, 0x0040, 0x0016, 0x0015, 0x0016, 0x0040, 0x0016, 0x0040,
0x0016, 0x0015, 0x0016, 0x0015, 0x0016, 0x0040, 0x0016, 0x0040,
0x0016, 0x0015, 0x0016, 0x071c
};
// Panasonic Plasma TV Descrete code (Power On).
// Acquired from:
// ftp://ftp.panasonic.com/pub/panasonic/drivers/monitors/Discrete-remote-control-codesProntoCCFformat.pdf
// e.g.
// 0000 0071 0000 0032 0080 003F 0010 0010 0010 0030 0010 0010 0010 0010 0010
// 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010
// 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010
// 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010 0010 0010 0010 0010 0010
// 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 0030 0010
// 0030 0010 0030 0010 0030 0010 0030 0010 0010 0010 0010 0010 0010 0010 0030
// 0010 0030 0010 0030 0010 0030 0010 0030 0010 0010 0010 0030 0010 0A98
//
// Or the equiv. of sendPanasonic64(0x400401007C7D);
uint16_t panasonicProntoCode[104] = {
0x0000, 0x0071, 0x0000, 0x0032,
0x0080, 0x003F, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0030, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0030,
0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0030,
0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0030, 0x0010, 0x0A98};
void setup() {
irsend.begin();
Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
}
void loop() {
Serial.println("Sending a Samsung TV 'on' command.");
irsend.sendPronto(samsungProntoCode, 72);
delay(2000);
Serial.println("Sending a Panasonic Plasma TV 'on' command.");
irsend.sendPronto(panasonicProntoCode, 104);
delay(2000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,56 @@
/*
* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend
* Version 0.1 June, 2015
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009, Copyright 2009 Ken Shirriff, http://arcfn.com
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#define PanasonicAddress 0x4004 // Panasonic address (Pre data)
#define PanasonicPower 0x100BCBD // Panasonic Power button
#define JVCPower 0xC5E8
IRsend irsend(4); // An IR LED is controlled by GPIO pin 4 (D2)
void setup() {
irsend.begin();
}
void loop() {
// This should turn your TV on and off
irsend.sendPanasonic(PanasonicAddress, PanasonicPower);
irsend.sendJVC(JVCPower, 16, 0); // hex value, 16 bits, no repeat
// see http://www.sbprojects.com/knowledge/ir/jvc.php for information
delayMicroseconds(50);
irsend.sendJVC(JVCPower, 16, 1); // hex value, 16 bits, repeat
delayMicroseconds(50);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,259 @@
// Copyright 2015 chaeplin
// Copyright 2017 xpokor22
// This is based on:
// https://github.com/z3t0/Arduino-IRremote/blob/master/examples/LGACSendDemo/LGACSendDemo.ino
#include <IRremoteESP8266.h>
#include <IRsend.h>
IRsend irsend(14); // An IR LED is controlled by GPIO pin 14 (D5)
// 0 : TOWER
// 1 : WALL
const unsigned int kAc_Type = 1;
// 0 : cooling
// 1 : heating
unsigned int ac_heat = 1;
// 0 : off
// 1 : on
unsigned int ac_power_on = 0;
// 0 : off
// 1 : on --> power on
unsigned int ac_air_clean_state = 0;
// temperature : 18 ~ 30
unsigned int ac_temperature = 24;
// 0 : low
// 1 : mid
// 2 : high
// if kAc_Type = 1, 3 : change
unsigned int ac_flow = 0;
const uint8_t kAc_Flow_Tower[3] = {0, 4, 6};
const uint8_t kAc_Flow_Wall[4] = {0, 2, 4, 5};
uint32_t ac_code_to_sent;
void Ac_Send_Code(uint32_t code) {
Serial.print("code to send : ");
Serial.print(code, BIN);
Serial.print(" : ");
Serial.println(code, HEX);
irsend.sendLG(code, 28);
}
void Ac_Activate(unsigned int temperature, unsigned int air_flow,
unsigned int heat) {
ac_heat = heat;
unsigned int ac_msbits1 = 8;
unsigned int ac_msbits2 = 8;
unsigned int ac_msbits3 = 0;
unsigned int ac_msbits4;
if (ac_heat == 1)
ac_msbits4 = 4; // heating
else
ac_msbits4 = 0; // cooling
unsigned int ac_msbits5 = (temperature < 15) ? 0 : temperature - 15;
unsigned int ac_msbits6;
if (0 <= air_flow && air_flow <= 2) {
if (kAc_Type == 0)
ac_msbits6 = kAc_Flow_Tower[air_flow];
else
ac_msbits6 = kAc_Flow_Wall[air_flow];
}
// calculating using other values
unsigned int ac_msbits7 = (ac_msbits3 + ac_msbits4 + ac_msbits5 +
ac_msbits6) & B00001111;
ac_code_to_sent = ac_msbits1 << 4;
ac_code_to_sent = (ac_code_to_sent + ac_msbits2) << 4;
ac_code_to_sent = (ac_code_to_sent + ac_msbits3) << 4;
ac_code_to_sent = (ac_code_to_sent + ac_msbits4) << 4;
ac_code_to_sent = (ac_code_to_sent + ac_msbits5) << 4;
ac_code_to_sent = (ac_code_to_sent + ac_msbits6) << 4;
ac_code_to_sent = (ac_code_to_sent + ac_msbits7);
Ac_Send_Code(ac_code_to_sent);
ac_power_on = 1;
ac_temperature = temperature;
ac_flow = air_flow;
}
void Ac_Change_Air_Swing(int air_swing) {
if (kAc_Type == 0) {
if (air_swing == 1)
ac_code_to_sent = 0x881316B;
else
ac_code_to_sent = 0x881317C;
} else {
if (air_swing == 1)
ac_code_to_sent = 0x8813149;
else
ac_code_to_sent = 0x881315A;
}
Ac_Send_Code(ac_code_to_sent);
}
void Ac_Power_Down() {
ac_code_to_sent = 0x88C0051;
Ac_Send_Code(ac_code_to_sent);
ac_power_on = 0;
}
void Ac_Air_Clean(int air_clean) {
if (air_clean == '1')
ac_code_to_sent = 0x88C000C;
else
ac_code_to_sent = 0x88C0084;
Ac_Send_Code(ac_code_to_sent);
ac_air_clean_state = air_clean;
}
void setup() {
Serial.begin(115200);
delay(1000);
irsend.begin();
}
void loop() {
char b;
Serial.println("# a : mode or temp b : air_flow, temp, swing, clean,"
" cooling/heating");
Serial.println("# 0 : off 0");
Serial.println("# 1 : on 0");
Serial.println("# 2 : air_swing 0 or 1");
Serial.println("# 3 : air_clean 0 or 1");
Serial.println("# 4 : air_flow 0 ~ 2 : flow");
Serial.println("# + : temp + 1");
Serial.println("# - : temp - 1");
Serial.println("# c : cooling");
Serial.println("# h : heating");
Serial.println("# m : change cooling to air clean, air clean to cooling");
Serial.println("a="); // Prompt User for input
while (Serial.available() == 0) { // Wait for user input
}
char a = Serial.read(); // Read user input into a
switch (a) {
case '0':
case '1':
case '+':
case '-':
case 'c':
case 'h':
case 'm':
break;
default:
Serial.println("b="); // Prompt User for input
while (Serial.available() == 0) {}
char b = Serial.read();
}
/*
# a : mode or temp b : air_flow, temp, swing, clean, cooling/heating
# 18 ~ 30 : temp 0 ~ 2 : flow // on
# 0 : off 0
# 1 : on 0
# 2 : air_swing 0 or 1
# 3 : air_clean 0 or 1
# 4 : air_flow 0 ~ 3 : flow
# + : temp + 1
# - : temp - 1
# c : cooling
# h : heating
# m : change cooling to air clean, air clean to cooling
*/
Serial.print("a : ");
Serial.print(a);
Serial.print(" b : ");
Serial.println(b);
switch (a) {
case '0': // off
Ac_Power_Down();
break;
case '1': // on
Ac_Activate(ac_temperature, ac_flow, ac_heat);
break;
case '2':
if (b == '0')
Ac_Change_Air_Swing(0);
else
Ac_Change_Air_Swing(1);
break;
case '3': // 1 : clean on, power on
if (b == '0' | b == '1')
Ac_Air_Clean(b);
break;
case '4':
switch (b) {
case '1':
Ac_Activate(ac_temperature, 1, ac_heat);
break;
case '2':
Ac_Activate(ac_temperature, 2, ac_heat);
break;
case '3':
Ac_Activate(ac_temperature, 3, ac_heat);
break;
default:
Ac_Activate(ac_temperature, 0, ac_heat);
}
break;
case '+':
if (18 <= ac_temperature && ac_temperature <= 29)
Ac_Activate((ac_temperature + 1), ac_flow, ac_heat);
break;
case '-':
if (19 <= ac_temperature && ac_temperature <= 30)
Ac_Activate((ac_temperature - 1), ac_flow, ac_heat);
break;
case 'c':
ac_heat = 0;
Ac_Activate(ac_temperature, ac_flow, ac_heat);
break;
case 'h':
ac_heat = 1;
Ac_Activate(ac_temperature, ac_flow, ac_heat);
break;
case 'm':
/*
if ac is on, 1) turn off, 2) turn on Ac_Air_Clean(1)
if ac is off, 1) turn on, 2) turn off Ac_Air_Clean(0)
*/
if (ac_power_on == 1) {
Ac_Power_Down();
delay(100);
Ac_Air_Clean(1);
} else {
if (ac_air_clean_state == 1) {
Ac_Air_Clean(0);
delay(100);
}
Ac_Activate(ac_temperature, ac_flow, ac_heat);
}
break;
}
delay(100);
Serial.println("ac_temperature");
Serial.println(ac_temperature);
Serial.println("ac_flow");
Serial.println(ac_flow);
Serial.println("ac_heat");
Serial.println(ac_heat);
Serial.println("ac_power_on");
Serial.println(ac_power_on);
}
@@ -0,0 +1,52 @@
/* Copyright 2017 crankyoldgit
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Argo.h>
IRArgoAC argoir(4); // An IR LED is controlled by GPIO pin 4 (D2)
void setup() {
argoir.begin();
Serial.begin(115200);
}
void loop() {
Serial.println("Sending...");
// Set up what we want to send. See ir_Argo.cpp for all the options.
argoir.setPower(true);
argoir.setFan(ARGO_FAN_1);
argoir.setCoolMode(ARGO_COOL_AUTO);
argoir.setTemp(25);
// Now send the IR signal.
argoir.send();
delay(5000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,56 @@
/* Copyright 2016 sillyfrog
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Daikin.h>
IRDaikinESP dakinir(D2); // An IR LED is controlled by GPIO pin 4 (D2)
void setup() {
dakinir.begin();
Serial.begin(115200);
}
void loop() {
Serial.println("Sending...");
// Set up what we want to send. See ir_Daikin.cpp for all the options.
dakinir.on();
dakinir.setFan(1);
dakinir.setMode(DAIKIN_COOL);
dakinir.setTemp(25);
dakinir.setSwingVertical(0);
dakinir.setSwingHorizontal(0);
// Now send the IR signal.
dakinir.send();
delay(5000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,44 @@
// Copyright 2017 Jonny Graham
#include <IRsend.h>
#include <ir_Fujitsu.h>
IRFujitsuAC fujitsu(5); // IR led controlled by Pin D1.
void printState() {
// Display the settings.
Serial.println("Fujitsu A/C remote is in the following state:");
Serial.printf(" Command:%d, Mode: %d, Temp: %dC, Fan Speed: %d," \
" Swing Mode: %d\n",
fujitsu.getCmd(), fujitsu.getMode(), fujitsu.getTemp(),
fujitsu.getFanSpeed(), fujitsu.getSwing());
// Display the encoded IR sequence.
unsigned char* ir_code = fujitsu.getRaw();
Serial.print("IR Code: 0x");
for (uint8_t i = 0; i < FUJITSU_AC_STATE_LENGTH; i++)
Serial.printf("%02X", ir_code[i]);
Serial.println();
}
void setup() {
fujitsu.begin();
Serial.begin(115200);
delay(200);
// Set up what we want to send. See ir_Mitsubishi.cpp for all the options.
Serial.println("Default state of the remote.");
printState();
Serial.println("Setting desired state for A/C.");
fujitsu.setCmd(FUJITSU_AC_CMD_TURN_ON);
fujitsu.setSwing(FUJITSU_AC_SWING_BOTH);
fujitsu.setMode(FUJITSU_AC_MODE_COOL);
fujitsu.setFanSpeed(FUJITSU_AC_FAN_HIGH);
fujitsu.setTemp(24);
}
void loop() {
// Now send the IR signal.
Serial.println("Sending IR command to A/C ...");
fujitsu.send();
printState();
delay(5000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,80 @@
/* Copyright 2016 David Conran
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Kelvinator.h>
IRKelvinatorAC kelvir(D2); // An IR LED is controlled by GPIO pin 4 (D2)
void printState() {
// Display the settings.
Serial.println("Kelvinator A/C remote is in the following state:");
Serial.printf(" Basic\n Power: %d, Mode: %d, Temp: %dC, Fan Speed: %d\n",
kelvir.getPower(), kelvir.getMode(), kelvir.getTemp(),
kelvir.getFan());
Serial.printf(" Options\n X-Fan: %d, Light: %d, Ion Filter: %d\n",
kelvir.getXFan(), kelvir.getLight(), kelvir.getIonFilter());
Serial.printf(" Swing (V): %d, Swing (H): %d, Turbo: %d, Quiet: %d\n",
kelvir.getSwingVertical(), kelvir.getSwingHorizontal(),
kelvir.getTurbo(), kelvir.getQuiet());
// Display the encoded IR sequence.
unsigned char* ir_code = kelvir.getRaw();
Serial.print("IR Code: 0x");
for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++)
Serial.printf("%02X", ir_code[i]);
Serial.println();
}
void setup() {
kelvir.begin();
Serial.begin(115200);
delay(200);
// Set up what we want to send. See ir_Kelvinator.cpp for all the options.
// Most things default to off.
Serial.println("Default state of the remote.");
printState();
Serial.println("Setting desired state for A/C.");
kelvir.on();
kelvir.setFan(1);
kelvir.setMode(KELVINATOR_COOL);
kelvir.setTemp(26);
kelvir.setSwingVertical(false);
kelvir.setSwingHorizontal(true);
kelvir.setXFan(true);
kelvir.setIonFilter(false);
kelvir.setLight(true);
}
void loop() {
// Now send the IR signal.
Serial.println("Sending IR command to A/C ...");
kelvir.send();
printState();
delay(5000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,71 @@
/* Copyright 2017 David Conran
*
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Mitsubishi.h>
IRMitsubishiAC mitsubir(D2); // An IR LED is controlled by GPIO pin 4 (D2)
void printState() {
// Display the settings.
Serial.println("Mitsubishi A/C remote is in the following state:");
Serial.printf(" Power: %d, Mode: %d, Temp: %dC, Fan Speed: %d," \
" Vane Mode: %d\n",
mitsubir.getPower(), mitsubir.getMode(), mitsubir.getTemp(),
mitsubir.getFan(), mitsubir.getVane());
// Display the encoded IR sequence.
unsigned char* ir_code = mitsubir.getRaw();
Serial.print("IR Code: 0x");
for (uint8_t i = 0; i < MITSUBISHI_AC_STATE_LENGTH; i++)
Serial.printf("%02X", ir_code[i]);
Serial.println();
}
void setup() {
mitsubir.begin();
Serial.begin(115200);
delay(200);
// Set up what we want to send. See ir_Mitsubishi.cpp for all the options.
Serial.println("Default state of the remote.");
printState();
Serial.println("Setting desired state for A/C.");
mitsubir.on();
mitsubir.setFan(1);
mitsubir.setMode(MITSUBISHI_AC_COOL);
mitsubir.setTemp(26);
mitsubir.setVane(MITSUBISHI_AC_VANE_AUTO);
}
void loop() {
// Now send the IR signal.
Serial.println("Sending IR command to A/C ...");
mitsubir.send();
printState();
delay(5000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
@@ -0,0 +1,52 @@
/* Copyright 2017 stufisher
* An IR LED circuit *MUST* be connected to ESP8266 pin 4 (D2).
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Trotec.h>
IRTrotecESP trotecir(D2); // An IR LED is controlled by GPIO pin 4 (D2)
void setup() {
trotecir.begin();
Serial.begin(115200);
}
void loop() {
Serial.println("Sending...");
// Set up what we want to send. See ir_Trotec.cpp for all the options.
trotecir.setPower(true);
trotecir.setSpeed(TROTEC_FAN_LOW);
trotecir.setMode(TROTEC_COOL);
trotecir.setTemp(25);
// Now send the IR signal.
trotecir.send();
delay(5000);
}
@@ -0,0 +1,17 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
+128
View File
@@ -0,0 +1,128 @@
#########################################
# Syntax Coloring Map For IRremoteESP8266
#########################################
#######################################################
# The Arduino IDE requires the use of a tab separator
# between the name and identifier. Without this tab the
# keyword is not highlighted.
#
# Reference: https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywords
#######################################################
#######################################
# Datatypes (KEYWORD1)
#######################################
decode_results KEYWORD1
IRrecv KEYWORD1
IRsend KEYWORD1
IRtimer KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
decode KEYWORD2
enableIRIn KEYWORD2
disableIRIn KEYWORD2
resume KEYWORD2
begin KEYWORD2
send KEYWORD2
enableIROut KEYWORD2
sendNEC KEYWORD2
encodeNEC KEYWORD2
sendLG KEYWORD2
encodeLG KEYWORD2
sendSony KEYWORD2
encodeSony KEYWORD2
sendSanyo KEYWORD2
sendSanyoLC7461 KEYWORD2
encodeSanyoLC7461 KEYWORD2
sendMitsubishi KEYWORD2
sendRaw KEYWORD2
sendGC KEYWORD2
sendRC5 KEYWORD2
sendRC6 KEYWORD2
sendRCMM KEYWORD2
sendDISH KEYWORD2
sendSharp KEYWORD2
sendSharpRaw KEYWORD2
encodeSharp KEYWORD2
sendPanasonic KEYWORD2
sendPanasonic64 KEYWORD2
encodePanasonic KEYWORD2
sendJVC KEYWORD2
encodeJVC KEYWORD2
sendWhynter KEYWORD2
sendSAMSUNG KEYWORD2
encodeSAMSUNG KEYWORD2
sendDaikin KEYWORD2
sendCOOLIX KEYWORD2
sendDenon KEYWORD2
sendKelvinator KEYWORD2
sendSherwood KEYWORD2
sendMitsubishiAC KEYWORD2
mark KEYWORD2
space KEYWORD2
reset KEYWORD2
elapsed KEYWORD2
calcLGChecksum KEYWORD2
reverseBits KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
NEC LITERAL1
SONY LITERAL1
SANYO LITERAL1
MITSUBISHI LITERAL1
RC5 LITERAL1
RC5X LITERAL1
RC6 LITERAL1
DISH LITERAL1
SHARP LITERAL1
PANASONIC LITERAL1
JVC LITERAL1
LG LITERAL1
SAMSUNG LITERAL1
WHYNTER LITERAL1
AIWA_RC_T501 LITERAL1
COOLIX LITERAL1
UNKNOWN LITERAL1
REPEAT LITERAL1
DENON LITERAL1
DAIKIN LITERAL1
KELVINATOR LITERAL1
SHERWOOD LITERAL1
MITSUBISHIAC LITERAL1
RCMM LITERAL1
SANYO_LC7461 LITERAL1
NEC_BITS LITERAL1
SHERWOOD_BITS LITERAL1
SONY_MIN_BITS LITERAL1
SONY_12_BITS LITERAL1
SONY_15_BITS LITERAL1
SONY_20_BITS LITERAL1
SANYO_SA8650B_BITS LITERAL1
MITSUBISHI_BITS LITERAL1
PANASONIC_BITS LITERAL1
JVC_BITS LITERAL1
LG_BITS LITERAL1
SAMSUNG_BITS LITERAL1
COOLIX_BITS LITERAL1
DAIKIN_BITS LITERAL1
RC5X_BITS LITERAL1
RC6_36_BITS LITERAL1
RC6_MODE0_BITS LITERAL1
RCMM_BITS LITERAL1
WHYNTER_BITS LITERAL1
SANYO_LC7461_BITS LITERAL1
SHARP_BITS LITERAL1
DISH_BITS LITERAL1
DENON_BITS LITERAL1
SONY_MIN_REPEAT LITERAL1
MITSUBISHI_MIN_REPEAT LITERAL1
DISH_MIN_REPEAT LITERAL1
SHERWOOD_MIN_REPEAT LITERAL1
+44
View File
@@ -0,0 +1,44 @@
{
"name": "IRremoteESP8266",
"version": "2.2.0",
"keywords": "infrared, ir, remote, esp8266",
"description": "Send and receive infrared signals with multiple protocols (ESP8266)",
"repository":
{
"type": "git",
"url": "https://github.com/markszabo/IRremoteESP8266.git"
},
"authors": [
{
"name": "Ken Shirriff",
"email": "zetoslab@gmail.com"
},
{
"name": "Mark Szabo",
"url": "http://nomartini-noparty.blogspot.com/",
"maintainer": true
},
{
"name": "Sebastien Warin",
"url": "http://sebastien.warin.fr",
"maintainer": true
},
{
"name": "David Conran",
"url": "https://plus.google.com/+davidconran",
"maintainer": true
},
{
"name": "Roi Dayan",
"url": "https://github.com/roidayan/",
"maintainer": true
},
{
"name": "Massimiliano Pinto",
"url": "https://github.com/pintomax/",
"maintainer": true
}
],
"frameworks": "arduino",
"platforms": "espressif8266"
}
+9
View File
@@ -0,0 +1,9 @@
name=IRremoteESP8266
version=2.2.0
author=Sebastien Warin, Mark Szabo, Ken Shirriff, David Conran
maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto
sentence=Send and receive infrared signals with multiple protocols (ESP8266)
paragraph=This library enables you to send and receive infra-red signals on an ESP8266.
category=Device Control
url=https://github.com/markszabo/IRremoteESP8266
architectures=esp8266
+26
View File
@@ -0,0 +1,26 @@
[platformio]
lib_extra_dirs = .
src_dir = examples/IRrecvDumpV2
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
[env:d1_mini]
platform = espressif8266
framework = arduino
board = d1_mini
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
+1
View File
@@ -0,0 +1 @@
filter=-build/include,+build/include_alpha,+build/include_order,+build/include_what_you_use
+627
View File
@@ -0,0 +1,627 @@
// Copyright 2009 Ken Shirriff
// Copyright 2015 Mark Szabo
// Copyright 2015 Sebastien Warin
// Copyright 2017 David Conran
#include "IRrecv.h"
#include <stddef.h>
#ifndef UNIT_TEST
extern "C" {
#include <gpio.h>
#include <user_interface.h>
}
#include <Arduino.h>
#endif
#include <algorithm>
#include "IRremoteESP8266.h"
#ifdef UNIT_TEST
#undef ICACHE_RAM_ATTR
#define ICACHE_RAM_ATTR
#endif
// Updated by Sebastien Warin (http://sebastien.warin.fr) for receiving IR code
// on ESP8266
// Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for
// sending IR code on ESP8266
// Globals
#ifndef UNIT_TEST
static ETSTimer timer;
#endif
volatile irparams_t irparams;
irparams_t *irparams_save; // A copy of the interrupt state while decoding.
#ifndef UNIT_TEST
static void ICACHE_RAM_ATTR read_timeout(void *arg __attribute__((unused))) {
os_intr_lock();
if (irparams.rawlen)
irparams.rcvstate = STATE_STOP;
os_intr_unlock();
}
static void ICACHE_RAM_ATTR gpio_intr() {
uint32_t now = system_get_time();
uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
static uint32_t start = 0;
os_timer_disarm(&timer);
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status);
// Grab a local copy of rawlen to reduce instructions used in IRAM.
// This is an ugly premature optimisation code-wise, but we do everything we
// can to save IRAM.
// It seems referencing the value via the structure uses more instructions.
// Less instructions means faster and less IRAM used.
// N.B. It saves about 13 bytes of IRAM.
uint16_t rawlen = irparams.rawlen;
if (rawlen >= irparams.bufsize) {
irparams.overflow = true;
irparams.rcvstate = STATE_STOP;
}
if (irparams.rcvstate == STATE_STOP)
return;
if (irparams.rcvstate == STATE_IDLE) {
irparams.rcvstate = STATE_MARK;
irparams.rawbuf[rawlen] = 1;
} else {
if (now < start)
irparams.rawbuf[rawlen] = (UINT32_MAX - start + now) / RAWTICK;
else
irparams.rawbuf[rawlen] = (now - start) / RAWTICK;
}
irparams.rawlen++;
start = now;
#define ONCE 0
os_timer_arm(&timer, irparams.timeout, ONCE);
}
#endif // UNIT_TEST
// Start of IRrecv class -------------------
// Class constructor
// Args:
// recvpin: GPIO pin the IR receiver module's data pin is connected to.
// bufsize: Nr. of entries to have in the capture buffer. (Default: RAWBUF)
// timeout: Nr. of milli-Seconds of no signal before we stop capturing data.
// (Default: TIMEOUT_MS)
// save_buffer: Use a second (save) buffer to decode from. (Def: false)
// Returns:
// A IRrecv class object.
IRrecv::IRrecv(uint16_t recvpin, uint16_t bufsize, uint8_t timeout,
bool save_buffer) {
irparams.recvpin = recvpin;
irparams.bufsize = bufsize;
// Ensure we are going to be able to store all possible values in the
// capture buffer.
irparams.timeout = std::min(timeout, (uint8_t) MAX_TIMEOUT_MS);
irparams.rawbuf = new uint16_t[bufsize];
if (irparams.rawbuf == NULL) {
DPRINTLN("Could not allocate memory for the primary IR buffer.\n"
"Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!");
#ifndef UNIT_TEST
ESP.restart(); // Mem alloc failure. Reboot.
#endif
}
// If we have been asked to use a save buffer (for decoding), then create one.
if (save_buffer) {
irparams_save = new irparams_t;
irparams_save->rawbuf = new uint16_t[bufsize];
// Check we allocated the memory successfully.
if (irparams_save->rawbuf == NULL) {
DPRINTLN("Could not allocate memory for the second IR buffer.\n"
"Try a smaller size for CAPTURE_BUFFER_SIZE.\nRebooting!");
#ifndef UNIT_TEST
ESP.restart(); // Mem alloc failure. Reboot.
#endif
}
} else {
irparams_save = NULL;
}
}
// Class destructor
IRrecv::~IRrecv(void) {
delete [] irparams.rawbuf;
if (irparams_save != NULL) {
delete [] irparams_save->rawbuf;
delete irparams_save;
}
}
// initialization
void IRrecv::enableIRIn() {
// initialize state machine variables
resume();
#ifndef UNIT_TEST
// Initialize timer
os_timer_disarm(&timer);
os_timer_setfn(&timer, reinterpret_cast<os_timer_func_t *>(read_timeout),
NULL);
// Attach Interrupt
attachInterrupt(irparams.recvpin, gpio_intr, CHANGE);
#endif
}
void IRrecv::disableIRIn() {
#ifndef UNIT_TEST
os_timer_disarm(&timer);
detachInterrupt(irparams.recvpin);
#endif
}
void IRrecv::resume() {
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
irparams.overflow = false;
}
// Make a copy of the interrupt state & buffer data.
// Needed because irparams is marked as volatile, thus memcpy() isn't allowed.
// Only call this when you know the interrupt handlers won't modify anything.
// i.e. In STATE_STOP.
//
// Args:
// src: Pointer to an irparams_t structure to copy from.
// dst: Pointer to an irparams_t structure to copy to.
void IRrecv::copyIrParams(volatile irparams_t *src, irparams_t *dst) {
// Typecast src and dst addresses to (char *)
char *csrc = (char *) src; // NOLINT(readability/casting)
char *cdst = (char *) dst; // NOLINT(readability/casting)
// Save the pointer to the destination's rawbuf so we don't lose it as
// the for-loop/copy after this will overwrite it with src's rawbuf pointer.
// This isn't immediately obvious due to typecasting/different variable names.
uint16_t *dst_rawbuf_ptr;
dst_rawbuf_ptr = dst->rawbuf;
// Copy contents of src[] to dst[]
for (uint16_t i = 0; i < sizeof(irparams_t); i++)
cdst[i] = csrc[i];
// Restore the buffer pointer
dst->rawbuf = dst_rawbuf_ptr;
// Copy the rawbuf
for (uint16_t i = 0; i < dst->bufsize; i++)
dst->rawbuf[i] = src->rawbuf[i];
}
// Obtain the maximum number of entries possible in the capture buffer.
// i.e. It's size.
uint16_t IRrecv::getBufSize() {
return irparams.bufsize;
}
// Decodes the received IR message.
// If the interrupt state is saved, we will immediately resume waiting
// for the next IR message to avoid missing messages.
// Note: There is a trade-off here. Saving the state means less time lost until
// we can receiving the next message vs. using more RAM. Choose appropriately.
//
// Args:
// results: A pointer to where the decoded IR message will be stored.
// save: A pointer to an irparams_t instance in which to save
// the interrupt's memory/state. NULL means don't save it.
// Returns:
// A boolean indicating if an IR message is ready or not.
bool IRrecv::decode(decode_results *results, irparams_t *save) {
// Proceed only if an IR message been received.
#ifndef UNIT_TEST
if (irparams.rcvstate != STATE_STOP)
return false;
#endif
// Clear the entry we are currently pointing to when we got the timeout.
// i.e. Stopped collecting IR data.
// It's junk as we never wrote an entry to it and can only confuse decoding.
// This is done here rather than logically the best place in read_timeout()
// as it saves a few bytes of ICACHE_RAM as that routine is bound to an
// interrupt. decode() is not stored in ICACHE_RAM.
// Another better option would be to zero the entire irparams.rawbuf[] on
// resume() but that is a much more expensive operation compare to this.
irparams.rawbuf[irparams.rawlen] = 0;
bool resumed = false; // Flag indicating if we have resumed.
// If we were requested to use a save buffer previously, do so.
if (save == NULL)
save = irparams_save;
if (save == NULL) {
// We haven't been asked to copy it so use the existing memory.
#ifndef UNIT_TEST
results->rawbuf = irparams.rawbuf;
results->rawlen = irparams.rawlen;
results->overflow = irparams.overflow;
#endif
} else {
copyIrParams(&irparams, save); // Duplicate the interrupt's memory.
resume(); // It's now safe to rearm. The IR message won't be overridden.
resumed = true;
// Point the results at the saved copy.
results->rawbuf = save->rawbuf;
results->rawlen = save->rawlen;
results->overflow = save->overflow;
}
// Reset any previously partially processed results.
results->decode_type = UNKNOWN;
results->bits = 0;
results->value = 0;
results->address = 0;
results->command = 0;
results->repeat = false;
#if DECODE_AIWA_RC_T501
DPRINTLN("Attempting Aiwa RC T501 decode");
// Try decodeAiwaRCT501() before decodeSanyoLC7461() & decodeNEC()
// because the protocols are similar. This protocol is more specific than
// those ones, so should got before them.
if (decodeAiwaRCT501(results))
return true;
#endif
#if DECODE_SANYO
DPRINTLN("Attempting Sanyo LC7461 decode");
// Try decodeSanyoLC7461() before decodeNEC() because the protocols are
// similar in timings & structure, but the Sanyo one is much longer than the
// NEC protocol (42 vs 32 bits) so this one should be tried first to try to
// reduce false detection as a NEC packet.
if (decodeSanyoLC7461(results))
return true;
#endif
#if DECODE_NEC
DPRINTLN("Attempting NEC decode");
if (decodeNEC(results))
return true;
#endif
#if DECODE_SONY
DPRINTLN("Attempting Sony decode");
if (decodeSony(results))
return true;
#endif
#if DECODE_MITSUBISHI
DPRINTLN("Attempting Mitsubishi decode");
if (decodeMitsubishi(results))
return true;
#endif
#if DECODE_RC5
DPRINTLN("Attempting RC5 decode");
if (decodeRC5(results))
return true;
#endif
#if DECODE_RC6
DPRINTLN("Attempting RC6 decode");
if (decodeRC6(results))
return true;
#endif
#if DECODE_RCMM
DPRINTLN("Attempting RC-MM decode");
if (decodeRCMM(results))
return true;
#endif
#if DECODE_DENON
// Denon needs to precede Panasonic as it is a special case of Panasonic.
#ifdef DEBUG
DPRINTLN("Attempting Denon decode");
#endif
if (decodeDenon(results, DENON_48_BITS) ||
decodeDenon(results, DENON_BITS) ||
decodeDenon(results, DENON_LEGACY_BITS))
return true;
#endif
#if DECODE_PANASONIC
DPRINTLN("Attempting Panasonic decode");
if (decodePanasonic(results))
return true;
#endif
#if DECODE_LG
DPRINTLN("Attempting LG (28-bit) decode");
if (decodeLG(results, LG_BITS, true))
return true;
DPRINTLN("Attempting LG (32-bit) decode");
// LG32 should be tried before Samsung
if (decodeLG(results, LG32_BITS, true))
return true;
#endif
#if DECODE_JVC
DPRINTLN("Attempting JVC decode");
if (decodeJVC(results))
return true;
#endif
#if DECODE_SAMSUNG
DPRINTLN("Attempting SAMSUNG decode");
if (decodeSAMSUNG(results))
return true;
#endif
#if DECODE_WHYNTER
DPRINTLN("Attempting Whynter decode");
if (decodeWhynter(results))
return true;
#endif
#if DECODE_DISH
DPRINTLN("Attempting DISH decode");
if (decodeDISH(results))
return true;
#endif
#if DECODE_SHARP
DPRINTLN("Attempting Sharp decode");
if (decodeSharp(results))
return true;
#endif
#if DECODE_COOLIX
DPRINTLN("Attempting Coolix decode");
if (decodeCOOLIX(results))
return true;
#endif
/* NOTE: Disabled due to poor quality.
#if DECODE_SANYO
// The Sanyo S866500B decoder is very poor quality & depricated.
// *IF* you are going to enable it, do it near last to avoid false positive
// matches.
DPRINTLN("Attempting Sanyo SA8650B decode");
if (decodeSanyo(results))
return true;
#endif
*/
#if DECODE_NEC
// Some devices send NEC-like codes that don't follow the true NEC spec.
// This should detect those. e.g. Apple TV remote etc.
// This needs to be done after all other codes that use strict and some
// other protocols that are NEC-like as well, as turning off strict may
// cause this to match other valid protocols.
DPRINTLN("Attempting NEC (non-stict) decode");
if (decodeNEC(results, NEC_BITS, false)) {
results->decode_type = NEC_LIKE;
return true;
}
#endif
// decodeHash returns a hash on any input.
// Thus, it needs to be last in the list.
// If you add any decodes, add them before this.
if (decodeHash(results)) {
return true;
}
// Throw away and start over
if (!resumed) // Check if we have already resumed.
resume();
return false;
}
// Calculate the lower bound of the nr. of ticks.
//
// Args:
// usecs: Nr. of uSeconds.
// tolerance: Percent as an integer. e.g. 10 is 10%
// Returns:
// Nr. of ticks.
uint32_t IRrecv::ticksLow(uint32_t usecs, uint8_t tolerance) {
// max() used to ensure the result can't drop below 0 before the cast.
return((uint32_t) std::max((int32_t) (usecs * (1.0 - tolerance / 100.0)), 0));
}
// Calculate the upper bound of the nr. of ticks.
//
// Args:
// usecs: Nr. of uSeconds.
// tolerance: Percent as an integer. e.g. 10 is 10%
// Returns:
// Nr. of ticks.
uint32_t IRrecv::ticksHigh(uint32_t usecs, uint8_t tolerance) {
return((uint32_t) (usecs * (1.0 + tolerance / 100.0)) + 1);
}
// Check if we match a pulse(measured) with the desired within
// +/-tolerance percent.
//
// Args:
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::match(uint32_t measured, uint32_t desired,
uint8_t tolerance) {
measured *= RAWTICK; // Convert to uSecs.
DPRINT("Matching: ");
DPRINT(ticksLow(desired, tolerance));
DPRINT(" <= ");
DPRINT(measured);
DPRINT(" <= ");
DPRINTLN(ticksHigh(desired, tolerance));
return (measured >= ticksLow(desired, tolerance) &&
measured <= ticksHigh(desired, tolerance));
}
// Check if we match a pulse(measured) of at least desired within
// +/-tolerance percent.
//
// Args:
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::matchAtLeast(uint32_t measured, uint32_t desired,
uint8_t tolerance) {
measured *= RAWTICK; // Convert to uSecs.
DPRINT("Matching ATLEAST ");
DPRINT(measured);
DPRINT(" vs ");
DPRINT(desired);
DPRINT(". Matching: ");
DPRINT(measured);
DPRINT(" >= ");
DPRINT(ticksLow(std::min(desired, MS_TO_USEC(irparams.timeout)), tolerance));
DPRINT(" [min(");
DPRINT(ticksLow(desired, tolerance));
DPRINT(", ");
DPRINT(ticksLow(MS_TO_USEC(irparams.timeout), tolerance));
DPRINTLN(")]");
// We really should never get a value of 0, except as the last value
// in the buffer. If that is the case, then assume infinity and return true.
if (measured == 0) return true;
return measured >= ticksLow(std::min(desired, MS_TO_USEC(irparams.timeout)),
tolerance);
}
// Check if we match a mark signal(measured) with the desired within
// +/-tolerance percent, after an expected is excess is added.
//
// Args:
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
// excess: Nr. of useconds.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::matchMark(uint32_t measured, uint32_t desired,
uint8_t tolerance, int16_t excess) {
DPRINT("Matching MARK ");
DPRINT(measured * RAWTICK);
DPRINT(" vs ");
DPRINT(desired);
DPRINT(" + ");
DPRINT(excess);
DPRINT(". ");
return match(measured, desired + excess, tolerance);
}
// Check if we match a space signal(measured) with the desired within
// +/-tolerance percent, after an expected is excess is removed.
//
// Args:
// measured: The recorded period of the signal pulse.
// desired: The expected period (in useconds) we are matching against.
// tolerance: A percentage expressed as an integer. e.g. 10 is 10%.
// excess: Nr. of useconds.
//
// Returns:
// Boolean: true if it matches, false if it doesn't.
bool IRrecv::matchSpace(uint32_t measured, uint32_t desired,
uint8_t tolerance, int16_t excess) {
DPRINT("Matching SPACE ");
DPRINT(measured * RAWTICK);
DPRINT(" vs ");
DPRINT(desired);
DPRINT(" - ");
DPRINT(excess);
DPRINT(". ");
return match(measured, desired - excess, tolerance);
}
/* -----------------------------------------------------------------------
* hashdecode - decode an arbitrary IR code.
* Instead of decoding using a standard encoding scheme
* (e.g. Sony, NEC, RC5), the code is hashed to a 32-bit value.
*
* The algorithm: look at the sequence of MARK signals, and see if each one
* is shorter (0), the same length (1), or longer (2) than the previous.
* Do the same with the SPACE signals. Hash the resulting sequence of 0's,
* 1's, and 2's to a 32-bit value. This will give a unique value for each
* different code (probably), for most code systems.
*
* http://arcfn.com/2010/01/using-arbitrary-remotes-with-arduino.html
*/
// Compare two tick values, returning 0 if newval is shorter,
// 1 if newval is equal, and 2 if newval is longer
// Use a tolerance of 20%
int16_t IRrecv::compare(uint16_t oldval, uint16_t newval) {
if (newval < oldval * 0.8)
return 0;
else if (oldval < newval * 0.8)
return 2;
else
return 1;
}
/* Converts the raw code values into a 32-bit hash code.
* Hopefully this code is unique for each button.
* This isn't a "real" decoding, just an arbitrary value.
*/
bool IRrecv::decodeHash(decode_results *results) {
// Require at least 6 samples to prevent triggering on noise
if (results->rawlen < 6)
return false;
int32_t hash = FNV_BASIS_32;
// 'rawlen - 2' to avoid the look ahead from going out of bounds.
// Should probably be -3 to avoid comparing the trailing space entry,
// however it is left this way for compatibility with previously captured
// values.
for (uint16_t i = 1; i < results->rawlen - 2; i++) {
int16_t value = compare(results->rawbuf[i], results->rawbuf[i + 2]);
// Add value into the hash
hash = (hash * FNV_PRIME_32) ^ value;
}
results->value = hash & 0xFFFFFFFF;
results->bits = results->rawlen / 2;
results->address = 0;
results->command = 0;
results->decode_type = UNKNOWN;
return true;
}
// Match & decode the typical data section of an IR message.
// The data value constructed as the Most Significant Bit first.
//
// Args:
// data_ptr: A pointer to where we are at in the capture buffer.
// nbits: Nr. of data bits we expect.
// onemark: Nr. of uSeconds in an expected mark signal for a '1' bit.
// onespace: Nr. of uSeconds in an expected space signal for a '1' bit.
// zeromark: Nr. of uSeconds in an expected mark signal for a '0' bit.
// zerospace: Nr. of uSeconds in an expected space signal for a '0' bit.
// Returns:
// A match_result_t structure containing the success (or not), the data value,
// and how many buffer entries were used.
match_result_t IRrecv::matchData(volatile uint16_t *data_ptr, uint16_t nbits,
uint16_t onemark, uint32_t onespace,
uint16_t zeromark, uint32_t zerospace) {
match_result_t result;
result.success = false;
result.data = 0;
if (onemark == zeromark) { // Is this space encoded data format?
for (result.used = 0;
result.used < nbits * 2;
result.used += 2, data_ptr++) {
if (!matchMark(*data_ptr, onemark))
return result; // Fail
data_ptr++;
if (matchSpace(*data_ptr, onespace))
result.data = (result.data << 1) | 1;
else if (matchSpace(*data_ptr, zerospace))
result.data <<= 1;
else
return result; // Fail
}
result.success = true;
} else if (onespace == zerospace) { // Is this mark encoded data format?
for (result.used = 0;
result.used < nbits * 2;
result.used += 2, data_ptr++) {
if (matchMark(*data_ptr, onemark))
result.data = (result.data << 1) | 1;
else if (matchMark(*data_ptr, zeromark))
result.data <<= 1;
else
return result; // Fail
data_ptr++;
if (!matchSpace(*data_ptr, onespace))
return result; // Fail
}
result.success = true;
}
return result;
}
// End of IRrecv class -------------------
+203
View File
@@ -0,0 +1,203 @@
// Copyright 2009 Ken Shirriff
// Copyright 2015 Mark Szabo
// Copyright 2015 Sebastien Warin
// Copyright 2017 David Conran
#ifndef IRRECV_H_
#define IRRECV_H_
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <stddef.h>
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include "IRremoteESP8266.h"
// Constants
#define HEADER 2U // Usual nr. of header entries.
#define FOOTER 2U // Usual nr. of footer (stop bits) entries.
#define OFFSET_START 1U // Usual rawbuf entry to start processing from.
#define MS_TO_USEC(x) (x * 1000U) // Convert milli-Seconds to micro-Seconds.
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 50U
#define RAWBUF 100U // Default length of raw capture buffer
#define REPEAT UINT64_MAX
// receiver states
#define STATE_IDLE 2U
#define STATE_MARK 3U
#define STATE_SPACE 4U
#define STATE_STOP 5U
#define TOLERANCE 25U // default percent tolerance in measurements
#define RAWTICK 2U // Capture tick to uSec factor.
// How long (ms) before we give up wait for more data?
// Don't exceed MAX_TIMEOUT_MS without a good reason.
// That is the capture buffers maximum value size. (UINT16_MAX / RAWTICK)
// Typically messages/protocols tend to repeat around the 100ms timeframe,
// thus we should timeout before that to give us some time to try to decode
// before we need to start capturing a possible new message.
// Typically 15ms suits most applications. However, some protocols demand a
// higher value. e.g. 90ms for XMP-1 and some aircon units.
#define TIMEOUT_MS 15U // In MilliSeconds.
#define MAX_TIMEOUT_MS (RAWTICK * UINT16_MAX / MS_TO_USEC(1))
// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param
#define FNV_PRIME_32 16777619UL
#define FNV_BASIS_32 2166136261UL
// Types
// information for the interrupt handler
typedef struct {
uint8_t recvpin; // pin for IR data from detector
uint8_t rcvstate; // state machine
uint16_t timer; // state timer, counts 50uS ticks.
uint16_t bufsize; // max. nr. of entries in the capture buffer.
uint16_t *rawbuf; // raw data
// uint16_t is used for rawlen as it saves 3 bytes of iram in the interrupt
// handler. Don't ask why, I don't know. It just does.
uint16_t rawlen; // counter of entries in rawbuf.
uint8_t overflow; // Buffer overflow indicator.
uint8_t timeout; // Nr. of milliSeconds before we give up.
} irparams_t;
// results from a data match
typedef struct {
bool success; // Was the match successful?
uint64_t data; // The data found.
uint16_t used; // How many buffer positions were used.
} match_result_t;
// Classes
// Results returned from the decoder
class decode_results {
public:
decode_type_t decode_type; // NEC, SONY, RC5, UNKNOWN
uint64_t value; // Decoded value
uint16_t bits; // Number of bits in decoded value
volatile uint16_t *rawbuf; // Raw intervals in .5 us ticks
uint16_t rawlen; // Number of records in rawbuf.
bool overflow;
bool repeat; // Is the result a repeat code?
uint32_t address; // Decoded device address.
uint32_t command; // Decoded command.
};
// main class for receiving IR
class IRrecv {
public:
explicit IRrecv(uint16_t recvpin, uint16_t bufsize = RAWBUF,
uint8_t timeout = TIMEOUT_MS,
bool save_buffer = false); // Constructor
~IRrecv(); // Destructor
bool decode(decode_results *results, irparams_t *save = NULL);
void enableIRIn();
void disableIRIn();
void resume();
uint16_t getBufSize();
#ifndef UNIT_TEST
private:
#endif
irparams_t *irparams_save;
// These are called by decode
void copyIrParams(volatile irparams_t *src, irparams_t *dst);
int16_t compare(uint16_t oldval, uint16_t newval);
uint32_t ticksLow(uint32_t usecs, uint8_t tolerance = TOLERANCE);
uint32_t ticksHigh(uint32_t usecs, uint8_t tolerance = TOLERANCE);
bool match(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE);
bool matchAtLeast(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE);
bool matchMark(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE, int16_t excess = MARK_EXCESS);
bool matchSpace(uint32_t measured, uint32_t desired,
uint8_t tolerance = TOLERANCE, int16_t excess = MARK_EXCESS);
match_result_t matchData(volatile uint16_t *data_ptr, uint16_t nbits,
uint16_t onemark, uint32_t onespace,
uint16_t zeromark, uint32_t zerospace);
bool decodeHash(decode_results *results);
#if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || SEND_SANYO)
bool decodeNEC(decode_results *results, uint16_t nbits = NEC_BITS,
bool strict = true);
#endif
#if DECODE_SONY
bool decodeSony(decode_results *results, uint16_t nbits = SONY_MIN_BITS,
bool strict = false);
#endif
#if DECODE_SANYO
// DISABLED due to poor quality.
// bool decodeSanyo(decode_results *results,
// uint16_t nbits = SANYO_SA8650B_BITS,
// bool strict = false);
bool decodeSanyoLC7461(decode_results *results,
uint16_t nbits = SANYO_LC7461_BITS,
bool strict = true);
#endif
#if DECODE_MITSUBISHI
bool decodeMitsubishi(decode_results *results,
uint16_t nbits = MITSUBISHI_BITS,
bool strict = true);
#endif
#if (DECODE_RC5 || DECODE_R6)
int16_t getRClevel(decode_results *results, uint16_t *offset, uint16_t *used,
uint16_t bitTime);
#endif
#if DECODE_RC5
bool decodeRC5(decode_results *results, uint16_t nbits = RC5X_BITS,
bool strict = true);
#endif
#if DECODE_RC6
bool decodeRC6(decode_results *results, uint16_t nbits = RC6_MODE0_BITS,
bool strict = false);
#endif
#if DECODE_RCMM
bool decodeRCMM(decode_results *results, uint16_t nbits = RCMM_BITS,
bool strict = false);
#endif
#if (DECODE_PANASONIC || DECODE_DENON)
bool decodePanasonic(decode_results *results, uint16_t nbits = PANASONIC_BITS,
bool strict = false,
uint32_t manufacturer = PANASONIC_MANUFACTURER);
#endif
#if DECODE_LG
bool decodeLG(decode_results *results, uint16_t nbits = LG_BITS,
bool strict = false);
#endif
#if DECODE_JVC
bool decodeJVC(decode_results *results, uint16_t nbits = JVC_BITS,
bool strict = true);
#endif
#if DECODE_SAMSUNG
bool decodeSAMSUNG(decode_results *results, uint16_t nbits = SAMSUNG_BITS,
bool strict = true);
#endif
#if DECODE_WHYNTER
bool decodeWhynter(decode_results *results, uint16_t nbits = WHYNTER_BITS,
bool strict = true);
#endif
#if DECODE_COOLIX
bool decodeCOOLIX(decode_results *results, uint16_t nbits = COOLIX_BITS,
bool strict = true);
#endif
#if DECODE_DENON
bool decodeDenon(decode_results *results, uint16_t nbits = DENON_BITS,
bool strict = true);
#endif
#if DECODE_DISH
bool decodeDISH(decode_results *results, uint16_t nbits = DISH_BITS,
bool strict = true);
#endif
#if (DECODE_SHARP || DECODE_DENON)
bool decodeSharp(decode_results *results, uint16_t nbits = SHARP_BITS,
bool strict = true, bool expansion = true);
#endif
#if DECODE_AIWA_RC_T501
bool decodeAiwaRCT501(decode_results *results,
uint16_t nbits = AIWA_RC_T501_BITS, bool strict = true);
#endif
};
#endif // IRRECV_H_
+243
View File
@@ -0,0 +1,243 @@
/***************************************************
* IRremote for ESP8266
*
* Based on the IRremote library for Arduino by Ken Shirriff
* Version 0.11 August, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
* Edited by Mitra to add new controller SANYO
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*
* JVC and Panasonic protocol added by Kristian Lauszus (Thanks to zenwheel and other people at the original blog post)
* LG added by Darryl Smith (based on the JVC protocol)
* Whynter A/C ARC-110WD added by Francesco Meschia
* Coolix A/C / heatpump added by (send) bakrus & (decode) crankyoldgit
* Denon: sendDenon, decodeDenon added by Massimiliano Pinto
(from https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp)
* Kelvinator A/C and Sherwood added by crankyoldgit
* Mitsubishi (TV) sending added by crankyoldgit
* Pronto code sending added by crankyoldgit
* Mitsubishi A/C added by crankyoldgit
* (derived from https://github.com/r45635/HVAC-IR-Control)
* DISH decode by marcosamarinho
* Gree Heatpump sending added by Ville Skyttä (scop)
* (derived from https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp)
* Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for sending IR code on ESP8266
* Updated by Sebastien Warin (http://sebastien.warin.fr) for receiving IR code on ESP8266
*
* Updated by sillyfrog for Daikin, adopted from
* (https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/)
* Fujitsu A/C code added by jonnygraham
* Trotec AC code by stufisher
* GPL license, all text above must be included in any redistribution
****************************************************/
#ifndef IRREMOTEESP8266_H_
#define IRREMOTEESP8266_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#ifdef UNIT_TEST
#include <iostream>
#endif
// Library Version
#define _IRREMOTEESP8266_VERSION_ "2.2.0"
// Supported IR protocols
// Each protocol you include costs memory and, during decode, costs time
// Disable (set to false) all the protocols you do not need/want!
//
#define DECODE_NEC true
#define SEND_NEC true
#define DECODE_SHERWOOD true // Doesn't exist. Actually is DECODE_NEC
#define SEND_SHERWOOD true
#define DECODE_RC5 true
#define SEND_RC5 true
#define DECODE_RC6 true
#define SEND_RC6 true
#define DECODE_RCMM true
#define SEND_RCMM true
#define DECODE_SONY true
#define SEND_SONY true
#define DECODE_PANASONIC true
#define SEND_PANASONIC true
#define DECODE_JVC true
#define SEND_JVC true
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
#define DECODE_WHYNTER true
#define SEND_WHYNTER true
#define DECODE_AIWA_RC_T501 true
#define SEND_AIWA_RC_T501 true
#define DECODE_LG true
#define SEND_LG true
#define DECODE_SANYO true
#define SEND_SANYO true
#define DECODE_MITSUBISHI true
#define SEND_MITSUBISHI true
#define DECODE_DISH true
#define SEND_DISH true
#define DECODE_SHARP true
#define SEND_SHARP true
#define DECODE_DENON true
#define SEND_DENON true
#define DECODE_KELVINATOR false // Not written.
#define SEND_KELVINATOR true
#define DECODE_MITSUBISHI_AC false // Not written.
#define SEND_MITSUBISHI_AC true
#define DECODE_FUJITSU_AC false // Not written.
#define SEND_FUJITSU_AC true
#define DECODE_DAIKIN false // Not finished.
#define SEND_DAIKIN true
#define DECODE_COOLIX true
#define SEND_COOLIX true
#define DECODE_GLOBALCACHE false // Not written.
#define SEND_GLOBALCACHE true
#define DECODE_GREE false // Not written.
#define SEND_GREE true
#define DECODE_PRONTO false // Not written.
#define SEND_PRONTO true
#define DECODE_ARGO false // Not written.
#define SEND_ARGO true
#define DECODE_TROTEC false // Not implemented.
#define SEND_TROTEC true
/*
* Always add to the end of the list and should never remove entries
* or change order. Projects may save the type number for later usage
* so numbering should always stay the same.
*/
enum decode_type_t {
UNKNOWN = -1,
UNUSED = 0,
RC5,
RC6,
NEC,
SONY,
PANASONIC,
JVC,
SAMSUNG,
WHYNTER,
AIWA_RC_T501,
LG,
SANYO,
MITSUBISHI,
DISH,
SHARP,
COOLIX,
DAIKIN,
DENON,
KELVINATOR,
SHERWOOD,
MITSUBISHI_AC,
RCMM,
SANYO_LC7461,
RC5X,
GREE,
PRONTO,
NEC_LIKE,
ARGO,
TROTEC
};
// Message lengths & required repeat values
#define AIWA_RC_T501_BITS 15U
#define AIWA_RC_T501_MIN_REPEAT 1U
#define COOLIX_BITS 24U
#define DAIKIN_BITS 99U
#define DAIKIN_COMMAND_LENGTH 27U
#define DENON_BITS SHARP_BITS
#define DENON_48_BITS PANASONIC_BITS
#define DENON_LEGACY_BITS 14U
#define DISH_BITS 16U
#define DISH_MIN_REPEAT 3U
#define GREE_STATE_LENGTH 8U
#define GREE_BITS (GREE_STATE_LENGTH * 8)
#define JVC_BITS 16U
#define KELVINATOR_STATE_LENGTH 16U
#define LG_BITS 28U
#define LG32_BITS 32U
#define MITSUBISHI_BITS 16U
// TODO(anyone): Verify that the Mitsubishi repeat is really needed.
#define MITSUBISHI_MIN_REPEAT 1U // Based on marcosamarinho's code.
#define MITSUBISHI_AC_STATE_LENGTH 18U
#define MITSUBISHI_AC_MIN_REPEAT 1U
#define FUJITSU_AC_MIN_REPEAT 0U
#define NEC_BITS 32U
#define PANASONIC_BITS 48U
#define PANASONIC_MANUFACTURER 0x4004ULL
#define PRONTO_MIN_LENGTH 6U
#define RC5_RAW_BITS 14U
#define RC5_BITS RC5_RAW_BITS - 2U
#define RC5X_BITS RC5_RAW_BITS - 1U
#define RC6_MODE0_BITS 20U // Excludes the 'start' bit.
#define RC6_36_BITS 36U // Excludes the 'start' bit.
#define RCMM_BITS 24U
#define SAMSUNG_BITS 32U
#define SANYO_SA8650B_BITS 12U
#define SANYO_LC7461_ADDRESS_BITS 13U
#define SANYO_LC7461_COMMAND_BITS 8U
#define SANYO_LC7461_BITS ((SANYO_LC7461_ADDRESS_BITS + \
SANYO_LC7461_COMMAND_BITS) * 2)
#define SHARP_ADDRESS_BITS 5U
#define SHARP_COMMAND_BITS 8U
#define SHARP_BITS (SHARP_ADDRESS_BITS + SHARP_COMMAND_BITS + 2) // 15U
#define SHERWOOD_BITS NEC_BITS
#define SHERWOOD_MIN_REPEAT 1U
#define SONY_12_BITS 12U
#define SONY_15_BITS 15U
#define SONY_20_BITS 20U
#define SONY_MIN_BITS SONY_12_BITS
#define SONY_MIN_REPEAT 2U
#define TROTEC_COMMAND_LENGTH 9U
#define WHYNTER_BITS 32U
#define ARGO_COMMAND_LENGTH 12U
// Turn on Debugging information by uncommenting the following line.
// #define DEBUG 1
#ifdef DEBUG
#ifdef UNIT_TEST
#define DPRINT(x) do { std::cout << x; } while (0)
#define DPRINTLN(x) do { std::cout << x << std::endl; } while (0)
#endif // UNIT_TEST
#ifdef ARDUINO
#define DPRINT(x) do { Serial.print(x); } while (0)
#define DPRINTLN(x) do { Serial.println(x); } while (0)
#endif // ARDUINO
#else // DEBUG
#define DPRINT(x)
#define DPRINTLN(x)
#endif // DEBUG
#endif // IRREMOTEESP8266_H_
+327
View File
@@ -0,0 +1,327 @@
// Copyright 2009 Ken Shirriff
// Copyright 2015 Mark Szabo
// Copyright 2017 David Conran
#include "IRsend.h"
#ifndef UNIT_TEST
#include <Arduino.h>
#else
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#endif
#include <algorithm>
#ifdef UNIT_TEST
#include <cmath>
#endif
#include "IRtimer.h"
// Originally from https://github.com/shirriff/Arduino-IRremote/
// Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for
// sending IR code on ESP8266
// IRsend ----------------------------------------------------------------------
// Create an IRsend object.
//
// Args:
// IRsendPin: Which GPIO pin to use when sending an IR command.
// inverted: *DANGER* Optional flag to invert the output. (default = false)
// e.g. LED is illuminated when GPIO is LOW rather than HIGH.
// Setting this to something other than the default could
// easily destroy your IR LED if you are overdriving it.
// Unless you *REALLY* know what you are doing, don't change this.
// Returns:
// An IRsend object.
IRsend::IRsend(uint16_t IRsendPin, bool inverted) : IRpin(IRsendPin),
periodOffset(PERIOD_OFFSET) {
if (inverted) {
outputOn = LOW;
outputOff = HIGH;
} else {
outputOn = HIGH;
outputOff = LOW;
}
}
// Enable the pin for output.
void IRsend::begin() {
#ifndef UNIT_TEST
pinMode(IRpin, OUTPUT);
#endif
}
// Turn off the IR LED.
void IRsend::ledOff() {
#ifndef UNIT_TEST
digitalWrite(IRpin, outputOff);
#endif
}
// Calculate the period for a given frequency. (T = 1/f)
//
// Args:
// freq: Frequency in Hz.
// use_offset: Should we use the calculated offset or not?
// Returns:
// nr. of uSeconds.
uint32_t IRsend::calcUSecPeriod(uint32_t hz, bool use_offset) {
if (hz == 0) hz = 1; // Avoid Zero hz. Divide by Zero is nasty.
uint32_t period = (1000000UL + hz/2) / hz; // The equiv of round(1000000/hz).
// Apply the offset and ensure we don't result in a <= 0 value.
if (use_offset)
return std::max((uint32_t) 1, period + periodOffset);
else
return std::max((uint32_t) 1, period);
}
// Set the output frequency modulation and duty cycle.
//
// Args:
// freq: The freq we want to modulate at. Assumes < 1000 means kHz else Hz.
// duty: Percentage duty cycle of the LED. e.g. 25 = 25% = 1/4 on, 3/4 off.
//
// Note:
// Integer timing functions & math mean we can't do fractions of
// microseconds timing. Thus minor changes to the freq & duty values may have
// limited effect. You've been warned.
void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
// Can't have more than 100% duty cycle.
duty = std::min(duty, (uint8_t) 100);
if (freq < 1000) // Were we given kHz? Supports the old call usage.
freq *= 1000;
uint32_t period = calcUSecPeriod(freq);
// Nr. of uSeconds the LED will be on per pulse.
onTimePeriod = (period * duty) / 100;
// Nr. of uSeconds the LED will be off per pulse.
offTimePeriod = period - onTimePeriod;
}
// Modulate the IR LED for the given period (usec) and at the duty cycle set.
//
// Args:
// usec: The period of time to modulate the IR LED for, in microseconds.
// Returns:
// Nr. of pulses actually sent.
//
// Note:
// The ESP8266 has no good way to do hardware PWM, so we have to do it all
// in software. There is a horrible kludge/brilliant hack to use the second
// serial TX line to do fairly accurate hardware PWM, but it is only
// available on a single specific GPIO and only available on some modules.
// e.g. It's not available on the ESP-01 module.
// Hence, for greater compatibility & choice, we don't use that method.
// Ref:
// https://www.analysir.com/blog/2017/01/29/updated-esp8266-nodemcu-backdoor-upwm-hack-for-ir-signals/
uint16_t IRsend::mark(uint16_t usec) {
uint16_t counter = 0;
IRtimer usecTimer = IRtimer();
// Cache the time taken so far. This saves us calling time, and we can be
// assured that we can't have odd math problems. i.e. unsigned under/overflow.
uint32_t elapsed = usecTimer.elapsed();
while (elapsed < usec) { // Loop until we've met/exceeded our required time.
#ifndef UNIT_TEST
digitalWrite(IRpin, outputOn); // Turn the LED on.
// Calculate how long we should pulse on for.
// e.g. Are we to close to the end of our requested mark time (usec)?
delayMicroseconds(std::min((uint32_t) onTimePeriod, usec - elapsed));
digitalWrite(IRpin, outputOff); // Turn the LED off.
#endif
counter++;
if (elapsed + onTimePeriod >= usec)
return counter; // LED is now off & we've passed our allotted time.
// Wait for the lesser of the rest of the duty cycle, or the time remaining.
#ifndef UNIT_TEST
delayMicroseconds(std::min(usec - elapsed - onTimePeriod,
(uint32_t) offTimePeriod));
#endif
elapsed = usecTimer.elapsed(); // Update & recache the actual elapsed time.
}
return counter;
}
// Turn the pin (LED) off for a given time.
// Sends an IR space for the specified number of microseconds.
// A space is no output, so the PWM output is disabled.
//
// Args:
// time: Time in microseconds (us).
void IRsend::space(uint32_t time) {
ledOff();
if (time == 0) return;
#ifndef UNIT_TEST
// delayMicroseconds is only accurate to 16383us.
// Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
if (time <= 16383) {
delayMicroseconds(time);
} else {
// Invoke a delay(), where possible, to avoid triggering the WDT.
delay(time / 1000UL); // Delay for as many whole milliseconds as we can.
// Delay the remaining sub-millisecond.
delayMicroseconds(static_cast<uint16_t>(time % 1000UL));
}
#endif
}
// Calculate & set any offsets to account for execution times.
//
// Args:
// hz: The frequency to calibrate at >= 1000Hz. Default is 38000Hz.
//
// Status: ALPHA / Untested.
//
// NOTE:
// This will generate an 65535us mark() IR LED signal.
// This only needs to be called once, if at all.
void IRsend::calibrate(uint16_t hz) {
if (hz < 1000) // Were we given kHz? Supports the old call usage.
hz *= 1000;
periodOffset = 0; // Turn off any existing offset while we calibrate.
enableIROut(hz);
IRtimer usecTimer = IRtimer(); // Start a timer *just* before we do the call.
uint16_t pulses = mark(UINT16_MAX); // Generate a PWM of 65,535 us. (Max.)
uint32_t timeTaken = usecTimer.elapsed(); // Record the time it took.
// While it shouldn't be necessary, assume at least 1 pulse, to avoid a
// divide by 0 situation.
pulses = std::max(pulses, (uint16_t) 1U);
uint32_t calcPeriod = calcUSecPeriod(hz); // e.g. @38kHz it should be 26us.
// Assuming 38kHz for the example calculations:
// In a 65535us pulse, we should have 2520.5769 pulses @ 26us periods.
// e.g. 65535.0us / 26us = 2520.5769
// This should have caused approx 2520 loops through the main loop in mark().
// The average over that many interations should give us a reasonable
// approximation at what offset we need to use to account for instruction
// execution times.
//
// Calculate the actual period from the actual time & the actual pulses
// generated.
double_t actualPeriod = (double_t) timeTaken / (double_t) pulses;
// Store the difference between the actual time per period vs. calculated.
periodOffset = (int8_t) ((double_t) calcPeriod - actualPeriod);
}
// Generic method for sending data that is common to most protocols.
// Will send leading or trailing 0's if the nbits is larger than the number
// of bits in data.
//
// Args:
// onemark: Nr. of usecs for the led to be pulsed for a '1' bit.
// onespace: Nr. of usecs for the led to be fully off for a '1' bit.
// zeromark: Nr. of usecs for the led to be pulsed for a '0' bit.
// zerospace: Nr. of usecs for the led to be fully off for a '0' bit.
// data: The data to be transmitted.
// nbits: Nr. of bits of data to be sent.
// MSBfirst: Flag for bit transmission order. Defaults to MSB->LSB order.
void IRsend::sendData(uint16_t onemark, uint32_t onespace,
uint16_t zeromark, uint32_t zerospace,
uint64_t data, uint16_t nbits, bool MSBfirst) {
if (nbits == 0) // If we are asked to send nothing, just return.
return;
if (MSBfirst) { // Send the MSB first.
// Send 0's until we get down to a bit size we can actually manage.
while (nbits > sizeof(data) * 8) {
mark(zeromark);
space(zerospace);
nbits--;
}
// Send the supplied data.
for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1)
if (data & mask) { // Send a 1
mark(onemark);
space(onespace);
} else { // Send a 0
mark(zeromark);
space(zerospace);
}
} else { // Send the Least Significant Bit (LSB) first / MSB last.
for (uint16_t bit = 0; bit < nbits; bit++, data >>= 1)
if (data & 1) { // Send a 1
mark(onemark);
space(onespace);
} else { // Send a 0
mark(zeromark);
space(zerospace);
}
}
}
// Send a raw IRremote message.
//
// Args:
// buf: An array of uint16_t's that has microseconds elements.
// len: Nr. of elements in the buf[] array.
// hz: Frequency to send the message at. (kHz < 1000; Hz >= 1000)
//
// Status: STABLE / Known working.
//
// Notes:
// Even elements are Mark times (On), Odd elements are Space times (Off).
//
// Ref:
// examples/IRrecvDumpV2/IRrecvDumpV2.ino
void IRsend::sendRaw(uint16_t buf[], uint16_t len, uint16_t hz) {
// Set IR carrier frequency
enableIROut(hz);
for (uint16_t i = 0; i < len; i++) {
if (i & 1) { // Odd bit.
space(buf[i]);
} else { // Even bit.
mark(buf[i]);
}
}
ledOff(); // We potentially have ended with a mark(), so turn of the LED.
}
#ifndef UNIT_TEST
void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
switch (type) {
#if SEND_NEC
case NEC: sendNEC(data, nbits); break;
#endif
#if SEND_SONY
case SONY: sendSony(data, nbits); break;
#endif
#if SEND_RC5
case RC5: sendRC5(data, nbits); break;
#endif
#if SEND_RC6
case RC6: sendRC6(data, nbits); break;
#endif
#if SEND_DISH
case DISH: sendDISH(data, nbits); break;
#endif
#if SEND_JVC
case JVC: sendJVC(data, nbits); break;
#endif
#if SEND_SAMSUNG
case SAMSUNG: sendSAMSUNG(data, nbits); break;
#endif
#if SEND_LG
case LG: sendLG(data, nbits); break;
#endif
#if SEND_WHYNTER
case WHYNTER: sendWhynter(data, nbits); break;
#endif
#if SEND_COOLIX
case COOLIX: sendCOOLIX(data, nbits); break;
#endif
#if SEND_DENON
case DENON: sendDenon(data, nbits); break;
#endif
#if SEND_SHERWOOD
case SHERWOOD: sendSherwood(data, nbits); break;
#endif
#if SEND_RCMM
case RCMM: sendRCMM(data, nbits); break;
#endif
#if SEND_MITSUBISHI
case MITSUBISHI: sendMitsubishi(data, nbits); break;
#endif
#if SEND_SHARP
case SHARP: sendSharpRaw(data, nbits); break;
#endif
#if SEND_AIWA_RC_T501
case AIWA_RC_T501: sendAiwaRCT501(data, nbits); break;
#endif
}
}
#endif
+206
View File
@@ -0,0 +1,206 @@
// Copyright 2009 Ken Shirriff
// Copyright 2015 Mark Szabo
// Copyright 2017 David Conran
#ifndef IRSEND_H_
#define IRSEND_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include "IRremoteESP8266.h"
// Originally from https://github.com/shirriff/Arduino-IRremote/
// Updated by markszabo (https://github.com/markszabo/IRremoteESP8266) for
// sending IR code on ESP8266
#if TEST || UNIT_TEST
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif
// Constants
// Offset (in microseconds) to use in Period time calculations to account for
// code excution time in producing the software PWM signal.
// Value determined in https://github.com/markszabo/IRremoteESP8266/issues/62
#define PERIOD_OFFSET -3
#define DUTY_DEFAULT 50
// Classes
class IRsend {
public:
explicit IRsend(uint16_t IRsendPin, bool inverted = false);
void begin();
void enableIROut(uint32_t freq, uint8_t duty = DUTY_DEFAULT);
VIRTUAL uint16_t mark(uint16_t usec);
VIRTUAL void space(uint32_t usec);
void calibrate(uint16_t hz = 38000U);
void sendRaw(uint16_t buf[], uint16_t len, uint16_t hz);
void sendData(uint16_t onemark, uint32_t onespace, uint16_t zeromark,
uint32_t zerospace, uint64_t data, uint16_t nbits,
bool MSBfirst = true);
void send(uint16_t type, uint64_t data, uint16_t nbits);
#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO)
void sendNEC(uint64_t data, uint16_t nbits = NEC_BITS, uint16_t repeat = 0);
uint32_t encodeNEC(uint16_t address, uint16_t command);
#endif
#if SEND_SONY
// sendSony() should typically be called with repeat=2 as Sony devices
// expect the code to be sent at least 3 times. (code + 2 repeats = 3 codes)
// Legacy use of this procedure was to only send a single code so call it with
// repeat=0 for backward compatibility. As of v2.0 it defaults to sending
// a Sony command that will be accepted be a device.
void sendSony(uint64_t data, uint16_t nbits = SONY_20_BITS,
uint16_t repeat = SONY_MIN_REPEAT);
uint32_t encodeSony(uint16_t nbits, uint16_t command, uint16_t address,
uint16_t extended = 0);
#endif
#if SEND_SHERWOOD
void sendSherwood(uint64_t data, uint16_t nbits = SHERWOOD_BITS,
uint16_t repeat = SHERWOOD_MIN_REPEAT);
#endif
#if SEND_SAMSUNG
void sendSAMSUNG(uint64_t data, uint16_t nbits = SAMSUNG_BITS,
uint16_t repeat = 0);
uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command);
#endif
#if SEND_LG
void sendLG(uint64_t data, uint16_t nbits = LG_BITS, uint16_t repeat = 0);
uint32_t encodeLG(uint16_t address, uint16_t command);
#endif
#if (SEND_SHARP || SEND_DENON)
uint32_t encodeSharp(uint16_t address, uint16_t command,
uint16_t expansion = 1, uint16_t check = 0,
bool MSBfirst = false);
void sendSharp(uint16_t address, uint16_t command,
uint16_t nbits = SHARP_BITS, uint16_t repeat = 0);
void sendSharpRaw(uint64_t data, uint16_t nbits = SHARP_BITS,
uint16_t repeat = 0);
#endif
#if SEND_JVC
void sendJVC(uint64_t data, uint16_t nbits = JVC_BITS, uint16_t repeat = 0);
uint16_t encodeJVC(uint8_t address, uint8_t command);
#endif
#if SEND_DENON
void sendDenon(uint64_t data, uint16_t nbits = DENON_BITS,
uint16_t repeat = 0);
#endif
#if SEND_SANYO
uint64_t encodeSanyoLC7461(uint16_t address, uint8_t command);
void sendSanyoLC7461(uint64_t data, uint16_t nbits = SANYO_LC7461_BITS,
uint16_t repeat = 0);
#endif
#if SEND_DISH
// sendDISH() should typically be called with repeat=3 as DISH devices
// expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes)
// Legacy use of this procedure was only to send a single code
// so use repeat=0 for backward compatibility.
void sendDISH(uint64_t data, uint16_t nbits = DISH_BITS,
uint16_t repeat = DISH_MIN_REPEAT);
#endif
#if (SEND_PANASONIC || SEND_DENON)
void sendPanasonic64(uint64_t data, uint16_t nbits = PANASONIC_BITS,
uint16_t repeat = 0);
void sendPanasonic(uint16_t address, uint32_t data,
uint16_t nbits = PANASONIC_BITS, uint16_t repeat = 0);
uint64_t encodePanasonic(uint16_t manufacturer, uint8_t device,
uint8_t subdevice, uint8_t function);
#endif
#if SEND_RC5
void sendRC5(uint64_t data, uint16_t nbits = RC5X_BITS, uint16_t repeat = 0);
uint16_t encodeRC5(uint8_t address, uint8_t command,
bool key_released = false);
uint16_t encodeRC5X(uint8_t address, uint8_t command,
bool key_released = false);
uint64_t toggleRC5(uint64_t data);
#endif
#if SEND_RC6
void sendRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS,
uint16_t repeat = 0);
uint64_t encodeRC6(uint32_t address, uint8_t command,
uint16_t mode = RC6_MODE0_BITS);
uint64_t toggleRC6(uint64_t data, uint16_t nbits = RC6_MODE0_BITS);
#endif
#if SEND_RCMM
void sendRCMM(uint64_t data, uint16_t nbits = RCMM_BITS, uint16_t repeat = 0);
#endif
#if SEND_COOLIX
void sendCOOLIX(uint64_t data, uint16_t nbits = COOLIX_BITS,
uint16_t repeat = 0);
#endif
#if SEND_WHYNTER
void sendWhynter(uint64_t data, uint16_t nbits = WHYNTER_BITS,
uint16_t repeat = 0);
#endif
#if SEND_MITSUBISHI
void sendMitsubishi(uint64_t data, uint16_t nbits = MITSUBISHI_BITS,
uint16_t repeat = MITSUBISHI_MIN_REPEAT);
#endif
#if SEND_MITSUBISHI_AC
void sendMitsubishiAC(unsigned char data[],
uint16_t nbytes = MITSUBISHI_AC_STATE_LENGTH,
uint16_t repeat = MITSUBISHI_AC_MIN_REPEAT);
#endif
#if SEND_FUJITSU_AC
void sendFujitsuAC(unsigned char data[],
uint16_t nbytes,
uint16_t repeat = FUJITSU_AC_MIN_REPEAT);
#endif
#if SEND_GLOBALCACHE
void sendGC(uint16_t buf[], uint16_t len);
#endif
#if SEND_KELVINATOR
void sendKelvinator(unsigned char data[],
uint16_t nbytes = KELVINATOR_STATE_LENGTH,
uint16_t repeat = 0);
#endif
#if SEND_DAIKIN
void sendDaikin(unsigned char data[],
uint16_t nbytes = DAIKIN_COMMAND_LENGTH,
uint16_t repeat = 0);
#endif
#if SEND_AIWA_RC_T501
void sendAiwaRCT501(uint64_t data, uint16_t nbits = AIWA_RC_T501_BITS,
uint16_t repeat = AIWA_RC_T501_MIN_REPEAT);
#endif
#if SEND_GREE
void sendGree(uint64_t data, uint16_t nbits = GREE_BITS, uint16_t repeat = 0);
void sendGree(uint8_t data[], uint16_t nbytes = GREE_STATE_LENGTH,
uint16_t repeat = 0);
#endif
#if SEND_PRONTO
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = 0);
#endif
#if SEND_ARGO
void sendArgo(unsigned char data[],
uint16_t nbytes = ARGO_COMMAND_LENGTH,
uint16_t repeat = 0);
#endif
#if SEND_TROTEC
void sendTrotec(unsigned char data[],
uint16_t nbytes = TROTEC_COMMAND_LENGTH,
uint16_t repeat = 0);
#endif
protected:
#ifdef UNIT_TEST
#ifndef HIGH
#define HIGH 0x1
#endif
#ifndef LOW
#define LOW 0x0
#endif
#endif // UNIT_TEST
uint8_t outputOn;
uint8_t outputOff;
private:
uint16_t onTimePeriod;
uint16_t offTimePeriod;
uint16_t IRpin;
int8_t periodOffset;
void ledOff();
uint32_t calcUSecPeriod(uint32_t hz, bool use_offset = true);
};
#endif // IRSEND_H_
+33
View File
@@ -0,0 +1,33 @@
// Copyright 2017 David Conran
#include "IRtimer.h"
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
// This class performs a simple time in useconds since instantiated.
// Handles when the system timer wraps around (once).
IRtimer::IRtimer() {
reset();
}
void IRtimer::reset() {
#ifndef UNIT_TEST
start = micros();
#else
start = 0;
#endif
}
uint32_t IRtimer::elapsed() {
#ifndef UNIT_TEST
uint32_t now = micros();
#else
uint32_t now = 0;
#endif
if (start <= now) // Check if the system timer has wrapped.
return now - start; // No wrap.
else
return UINT32_MAX - start + now; // Has wrapped.
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2017 David Conran
#ifndef IRTIMER_H_
#define IRTIMER_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
// Classes
class IRtimer {
public:
IRtimer();
void reset();
uint32_t elapsed();
private:
uint32_t start;
};
#endif // IRTIMER_H_
+59
View File
@@ -0,0 +1,59 @@
// Copyright 2017 David Conran
#include "IRutils.h"
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <algorithm>
#include "IRrecv.h"
// Reverse the order of the requested least significant nr. of bits.
// Args:
// input: Bit pattern/integer to reverse.
// nbits: Nr. of bits to reverse.
// Returns:
// The reversed bit pattern.
uint64_t reverseBits(uint64_t input, uint16_t nbits) {
if (nbits <= 1)
return input; // Reversing <= 1 bits makes no change at all.
// Cap the nr. of bits to rotate to the max nr. of bits in the input.
nbits = std::min(nbits, (uint16_t) (sizeof(input) * 8));
uint64_t output = 0;
for (uint16_t i = 0; i < nbits; i++) {
output <<= 1;
output |= (input & 1);
input >>= 1;
}
// Merge any remaining unreversed bits back to the top of the reversed bits.
return (input << nbits) | output;
}
// Print a uint64_t/unsigned long long to the Serial port
// Serial.print() can't handle printing long longs. (uint64_t)
//
// Args:
// input: The value to print
// base: The output base.
// Note: Based on Arduino's Print::printNumber()
void serialPrintUint64(uint64_t input, uint8_t base) {
char buf[8 * sizeof(input) + 1]; // Assumes 8-bit chars plus zero byte.
char *str = &buf[sizeof(buf) - 1];
*str = '\0';
// prevent crash if called with base == 1
if (base < 2) base = 10;
do {
char c = input % base;
input /= base;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while (input);
#ifndef UNIT_TEST
Serial.print(str);
#endif
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef IRUTILS_H_
#define IRUTILS_H_
// Copyright 2017 David Conran
#define __STDC_LIMIT_MACROS
#include <stdint.h>
uint64_t reverseBits(uint64_t input, uint16_t nbits);
void serialPrintUint64(uint64_t input, uint8_t base);
#endif // IRUTILS_H_
+118
View File
@@ -0,0 +1,118 @@
// Copyright 2017 David Conran
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
// AAA IIIII W W AAA
// A A I W W A A
// AAAAA I W W W AAAAA
// A A I W W W A A
// A A IIIII WWW A A
// Based off the RC-T501 RCU
// Added by David Conran. (Inspired by IRremoteESP8266's implementation:
// https://github.com/z3t0/Arduino-IRremote)
#define AIWA_RC_T501_PRE_BITS 26U
#define AIWA_RC_T501_POST_BITS 1U
// NOTE: These are the compliment (inverted) of lirc values as
// lirc uses a '0' for a mark, and a '1' for a space.
#define AIWA_RC_T501_PRE_DATA 0x1D8113FULL // 26-bits
#define AIWA_RC_T501_POST_DATA 1ULL
#if SEND_AIWA_RC_T501
// Send a Aiwa RC T501 formatted message.
//
// Args:
// data: The message to be sent.
// nbits: The number of bits of the message to be sent.
// Typically AIWA_RC_T501_BITS. Max is 37 = (64 - 27)
// repeat: The number of times the command is to be repeated.
//
// Status: BETA / Should work.
//
// Ref:
// http://lirc.sourceforge.net/remotes/aiwa/RC-T501
void IRsend::sendAiwaRCT501(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Appears to be an extended NEC1 protocol. i.e. 42 bits instead of 32 bits.
// So use sendNEC instead, however the twist is it has a fixed 26 bit
// prefix, and a fixed postfix bit.
uint64_t new_data = (
(AIWA_RC_T501_PRE_DATA << (nbits + AIWA_RC_T501_POST_BITS)) |
(data << AIWA_RC_T501_POST_BITS) | AIWA_RC_T501_POST_DATA);
nbits += AIWA_RC_T501_PRE_BITS + AIWA_RC_T501_POST_BITS;
if (nbits > sizeof(new_data) * 8)
return; // We are overflowing. Abort, and don't send.
sendNEC(new_data, nbits, repeat);
}
#endif
#if DECODE_AIWA_RC_T501
// Decode the supplied Aiwa RC T501 message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: The number of data bits to expect. Typically AIWA_RC_T501_BITS.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should work.
//
// Notes:
// Aiwa RC T501 appears to be a 42 bit variant of the NEC1 protocol.
// However, we historically (original Arduino IRremote project) treats it as
// a 15 bit (data) protocol. So, we expect nbits to typically be 15, and we
// will remove the prefix and postfix from the raw data, and use that as
// the result.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/nec.php
bool IRrecv::decodeAiwaRCT501(decode_results *results, uint16_t nbits,
bool strict) {
// Compliance
if (strict && nbits != AIWA_RC_T501_BITS)
return false; // Doesn't match our protocol defn.
// Add on the pre & post bits to our requested bit length.
uint16_t expected_nbits = nbits + AIWA_RC_T501_PRE_BITS +
AIWA_RC_T501_POST_BITS;
uint64_t new_data;
if (expected_nbits > sizeof(new_data) * 8)
return false; // We can't possibly match something that big.
// Decode it as a much bigger (non-standard) NEC message, so we have to turn
// off strict mode checking for NEC.
if (!decodeNEC(results, expected_nbits, false))
return false; // The NEC decode had a problem, so we should too.
uint16_t actual_bits = results->bits;
new_data = results->value;
if (actual_bits < expected_nbits)
return false; // The data we caught was undersized. Throw it back.
if ((new_data & 0x1ULL) != AIWA_RC_T501_POST_DATA)
return false; // The post data doesn't match, so it can't be this protocol.
// Trim off the post data bit.
new_data >>= AIWA_RC_T501_POST_BITS;
actual_bits -= AIWA_RC_T501_POST_BITS;
// Extract out our likely new value and put it back in the results.
actual_bits -= AIWA_RC_T501_PRE_BITS;
results->value = new_data & ((1ULL << actual_bits) - 1);
// Check the prefix data matches.
new_data >>= actual_bits; // Trim off the new data to expose the prefix.
if (new_data != AIWA_RC_T501_PRE_DATA) // Check the prefix.
return false;
// Compliance
if (strict && results->bits != expected_nbits)
return false;
// Success
results->decode_type = AIWA_RC_T501;
results->bits = actual_bits;
results->address = 0;
results->command = 0;
return true;
}
#endif
+264
View File
@@ -0,0 +1,264 @@
/*
Node MCU/ESP8266 Sketch to emulate Argo Ulisse 13 DCI remote
Controls Argo Ulisse 13 DCI A/C
Copyright 2017 Schmolders
*/
#include "ir_Argo.h"
#include <algorithm>
#include "IRremoteESP8266.h"
#include "IRutils.h"
// Constants
// using SPACE modulation. MARK is always const 400u
#define ARGO_PREAMBLE_1 6400U // Mark
#define ARGO_PREAMBLE_2 3300U // Space
#define ARGO_MARK 400U
#define ARGO_ONE_SPACE 2200U
#define ARGO_ZERO_SPACE 900U
#if SEND_ARGO
// Send a Argo A/C message.
//
// Args:
// data: An array of ARGO_COMMAND_LENGTH bytes containing the IR command.
//
// Status: ALPHA / Untested.
//
// Overloading the IRSend Function
void IRsend::sendArgo(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
// Check if we have enough bytes to send a proper message.
if (nbytes < ARGO_COMMAND_LENGTH) return;
// Set IR carrier frequency
enableIROut(38);
for (uint16_t r = 0; r <= repeat; r++) {
// Header
// TODO(kaschmo): validate
mark(ARGO_PREAMBLE_1);
space(ARGO_PREAMBLE_2);
// send data, defined in IRSend.cpp
for (uint16_t i = 0; i < nbytes; i++)
sendData(ARGO_MARK, ARGO_ONE_SPACE, ARGO_MARK,
ARGO_ZERO_SPACE, data[i], 8, false);
// send LSB first reverses the bit order in array for sending.
}
}
IRArgoAC::IRArgoAC(uint16_t pin) : _irsend(pin) {
stateReset();
}
void IRArgoAC::begin() {
_irsend.begin();
}
void IRArgoAC::send() {
// Serial.println("Sending IR code"); // Only for Debug
checksum(); // Create valid checksum before sending
_irsend.sendArgo(argo);
}
void IRArgoAC::checksum() {
uint8_t sum = 2; // Corresponds to byte 11 being constant 0b01
uint8_t i;
// Only add up bytes to 9. byte 10 is 0b01 constant anyway.
// Assume that argo array is MSB first (left)
for (i = 0; i < 10; i++)
sum += argo[i];
sum = sum % 256; // modulo 256
// Append sum to end of array
// Set const part of checksum bit 10
argo[10] = 0b00000010;
argo[10] += sum << 2; // Shift up 2 bits and append to byte 10
argo[11] = sum >> 6; // Shift down 6 bits and add in two LSBs of bit 11
}
void IRArgoAC::stateReset() {
for (uint8_t i = 0; i < ARGO_COMMAND_LENGTH; i++)
argo[i] = 0x0;
// Argo Message. Store MSB left.
// Default message:
argo[0] = 0b10101100; // LSB first (as sent) 0b00110101; //const preamble
argo[1] = 0b11110101; // LSB first: 0b10101111; //const preamble
// Keep payload 2-9 at zero
argo[10] = 0b00000010; // Const 01, checksum 6bit
argo[11] = 0b00000000; // Checksum 2bit
this->off();
this->setTemp(20);
this->setRoomTemp(25);
this->setCoolMode(ARGO_COOL_AUTO);
this->setFan(ARGO_FAN_AUTO);
}
uint8_t* IRArgoAC::getRaw() {
checksum(); // Ensure correct bit array before returning
return argo;
}
void IRArgoAC::on() {
// state = ON;
ac_state = 1;
// Bit 5 of byte 9 is on/off
// in MSB first
argo[9] = argo[9] | 0b00100000; // Set ON/OFF bit to 1
}
void IRArgoAC::off() {
// state = OFF;
ac_state = 0;
// in MSB first
// bit 5 of byte 9 to off
argo[9] = argo[9] & 0b11011111; // Set on/off bit to 0
}
void IRArgoAC::setPower(bool state) {
if (state)
on();
else
off();
}
uint8_t IRArgoAC::getPower() {
return ac_state;
}
void IRArgoAC::setMax(bool state) {
max_mode = state;
if (max_mode)
argo[9] |= 0b00001000;
else
argo[9] &= 0b11110111;
}
bool IRArgoAC::getMax() {
return max_mode;
}
// Set the temp in deg C
// Sending 0 equals +4
void IRArgoAC::setTemp(uint8_t temp) {
if (temp < ARGO_MIN_TEMP)
temp = ARGO_MIN_TEMP;
else if (temp > ARGO_MAX_TEMP)
temp = ARGO_MAX_TEMP;
// Store in attributes
set_temp = temp;
// offset 4 degrees. "If I want 12 degrees, I need to send 8"
temp -= 4;
// Settemp = Bit 6,7 of byte 2, and bit 0-2 of byte 3
// mask out bits
// argo[13] & 0x00000100; // mask out ON/OFF Bit
argo[2] &= 0b00111111;
argo[3] &= 0b11111000;
argo[2] += temp << 6; // append to bit 6,7
argo[3] += temp >> 2; // remove lowest to bits and append in 0-2
}
uint8_t IRArgoAC::getTemp() {
return set_temp;
}
// Set the speed of the fan
void IRArgoAC::setFan(uint8_t fan) {
// Set the fan speed bits, leave low 4 bits alone
fan_mode = fan;
// Mask out bits
argo[3] &= 0b11100111;
// Set fan mode at bit positions
argo[3] += fan << 3;
}
uint8_t IRArgoAC::getFan() {
return fan_mode;
}
void IRArgoAC::setFlap(uint8_t flap) {
flap_mode = flap;
// TODO(kaschmo): set correct bits for flap mode
}
uint8_t IRArgoAC::getFlap() {
return flap_mode;
}
uint8_t IRArgoAC::getMode() {
// return cooling 0, heating 1
return ac_mode;
}
void IRArgoAC::setCoolMode(uint8_t mode) {
ac_mode = 0; // Set ac mode to cooling
cool_mode = mode;
// Mask out bits, also leave bit 5 on 0 for cooling
argo[2] &= 0b11000111;
// Set cool mode at bit positions
argo[2] += mode << 3;
}
uint8_t IRArgoAC::getCoolMode() {
return cool_mode;
}
void IRArgoAC::setHeatMode(uint8_t mode) {
ac_mode = 1; // Set ac mode to heating
heat_mode = mode;
// Mask out bits
argo[2] &= 0b11000111;
// Set heating bit
argo[2] |= 0b00100000;
// Set cool mode at bit positions
argo[2] += mode << 3;
}
uint8_t IRArgoAC::getHeatMode() {
return heat_mode;
}
void IRArgoAC::setNight(bool state) {
night_mode = state;
if (night_mode)
// Set bit at night position: bit 2
argo[9] |= 0b00000100;
else
argo[9] &= 0b11111011;
}
bool IRArgoAC::getNight() {
return night_mode;
}
void IRArgoAC::setiFeel(bool state) {
ifeel_mode = state;
if (ifeel_mode)
// Set bit at iFeel position: bit 7
argo[9] |= 0b10000000;
else
argo[9] &= 0b01111111;
}
bool IRArgoAC::getiFeel() {
return ifeel_mode;
}
void IRArgoAC::setTime() {
// TODO(kaschmo): use function call from checksum to set time first
}
void IRArgoAC::setRoomTemp(uint8_t temp) {
temp -= 4;
// Mask out bits
argo[3] &= 0b00011111;
argo[4] &= 0b11111100;
argo[3] += temp << 5; // Append to bit 5,6,7
argo[4] += temp >> 3; // Remove lowest 3 bits and append in 0,1
}
#endif // SEND_ARGO
+124
View File
@@ -0,0 +1,124 @@
/* Copyright 2017 Schmolders
// Adds support for Argo Ulisse 13 DCI Mobile Split ACs.
*/
#ifndef IR_ARGO_H_
#define IR_ARGO_H_
#include "IRremoteESP8266.h"
#include "IRsend.h"
// ARGO Ulisse DCI
/*
Protocol Description:
All in LSB first as it is sent. argo message array will be stored MSB first!
do LSB-MSB conversion in sendData
Byte 0: const 0 0 1 1 0 1 0 1
Byte 1: const 1 0 1 0 1 1 1 1
Byte 2: 0 0 0, 3bit Cool/Heat Mode, 2bit start SetTemp LSB first
Byte 3: 3bit End SetTemp, 2bit Fan Mode, 3bit RoomTemp LSB first
Byte 4: 2bit RoomTemp, 3bit Flap Mode, 3bit OnTimer
Byte 5: 8bit OnTimer
Byte 6: 8Bit OffTimer
Byte 7: 3bit OffTimer, 5bit Time
Byte 8: 6bit Time, 1bit Timer On/Off, 1bit Timer Program
Byte 9: 1bit Timer Program, 1bit Timer 1h, 1 bit Night Mode, 1bit Max Mode, 1bit Filter, 1bit on/off, 1bit const 0, 1bit iFeel
Byte 10: 2bit const 0 1, 6bit Checksum
Byte 11: 2bit Checksum
*/
// Constants. Store MSB left.
#define ARGO_COOL_ON 0U // 0b000
#define ARGO_COOL_OFF 3U // 0b110
#define ARGO_COOL_AUTO 2U // 0b010
#define ARGO_COOl_HUM 1U // 0b100
#define ARGO_HEAT_ON 0U // 0b001
#define ARGO_HEAT_AUTO 1U // 0b101
#define ARGO_HEAT_BLINK 2U // 0b011 // ??no idea what mode that is
#define ARGO_MIN_TEMP 10U // Celsius offset +4
#define ARGO_MAX_TEMP 32U // Celsius
#define ARGO_FAN_AUTO 0U // 0b00
#define ARGO_FAN_3 3U // 0b11
#define ARGO_FAN_2 2U // 0b01
#define ARGO_FAN_1 1U // 0b10
#define ARGO_FLAP_AUTO 0U // 0b000
#define ARGO_FLAP_1 1U // 0b100
#define ARGO_FLAP_2 2U // 0b010
#define ARGO_FLAP_3 3U // 0b110
#define ARGO_FLAP_4 4U // 0b001
#define ARGO_FLAP_5 5U // 0b101
#define ARGO_FLAP_6 6U // 0b011
#define ARGO_FLAP_FULL 7U // 0b111
#if SEND_ARGO
class IRArgoAC {
public:
explicit IRArgoAC(uint16_t pin);
void send();
void begin();
void on();
void off();
void setPower(bool state);
uint8_t getPower();
void setTemp(uint8_t temp);
uint8_t getTemp();
void setFan(uint8_t fan);
uint8_t getFan();
void setFlap(uint8_t flap);
uint8_t getFlap();
void setCoolMode(uint8_t mode);
uint8_t getCoolMode();
void setHeatMode(uint8_t mode);
uint8_t getHeatMode();
uint8_t getMode();
void setMax(bool state);
bool getMax();
void setNight(bool state);
bool getNight();
void setiFeel(bool state);
bool getiFeel();
void setTime();
void setRoomTemp(uint8_t temp);
uint8_t* getRaw();
private:
// # of bytes per command
uint8_t argo[ARGO_COMMAND_LENGTH]; // Defined in IRremoteESP8266.h
void stateReset();
void checksum();
IRsend _irsend; // instance of the IR send class
// Attributes
uint8_t set_temp;
uint8_t fan_mode;
uint8_t flap_mode;
uint8_t ac_state;
uint8_t ac_mode; // heat 1, cool 0
uint8_t heat_mode;
uint8_t cool_mode;
uint8_t night_mode; // on/off
uint8_t max_mode; // on/off
uint8_t ifeel_mode; // on/off
};
#endif // SEND_ARGO
#endif // IR_ARGO_H_
+167
View File
@@ -0,0 +1,167 @@
// Copyright bakrus
// Copyright 2017 David Conran
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// CCCCC OOOOO OOOOO LL IIIII XX XX
// CC C OO OO OO OO LL III XX XX
// CC OO OO OO OO LL III XXXX
// CC C OO OO OO OO LL III XX XX
// CCCCC OOOO0 OOOO0 LLLLLLL IIIII XX XX
// Coolix A/C / heatpump added by (send) bakrus & (decode) crankyoldgit
// Constants
// Pulse parms are *50-100 for the Mark and *50+100 for the space
// First MARK is the one after the long gap
// pulse parameters in usec
#define COOLIX_TICK 560U // Approximately 21 cycles at 38kHz
#define COOLIX_BIT_MARK_TICKS 1U
#define COOLIX_BIT_MARK (COOLIX_BIT_MARK_TICKS * COOLIX_TICK)
#define COOLIX_ONE_SPACE_TICKS 3U
#define COOLIX_ONE_SPACE (COOLIX_ONE_SPACE_TICKS * COOLIX_TICK)
#define COOLIX_ZERO_SPACE_TICKS 1U
#define COOLIX_ZERO_SPACE (COOLIX_ZERO_SPACE_TICKS * COOLIX_TICK)
#define COOLIX_HDR_MARK_TICKS 8U
#define COOLIX_HDR_MARK (COOLIX_HDR_MARK_TICKS * COOLIX_TICK)
#define COOLIX_HDR_SPACE_TICKS 8U
#define COOLIX_HDR_SPACE (COOLIX_HDR_SPACE_TICKS * COOLIX_TICK)
#define COOLIX_MIN_GAP_TICKS (COOLIX_HDR_MARK_TICKS + \
COOLIX_ZERO_SPACE_TICKS)
#define COOLIX_MIN_GAP (COOLIX_MIN_GAP_TICKS * COOLIX_TICK)
#if SEND_COOLIX
// Send a Coolix message
//
// Args:
// data: Contents of the message to be sent.
// nbits: Nr. of bits of data to be sent. Typically COOLIX_BITS.
// repeat: Nr. of additional times the message is to be sent.
//
// Status: BETA / Probably works.
//
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_COOLIX.cpp
// TODO(anyone): Verify repeat functionality against a real unit.
void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) {
if (nbits % 8 != 0)
return; // nbits is required to be a multiple of 8.
// Set IR carrier frequency
enableIROut(38);
for (uint16_t r = 0; r <= repeat; r++) {
// Header
mark(COOLIX_HDR_MARK);
space(COOLIX_HDR_SPACE);
// Data
// Break data into byte segments, starting at the Most Significant
// Byte. Each byte then being sent normal, then followed inverted.
for (uint16_t i = 8; i <= nbits; i += 8) {
// Grab a bytes worth of data.
uint8_t segment = (data >> (nbits - i)) & 0xFF;
// Normal
sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE,
COOLIX_BIT_MARK, COOLIX_ZERO_SPACE,
segment, 8, true);
// Inverted.
sendData(COOLIX_BIT_MARK, COOLIX_ONE_SPACE,
COOLIX_BIT_MARK, COOLIX_ZERO_SPACE,
segment ^ 0xFF, 8, true);
}
// Footer
mark(COOLIX_BIT_MARK);
space(COOLIX_MIN_GAP); // Pause before repeating
}
}
#endif
#if DECODE_COOLIX
// Decode the supplied Coolix message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: The number of data bits to expect. Typically COOLIX_BITS.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Probably working.
bool IRrecv::decodeCOOLIX(decode_results *results, uint16_t nbits,
bool strict) {
// The protocol sends the data normal + inverted, alternating on
// each byte. Hence twice the number of expected data bits.
if (results->rawlen < 2 * 2 * nbits + HEADER + FOOTER - 1)
return false; // Can't possibly be a valid COOLIX message.
if (strict && nbits != COOLIX_BITS)
return false; // Not strictly an COOLIX message.
if (nbits % 8 != 0) // nbits has to be a multiple of nr. of bits in a byte.
return false;
uint64_t data = 0;
uint64_t inverted = 0;
uint16_t offset = OFFSET_START;
if (nbits > sizeof(data) * 8)
return false; // We can't possibly capture a Coolix packet that big.
// Header
if (!matchMark(results->rawbuf[offset], COOLIX_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / COOLIX_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], COOLIX_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
COOLIX_HDR_SPACE_TICKS;
// Data
// Twice as many bits as there are normal plus inverted bits.
for (uint16_t i = 0; i < nbits * 2; i++, offset++) {
bool flip = (i / 8) % 2;
if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK_TICKS * m_tick))
return false;
if (matchSpace(results->rawbuf[offset], COOLIX_ONE_SPACE_TICKS * s_tick)) {
if (flip)
inverted = (inverted << 1) | 1;
else
data = (data << 1) | 1;
} else if (matchSpace(results->rawbuf[offset],
COOLIX_ZERO_SPACE_TICKS * s_tick)) {
if (flip)
inverted <<= 1;
else
data <<= 1;
} else {
return false;
}
}
// Footer
if (!matchMark(results->rawbuf[offset++], COOLIX_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], COOLIX_MIN_GAP_TICKS * s_tick))
return false;
// Compliance
uint64_t orig = data; // Save a copy of the data.
if (strict) {
for (uint16_t i = 0; i < nbits; i += 8, data >>= 8, inverted >>= 8)
if ((data & 0xFF) != ((inverted & 0xFF) ^ 0xFF))
return false;
}
// Success
results->decode_type = COOLIX;
results->bits = nbits;
results->value = orig;
results->address = 0;
results->command = 0;
return true;
}
#endif
+347
View File
@@ -0,0 +1,347 @@
/*
An Arduino sketch to emulate IR Daikin ARC433** remote control unit
Read more at:
http://harizanov.com/2012/02/control-daikin-air-conditioner-over-the-internet/
Copyright 2016 sillyfrog
*/
#include "ir_Daikin.h"
#include <algorithm>
#include "IRremoteESP8266.h"
#include "IRutils.h"
// DDDDD AAA IIIII KK KK IIIII NN NN
// DD DD AAAAA III KK KK III NNN NN
// DD DD AA AA III KKKK III NN N NN
// DD DD AAAAAAA III KK KK III NN NNN
// DDDDDD AA AA IIIII KK KK IIIII NN NN
// Constants
// Ref:
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
#define DAIKIN_HDR_MARK 3650U // DAIKIN_ZERO_MARK * 8
#define DAIKIN_HDR_SPACE 1623U // DAIKIN_ZERO_MARK * 4
#define DAIKIN_ONE_SPACE 1280U
#define DAIKIN_ONE_MARK 428U
#define DAIKIN_ZERO_MARK 428U
#define DAIKIN_ZERO_SPACE 428U
#define DAIKIN_GAP 29000U
#if SEND_DAIKIN
// Send a Daikin A/C message.
//
// Args:
// data: An array of DAIKIN_COMMAND_LENGTH bytes containing the IR command.
//
// Status: STABLE
//
// Ref:
// IRDaikinESP.cpp
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
void IRsend::sendDaikin(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
if (nbytes < DAIKIN_COMMAND_LENGTH)
return; // Not enough bytes to send a proper message.
// Set IR carrier frequency
enableIROut(38);
for (uint16_t r = 0; r <= repeat; r++) {
// Header #1
mark(DAIKIN_HDR_MARK);
space(DAIKIN_HDR_SPACE);
// Data #1
for (uint16_t i = 0; i < 8 && i < nbytes; i++)
sendData(DAIKIN_ONE_MARK, DAIKIN_ONE_SPACE, DAIKIN_ZERO_MARK,
DAIKIN_ZERO_SPACE, data[i], 8, false);
// Footer #1
mark(DAIKIN_ONE_MARK);
space(DAIKIN_ZERO_SPACE + DAIKIN_GAP);
// Header #2
mark(DAIKIN_HDR_MARK);
space(DAIKIN_HDR_SPACE);
// Data #2
for (uint16_t i = 8; i < nbytes; i++)
sendData(DAIKIN_ONE_MARK, DAIKIN_ONE_SPACE, DAIKIN_ZERO_MARK,
DAIKIN_ZERO_SPACE, data[i], 8, false);
// Footer #2
mark(DAIKIN_ONE_MARK);
space(DAIKIN_ZERO_SPACE + DAIKIN_GAP);
}
}
IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) {
stateReset();
}
void IRDaikinESP::begin() {
_irsend.begin();
}
void IRDaikinESP::send() {
_irsend.sendDaikin(daikin);
}
void IRDaikinESP::checksum() {
uint8_t sum = 0;
uint8_t i;
for (i = 0; i <= 6; i++)
sum += daikin[i];
daikin[7] = sum & 0xFF;
sum = 0;
for (i = 8; i <= 25; i++)
sum += daikin[i];
daikin[26] = sum & 0xFF;
}
void IRDaikinESP::stateReset() {
for (uint8_t i = 4; i < DAIKIN_COMMAND_LENGTH; i++)
daikin[i] = 0x0;
daikin[0] = 0x11;
daikin[1] = 0xDA;
daikin[2] = 0x27;
daikin[3] = 0xF0;
daikin[7] = 0x20;
daikin[8] = 0x11;
daikin[9] = 0xDA;
daikin[10] = 0x27;
daikin[13] = 0x41;
daikin[14] = 0x1E;
daikin[16] = 0xB0;
daikin[23] = 0xC0;
daikin[26] = 0xE3;
checksum();
}
uint8_t* IRDaikinESP::getRaw() {
checksum(); // Ensure correct settings before sending.
return daikin;
}
void IRDaikinESP::on() {
// state = ON;
daikin[13] |= 0x01;
checksum();
}
void IRDaikinESP::off() {
// state = OFF;
daikin[13] &= 0xFE;
checksum();
}
void IRDaikinESP::setPower(bool state) {
if (state)
on();
else
off();
}
uint8_t IRDaikinESP::getPower() {
return daikin[13] & 0x01;
}
// DAIKIN_SILENT or DAIKIN_POWERFUL
void IRDaikinESP::setAux(uint8_t aux) {
daikin[21] = aux;
checksum();
}
uint8_t IRDaikinESP::getAux() {
return daikin[21];
}
void IRDaikinESP::setQuiet(bool state) {
if (state)
setAux(DAIKIN_SILENT);
else
setAux(0x0);
}
bool IRDaikinESP::getQuiet() {
return (getAux() == DAIKIN_SILENT);
}
void IRDaikinESP::setPowerful(bool state) {
if (state)
setAux(DAIKIN_POWERFUL);
else
setAux(0x0);
}
bool IRDaikinESP::getPowerful() {
return (getAux() == DAIKIN_POWERFUL);
}
// Set the temp in deg C
void IRDaikinESP::setTemp(uint8_t temp) {
if (temp < DAIKIN_MIN_TEMP)
temp = DAIKIN_MIN_TEMP;
else if (temp > DAIKIN_MAX_TEMP)
temp = DAIKIN_MAX_TEMP;
daikin[14] = temp * 2;
checksum();
}
uint8_t IRDaikinESP::getTemp() {
return daikin[14] / 2;
}
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
void IRDaikinESP::setFan(uint8_t fan) {
// Set the fan speed bits, leave low 4 bits alone
uint8_t fanset;
daikin[16] &= 0x0F;
fan = std::min(fan, DAIKIN_FAN_MAX);
if (fan == DAIKIN_FAN_AUTO)
fanset = 0xA0;
else
fanset = 0x20 + (0x10 * fan);
daikin[16] |= fanset;
checksum();
}
uint8_t IRDaikinESP::getFan() {
uint8_t fan = daikin[16] >> 4;
fan -= 2;
if (fan > DAIKIN_FAN_MAX)
fan = DAIKIN_FAN_AUTO;
return fan;
}
uint8_t IRDaikinESP::getMode() {
/*
DAIKIN_COOL
DAIKIN_HEAT
DAIKIN_FAN
DAIKIN_AUTO
DAIKIN_DRY
*/
return daikin[13] >> 4;
}
void IRDaikinESP::setMode(uint8_t mode) {
switch (mode) {
case DAIKIN_COOL:
case DAIKIN_HEAT:
case DAIKIN_FAN:
case DAIKIN_DRY:
break;
default:
mode = DAIKIN_AUTO;
}
daikin[13] = (mode << 4) | getPower();
checksum();
}
void IRDaikinESP::setSwingVertical(bool state) {
if (state)
daikin[16] |= 0x0F;
else
daikin[16] &= 0xF0;
checksum();
}
bool IRDaikinESP::getSwingVertical() {
return daikin[16] & 0x01;
}
void IRDaikinESP::setSwingHorizontal(bool state) {
if (state)
daikin[17] |= 0x0F;
else
daikin[17] &= 0xF0;
checksum();
}
bool IRDaikinESP::getSwingHorizontal() {
return daikin[17] & 0x01;
}
#endif // SEND_DAIKIN
#if DECODE_DAIKIN
// TODO(crankyoldgit): NOT WORKING. This needs to be finished.
// Decode the supplied Daikin A/C message. (NOT WORKING - DO NOT USE)
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of bits to expect in the data portion. Typically SAMSUNG_BITS.
// strict: Flag to indicate if we strictly adhere to the specification.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: UNFINISHED / Completely not working, not even vaguely.
//
// Ref:
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits,
bool strict) {
if (results->rawlen < 2 * nbits + HEADER + FOOTER)
return false;
// Compliance
if (strict && nbits != DAIKIN_BITS)
return false;
uint32_t data = 0;
uint16_t offset = OFFSET_START;
// Header
if (!matchMark(results->rawbuf[offset++], DAIKIN_HDR_MARK))
return false;
if (!matchSpace(results->rawbuf[offset++], DAIKIN_HDR_SPACE))
return false;
// Data (#1)
for (uint8_t i = 0; i < sizeof(data) * 8; i++, offset++) {
if (!matchMark(results->rawbuf[offset++], DAIKIN_ONE_MARK))
return false;
if (matchSpace(results->rawbuf[offset], DAIKIN_ONE_SPACE))
data = (data << 1) | 1; // 1
else if (matchSpace(results->rawbuf[offset], DAIKIN_ZERO_SPACE))
data <<= 1; // 0
else
return false;
}
uint32_t number = data; // some number...
uint32_t reversed = reverseBits(number, sizeof(number) * 8)
DPRINT("Code ");
DPRINTLN(reversed, HEX);
// Data (#2)
for (uint8_t i = 0; i < sizeof(data) * 8; i++, offset++) {
if (!matchMark(results->rawbuf[offset++], DAIKIN_ONE_MARK))
return false;
if (matchSpace(results->rawbuf[offset], DAIKIN_ONE_SPACE))
data = (data << 1) | 1; // 1
else if (matchSpace(results->rawbuf[offset], DAIKIN_ZERO_SPACE))
data <<= 1; // 0
else
return false;
}
number = data; // some number...
reversed = reverseBits(number, sizeof(number) * 8)
DPRINT("Code2 ");
DPRINTLN(reversed, HEX);
if (!matchSpace(results->rawbuf[offset++], DAIKIN_GAP)) {
DPRINTLN("no gap");
return false;
}
// Success
results->bits = DAIKIN_BITS;
results->value = reversed;
results->decode_type = DAIKIN;
results->address = 0;
results->command = 0;
return true;
}
#endif // DECODE_DAIKIN
+107
View File
@@ -0,0 +1,107 @@
/* Copyright 2016 sillyfrog */
#ifndef IR_DAIKIN_H_
#define IR_DAIKIN_H_
#include "IRremoteESP8266.h"
#include "IRsend.h"
// DDDDD AAA IIIII KK KK IIIII NN NN
// DD DD AAAAA III KK KK III NNN NN
// DD DD AA AA III KKKK III NN N NN
// DD DD AAAAAAA III KK KK III NN NNN
// DDDDDD AA AA IIIII KK KK IIIII NN NN
/*
Daikin AC map
byte 7= checksum of the first part (and last byte before a 29ms pause)
byte 13=mode
b7 = 0
b6+b5+b4 = Mode
Modes: b6+b5+b4
011 = Cool
100 = Heat (temp 23)
110 = FAN (temp not shown, but 25)
000 = Fully Automatic (temp 25)
010 = DRY (temp 0xc0 = 96 degrees c)
b3 = 0
b2 = OFF timer set
b1 = ON timer set
b0 = Air Conditioner ON
byte 14=temp*2 (Temp should be between 18 - 32)
byte 16=Fan
FAN control
b7+b6+b5+b4 = Fan speed
Fan: b7+b6+b5+b4
0×30 = 1 bar
0×40 = 2 bar
0×50 = 3 bar
0×60 = 4 bar
0×70 = 5 bar
0xa0 = Auto
0xb0 = Not auto, moon + tree
b3+b2+b1+b0 = Swing control up/down
Swing control up/down:
0000 = Swing up/down off
1111 = Swing up/down on
byte 17
Swing control left/right:
0000 = Swing left/right off
1111 = Swing left/right on
byte 21=Aux -> Powerful (bit 1), Silent (bit 5)
byte 24=Aux2 -> Intelligent eye on (bit 7)
byte 26= checksum of the second part
*/
// Constants
#define DAIKIN_COOL 0b011
#define DAIKIN_HEAT 0b100
#define DAIKIN_FAN 0b110
#define DAIKIN_AUTO 0b000
#define DAIKIN_DRY 0b010
#define DAIKIN_POWERFUL 0b00000010
#define DAIKIN_SILENT 0b00100000
#define DAIKIN_MIN_TEMP 18U // Celsius
#define DAIKIN_MAX_TEMP 32U // Celsius
#define DAIKIN_FAN_AUTO (uint8_t) 0U
#define DAIKIN_FAN_MIN (uint8_t) 1U
#define DAIKIN_FAN_MAX (uint8_t) 5U
#if SEND_DAIKIN
class IRDaikinESP {
public:
explicit IRDaikinESP(uint16_t pin);
void send();
void begin();
void on();
void off();
void setPower(bool state);
uint8_t getPower();
void setAux(uint8_t aux);
uint8_t getAux();
void setTemp(uint8_t temp);
uint8_t getTemp();
void setFan(uint8_t fan);
uint8_t getFan();
uint8_t getMode();
void setMode(uint8_t mode);
void setSwingVertical(bool state);
bool getSwingVertical();
void setSwingHorizontal(bool state);
bool getSwingHorizontal();
bool getQuiet();
void setQuiet(bool state);
bool getPowerful();
void setPowerful(bool state);
uint8_t* getRaw();
private:
// # of bytes per command
uint8_t daikin[DAIKIN_COMMAND_LENGTH];
void stateReset();
void checksum();
IRsend _irsend;
};
#endif
#endif // IR_DAIKIN_H_
+153
View File
@@ -0,0 +1,153 @@
// Copyright 2016 Massimiliano Pinto
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// DDDD EEEEE N N OOO N N
// D D E NN N O O NN N
// D D EEE N N N O O N N N
// D D E N NN O O N NN
// DDDD EEEEE N N OOO N N
// Original Denon support added by https://github.com/csBlueChip
// Ported over by Massimiliano Pinto
// Constants
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp
#define DENON_TICK 263U
#define DENON_HDR_MARK_TICKS 1U
#define DENON_HDR_MARK (DENON_HDR_MARK_TICKS * DENON_TICK)
#define DENON_HDR_SPACE_TICKS 3U
#define DENON_HDR_SPACE (DENON_HDR_SPACE_TICKS * DENON_TICK)
#define DENON_BIT_MARK_TICKS 1U
#define DENON_BIT_MARK (DENON_BIT_MARK_TICKS * DENON_TICK)
#define DENON_ONE_SPACE_TICKS 7U
#define DENON_ONE_SPACE (DENON_ONE_SPACE_TICKS * DENON_TICK)
#define DENON_ZERO_SPACE_TICKS 3U
#define DENON_ZERO_SPACE (DENON_ZERO_SPACE_TICKS * DENON_TICK)
#define DENON_MIN_COMMAND_LENGTH_TICKS 510U
#define DENON_MIN_COMMAND_LENGTH (DENON_MIN_COMMAND_LENGTH_TICKS * DENON_TICK)
#define DENON_MIN_GAP_TICKS (DENON_MIN_COMMAND_LENGTH_TICKS - \
(DENON_HDR_MARK_TICKS + DENON_HDR_SPACE_TICKS + \
DENON_BITS * (DENON_BIT_MARK_TICKS + DENON_ONE_SPACE_TICKS) + \
DENON_BIT_MARK_TICKS))
#define DENON_MIN_GAP (DENON_MIN_GAP_TICKS * DENON_TICK)
#define DENON_MANUFACTURER 0x2A4CULL
#if SEND_DENON
// Send a Denon message
//
// Args:
// data: Contents of the message to be sent.
// nbits: Nr. of bits of data to be sent. Typically DENON_BITS.
// repeat: Nr. of additional times the message is to be sent.
//
// Status: BETA / Should be working.
//
// Notes:
// Some Denon devices use a Kaseikyo/Panasonic 48-bit format
// Others use the Sharp protocol.
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp
// http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls
void IRsend::sendDenon(uint64_t data, uint16_t nbits, uint16_t repeat) {
if (nbits >= PANASONIC_BITS) // Is this really Panasonic?
sendPanasonic64(data, nbits, repeat);
else if (nbits == DENON_LEGACY_BITS)
// Support legacy (broken) calls of sendDenon().
sendSharpRaw(data & (~0x2000ULL), nbits + 1, repeat);
else
sendSharpRaw(data, nbits, repeat);
}
#endif
#if DECODE_DENON
// Decode a Denon message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Expected nr. of data bits. (Typically DENON_BITS)
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should work fine.
//
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Denon.cpp
bool IRrecv::decodeDenon(decode_results *results, uint16_t nbits, bool strict) {
// Compliance
if (strict) {
switch (nbits) {
case DENON_BITS:
case DENON_48_BITS:
case DENON_LEGACY_BITS:
break;
default:
return false;
}
}
// Denon uses the Sharp & Panasonic(Kaseikyo) protocol for some
// devices, so check for those first.
// It is not exactly like Sharp's protocols, but close enough.
// e.g. The expansion bit is not set for Denon vs. set for Sharp.
// Ditto for Panasonic, it's the same except for a different
// manufacturer code.
if (!decodeSharp(results, nbits, true, false) &&
!decodePanasonic(results, nbits, true, DENON_MANUFACTURER)) {
// We couldn't decode it as expected, so try the old legacy method.
// NOTE: I don't think this following protocol actually exists.
// Looks like a partial version of the Sharp protocol.
// Check we have enough data
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1)
return false;
if (strict && nbits != DENON_LEGACY_BITS)
return false;
uint64_t data = 0;
uint16_t offset = OFFSET_START;
// Header
if (!matchMark(results->rawbuf[offset], DENON_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK /
DENON_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], DENON_HDR_SPACE)) return false;
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
DENON_HDR_SPACE_TICKS;
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
DENON_BIT_MARK_TICKS * m_tick,
DENON_ONE_SPACE_TICKS * s_tick,
DENON_BIT_MARK_TICKS * m_tick,
DENON_ZERO_SPACE_TICKS * s_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!matchMark(results->rawbuf[offset++], DENON_BIT_MARK_TICKS * m_tick))
return false;
// Success
results->bits = nbits;
results->value = data;
results->address = 0;
results->command = 0;
} // Legacy decode.
// Compliance
if (strict && nbits != results->bits) return false;
// Success
results->decode_type = DENON;
return true;
}
#endif
+144
View File
@@ -0,0 +1,144 @@
// Copyright Todd Treece
// Copyright 2017 David Conran
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// DDDD IIIII SSSS H H
// D D I S H H
// D D I SSS HHHHH
// D D I S H H
// DDDD IIIII SSSS H H
// DISH support originally by Todd Treece
// http://unionbridge.org/design/ircommand
// Constants
// Ref:
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp
// http://www.hifi-remote.com/wiki/index.php?title=Dish
#define DISH_TICK 100U
#define DISH_HDR_MARK_TICKS 4U
#define DISH_HDR_MARK (DISH_HDR_MARK_TICKS * DISH_TICK)
#define DISH_HDR_SPACE_TICKS 61U
#define DISH_HDR_SPACE (DISH_HDR_SPACE_TICKS * DISH_TICK)
#define DISH_BIT_MARK_TICKS 4U
#define DISH_BIT_MARK (DISH_BIT_MARK_TICKS * DISH_TICK)
#define DISH_ONE_SPACE_TICKS 17U
#define DISH_ONE_SPACE (DISH_ONE_SPACE_TICKS * DISH_TICK)
#define DISH_ZERO_SPACE_TICKS 28U
#define DISH_ZERO_SPACE (DISH_ZERO_SPACE_TICKS * DISH_TICK)
#define DISH_RPT_SPACE_TICKS DISH_HDR_SPACE_TICKS
#define DISH_RPT_SPACE (DISH_RPT_SPACE_TICKS * DISH_TICK)
#if SEND_DISH
// Send an IR command to a DISH NETWORK device.
//
// Args:
// data: The contents of the command you want to send.
// nbits: The bit size of the command being sent.
// repeat: The number of times you want the command to be repeated.
//
// Status: BETA / Previously working.
//
// Note:
// Dishplayer is a different protocol.
// Typically a DISH device needs to get a command a total of at least 4
// times to accept it. e.g. repeat=3
//
// Here is the LIRC file I found that seems to match the remote codes from the
// oscilloscope:
// DISH NETWORK (echostar 301):
// http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
//
// Ref:
// http://www.hifi-remote.com/wiki/index.php?title=Dish
void IRsend::sendDISH(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set 57.6kHz IR carrier frequency, duty cycle is unknown.
enableIROut(57600);
// Header
mark(DISH_HDR_MARK);
space(DISH_HDR_SPACE);
// We always send a command, even for repeat=0, hence '<= repeat'.
for (uint16_t i = 0; i <= repeat; i++) {
// Data
sendData(DISH_BIT_MARK, DISH_ONE_SPACE, DISH_BIT_MARK, DISH_ZERO_SPACE,
data, nbits, true);
// Footer
mark(DISH_BIT_MARK);
space(DISH_RPT_SPACE);
}
}
#endif
#if DECODE_DISH
// Decode the supplied DISH NETWORK message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of bits to expect in the data portion. Typically DISH_BITS.
// strict: Flag to indicate if we strictly adhere to the specification.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: ALPHA (untested and unconfirmed.)
//
// Note:
// Dishplayer is a different protocol.
// Typically a DISH device needs to get a command a total of at least 4
// times to accept it.
// Ref:
// http://www.hifi-remote.com/wiki/index.php?title=Dish
// http://lirc.sourceforge.net/remotes/echostar/301_501_3100_5100_58xx_59xx
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Dish.cpp
bool IRrecv::decodeDISH(decode_results *results, uint16_t nbits, bool strict) {
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1)
return false; // Not enough entries to be valid.
if (strict && nbits != DISH_BITS)
return false; // Not strictly compliant.
uint64_t data = 0;
uint16_t offset = OFFSET_START;
// Header
if (!match(results->rawbuf[offset], DISH_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], DISH_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / DISH_HDR_SPACE_TICKS;
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
DISH_BIT_MARK_TICKS * m_tick,
DISH_ONE_SPACE_TICKS * s_tick,
DISH_BIT_MARK_TICKS * m_tick,
DISH_ZERO_SPACE_TICKS * s_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!matchMark(results->rawbuf[offset++], DISH_BIT_MARK_TICKS * m_tick))
return false;
// Compliance
if (strict) {
// The DISH protocol calls for a repeated message, so strictly speaking
// there should be a code following this. Only require it if we are set to
// strict matching.
if (!matchSpace(results->rawbuf[offset], DISH_RPT_SPACE_TICKS * s_tick))
return false;
}
// Success
results->decode_type = DISH;
results->bits = nbits;
results->value = data;
results->address = 0;
results->command = 0;
return true;
}
#endif
+221
View File
@@ -0,0 +1,221 @@
// Copyright 2017 Jonny Graham
#include "ir_Fujitsu.h"
#include <algorithm>
#include "IRsend.h"
// Fujitsu A/C support added by Jonny Graham
// Fujitsu A/C
// Ref:
// These values are based on averages of measurements
#define FUJITSU_AC_HDR_MARK 3224U
#define FUJITSU_AC_HDR_SPACE 1574U
#define FUJITSU_AC_BIT_MARK 448U
#define FUJITSU_AC_ONE_SPACE 1182U
#define FUJITSU_AC_ZERO_SPACE 367U
#define FUJITSU_AC_TRL_MARK 448U
#define FUJITSU_AC_TRL_SPACE 8100U
#if SEND_FUJITSU_AC
// Send a Fujitsu A/C message.
//
// Args:
// data: An array of bytes containing the IR command.
// nbytes: Nr. of bytes of data in the array. (typically either
// FUJITSU_AC_STATE_LENGTH or FUJITSU_AC_STATE_LENGTH_SHORT)
// repeat: Nr. of times the message is to be repeated.
// (Default = FUJITSU_AC_MIN_REPEAT).
//
// Status: BETA / Appears to be working.
//
void IRsend::sendFujitsuAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
// Set IR carrier frequency
enableIROut(38);
for (uint16_t r = 0; r <= repeat; ++r) {
// Header
mark(FUJITSU_AC_HDR_MARK);
space(FUJITSU_AC_HDR_SPACE);
// Data
for (uint16_t i = 0; i < nbytes; i++)
sendData(FUJITSU_AC_BIT_MARK, FUJITSU_AC_ONE_SPACE,
FUJITSU_AC_BIT_MARK, FUJITSU_AC_ZERO_SPACE,
data[i], 8, false);
// Footer
mark(FUJITSU_AC_TRL_MARK);
space(FUJITSU_AC_TRL_SPACE);
}
}
// Code to emulate Fujitsu A/C IR remote control unit.
// Warning: Consider this very alpha code. Seems to work, but not validated.
//
// Equipment it seems compatible with:
// * Fujitsu ASYG30LFCA with remote AR-RAH2E
// * <Add models (A/C & remotes) you've gotten it working with here>
// Initialise the object.
IRFujitsuAC::IRFujitsuAC(uint16_t pin) : _irsend(pin) {
stateReset();
}
// Reset the state of the remote to a known good state/sequence.
void IRFujitsuAC::stateReset() {
_temp = 24;
_fanSpeed = FUJITSU_AC_FAN_HIGH;
_mode = FUJITSU_AC_MODE_COOL;
_swingMode = FUJITSU_AC_SWING_BOTH;
_cmd = FUJITSU_AC_CMD_TURN_ON;
}
// Configure the pin for output.
void IRFujitsuAC::begin() {
_irsend.begin();
}
// Send the current desired state to the IR LED.
void IRFujitsuAC::send() {
getRaw();
uint8_t len = getCommandLength();
_irsend.sendFujitsuAC(remote_state, len);
}
uint8_t IRFujitsuAC::getCommandLength() {
if (remote_state[5] != 0xFE)
return FUJITSU_AC_STATE_LENGTH_SHORT;
else
return FUJITSU_AC_STATE_LENGTH;
}
// Return a pointer to the internal state date of the remote.
uint8_t* IRFujitsuAC::getRaw() {
remote_state[0] = 0x14;
remote_state[1] = 0x63;
remote_state[2] = 0x00;
remote_state[3] = 0x10;
remote_state[4] = 0x10;
bool fullCmd = false;
switch (_cmd) {
case FUJITSU_AC_CMD_TURN_OFF:
remote_state[5] = 0x02;
break;
case FUJITSU_AC_CMD_STEP_HORIZ:
remote_state[5] = 0x79;
break;
case FUJITSU_AC_CMD_STEP_VERT:
remote_state[5] = 0x6C;
break;
default:
remote_state[5] = 0xFE;
fullCmd = true;
break;
}
if (fullCmd) {
remote_state[6] = 0x09;
remote_state[7] = 0x30;
uint8_t tempByte = _temp - FUJITSU_AC_MIN_TEMP;
remote_state[8] = (_cmd == FUJITSU_AC_CMD_TURN_ON) | (tempByte << 4);
remote_state[9] = _mode | 0 << 4; // timer off
remote_state[10] = _fanSpeed | _swingMode << 4;
remote_state[11] = 0; // timerOff values
remote_state[12] = 0; // timerOff/on values
remote_state[13] = 0; // timerOn values
remote_state[14] = 0x20;
// Checksum is the sum of the 8th to 16th bytes (ie remote_state[7]
// thru remote_state[15]).
// The checksum itself is stored in the 16th byte (ie remote_state[15]).
// So we sum bytes 8th-15th...
uint8_t checksum = 0;
for (uint8_t i = 7 ; i < 15; ++i) {
checksum += remote_state[i];
}
// and then do 0 - sum and store it in 16th.
remote_state[15] = 0 - checksum;
} else {
// For the short codes, byte 7 is the inverse of byte 6
remote_state[6] = ~remote_state[5];
for (uint8_t i = 7; i < FUJITSU_AC_STATE_LENGTH; ++i) {
remote_state[i] = 0;
}
}
return remote_state;
}
// Set the requested power state of the A/C to off.
void IRFujitsuAC::off() {
_cmd = FUJITSU_AC_CMD_TURN_OFF;
}
void IRFujitsuAC::stepHoriz() {
_cmd = FUJITSU_AC_CMD_STEP_HORIZ;
}
void IRFujitsuAC::stepVert() {
_cmd = FUJITSU_AC_CMD_STEP_VERT;
}
// Set the requested command of the A/C.
void IRFujitsuAC::setCmd(uint8_t cmd) {
switch (cmd) {
case FUJITSU_AC_CMD_TURN_OFF:
case FUJITSU_AC_CMD_TURN_ON:
case FUJITSU_AC_CMD_STAY_ON:
case FUJITSU_AC_CMD_STEP_HORIZ:
case FUJITSU_AC_CMD_STEP_VERT:
break;
default:
cmd = FUJITSU_AC_CMD_STAY_ON;
break;
}
_cmd = cmd;
}
uint8_t IRFujitsuAC::getCmd() {
return _cmd;
}
// Set the temp. in deg C
void IRFujitsuAC::setTemp(uint8_t temp) {
temp = std::max((uint8_t) FUJITSU_AC_MIN_TEMP, temp);
temp = std::min((uint8_t) FUJITSU_AC_MAX_TEMP, temp);
_temp = temp;
}
uint8_t IRFujitsuAC::getTemp() {
return _temp;
}
// Set the speed of the fan
void IRFujitsuAC::setFanSpeed(uint8_t fanSpeed) {
if (fanSpeed > FUJITSU_AC_FAN_QUIET)
fanSpeed = FUJITSU_AC_FAN_HIGH; // Set the fan to maximum if out of range.
_fanSpeed = fanSpeed;
}
uint8_t IRFujitsuAC::getFanSpeed() {
return _fanSpeed;
}
// Set the requested climate operation mode of the a/c unit.
void IRFujitsuAC::setMode(uint8_t mode) {
if (mode > FUJITSU_AC_MODE_HEAT)
mode = FUJITSU_AC_MODE_HEAT; // Set the mode to maximum if out of range.
_mode = mode;
}
uint8_t IRFujitsuAC::getMode() {
return _mode;
}
// Set the requested swing operation mode of the a/c unit.
void IRFujitsuAC::setSwing(uint8_t swingMode) {
if (swingMode > FUJITSU_AC_SWING_BOTH)
swingMode = FUJITSU_AC_SWING_BOTH; // Set the mode to max if out of range
_swingMode = swingMode;
}
uint8_t IRFujitsuAC::getSwing() {
return _swingMode;
}
#endif
+80
View File
@@ -0,0 +1,80 @@
// Copyright 2017 Jonny Graham
#ifndef IR_FUJITSU_H_
#define IR_FUJITSU_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include "IRremoteESP8266.h"
#include "IRsend.h"
// FUJITSU A/C support added by Jonny Graham
// Constants
#define FUJITSU_AC_MODE_AUTO 0x00U
#define FUJITSU_AC_MODE_COOL 0x01U
#define FUJITSU_AC_MODE_DRY 0x02U
#define FUJITSU_AC_MODE_FAN 0x03U
#define FUJITSU_AC_MODE_HEAT 0x04U
#define FUJITSU_AC_CMD_STAY_ON 0x00U
#define FUJITSU_AC_CMD_TURN_ON 0x01U
#define FUJITSU_AC_CMD_TURN_OFF 0x02U
#define FUJITSU_AC_CMD_STEP_HORIZ 0x79U
#define FUJITSU_AC_CMD_STEP_VERT 0x6CU
#define FUJITSU_AC_FAN_AUTO 0x00U
#define FUJITSU_AC_FAN_HIGH 0x01U
#define FUJITSU_AC_FAN_MED 0x02U
#define FUJITSU_AC_FAN_LOW 0x03U
#define FUJITSU_AC_FAN_QUIET 0x04U
#define FUJITSU_AC_MIN_TEMP 16U // 16C
#define FUJITSU_AC_MAX_TEMP 30U // 30C
#define FUJITSU_AC_SWING_OFF 0x00U
#define FUJITSU_AC_SWING_VERT 0x01U
#define FUJITSU_AC_SWING_HORIZ 0x02U
#define FUJITSU_AC_SWING_BOTH 0x03U
#define FUJITSU_AC_STATE_LENGTH 16
#define FUJITSU_AC_STATE_LENGTH_SHORT 7
#if SEND_FUJITSU_AC
class IRFujitsuAC {
public:
explicit IRFujitsuAC(uint16_t pin);
void stateReset();
void send();
void begin();
void off();
void stepHoriz();
void stepVert();
void setCmd(uint8_t cmd);
uint8_t getCmd();
void setTemp(uint8_t temp);
uint8_t getTemp();
void setFanSpeed(uint8_t fan);
uint8_t getFanSpeed();
void setMode(uint8_t mode);
uint8_t getMode();
void setSwing(uint8_t mode);
uint8_t getSwing();
uint8_t* getRaw();
private:
uint8_t remote_state[FUJITSU_AC_STATE_LENGTH];
uint8_t getCommandLength();
IRsend _irsend;
uint8_t _temp;
uint8_t _fanSpeed;
uint8_t _mode;
uint8_t _swingMode;
uint8_t _cmd;
};
#endif
#endif // IR_FUJITSU_H_
@@ -0,0 +1,72 @@
// Copyright 2016 Hisham Khalifa
// Copyright 2017 David Conran
#include <algorithm>
#include "IRsend.h"
#include "IRtimer.h"
// GGG L OOOO BBBB AA L CCCC AA CCCC H H EEEEEE
// G G L O O B B AAAA L C C AAAA C C H H E
// G L O O BBBBB A A L C A A C HHHHHH EEEE
// G GG L O O B BB AAAAAA L C C AAAAAA C C H H E
// GGGGG LLLLLL OOOO BBBBB A A LLLLLL CCCC A A CCCC H H EEEEEE
// Global Cache IR format sender originally added by Hisham Khalifa
// (http://www.hishamkhalifa.com)
// Constants
#define GLOBALCACHE_MAX_REPEAT 50U
#define GLOBALCACHE_MIN_USEC 80U
#define GLOBALCACHE_FREQ_INDEX 0U
#define GLOBALCACHE_RPT_INDEX GLOBALCACHE_FREQ_INDEX + 1U
#define GLOBALCACHE_RPT_START_INDEX GLOBALCACHE_RPT_INDEX + 1U
#define GLOBALCACHE_START_INDEX GLOBALCACHE_RPT_START_INDEX + 1U
#if SEND_GLOBALCACHE
// Send a shortened GlobalCache (GC) IRdb/control tower formatted message.
//
// Args:
// buf: An array of uint16_t containing the shortened GlobalCache data.
// len: Nr. of entries in the buf[] array.
//
// Status: STABLE / Known working.
//
// Note:
// Global Cache format without the emitter ID or request ID.
// Starts at the frequency (Hertz), followed by nr. of times to emit (count),
// then the offset for repeats (where a repeat will start from),
// then the rest of entries are the actual IR message as units of periodic
// time.
// e.g. sendir,1:1,1,38000,1,1,9,70,9,30,9,... -> 38000,1,1,9,70,9,30,9,...
// Ref:
// https://irdb.globalcache.com/Home/Database
void IRsend::sendGC(uint16_t buf[], uint16_t len) {
uint16_t hz = buf[GLOBALCACHE_FREQ_INDEX]; // GC frequency is in Hz.
enableIROut(hz);
uint32_t periodic_time = calcUSecPeriod(hz, false);
uint8_t emits = std::min(buf[GLOBALCACHE_RPT_INDEX],
(uint16_t) GLOBALCACHE_MAX_REPEAT);
// Repeat
for (uint8_t repeat = 0; repeat < emits; repeat++) {
// First time through, start at the beginning (GLOBALCACHE_START_INDEX),
// otherwise for repeats, we start a specified offset from that.
uint16_t offset = GLOBALCACHE_START_INDEX;
if (repeat)
offset += buf[GLOBALCACHE_RPT_START_INDEX] - 1;
// Data
for (; offset < len; offset++) {
// Convert periodic units to microseconds.
// Minimum is GLOBALCACHE_MIN_USEC for actual GC units.
uint32_t microseconds = std::max(buf[offset] * periodic_time,
GLOBALCACHE_MIN_USEC);
// These codes start at an odd index (not even as with sendRaw).
if (offset & 1) // Odd bit.
mark(microseconds);
else // Even bit.
space(microseconds);
}
}
// It's possible that we've ended on a mark(), thus ensure the LED is off.
ledOff();
}
#endif
+113
View File
@@ -0,0 +1,113 @@
// Copyright 2017 Ville Skyttä (scop)
// Copyright 2017 David Conran
//
// Gree protocol compatible heat pump carrying the "Ultimate" brand name.
//
#include "IRremoteESP8266.h"
#include "IRsend.h"
// GGGG RRRRRR EEEEEEE EEEEEEE
// GG GG RR RR EE EE
// GG RRRRRR EEEEE EEEEE
// GG GG RR RR EE EE
// GGGGGG RR RR EEEEEEE EEEEEEE
// Constants
// Ref: https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.h
#define GREE_HDR_MARK 9000U
#define GREE_HDR_SPACE 4000U
#define GREE_BIT_MARK 620U
#define GREE_ONE_SPACE 1600U
#define GREE_ZERO_SPACE 540U
#define GREE_MSG_SPACE 19000U
#if SEND_GREE
// Send a Gree Heat Pump message.
//
// Args:
// data: An array of bytes containing the IR command.
// nbytes: Nr. of bytes of data in the array. (>=GREE_STATE_LENGTH)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
// Status: ALPHA / Untested.
//
// Ref:
// https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp
void IRsend::sendGree(unsigned char data[], uint16_t nbytes, uint16_t repeat) {
if (nbytes < GREE_STATE_LENGTH)
return; // Not enough bytes to send a proper message.
// Set IR carrier frequency
enableIROut(38);
for (uint16_t r = 0; r <= repeat; r++) {
// Header #1
mark(GREE_HDR_MARK);
space(GREE_HDR_SPACE);
// Data #1
uint16_t i;
for (i = 0; i < 4 && i < nbytes; i++)
sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE,
data[i], 8, false);
// Footer #1 (010)
sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE,
0b010, 3);
// Header #2
mark(GREE_BIT_MARK);
space(GREE_MSG_SPACE);
// Data #2
for (; i < nbytes; i++)
sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE,
data[i], 8, false);
// Footer #2
mark(GREE_BIT_MARK);
space(GREE_MSG_SPACE);
}
}
// Send a Gree Heat Pump message.
//
// Args:
// data: The raw message to be sent.
// nbits: Nr. of bits of data in the message. (Default is GREE_BITS)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
// Status: ALPHA / Untested.
//
// Ref:
// https://github.com/ToniA/arduino-heatpumpir/blob/master/GreeHeatpumpIR.cpp
void IRsend::sendGree(uint64_t data, uint16_t nbits, uint16_t repeat) {
if (nbits != GREE_BITS)
return; // Wrong nr. of bits to send a proper message.
// Set IR carrier frequency
enableIROut(38);
for (uint16_t r = 0; r <= repeat; r++) {
// Header
mark(GREE_HDR_MARK);
space(GREE_HDR_SPACE);
// Data
for (int16_t i = 8; i <= nbits; i += 8) {
sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE,
(data >> (nbits - i)) & 0xFF, 8, false);
if (i == nbits / 2) {
// Send the mid-message Footer.
sendData(GREE_BIT_MARK, GREE_ONE_SPACE, GREE_BIT_MARK, GREE_ZERO_SPACE,
0b010, 3);
mark(GREE_BIT_MARK);
space(GREE_MSG_SPACE);
}
}
// Footer
mark(GREE_BIT_MARK);
space(GREE_MSG_SPACE);
}
}
#endif // SEND_GREE
+165
View File
@@ -0,0 +1,165 @@
// Copyright 2015 Kristian Lauszus
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// JJJJJ V V CCCC
// J V V C
// J V V C
// J J V V C
// J V CCCC
// JVC originally added by Kristian Lauszus
// (Thanks to zenwheel and other people at the original blog post)
// Constants
// Ref:
// http://www.sbprojects.com/knowledge/ir/jvc.php
#define JVC_TICK 75U
#define JVC_HDR_MARK_TICKS 112U
#define JVC_HDR_MARK (JVC_HDR_MARK_TICKS * JVC_TICK)
#define JVC_HDR_SPACE_TICKS 56U
#define JVC_HDR_SPACE (JVC_HDR_SPACE_TICKS * JVC_TICK)
#define JVC_BIT_MARK_TICKS 7U
#define JVC_BIT_MARK (JVC_BIT_MARK_TICKS * JVC_TICK)
#define JVC_ONE_SPACE_TICKS 23U
#define JVC_ONE_SPACE (JVC_ONE_SPACE_TICKS * JVC_TICK)
#define JVC_ZERO_SPACE_TICKS 7U
#define JVC_ZERO_SPACE (JVC_ZERO_SPACE_TICKS * JVC_TICK)
#define JVC_RPT_LENGTH_TICKS 800U
#define JVC_RPT_LENGTH (JVC_RPT_LENGTH_TICKS * JVC_TICK)
#define JVC_MIN_GAP_TICKS (JVC_RPT_LENGTH_TICKS - \
(JVC_HDR_MARK_TICKS + JVC_HDR_SPACE_TICKS + \
JVC_BITS * (JVC_BIT_MARK_TICKS + JVC_ONE_SPACE_TICKS) + \
JVC_BIT_MARK_TICKS))
#define JVC_MIN_GAP (JVC_MIN_GAP_TICKS * JVC_TICK)
#if SEND_JVC
// Send a JVC message.
//
// Args:
// data: The contents of the command you want to send.
// nbits: The bit size of the command being sent. (JVC_BITS)
// repeat: The number of times you want the command to be repeated.
//
// Status: STABLE.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/jvc.php
void IRsend::sendJVC(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set 38kHz IR carrier frequency & a 1/3 (33%) duty cycle.
enableIROut(38, 33);
IRtimer usecs = IRtimer();
// Header
// Only sent for the first message.
mark(JVC_HDR_MARK);
space(JVC_HDR_SPACE);
// We always send the data & footer at least once, hence '<= repeat'.
for (uint16_t i = 0; i <= repeat; i++) {
// Data
sendData(JVC_BIT_MARK, JVC_ONE_SPACE, JVC_BIT_MARK, JVC_ZERO_SPACE,
data, nbits, true);
// Footer
mark(JVC_BIT_MARK);
// Wait till the end of the repeat time window before we send another code.
space(std::max(JVC_MIN_GAP, JVC_RPT_LENGTH - usecs.elapsed()));
usecs.reset();
}
}
// Calculate the raw JVC data based on address and command.
//
// Args:
// address: An 8-bit address value.
// command: An 8-bit command value.
// Returns:
// A raw JVC message.
//
// Status: BETA / Should work fine.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/jvc.php
uint16_t IRsend::encodeJVC(uint8_t address, uint8_t command) {
return reverseBits((command << 8) | address, 16);
}
#endif
#if DECODE_JVC
// Decode the supplied JVC message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of bits of data to expect. Typically JVC_BITS.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: STABLE
//
// Note:
// JVC repeat codes don't have a header.
// Ref:
// http://www.sbprojects.com/knowledge/ir/jvc.php
bool IRrecv::decodeJVC(decode_results *results, uint16_t nbits, bool strict) {
if (strict && nbits != JVC_BITS)
return false; // Must be called with the correct nr. of bits.
if (results->rawlen < 2 * nbits + FOOTER - 1)
return false; // Can't possibly be a valid JVC message.
uint64_t data = 0;
uint16_t offset = OFFSET_START;
bool isRepeat = true;
uint32_t m_tick;
uint32_t s_tick;
// Header
// (Optional as repeat codes don't have the header)
if (matchMark(results->rawbuf[offset], JVC_HDR_MARK)) {
isRepeat = false;
m_tick = results->rawbuf[offset++] * RAWTICK / JVC_HDR_MARK_TICKS;
if (results->rawlen < 2 * nbits + 4)
return false; // Can't possibly be a valid JVC message with a header.
if (!matchSpace(results->rawbuf[offset], JVC_HDR_SPACE))
return false;
s_tick = results->rawbuf[offset++] * RAWTICK / JVC_HDR_SPACE_TICKS;
} else {
// We can't easily auto-calibrate as there is no header, so assume
// the default tick time.
m_tick = JVC_TICK;
s_tick = JVC_TICK;
}
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
JVC_BIT_MARK_TICKS * m_tick,
JVC_ONE_SPACE_TICKS * s_tick,
JVC_BIT_MARK_TICKS * m_tick,
JVC_ZERO_SPACE_TICKS * s_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!matchMark(results->rawbuf[offset++], JVC_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], JVC_MIN_GAP_TICKS * s_tick))
return false;
// Success
results->decode_type = JVC;
results->bits = nbits;
results->value = data;
// command & address are transmitted LSB first, so we need to reverse them.
results->address = reverseBits(data >> 8, 8); // The first 8 bits sent.
results->command = reverseBits(data & 0xFF, 8); // The last 8 bits sent.
results->repeat = isRepeat;
return true;
}
#endif
+329
View File
@@ -0,0 +1,329 @@
// Copyright 2016 David Conran
//
// Code to emulate IR Kelvinator YALIF remote control unit, which should control
// at least the following Kelvinator A/C units:
// KSV26CRC, KSV26HRC, KSV35CRC, KSV35HRC, KSV53HRC, KSV62HRC, KSV70CRC,
// KSV70HRC, KSV80HRC.
//
// Note:
// * Unsupported:
// - All Sleep modes.
// - All Timer modes.
// - "I Feel" button & mode.
// - Energy Saving mode.
// - Low Heat mode.
// - Fahrenheit.
#include "ir_Kelvinator.h"
#include <algorithm>
// KK KK EEEEEEE LL VV VV IIIII NN NN AAA TTTTTTT OOOOO RRRRRR
// KK KK EE LL VV VV III NNN NN AAAAA TTT OO OO RR RR
// KKKK EEEEE LL VV VV III NN N NN AA AA TTT OO OO RRRRRR
// KK KK EE LL VV VV III NN NNN AAAAAAA TTT OO OO RR RR
// KK KK EEEEEEE LLLLLLL VVV IIIII NN NN AA AA TTT OOOO0 RR RR
// Constants
#define KELVINATOR_HDR_MARK 8990U
#define KELVINATOR_HDR_SPACE 4490U
#define KELVINATOR_BIT_MARK 675U
#define KELVINATOR_ONE_SPACE 1560U
#define KELVINATOR_ZERO_SPACE 520U
#define KELVINATOR_GAP_SPACE 19950U
#define KELVINATOR_CMD_FOOTER 2U
#define KELVINATOR_POWER 8U
#define KELVINATOR_MODE_MASK 0xF8U
#define KELVINATOR_FAN_OFFSET 4U
#define KELVINATOR_BASIC_FAN_MASK uint8_t(0xFFU ^ (3U << KELVINATOR_FAN_OFFSET))
#define KELVINATOR_FAN_MASK uint8_t(0xFFU ^ (7U << KELVINATOR_FAN_OFFSET))
#define KELVINATOR_CHECKSUM_START 10U
#define KELVINATOR_VENT_SWING_OFFSET 6U
#define KELVINATOR_VENT_SWING uint8_t(1U << KELVINATOR_VENT_SWING_OFFSET)
#define KELVINATOR_VENT_SWING_V uint8_t(1U)
#define KELVINATOR_VENT_SWING_H uint8_t(1U << 4)
#define KELVINATOR_SLEEP_1_AND_3 uint8_t(1U << 7)
#define KELVINATOR_QUIET_OFFSET 7U
#define KELVINATOR_QUIET uint8_t(1U << KELVINATOR_QUIET_OFFSET)
#define KELVINATOR_ION_FILTER_OFFSET 6U
#define KELVINATOR_ION_FILTER uint8_t(1U << KELVINATOR_ION_FILTER_OFFSET)
#define KELVINATOR_LIGHT_OFFSET 5U
#define KELVINATOR_LIGHT uint8_t(1U << KELVINATOR_LIGHT_OFFSET)
#define KELVINATOR_XFAN_OFFSET 7U
#define KELVINATOR_XFAN uint8_t(1U << KELVINATOR_XFAN_OFFSET)
#define KELVINATOR_TURBO_OFFSET 4U
#define KELVINATOR_TURBO uint8_t(1U << KELVINATOR_TURBO_OFFSET)
#if SEND_KELVINATOR
// Send a Kelvinator A/C message.
//
// Args:
// data: An array of bytes containing the IR command.
// nbytes: Nr. of bytes of data in the array. (>=KELVINATOR_STATE_LENGTH)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
// Status: STABLE / Known working.
//
void IRsend::sendKelvinator(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
if (nbytes < KELVINATOR_STATE_LENGTH)
return; // Not enough bytes to send a proper message.
// Set IR carrier frequency
enableIROut(38);
for (uint16_t r = 0; r <= repeat; r++) {
// Header #1
mark(KELVINATOR_HDR_MARK);
space(KELVINATOR_HDR_SPACE);
// Data (command)
// Send the first command data (4 bytes)
uint8_t i;
for (i = 0; i < 4; i++)
sendData(KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, KELVINATOR_BIT_MARK,
KELVINATOR_ZERO_SPACE, data[i], 8, false);
// Send Footer for the command data (3 bits (0b010))
sendData(KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, KELVINATOR_BIT_MARK,
KELVINATOR_ZERO_SPACE, KELVINATOR_CMD_FOOTER, 3, false);
// Send an interdata gap.
mark(KELVINATOR_BIT_MARK);
space(KELVINATOR_GAP_SPACE);
// Data (options)
// Send the 1st option chunk of data (4 bytes).
for (; i < 8; i++)
sendData(KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, KELVINATOR_BIT_MARK,
KELVINATOR_ZERO_SPACE, data[i], 8, false);
// Send a double data gap to signify we are starting a new command sequence.
mark(KELVINATOR_BIT_MARK);
space(KELVINATOR_GAP_SPACE * 2);
// Header #2
mark(KELVINATOR_HDR_MARK);
space(KELVINATOR_HDR_SPACE);
// Data (command)
// Send the 2nd command data (4 bytes).
// Basically an almost identical repeat of the earlier command data.
for (; i < 12; i++)
sendData(KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, KELVINATOR_BIT_MARK,
KELVINATOR_ZERO_SPACE, data[i], 8, false);
// Send Footer for the command data (3 bits (B010))
sendData(KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, KELVINATOR_BIT_MARK,
KELVINATOR_ZERO_SPACE, KELVINATOR_CMD_FOOTER, 3, false);
// Send an interdata gap.
mark(KELVINATOR_BIT_MARK);
space(KELVINATOR_GAP_SPACE);
// Data (options)
// Send the 2nd option chunk of data (4 bytes).
// Unlike the commands, definitely not a repeat of the earlier option data.
for (; i < KELVINATOR_STATE_LENGTH; i++)
sendData(KELVINATOR_BIT_MARK, KELVINATOR_ONE_SPACE, KELVINATOR_BIT_MARK,
KELVINATOR_ZERO_SPACE, data[i], 8, false);
// Footer
mark(KELVINATOR_BIT_MARK);
space(KELVINATOR_GAP_SPACE * 2);
}
}
IRKelvinatorAC::IRKelvinatorAC(uint16_t pin) : _irsend(pin) {
stateReset();
}
void IRKelvinatorAC::stateReset() {
for (uint8_t i = 0; i < KELVINATOR_STATE_LENGTH; i++)
remote_state[i] = 0x0;
remote_state[3] = 0x50;
remote_state[11] = 0x70;
}
void IRKelvinatorAC::begin() {
_irsend.begin();
}
void IRKelvinatorAC::fixup() {
// X-Fan mode is only valid in COOL or DRY modes.
if (getMode() != KELVINATOR_COOL && getMode() != KELVINATOR_DRY)
setXFan(false);
checksum(); // Calculate the checksums
}
void IRKelvinatorAC::send() {
fixup(); // Ensure correct settings before sending.
_irsend.sendKelvinator(remote_state);
}
uint8_t* IRKelvinatorAC::getRaw() {
fixup(); // Ensure correct settings before sending.
return remote_state;
}
// Many Bothans died to bring us this information.
void IRKelvinatorAC::checksum() {
// For each command + options block.
for (uint8_t offset = 0; offset < KELVINATOR_STATE_LENGTH; offset += 8) {
uint8_t sum = KELVINATOR_CHECKSUM_START;
// Sum the lower half of the first 4 bytes of this block.
for (uint8_t i = 0; i < 4; i++)
sum += (remote_state[i + offset] & 0xFU);
// then sum the upper half of the next 3 bytes.
for (uint8_t i = 4; i < 7; i++)
sum += (remote_state[i + offset] >> 4);
// Trim it down to fit into the 4 bits allowed. i.e. Mod 16.
sum &= 0xFU;
// Place it into the IR code in the top half of the 8th & 16th byte.
remote_state[7 + offset] = (sum << 4) | (remote_state[7 + offset] & 0xFU);
}
}
void IRKelvinatorAC::on() {
remote_state[0] |= KELVINATOR_POWER;
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
}
void IRKelvinatorAC::off() {
remote_state[0] &= ~KELVINATOR_POWER;
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
}
void IRKelvinatorAC::setPower(bool state) {
if (state)
on();
else
off();
}
bool IRKelvinatorAC::getPower() {
return ((remote_state[0] & KELVINATOR_POWER) != 0);
}
// Set the temp. in deg C
void IRKelvinatorAC::setTemp(uint8_t temp) {
temp = std::max((uint8_t) KELVINATOR_MIN_TEMP, temp);
temp = std::min((uint8_t) KELVINATOR_MAX_TEMP, temp);
remote_state[1] = (remote_state[1] & 0xF0U) | (temp - KELVINATOR_MIN_TEMP);
remote_state[9] = remote_state[1]; // Duplicate to the 2nd command chunk.
}
// Return the set temp. in deg C
uint8_t IRKelvinatorAC::getTemp() {
return ((remote_state[1] & 0xFU) + KELVINATOR_MIN_TEMP);
}
// Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed
void IRKelvinatorAC::setFan(uint8_t fan) {
fan = std::min((uint8_t) KELVINATOR_FAN_MAX, fan); // Bounds check
// Only change things if we need to.
if (fan != getFan()) {
// Set the basic fan values.
uint8_t fan_basic = std::min((uint8_t) KELVINATOR_BASIC_FAN_MAX, fan);
remote_state[0] = (remote_state[0] & KELVINATOR_BASIC_FAN_MASK) |
(fan_basic << KELVINATOR_FAN_OFFSET);
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
// Set the advanced(?) fan value.
remote_state[14] = (remote_state[14] & KELVINATOR_FAN_MASK) |
(fan << KELVINATOR_FAN_OFFSET);
setTurbo(false); // Turbo mode is turned off if we change the fan settings.
}
}
uint8_t IRKelvinatorAC::getFan() {
return ((remote_state[14] & ~KELVINATOR_FAN_MASK) >> KELVINATOR_FAN_OFFSET);
}
uint8_t IRKelvinatorAC::getMode() {
return (remote_state[0] & ~KELVINATOR_MODE_MASK);
}
void IRKelvinatorAC::setMode(uint8_t mode) {
// If we get an unexpected mode, default to AUTO.
if (mode > KELVINATOR_HEAT) mode = KELVINATOR_AUTO;
remote_state[0] = (remote_state[0] & KELVINATOR_MODE_MASK) | mode;
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
if (mode == KELVINATOR_AUTO || KELVINATOR_DRY)
// When the remote is set to Auto or Dry, it defaults to 25C and doesn't
// show it.
setTemp(KELVINATOR_AUTO_TEMP);
}
void IRKelvinatorAC::setSwingVertical(bool state) {
if (state) {
remote_state[0] |= KELVINATOR_VENT_SWING;
remote_state[4] |= KELVINATOR_VENT_SWING_V;
} else {
remote_state[4] &= ~KELVINATOR_VENT_SWING_V;
if (!getSwingHorizontal())
remote_state[0] &= ~KELVINATOR_VENT_SWING;
}
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
}
bool IRKelvinatorAC::getSwingVertical() {
return ((remote_state[4] & KELVINATOR_VENT_SWING_V) != 0);
}
void IRKelvinatorAC::setSwingHorizontal(bool state) {
if (state) {
remote_state[0] |= KELVINATOR_VENT_SWING;
remote_state[4] |= KELVINATOR_VENT_SWING_H;
} else {
remote_state[4] &= ~KELVINATOR_VENT_SWING_H;
if (!getSwingVertical())
remote_state[0] &= ~KELVINATOR_VENT_SWING;
}
remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk.
}
bool IRKelvinatorAC::getSwingHorizontal() {
return ((remote_state[4] & KELVINATOR_VENT_SWING_H) != 0);
}
void IRKelvinatorAC::setQuiet(bool state) {
remote_state[12] &= ~KELVINATOR_QUIET;
remote_state[12] |= (state << KELVINATOR_QUIET_OFFSET);
}
bool IRKelvinatorAC::getQuiet() {
return ((remote_state[12] & KELVINATOR_QUIET) != 0);
}
void IRKelvinatorAC::setIonFilter(bool state) {
remote_state[2] &= ~KELVINATOR_ION_FILTER;
remote_state[2] |= (state << KELVINATOR_ION_FILTER_OFFSET);
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
}
bool IRKelvinatorAC::getIonFilter() {
return ((remote_state[2] & KELVINATOR_ION_FILTER) != 0);
}
void IRKelvinatorAC::setLight(bool state) {
remote_state[2] &= ~KELVINATOR_LIGHT;
remote_state[2] |= (state << KELVINATOR_LIGHT_OFFSET);
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
}
bool IRKelvinatorAC::getLight() {
return ((remote_state[2] & KELVINATOR_LIGHT) != 0);
}
// Note: XFan mode is only valid in Cool or Dry mode.
void IRKelvinatorAC::setXFan(bool state) {
remote_state[2] &= ~KELVINATOR_XFAN;
remote_state[2] |= (state << KELVINATOR_XFAN_OFFSET);
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
}
bool IRKelvinatorAC::getXFan() {
return ((remote_state[2] & KELVINATOR_XFAN) != 0);
}
// Note: Turbo mode is turned off if the fan speed is changed.
void IRKelvinatorAC::setTurbo(bool state) {
remote_state[2] &= ~KELVINATOR_TURBO;
remote_state[2] |= (state << KELVINATOR_TURBO_OFFSET);
remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk.
}
bool IRKelvinatorAC::getTurbo() {
return ((remote_state[2] & KELVINATOR_TURBO) != 0);
}
#endif
+152
View File
@@ -0,0 +1,152 @@
// Kelvinator A/C
//
// Copyright 2016 David Conran
#ifndef IR_KELVINATOR_H_
#define IR_KELVINATOR_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include "IRremoteESP8266.h"
#include "IRsend.h"
// KK KK EEEEEEE LL VV VV IIIII NN NN AAA TTTTTTT OOOOO RRRRRR
// KK KK EE LL VV VV III NNN NN AAAAA TTT OO OO RR RR
// KKKK EEEEE LL VV VV III NN N NN AA AA TTT OO OO RRRRRR
// KK KK EE LL VV VV III NN NNN AAAAAAA TTT OO OO RR RR
// KK KK EEEEEEE LLLLLLL VVV IIIII NN NN AA AA TTT OOOO0 RR RR
// Constants
#define KELVINATOR_AUTO 0U
#define KELVINATOR_COOL 1U
#define KELVINATOR_DRY 2U
#define KELVINATOR_FAN 3U
#define KELVINATOR_HEAT 4U
#define KELVINATOR_BASIC_FAN_MAX 3U
#define KELVINATOR_FAN_MAX 5U
#define KELVINATOR_MIN_TEMP 16U // 16C
#define KELVINATOR_MAX_TEMP 30U // 30C
#define KELVINATOR_AUTO_TEMP 25U // 25C
/*
Kelvinator AC map
(header mark and space)
byte 0 = Basic Modes
b2-0 = Modes
Modes:
000 = Auto (temp = 25C)
001 = Cool
010 = Dry (temp = 25C, but not shown)
011 = Fan
100 = Heat
b3 = Power Status (1 = On, 0 = Off)
b5-4 = Fan (Basic modes)
Fan:
00 = Auto
01 = Fan 1
10 = Fan 2
11 = Fan 3 or higher (See byte 14)
b6 = Vent swing (1 = On, 0 = Off) (See byte 4)
b7 = Sleep Modes 1 & 3 (1 = On, 0 = Off)
byte 1 = Temperature
b3-0: Degrees C.
0000 (0) = 16C
0001 (1) = 17C
0010 (2) = 18C
...
1101 (13) = 29C
1110 (14) = 30C
byte 2 = Extras
b3-0 = UNKNOWN, typically 0.
b4 = Turbo Fan (1 = On, 0 = Off)
b5 = Light (Display) (1 = On, 0 = Off)
b6 = Ion Filter (1 = On, 0 = Off)
b7 = X-Fan (Fan runs for a while after power off) (1 = On, 0 = Off)
byte 3 = Section Indicator
b3-0 = Unused (Typically 0)
b5-4 = Unknown (possibly timer related) (Typically 0b01)
b7-6 = End of command block (B01)
(B010 marker and a gap of 20ms)
byte 4 = Extended options
b0 = Swing Vent Vertical (1 = On, 0 = Off)
b4 = Swing Vent Horizontal (1 = On, 0 = Off)
byte 5-6 = Timer related. Typically 0 except when timer in use.
byte 7 = checksum
b3-0 = Unknown (Used in Timer mode)
b7-4 = checksum of the previous bytes (0-6)
(gap of 40ms)
(header mark and space)
byte 8 = Repeat of byte 0
byte 9 = Repeat of byte 1
byte 10 = Repeat of byte 2
byte 11 = Section Indicator
b3-0 = Unused (Typically 0)
b5-4 = Unknown (possibly timer related) (Typically 0b11)
b7-6 = End of command block (B01)
(B010 marker and a gap of 20ms)
byte 12 = Extended options
b0 = Sleep mode 2 (1 = On, 0=Off)
b6-1 = Unknown (Used in Sleep Mode 3, Typically 0b000000)
b7 = Quiet Mode (1 = On, 0=Off)
byte 13 = Unknown (Sleep Mode 3 related, Typically 0x00)
byte 14 = Fan control
b3-0 = Unknown (Sleep Mode 3 related, Typically 0b0000)
b6-4 = Fan speed
0b000 (0) = Automatic
0b001 (1) = Fan 1
0b010 (2) = Fan 2
0b011 (3) = Fan 3
0b100 (4) = Fan 4
0b101 (5) = Fan 5
byte 15 = checksum
b3-0 = Unknown (Typically 0b0000)
b7-4 = checksum of the previous bytes (8-14)
*/
#if SEND_KELVINATOR
// Classes
class IRKelvinatorAC {
public:
explicit IRKelvinatorAC(uint16_t pin);
void stateReset();
void send();
void begin();
void on();
void off();
void setPower(bool state);
bool getPower();
void setTemp(uint8_t temp);
uint8_t getTemp();
void setFan(uint8_t fan);
uint8_t getFan();
void setMode(uint8_t mode);
uint8_t getMode();
void setSwingVertical(bool state);
bool getSwingVertical();
void setSwingHorizontal(bool state);
bool getSwingHorizontal();
void setQuiet(bool state);
bool getQuiet();
void setIonFilter(bool state);
bool getIonFilter();
void setLight(bool state);
bool getLight();
void setXFan(bool state);
bool getXFan();
void setTurbo(bool state);
bool getTurbo();
uint8_t* getRaw();
private:
// The state of the IR remote in IR code form.
uint8_t remote_state[KELVINATOR_STATE_LENGTH];
void checksum();
void fixup();
IRsend _irsend;
};
#endif
#endif // IR_KELVINATOR_H_
+233
View File
@@ -0,0 +1,233 @@
// Copyright 2015 Darryl Smith
// Copyright 2015 cheaplin
// Copyright 2017 David Conran
#include "ir_LG.h"
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// L GGGG
// L G
// L G GG
// L G G
// LLLLL GGG
// LG decode originally added by Darryl Smith (based on the JVC protocol)
// LG send originally added by https://github.com/chaeplin
// Constants
#define LG_TICK 50U
#define LG_HDR_MARK_TICKS 160U
#define LG_HDR_MARK (LG_HDR_MARK_TICKS * LG_TICK)
#define LG_HDR_SPACE_TICKS 80U
#define LG_HDR_SPACE (LG_HDR_SPACE_TICKS * LG_TICK)
#define LG_BIT_MARK_TICKS 11U
#define LG_BIT_MARK (LG_BIT_MARK_TICKS * LG_TICK)
#define LG_ONE_SPACE_TICKS 32U
#define LG_ONE_SPACE (LG_ONE_SPACE_TICKS * LG_TICK)
#define LG_ZERO_SPACE_TICKS 11U
#define LG_ZERO_SPACE (LG_ZERO_SPACE_TICKS * LG_TICK)
#define LG_RPT_SPACE_TICKS 45U
#define LG_RPT_SPACE (LG_RPT_SPACE_TICKS * LG_TICK)
#define LG_MIN_GAP_TICKS 795U
#define LG_MIN_GAP (LG_MIN_GAP_TICKS * LG_TICK)
#define LG_MIN_MESSAGE_LENGTH_TICKS 2161U
#define LG_MIN_MESSAGE_LENGTH (LG_MIN_MESSAGE_LENGTH_TICKS * LG_TICK)
#define LG32_HDR_MARK_TICKS 90U
#define LG32_HDR_MARK (LG32_HDR_MARK_TICKS * LG_TICK)
#define LG32_HDR_SPACE_TICKS 89U
#define LG32_HDR_SPACE (LG32_HDR_SPACE_TICKS * LG_TICK)
#define LG32_RPT_HDR_MARK_TICKS 179U
#define LG32_RPT_HDR_MARK (LG32_RPT_HDR_MARK_TICKS * LG_TICK)
#if (SEND_LG || DECODE_LG)
// Calculate the rolling 4-bit wide checksum over all of the data.
// Args:
// data: The value to be checksum'ed.
// Returns:
// A 4-bit checksum.
uint8_t calcLGChecksum(uint16_t data) {
return(((data >> 12) + ((data >> 8) & 0xF) + ((data >> 4) & 0xF) +
(data & 0xF)) & 0xF);
}
#endif
#if SEND_LG
// Send an LG formatted message.
//
// Args:
// data: The contents of the message you want to send.
// nbits: The bit size of the message being sent.
// Typically LG_BITS or LG32_BITS.
// repeat: The number of times you want the message to be repeated.
//
// Status: Beta / Should be working.
//
// Notes:
// LG has a separate message to indicate a repeat, like NEC does.
void IRsend::sendLG(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set IR carrier frequency
enableIROut(38);
uint16_t repeatHeaderMark = 0;
IRtimer usecTimer = IRtimer();
if (nbits >= LG32_BITS) {
// LG 32bit protocol is near identical to Samsung except for repeats.
sendSAMSUNG(data, nbits, 0); // Send it as a single Samsung message.
repeatHeaderMark = LG32_RPT_HDR_MARK;
repeat++;
} else {
// LG (28-bit) protocol.
repeatHeaderMark = LG_HDR_MARK;
// Header
usecTimer.reset();
mark(LG_HDR_MARK);
space(LG_HDR_SPACE);
// Data
sendData(LG_BIT_MARK, LG_ONE_SPACE, LG_BIT_MARK, LG_ZERO_SPACE,
data, nbits, true);
// Footer
mark(LG_BIT_MARK);
space(std::max((uint32_t) (LG_MIN_MESSAGE_LENGTH - usecTimer.elapsed()),
(uint32_t) LG_MIN_GAP));
}
// Repeat
// Protocol has a mandatory repeat-specific code sent after every command.
for (uint16_t i = 0; i < repeat; i++) {
usecTimer.reset();
mark(repeatHeaderMark);
space(LG_RPT_SPACE);
mark(LG_BIT_MARK);
space(std::max((uint32_t) LG_MIN_MESSAGE_LENGTH - usecTimer.elapsed(),
(uint32_t) LG_MIN_GAP));
}
}
// Construct a raw 28-bit LG message from the supplied address & command.
//
// Args:
// address: The address code.
// command: The command code.
// Returns:
// A raw 28-bit LG message suitable for sendLG().
//
// Status: BETA / Should work.
//
// Notes:
// e.g. Sequence of bits = address + command + checksum.
uint32_t IRsend::encodeLG(uint16_t address, uint16_t command) {
return ((address << 20) | (command << 4) | calcLGChecksum(command));
}
#endif
#if DECODE_LG
// Decode the supplied LG message.
// LG protocol has a repeat code which is 4 items long.
// Even though the protocol has 28/32 bits of data, only 24/28 bits are
// distinct.
// In transmission order, the 28/32 bits are constructed as follows:
// 8/12 bits of address + 16 bits of command + 4 bits of checksum.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of bits to expect in the data portion.
// Typically LG_BITS or LG32_BITS.
// strict: Flag to indicate if we strictly adhere to the specification.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should work.
//
// Note:
// LG 32bit protocol appears near identical to the Samsung protocol.
// They possibly differ on how they repeat and initial HDR mark.
// Ref:
// https://funembedded.wordpress.com/2014/11/08/ir-remote-control-for-lg-conditioner-using-stm32f302-mcu-on-mbed-platform/
bool IRrecv::decodeLG(decode_results *results, uint16_t nbits, bool strict) {
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1 && results->rawlen != 4)
return false; // Can't possibly be a valid LG message.
if (strict && nbits != LG_BITS && nbits != LG32_BITS)
return false; // Doesn't comply with expected LG protocol.
uint64_t data = 0;
uint16_t offset = OFFSET_START;
// Header
if (!matchMark(results->rawbuf[offset], LG_HDR_MARK) &&
!matchMark(results->rawbuf[offset], LG32_HDR_MARK)) return false;
uint32_t m_tick;
if (matchMark(results->rawbuf[offset], LG_HDR_MARK))
m_tick = results->rawbuf[offset++] * RAWTICK / LG_HDR_MARK_TICKS;
else
m_tick = results->rawbuf[offset++] * RAWTICK / LG32_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], LG_HDR_SPACE) &&
!matchSpace(results->rawbuf[offset], LG32_HDR_SPACE)) return false;
uint32_t s_tick;
if (matchSpace(results->rawbuf[offset], LG_HDR_SPACE))
s_tick = results->rawbuf[offset++] * RAWTICK / LG_HDR_SPACE_TICKS;
else
s_tick = results->rawbuf[offset++] * RAWTICK / LG32_HDR_SPACE_TICKS;
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
LG_BIT_MARK_TICKS * m_tick,
LG_ONE_SPACE_TICKS * s_tick,
LG_BIT_MARK_TICKS * m_tick,
LG_ZERO_SPACE_TICKS * s_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!matchMark(results->rawbuf[offset++], LG_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], LG_MIN_GAP_TICKS * s_tick))
return false;
// Repeat
if (nbits >= LG32_BITS) {
// If we are expecting the LG 32-bit protocol, there is always
// a repeat message. So, check for it.
#ifndef UNIT_TEST
if (!matchSpace(results->rawbuf[offset], LG_MIN_GAP_TICKS * s_tick))
#else
if (!(matchSpace(results->rawbuf[offset],
LG_MIN_MESSAGE_LENGTH_TICKS * s_tick) ||
matchSpace(results->rawbuf[offset], 65500) ||
matchSpace(results->rawbuf[offset], LG_MIN_GAP_TICKS * s_tick)))
#endif // UNIT_TEST
return false;
offset++;
if (!matchMark(results->rawbuf[offset++], LG32_RPT_HDR_MARK_TICKS * m_tick))
return false;
if (!matchSpace(results->rawbuf[offset++], LG_RPT_SPACE_TICKS * s_tick))
return false;
if (!matchMark(results->rawbuf[offset++], LG_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], LG_MIN_GAP_TICKS * s_tick))
return false;
}
// Compliance
uint16_t command = (data >> 4) & 0xFFFF; // The 16 bits before the checksum.
if (strict && (data & 0xF) != calcLGChecksum(command))
return false; // The last 4 bits sent are the expected checksum.
// Success
results->decode_type = LG;
results->bits = nbits;
results->value = data;
results->command = command;
results->address = data >> 20; // The bits before the command.
return true;
}
#endif
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2017 David Conran
#ifndef IR_LG_H_
#define IR_LG_H_
// L GGGG
// L G
// L G GG
// L G G
// LLLLL GGG
#define __STDC_LIMIT_MACROS
#include <stdint.h>
uint8_t calcLGChecksum(uint16_t data);
#endif // IR_LG_H_
+349
View File
@@ -0,0 +1,349 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
#include "ir_Mitsubishi.h"
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// MMMMM IIIII TTTTT SSSS U U BBBB IIIII SSSS H H IIIII
// M M M I T S U U B B I S H H I
// M M M I T SSS U U BBBB I SSS HHHHH I
// M M I T S U U B B I S H H I
// M M IIIII T SSSS UUU BBBBB IIIII SSSS H H IIIII
// Mitsubishi (TV) decoding added from https://github.com/z3t0/Arduino-IRremote
// Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran
// Constants
// Mitsubishi TV
// period time is 1/33000Hz = 30.303 uSeconds (T)
// Ref:
// GlobalCache's Control Tower's Mitsubishi TV data.
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Mitsubishi.cpp
#define MITSUBISHI_TICK 30U
#define MITSUBISHI_BIT_MARK_TICKS 10U
#define MITSUBISHI_BIT_MARK (MITSUBISHI_BIT_MARK_TICKS * \
MITSUBISHI_TICK)
#define MITSUBISHI_ONE_SPACE_TICKS 70U
#define MITSUBISHI_ONE_SPACE (MITSUBISHI_ONE_SPACE_TICKS * \
MITSUBISHI_TICK)
#define MITSUBISHI_ZERO_SPACE_TICKS 30U
#define MITSUBISHI_ZERO_SPACE (MITSUBISHI_ZERO_SPACE_TICKS * \
MITSUBISHI_TICK)
#define MITSUBISHI_MIN_COMMAND_LENGTH_TICKS 1786U
#define MITSUBISHI_MIN_COMMAND_LENGTH (MITSUBISHI_MIN_COMMAND_LENGTH_TICKS * \
MITSUBISHI_TICK)
#define MITSUBISHI_MIN_GAP_TICKS 936U
#define MITSUBISHI_MIN_GAP (MITSUBISHI_MIN_GAP_TICKS * \
MITSUBISHI_TICK)
// Mitsubishi A/C
// Ref:
// https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L84
#define MITSUBISHI_AC_HDR_MARK 3400U
#define MITSUBISHI_AC_HDR_SPACE 1750U
#define MITSUBISHI_AC_BIT_MARK 450U
#define MITSUBISHI_AC_ONE_SPACE 1300U
#define MITSUBISHI_AC_ZERO_SPACE 420U
#define MITSUBISHI_AC_RPT_MARK 440U
#define MITSUBISHI_AC_RPT_SPACE 17100UL
#if SEND_MITSUBISHI
// Send a Mitsubishi message
//
// Args:
// data: Contents of the message to be sent.
// nbits: Nr. of bits of data to be sent. Typically MITSUBISHI_BITS.
// repeat: Nr. of additional times the message is to be sent.
//
// Status: ALPHA / untested.
//
// Notes:
// This protocol appears to have no header.
// Ref:
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Mitsubishi.cpp
// GlobalCache's Control Tower's Mitsubishi TV data.
void IRsend::sendMitsubishi(uint64_t data, uint16_t nbits, uint16_t repeat) {
enableIROut(33); // Set IR carrier frequency
IRtimer usecTimer = IRtimer();
for (uint16_t i = 0; i <= repeat; i++) {
usecTimer.reset();
// No header
// Data
sendData(MITSUBISHI_BIT_MARK, MITSUBISHI_ONE_SPACE,
MITSUBISHI_BIT_MARK, MITSUBISHI_ZERO_SPACE,
data, nbits, true);
// Footer
mark(MITSUBISHI_BIT_MARK);
space(std::max(MITSUBISHI_MIN_COMMAND_LENGTH - usecTimer.elapsed(),
MITSUBISHI_MIN_GAP));
}
}
#endif
#if DECODE_MITSUBISHI
// Decode the supplied Mitsubishi message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / previously working.
//
// Notes:
// This protocol appears to have no header.
//
// Ref:
// GlobalCache's Control Tower's Mitsubishi TV data.
bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits,
bool strict) {
if (results->rawlen < 2 * nbits + FOOTER - 1)
return false; // Shorter than shortest possibly expected.
if (strict && nbits != MITSUBISHI_BITS)
return false; // Request is out of spec.
uint16_t offset = OFFSET_START;
uint64_t data = 0;
// No Header
// But try to auto-calibrate off the initial mark signal.
if (!matchMark(results->rawbuf[offset], MITSUBISHI_BIT_MARK, 30))
return false;
// Calculate how long the common tick time is based on the initial mark.
uint32_t tick = results->rawbuf[offset] * RAWTICK / MITSUBISHI_BIT_MARK_TICKS;
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
MITSUBISHI_BIT_MARK_TICKS * tick,
MITSUBISHI_ONE_SPACE_TICKS * tick,
MITSUBISHI_BIT_MARK_TICKS * tick,
MITSUBISHI_ZERO_SPACE_TICKS * tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
uint16_t actualBits = data_result.used / 2;
// Footer
if (!matchMark(results->rawbuf[offset++], MITSUBISHI_BIT_MARK_TICKS * tick,
30)) return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], MITSUBISHI_MIN_GAP_TICKS * tick))
return false;
// Compliance
if (actualBits < nbits)
return false;
if (strict && actualBits != nbits)
return false; // Not as we expected.
// Success
results->decode_type = MITSUBISHI;
results->bits = actualBits;
results->value = data;
results->address = 0;
results->command = 0;
return true;
}
#endif
#if SEND_MITSUBISHI_AC
// Send a Mitsubishi A/C message.
//
// Args:
// data: An array of bytes containing the IR command.
// nbytes: Nr. of bytes of data in the array. (>=MITSUBISHI_AC_STATE_LENGTH)
// repeat: Nr. of times the message is to be repeated.
// (Default = MITSUBISHI_AC_MIN_REPEAT).
//
// Status: BETA / Appears to be working.
//
void IRsend::sendMitsubishiAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
if (nbytes < MITSUBISHI_AC_STATE_LENGTH)
return; // Not enough bytes to send a proper message.
// Set IR carrier frequency
enableIROut(38);
// Mitsubishi AC remote sends the packet twice.
for (uint16_t r = 0; r <= repeat; r++) {
// Header
mark(MITSUBISHI_AC_HDR_MARK);
space(MITSUBISHI_AC_HDR_SPACE);
// Data
for (uint16_t i = 0; i < nbytes; i++)
sendData(MITSUBISHI_AC_BIT_MARK, MITSUBISHI_AC_ONE_SPACE,
MITSUBISHI_AC_BIT_MARK, MITSUBISHI_AC_ZERO_SPACE,
data[i], 8, false);
// Footer
mark(MITSUBISHI_AC_RPT_MARK);
space(MITSUBISHI_AC_RPT_SPACE);
}
}
// Code to emulate Mitsubishi A/C IR remote control unit.
// Inspired and derived from the work done at:
// https://github.com/r45635/HVAC-IR-Control
//
// Warning: Consider this very alpha code. Seems to work, but not validated.
//
// Equipment it seems compatible with:
// * <Add models (A/C & remotes) you've gotten it working with here>
// Initialise the object.
IRMitsubishiAC::IRMitsubishiAC(uint16_t pin) : _irsend(pin) {
stateReset();
}
// Reset the state of the remote to a known good state/sequence.
void IRMitsubishiAC::stateReset() {
// The state of the IR remote in IR code form.
// Known good state obtained from:
// https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L108
// Note: Can't use the following because it requires -std=c++11
// uint8_t known_good_state[MITSUBISHI_AC_STATE_LENGTH] = {
// 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F};
remote_state[0] = 0x23;
remote_state[1] = 0xCB;
remote_state[2] = 0x26;
remote_state[3] = 0x01;
remote_state[4] = 0x00;
remote_state[5] = 0x20;
remote_state[6] = 0x08;
remote_state[7] = 0x06;
remote_state[8] = 0x30;
remote_state[9] = 0x45;
remote_state[10] = 0x67;
for (uint8_t i = 11; i < MITSUBISHI_AC_STATE_LENGTH - 1; i++)
remote_state[i] = 0;
remote_state[MITSUBISHI_AC_STATE_LENGTH - 1] = 0x1F;
checksum(); // Calculate the checksum
}
// Configure the pin for output.
void IRMitsubishiAC::begin() {
_irsend.begin();
}
// Send the current desired state to the IR LED.
void IRMitsubishiAC::send() {
checksum(); // Ensure correct checksum before sending.
_irsend.sendMitsubishiAC(remote_state);
}
// Return a pointer to the internal state date of the remote.
uint8_t* IRMitsubishiAC::getRaw() {
checksum();
return remote_state;
}
// Calculate the checksum for the current internal state of the remote.
void IRMitsubishiAC::checksum() {
uint8_t sum = 0;
// Checksum is simple addition of all previous bytes stored
// as a 8 bit value.
for (uint8_t i = 0; i < 17; i++)
sum += remote_state[i];
remote_state[17] = sum & 0xFFU;
}
// Set the requested power state of the A/C to off.
void IRMitsubishiAC::on() {
// state = ON;
remote_state[5] |= MITSUBISHI_AC_POWER;
}
// Set the requested power state of the A/C to off.
void IRMitsubishiAC::off() {
// state = OFF;
remote_state[5] &= ~MITSUBISHI_AC_POWER;
}
// Set the requested power state of the A/C.
void IRMitsubishiAC::setPower(bool state) {
if (state)
on();
else
off();
}
// Return the requested power state of the A/C.
bool IRMitsubishiAC::getPower() {
return((remote_state[5] & MITSUBISHI_AC_POWER) != 0);
}
// Set the temp. in deg C
void IRMitsubishiAC::setTemp(uint8_t temp) {
temp = std::max((uint8_t) MITSUBISHI_AC_MIN_TEMP, temp);
temp = std::min((uint8_t) MITSUBISHI_AC_MAX_TEMP, temp);
remote_state[7] = temp - MITSUBISHI_AC_MIN_TEMP;
}
// Return the set temp. in deg C
uint8_t IRMitsubishiAC::getTemp() {
return(remote_state[7] + MITSUBISHI_AC_MIN_TEMP);
}
// Set the speed of the fan, 0-6.
// 0 is auto, 1-5 is the speed, 6 is silent.
void IRMitsubishiAC::setFan(uint8_t fan) {
// Bounds check
if (fan > MITSUBISHI_AC_FAN_SILENT)
fan = MITSUBISHI_AC_FAN_MAX; // Set the fan to maximum if out of range.
if (fan == MITSUBISHI_AC_FAN_AUTO) { // Automatic is a special case.
remote_state[9] = 0b10000000 | (remote_state[9] & 0b01111000);
return;
} else if (fan >= MITSUBISHI_AC_FAN_MAX) {
fan--; // There is no spoon^H^H^Heed 5 (max), pretend it doesn't exist.
}
remote_state[9] &= 0b01111000; // Clear the previous state
remote_state[9] |= fan;
}
// Return the requested state of the unit's fan.
uint8_t IRMitsubishiAC::getFan() {
uint8_t fan = remote_state[9] & 0b111;
if (fan == MITSUBISHI_AC_FAN_MAX)
return MITSUBISHI_AC_FAN_SILENT;
return fan;
}
// Return the requested climate operation mode of the a/c unit.
uint8_t IRMitsubishiAC::getMode() {
return(remote_state[6]);
}
// Set the requested climate operation mode of the a/c unit.
void IRMitsubishiAC::setMode(uint8_t mode) {
// If we get an unexpected mode, default to AUTO.
switch (mode) {
case MITSUBISHI_AC_AUTO: break;
case MITSUBISHI_AC_COOL: break;
case MITSUBISHI_AC_DRY: break;
case MITSUBISHI_AC_HEAT: break;
default: mode = MITSUBISHI_AC_AUTO;
}
remote_state[6] = mode;
}
// Set the requested vane operation mode of the a/c unit.
void IRMitsubishiAC::setVane(uint8_t mode) {
mode = std::min(mode, (uint8_t) 0b111); // bounds check
mode |= 0b1000;
mode <<= 3;
remote_state[9] &= 0b11000111; // Clear the previous setting.
remote_state[9] |= mode;
}
// Return the requested vane operation mode of the a/c unit.
uint8_t IRMitsubishiAC::getVane() {
return ((remote_state[9] & 0b00111000) >> 3);
}
#endif
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
#ifndef IR_MITSUBISHI_H_
#define IR_MITSUBISHI_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include "IRremoteESP8266.h"
#include "IRsend.h"
// MMMMM IIIII TTTTT SSSS U U BBBB IIIII SSSS H H IIIII
// M M M I T S U U B B I S H H I
// M M M I T SSS U U BBBB I SSS HHHHH I
// M M I T S U U B B I S H H I
// M M IIIII T SSSS UUU BBBBB IIIII SSSS H H IIIII
// Mitsubishi (TV) decoding added from https://github.com/z3t0/Arduino-IRremote
// Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran
// Constants
#define MITSUBISHI_AC_AUTO 0x20U
#define MITSUBISHI_AC_COOL 0x18U
#define MITSUBISHI_AC_DRY 0x10U
#define MITSUBISHI_AC_HEAT 0x08U
#define MITSUBISHI_AC_POWER 0x20U
#define MITSUBISHI_AC_FAN_AUTO 0U
#define MITSUBISHI_AC_FAN_MAX 5U
#define MITSUBISHI_AC_FAN_REAL_MAX 4U
#define MITSUBISHI_AC_FAN_SILENT 6U
#define MITSUBISHI_AC_MIN_TEMP 16U // 16C
#define MITSUBISHI_AC_MAX_TEMP 31U // 31C
#define MITSUBISHI_AC_VANE_AUTO 0U
#define MITSUBISHI_AC_VANE_AUTO_MOVE 7U
#if SEND_MITSUBISHI_AC
class IRMitsubishiAC {
public:
explicit IRMitsubishiAC(uint16_t pin);
void stateReset();
void send();
void begin();
void on();
void off();
void setPower(bool state);
bool getPower();
void setTemp(uint8_t temp);
uint8_t getTemp();
void setFan(uint8_t fan);
uint8_t getFan();
void setMode(uint8_t mode);
uint8_t getMode();
void setVane(uint8_t mode);
uint8_t getVane();
uint8_t* getRaw();
private:
uint8_t remote_state[MITSUBISHI_AC_STATE_LENGTH];
void checksum();
IRsend _irsend;
};
#endif
#endif // IR_MITSUBISHI_H_
+210
View File
@@ -0,0 +1,210 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// N N EEEEE CCCC
// NN N E C
// N N N EEE C
// N NN E C
// N N EEEEE CCCC
// NEC originally added from https://github.com/shirriff/Arduino-IRremote/
// Constants
// Ref:
// http://www.sbprojects.com/knowledge/ir/nec.php
#define NEC_TICK 560U
#define NEC_HDR_MARK_TICKS 16U
#define NEC_HDR_MARK (NEC_HDR_MARK_TICKS * NEC_TICK)
#define NEC_HDR_SPACE_TICKS 8U
#define NEC_HDR_SPACE (NEC_HDR_SPACE_TICKS * NEC_TICK)
#define NEC_BIT_MARK_TICKS 1U
#define NEC_BIT_MARK (NEC_BIT_MARK_TICKS * NEC_TICK)
#define NEC_ONE_SPACE_TICKS 3U
#define NEC_ONE_SPACE (NEC_TICK * NEC_ONE_SPACE_TICKS)
#define NEC_ZERO_SPACE_TICKS 1U
#define NEC_ZERO_SPACE (NEC_TICK * NEC_ZERO_SPACE_TICKS)
#define NEC_RPT_SPACE_TICKS 4U
#define NEC_RPT_SPACE (NEC_RPT_SPACE_TICKS * NEC_TICK)
#define NEC_RPT_LENGTH 4U
#define NEC_MIN_COMMAND_LENGTH_TICKS 193U
#define NEC_MIN_COMMAND_LENGTH (NEC_MIN_COMMAND_LENGTH_TICKS * NEC_TICK)
#define NEC_MIN_GAP (NEC_MIN_COMMAND_LENGTH - \
(NEC_HDR_MARK + NEC_HDR_SPACE + NEC_BITS * (NEC_BIT_MARK + NEC_ONE_SPACE) \
+ NEC_BIT_MARK))
#define NEC_MIN_GAP_TICKS (NEC_MIN_COMMAND_LENGTH_TICKS - \
(NEC_HDR_MARK_TICKS + NEC_HDR_SPACE_TICKS + \
NEC_BITS * (NEC_BIT_MARK_TICKS + NEC_ONE_SPACE_TICKS) + \
NEC_BIT_MARK_TICKS))
#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO)
// Send a raw NEC(Renesas) formatted message.
//
// Args:
// data: The message to be sent.
// nbits: The number of bits of the message to be sent. Typically NEC_BITS.
// repeat: The number of times the command is to be repeated.
//
// Status: STABLE / Known working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/nec.php
void IRsend::sendNEC(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set 38kHz IR carrier frequency & a 1/3 (33%) duty cycle.
enableIROut(38, 33);
IRtimer usecs = IRtimer();
// Header
mark(NEC_HDR_MARK);
space(NEC_HDR_SPACE);
// Data
sendData(NEC_BIT_MARK, NEC_ONE_SPACE, NEC_BIT_MARK, NEC_ZERO_SPACE,
data, nbits, true);
// Footer
mark(NEC_BIT_MARK);
// Gap to next command.
space(std::max(NEC_MIN_GAP, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
// Optional command repeat sequence.
for (uint16_t i = 0; i < repeat; i++) {
usecs.reset();
mark(NEC_HDR_MARK);
space(NEC_RPT_SPACE);
mark(NEC_BIT_MARK);
// Gap till next command.
space(std::max(NEC_MIN_GAP, NEC_MIN_COMMAND_LENGTH - usecs.elapsed()));
}
}
// Calculate the raw NEC data based on address and command.
// Args:
// address: An address value.
// command: An 8-bit command value.
// Returns:
// A raw 32-bit NEC message.
//
// Status: BETA / Expected to work.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/nec.php
uint32_t IRsend::encodeNEC(uint16_t address, uint16_t command) {
command &= 0xFF; // We only want the least significant byte of command.
// sendNEC() sends MSB first, but protocol says this is LSB first.
command = reverseBits(command, 8);
command = (command << 8) + (command ^ 0xFF); // Calculate the new command.
if (address > 0xFF) { // Is it Extended NEC?
address = reverseBits(address, 16);
return ((address << 16) + command); // Extended.
} else {
address = reverseBits(address, 8);
return (address << 24) + ((address ^ 0xFF) << 16) + command; // Normal.
}
}
#endif
#if (DECODE_NEC || DECODE_SHERWOOD || DECODE_AIWA_RC_T501 || DECODE_SANYO)
// Decode the supplied NEC message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: The number of data bits to expect. Typically NEC_BITS.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: STABLE / Known good.
//
// Notes:
// NEC protocol has three varients/forms.
// Normal: a 8 bit address & a 8 bit command in 32 bit data form.
// i.e. address + inverted(address) + command + inverted(command)
// Extended: a 16 bit address & a 8 bit command in 32 bit data form.
// i.e. address + command + inverted(command)
// Repeat: a 0-bit code. i.e. No data bits. Just the header + footer.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/nec.php
bool IRrecv::decodeNEC(decode_results *results, uint16_t nbits, bool strict) {
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1 &&
results->rawlen != NEC_RPT_LENGTH)
return false; // Can't possibly be a valid NEC message.
if (strict && nbits != NEC_BITS)
return false; // Not strictly an NEC message.
uint64_t data = 0;
uint16_t offset = OFFSET_START;
// Header
if (!matchMark(results->rawbuf[offset], NEC_HDR_MARK)) return false;
// Calculate how long the lowest tick time is based on the header mark.
uint32_t mark_tick = results->rawbuf[offset++] * RAWTICK /
NEC_HDR_MARK_TICKS;
// Check if it is a repeat code.
if (results->rawlen == NEC_RPT_LENGTH &&
matchSpace(results->rawbuf[offset], NEC_RPT_SPACE) &&
matchMark(results->rawbuf[offset + 1], NEC_BIT_MARK_TICKS * mark_tick)) {
results->value = REPEAT;
results->decode_type = NEC;
results->bits = 0;
results->address = 0;
results->command = 0;
results->repeat = true;
return true;
}
// Header (cont.)
if (!matchSpace(results->rawbuf[offset], NEC_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t space_tick = results->rawbuf[offset++] * RAWTICK /
NEC_HDR_SPACE_TICKS;
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
NEC_BIT_MARK_TICKS * mark_tick,
NEC_ONE_SPACE_TICKS * space_tick,
NEC_BIT_MARK_TICKS * mark_tick,
NEC_ZERO_SPACE_TICKS * space_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!matchMark(results->rawbuf[offset++], NEC_BIT_MARK_TICKS * mark_tick))
return false;
if (offset <= results->rawlen &&
!matchAtLeast(results->rawbuf[offset], NEC_MIN_GAP_TICKS * space_tick))
return false;
// Compliance
// Calculate command and optionally enforce integrity checking.
uint8_t command = (data & 0xFF00) >> 8;
// Command is sent twice, once as plain and then inverted.
if ((command ^ 0xFF) != (data & 0xFF)) {
if (strict)
return false; // Command integrity failed.
command = 0; // The command value isn't valid, so default to zero.
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = NEC;
// NEC command and address are technically in LSB first order so the
// final versions have to be reversed.
results->command = reverseBits(command, 8);
// Normal NEC protocol has an 8 bit address sent, followed by it inverted.
uint8_t address = (data & 0xFF000000) >> 24;
uint8_t address_inverted = (data & 0x00FF0000) >> 16;
if (address == (address_inverted ^ 0xFF))
// Inverted, so it is normal NEC protocol.
results->address = reverseBits(address, 8);
else // Not inverted, so must be Extended NEC protocol, thus 16 bit address.
results->address = reverseBits((data >> 16) & UINT16_MAX, 16);
return true;
}
#endif
+196
View File
@@ -0,0 +1,196 @@
// Copyright 2015 Kristian Lauszus
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// PPPP AAA N N AAA SSSS OOO N N IIIII CCCC
// P P A A NN N A A S O O NN N I C
// PPPP AAAAA N N N AAAAA SSS O O N N N I C
// P A A N NN A A S O O N NN I C
// P A A N N A A SSSS OOO N N IIIII CCCC
// Panasonic protocol originally added by Kristian Lauszus from:
// https://github.com/z3t0/Arduino-IRremote
// (Thanks to zenwheel and other people at the original blog post)
// Constants
// Ref:
// http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152
#define PANASONIC_TICK 432U
#define PANASONIC_HDR_MARK_TICKS 8U
#define PANASONIC_HDR_MARK (PANASONIC_HDR_MARK_TICKS * PANASONIC_TICK)
#define PANASONIC_HDR_SPACE_TICKS 4U
#define PANASONIC_HDR_SPACE (PANASONIC_HDR_SPACE_TICKS * PANASONIC_TICK)
#define PANASONIC_BIT_MARK_TICKS 1U
#define PANASONIC_BIT_MARK (PANASONIC_BIT_MARK_TICKS * PANASONIC_TICK)
#define PANASONIC_ONE_SPACE_TICKS 3U
#define PANASONIC_ONE_SPACE (PANASONIC_ONE_SPACE_TICKS * PANASONIC_TICK)
#define PANASONIC_ZERO_SPACE_TICKS 1U
#define PANASONIC_ZERO_SPACE (PANASONIC_ZERO_SPACE_TICKS * PANASONIC_TICK)
#define PANASONIC_MIN_COMMAND_LENGTH_TICKS 300UL
#define PANASONIC_MIN_COMMAND_LENGTH (PANASONIC_MIN_COMMAND_LENGTH_TICKS * \
PANASONIC_TICK)
#define PANASONIC_END_GAP 5000U // See issue #245
#define PANASONIC_MIN_GAP_TICKS (PANASONIC_MIN_COMMAND_LENGTH_TICKS - \
(PANASONIC_HDR_MARK_TICKS + PANASONIC_HDR_SPACE_TICKS + \
PANASONIC_BITS * (PANASONIC_BIT_MARK_TICKS + PANASONIC_ONE_SPACE_TICKS) + \
PANASONIC_BIT_MARK_TICKS))
#define PANASONIC_MIN_GAP ((uint32_t)(PANASONIC_MIN_GAP_TICKS * PANASONIC_TICK))
#if (SEND_PANASONIC || SEND_DENON)
// Send a Panasonic formatted message.
//
// Args:
// data: The message to be sent.
// nbits: The number of bits of the message to be sent. (PANASONIC_BITS).
// repeat: The number of times the command is to be repeated.
//
// Status: BETA / Should be working.
//
// Note:
// This protocol is a modified version of Kaseikyo.
void IRsend::sendPanasonic64(uint64_t data, uint16_t nbits, uint16_t repeat) {
enableIROut(36700U); // Set IR carrier frequency of 36.7kHz.
IRtimer usecTimer = IRtimer();
for (uint16_t i = 0; i <= repeat; i++) {
usecTimer.reset();
// Header
mark(PANASONIC_HDR_MARK);
space(PANASONIC_HDR_SPACE);
// Data
sendData(PANASONIC_BIT_MARK, PANASONIC_ONE_SPACE,
PANASONIC_BIT_MARK, PANASONIC_ZERO_SPACE,
data, nbits, true);
// Footer
mark(PANASONIC_BIT_MARK);
space(std::max((uint32_t) PANASONIC_MIN_COMMAND_LENGTH -
usecTimer.elapsed(),
PANASONIC_MIN_GAP));
}
}
// Send a Panasonic formatted message.
//
// Args:
// address: The manufacturer code.
// data: The data portion to be sent.
// nbits: The number of bits of the message to be sent. (PANASONIC_BITS).
// repeat: The number of times the command is to be repeated.
//
// Status: STABLE.
//
// Note:
// This protocol is a modified version of Kaseikyo.
void IRsend::sendPanasonic(uint16_t address, uint32_t data, uint16_t nbits,
uint16_t repeat) {
sendPanasonic64(((uint64_t) address << 32) | (uint64_t) data, nbits, repeat);
}
// Calculate the raw Panasonic data based on device, subdevice, & function.
//
// Args:
// manufacturer: A 16-bit manufacturer code. e.g. 0x4004 is Panasonic.
// device: An 8-bit code.
// subdevice: An 8-bit code.
// function: An 8-bit code.
// Returns:
// A raw uint64_t Panasonic message.
//
// Status: BETA / Should be working..
//
// Note:
// Panasonic 48-bit protocol is a modified version of Kaseikyo.
// Ref:
// http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?2615
uint64_t IRsend::encodePanasonic(uint16_t manufacturer,
uint8_t device,
uint8_t subdevice,
uint8_t function) {
uint8_t checksum = device ^ subdevice ^ function;
return (((uint64_t) manufacturer << 32) |
((uint64_t) device << 24) |
((uint64_t) subdevice << 16) |
((uint64_t) function << 8) |
checksum);
}
#endif // (SEND_PANASONIC || SEND_DENON)
#if (DECODE_PANASONIC || DECODE_DENON)
// Decode the supplied Panasonic message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should be working.
// Note:
// Panasonic 48-bit protocol is a modified version of Kaseikyo.
// Ref:
// http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152
// http://www.hifi-remote.com/wiki/index.php?title=Panasonic
bool IRrecv::decodePanasonic(decode_results *results, uint16_t nbits,
bool strict, uint32_t manufacturer) {
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1)
return false; // Not enough entries to be a Panasonic message.
if (strict && nbits != PANASONIC_BITS)
return false; // Request is out of spec.
uint64_t data = 0;
uint16_t offset = OFFSET_START;
// Header
if (!matchMark(results->rawbuf[offset], PANASONIC_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK /
PANASONIC_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], PANASONIC_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
PANASONIC_HDR_SPACE_TICKS;
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
PANASONIC_BIT_MARK_TICKS * m_tick,
PANASONIC_ONE_SPACE_TICKS * s_tick,
PANASONIC_BIT_MARK_TICKS * m_tick,
PANASONIC_ZERO_SPACE_TICKS * s_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!match(results->rawbuf[offset++], PANASONIC_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], PANASONIC_END_GAP))
return false;
// Compliance
uint32_t address = data >> 32;
uint32_t command = data & 0xFFFFFFFF;
if (strict) {
if (address != manufacturer) // Verify the Manufacturer code.
return false;
// Verify the checksum.
uint8_t checksumOrig = data & 0xFF;
uint8_t checksumCalc = ((data >> 24) ^ (data >> 16) ^ (data >> 8)) & 0xFF;
if (checksumOrig != checksumCalc)
return false;
}
// Success
results->value = data;
results->address = address;
results->command = command;
results->decode_type = PANASONIC;
results->bits = nbits;
return true;
}
#endif // (DECODE_PANASONIC || DECODE_DENON)
+109
View File
@@ -0,0 +1,109 @@
// Copyright 2017 David Conran
#include <algorithm>
#include "IRsend.h"
#include "IRtimer.h"
// PPPPPP tt
// PP PP rr rr oooo nn nnn tt oooo
// PPPPPP rrr r oo oo nnn nn tttt oo oo
// PP rr oo oo nn nn tt oo oo
// PP rr oooo nn nn tttt oooo
// Constants
#define PRONTO_FREQ_FACTOR 0.241246
#define PRONTO_TYPE_OFFSET 0U
#define PRONTO_FREQ_OFFSET 1U
#define PRONTO_SEQ_1_LEN_OFFSET 2U
#define PRONTO_SEQ_2_LEN_OFFSET 3U
#define PRONTO_DATA_OFFSET 4U
#if SEND_PRONTO
// Send a Pronto Code formatted message.
//
// Args:
// data: An array of uint16_t containing the pronto codes.
// len: Nr. of entries in the data[] array.
// repeat: Nr. of times to repeat the message.
//
// Status: ALPHA / Not tested in the real world.
//
// Note:
// Pronto codes are typically represented in hexadecimal.
// You will need to convert the code to an array of integers, and calculate
// it's length.
// e.g.
// A Sony 20 bit DVD remote command.
// "0000 0067 0000 0015 0060 0018 0018 0018 0030 0018 0030 0018 0030 0018
// 0018 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 0018 0030 0018
// 0030 0018 0030 0018 0018 0018 0018 0018 0030 0018 0018 0018 0018 0018
// 0030 0018 0018 03f6"
//
// converts to:
//
// uint16_t prontoCode[46] = {
// 0x0000, 0x0067, 0x0000, 0x0015,
// 0x0060, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0030, 0x0018,
// 0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018,
// 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018,
// 0x0030, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
// 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018,
// 0x0018, 0x03f6};
// // Send the Pronto(Sony) code. Repeat twice as Sony's require that.
// sendPronto(prontoCode, 46, SONY_MIN_REPEAT);
//
// Ref:
// http://www.etcwiki.org/wiki/Pronto_Infrared_Format
// http://www.remotecentral.com/features/irdisp2.htm
void IRsend::sendPronto(uint16_t data[], uint16_t len, uint16_t repeat) {
// Check we have enough data to work out what to send.
if (len < PRONTO_MIN_LENGTH) return;
// We only know how to deal with 'raw' pronto codes types. Reject all others.
if (data[PRONTO_TYPE_OFFSET] != 0) return;
// Pronto frequency is in Hz.
uint16_t hz = (uint16_t) (1000000U / (data[PRONTO_FREQ_OFFSET] *
PRONTO_FREQ_FACTOR));
enableIROut(hz);
// Grab the length of the two sequences.
uint16_t seq_1_len = data[PRONTO_SEQ_1_LEN_OFFSET] * 2;
uint16_t seq_2_len = data[PRONTO_SEQ_2_LEN_OFFSET] * 2;
// Calculate where each sequence starts in the buffer.
uint16_t seq_1_start = PRONTO_DATA_OFFSET;
uint16_t seq_2_start = PRONTO_DATA_OFFSET + seq_1_len;
uint32_t periodic_time = calcUSecPeriod(hz, false);
// Normal (1st sequence) case.
// Is there a first (normal) sequence to send?
if (seq_1_len > 0) {
// Check we have enough data to send the complete first sequence.
if (seq_1_len + seq_1_start > len) return;
// Send the contents of the 1st sequence.
for (uint16_t i = seq_1_start; i < seq_1_start + seq_1_len; i += 2) {
mark(data[i] * periodic_time);
space(data[i + 1] * periodic_time);
}
} else {
// There was no first sequence to send, it is implied that we have to send
// the 2nd/repeat sequence an additional time. i.e. At least once.
repeat++;
}
// Repeat (2nd sequence) case.
// Is there a second (repeat) sequence to be sent?
if (seq_2_len > 0) {
// Check we have enough data to send the complete second sequence.
if (seq_2_len + seq_2_start > len) return;
// Send the contents of the 2nd sequence.
for (uint16_t r = 0; r < repeat; r++)
for (uint16_t i = seq_2_start; i < seq_2_start + seq_2_len; i += 2) {
mark(data[i] * periodic_time);
space(data[i + 1] * periodic_time);
}
}
}
#endif
+514
View File
@@ -0,0 +1,514 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// RRRRRR CCCCC 555555 XX XX RRRRRR CCCCC 666
// RR RR CC C 55 XX XX RR RR CC C 66
// RRRRRR CC _____ 555555 XXXX RRRRRR CC _____ 666666
// RR RR CC C 5555 XX XX RR RR CC C 66 66
// RR RR CCCCC 555555 XX XX RR RR CCCCC 66666
// RC-5 & RC-6 support added from https://github.com/z3t0/Arduino-IRremote
// RC-5X support added by David Conran
// Constants
// RC-5/RC-5X
// Ref:
// https://en.wikipedia.org/wiki/RC-5
// http://www.sbprojects.com/knowledge/ir/rc5.php
#define MIN_RC5_SAMPLES 11U
#define MIN_RC6_SAMPLES 1U
#define RC5_T1 889U
#define RC5_MIN_COMMAND_LENGTH 113778UL
#define RC5_MIN_GAP (RC5_MIN_COMMAND_LENGTH - RC5_RAW_BITS * (2 * RC5_T1))
#define RC5_TOGGLE_MASK 0x800U // (The 12th bit)
// RC-6
// Ref:
// https://en.wikipedia.org/wiki/RC-6
// http://www.pcbheaven.com/userpages/The_Philips_RC6_Protocol/
#define RC6_TICK 444U
#define RC6_HDR_MARK_TICKS 6U
#define RC6_HDR_MARK (RC6_HDR_MARK_TICKS * RC6_TICK)
#define RC6_HDR_SPACE_TICKS 2U
#define RC6_HDR_SPACE (RC6_HDR_SPACE_TICKS * RC6_TICK)
#define RC6_RPT_LENGTH_TICKS 187U
#define RC6_RPT_LENGTH (RC6_RPT_LENGTH_TICKS * RC6_TICK)
#define RC6_TOGGLE_MASK 0x10000UL // (The 17th bit)
#define RC6_36_TOGGLE_MASK 0x8000U // (The 16th bit)
// Common (getRClevel())
#define MARK 0U
#define SPACE 1U
#if SEND_RC5
// Send a Philips RC-5/RC-5X packet.
//
// Args:
// data: The message you wish to send.
// nbits: Bit size of the protocol you want to send.
// repeat: Nr. of extra times the data will be sent.
//
// Status: RC-5 (stable), RC-5X (alpha)
//
// Note:
// Caller needs to take care of flipping the toggle bit.
// That bit differentiates between key press & key release.
// For RC-5 it is the MSB of the data.
// For RC-5X it is the 2nd MSB of the data.
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc5.php
// https://en.wikipedia.org/wiki/RC-5
// https://en.wikipedia.org/wiki/Manchester_code
// TODO(anyone):
// Testing of the RC-5X components.
void IRsend::sendRC5(uint64_t data, uint16_t nbits, uint16_t repeat) {
if (nbits > sizeof(data) * 8)
return; // We can't send something that big.
bool skipSpace = true;
bool field_bit = true;
// Set 36kHz IR carrier frequency & a 1/4 (25%) duty cycle.
enableIROut(36, 25);
if (nbits >= RC5X_BITS) { // Is this a RC-5X message?
// field bit is the inverted MSB of RC-5X data.
field_bit = ((data >> (nbits - 1)) ^ 1) & 1;
nbits--;
}
IRtimer usecTimer = IRtimer();
for (uint16_t i = 0; i <= repeat; i++) {
usecTimer.reset();
// Header
// First start bit (0x1). space, then mark.
if (skipSpace)
skipSpace = false; // First time through, we assume the leading space().
else
space(RC5_T1);
mark(RC5_T1);
// Field/Second start bit.
if (field_bit) { // Send a 1. Normal for RC-5.
space(RC5_T1);
mark(RC5_T1);
} else { // Send a 0. Special case for RC-5X. Means 7th command bit is 1.
mark(RC5_T1);
space(RC5_T1);
}
// Data
for (uint64_t mask = 1ULL << (nbits - 1); mask; mask >>= 1)
if (data & mask) { // 1
space(RC5_T1); // 1 is space, then mark.
mark(RC5_T1);
} else { // 0
mark(RC5_T1); // 0 is mark, then space.
space(RC5_T1);
}
// Footer
space(std::max(RC5_MIN_GAP, RC5_MIN_COMMAND_LENGTH - usecTimer.elapsed()));
}
}
// Encode a Philips RC-5 data message.
//
// Args:
// address: The 5-bit address value for the message.
// command: The 6-bit command value for the message.
// key_released: Boolean flag indicating if the remote key has been released.
//
// Returns:
// A data message suitable for use in sendRC5().
//
// Status: Beta / Should be working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc5.php
// https://en.wikipedia.org/wiki/RC-5
uint16_t IRsend::encodeRC5(uint8_t address, uint8_t command,
bool key_released) {
return (key_released << (RC5_BITS - 1)) |
((address & 0x1f) << 6) |
(command & 0x3F);
}
// Encode a Philips RC-5X data message.
//
// Args:
// address: The 5-bit address value for the message.
// command: The 7-bit command value for the message.
// key_released: Boolean flag indicating if the remote key has been released.
//
// Returns:
// A data message suitable for use in sendRC5().
//
// Status: Beta / Should be working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc5.php
// https://en.wikipedia.org/wiki/RC-5
uint16_t IRsend::encodeRC5X(uint8_t address, uint8_t command,
bool key_released) {
// The 2nd start/field bit (MSB of the return value) is the value of the 7th
// command bit.
bool s2 = (command >> 6) & 1;
return ((uint16_t) s2 << (RC5X_BITS - 1)) |
encodeRC5(address, command, key_released);
}
// Flip the toggle bit of a Philips RC-5/RC-5X data message.
// Used to indicate a change of remote button's state.
//
// Args:
// data: The existing RC-5/RC-5X message.
//
// Returns:
// A data message suitable for use in sendRC5() with the toggle bit flipped.
//
// Status: STABLE.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc5.php
// https://en.wikipedia.org/wiki/RC-5
uint64_t IRsend::toggleRC5(uint64_t data) {
return data ^ RC5_TOGGLE_MASK;
}
#endif // SEND_RC5
#if SEND_RC6
// Flip the toggle bit of a Philips RC-6 data message.
// Used to indicate a change of remote button's state.
// For RC-6 (20-bits), it is the 17th least significant bit.
// for RC-6 (36-bits/Xbox-360), it is the 16th least significant bit.
//
// Args:
// data: The existing RC-6 message.
// nbits: Nr. of bits in the RC-6 protocol.
//
// Returns:
// A data message suitable for use in sendRC6() with the toggle bit flipped.
//
// Status: BETA / Should work fine.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc6.php
// http://www.righto.com/2010/12/64-bit-rc6-codes-arduino-and-xbox.html
uint64_t IRsend::toggleRC6(uint64_t data, uint16_t nbits) {
if (nbits == RC6_36_BITS)
return data ^ RC6_36_TOGGLE_MASK;
return data ^ RC6_TOGGLE_MASK;
}
// Encode a Philips RC-6 data message.
//
// Args:
// address: The address (aka. control) value for the message.
// Includes the field/mode/toggle bits.
// command: The 8-bit command value for the message. (aka. information)
// mode: Which protocol to use. Defined by nr. of bits in the protocol.
//
// Returns:
// A data message suitable for use in sendRC6().
//
// Status: Beta / Should be working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc6.php
// http://www.righto.com/2010/12/64-bit-rc6-codes-arduino-and-xbox.html
// http://www.pcbheaven.com/userpages/The_Philips_RC6_Protocol/
uint64_t IRsend::encodeRC6(uint32_t address, uint8_t command,
uint16_t mode) {
switch (mode) {
case RC6_MODE0_BITS:
return ((address & 0xFFF) << 8) | (command & 0xFF);
case RC6_36_BITS:
return ((uint64_t) (address & 0xFFFFFFF) << 8) | (command & 0xFF);
default:
return 0;
}
}
// Send a Philips RC-6 packet.
// Note: Caller needs to take care of flipping the toggle bit (The 4th Most
// Significant Bit). That bit differentiates between key press & key release.
//
// Args:
// data: The message you wish to send.
// nbits: Bit size of the protocol you want to send.
// repeat: Nr. of extra times the data will be sent.
//
// Status: Stable.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc6.php
// http://www.righto.com/2010/12/64-bit-rc6-codes-arduino-and-xbox.html
// https://en.wikipedia.org/wiki/Manchester_code
void IRsend::sendRC6(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Check we can send the number of bits requested.
if (nbits > sizeof(data) * 8)
return;
// Set 36kHz IR carrier frequency & a 1/3 (33%) duty cycle.
enableIROut(36, 33);
for (uint16_t r = 0; r <= repeat; r++) {
// Header
mark(RC6_HDR_MARK);
space(RC6_HDR_SPACE);
// Start bit.
mark(RC6_TICK); // mark, then space == 0x1.
space(RC6_TICK);
// Data
uint16_t bitTime;
for (uint64_t i = 1, mask = 1ULL << (nbits - 1); mask; i++, mask >>= 1) {
if (i == 4) // The fourth bit we send is a "double width trailer bit".
bitTime = 2 * RC6_TICK; // double-wide trailer bit
else
bitTime = RC6_TICK; // Normal bit
if (data & mask) { // 1
mark(bitTime);
space(bitTime);
} else { // 0
space(bitTime);
mark(bitTime);
}
}
// Footer
space(RC6_RPT_LENGTH);
}
}
#endif // SEND_RC6
#if (DECODE_RC5 || DECODE_RC6)
// Gets one undecoded level at a time from the raw buffer.
// The RC5/6 decoding is easier if the data is broken into time intervals.
// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
// successive calls to getRClevel will return MARK, MARK, SPACE.
// offset and used are updated to keep track of the current position.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// offset: Ptr to the currect offset to the rawbuf.
// used: Ptr to the current used counter.
// bitTime: Time interval of single bit in microseconds.
// Returns:
// int: MARK, SPACE, or -1 for error (The measured time interval is not a
// multiple of t1.)
// Ref:
// https://en.wikipedia.org/wiki/Manchester_code
int16_t IRrecv::getRClevel(decode_results *results, uint16_t *offset,
uint16_t *used, uint16_t bitTime) {
if (*offset >= results->rawlen)
return SPACE; // After end of recorded buffer, assume SPACE.
uint16_t width = results->rawbuf[*offset];
// If the value of offset is odd, it's a MARK. Even, it's a SPACE.
uint16_t val = ((*offset) % 2) ? MARK : SPACE;
// Check to see if we have hit an inter-message gap (> 20ms).
if (val == SPACE && width > 20000)
return SPACE;
int16_t correction = (val == MARK) ? MARK_EXCESS : -MARK_EXCESS;
// Calculate the look-ahead for our current position in the buffer.
uint16_t avail;
// Note: We want to match in greedy order as the other way leads to
// mismatches due to overlaps induced by the correction and tolerance
// values.
if (match(width, 3 * bitTime + correction))
avail = 3;
else if (match(width, 2 * bitTime + correction))
avail = 2;
else if (match(width, bitTime + correction))
avail = 1;
else
return -1; // The width is not what we expected.
(*used)++; // Count another one of the avail slots as used.
if (*used >= avail) { // Are we out of look-ahead/avail slots?
// Yes, so reset the used counter, and move the offset ahead.
*used = 0;
(*offset)++;
}
return val;
}
#endif // (DECODE_RC5 || DECODE_RC6)
#if DECODE_RC5
// Decode the supplied RC-5/RC5X message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: The number of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: RC-5 (stable), RC-5X (alpha)
//
// Note:
// The 'toggle' bit is included as the 6th (MSB) address bit, the MSB of data,
// & in the count of bits decoded.
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc5.php
// https://en.wikipedia.org/wiki/RC-5
// https://en.wikipedia.org/wiki/Manchester_code
// TODO(anyone):
// Serious testing of the RC-5X and strict aspects needs to be done.
bool IRrecv::decodeRC5(decode_results *results, uint16_t nbits, bool strict) {
if (results->rawlen < MIN_RC5_SAMPLES + HEADER - 1) return false;
// Compliance
if (strict && nbits != RC5_BITS && nbits != RC5X_BITS)
return false; // It's neither RC-5 or RC-5X.
uint16_t offset = OFFSET_START;
uint16_t used = 0;
bool is_rc5x = false;
uint64_t data = 0;
// Header
// Get start bit #1.
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return false;
// Get field/start bit #2 (inverted bit-7 of the command if RC-5X protocol)
uint16_t actual_bits = 1;
int16_t levelA = getRClevel(results, &offset, &used, RC5_T1);
int16_t levelB = getRClevel(results, &offset, &used, RC5_T1);
if (levelA == SPACE && levelB == MARK) { // Matched a 1.
is_rc5x = false;
} else if (levelA == MARK && levelB == SPACE) { // Matched a 0.
if (nbits <= RC5_BITS) return false; // Field bit must be '1' for RC5.
is_rc5x = true;
data = 1;
} else {
return false; // Not what we expected.
}
// Data
for (; offset < results->rawlen; actual_bits++) {
int16_t levelA = getRClevel(results, &offset, &used, RC5_T1);
int16_t levelB = getRClevel(results, &offset, &used, RC5_T1);
if (levelA == SPACE && levelB == MARK)
data = (data << 1) | 1; // 1
else if (levelA == MARK && levelB == SPACE)
data <<= 1; // 0
else
break;
}
// Footer (None)
// Compliance
if (actual_bits < nbits) return false; // Less data than we expected.
if (strict && actual_bits != RC5_BITS &&
actual_bits != RC5X_BITS) return false;
// Success
results->value = data;
results->address = (data >> 6) & 0x1F;
results->command = data & 0x3F;
results->repeat = false;
if (is_rc5x) {
results->decode_type = RC5X;
results->command |= ((uint32_t) is_rc5x) << 6;
} else {
results->decode_type = RC5;
actual_bits--; // RC5 doesn't count the field bit as data.
}
results->bits = actual_bits;
return true;
}
#endif // DECODE_RC5
#if DECODE_RC6
// Decode the supplied RC6 message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: The number of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: Stable.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rc6.php
// https://en.wikipedia.org/wiki/Manchester_code
// TODO(anyone):
// Testing of the strict compliance aspects.
bool IRrecv::decodeRC6(decode_results *results, uint16_t nbits, bool strict) {
if (results->rawlen < HEADER + 2 + 4) // Up to the double-wide T bit.
return false; // Smaller than absolute smallest possible RC6 message.
if (strict) { // Compliance
// Unlike typical protocols, the ability to have mark+space, and space+mark
// as data bits means it is possible to only have nbits of entries for the
// data portion, rather than the typically required 2 * nbits.
// Also due to potential melding with the start bit, we can only count
// the start bit as 1, instead of a more typical 2 value. The header still
// remains as normal.
if (results->rawlen < nbits + HEADER + 1)
return false; // Don't have enough entries/samples to be valid.
switch (nbits) {
case RC6_MODE0_BITS:
case RC6_36_BITS:
break;
default:
return false; // Asking for the wrong number of bits.
}
}
uint16_t offset = OFFSET_START;
// Header
if (!matchMark(results->rawbuf[offset], RC6_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t tick = results->rawbuf[offset++] * RAWTICK / RC6_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset++], RC6_HDR_SPACE_TICKS * tick))
return false;
uint16_t used = 0;
// Get the start bit. e.g. 1.
if (getRClevel(results, &offset, &used, tick) != MARK) return false;
if (getRClevel(results, &offset, &used, tick) != SPACE) return false;
uint16_t actual_bits;
uint64_t data = 0;
// Data (Warning: Here be dragons^Wpointers!!)
for (actual_bits = 0; offset < results->rawlen; actual_bits++) {
int16_t levelA, levelB; // Next two levels
levelA = getRClevel(results, &offset, &used, tick);
// T bit is double wide; make sure second half matches
if (actual_bits == 3 &&
levelA != getRClevel(results, &offset, &used, tick))
return false;
levelB = getRClevel(results, &offset, &used, tick);
// T bit is double wide; make sure second half matches
if (actual_bits == 3 &&
levelB != getRClevel(results, &offset, &used, tick))
return false;
if (levelA == MARK && levelB == SPACE) // reversed compared to RC5
data = (data << 1) | 1; // 1
else if (levelA == SPACE && levelB == MARK)
data <<= 1; // 0
else
break;
}
// More compliance
if (strict && actual_bits != nbits)
return false; // Actual nr. of bits didn't match expected.
// Success
results->decode_type = RC6;
results->bits = actual_bits;
results->value = data;
results->address = data >> 8;
results->command = data & 0xFF;
return true;
}
#endif // DECODE_RC6
+174
View File
@@ -0,0 +1,174 @@
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// RRRRRR CCCCC MM MM MM MM
// RR RR CC C MMM MMM MMM MMM
// RRRRRR CC _____ MM MM MM MM MM MM
// RR RR CC C MM MM MM MM
// RR RR CCCCC MM MM MM MM
// Send & decode support for RC-MM added by David Conran
// Constants
// Ref:
// http://www.sbprojects.com/knowledge/ir/rcmm.php
#define RCMM_TICK 28U // Technically it would be 27.777*
#define RCMM_HDR_MARK_TICKS 15U
#define RCMM_HDR_MARK 416U
#define RCMM_HDR_SPACE_TICKS 10U
#define RCMM_HDR_SPACE 277U
#define RCMM_BIT_MARK_TICKS 6U
#define RCMM_BIT_MARK 166U
#define RCMM_BIT_SPACE_0_TICKS 10U
#define RCMM_BIT_SPACE_0 277U
#define RCMM_BIT_SPACE_1_TICKS 16U
#define RCMM_BIT_SPACE_1 444U
#define RCMM_BIT_SPACE_2_TICKS 22U
#define RCMM_BIT_SPACE_2 611U
#define RCMM_BIT_SPACE_3_TICKS 28U
#define RCMM_BIT_SPACE_3 777U
#define RCMM_RPT_LENGTH_TICKS 992U
#define RCMM_RPT_LENGTH 27778U
#define RCMM_MIN_GAP_TICKS 120U
#define RCMM_MIN_GAP 3360U
// Use a tolerance of +/-10% when matching some data spaces.
#define RCMM_TOLERANCE 10U
#define RCMM_EXCESS 50U
#if SEND_RCMM
// Send a Philips RC-MM packet.
//
// Args:
// data: The data we want to send. MSB first.
// nbits: The number of bits of data to send. (Typically 12, 24, or 32[Nokia])
// repeat: The nr. of times the message should be sent.
//
// Status: BETA / Should be working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rcmm.php
void IRsend::sendRCMM(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set 36kHz IR carrier frequency & a 1/3 (33%) duty cycle.
enableIROut(36, 33);
IRtimer usecs = IRtimer();
for (uint16_t r = 0; r <= repeat; r++) {
usecs.reset();
// Header
mark(RCMM_HDR_MARK);
space(RCMM_HDR_SPACE);
// Data
uint64_t mask = 0b11ULL << (nbits - 2);
// RC-MM sends data 2 bits at a time.
for (int32_t i = nbits; i > 0; i -= 2) {
mark(RCMM_BIT_MARK);
// Grab the next Most Significant Bits to send.
switch ((data & mask) >> (i - 2)) {
case 0b00: space(RCMM_BIT_SPACE_0); break;
case 0b01: space(RCMM_BIT_SPACE_1); break;
case 0b10: space(RCMM_BIT_SPACE_2); break;
case 0b11: space(RCMM_BIT_SPACE_3); break;
}
mask >>= 2;
}
// Footer
mark(RCMM_BIT_MARK);
// Protocol requires us to wait at least RCMM_RPT_LENGTH usecs from the
// start or RCMM_MIN_GAP usecs.
space(std::max(RCMM_RPT_LENGTH - usecs.elapsed(), RCMM_MIN_GAP));
}
}
#endif
#if DECODE_RCMM
// Decode a Philips RC-MM packet (between 12 & 32 bits) if possible.
// Places successful decode information in the results pointer.
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of bits to expect in the data portion. Typically RCMM_BITS.
// strict: Flag to indicate if we strictly adhere to the specification.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should be working.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/rcmm.php
bool IRrecv::decodeRCMM(decode_results *results, uint16_t nbits, bool strict) {
uint64_t data = 0;
uint16_t offset = OFFSET_START;
if (results->rawlen <= 4)
return false; // Not enough entries to ever be RCMM.
// Calc the maximum size in bits, the message can be, or that we can accept.
int16_t maxBitSize = std::min((uint16_t) results->rawlen - 4,
(uint16_t) sizeof(data) * 8);
// Compliance
if (strict) {
// Technically the spec says bit sizes should be 12 xor 24. however
// 32 bits has been seen from a device. We are going to assume
// 12 <= bits <= 32 is the 'required' bit length for the spec.
if (maxBitSize < 12 || maxBitSize > 32)
return false;
if (maxBitSize < nbits)
return false; // Short cut, we can never reach the expected nr. of bits.
}
// Header decode
if (!matchMark(results->rawbuf[offset], RCMM_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK / RCMM_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], RCMM_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK / RCMM_HDR_SPACE_TICKS;
// Data decode
// RC-MM has two bits of data per mark/space pair.
uint16_t actualBits;
for (actualBits = 0; actualBits < maxBitSize; actualBits += 2, offset++) {
if (!match(results->rawbuf[offset++], RCMM_BIT_MARK_TICKS * m_tick))
return false;
data <<= 2;
// Use non-default tolerance & excess for matching some of the spaces as the
// defaults are too generous and causes mis-matches in some cases.
if (match(results->rawbuf[offset], RCMM_BIT_SPACE_0_TICKS * s_tick,
TOLERANCE))
data += 0;
else if (match(results->rawbuf[offset], RCMM_BIT_SPACE_1_TICKS * s_tick,
TOLERANCE))
data += 1;
else if (match(results->rawbuf[offset], RCMM_BIT_SPACE_2_TICKS * s_tick,
RCMM_TOLERANCE))
data += 2;
else if (match(results->rawbuf[offset], RCMM_BIT_SPACE_3_TICKS * s_tick,
RCMM_TOLERANCE))
data += 3;
else
return false;
}
// Footer decode
if (!match(results->rawbuf[offset++], RCMM_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], RCMM_MIN_GAP_TICKS * s_tick))
return false;
// Compliance
if (strict && actualBits != nbits)
return false;
// Success
results->value = data;
results->decode_type = RCMM;
results->bits = actualBits;
results->address = 0;
results->command = 0;
return true;
}
#endif
+175
View File
@@ -0,0 +1,175 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// SSSS AAA MMM SSSS U U N N GGGG
// S A A M M M S U U NN N G
// SSS AAAAA M M M SSS U U N N N G GG
// S A A M M S U U N NN G G
// SSSS A A M M SSSS UUU N N GGG
// Samsung originally added from https://github.com/shirriff/Arduino-IRremote/
// Constants
// Ref:
// http://elektrolab.wz.cz/katalog/samsung_protocol.pdf
#define SAMSUNG_TICK 560U
#define SAMSUNG_HDR_MARK_TICKS 8U
#define SAMSUNG_HDR_MARK (SAMSUNG_HDR_MARK_TICKS * SAMSUNG_TICK)
#define SAMSUNG_HDR_SPACE_TICKS 8U
#define SAMSUNG_HDR_SPACE (SAMSUNG_HDR_SPACE_TICKS * SAMSUNG_TICK)
#define SAMSUNG_BIT_MARK_TICKS 1U
#define SAMSUNG_BIT_MARK (SAMSUNG_BIT_MARK_TICKS * SAMSUNG_TICK)
#define SAMSUNG_ONE_SPACE_TICKS 3U
#define SAMSUNG_ONE_SPACE (SAMSUNG_ONE_SPACE_TICKS * SAMSUNG_TICK)
#define SAMSUNG_ZERO_SPACE_TICKS 1U
#define SAMSUNG_ZERO_SPACE (SAMSUNG_ZERO_SPACE_TICKS * SAMSUNG_TICK)
#define SAMSUNG_RPT_SPACE_TICKS 4U
#define SAMSUNG_RPT_SPACE (SAMSUNG_RPT_SPACE_TICKS * SAMSUNG_TICK)
#define SAMSUNG_MIN_MESSAGE_LENGTH_TICKS 193U
#define SAMSUNG_MIN_MESSAGE_LENGTH (SAMSUNG_MIN_MESSAGE_LENGTH_TICKS * \
SAMSUNG_TICK)
#define SAMSUNG_MIN_GAP_TICKS (SAMSUNG_MIN_MESSAGE_LENGTH_TICKS - \
(SAMSUNG_HDR_MARK_TICKS + SAMSUNG_HDR_SPACE_TICKS + \
SAMSUNG_BITS * (SAMSUNG_BIT_MARK_TICKS + SAMSUNG_ONE_SPACE_TICKS) + \
SAMSUNG_BIT_MARK_TICKS))
#define SAMSUNG_MIN_GAP (SAMSUNG_MIN_GAP_TICKS * SAMSUNG_TICK)
#if SEND_SAMSUNG
// Send a Samsung formatted message.
// Samsung has a separate message to indicate a repeat, like NEC does.
// TODO(crankyoldgit): Confirm that is actually how Samsung sends a repeat.
// The refdoc doesn't indicate it is true.
//
// Args:
// data: The message to be sent.
// nbits: The bit size of the message being sent. typically SAMSUNG_BITS.
// repeat: The number of times the message is to be repeated.
//
// Status: BETA / Should be working.
//
// Ref: http://elektrolab.wz.cz/katalog/samsung_protocol.pdf
void IRsend::sendSAMSUNG(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set 38kHz IR carrier frequency & a 1/3 (33%) duty cycle.
enableIROut(38, 33);
IRtimer usecTimer = IRtimer();
// We always send a message, even for repeat=0, hence '<= repeat'.
for (uint16_t i=0; i <= repeat; i++) {
usecTimer.reset();
// Header
mark(SAMSUNG_HDR_MARK);
space(SAMSUNG_HDR_SPACE);
// Data
sendData(SAMSUNG_BIT_MARK, SAMSUNG_ONE_SPACE, SAMSUNG_BIT_MARK,
SAMSUNG_ZERO_SPACE, data, nbits, true);
// Footer
mark(SAMSUNG_BIT_MARK);
space(std::max((uint32_t) SAMSUNG_MIN_GAP,
(uint32_t) (SAMSUNG_MIN_MESSAGE_LENGTH -
usecTimer.elapsed())));
}
}
// Construct a raw Samsung message from the supplied customer(address) &
// command.
//
// Args:
// customer: The customer code. (aka. Address)
// command: The command code.
// Returns:
// A raw 32-bit Samsung message suitable for sendSAMSUNG().
//
// Status: BETA / Should be working.
uint32_t IRsend::encodeSAMSUNG(uint8_t customer, uint8_t command) {
customer = reverseBits(customer, sizeof(customer) * 8);
command = reverseBits(command, sizeof(command) * 8);
return((command ^ 0xFF) | (command << 8) |
(customer << 16) | (customer << 24));
}
#endif
#if DECODE_SAMSUNG
// Decode the supplied Samsung message.
// Samsung messages whilst 32 bits in size, only contain 16 bits of distinct
// data. e.g. In transmition order:
// customer_byte + customer_byte(same) + address_byte + invert(address_byte)
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of bits to expect in the data portion. Typically SAMSUNG_BITS.
// strict: Flag to indicate if we strictly adhere to the specification.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: STABLE
//
// Note:
// LG 32bit protocol appears near identical to the Samsung protocol.
// They differ on their compliance criteria and how they repeat.
// Ref:
// http://elektrolab.wz.cz/katalog/samsung_protocol.pdf
bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t nbits,
bool strict) {
if (results->rawlen < 2 * nbits + HEADER + FOOTER - 1)
return false; // Can't possibly be a valid Samsung message.
if (strict && nbits != SAMSUNG_BITS)
return false; // We expect Samsung to be 32 bits of message.
uint64_t data = 0;
uint16_t offset = OFFSET_START;
// Header
if (!matchMark(results->rawbuf[offset], SAMSUNG_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK /
SAMSUNG_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], SAMSUNG_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
SAMSUNG_HDR_SPACE_TICKS;
// Data
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
SAMSUNG_BIT_MARK_TICKS * m_tick,
SAMSUNG_ONE_SPACE_TICKS * s_tick,
SAMSUNG_BIT_MARK_TICKS * m_tick,
SAMSUNG_ZERO_SPACE_TICKS * s_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!matchMark(results->rawbuf[offset++], SAMSUNG_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], SAMSUNG_MIN_GAP_TICKS * s_tick))
return false;
// Compliance
// According to the spec, the customer (address) code is the first 8
// transmitted bits. It's then repeated. Check for that.
uint8_t address = data >> 24;
if (strict && address != ((data >> 16) & 0xFF))
return false;
// Spec says the command code is the 3rd block of transmitted 8-bits,
// followed by the inverted command code.
uint8_t command = (data & 0xFF00) >> 8;
if (strict && command != ((data & 0xFF) ^ 0xFF))
return false;
// Success
results->bits = nbits;
results->value = data;
results->decode_type = SAMSUNG;
// command & address need to be reversed as they are transmitted LSB first,
results->command = reverseBits(command, sizeof(command) * 8);
results->address = reverseBits(address, sizeof(address) * 8);
return true;
}
#endif
+239
View File
@@ -0,0 +1,239 @@
// Copyright 2009 Ken Shirriff
// Copyright 2016 marcosamarinho
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
// SSSS AAA N N Y Y OOO
// S A A NN N Y Y O O
// SSS AAAAA N N N Y O O
// S A A N NN Y O O
// SSSS A A N N Y OOO
// Sanyo SA 8650B originally added from:
// https://github.com/shirriff/Arduino-IRremote/
// Sanyo LC7461 support originally by marcosamarinho
// Constants
// Sanyo SA 8650B
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Sanyo.cpp
#define SANYO_SA8650B_HDR_MARK 3500U // seen range 3500
#define SANYO_SA8650B_HDR_SPACE 950U // seen 950
#define SANYO_SA8650B_ONE_MARK 2400U // seen 2400
#define SANYO_SA8650B_ZERO_MARK 700U // seen 700
// usually see 713 - not using ticks as get number wrapround
#define SANYO_SA8650B_DOUBLE_SPACE_USECS 800U
#define SANYO_SA8650B_RPT_LENGTH 45000U
// Sanyo LC7461
// Ref:
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp
// http://slydiman.narod.ru/scr/kb/sanyo.htm
// http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf
#define SANYO_LC7461_ADDRESS_MASK ((1 << SANYO_LC7461_ADDRESS_BITS) - 1)
#define SANYO_LC7461_COMMAND_MASK ((1 << SANYO_LC7461_COMMAND_BITS) - 1)
#define SANYO_LC7461_HDR_MARK 9000U
#define SANYO_LC7461_HDR_SPACE 4500U
#define SANYO_LC7461_BIT_MARK 560U // 1T
#define SANYO_LC7461_ONE_SPACE 1690U // 3T
#define SANYO_LC7461_ZERO_SPACE 560U // 1T
#define SANYO_LC7461_MIN_COMMAND_LENGTH 108000UL
#define SANYO_LC7461_MIN_GAP SANYO_LC7461_MIN_COMMAND_LENGTH - \
(SANYO_LC7461_HDR_MARK + SANYO_LC7461_HDR_SPACE + SANYO_LC7461_BITS * \
(SANYO_LC7461_BIT_MARK + (SANYO_LC7461_ONE_SPACE + \
SANYO_LC7461_ZERO_SPACE) / 2) \
+ SANYO_LC7461_BIT_MARK)
#if SEND_SANYO
// Construct a Sanyo LC7461 message.
//
// Args:
// address: The 13 bit value of the address(Custom) portion of the protocol.
// command: The 8 bit value of the command(Key) portion of the protocol.
// Returns:
// An uint64_t with the encoded raw 42 bit Sanyo LC7461 data value.
//
// Notes:
// This protocol uses the NEC protocol timings. However, data is
// formatted as : address(13 bits), !address, command(8 bits), !command.
// According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
uint64_t IRsend::encodeSanyoLC7461(uint16_t address, uint8_t command) {
// Mask our input values to ensure the correct bit sizes.
address &= SANYO_LC7461_ADDRESS_MASK;
command &= SANYO_LC7461_COMMAND_MASK;
uint64_t data = address;
address ^= SANYO_LC7461_ADDRESS_MASK; // Invert the 13 LSBs.
// Append the now inverted address.
data = (data << SANYO_LC7461_ADDRESS_BITS) | address;
// Append the command.
data = (data << SANYO_LC7461_COMMAND_BITS) | command;
command ^= SANYO_LC7461_COMMAND_MASK; // Invert the command.
// Append the now inverted command.
data = (data << SANYO_LC7461_COMMAND_BITS) | command;
return data;
}
// Send a Sanyo LC7461 message.
//
// Args:
// data: The contents of the command you want to send.
// nbits: The bit size of the command being sent.
// repeat: The number of times you want the command to be repeated.
//
// Status: BETA / Probably works.
//
// Notes:
// Based on @marcosamarinho's work.
// This protocol uses the NEC protocol timings. However, data is
// formatted as : address(13 bits), !address, command (8 bits), !command.
// According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
// Information for this protocol is available at the Sanyo LC7461 datasheet.
// Repeats are performed similar to the NEC method of sending a special
// repeat message, rather than duplicating the entire message.
// Ref:
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp
// http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf
void IRsend::sendSanyoLC7461(uint64_t data, uint16_t nbits, uint16_t repeat) {
// This protocol appears to be another 42-bit variant of the NEC protcol.
sendNEC(data, nbits, repeat);
}
#endif // SEND_SANYO
#if DECODE_SANYO
// Decode the supplied SANYO LC7461 message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Probably works.
//
// Notes:
// Based on @marcosamarinho's work.
// This protocol uses the NEC protocol. However, data is
// formatted as : address(13 bits), !address, command (8 bits), !command.
// According with LIRC, this protocol is used on Sanyo, Aiwa and Chinon
// Information for this protocol is available at the Sanyo LC7461 datasheet.
// Ref:
// http://slydiman.narod.ru/scr/kb/sanyo.htm
// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp
// http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf
bool IRrecv::decodeSanyoLC7461(decode_results *results, uint16_t nbits,
bool strict) {
if (strict && nbits != SANYO_LC7461_BITS)
return false; // Not strictly in spec.
// This protocol is basically a 42-bit variant of the NEC protocol.
if (!decodeNEC(results, nbits, false))
return false; // Didn't match a NEC format (without strict)
// Bits 30 to 42+.
uint16_t address = results->value >> (SANYO_LC7461_BITS -
SANYO_LC7461_ADDRESS_BITS);
// Bits 9 to 16.
uint8_t command = (results->value >> SANYO_LC7461_COMMAND_BITS) &
SANYO_LC7461_COMMAND_MASK;
// Compliance
if (strict) {
if (results->bits != nbits)
return false;
// Bits 17 to 29.
uint16_t inverted_address =
(results->value >> (SANYO_LC7461_COMMAND_BITS * 2)) &
SANYO_LC7461_ADDRESS_MASK;
// Bits 1-8.
uint8_t inverted_command = results->value & SANYO_LC7461_COMMAND_MASK;
if ((address ^ SANYO_LC7461_ADDRESS_MASK) != inverted_address)
return false; // Address integrity check failed.
if ((command ^ SANYO_LC7461_COMMAND_MASK) != inverted_command)
return false; // Command integrity check failed.
}
// Success
results->decode_type = SANYO_LC7461;
results->address = address;
results->command = command;
return true;
}
/* NOTE: Disabled due to poor quality.
// Decode the supplied Sanyo SA 8650B message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: Depricated.
//
// NOTE: This decoder looks like rubbish. Only keeping it for compatibility
// with the Arduino IRremote library. Seriously, don't trust it.
// If someone has a device that this is supposed to be for, please log an
// Issue on github with a rawData dump please. We should probably remove
// it. We think this is a Sanyo decoder - serial = SA 8650B
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Sanyo.cpp
bool IRrecv::decodeSanyo(decode_results *results, uint16_t nbits, bool strict) {
if (results->rawlen < 2 * nbits + HEADER - 1)
return false; // Shorter than shortest possible.
if (strict && nbits != SANYO_SA8650B_BITS)
return false; // Doesn't match the spec.
uint16_t offset = 0;
// TODO(crankyoldgit): This repeat code looks like garbage, it should never
// match or if it does, it won't be reliable. We should probably just
// remove it.
if (results->rawbuf[offset++] < SANYO_SA8650B_DOUBLE_SPACE_USECS) {
results->bits = 0;
results->value = REPEAT;
results->decode_type = SANYO;
results->address = 0;
results->command = 0;
results->repeat = true;
return true;
}
// Header
if (!matchMark(results->rawbuf[offset++], SANYO_SA8650B_HDR_MARK))
return false;
// NOTE: These next two lines look very wrong. Treat as suspect.
if (!matchMark(results->rawbuf[offset++], SANYO_SA8650B_HDR_MARK))
return false;
// Data
uint64_t data = 0;
while (offset + 1 < results->rawlen) {
if (!matchSpace(results->rawbuf[offset], SANYO_SA8650B_HDR_SPACE))
break;
offset++;
if (matchMark(results->rawbuf[offset], SANYO_SA8650B_ONE_MARK))
data = (data << 1) | 1; // 1
else if (matchMark(results->rawbuf[offset], SANYO_SA8650B_ZERO_MARK))
data <<= 1; // 0
else
return false;
offset++;
}
if (strict && SANYO_SA8650B_BITS > (offset - 1U) / 2U)
return false;
// Success
results->bits = (offset - 1) / 2;
results->decode_type = SANYO;
results->value = data;
results->address = 0;
results->command = 0;
return true;
}
*/
#endif // DECODE_SANYO
+278
View File
@@ -0,0 +1,278 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// SSSS H H AAA RRRR PPPP
// S H H A A R R P P
// SSS HHHHH AAAAA RRRR PPPP
// S H H A A R R P
// SSSS H H A A R R P
// Constants
// period time = 1/38000Hz = 26.316 microseconds.
// Ref:
// GlobalCache's IR Control Tower data.
// http://www.sbprojects.com/knowledge/ir/sharp.php
#define SHARP_TICK 26U
#define SHARP_BIT_MARK_TICKS 10U
#define SHARP_BIT_MARK (SHARP_BIT_MARK_TICKS * SHARP_TICK)
#define SHARP_ONE_SPACE_TICKS 70U
#define SHARP_ONE_SPACE (SHARP_ONE_SPACE_TICKS * SHARP_TICK)
#define SHARP_ZERO_SPACE_TICKS 30U
#define SHARP_ZERO_SPACE (SHARP_ZERO_SPACE_TICKS * SHARP_TICK)
#define SHARP_GAP_TICKS 1677U
#define SHARP_GAP (SHARP_GAP_TICKS * SHARP_TICK)
// Address(5) + Command(8) + Expansion(1) + Check(1)
#define SHARP_TOGGLE_MASK ((1 << (SHARP_BITS - SHARP_ADDRESS_BITS)) - 1)
#define SHARP_ADDRESS_MASK ((1 << SHARP_ADDRESS_BITS) - 1)
#define SHARP_COMMAND_MASK ((1 << SHARP_COMMAND_BITS) - 1)
#if (SEND_SHARP || SEND_DENON)
// Send a (raw) Sharp message
//
// Args:
// data: Contents of the message to be sent.
// nbits: Nr. of bits of data to be sent. Typically SHARP_BITS.
// repeat: Nr. of additional times the message is to be sent.
//
// Status: BETA / Previously working fine.
//
// Notes:
// This procedure handles the inversion of bits required per protocol.
// The protocol spec says to send the LSB first, but legacy code & usage
// has us sending the MSB first. Grrrr. Normal invocation of encodeSharp()
// handles this for you, assuming you are using the correct/standard values.
// e.g. sendSharpRaw(encodeSharp(address, command));
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/sharp.htm
// http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
// http://www.mwftr.com/ucF08/LEC14%20PIC%20IR.pdf
// http://www.hifi-remote.com/johnsfine/DecodeIR.html#Sharp
void IRsend::sendSharpRaw(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set 38kHz IR carrier frequency & a 1/3 (33%) duty cycle.
enableIROut(38, 33);
for (uint16_t i = 0; i <= repeat; i++) {
// Protocol demands that the data be sent twice; once normally,
// then with all but the address bits inverted.
// Note: Previously this used to be performed 3 times (normal, inverted,
// normal), however all data points to that being incorrect.
for (uint8_t n = 0; n < 2; n++) {
// No Header
// Data
sendData(SHARP_BIT_MARK, SHARP_ONE_SPACE,
SHARP_BIT_MARK, SHARP_ZERO_SPACE,
data, nbits, true);
// Footer
mark(SHARP_BIT_MARK);
space(SHARP_GAP);
// Invert the data per protocol. This is always called twice, so it's
// retured to original upon exiting the inner loop.
data ^= SHARP_TOGGLE_MASK;
}
}
}
// Encode a (raw) Sharp message from it's components.
//
// Args:
// address: The value of the address to be sent.
// command: The value of the address to be sent. (8 bits)
// expansion: The value of the expansion bit to use. (0 or 1, typically 1)
// check: The value of the check bit to use. (0 or 1, typically 0)
// MSBfirst: Flag indicating MSB first or LSB first order. (Default: false)
// Returns:
// An uint32_t containing the raw Sharp message for sendSharpRaw().
//
// Status: BETA / Should work okay.
//
// Notes:
// Assumes the standard Sharp bit sizes.
// Historically sendSharp() sends address & command in
// MSB first order. This is actually incorrect. It should be sent in LSB
// order. The behaviour of sendSharp() hasn't been changed to maintain
// backward compatibility.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/sharp.htm
// http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
// http://www.mwftr.com/ucF08/LEC14%20PIC%20IR.pdf
uint32_t IRsend::encodeSharp(uint16_t address, uint16_t command,
uint16_t expansion, uint16_t check,
bool MSBfirst) {
// Mask any unexpected bits.
address &= ((1 << SHARP_ADDRESS_BITS) - 1);
command &= ((1 << SHARP_COMMAND_BITS) - 1);
expansion &= 1;
check &= 1;
if (!MSBfirst) { // Correct bit order if needed.
address = reverseBits(address, SHARP_ADDRESS_BITS);
command = reverseBits(command, SHARP_COMMAND_BITS);
}
// Concatinate all the bits.
return (address << (SHARP_COMMAND_BITS + 2)) | (command << 2) |
(expansion << 1) | check;
}
// Send a Sharp message
//
// Args:
// address: Address value to be sent.
// command: Command value to be sent.
// nbits: Nr. of bits of data to be sent. Typically SHARP_BITS.
// repeat: Nr. of additional times the message is to be sent.
//
// Status: DEPRICATED / Previously working fine.
//
// Notes:
// This procedure has a non-standard invocation style compared to similar
// sendProtocol() routines. This is due to legacy, compatibility, & historic
// reasons. Normally the calling syntax version is like sendSharpRaw().
// This procedure transmits the address & command in MSB first order, which is
// incorrect. This behaviour is left as-is to maintain backward
// compatibility with legacy code.
// In short, you should use sendSharpRaw(), encodeSharp(), and the correct
// values of address & command instead of using this, & the wrong values.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/sharp.htm
// http://lirc.sourceforge.net/remotes/sharp/GA538WJSA
// http://www.mwftr.com/ucF08/LEC14%20PIC%20IR.pdf
void IRsend::sendSharp(uint16_t address, uint16_t command, uint16_t nbits,
uint16_t repeat) {
sendSharpRaw(encodeSharp(address, command, 1, 0, true), nbits, repeat);
}
#endif // (SEND_SHARP || SEND_DENON)
#if (DECODE_SHARP || DECODE_DENON)
// Decode the supplied Sharp message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of data bits to expect. Typically SHARP_BITS.
// strict: Flag indicating if we should perform strict matching.
// expansion: Should we expect the expansion bit to be set. Default is true.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should work okay.
//
// Note:
// This procedure returns a value suitable for use in sendSharpRaw().
// TODO(crankyoldgit): Need to ensure capture of the inverted message as it can
// be missed due to the interrupt timeout used to detect an end of message.
// Several compliance checks are disabled until that is resolved.
// Ref:
// http://www.sbprojects.com/knowledge/ir/sharp.php
// http://www.mwftr.com/ucF08/LEC14%20PIC%20IR.pdf
// http://www.hifi-remote.com/johnsfine/DecodeIR.html#Sharp
bool IRrecv::decodeSharp(decode_results *results, uint16_t nbits, bool strict,
bool expansion) {
if (results->rawlen < 2 * nbits + FOOTER - 1)
return false; // Not enough entries to be a Sharp message.
// Compliance
if (strict) {
if (nbits != SHARP_BITS)
return false; // Request is out of spec.
// DISABLED - See TODO
#ifdef UNIT_TEST
// An in spec message has the data sent normally, then inverted. So we
// expect twice as many entries than to just get the results.
if (results->rawlen < 2 * (2 * nbits + FOOTER))
return false;
#endif
}
uint64_t data = 0;
uint16_t offset = OFFSET_START;
// No header
// But try to auto-calibrate off the initial mark signal.
if (!matchMark(results->rawbuf[offset], SHARP_BIT_MARK, 35)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t tick = results->rawbuf[offset] * RAWTICK / SHARP_BIT_MARK_TICKS;
// Data
for (uint16_t i = 0; i < nbits; i++, offset++) {
// Use a higher tolerance value for SHARP_BIT_MARK as it is quite small.
if (!matchMark(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick, 35))
return false;
if (matchSpace(results->rawbuf[offset], SHARP_ONE_SPACE_TICKS * tick))
data = (data << 1) | 1; // 1
else if (matchSpace(results->rawbuf[offset], SHARP_ZERO_SPACE_TICKS * tick))
data <<= 1; // 0
else
return false;
}
// Footer
if (!match(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], SHARP_GAP_TICKS * tick))
return false;
// Compliance
if (strict) {
// Check the state of the expansion bit is what we expect.
if ((data & 0b10) >> 1 != expansion)
return false;
// The check bit should be cleared in a normal message.
if (data & 0b1)
return false;
// DISABLED - See TODO
#ifdef UNIT_TEST
// Grab the second copy of the data (i.e. inverted)
// Header
// i.e. The inter-data/command repeat gap.
if (!matchSpace(results->rawbuf[offset++], SHARP_GAP_TICKS * tick))
return false;
// Data
uint64_t second_data = 0;
for (uint16_t i = 0; i < nbits; i++, offset++) {
// Use a higher tolerance value for SHARP_BIT_MARK as it is quite small.
if (!matchMark(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick,
35))
return false;
if (matchSpace(results->rawbuf[offset], SHARP_ONE_SPACE_TICKS * tick))
second_data = (second_data << 1) | 1; // 1
else if (matchSpace(results->rawbuf[offset],
SHARP_ZERO_SPACE_TICKS * tick))
second_data <<= 1; // 0
else
return false;
}
// Footer
if (!match(results->rawbuf[offset++], SHARP_BIT_MARK_TICKS * tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], SHARP_GAP_TICKS * tick))
return false;
// Check that second_data has been inverted correctly.
if (data != (second_data ^ SHARP_TOGGLE_MASK))
return false;
#endif // UNIT_TEST
}
// Success
results->decode_type = SHARP;
results->bits = nbits;
results->value = data;
// Address & command are actually transmitted in LSB first order.
results->address = reverseBits(data, nbits) & SHARP_ADDRESS_MASK;
results->command = reverseBits((data >> 2) & SHARP_COMMAND_MASK,
SHARP_COMMAND_BITS);
return true;
}
#endif // (DECODE_SHARP || DECODE_DENON)
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2017 David Conran
#include <algorithm>
#include "IRsend.h"
// SSSSS HH HH EEEEEEE RRRRRR WW WW OOOOO OOOOO DDDDD
// SS HH HH EE RR RR WW WW OO OO OO OO DD DD
// SSSSS HHHHHHH EEEEE RRRRRR WW W WW OO OO OO OO DD DD
// SS HH HH EE RR RR WW WWW WW OO OO OO OO DD DD
// SSSSS HH HH EEEEEEE RR RR WW WW OOOO0 OOOO0 DDDDDD
#if SEND_SHERWOOD
// Send an IR command to a Sherwood device.
//
// Args:
// data: The contents of the command you want to send.
// nbits: The bit size of the command being sent. (SHERWOOD_BITS)
// repeat: The nr. of times you want the command to be repeated. (Default: 1)
//
// Status: STABLE / Known working.
//
// Note:
// Sherwood remote codes appear to be NEC codes with a manditory repeat code.
// i.e. repeat should be >= SHERWOOD_MIN_REPEAT (1).
void IRsend::sendSherwood(uint64_t data, uint16_t nbits,
uint16_t repeat) {
sendNEC(data, nbits, std::max((uint16_t) SHERWOOD_MIN_REPEAT, repeat));
}
#endif
+197
View File
@@ -0,0 +1,197 @@
// Copyright 2009 Ken Shirriff
// Copyright 2016 marcosamarinho
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// SSSS OOO N N Y Y
// S O O NN N Y Y
// SSS O O N N N Y
// S O O N NN Y
// SSSS OOO N N Y
// Sony originally added from https://github.com/shirriff/Arduino-IRremote/
// Updates from marcosamarinho
// Constants
// Ref:
// http://www.sbprojects.com/knowledge/ir/sirc.php
#define SONY_TICK 200U
#define SONY_HDR_MARK_TICKS 12U
#define SONY_HDR_MARK (SONY_HDR_MARK_TICKS * SONY_TICK)
#define SONY_SPACE_TICKS 3U
#define SONY_SPACE (SONY_SPACE_TICKS * SONY_TICK)
#define SONY_ONE_MARK_TICKS 6U
#define SONY_ONE_MARK (SONY_ONE_MARK_TICKS * SONY_TICK)
#define SONY_ZERO_MARK_TICKS 3U
#define SONY_ZERO_MARK (SONY_ZERO_MARK_TICKS * SONY_TICK)
#define SONY_RPT_LENGTH_TICKS 225U
#define SONY_RPT_LENGTH (SONY_RPT_LENGTH_TICKS * SONY_TICK)
#define SONY_MIN_GAP_TICKS 50U
#define SONY_MIN_GAP (SONY_MIN_GAP_TICKS * SONY_TICK)
#if SEND_SONY
// Send a Sony/SIRC(Serial Infra-Red Control) message.
//
// Args:
// data: message to be sent.
// nbits: Nr. of bits of the message to be sent.
// repeat: Nr. of additional times the message is to be sent. (Default: 2)
//
// Status: STABLE / Known working.
//
// Notes:
// sendSony() should typically be called with repeat=2 as Sony devices
// expect the message to be sent at least 3 times.
//
// Ref:
// http://www.sbprojects.com/knowledge/ir/sirc.php
void IRsend::sendSony(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Sony devices use a 40kHz IR carrier frequency & a 1/3 (33%) duty cycle.
enableIROut(40, 33);
IRtimer usecs = IRtimer();
for (uint16_t i = 0; i <= repeat; i++) { // Typically loop 3 or more times.
usecs.reset();
// Header
mark(SONY_HDR_MARK);
space(SONY_SPACE);
// Data
sendData(SONY_ONE_MARK, SONY_SPACE, SONY_ZERO_MARK, SONY_SPACE,
data, nbits, true);
// Footer
// The Sony protocol requires us to wait 45ms from start of a code to the
// start of the next one. A 10ms minimum gap is also required.
space(std::max(SONY_MIN_GAP, SONY_RPT_LENGTH - usecs.elapsed()));
}
// A space() is always performed last, so no need to turn off the LED.
}
// Convert Sony/SIRC command, address, & extended bits into sendSony format.
// Args:
// nbits: Sony protocol bit size.
// command: Sony command bits.
// address: Sony address bits.
// extended: Sony extended bits.
// Returns:
// A sendSony compatible data message.
//
// Status: BETA / Should be working.
uint32_t IRsend::encodeSony(uint16_t nbits, uint16_t command,
uint16_t address, uint16_t extended) {
uint32_t result = 0;
switch (nbits) {
case 12: // 5 address bits.
result = address & 0x1F;
break;
case 15: // 8 address bits.
result = address & 0xFF;
break;
case 20: // 5 address bits, 8 extended bits.
result = address & 0x1F;
result |= (extended & 0xFF) << 5;
break;
default:
return 0; // This is not an expected Sony bit size/protocol.
}
result = (result << 7) | (command & 0x7F); // All sizes have 7 command bits.
return reverseBits(result, nbits); // sendSony uses reverse ordered bits.
}
#endif
#if DECODE_SONY
// Decode the supplied Sony/SIRC message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: The number of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should be working. strict mode is ALPHA / Untested.
//
// Notes:
// SONY protocol, SIRC (Serial Infra-Red Control) can be 12,15,20 bits long.
// Ref:
// http://www.sbprojects.com/knowledge/ir/sirc.php
bool IRrecv::decodeSony(decode_results *results, uint16_t nbits, bool strict) {
if (results->rawlen < 2 * nbits + HEADER - 1)
return false; // Message is smaller than we expected.
// Compliance
if (strict) {
switch (nbits) { // Check we've been called with a correct bit size.
case 12:
case 15:
case 20:
break;
default:
return false; // The request doesn't strictly match the protocol defn.
}
}
uint64_t data = 0;
uint16_t offset = OFFSET_START;
uint16_t actualBits;
uint32_t timeSoFar = 0; // Time in uSecs of the message length.
// Header
timeSoFar += results->rawbuf[offset] * RAWTICK;
if (!matchMark(results->rawbuf[offset], SONY_HDR_MARK))
return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t tick = results->rawbuf[offset++] * RAWTICK / SONY_HDR_MARK_TICKS;
// Data
for (actualBits = 0; offset < results->rawlen - 1; actualBits++, offset++) {
// The gap after a Sony packet for a repeat should be SONY_MIN_GAP or
// (SONY_RPT_LENGTH - timeSoFar) according to the spec.
if (matchSpace(results->rawbuf[offset], SONY_MIN_GAP_TICKS * tick) ||
matchAtLeast(results->rawbuf[offset], SONY_RPT_LENGTH - timeSoFar))
break; // Found a repeat space.
timeSoFar += results->rawbuf[offset] * RAWTICK;
if (!matchSpace(results->rawbuf[offset++], SONY_SPACE_TICKS * tick))
return false;
timeSoFar += results->rawbuf[offset] * RAWTICK;
if (matchMark(results->rawbuf[offset], SONY_ONE_MARK_TICKS * tick))
data = (data << 1) | 1;
else if (matchMark(results->rawbuf[offset], SONY_ZERO_MARK_TICKS * tick))
data <<= 1;
else
return false;
}
// No Footer for Sony.
// Compliance
if (strict && actualBits != nbits)
return false; // We got the wrong number of bits.
// Success
results->bits = actualBits;
results->value = data;
results->decode_type = SONY;
// Message comes in LSB first. Convert ot MSB first.
data = reverseBits(data, actualBits);
// Decode the address & command from raw decode value.
switch (actualBits) {
case 12: // 7 command bits, 5 address bits.
case 15: // 7 command bits, 8 address bits.
results->command = data & 0x7F; // Bits 0-6
results->address = data >> 7; // Bits 7-14
break;
case 20: // 7 command bits, 5 address bits, 8 extended (command) bits.
results->command = (data & 0x7F) + ((data >> 12) << 7); // Bits 0-6,12-19
results->address = (data >> 7) & 0x1F; // Bits 7-11
break;
default: // Shouldn't happen, but just in case.
results->address = 0;
results->command = 0;
}
return true;
}
#endif
+151
View File
@@ -0,0 +1,151 @@
// Copyright 2017 stufisher
#include "ir_Trotec.h"
#include "IRremoteESP8266.h"
#include "IRutils.h"
// Constants
#define TROTEC_HDR_MARK 5952U
#define TROTEC_HDR_SPACE 7364U
#define TROTEC_ONE_MARK 592U
#define TROTEC_ONE_SPACE 1560U
#define TROTEC_ZERO_MARK 592U
#define TROTEC_ZERO_SPACE 592U
#define TROTEC_GAP 6184U
#define TROTEC_GAP_END 1500U // made up value
#if SEND_TROTEC
void IRsend::sendTrotec(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
if (nbytes < TROTEC_COMMAND_LENGTH)
return;
enableIROut(36);
for (uint16_t r = 0; r <= repeat; r++) {
// Header
mark(TROTEC_HDR_MARK);
space(TROTEC_HDR_SPACE);
// Data
for (uint16_t i = 0; i < nbytes; i++)
sendData(TROTEC_ONE_MARK, TROTEC_ONE_SPACE, TROTEC_ZERO_MARK,
TROTEC_ZERO_SPACE, data[i], 8, false);
// Footer
mark(TROTEC_ONE_MARK);
space(TROTEC_GAP);
mark(TROTEC_ONE_MARK);
space(TROTEC_GAP_END);
}
}
IRTrotecESP::IRTrotecESP(uint16_t pin) : _irsend(pin) {
stateReset();
}
void IRTrotecESP::begin() {
_irsend.begin();
}
void IRTrotecESP::send() {
checksum();
_irsend.sendTrotec(trotec);
}
void IRTrotecESP::checksum() {
uint8_t sum = 0;
uint8_t i;
for (i = 2; i < 8; i++) sum += trotec[i];
trotec[8] = sum & 0xFF;
}
void IRTrotecESP::stateReset() {
for (uint8_t i = 2; i < TROTEC_COMMAND_LENGTH; i++)
trotec[i] = 0x0;
trotec[0] = TROTEC_INTRO1;
trotec[1] = TROTEC_INTRO2;
setPower(false);
setTemp(TROTEC_DEF_TEMP);
setSpeed(TROTEC_FAN_MED);
setMode(TROTEC_AUTO);
}
uint8_t* IRTrotecESP::getRaw() {
checksum();
return trotec;
}
void IRTrotecESP::setPower(bool state) {
if (state)
trotec[2] |= (TROTEC_ON << 3);
else
trotec[2] &= ~(TROTEC_ON << 3);
}
uint8_t IRTrotecESP::getPower() {
return trotec[2] & (TROTEC_ON << 3);
}
void IRTrotecESP::setSpeed(uint8_t speed) {
trotec[2] = (trotec[2] & 0xcf) | (speed << 4);
}
uint8_t IRTrotecESP::getSpeed() {
return trotec[2] & 0x30;
}
void IRTrotecESP::setMode(uint8_t mode) {
trotec[2] = (trotec[2] & 0xfc) | mode;
}
uint8_t IRTrotecESP::getMode() {
return trotec[2] & 0x03;
}
void IRTrotecESP::setTemp(uint8_t temp) {
if (temp < TROTEC_MIN_TEMP)
temp = TROTEC_MIN_TEMP;
else if (temp > TROTEC_MAX_TEMP)
temp = TROTEC_MAX_TEMP;
trotec[3] = (trotec[3] & 0x80) | (temp - TROTEC_MIN_TEMP);
}
uint8_t IRTrotecESP::getTemp() {
return trotec[3] & 0x7f;
}
void IRTrotecESP::setSleep(bool sleep) {
if (sleep)
trotec[3] |= (TROTEC_SLEEP_ON << 7);
else
trotec[3] &= ~(TROTEC_SLEEP_ON << 7);
}
bool IRTrotecESP::getSleep(void) {
return trotec[3] & (TROTEC_SLEEP_ON << 7);
}
void IRTrotecESP::setTimer(uint8_t timer) {
if (timer > TROTEC_MAX_TIMER) timer = TROTEC_MAX_TIMER;
if (timer) {
trotec[5] |= (TROTEC_TIMER_ON << 6);
trotec[6] = timer;
} else {
trotec[5] &= ~(TROTEC_TIMER_ON << 6);
trotec[6] = 0;
}
}
uint8_t IRTrotecESP::getTimer() {
return trotec[6];
}
#endif // SEND_TROTEC
+80
View File
@@ -0,0 +1,80 @@
// Copyright 2017 stufisher
#ifndef IR_TROTEC_H_
#define IR_TROTEC_H_
#include "IRremoteESP8266.h"
#include "IRsend.h"
// Constants
// Byte 0
#define TROTEC_INTRO1 0x12
// Byte 1
#define TROTEC_INTRO2 0x34
// Byte 2
#define TROTEC_AUTO 0
#define TROTEC_COOL 1
#define TROTEC_DRY 2
#define TROTEC_FAN 3
#define TROTEC_ON 1
#define TROTEC_OFF 0
#define TROTEC_FAN_LOW 1
#define TROTEC_FAN_MED 2
#define TROTEC_FAN_HIGH 3
// Byte 3
#define TROTEC_MIN_TEMP 18
#define TROTEC_MAX_TEMP 32
#define TROTEC_DEF_TEMP 25
#define TROTEC_SLEEP_ON 1
// Byte 5
#define TROTEC_TIMER_ON 1
// Byte 6
#define TROTEC_MIN_TIMER 0
#define TROTEC_MAX_TIMER 23
#if SEND_TROTEC
class IRTrotecESP {
public:
explicit IRTrotecESP(uint16_t pin);
void send();
void begin();
void setPower(bool state);
uint8_t getPower();
void setTemp(uint8_t temp);
uint8_t getTemp();
void setSpeed(uint8_t fan);
uint8_t getSpeed();
uint8_t getMode();
void setMode(uint8_t mode);
bool getSleep();
void setSleep(bool sleep);
uint8_t getTimer();
void setTimer(uint8_t timer);
uint8_t* getRaw();
private:
uint8_t trotec[TROTEC_COMMAND_LENGTH];
void stateReset();
void checksum();
IRsend _irsend;
};
#endif
#endif // IR_TROTEC_H_
+144
View File
@@ -0,0 +1,144 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017 David Conran
#include <algorithm>
#include "IRrecv.h"
#include "IRsend.h"
#include "IRtimer.h"
#include "IRutils.h"
// W W H H Y Y N N TTTTT EEEEE RRRRR
// W W H H Y Y NN N T E R R
// W W W HHHHH Y N N N T EEE RRRR
// W W W H H Y N NN T E R R
// WWW H H Y N N T EEEEE R R
// Whynter A/C ARC-110WD added by Francesco Meschia
// Whynter originally added from https://github.com/shirriff/Arduino-IRremote/
// Constants
#define WHYNTER_TICK 50U
#define WHYNTER_HDR_MARK_TICKS 57U
#define WHYNTER_HDR_MARK (WHYNTER_HDR_MARK_TICKS * WHYNTER_TICK)
#define WHYNTER_HDR_SPACE_TICKS 57U
#define WHYNTER_HDR_SPACE (WHYNTER_HDR_SPACE_TICKS * \
WHYNTER_TICK)
#define WHYNTER_BIT_MARK_TICKS 15U
#define WHYNTER_BIT_MARK (WHYNTER_BIT_MARK_TICKS * WHYNTER_TICK)
#define WHYNTER_ONE_SPACE_TICKS 43U
#define WHYNTER_ONE_SPACE (WHYNTER_ONE_SPACE_TICKS * \
WHYNTER_TICK)
#define WHYNTER_ZERO_SPACE_TICKS 15U
#define WHYNTER_ZERO_SPACE (WHYNTER_ZERO_SPACE_TICKS * \
WHYNTER_TICK)
#define WHYNTER_MIN_COMMAND_LENGTH_TICKS 2160U // Completely made up value.
#define WHYNTER_MIN_COMMAND_LENGTH (WHYNTER_MIN_COMMAND_LENGTH_TICKS * \
WHYNTER_TICK)
#define WHYNTER_MIN_GAP_TICKS (WHYNTER_MIN_COMMAND_LENGTH_TICKS - \
(2 * (WHYNTER_BIT_MARK_TICKS + WHYNTER_ZERO_SPACE_TICKS) + \
WHYNTER_BITS * (WHYNTER_BIT_MARK_TICKS + WHYNTER_ONE_SPACE_TICKS)))
#define WHYNTER_MIN_GAP (WHYNTER_MIN_GAP_TICKS * WHYNTER_TICK)
#if SEND_WHYNTER
// Send a Whynter message.
//
// Args:
// data: message to be sent.
// nbits: Nr. of bits of the message to be sent.
// repeat: Nr. of additional times the message is to be sent.
//
// Status: STABLE
//
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Whynter.cpp
void IRsend::sendWhynter(uint64_t data, uint16_t nbits, uint16_t repeat) {
// Set IR carrier frequency
enableIROut(38);
IRtimer usecTimer = IRtimer();
for (uint16_t i = 0; i <= repeat; i++) {
usecTimer.reset();
// Header
mark(WHYNTER_BIT_MARK);
space(WHYNTER_ZERO_SPACE);
mark(WHYNTER_HDR_MARK);
space(WHYNTER_HDR_SPACE);
// Data
sendData(WHYNTER_BIT_MARK, WHYNTER_ONE_SPACE, WHYNTER_BIT_MARK,
WHYNTER_ZERO_SPACE, data, nbits, true);
// Footer
mark(WHYNTER_BIT_MARK);
space(std::max(WHYNTER_MIN_COMMAND_LENGTH - usecTimer.elapsed(),
WHYNTER_MIN_GAP));
}
}
#endif
#if DECODE_WHYNTER
// Decode the supplied Whynter message.
//
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of data bits to expect.
// strict: Flag indicating if we should perform strict matching.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA Strict mode is ALPHA.
//
// Ref:
// https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Whynter.cpp
bool IRrecv::decodeWhynter(decode_results *results, uint16_t nbits,
bool strict) {
if (results->rawlen < 2 * nbits + 2 * HEADER + FOOTER - 1)
return false; // We don't have enough entries to possibly match.
// Compliance
if (strict && nbits != WHYNTER_BITS)
return false; // Incorrect nr. of bits per spec.
uint16_t offset = OFFSET_START;
// Header
// Sequence begins with a bit mark and a zero space.
// These are typically small, so we'll prefer to do the calibration
// on the much larger header mark & space that are next.
if (!matchMark(results->rawbuf[offset++], WHYNTER_BIT_MARK)) return false;
if (!matchSpace(results->rawbuf[offset++], WHYNTER_ZERO_SPACE)) return false;
// Main header mark and space
if (!matchMark(results->rawbuf[offset], WHYNTER_HDR_MARK)) return false;
// Calculate how long the common tick time is based on the header mark.
uint32_t m_tick = results->rawbuf[offset++] * RAWTICK /
WHYNTER_HDR_MARK_TICKS;
if (!matchSpace(results->rawbuf[offset], WHYNTER_HDR_SPACE)) return false;
// Calculate how long the common tick time is based on the header space.
uint32_t s_tick = results->rawbuf[offset++] * RAWTICK /
WHYNTER_HDR_SPACE_TICKS;
// Data
uint64_t data = 0;
match_result_t data_result = matchData(&(results->rawbuf[offset]), nbits,
WHYNTER_BIT_MARK_TICKS * m_tick,
WHYNTER_ONE_SPACE_TICKS * s_tick,
WHYNTER_BIT_MARK_TICKS * m_tick,
WHYNTER_ZERO_SPACE_TICKS * s_tick);
if (data_result.success == false) return false;
data = data_result.data;
offset += data_result.used;
// Footer
if (!matchMark(results->rawbuf[offset++], WHYNTER_BIT_MARK_TICKS * m_tick))
return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], WHYNTER_MIN_GAP_TICKS * s_tick))
return false;
// Success
results->decode_type = WHYNTER;
results->bits = nbits;
results->value = data;
results->address = 0;
results->command = 0;
return true;
}
#endif
+448
View File
@@ -0,0 +1,448 @@
// Copyright 2017 David Conran
#include "IRremoteESP8266.h"
#include "IRrecv.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for the IRrecv object.
TEST(TestIRrecv, DefaultBufferSize) {
IRrecv irrecv_default(1);
EXPECT_EQ(RAWBUF, irrecv_default.getBufSize());
}
TEST(TestIRrecv, LargeBufferSize) {
IRrecv irrecv_large(3, 1024);
EXPECT_EQ(1024, irrecv_large.getBufSize());
}
TEST(TestIRrecv, SmallBufferSize) {
IRrecv irrecv_small(4, 80);
EXPECT_EQ(80, irrecv_small.getBufSize());
}
TEST(TestIRrecv, MediumBufferSize) {
IRrecv irrecv_medium(4, 512);
EXPECT_EQ(512, irrecv_medium.getBufSize());
}
TEST(TestIRrecv, IRrecvDestructor) {
IRrecv *irrecv_ptr = new IRrecv(1);
EXPECT_EQ(RAWBUF, irrecv_ptr->getBufSize());
delete irrecv_ptr;
irrecv_ptr = new IRrecv(1, 1234);
EXPECT_EQ(1234, irrecv_ptr->getBufSize());
delete irrecv_ptr;
irrecv_ptr = new IRrecv(1, 123);
EXPECT_EQ(123, irrecv_ptr->getBufSize());
delete irrecv_ptr;
}
// Tests for copyIrParams()
TEST(TestCopyIrParams, CopyEmpty) {
irparams_t src;
irparams_t dst;
uint16_t test_size = 1234;
src.bufsize = test_size;
src.rawlen = 0;
src.rawbuf = new uint16_t[test_size];
src.overflow = false;
dst.bufsize = 4567;
dst.rawlen = 123;
dst.rawbuf = new uint16_t[test_size];
dst.overflow = true;
// Confirm we are looking at different memory for the buffers.
ASSERT_NE(src.rawbuf, dst.rawbuf);
IRrecv irrecv(4);
irrecv.copyIrParams(&src, &dst);
ASSERT_EQ(src.bufsize, dst.bufsize);
ASSERT_EQ(src.rawlen, dst.rawlen);
ASSERT_NE(src.rawbuf, dst.rawbuf); // Pointers, not content.
ASSERT_EQ(src.overflow, dst.overflow);
// Contents of the buffers needs to match.
EXPECT_EQ(0, memcmp(src.rawbuf, dst.rawbuf, src.bufsize * sizeof(uint16_t)));
}
TEST(TestCopyIrParams, CopyNonEmpty) {
irparams_t src;
irparams_t dst;
uint16_t test_size = 1234;
src.bufsize = test_size;
src.rawlen = 67;
src.rawbuf = new uint16_t[test_size];
src.rawbuf[0] = 0xF00D;
src.rawbuf[1] = 0xBEEF;
src.rawbuf[test_size - 1] = 0xDEAD;
src.overflow = true;
dst.bufsize = 0;
dst.rawlen = 0;
dst.rawbuf = new uint16_t[test_size];
dst.overflow = false;
// Confirm we are looking at different memory for the buffers.
ASSERT_NE(src.rawbuf, dst.rawbuf);
// and that they differ before we test.
EXPECT_NE(0, memcmp(src.rawbuf, dst.rawbuf, src.bufsize * sizeof(uint16_t)));
IRrecv irrecv(4);
irrecv.copyIrParams(&src, &dst);
ASSERT_EQ(src.bufsize, dst.bufsize);
EXPECT_EQ(test_size, dst.bufsize);
ASSERT_EQ(src.rawlen, dst.rawlen);
EXPECT_EQ(67, dst.rawlen);
ASSERT_EQ(src.overflow, dst.overflow);
EXPECT_TRUE(dst.overflow);
ASSERT_NE(src.rawbuf, dst.rawbuf); // Pointers, not content.
// Contents of the buffers needs to match.
EXPECT_EQ(0, memcmp(src.rawbuf, dst.rawbuf, src.bufsize * sizeof(uint16_t)));
// Check the canary values.
EXPECT_EQ(0xF00D, dst.rawbuf[0]);
EXPECT_EQ(0xBEEF, dst.rawbuf[1]);
EXPECT_EQ(0xDEAD, dst.rawbuf[test_size - 1]);
}
// Tests for decode().
// Test decode of a NEC message.
TEST(TestDecode, DecodeNEC) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendNEC(0x807F40BF);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x807F40BF, irsend.capture.value);
}
// Test decode of a JVC message.
TEST(TestDecode, DecodeJVC) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendJVC(0xC2B8);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
}
// Test decode of a LG message.
TEST(TestDecode, DecodeLG) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendLG(0x4B4AE51);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG_BITS, irsend.capture.bits);
EXPECT_EQ(0x4B4AE51, irsend.capture.value);
irsend.reset();
irsend.sendLG(0xB4B4AE51, LG32_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG32_BITS, irsend.capture.bits);
EXPECT_EQ(0xB4B4AE51, irsend.capture.value);
}
// Test decode of a Panasonic message.
TEST(TestDecode, DecodePanasonic) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
}
// Test decode of a Samsun message.
TEST(TestDecode, DecodeSamsung) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendSAMSUNG(0xE0E09966);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SAMSUNG, irsend.capture.decode_type);
EXPECT_EQ(SAMSUNG_BITS, irsend.capture.bits);
EXPECT_EQ(0xE0E09966, irsend.capture.value);
}
// Test decode of a Sherwood message.
TEST(TestDecode, DecodeSherwood) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendSherwood(0x807F40BF);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
// Sherwood codes are really NEC codes.
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x807F40BF, irsend.capture.value);
}
// Test decode of a Whynter message.
TEST(TestDecode, DecodeWhynter) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendWhynter(0x87654321);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(WHYNTER, irsend.capture.decode_type);
EXPECT_EQ(WHYNTER_BITS, irsend.capture.bits);
EXPECT_EQ(0x87654321, irsend.capture.value);
}
// Test decode of Sony messages.
TEST(TestDecode, DecodeSony) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
// Synthesised Normal Sony 20-bit message.
irsend.reset();
irsend.sendSony(irsend.encodeSony(SONY_20_BITS, 0x1, 0x1, 0x1));
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SONY, irsend.capture.decode_type);
EXPECT_EQ(SONY_20_BITS, irsend.capture.bits);
EXPECT_EQ(0x81080, irsend.capture.value);
// Synthesised Normal Sony 15-bit message.
irsend.reset();
irsend.sendSony(irsend.encodeSony(SONY_15_BITS, 21, 1), SONY_15_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SONY, irsend.capture.decode_type);
EXPECT_EQ(SONY_15_BITS, irsend.capture.bits);
EXPECT_EQ(0x5480, irsend.capture.value);
// Synthesised Normal Sony 12-bit message.
irsend.reset();
irsend.sendSony(irsend.encodeSony(SONY_12_BITS, 21, 1), SONY_12_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SONY, irsend.capture.decode_type);
EXPECT_EQ(SONY_12_BITS, irsend.capture.bits);
EXPECT_EQ(0xA90, irsend.capture.value);
}
// Test decode of Sharp messages.
TEST(TestDecode, DecodeSharp) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendSharpRaw(0x454A);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SHARP, irsend.capture.decode_type);
EXPECT_EQ(SHARP_BITS, irsend.capture.bits);
EXPECT_EQ(0x454A, irsend.capture.value);
}
// Test decode of Sanyo messages.
TEST(TestDecode, DecodeSanyo) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendSanyoLC7461(0x2468DCB56A9);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SANYO_LC7461, irsend.capture.decode_type);
EXPECT_EQ(SANYO_LC7461_BITS, irsend.capture.bits);
EXPECT_EQ(0x2468DCB56A9, irsend.capture.value);
}
// Test decode of RC-MM messages.
TEST(TestDecode, DecodeRCMM) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
// Normal RCMM 24-bit message.
irsend.reset();
irsend.sendRCMM(0xe0a600);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(RCMM, irsend.capture.decode_type);
EXPECT_EQ(RCMM_BITS, irsend.capture.bits);
EXPECT_EQ(0xe0a600, irsend.capture.value);
// Normal RCMM 12-bit message.
irsend.reset();
irsend.sendRCMM(0x600, 12);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(RCMM, irsend.capture.decode_type);
EXPECT_EQ(12, irsend.capture.bits);
EXPECT_EQ(0x600, irsend.capture.value);
// Normal RCMM 32-bit message.
irsend.reset();
irsend.sendRCMM(0x28e0a600, 32);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(RCMM, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0x28e0a600, irsend.capture.value);
}
// Test decode of Mitsubishi messages.
TEST(TestDecode, DecodeMitsubishi) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendMitsubishi(0xC2B8);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
}
// Test decode of RC-5/RC-5X messages.
TEST(TestDecode, DecodeRC5) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
// Normal RC-5 12-bit message.
irsend.reset();
irsend.sendRC5(0x175);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(RC5, irsend.capture.decode_type);
EXPECT_EQ(RC5_BITS, irsend.capture.bits);
EXPECT_EQ(0x175, irsend.capture.value);
// Synthesised Normal RC-5X 13-bit message.
irsend.reset();
irsend.sendRC5(irsend.encodeRC5X(0x02, 0x41, true), RC5X_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(RC5X, irsend.capture.decode_type);
EXPECT_EQ(RC5X_BITS, irsend.capture.bits);
EXPECT_EQ(0x1881, irsend.capture.value);
}
// Test decode of RC-6 messages.
TEST(TestDecode, DecodeRC6) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
// Normal RC-6 Mode 0 (20-bit) message.
irsend.reset();
irsend.sendRC6(0x175);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(RC6, irsend.capture.decode_type);
EXPECT_EQ(RC6_MODE0_BITS, irsend.capture.bits);
EXPECT_EQ(0x175, irsend.capture.value);
// Normal RC-6 36-bit message.
irsend.reset();
irsend.sendRC6(0xC800F742A, RC6_36_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(RC6, irsend.capture.decode_type);
EXPECT_EQ(RC6_36_BITS, irsend.capture.bits);
EXPECT_EQ(0xC800F742A, irsend.capture.value);
}
// Test decode of Dish messages.
TEST(TestDecode, DecodeDish) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendDISH(0x9C00);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(DISH_BITS, irsend.capture.bits);
EXPECT_EQ(0x9C00, irsend.capture.value);
}
// Test decode of Denon messages.
TEST(TestDecode, DecodeDenon) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
// Normal Denon 15-bit message. (Sharp)
irsend.reset();
irsend.sendDenon(0x2278);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_BITS, irsend.capture.bits);
EXPECT_EQ(0x2278, irsend.capture.value);
// Legacy Denon 14-bit message.
irsend.reset();
irsend.sendDenon(0x1278, DENON_LEGACY_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_BITS, irsend.capture.bits);
EXPECT_EQ(0x1278, irsend.capture.value);
// Normal Denon 48-bit message. (Panasonic/Kaseikyo)
irsend.reset();
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_48_BITS, irsend.capture.bits);
EXPECT_EQ(0x2A4C028D6CE3, irsend.capture.value);
}
// Test decode of Coolix messages.
TEST(TestDecode, DecodeCoolix) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendCOOLIX(0x123456);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(COOLIX_BITS, irsend.capture.bits);
EXPECT_EQ(0x123456, irsend.capture.value);
}
// Test decode of Aiwa messages.
TEST(TestDecode, DecodeAiwa) {
IRsendTest irsend(0);
IRrecv irrecv(1);
irsend.begin();
irsend.reset();
irsend.sendAiwaRCT501(0x7F);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits);
EXPECT_EQ(0x7F, irsend.capture.value);
}
+139
View File
@@ -0,0 +1,139 @@
// Copyright 2017 David Conran
#include "IRsend_test.h"
#include "IRsend.h"
#include "gtest/gtest.h"
// Tests sendData().
// Test sending zero bits.
TEST(TestSendData, SendZeroBits) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1, 0, true);
EXPECT_EQ("", irsend.outputStr());
}
// Test sending zero and one.
TEST(TestSendData, SendSingleBit) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
EXPECT_EQ("m1s2", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
EXPECT_EQ("m3s4", irsend.outputStr());
}
// Test sending bit order.
TEST(TestSendData, TestingBitSendOrder) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b10, 2, true);
EXPECT_EQ("m1s2m3s4", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b10, 2, false);
EXPECT_EQ("m3s4m1s2", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b0001, 4, false);
EXPECT_EQ("m1s2m3s4m3s4m3s4", irsend.outputStr());
}
// Test sending typical data.
TEST(TestSendData, SendTypicalData) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1010110011110000, 16, true);
EXPECT_EQ("m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4m3s4",
irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0x1234567890ABCDEF, 64, true);
EXPECT_EQ("m3s4m3s4m3s4m1s2m3s4m3s4m1s2m3s4m3s4m3s4m1s2m1s2m3s4m1s2m3s4m3s4"
"m3s4m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4"
"m1s2m3s4m3s4m1s2m3s4m3s4m3s4m3s4m1s2m3s4m1s2m3s4m1s2m3s4m1s2m1s2"
"m1s2m1s2m3s4m3s4m1s2m1s2m3s4m1s2m1s2m1s2m1s2m3s4m1s2m1s2m1s2m1s2",
irsend.outputStr());
}
// Test sending more than expected bits.
TEST(TestSendData, SendOverLargeData) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0xFFFFFFFFFFFFFFFF, 70, true);
EXPECT_EQ("m3s4m3s4m3s4m3s4m3s4m3s4"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2",
irsend.outputStr());
}
// Test inverting the output.
TEST(TestIRSend, InvertedOutput) {
IRsendTest irsend(4, true);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
EXPECT_EQ("s1m2", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
EXPECT_EQ("s3m4", irsend.outputStr());
}
// Test typical use of sendRaw().
TEST(TestSendRaw, GeneralUse) {
IRsendTest irsend(4);
IRrecv irrecv(0);
irsend.begin();
// NEC C3E0E0E8 as measured in #204
uint16_t rawData[67] = {8950, 4500, 550, 1650, 600, 1650, 550, 550, 600, 500,
600, 550, 550, 550, 600, 1650, 550, 1650, 600, 1650,
600, 1650, 550, 1700, 550, 550, 600, 550, 550, 550,
600, 500, 600, 550, 550, 1650, 600, 1650, 600, 1650,
550, 550, 600, 500, 600, 500, 600, 550, 550, 550,
600, 1650, 550, 1650, 600, 1650, 600, 500, 650, 1600,
600, 500, 600, 550, 550, 550, 600};
irsend.sendRaw(rawData, 67, 38);
EXPECT_EQ(
"m8950s4500"
"m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
"m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
"m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
"m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
"m600", irsend.outputStr());
irsend.reset();
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
EXPECT_EQ(
"m8950s4500"
"m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
"m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
"m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
"m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
"m600", irsend.outputStr());
ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, NEC_BITS, false));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0xC3E0E0E8, irsend.capture.value);
}
// Incorrect handling of decodes from Raw. i.e. There is no gap recorded at
// the end of a command when using the interrupt code. sendRaw() best emulates
// this for unit testing purposes. sendGC() and sendXXX() will add the trailing
// gap. Users won't see this in normal use.
TEST(TestSendRaw, NoTrailingGap) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650,
600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650,
650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550,
650, 550, 650, 550, 600, 550, 650, 550, 650, 550,
650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
650, 1650, 650, 1650, 650, 1650, 600};
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
}
+104
View File
@@ -0,0 +1,104 @@
// Copyright 2017 David Conran
#ifndef TEST_IRSEND_TEST_H_
#define TEST_IRSEND_TEST_H_
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <iostream>
#include <sstream>
#include <string>
#include "IRrecv.h"
#include "IRsend.h"
#define OUTPUT_BUF 1000U
#define RAW_BUF 1000U
class IRsendTest: public IRsend {
public:
uint32_t output[OUTPUT_BUF];
uint16_t last;
uint16_t rawbuf[RAW_BUF];
decode_results capture;
explicit IRsendTest(uint16_t x, bool i = false) : IRsend(x, i) {
reset();
}
void reset() {
last = 0;
output[last] = 0;
}
std::string outputStr() {
std::stringstream result;
if (last == 0 && output[0] == 0)
return "";
for (uint16_t i = 0; i <= last; i++) {
if ((i & 1) != outputOff ) // Odd XOR outputOff
result << "s";
else
result << "m";
result << output[i];
}
reset();
return result.str();
}
void makeDecodeResult(uint16_t offset = 0) {
capture.decode_type = UNKNOWN;
capture.bits = 0;
capture.rawlen = last + 1 - offset;
capture.overflow = (last - offset >= (int16_t) RAW_BUF);
capture.repeat = false;
capture.address = 0;
capture.command = 0;
capture.value = 0;
capture.rawbuf = rawbuf;
for (uint16_t i = 0;
(i < RAW_BUF - 1) && (offset < OUTPUT_BUF);
i++, offset++)
if (output[offset] / RAWTICK > UINT16_MAX)
rawbuf[i + 1] = UINT16_MAX;
else
rawbuf[i + 1] = output[offset] / RAWTICK;
}
void dumpRawResult() {
std::cout << "uint16_t rawbuf["<< capture.rawlen << "] =\n";
for (uint16_t i = 0; i < capture.rawlen; i++) {
std::cout << (capture.rawbuf[i] * RAWTICK);
std::cout << "(";
std::cout << capture.rawbuf[i];
std::cout << "), ";
if (i % 8 == 7)
std::cout << "\n";
}
std::cout << "\n";
}
void addGap(uint32_t usecs) {
space(usecs);
}
protected:
uint16_t mark(uint16_t usec) {
if (last >= OUTPUT_BUF)
return 0;
if (last & 1) // Is odd? (i.e. last call was a space())
output[++last] = usec;
else
output[last] += usec;
return 0;
}
void space(uint32_t time) {
if (last >= OUTPUT_BUF)
return;
if (last & 1) { // Is odd? (i.e. last call was a space())
output[last] += time;
} else {
output[++last] = time;
}
}
};
#endif // TEST_IRSEND_TEST_H_
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2017 David Conran
#include "IRutils.h"
#include "gtest/gtest.h"
// Tests reverseBits().
// Tests reverseBits for typical use.
TEST(ReverseBitsTest, TypicalUse) {
EXPECT_EQ(0xF, reverseBits(0xF0, 8));
EXPECT_EQ(0xFFFF, reverseBits(0xFFFF0000, 32));
EXPECT_EQ(0x555500005555FFFF, reverseBits(0xFFFFAAAA0000AAAA, 64));
EXPECT_EQ(0, reverseBits(0, 64));
EXPECT_EQ(0xFFFFFFFFFFFFFFFF, reverseBits(0xFFFFFFFFFFFFFFFF, 64));
}
// Tests reverseBits for bit size values <= 1
TEST(ReverseBitsTest, LessThanTwoBitsReversed) {
EXPECT_EQ(0x12345678, reverseBits(0x12345678, 1));
EXPECT_EQ(1234, reverseBits(1234, 0));
}
// Tests reverseBits for bit size larger than a uint64_t.
TEST(ReverseBitsTest, LargerThan64BitsReversed) {
EXPECT_EQ(0, reverseBits(0, 65));
EXPECT_EQ(0xFFFFFFFFFFFFFFFF, reverseBits(0xFFFFFFFFFFFFFFFF, 100));
EXPECT_EQ(0x555500005555FFFF, reverseBits(0xFFFFAAAA0000AAAA, 3000));
}
// Tests reverseBits for bit sizes less than all the data stored.
TEST(ReverseBitsTest, LessBitsReversedThanInputHasSet) {
EXPECT_EQ(0xF8, reverseBits(0xF1, 4));
EXPECT_EQ(0xF5, reverseBits(0xFA, 4));
EXPECT_EQ(0x12345678FFFF0000, reverseBits(0x123456780000FFFF, 32));
}
+339
View File
@@ -0,0 +1,339 @@
# SYNOPSIS:
#
# make [all] - makes everything.
# make TARGET - makes the given target.
# make clean - removes all files generated by make.
# Please tweak the following variable definitions as needed by your
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.
# Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file.
GTEST_DIR = ../lib/googletest/googletest
# Where to find user code.
USER_DIR = ../src
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
# the compiler doesn't generate warnings in Google Test headers.
CPPFLAGS += -isystem $(GTEST_DIR)/include -DUNIT_TEST
# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra -pthread
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
TESTS = IRutils_test IRsend_test ir_NEC_test ir_GlobalCache_test \
ir_Sherwood_test ir_Sony_test ir_Samsung_test ir_Kelvinator_test \
ir_JVC_test ir_RCMM_test ir_LG_test ir_Mitsubishi_test ir_Sharp_test \
ir_RC5_RC6_test ir_Panasonic_test ir_Dish_test ir_Whynter_test \
ir_Aiwa_test ir_Denon_test ir_Sanyo_test ir_Daikin_test ir_Coolix_test \
ir_Gree_test IRrecv_test ir_Pronto_test ir_Fujitsu_test
# All Google Test headers. Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
# House-keeping build targets.
all : $(TESTS)
clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o
# Build and run all the tests.
run : all
failed=""; \
for unittest in $(TESTS); do \
./$${unittest} || failed="$${failed} $${unittest}"; \
done; \
if [ -n "$${failed}" ]; then \
echo "FAIL: :-( :-( Unit test(s)$${failed} failed! :-( :-("; exit 1; \
else \
echo "PASS: \o/ \o/ All unit tests passed. \o/ \o/"; \
fi
install-googletest :
git clone https://github.com/google/googletest.git ../lib/googletest
# Builds gtest.a and gtest_main.a.
# Usually you shouldn't tweak such internal variables, indicated by a
# trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
# All the IR protocol object files.
PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \
ir_LG.o ir_Mitsubishi.o ir_Fujitsu.o ir_Sharp.o ir_Sanyo.o ir_Denon.o ir_Dish.o \
ir_Panasonic.o ir_Whynter.o ir_Coolix.o ir_Aiwa.o ir_Sherwood.o \
ir_Kelvinator.o ir_Daikin.o ir_Gree.o ir_Pronto.o
# Common object files
COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o ir_GlobalCache.o \
$(PROTOCOLS) gtest_main.a
# Common dependencies
COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \
$(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h
# Common test dependencies
COMMON_TEST_DEPS = $(COMMON_DEPS) IRsend_test.h
# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc
gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $@ $^
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $@ $^
# Builds a our test. A test should link with either gtest.a or
# gtest_main.a, depending on whether it defines its own main()
# function.
IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRutils.cpp
IRutils_test.o : IRutils_test.cpp $(USER_DIR)/IRutils.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRutils_test.cpp
IRutils_test : IRutils.o IRutils_test.o gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
IRtimer.o : $(USER_DIR)/IRtimer.cpp $(USER_DIR)/IRtimer.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRtimer.cpp
IRsend.o : $(USER_DIR)/IRsend.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRremoteESP8266.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRsend.cpp
IRsend_test.o : IRsend_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRsend_test.cpp
IRsend_test : IRsend_test.o $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
IRrecv.o : $(USER_DIR)/IRrecv.cpp $(USER_DIR)/IRrecv.h $(USER_DIR)/IRremoteESP8266.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRrecv.cpp
IRrecv_test.o : IRrecv_test.cpp $(USER_DIR)/IRsend.h $(USER_DIR)/IRrecv.h IRsend_test.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c IRrecv_test.cpp
IRrecv_test : IRrecv_test.o $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_NEC.o : $(USER_DIR)/ir_NEC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_NEC.cpp
ir_NEC_test.o : ir_NEC_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_NEC_test.cpp
ir_NEC_test : $(COMMON_OBJ) ir_NEC_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_GlobalCache.o : $(USER_DIR)/ir_GlobalCache.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_GlobalCache.cpp
ir_GlobalCache_test.o : ir_GlobalCache_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_GlobalCache_test.cpp
ir_GlobalCache_test : $(COMMON_OBJ) ir_GlobalCache_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Sherwood.o : $(USER_DIR)/ir_Sherwood.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sherwood.cpp
ir_Sherwood_test.o : ir_Sherwood_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sherwood_test.cpp
ir_Sherwood_test : $(COMMON_OBJ) ir_Sherwood_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Sony.o : $(USER_DIR)/ir_Sony.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sony.cpp
ir_Sony_test.o : ir_Sony_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sony_test.cpp
ir_Sony_test : $(COMMON_OBJ) ir_Sony_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Samsung.o : $(USER_DIR)/ir_Samsung.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Samsung.cpp
ir_Samsung_test.o : ir_Samsung_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Samsung_test.cpp
ir_Samsung_test : $(COMMON_OBJ) ir_Samsung_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Kelvinator.o : $(USER_DIR)/ir_Kelvinator.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Kelvinator.cpp
ir_Kelvinator_test.o : ir_Kelvinator_test.cpp $(USER_DIR)/ir_Kelvinator.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Kelvinator_test.cpp
ir_Kelvinator_test : $(COMMON_OBJ) ir_Kelvinator_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_JVC.o : $(USER_DIR)/ir_JVC.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_JVC.cpp
ir_JVC_test.o : ir_JVC_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_JVC_test.cpp
ir_JVC_test : $(COMMON_OBJ) ir_JVC_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_RCMM.o : $(USER_DIR)/ir_RCMM.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RCMM.cpp
ir_RCMM_test.o : ir_RCMM_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_RCMM_test.cpp
ir_RCMM_test : $(COMMON_OBJ) ir_RCMM_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_LG.o : $(USER_DIR)/ir_LG.h $(USER_DIR)/ir_LG.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_LG.cpp
ir_LG_test.o : ir_LG_test.cpp $(USER_DIR)/ir_LG.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_LG_test.cpp
ir_LG_test : $(COMMON_OBJ) ir_LG_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Mitsubishi.o : $(USER_DIR)/ir_Mitsubishi.h $(USER_DIR)/ir_Mitsubishi.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Mitsubishi.cpp
ir_Mitsubishi_test.o : ir_Mitsubishi_test.cpp $(USER_DIR)/ir_Mitsubishi.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Mitsubishi_test.cpp
ir_Mitsubishi_test : $(COMMON_OBJ) ir_Mitsubishi_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Fujitsu.o : $(USER_DIR)/ir_Fujitsu.h $(USER_DIR)/ir_Fujitsu.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Fujitsu.cpp
ir_Fujitsu_test.o : ir_Fujitsu_test.cpp $(USER_DIR)/ir_Fujitsu.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Fujitsu_test.cpp
ir_Fujitsu_test : $(COMMON_OBJ) ir_Fujitsu_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Sharp.o : $(USER_DIR)/ir_Sharp.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sharp.cpp
ir_Sharp_test.o : ir_Sharp_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sharp_test.cpp
ir_Sharp_test : $(COMMON_OBJ) ir_Sharp_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_RC5_RC6.o : $(USER_DIR)/ir_RC5_RC6.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RC5_RC6.cpp
ir_RC5_RC6_test.o : ir_RC5_RC6_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_RC5_RC6_test.cpp
ir_RC5_RC6_test : $(COMMON_OBJ) ir_RC5_RC6_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Panasonic.o : $(USER_DIR)/ir_Panasonic.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Panasonic.cpp
ir_Panasonic_test.o : ir_Panasonic_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Panasonic_test.cpp
ir_Panasonic_test : $(COMMON_OBJ) ir_Panasonic_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Dish.o : $(USER_DIR)/ir_Dish.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Dish.cpp
ir_Dish_test.o : ir_Dish_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Dish_test.cpp
ir_Dish_test : $(COMMON_OBJ) ir_Dish_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Whynter.o : $(USER_DIR)/ir_Whynter.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Whynter.cpp
ir_Whynter_test.o : ir_Whynter_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Whynter_test.cpp
ir_Whynter_test : $(COMMON_OBJ) ir_Whynter_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Coolix.o : $(USER_DIR)/ir_Coolix.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Coolix.cpp
ir_Coolix_test.o : ir_Coolix_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Coolix_test.cpp
ir_Coolix_test : $(COMMON_OBJ) ir_Coolix_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Aiwa.o : $(USER_DIR)/ir_Aiwa.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Aiwa.cpp
ir_Aiwa_test.o : ir_Aiwa_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Aiwa_test.cpp
ir_Aiwa_test : $(COMMON_OBJ) ir_Aiwa_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Denon.o : $(USER_DIR)/ir_Denon.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Denon.cpp
ir_Denon_test.o : ir_Denon_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Denon_test.cpp
ir_Denon_test : $(COMMON_OBJ) ir_Denon_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Sanyo.o : $(USER_DIR)/ir_Sanyo.cpp $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Sanyo.cpp
ir_Sanyo_test.o : ir_Sanyo_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Sanyo_test.cpp
ir_Sanyo_test : $(COMMON_OBJ) ir_Sanyo_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Daikin.o : $(USER_DIR)/ir_Daikin.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Daikin.cpp
ir_Daikin_test.o : ir_Daikin_test.cpp $(USER_DIR)/ir_Daikin.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Daikin_test.cpp
ir_Daikin_test : $(COMMON_OBJ) ir_Daikin_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Gree.o : $(USER_DIR)/ir_Gree.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Gree.cpp
ir_Gree_test.o : ir_Gree_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Gree_test.cpp
ir_Gree_test : $(COMMON_OBJ) ir_Gree_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
ir_Pronto.o : $(USER_DIR)/ir_Pronto.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Pronto.cpp
ir_Pronto_test.o : ir_Pronto_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -I$(USER_DIR) -c ir_Pronto_test.cpp
ir_Pronto_test : $(COMMON_OBJ) ir_Pronto_test.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
+338
View File
@@ -0,0 +1,338 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendAiwaRCT501().
// Test sending typical data only.
TEST(TestSendAiwa, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendAiwaRCT501(0x7F); // Aiwa Power Toggle.
EXPECT_EQ(
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s108080"
"m8960s2240m560s108080", irsend.outputStr());
}
// Test sending oversized data.
TEST(TestSendAiwa, SendOversizedData) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendAiwaRCT501(0x7F, 38); // 38 bits is over the maximum. Should fail.
EXPECT_EQ("", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendAiwa, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 0); // No repeats.
EXPECT_EQ(
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s108080", irsend.outputStr());
irsend.reset();
irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s108080"
"m8960s2240m560s108080", irsend.outputStr());
irsend.reset();
irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s108080"
"m8960s2240m560s108080"
"m8960s2240m560s108080", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendAiwa, SendUsualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendAiwaRCT501(0x12, 8);
EXPECT_EQ(
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s108080"
"m8960s2240m560s108080", irsend.outputStr());
irsend.reset();
irsend.sendAiwaRCT501(0x1234567890, 37);
EXPECT_EQ(
"m8960s4480"
"m560s560m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s1680"
"m560s560m560s560m560s1680m560s560m560s560m560s560m560s560m560s1680"
"m560s108080"
"m8960s2240m560s108080", irsend.outputStr());
}
// Tests for decodeAiwaRCT501().
// Decode normal Aiwa messages.
TEST(TestDecodeAiwa, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Aiwa 15-bit(42bit) message.
irsend.reset();
irsend.sendAiwaRCT501(0x7F);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits);
EXPECT_EQ(0x7F, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal Aiwa 15-bit(42bit) message.
irsend.reset();
irsend.sendAiwaRCT501(0x0);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal Aiwa 15-bit(42bit) message.
irsend.reset();
irsend.sendAiwaRCT501(0x7FFF);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits);
EXPECT_EQ(0x7FFF, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode normal repeated Aiwa messages.
TEST(TestDecodeAiwa, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Aiwa 15-bit(42bit) message with 2 repeats.
irsend.reset();
irsend.sendAiwaRCT501(0x7F, AIWA_RC_T501_BITS, 2);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits);
EXPECT_EQ(0x7F, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode unsupported Aiwa messages.
TEST(TestDecodeAiwa, DecodeWithNonStrictValues) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Confirm using sendNEC(data, 42, 1) can make a legal Aiwa message.
irsend.sendNEC(0x1D8113F00FF, 42, AIWA_RC_T501_MIN_REPEAT);
irsend.makeDecodeResult();
// MUST pass with strict on.
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
ASSERT_EQ(0x7F, irsend.capture.value);
irsend.reset();
// Use sendNEC(data, 42) to make/send an illegal value Aiwa message.
// Value is illegal due to bad pre & post data.
irsend.sendNEC(0x1234567890A, 42, AIWA_RC_T501_MIN_REPEAT);
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
// Should fail if strict off too.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
false));
irsend.reset();
// Use sendNEC(data, 42) to make/send an illegal value Aiwa message.
// Value is illegal due to bad post data only.
irsend.sendNEC(0x1D8113F00FE, 42, AIWA_RC_T501_MIN_REPEAT);
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
// Should fail if strict off too.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
false));
irsend.reset();
// Use sendNEC(data, 42) to make/send an illegal value Aiwa message.
// Value is illegal due to bad pre data only.
irsend.sendNEC(0x0D8113F00FF, 42, AIWA_RC_T501_MIN_REPEAT);
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
// Should fail if strict off too.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
false));
}
// Decode unsupported Aiwa messages.
TEST(TestDecodeAiwa, DecodeWithNonStrictSizes) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendAiwaRCT501(0x0, 8); // Illegal size Aiwa 8-bit message.
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, 8, false));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(8, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
irsend.reset();
irsend.sendAiwaRCT501(0x12345678, 32); // Illegal size Aiwa 32-bit message.
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
true));
// Should fail with strict when we ask for the wrong bit size.
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, 32, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, 32, false));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0x12345678, irsend.capture.value);
}
// Decode (non-standard) 64-bit messages.
TEST(TestDecodeAiwa, Decode64BitMessages) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Illegal value & size Aiwa 37(64)-bit message.
irsend.sendAiwaRCT501(0x1FFFFFFFFF, 37);
irsend.makeDecodeResult();
// Should work with a 'normal' match (not strict)
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, 37, false));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(37, irsend.capture.bits);
EXPECT_EQ(0x1FFFFFFFFF, irsend.capture.value);
// Reconfirm it by sending a true 64bit NEC message with the Aiwa prefix.
irsend.reset();
irsend.sendNEC(0x76044FFFFFFFFFFF, 64, AIWA_RC_T501_MIN_REPEAT);
irsend.makeDecodeResult();
// Should work with a 'normal' match (not strict)
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture, 37, false));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(37, irsend.capture.bits);
EXPECT_EQ(0x1FFFFFFFFF, irsend.capture.value);
}
// Decode a 'real' example via GlobalCache
TEST(TestDecodeAiwa, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Aiwa Power Toggle from Global Cache.
uint16_t gc_test[95] = {38000, 1, 89, 342, 171, 21, 21, 21, 64, 21, 64,
21, 64, 21, 21, 21, 64, 21, 64, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21,
21, 21, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64,
21, 64, 21, 64, 21, 64, 21, 64, 21, 64, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 64, 21, 64, 21, 64, 21, 64, 21, 64,
21, 64, 21, 64, 21, 64, 21, 875, 342, 171, 21, 3565};
irsend.sendGC(gc_test, 95);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeAiwaRCT501(&irsend.capture));
EXPECT_EQ(AIWA_RC_T501, irsend.capture.decode_type);
EXPECT_EQ(AIWA_RC_T501_BITS, irsend.capture.bits);
EXPECT_EQ(0x7F, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Confirm what the 42-bit NEC decode is.
ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, 42, false));
EXPECT_EQ(0x1D8113F00FF, irsend.capture.value);
}
// Fail to decode a non-Aiwa example via GlobalCache
TEST(TestDecodeAiwa, FailToDecodeNonAiwaExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture));
ASSERT_FALSE(irrecv.decodeAiwaRCT501(&irsend.capture, AIWA_RC_T501_BITS,
false));
}
+290
View File
@@ -0,0 +1,290 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendCOOLIX().
// Test sending typical data only.
TEST(TestSendCoolix, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendCOOLIX(0x0);
EXPECT_EQ(
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s5040", irsend.outputStr());
irsend.reset();
irsend.sendCOOLIX(0xAA55AA);
EXPECT_EQ(
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s5040", irsend.outputStr());
irsend.reset();
irsend.sendCOOLIX(0xFFFFFF);
EXPECT_EQ(
"m4480s4480"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s5040", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendCoolix, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendCOOLIX(0xAA55AA, COOLIX_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s5040"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s5040", irsend.outputStr());
irsend.sendCOOLIX(0xAA55AA, COOLIX_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s5040"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s5040"
"m4480s4480"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680"
"m560s5040", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendCoolix, SendUsualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendCOOLIX(0x0, 8);
EXPECT_EQ(
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s5040", irsend.outputStr());
irsend.reset();
irsend.sendCOOLIX(0x1234567890ABCDEF, 64);
EXPECT_EQ(
"m4480s4480"
"m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560"
"m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s1680"
"m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560m560s1680"
"m560s560m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560"
"m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680"
"m560s1680m560s560m560s560m560s1680m560s560m560s560m560s560m560s560"
"m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680"
"m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680"
"m560s560m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560"
"m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680"
"m560s560m560s560m560s560m560s1680m560s560m560s560m560s560m560s560"
"m560s5040", irsend.outputStr());
// Bit sizes must be a multiple of 8.
irsend.reset();
irsend.sendCOOLIX(0x0, 17);
EXPECT_EQ("" , irsend.outputStr());
}
// Tests for decodeCOOLIX().
// Decode normal Coolix messages.
TEST(TestDecodeCoolix, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Coolix 24-bit message.
irsend.reset();
irsend.sendCOOLIX(0x123456);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(COOLIX_BITS, irsend.capture.bits);
EXPECT_EQ(0x123456, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal Coolix 24-bit message.
irsend.reset();
irsend.sendCOOLIX(0x0);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(COOLIX_BITS, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal Coolix 24-bit message.
irsend.reset();
irsend.sendCOOLIX(0xFFFFFF);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(COOLIX_BITS, irsend.capture.bits);
EXPECT_EQ(0xFFFFFF, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode normal repeated Coolix messages.
TEST(TestDecodeCoolix, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Coolix 16-bit message with 2 repeats.
irsend.reset();
irsend.sendCOOLIX(0x123456, COOLIX_BITS, 2);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(COOLIX_BITS, irsend.capture.bits);
EXPECT_EQ(0x123456, irsend.capture.value);
EXPECT_FALSE(irsend.capture.repeat);
irsend.makeDecodeResult(4 * COOLIX_BITS + 4);
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(COOLIX_BITS, irsend.capture.bits);
EXPECT_EQ(0x123456, irsend.capture.value);
irsend.makeDecodeResult(2 * (4 * COOLIX_BITS + 4));
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(COOLIX_BITS, irsend.capture.bits);
EXPECT_EQ(0x123456, irsend.capture.value);
}
// Decode unsupported Coolix messages.
TEST(TestDecodeCoolix, DecodeWithNonStrictSizes) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendCOOLIX(0x12, 8); // Illegal value Coolix 8-bit message.
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, 8, false));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(8, irsend.capture.bits);
EXPECT_EQ(0x12, irsend.capture.value);
irsend.reset();
irsend.sendCOOLIX(0x12345678, 32); // Illegal value Coolix 32-bit message.
irsend.makeDecodeResult();
// Shouldn't pass with strict when we ask for less bits than we got.
ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, true));
irsend.makeDecodeResult();
// Should fail with strict when we ask for the wrong bit size.
ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, 32, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, 32, false));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0x12345678, irsend.capture.value);
// Decode should fail if asked to decode non-multiples of 8 bits.
irsend.reset();
irsend.sendCOOLIX(0x123456, COOLIX_BITS, 2);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, 9, false));
}
// Decode (non-standard) 64-bit messages.
TEST(TestDecodeCoolix, Decode64BitMessages) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Illegal size Coolix 64-bit message.
irsend.sendCOOLIX(0xFFFFFFFFFFFFFFFF, 64);
irsend.makeDecodeResult();
// Should work with a 'normal' match (not strict)
ASSERT_TRUE(irrecv.decodeCOOLIX(&irsend.capture, 64, false));
EXPECT_EQ(COOLIX, irsend.capture.decode_type);
EXPECT_EQ(64, irsend.capture.bits);
EXPECT_EQ(0xFFFFFFFFFFFFFFFF, irsend.capture.value);
}
// Fail to decode a non-Coolix example via GlobalCache
TEST(TestDecodeCoolix, FailToDecodeNonCoolixExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Modified a few entries to unexpected values, based on previous test case.
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture));
ASSERT_FALSE(irrecv.decodeCOOLIX(&irsend.capture, COOLIX_BITS, false));
}
+419
View File
@@ -0,0 +1,419 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "ir_Daikin.h"
#include "gtest/gtest.h"
// Tests for sendDaikin().
// Test sending typical data only.
TEST(TestSendDaikin, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
uint8_t daikin_code[DAIKIN_COMMAND_LENGTH] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20,
0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3};
irsend.reset();
irsend.sendDaikin(daikin_code);
EXPECT_EQ(
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428"
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s29428", irsend.outputStr());
}
// Test sending with repeats.
TEST(TestSendDaikin, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
uint8_t daikin_code[DAIKIN_COMMAND_LENGTH] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20,
0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3};
irsend.reset();
irsend.sendDaikin(daikin_code, DAIKIN_COMMAND_LENGTH, 1);
EXPECT_EQ(
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428"
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s29428"
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428"
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s29428", irsend.outputStr());
}
// Test sending atypical sizes.
TEST(TestSendDaikin, SendUnexpectedSizes) {
IRsendTest irsend(4);
irsend.begin();
uint8_t daikin_short_code[DAIKIN_COMMAND_LENGTH - 1] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20,
0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00};
irsend.reset();
irsend.sendDaikin(daikin_short_code, DAIKIN_COMMAND_LENGTH - 1);
ASSERT_EQ("", irsend.outputStr());
uint8_t daikin_long_code[DAIKIN_COMMAND_LENGTH + 1] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20,
0x11, 0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3, 0x11};
irsend.reset();
irsend.sendDaikin(daikin_long_code, DAIKIN_COMMAND_LENGTH + 1);
ASSERT_EQ(
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428"
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s29428", irsend.outputStr());
}
// Tests for IRDaikinESP class.
TEST(TestDaikinClass, Power) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.on();
EXPECT_TRUE(irdaikin.getPower());
irdaikin.off();
EXPECT_FALSE(irdaikin.getPower());
irdaikin.setPower(true);
EXPECT_TRUE(irdaikin.getPower());
irdaikin.setPower(false);
EXPECT_FALSE(irdaikin.getPower());
}
TEST(TestDaikinClass, Temperature) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setTemp(0);
EXPECT_EQ(DAIKIN_MIN_TEMP, irdaikin.getTemp());
irdaikin.setTemp(255);
EXPECT_EQ(DAIKIN_MAX_TEMP, irdaikin.getTemp());
irdaikin.setTemp(DAIKIN_MIN_TEMP);
EXPECT_EQ(DAIKIN_MIN_TEMP, irdaikin.getTemp());
irdaikin.setTemp(DAIKIN_MAX_TEMP);
EXPECT_EQ(DAIKIN_MAX_TEMP, irdaikin.getTemp());
irdaikin.setTemp(DAIKIN_MIN_TEMP - 1);
EXPECT_EQ(DAIKIN_MIN_TEMP, irdaikin.getTemp());
irdaikin.setTemp(DAIKIN_MAX_TEMP + 1);
EXPECT_EQ(DAIKIN_MAX_TEMP, irdaikin.getTemp());
irdaikin.setTemp(DAIKIN_MIN_TEMP + 1);
EXPECT_EQ(DAIKIN_MIN_TEMP + 1, irdaikin.getTemp());
irdaikin.setTemp(21);
EXPECT_EQ(21, irdaikin.getTemp());
irdaikin.setTemp(25);
EXPECT_EQ(25, irdaikin.getTemp());
irdaikin.setTemp(29);
EXPECT_EQ(29, irdaikin.getTemp());
}
TEST(TestDaikinClass, OperatingMode) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setMode(DAIKIN_AUTO);
EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode());
irdaikin.setMode(DAIKIN_COOL);
EXPECT_EQ(DAIKIN_COOL, irdaikin.getMode());
irdaikin.setMode(DAIKIN_HEAT);
EXPECT_EQ(DAIKIN_HEAT, irdaikin.getMode());
irdaikin.setMode(DAIKIN_DRY);
EXPECT_EQ(DAIKIN_DRY, irdaikin.getMode());
irdaikin.setMode(DAIKIN_FAN);
EXPECT_EQ(DAIKIN_FAN, irdaikin.getMode());
irdaikin.setMode(DAIKIN_FAN + 1);
EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode());
irdaikin.setMode(DAIKIN_AUTO + 1);
EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode());
irdaikin.setMode(255);
EXPECT_EQ(DAIKIN_AUTO, irdaikin.getMode());
}
TEST(TestDaikinClass, VaneSwing) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setSwingHorizontal(true);
irdaikin.setSwingVertical(false);
irdaikin.setSwingHorizontal(true);
EXPECT_TRUE(irdaikin.getSwingHorizontal());
EXPECT_FALSE(irdaikin.getSwingVertical());
irdaikin.setSwingVertical(true);
EXPECT_TRUE(irdaikin.getSwingHorizontal());
EXPECT_TRUE(irdaikin.getSwingVertical());
irdaikin.setSwingHorizontal(false);
EXPECT_FALSE(irdaikin.getSwingHorizontal());
EXPECT_TRUE(irdaikin.getSwingVertical());
irdaikin.setSwingVertical(false);
EXPECT_FALSE(irdaikin.getSwingHorizontal());
EXPECT_FALSE(irdaikin.getSwingVertical());
}
TEST(TestDaikinClass, QuietMode) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setQuiet(true);
EXPECT_TRUE(irdaikin.getQuiet());
irdaikin.setQuiet(false);
EXPECT_FALSE(irdaikin.getQuiet());
irdaikin.setQuiet(true);
EXPECT_TRUE(irdaikin.getQuiet());
irdaikin.setPowerful(true);
EXPECT_FALSE(irdaikin.getQuiet());
}
TEST(TestDaikinClass, PowerfulMode) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setPowerful(true);
EXPECT_TRUE(irdaikin.getPowerful());
irdaikin.setPowerful(false);
EXPECT_FALSE(irdaikin.getPowerful());
irdaikin.setPowerful(true);
EXPECT_TRUE(irdaikin.getPowerful());
irdaikin.setQuiet(true);
EXPECT_FALSE(irdaikin.getPowerful());
}
TEST(TestDaikinClass, FanSpeed) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setFan(0);
EXPECT_EQ(0, irdaikin.getFan());
irdaikin.setFan(255);
EXPECT_EQ(DAIKIN_FAN_MAX, irdaikin.getFan());
irdaikin.setFan(DAIKIN_FAN_MAX);
EXPECT_EQ(DAIKIN_FAN_MAX, irdaikin.getFan());
irdaikin.setFan(DAIKIN_FAN_MAX + 1);
EXPECT_EQ(DAIKIN_FAN_MAX, irdaikin.getFan());
irdaikin.setFan(DAIKIN_FAN_MAX - 1);
EXPECT_EQ(DAIKIN_FAN_MAX - 1, irdaikin.getFan());
irdaikin.setFan(DAIKIN_FAN_MIN);
EXPECT_EQ(DAIKIN_FAN_MIN, irdaikin.getFan());
irdaikin.setFan(DAIKIN_FAN_MIN + 1);
EXPECT_EQ(DAIKIN_FAN_MIN + 1, irdaikin.getFan());
irdaikin.setFan(3);
EXPECT_EQ(3, irdaikin.getFan());
irdaikin.setFan(DAIKIN_FAN_AUTO);
EXPECT_EQ(DAIKIN_FAN_AUTO, irdaikin.getFan());
}
TEST(TestDaikinClass, MessageConstuction) {
IRDaikinESP irdaikin(0);
IRsendTest irsend(4);
irdaikin.begin();
irsend.begin();
irdaikin.setFan(DAIKIN_FAN_MIN);
irdaikin.setMode(DAIKIN_COOL);
irdaikin.setTemp(27);
irdaikin.setSwingVertical(false);
irdaikin.setSwingHorizontal(true);
irdaikin.setQuiet(false);
irdaikin.setPower(true);
// Check everything for kicks.
EXPECT_EQ(DAIKIN_FAN_MIN, irdaikin.getFan());
EXPECT_EQ(DAIKIN_COOL, irdaikin.getMode());
EXPECT_EQ(27, irdaikin.getTemp());
EXPECT_FALSE(irdaikin.getSwingVertical());
EXPECT_TRUE(irdaikin.getSwingHorizontal());
EXPECT_FALSE(irdaikin.getQuiet());
EXPECT_TRUE(irdaikin.getPower());
irsend.reset();
irsend.sendDaikin(irdaikin.getRaw());
EXPECT_EQ(
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s29428"
"m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s428m428s428"
"m428s428m428s1280m428s1280m428s428m428s1280m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s428"
"m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280m428s428"
"m428s29428", irsend.outputStr());
}
+272
View File
@@ -0,0 +1,272 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendDenon().
// Test sending typical data only.
TEST(TestSendDenon, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendDenon(0x2278); // Denon AVR Power On. (Sharp)
EXPECT_EQ(
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820"
"m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820"
"m260s43602", irsend.outputStr());
irsend.reset();
// Denon Eco Mode On. (Panasonic/Kaseikyo)
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS);
EXPECT_EQ(
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s1296m432s432"
"m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296"
"m432s129600", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendDenon, SendNormalWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendDenon(0x2278, DENON_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820"
"m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820"
"m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820"
"m260s43602", irsend.outputStr());
irsend.sendDenon(0x2278, DENON_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820"
"m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820"
"m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s1820m260s780m260s780"
"m260s1820m260s1820m260s1820m260s1820m260s780m260s780m260s780"
"m260s43602"
"m260s780m260s1820m260s780m260s780m260s780m260s780m260s1820m260s1820"
"m260s780m260s780m260s780m260s780m260s1820m260s1820m260s1820"
"m260s43602", irsend.outputStr());
}
TEST(TestSendDenon, Send48BitWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s1296m432s432"
"m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296"
"m432s129600"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s1296m432s432"
"m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296"
"m432s129600", irsend.outputStr());
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s1296m432s432"
"m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296"
"m432s129600"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s1296m432s432"
"m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296"
"m432s129600"
"m3456s1728"
"m432s432m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s432"
"m432s432m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s1296m432s432"
"m432s1296m432s432m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s432m432s432m432s1296m432s1296"
"m432s129600", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendDenon, SendUnusualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendDenon(0x12, 8);
EXPECT_EQ(
"m260s780m260s780m260s780m260s1820m260s780m260s780m260s1820m260s780"
"m260s43602"
"m260s1820m260s1820m260s1820m260s780m260s1820m260s1820m260s780m260s1820"
"m260s43602", irsend.outputStr());
irsend.reset();
irsend.sendDenon(0x1234567890ABCDEF, 64);
EXPECT_EQ(
"m3456s1728"
"m432s432m432s432m432s432m432s1296m432s432m432s432m432s1296m432s432"
"m432s432m432s432m432s1296m432s1296m432s432m432s1296m432s432m432s432"
"m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s1296m432s432"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s432m432s432m432s432"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s1296"
"m432s1296m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s1296m432s1296"
"m432s129600", irsend.outputStr());
}
// Tests for decodeDenon().
// Decode normal Denon messages.
TEST(TestDecodeDenon, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Denon 15-bit message. (Sharp)
irsend.reset();
irsend.sendDenon(0x2278);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDenon(&irsend.capture, DENON_BITS, true));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_BITS, irsend.capture.bits);
EXPECT_EQ(0x2278, irsend.capture.value);
EXPECT_EQ(0x2, irsend.capture.address);
EXPECT_EQ(0x79, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Legacy Denon 14-bit message.
irsend.reset();
irsend.sendDenon(0x1278, DENON_LEGACY_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDenon(&irsend.capture, DENON_LEGACY_BITS, true));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_LEGACY_BITS, irsend.capture.bits);
EXPECT_EQ(0x1278, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal Denon 48-bit message. (Panasonic/Kaseikyo)
irsend.reset();
irsend.sendDenon(0x2A4C028D6CE3, DENON_48_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDenon(&irsend.capture, DENON_48_BITS, true));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_48_BITS, irsend.capture.bits);
EXPECT_EQ(0x2A4C028D6CE3, irsend.capture.value);
EXPECT_EQ(0x2A4C, irsend.capture.address);
EXPECT_EQ(0x028D6CE3, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode a 'real' example via GlobalCache
TEST(TestDecodeDenon, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Denon AVR series Power On code from Global Cache. (Sharp style)
uint16_t gc_test_power[67] = {38000, 1, 1,
10, 30, 10, 70, 10, 30, 10, 30, 10, 30, 10, 70,
10, 30, 10, 30, 10, 70, 10, 70, 10, 70, 10, 70,
10, 30, 10, 30, 10, 30, 10, 1657,
10, 30, 10, 70, 10, 30, 10, 30, 10, 30, 10, 30,
10, 70, 10, 70, 10, 30, 10, 30, 10, 30, 10, 30,
10, 70, 10, 70, 10, 70, 10, 1657};
irsend.sendGC(gc_test_power, 67);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDenon(&irsend.capture, DENON_BITS, true));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_BITS, irsend.capture.bits);
EXPECT_EQ(0x2278, irsend.capture.value);
EXPECT_EQ(0x2, irsend.capture.address);
EXPECT_EQ(0x79, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Denon "Eco Mode Auto" code from Global Cache. (Panasonic style)
uint16_t gc_test_eco[103] = {37000, 1, 1, 128, 64, 16, 16, 16, 16, 16, 48,
16, 16, 16, 48, 16, 16, 16, 48, 16, 16, 16, 16,
16, 48, 16, 16, 16, 16, 16, 48, 16, 48, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 48, 16, 16, 16, 48, 16, 16, 16, 16,
16, 16, 16, 48, 16, 48, 16, 16, 16, 48, 16, 16,
16, 48, 16, 48, 16, 16, 16, 48, 16, 48, 16, 16,
16, 16, 16, 48, 16, 48, 16, 48, 16, 16, 16, 16,
16, 16, 16, 48, 16, 48, 16, 2766};
irsend.reset();
irsend.sendGC(gc_test_eco, 103);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDenon(&irsend.capture, DENON_48_BITS, true));
EXPECT_EQ(DENON, irsend.capture.decode_type);
EXPECT_EQ(DENON_48_BITS, irsend.capture.bits);
EXPECT_EQ(0x2A4C028D6CE3, irsend.capture.value);
EXPECT_EQ(0x2A4C, irsend.capture.address);
EXPECT_EQ(0x028D6CE3, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Fail to decode a non-Denon example via GlobalCache
TEST(TestDecodeDenon, FailToDecodeNonDenonExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture));
ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture, DENON_LEGACY_BITS, false));
ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture, DENON_BITS, false));
ASSERT_FALSE(irrecv.decodeDenon(&irsend.capture, DENON_48_BITS, false));
}
+321
View File
@@ -0,0 +1,321 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendDISH().
// Test sending typical data only.
TEST(TestSendDish, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendDISH(0x0);
EXPECT_EQ(
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100", irsend.outputStr());
irsend.reset();
irsend.sendDISH(0x9C00); // Power on.
EXPECT_EQ(
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100", irsend.outputStr());
irsend.reset();
irsend.sendDISH(0xFFFF);
EXPECT_EQ(
"m400s6100"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s6100"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s6100"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s6100"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700m400s1700"
"m400s6100", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendDish, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendDISH(0x9C00, DISH_BITS, 0); // 0 repeats.
EXPECT_EQ(
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100", irsend.outputStr());
irsend.reset();
irsend.sendDISH(0x9C00, DISH_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100", irsend.outputStr());
irsend.sendDISH(0x9C00, DISH_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s1700m400s2800m400s2800m400s1700m400s1700m400s1700m400s2800m400s2800"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendDish, SendUnusualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendDISH(0x0, 8);
EXPECT_EQ(
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100"
"m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800m400s2800"
"m400s6100", irsend.outputStr());
irsend.reset();
irsend.sendDISH(0x1234567890ABCDEF, 64);
EXPECT_EQ(
"m400s6100"
"m400s2800m400s2800m400s2800m400s1700m400s2800m400s2800m400s1700m400s2800"
"m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700m400s2800m400s2800"
"m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700m400s2800"
"m400s2800m400s1700m400s1700m400s1700m400s1700m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s2800m400s1700m400s2800m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700"
"m400s1700m400s1700m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700"
"m400s1700m400s1700m400s1700m400s2800m400s1700m400s1700m400s1700m400s1700"
"m400s6100"
"m400s2800m400s2800m400s2800m400s1700m400s2800m400s2800m400s1700m400s2800"
"m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700m400s2800m400s2800"
"m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700m400s2800"
"m400s2800m400s1700m400s1700m400s1700m400s1700m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s2800m400s1700m400s2800m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700"
"m400s1700m400s1700m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700"
"m400s1700m400s1700m400s1700m400s2800m400s1700m400s1700m400s1700m400s1700"
"m400s6100"
"m400s2800m400s2800m400s2800m400s1700m400s2800m400s2800m400s1700m400s2800"
"m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700m400s2800m400s2800"
"m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700m400s2800"
"m400s2800m400s1700m400s1700m400s1700m400s1700m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s2800m400s1700m400s2800m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700"
"m400s1700m400s1700m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700"
"m400s1700m400s1700m400s1700m400s2800m400s1700m400s1700m400s1700m400s1700"
"m400s6100"
"m400s2800m400s2800m400s2800m400s1700m400s2800m400s2800m400s1700m400s2800"
"m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700m400s2800m400s2800"
"m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700m400s2800"
"m400s2800m400s1700m400s1700m400s1700m400s1700m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s2800m400s1700m400s2800m400s2800m400s2800m400s2800"
"m400s1700m400s2800m400s1700m400s2800m400s1700m400s2800m400s1700m400s1700"
"m400s1700m400s1700m400s2800m400s2800m400s1700m400s1700m400s2800m400s1700"
"m400s1700m400s1700m400s1700m400s2800m400s1700m400s1700m400s1700m400s1700"
"m400s6100", irsend.outputStr());
}
// Tests for decodeDISH().
// Decode normal Dish messages.
TEST(TestDecodeDish, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Dish 16-bit message.
irsend.reset();
irsend.sendDISH(0x9C00);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(DISH_BITS, irsend.capture.bits);
EXPECT_EQ(0x9C00, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode Dish messages with unsupported size/lengths.
TEST(TestDecodeDish, DecodeWithNonStrictSize) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendDISH(0x12, 8); // Illegal size Dish message. (smaller)
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true));
irsend.makeDecodeResult();
// Should fail with strict when we ask for the wrong bit size.
ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, 8, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, 8, false));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(8, irsend.capture.bits);
EXPECT_EQ(0x12, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
irsend.reset();
irsend.sendDISH(0x12345678, 32); // Illegal size Dish message. (larger)
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true));
irsend.makeDecodeResult();
// Should fail with strict when we ask for the wrong bit size.
ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, 32, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, 32, false));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0x12345678, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
}
// Decode (non-standard) 64-bit messages.
TEST(TestDecodeDish, Decode64BitMessages) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Illegal value & size Dish 64-bit message.
irsend.sendDISH(0xFFFFFFFFFFFFFFFF, 64);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, 64, true));
// Should work with a 'normal' match (not strict)
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, 64, false));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(64, irsend.capture.bits);
EXPECT_EQ(0xFFFFFFFFFFFFFFFF, irsend.capture.value);
}
// Decode a 'real' example via GlobalCache
TEST(TestDecodeDish, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
/*
irsend.reset();
// Dish DTV Pal code from Global Cache.
uint16_t gc_test_dtv[27] = {58000, 1, 3, 22, 538, 22, 252, 22, 156, 22, 156,
22, 156, 22, 156, 22, 252, 22, 252, 22, 252, 22,
252, 22, 252, 22, 538};
irsend.sendGC(gc_test_dtv, 27);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(DISH_BITS, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(DISH_BITS, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
*/
// Dish Hopper 3 code from Global Cache.
uint16_t gc_test_hopper[73] = {58000, 1, 37, 23, 351, 23, 94, 23, 164,
23, 164, 23, 94, 23, 94, 23, 94, 23, 164,
23, 164, 23, 164, 23, 164, 23, 164, 23, 164,
23, 164, 23, 164, 23, 164, 23, 164, 23, 351,
23, 94, 23, 164, 23, 164, 23, 94, 23, 94,
23, 94, 23, 164, 23, 164, 23, 164, 23, 164,
23, 164, 23, 164, 23, 164, 23, 164, 23, 164,
23, 164, 23, 351};
irsend.reset();
irsend.sendGC(gc_test_hopper, 73);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, true));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(DISH_BITS, irsend.capture.bits);
EXPECT_EQ(0x9C00, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
ASSERT_TRUE(irrecv.decodeDISH(&irsend.capture));
EXPECT_EQ(DISH, irsend.capture.decode_type);
EXPECT_EQ(DISH_BITS, irsend.capture.bits);
EXPECT_EQ(0x9C00, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Fail to decode a non-Dish example via GlobalCache
TEST(TestDecodeDish, FailToDecodeNonDishExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Modified a few entries to unexpected values, based on previous test case.
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture));
ASSERT_FALSE(irrecv.decodeDISH(&irsend.capture, DISH_BITS, false));
}
@@ -0,0 +1,207 @@
// Copyright 2017 Jonny Graham
#include "IRsend.h"
#include "IRsend_test.h"
#include "ir_Fujitsu.h"
#include "gtest/gtest.h"
template<typename T, size_t size>
::testing::AssertionResult ArraysMatch(const T (&expected)[size],
const T* actual) {
for (size_t i(0); i < size; ++i) {
if (expected[i] != actual[i]) {
int e = expected[i];
int a = actual[i];
return ::testing::AssertionFailure() << "array[" << i
<< "] (" << std::hex << a << std::dec << ") != expected[" << i
<< "] (" << std::hex << e << std::dec << ")";
}
}
return ::testing::AssertionSuccess();
}
// Tests for Mitsubishi A/C methods.
// Test sending typical data only.
TEST(TestSendFujitsuAC, GetRawDefault) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
fujitsuACSender.setCmd(FUJITSU_AC_CMD_TURN_ON);
fujitsuACSender.setSwing(FUJITSU_AC_SWING_BOTH);
fujitsuACSender.setMode(FUJITSU_AC_MODE_COOL);
fujitsuACSender.setFanSpeed(FUJITSU_AC_FAN_HIGH);
fujitsuACSender.setTemp(24);
uint8_t expected[16] = {0x14, 0x63, 0x0, 0x10, 0x10, 0xFE, 0x9, 0x30,
0x81, 0x1, 0x31, 0x0, 0x0, 0x0, 0x20, 0xFD};
EXPECT_TRUE(ArraysMatch(expected, fujitsuACSender.getRaw()));
}
TEST(TestSendFujitsuAC, GetRawTurnOff) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
fujitsuACSender.off();
uint8_t expected[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02, 0xFD};
EXPECT_TRUE(ArraysMatch(expected, fujitsuACSender.getRaw()));
}
TEST(TestSendFujitsuAC, GetRawStepHoriz) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
fujitsuACSender.stepHoriz();
uint8_t expected[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x79, 0x86};
EXPECT_TRUE(ArraysMatch(expected, fujitsuACSender.getRaw()));
}
TEST(TestSendFujitsuAC, GetRawStepVert) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
fujitsuACSender.stepVert();
uint8_t expected[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x6C, 0x93};
EXPECT_TRUE(ArraysMatch(expected, fujitsuACSender.getRaw()));
}
TEST(TestSendFujitsuAC, GetRawWithSwingHoriz) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
fujitsuACSender.setCmd(FUJITSU_AC_CMD_STAY_ON);
fujitsuACSender.setSwing(FUJITSU_AC_SWING_HORIZ);
fujitsuACSender.setMode(FUJITSU_AC_MODE_COOL);
fujitsuACSender.setFanSpeed(FUJITSU_AC_FAN_QUIET);
fujitsuACSender.setTemp(25);
uint8_t expected[16] = {0x14, 0x63, 0x0, 0x10, 0x10, 0xFE, 0x9, 0x30,
0x90, 0x1, 0x24, 0x0, 0x0, 0x0, 0x20, 0xFB};
EXPECT_TRUE(ArraysMatch(expected, fujitsuACSender.getRaw()));
}
TEST(TestSendFujitsuAC, GetRawWithFan) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
fujitsuACSender.setCmd(FUJITSU_AC_CMD_STAY_ON);
fujitsuACSender.setSwing(FUJITSU_AC_SWING_HORIZ);
fujitsuACSender.setMode(FUJITSU_AC_MODE_FAN);
fujitsuACSender.setFanSpeed(FUJITSU_AC_FAN_MED);
fujitsuACSender.setTemp(20); // temp doesn't matter for fan
// but it is sent by the RC anyway
uint8_t expected[16] = {0x14, 0x63, 0x0, 0x10, 0x10, 0xFE, 0x9, 0x30,
0x40, 0x3, 0x22, 0x0, 0x0, 0x0, 0x20, 0x4B};
EXPECT_TRUE(ArraysMatch(expected, fujitsuACSender.getRaw()));
}
TEST(TestSendFujitsuAC, GenerateMessage) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
IRsendTest irsend(4);
fujitsuACSender.begin();
irsend.begin();
fujitsuACSender.setCmd(FUJITSU_AC_CMD_STAY_ON);
fujitsuACSender.setSwing(FUJITSU_AC_SWING_BOTH);
fujitsuACSender.setMode(FUJITSU_AC_MODE_COOL);
fujitsuACSender.setFanSpeed(FUJITSU_AC_FAN_HIGH);
fujitsuACSender.setTemp(24);
EXPECT_EQ(FUJITSU_AC_FAN_HIGH, fujitsuACSender.getFanSpeed());
EXPECT_EQ(FUJITSU_AC_MODE_COOL, fujitsuACSender.getMode());
EXPECT_EQ(24, fujitsuACSender.getTemp());
EXPECT_EQ(FUJITSU_AC_SWING_BOTH, fujitsuACSender.getSwing());
EXPECT_EQ(FUJITSU_AC_CMD_STAY_ON, fujitsuACSender.getCmd());
irsend.reset();
irsend.sendFujitsuAC(fujitsuACSender.getRaw(), FUJITSU_AC_STATE_LENGTH);
EXPECT_EQ(
"m3224s1574m448s367m448s367m448s1182m448s367m448s1182m448s367m448s367m448"
"s367m448s1182m448s1182m448s367m448s367m448s367m448s1182m448s1182m448s367"
"m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448"
"s367m448s367m448s367m448s367m448s1182m448s367m448s367m448s367m448s367m448"
"s367m448s367m448s367m448s1182m448s367m448s367m448s367m448s367m448s1182"
"m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s367"
"m448s367m448s1182m448s367m448s367m448s367m448s367m448s367m448s367m448s367"
"m448s367m448s1182m448s1182m448s367m448s367m448s367m448s367m448s367m448s367"
"m448s367m448s367m448s367m448s1182m448s1182m448s367m448s367m448s367m448"
"s367m448s367m448s367m448s367m448s1182m448s367m448s367m448s367m448s1182m448"
"s1182m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448"
"s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448"
"s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448"
"s367m448s367m448s367m448s367m448s367m448s1182m448s367m448s367m448s367m448"
"s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182m448s8100",
irsend.outputStr());
}
TEST(TestSendFujitsuAC, GenerateShortMessage) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
IRsendTest irsend(4);
fujitsuACSender.begin();
irsend.begin();
fujitsuACSender.off();
EXPECT_EQ(FUJITSU_AC_CMD_TURN_OFF, fujitsuACSender.getCmd());
irsend.reset();
irsend.sendFujitsuAC(fujitsuACSender.getRaw(), FUJITSU_AC_STATE_LENGTH_SHORT);
EXPECT_EQ(
"m3224s1574m448s367m448s367m448s1182m448s367m448s1182m448s367m448s367m448"
"s367m448s1182m448s1182m448s367m448s367m448s367m448s1182m448s1182m448s367"
"m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367"
"m448s367m448s367m448s367m448s1182m448s367m448s367m448s367m448s367m448s367"
"m448s367m448s367m448s1182m448s367m448s367m448s367m448s367m448s1182m448s367"
"m448s367m448s367m448s367m448s367m448s367m448s1182m448s367m448s1182m448"
"s1182m448s1182m448s1182m448s1182m448s1182m448s8100",
irsend.outputStr());
}
// Issue #275
TEST(TestSendFujitsuAC, Issue275) {
IRFujitsuAC fujitsuACSender = IRFujitsuAC(4);
IRsendTest irsend(4);
fujitsuACSender.begin();
irsend.begin();
irsend.reset();
fujitsuACSender.setCmd(FUJITSU_AC_CMD_TURN_OFF);
irsend.sendFujitsuAC(fujitsuACSender.getRaw(), FUJITSU_AC_STATE_LENGTH_SHORT);
EXPECT_EQ(
// Header
"m3224s1574"
// 0 0 1 0 1 0 0 0 (0x28)
"m448s367m448s367m448s1182m448s367m448s1182m448s367m448s367m448s367"
// 1 1 0 0 0 1 1 0 (0xC6)
"m448s1182m448s1182m448s367m448s367m448s367m448s1182m448s1182m448s367"
// 0 0 0 0 0 0 0 0 (0x00)
"m448s367m448s367m448s367m448s367m448s367m448s367m448s367m448s367"
// 0 0 0 0 1 0 0 0 (0x08)
"m448s367m448s367m448s367m448s367m448s1182m448s367m448s367m448s367"
// 0 0 0 0 1 0 0 0 (0x08)
"m448s367m448s367m448s367m448s367m448s1182m448s367m448s367m448s367"
// 0 1 0 0 0 0 0 0 (0x40)
"m448s367m448s1182m448s367m448s367m448s367m448s367m448s367m448s367"
// 1 0 1 1 1 1 1 1 (0xBF)
"m448s1182m448s367m448s1182m448s1182m448s1182m448s1182m448s1182m448s1182"
// Footer
"m448s8100", irsend.outputStr());
irsend.reset();
// Per report in Issue #275
uint16_t off[115] = {
3350, 1650,
450, 400, 450, 450, 450, 1250, 450, 400, 450, 1250, 450, 400, 450, 400,
450, 400, 450, 1250, 450, 1250, 450, 400, 450, 400, 450, 400, 450, 1250,
450, 1250, 450, 400, 450, 400, 450, 400, 450, 400, 450, 400, 450, 400,
450, 400, 450, 400, 450, 400, 450, 400, 450, 400, 450, 400, 450, 400,
450, 1250, 450, 400, 450, 400, 450, 400, 450, 400, 450, 400, 450, 400,
450, 400, 450, 1250, 450, 400, 450, 400, 450, 400, 450, 400, 450, 1250,
450, 400, 450, 400, 450, 400, 450, 400, 450, 400, 450, 400, 450, 1250,
450, 400, 450, 1250, 450, 1250, 450, 1250, 450, 1250, 450, 1250,
450, 1250, 450};
irsend.sendRaw(off, 115, 38);
EXPECT_EQ(
// Header
"m3350s1650"
// 0 0 1 0 1 0 0 0 (0x28)
"m450s400m450s450m450s1250m450s400m450s1250m450s400m450s400m450s400"
// 1 1 0 0 0 1 1 0 (0xC6)
"m450s1250m450s1250m450s400m450s400m450s400m450s1250m450s1250m450s400"
// 0 0 0 0 0 0 0 0 (0x00)
"m450s400m450s400m450s400m450s400m450s400m450s400m450s400m450s400"
// 0 0 0 0 1 0 0 0 (0x08)
"m450s400m450s400m450s400m450s400m450s1250m450s400m450s400m450s400"
// 0 0 0 0 1 0 0 0 (0x08)
"m450s400m450s400m450s400m450s400m450s1250m450s400m450s400m450s400"
// 0 1 0 0 0 0 0 0 (0x40)
"m450s400m450s1250m450s400m450s400m450s400m450s400m450s400m450s400"
// 1 0 1 1 1 1 1 1 (0xBF)
"m450s1250m450s400m450s1250m450s1250m450s1250m450s1250m450s1250m450s1250"
// Footer
"m450",
irsend.outputStr());
}
@@ -0,0 +1,68 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendGlobalCache().
// Test sending a typical command wihtout a repeat.
TEST(TestSendGlobalCache, NonRepeatingCode) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Modified NEC TV "Power On" from Global Cache with no repeats
uint16_t gc_test[71] = {38000, 1, 1, 342, 172, 21, 22, 21, 21, 21, 65, 21, 21,
21, 22, 21, 22, 21, 21, 21, 22, 21, 65, 21, 65, 21,
22, 21, 65, 21, 65, 21, 65, 21, 65, 21, 65, 21, 65,
21, 22, 21, 22, 21, 21, 21, 22, 21, 22, 21, 65, 21,
22, 21, 21, 21, 65, 21, 65, 21, 65, 21, 64, 22, 65,
21, 22, 21, 65, 21, 1519};
irsend.sendGC(gc_test, 71);
irsend.makeDecodeResult();
EXPECT_EQ("m8892s4472m546s572m546s546m546s1690m546s546m546s572m546s572"
"m546s546m546s572m546s1690m546s1690m546s572m546s1690m546s1690"
"m546s1690m546s1690m546s1690m546s1690m546s572m546s572m546s546"
"m546s572m546s572m546s1690m546s572m546s546m546s1690m546s1690"
"m546s1690m546s1664m572s1690m546s572m546s1690m546s39494",
irsend.outputStr());
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x20DF827D, irsend.capture.value);
EXPECT_EQ(0x4, irsend.capture.address);
EXPECT_EQ(0x41, irsend.capture.command);
}
// Test sending typical command with repeats.
TEST(TestSendGlobalCache, RepeatCode) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Sherwood (NEC-like) "Power On" from Global Cache with 2 repeats
uint16_t gc_test[75] = {38000, 2, 69, 341, 171, 21, 64, 21, 64, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 64, 21, 64, 21, 21,
21, 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21,
64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 21, 21, 21,
21, 21, 21, 21, 21, 64, 21, 64, 21, 64, 21, 21, 21,
64, 21, 64, 21, 64, 21, 1600, 341, 85, 21, 3647};
irsend.sendGC(gc_test, 75);
irsend.makeDecodeResult();
EXPECT_EQ("m8866s4446m546s1664m546s1664m546s546m546s546m546s546m546s546"
"m546s546m546s1664m546s1664m546s546m546s1664m546s546m546s546"
"m546s546m546s1664m546s546m546s1664m546s546m546s546m546s546"
"m546s1664m546s546m546s546m546s546m546s546m546s1664m546s1664"
"m546s1664m546s546m546s1664m546s1664m546s1664m546s41600"
"m8866s2210m546s94822"
"m8866s2210m546s94822", irsend.outputStr());
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC1A28877, irsend.capture.value);
EXPECT_EQ(0x4583, irsend.capture.address);
EXPECT_EQ(0x11, irsend.capture.command);
}
+192
View File
@@ -0,0 +1,192 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendGree().
// Test sending typical data only.
TEST(TestSendGreeChars, SendData) {
IRsendTest irsend(4);
irsend.begin();
uint8_t gree_code[GREE_STATE_LENGTH] = {
0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
irsend.reset();
irsend.sendGree(gree_code);
EXPECT_EQ(
"m9000s4000"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
"m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540"
"m620s540m620s1600m620s540"
"m620s19000"
"m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600"
"m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600"
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000", irsend.outputStr());
}
TEST(TestSendGreeUint64, SendData) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF);
EXPECT_EQ(
"m9000s4000"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
"m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540"
"m620s540m620s1600m620s540"
"m620s19000"
"m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600"
"m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600"
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000", irsend.outputStr());
}
// Test sending with repeats.
TEST(TestSendGreeChars, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
uint8_t gree_code[GREE_STATE_LENGTH] = {
0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
irsend.reset();
irsend.sendGree(gree_code, GREE_STATE_LENGTH, 1);
EXPECT_EQ(
"m9000s4000"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
"m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540"
"m620s540m620s1600m620s540"
"m620s19000"
"m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600"
"m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600"
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000"
"m9000s4000"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
"m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540"
"m620s540m620s1600m620s540"
"m620s19000"
"m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600"
"m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600"
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000", irsend.outputStr());
}
TEST(TestSendGreeUint64, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF, GREE_BITS, 1);
EXPECT_EQ(
"m9000s4000"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
"m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540"
"m620s540m620s1600m620s540"
"m620s19000"
"m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600"
"m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600"
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000"
"m9000s4000"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
"m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540"
"m620s540m620s1600m620s540"
"m620s19000"
"m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600"
"m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600"
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s19000", irsend.outputStr());
}
// Test sending atypical sizes.
TEST(TestSendGreeChars, SendUnexpectedSizes) {
IRsendTest irsend(4);
irsend.begin();
uint8_t gree_short_code[GREE_STATE_LENGTH - 1] = {
0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD};
uint8_t gree_long_code[GREE_STATE_LENGTH + 1] = {
0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12};
irsend.reset();
irsend.sendGree(gree_short_code, GREE_STATE_LENGTH - 1);
ASSERT_EQ("", irsend.outputStr());
irsend.reset();
irsend.sendGree(gree_long_code, GREE_STATE_LENGTH + 1);
ASSERT_EQ(
"m9000s4000"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s540m620s540m620s1600m620s540m620s1600m620s1600m620s540m620s540"
"m620s540m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540"
"m620s540m620s540m620s540m620s1600m620s1600m620s1600m620s1600m620s540"
"m620s540m620s1600m620s540"
"m620s19000"
"m620s540m620s540m620s540m620s540m620s1600m620s540m620s540m620s1600"
"m620s1600m620s1600m620s540m620s1600m620s540m620s1600m620s540m620s1600"
"m620s1600m620s540m620s1600m620s1600m620s540m620s540m620s1600m620s1600"
"m620s1600m620s1600m620s1600m620s1600m620s540m620s1600m620s1600m620s1600"
"m620s540m620s1600m620s540m620s540m620s1600m620s540m620s540m620s540"
"m620s19000", irsend.outputStr());
}
TEST(TestSendGreeUint64, SendUnexpectedSizes) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF, GREE_BITS - 1);
ASSERT_EQ("", irsend.outputStr());
irsend.reset();
irsend.sendGree(0x1234567890ABCDEF, GREE_BITS + 1);
ASSERT_EQ("", irsend.outputStr());
}
TEST(TestSendGree, CompareUint64ToCharResults) {
IRsendTest irsend_chars(4);
IRsendTest irsend_uint64(0);
uint8_t gree_code[GREE_STATE_LENGTH] = {
0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
irsend_chars.begin();
irsend_uint64.begin();
irsend_chars.reset();
irsend_uint64.reset();
irsend_chars.sendGree(gree_code);
irsend_uint64.sendGree(0x1234567890ABCDEF);
ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr());
uint8_t gree_zero_code[GREE_STATE_LENGTH] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
irsend_chars.reset();
irsend_uint64.reset();
irsend_chars.sendGree(gree_zero_code);
irsend_uint64.sendGree((uint64_t) 0x0);
ASSERT_EQ(irsend_chars.outputStr(), irsend_uint64.outputStr());
}
+299
View File
@@ -0,0 +1,299 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendJVC().
// Test sending typical data only.
TEST(TestSendJVC, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendJVC(0xC2B8); // JVC VCR Power On.
EXPECT_EQ(
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
"m525s60000", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendJVC, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendJVC(0xC2B8, JVC_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
"m525s60000"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
"m525s60000", irsend.outputStr());
irsend.sendJVC(0xC2B8, JVC_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m8400s4200"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
"m525s60000"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
"m525s60000"
"m525s1725m525s1725m525s525m525s525m525s525m525s525m525s1725m525s525"
"m525s1725m525s525m525s1725m525s1725m525s1725m525s525m525s525m525s525"
"m525s60000", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendJVC, SendUsualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendJVC(0x0, 8);
EXPECT_EQ(
"m8400s4200"
"m525s525m525s525m525s525m525s525m525s525m525s525m525s525m525s525"
"m525s60000", irsend.outputStr());
irsend.reset();
irsend.sendJVC(0x1234567890ABCDEF, 64);
EXPECT_EQ(
"m8400s4200"
"m525s525m525s525m525s525m525s1725m525s525m525s525m525s1725m525s525"
"m525s525m525s525m525s1725m525s1725m525s525m525s1725m525s525m525s525"
"m525s525m525s1725m525s525m525s1725m525s525m525s1725m525s1725m525s525"
"m525s525m525s1725m525s1725m525s1725m525s1725m525s525m525s525m525s525"
"m525s1725m525s525m525s525m525s1725m525s525m525s525m525s525m525s525"
"m525s1725m525s525m525s1725m525s525m525s1725m525s525m525s1725m525s1725"
"m525s1725m525s1725m525s525m525s525m525s1725m525s1725m525s525m525s1725"
"m525s1725m525s1725m525s1725m525s525m525s1725m525s1725m525s1725m525s1725"
"m525s60000", irsend.outputStr());
}
// Tests for encodeJVC().
TEST(TestEncodeJVC, NormalEncoding) {
IRsendTest irsend(4);
EXPECT_EQ(0x0, irsend.encodeJVC(0, 0));
EXPECT_EQ(0x8080, irsend.encodeJVC(1, 1));
EXPECT_EQ(0x8040, irsend.encodeJVC(1, 2));
EXPECT_EQ(0xC2B8, irsend.encodeJVC(0x43, 0x1D));
EXPECT_EQ(0x55AA, irsend.encodeJVC(0xAA, 0x55));
EXPECT_EQ(0xFFFF, irsend.encodeJVC(0xFF, 0xFF));
}
// Tests for decodeJVC().
// Decode normal JVC messages.
TEST(TestDecodeJVC, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal JVC 16-bit message.
irsend.reset();
irsend.sendJVC(0xC2B8);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_EQ(0x43, irsend.capture.address);
EXPECT_EQ(0x1D, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Synthesised Normal JVC 16-bit message.
irsend.reset();
irsend.sendJVC(irsend.encodeJVC(0x07, 0x99));
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xE099, irsend.capture.value);
EXPECT_EQ(0x07, irsend.capture.address);
EXPECT_EQ(0x99, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Synthesised Normal JVC 16-bit message.
irsend.reset();
irsend.sendJVC(irsend.encodeJVC(0x1, 0x1));
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0x8080, irsend.capture.value);
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x1, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode normal repeated JVC messages.
TEST(TestDecodeJVC, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal JVC 16-bit message with 2 repeats.
irsend.reset();
irsend.sendJVC(0xC2B8, JVC_BITS, 2);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_EQ(0x43, irsend.capture.address);
EXPECT_EQ(0x1D, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
irsend.makeDecodeResult(2 * JVC_BITS + 4);
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_TRUE(irsend.capture.repeat);
irsend.makeDecodeResult(2 * JVC_BITS + 4 + 2 * JVC_BITS + 2);
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_TRUE(irsend.capture.repeat);
// Simulate 'just' a JVC repeat command.
// JVC VCR Power On from Global Cache, but modified to be a repeat message.
uint16_t gc_test[37] = {38000, 1, 1, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 20, 20, 61, 20, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.reset();
irsend.sendGC(gc_test, 37);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_EQ(0x43, irsend.capture.address);
EXPECT_EQ(0x1D, irsend.capture.command);
EXPECT_TRUE(irsend.capture.repeat);
}
// Decode unsupported JVC messages.
TEST(TestDecodeJVC, DecodeWithNonStrictValues) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendJVC(0x0, 8); // Illegal value JVC 8-bit message.
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, 8, false));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(8, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
irsend.reset();
irsend.sendJVC(0x12345678, 32); // Illegal value JVC 32-bit message.
irsend.makeDecodeResult();
// Should not pass with strict when we ask for less bits than we got.
ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, true));
irsend.makeDecodeResult();
// Should fail with strict when we ask for the wrong bit size.
ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, 32, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, 32, false));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0x12345678, irsend.capture.value);
EXPECT_EQ(0x12346A, irsend.capture.address);
EXPECT_EQ(0x1E, irsend.capture.command);
// Illegal over length (36-bit) message.
irsend.reset();
irsend.sendJVC(irsend.encodeJVC(2, 3), 36);
irsend.makeDecodeResult();
// Shouldn't pass if strict off and the wrong expected bits.
ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, false));
// Re-decode with correct bit size.
ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, 36, true));
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, 36, false));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(36, irsend.capture.bits);
EXPECT_EQ(0x40C0, irsend.capture.value);
EXPECT_EQ(0x2, irsend.capture.address);
EXPECT_EQ(0x3, irsend.capture.command);
}
// Decode (non-standard) 64-bit messages.
TEST(TestDecodeJVC, Decode64BitMessages) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Illegal value & size JVC 64-bit message.
irsend.sendJVC(0xFFFFFFFFFFFFFFFF, 64);
irsend.makeDecodeResult();
// Should work with a 'normal' match (not strict)
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture, 64, false));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(64, irsend.capture.bits);
EXPECT_EQ(0xFFFFFFFFFFFFFFFF, irsend.capture.value);
EXPECT_EQ(0xFFFFFFFF, irsend.capture.address);
EXPECT_EQ(0xFF, irsend.capture.command);
}
// Decode a 'real' example via GlobalCache
TEST(TestDecodeJVC, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// JVC VCR Power On from Global Cache.
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 20, 20, 61, 20, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
// 38000,1,37,320,161,21,59,21,59,21,19,21,19,21,19,21,19,21,59,21,19,21,59,21,59,21,19,21,59,21,19,21,19,21,19,21,19,21,838,21,59,21,59,21,19,21,19,21,19,21,19,21,59,21,19,21,59,21,19,21,59,21,59,21,59,21,19,21,19,21,19,21,850};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeJVC(&irsend.capture));
EXPECT_EQ(JVC, irsend.capture.decode_type);
EXPECT_EQ(JVC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_EQ(0x43, irsend.capture.address);
EXPECT_EQ(0x1D, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Fail to decode a non-JVC example via GlobalCache
TEST(TestDecodeJVC, FailToDecodeNonJVCExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Modified a few entries to unexpected values, based on previous test case.
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture));
ASSERT_FALSE(irrecv.decodeJVC(&irsend.capture, JVC_BITS, false));
}
@@ -0,0 +1,432 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "ir_Kelvinator.h"
#include "gtest/gtest.h"
// Tests for sendKelvinator().
// Test sending typical data only.
TEST(TestSendKelvinator, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
uint8_t kelv_code[KELVINATOR_STATE_LENGTH] = {
0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0,
0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0};
irsend.reset();
irsend.sendKelvinator(kelv_code);
EXPECT_EQ(
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560"
"m675s39900"
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s1560"
"m675s39900", irsend.outputStr());
}
// Test sending with repeats.
TEST(TestSendKelvinator, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
uint8_t kelv_code[KELVINATOR_STATE_LENGTH] = {
0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0,
0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0};
irsend.reset();
irsend.sendKelvinator(kelv_code, KELVINATOR_STATE_LENGTH, 1);
EXPECT_EQ(
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560"
"m675s39900"
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s1560"
"m675s39900"
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560"
"m675s39900"
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s1560"
"m675s39900", irsend.outputStr());
}
// Test sending atypical sizes.
TEST(TestSendKelvinator, SendUnexpectedSizes) {
IRsendTest irsend(4);
irsend.begin();
uint8_t kelv_short_code[15] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0,
0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10};
uint8_t kelv_long_code[17] = {0x19, 0x0B, 0x80, 0x50, 0x00, 0x00, 0x00, 0xE0,
0x19, 0x0B, 0x80, 0x70, 0x00, 0x00, 0x10, 0xf0,
0x00};
irsend.reset();
irsend.sendKelvinator(kelv_short_code, 15);
ASSERT_EQ("", irsend.outputStr());
irsend.reset();
// Shouldn't be different from the SendDataOnly. We just don't send the
// extra data.
irsend.sendKelvinator(kelv_long_code, 17);
ASSERT_EQ(
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560"
"m675s39900"
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s520m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s1560"
"m675s39900", irsend.outputStr());
}
// Tests for IRKelvinatorAC class.
TEST(TestKelvinatorClass, Power) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.on();
EXPECT_TRUE(irkelv.getPower());
irkelv.off();
EXPECT_FALSE(irkelv.getPower());
irkelv.setPower(true);
EXPECT_TRUE(irkelv.getPower());
irkelv.setPower(false);
EXPECT_FALSE(irkelv.getPower());
}
TEST(TestKelvinatorClass, Temperature) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setTemp(0);
EXPECT_EQ(KELVINATOR_MIN_TEMP, irkelv.getTemp());
irkelv.setTemp(255);
EXPECT_EQ(KELVINATOR_MAX_TEMP, irkelv.getTemp());
irkelv.setTemp(KELVINATOR_MIN_TEMP);
EXPECT_EQ(KELVINATOR_MIN_TEMP, irkelv.getTemp());
irkelv.setTemp(KELVINATOR_MAX_TEMP);
EXPECT_EQ(KELVINATOR_MAX_TEMP, irkelv.getTemp());
irkelv.setTemp(KELVINATOR_MIN_TEMP - 1);
EXPECT_EQ(KELVINATOR_MIN_TEMP, irkelv.getTemp());
irkelv.setTemp(KELVINATOR_MAX_TEMP + 1);
EXPECT_EQ(KELVINATOR_MAX_TEMP, irkelv.getTemp());
irkelv.setTemp(17);
EXPECT_EQ(17, irkelv.getTemp());
irkelv.setTemp(21);
EXPECT_EQ(21, irkelv.getTemp());
irkelv.setTemp(25);
EXPECT_EQ(25, irkelv.getTemp());
irkelv.setTemp(29);
EXPECT_EQ(29, irkelv.getTemp());
}
TEST(TestKelvinatorClass, OperatingMode) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setTemp(24);
irkelv.setMode(KELVINATOR_AUTO);
EXPECT_EQ(KELVINATOR_AUTO, irkelv.getMode());
EXPECT_EQ(KELVINATOR_AUTO_TEMP, irkelv.getTemp());
irkelv.setMode(KELVINATOR_COOL);
EXPECT_EQ(KELVINATOR_COOL, irkelv.getMode());
irkelv.setMode(KELVINATOR_HEAT);
EXPECT_EQ(KELVINATOR_HEAT, irkelv.getMode());
irkelv.setTemp(24);
irkelv.setMode(KELVINATOR_DRY);
EXPECT_EQ(KELVINATOR_DRY, irkelv.getMode());
EXPECT_EQ(KELVINATOR_AUTO_TEMP, irkelv.getTemp());
irkelv.setMode(KELVINATOR_FAN);
EXPECT_EQ(KELVINATOR_FAN, irkelv.getMode());
irkelv.setMode(KELVINATOR_HEAT + 1);
EXPECT_EQ(KELVINATOR_AUTO, irkelv.getMode());
irkelv.setMode(255);
EXPECT_EQ(KELVINATOR_AUTO, irkelv.getMode());
}
TEST(TestKelvinatorClass, VaneSwing) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setSwingHorizontal(true);
irkelv.setSwingVertical(false);
irkelv.setSwingHorizontal(true);
EXPECT_TRUE(irkelv.getSwingHorizontal());
EXPECT_FALSE(irkelv.getSwingVertical());
irkelv.setSwingVertical(true);
EXPECT_TRUE(irkelv.getSwingHorizontal());
EXPECT_TRUE(irkelv.getSwingVertical());
irkelv.setSwingHorizontal(false);
EXPECT_FALSE(irkelv.getSwingHorizontal());
EXPECT_TRUE(irkelv.getSwingVertical());
irkelv.setSwingVertical(false);
EXPECT_FALSE(irkelv.getSwingHorizontal());
EXPECT_FALSE(irkelv.getSwingVertical());
}
TEST(TestKelvinatorClass, QuietMode) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setQuiet(true);
EXPECT_TRUE(irkelv.getQuiet());
irkelv.setQuiet(false);
EXPECT_FALSE(irkelv.getQuiet());
irkelv.setQuiet(true);
EXPECT_TRUE(irkelv.getQuiet());
}
TEST(TestKelvinatorClass, IonFilter) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setIonFilter(true);
EXPECT_TRUE(irkelv.getIonFilter());
irkelv.setIonFilter(false);
EXPECT_FALSE(irkelv.getIonFilter());
irkelv.setIonFilter(true);
EXPECT_TRUE(irkelv.getIonFilter());
}
TEST(TestKelvinatorClass, Light) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setLight(true);
EXPECT_TRUE(irkelv.getLight());
irkelv.setLight(false);
EXPECT_FALSE(irkelv.getLight());
irkelv.setLight(true);
EXPECT_TRUE(irkelv.getLight());
}
TEST(TestKelvinatorClass, XFan) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setXFan(true);
EXPECT_TRUE(irkelv.getXFan());
irkelv.setXFan(false);
EXPECT_FALSE(irkelv.getXFan());
irkelv.setXFan(true);
EXPECT_TRUE(irkelv.getXFan());
}
TEST(TestKelvinatorClass, TurboFan) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setTurbo(true);
EXPECT_TRUE(irkelv.getTurbo());
irkelv.setTurbo(false);
EXPECT_FALSE(irkelv.getTurbo());
irkelv.setFan(2);
irkelv.setTurbo(true);
EXPECT_TRUE(irkelv.getTurbo());
// Turbo mode is turned off if the temperature is changed.
irkelv.setFan(3);
EXPECT_FALSE(irkelv.getTurbo());
// But only when it is changed, not set to the same value again.
irkelv.setTurbo(true);
irkelv.setFan(3);
EXPECT_TRUE(irkelv.getTurbo());
}
TEST(TestKelvinatorClass, FanSpeed) {
IRKelvinatorAC irkelv(0);
irkelv.begin();
irkelv.setFan(0);
EXPECT_EQ(0, irkelv.getFan());
irkelv.setFan(255);
EXPECT_EQ(KELVINATOR_FAN_MAX, irkelv.getFan());
irkelv.setFan(KELVINATOR_FAN_MAX);
EXPECT_EQ(KELVINATOR_FAN_MAX, irkelv.getFan());
irkelv.setFan(KELVINATOR_FAN_MAX + 1);
EXPECT_EQ(KELVINATOR_FAN_MAX, irkelv.getFan());
irkelv.setFan(KELVINATOR_FAN_MAX - 1);
EXPECT_EQ(KELVINATOR_FAN_MAX - 1, irkelv.getFan());
irkelv.setFan(1);
EXPECT_EQ(1, irkelv.getFan());
irkelv.setFan(1);
EXPECT_EQ(1, irkelv.getFan());
irkelv.setFan(3);
EXPECT_EQ(3, irkelv.getFan());
}
TEST(TestKelvinatorClass, MessageConstuction) {
IRKelvinatorAC irkelv(0);
IRsendTest irsend(4);
irkelv.begin();
irsend.begin();
irkelv.setFan(1);
irkelv.setMode(KELVINATOR_COOL);
irkelv.setTemp(27);
irkelv.setSwingVertical(false);
irkelv.setSwingHorizontal(true);
irkelv.setIonFilter(true);
irkelv.setQuiet(false);
irkelv.setLight(false);
irkelv.setPower(true);
irkelv.setTurbo(false);
irkelv.setXFan(true);
// Check everything for kicks.
EXPECT_EQ(1, irkelv.getFan());
EXPECT_EQ(KELVINATOR_COOL, irkelv.getMode());
EXPECT_EQ(27, irkelv.getTemp());
EXPECT_FALSE(irkelv.getSwingVertical());
EXPECT_TRUE(irkelv.getSwingHorizontal());
EXPECT_TRUE(irkelv.getIonFilter());
EXPECT_FALSE(irkelv.getQuiet());
EXPECT_FALSE(irkelv.getLight());
EXPECT_TRUE(irkelv.getPower());
EXPECT_FALSE(irkelv.getTurbo());
EXPECT_TRUE(irkelv.getXFan());
irsend.reset();
irsend.sendKelvinator(irkelv.getRaw());
EXPECT_EQ(
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s1560m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s1560m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s1560"
"m675s39900"
"m8990s4490"
"m675s1560m675s520m675s520m675s1560m675s1560m675s520m675s1560m675s520"
"m675s1560m675s1560m675s520m675s1560m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s1560m675s1560"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s520"
"m675s520m675s1560m675s520"
"m675s19950"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s520m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s520m675s520m675s520"
"m675s520m675s520m675s520m675s520m675s1560m675s1560m675s1560m675s1560"
"m675s39900", irsend.outputStr());
}
+358
View File
@@ -0,0 +1,358 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "ir_LG.h"
#include "gtest/gtest.h"
// Tests for calcLGChecksum()
TEST(TestCalcLGChecksum, General) {
EXPECT_EQ(0x0, calcLGChecksum(0x0));
EXPECT_EQ(0x1, calcLGChecksum(0x1));
EXPECT_EQ(0xF, calcLGChecksum(0xF));
EXPECT_EQ(0x4, calcLGChecksum(0x1111));
EXPECT_EQ(0x8, calcLGChecksum(0x2222));
EXPECT_EQ(0x0, calcLGChecksum(0x4444));
EXPECT_EQ(0xA, calcLGChecksum(0x1234));
EXPECT_EQ(0xA, calcLGChecksum(0x4321));
EXPECT_EQ(0xE, calcLGChecksum(0xABCD));
EXPECT_EQ(0x1, calcLGChecksum(0x4AE5));
EXPECT_EQ(0xC, calcLGChecksum(0xFFFF));
}
// Tests for sendLG().
// Test sending typical data only.
TEST(TestSendLG, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendLG(0x4B4AE51);
EXPECT_EQ(
"m8000s4000"
"m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s550m550s1600m550s1600m550s1600m550s550"
"m550s550m550s1600m550s550m550s1600m550s550m550s550m550s550m550s1600"
"m550s108050", irsend.outputStr());
irsend.reset();
irsend.sendLG(0xB4B4AE51, LG32_BITS);
EXPECT_EQ(
"m4480s4480"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560m560s1680"
"m560s108080"
"m8950s2250m550s108050", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendLG, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendLG(0x4B4AE51, LG_BITS, 1);
EXPECT_EQ(
"m8000s4000"
"m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s1600m550s550m550s1600m550s550m550s550"
"m550s1600m550s550m550s1600m550s550m550s1600m550s1600m550s1600m550s550"
"m550s550m550s1600m550s550m550s1600m550s550m550s550m550s550m550s1600"
"m550s108050"
"m8000s2250m550s108050", irsend.outputStr());
irsend.reset();
irsend.sendLG(0xB4B4AE51, LG32_BITS, 1);
EXPECT_EQ(
"m4480s4480"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s1680m560s560"
"m560s560m560s1680m560s560m560s1680m560s560m560s560m560s560m560s1680"
"m560s108080"
"m8950s2250m550s108050"
"m8950s2250m550s108050", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendLG, SendUsualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendLG(0x0, 31);
EXPECT_EQ(
"m8000s4000"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
"m550s550m550s550m550s550m550s550m550s550m550s550m550s550"
"m550s108050", irsend.outputStr());
irsend.reset();
irsend.sendLG(0x0, 64);
EXPECT_EQ(
"m4480s4480"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s108080"
"m8950s2250m550s108050", irsend.outputStr());
}
// Tests for encodeLG().
TEST(TestEncodeLG, NormalEncoding) {
IRsendTest irsend(4);
EXPECT_EQ(0x0, irsend.encodeLG(0, 0));
EXPECT_EQ(0x100011, irsend.encodeLG(1, 1));
EXPECT_EQ(0x100022, irsend.encodeLG(1, 2));
EXPECT_EQ(0x43001DE, irsend.encodeLG(0x43, 0x1D));
EXPECT_EQ(0xB4B4AE51, irsend.encodeLG(0xB4B, 0x4AE5));
EXPECT_EQ(0xAA0055A, irsend.encodeLG(0xAA, 0x55));
EXPECT_EQ(0xFFFFFFFC, irsend.encodeLG(0xFFFF, 0xFFFF));
}
// Tests for decodeLG().
// Decode normal LG messages.
TEST(TestDecodeLG, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal LG 28-bit message.
irsend.reset();
irsend.sendLG(0x4B4AE51, LG_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, true));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG_BITS, irsend.capture.bits);
EXPECT_EQ(0x4B4AE51, irsend.capture.value);
EXPECT_EQ(0x4B, irsend.capture.address);
EXPECT_EQ(0x4AE5, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal LG 32-bit message.
irsend.reset();
irsend.sendLG(0xB4B4AE51, LG32_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG32_BITS, irsend.capture.bits);
EXPECT_EQ(0xB4B4AE51, irsend.capture.value);
EXPECT_EQ(0xB4B, irsend.capture.address);
EXPECT_EQ(0x4AE5, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Synthesised Normal LG 28-bit message.
irsend.reset();
irsend.sendLG(irsend.encodeLG(0x07, 0x99));
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, true));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG_BITS, irsend.capture.bits);
EXPECT_EQ(0x700992, irsend.capture.value);
EXPECT_EQ(0x07, irsend.capture.address);
EXPECT_EQ(0x99, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Synthesised Normal LG 32-bit message.
irsend.reset();
irsend.sendLG(irsend.encodeLG(0x800, 0x8000), LG32_BITS);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG32_BITS, irsend.capture.bits);
EXPECT_EQ(0x80080008, irsend.capture.value);
EXPECT_EQ(0x800, irsend.capture.address);
EXPECT_EQ(0x8000, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode normal repeated LG messages.
TEST(TestDecodeLG, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal LG 28-bit message with 2 repeats.
irsend.reset();
irsend.sendLG(irsend.encodeLG(0x07, 0x99), LG_BITS, 2);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, true));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG_BITS, irsend.capture.bits);
EXPECT_EQ(0x700992, irsend.capture.value);
EXPECT_EQ(0x07, irsend.capture.address);
EXPECT_EQ(0x99, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal LG 32-bit message with 2 repeats.
irsend.reset();
irsend.sendLG(irsend.encodeLG(0x07, 0x99), LG32_BITS, 2);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG32_BITS, irsend.capture.bits);
EXPECT_EQ(0x700992, irsend.capture.value);
EXPECT_EQ(0x07, irsend.capture.address);
EXPECT_EQ(0x99, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode unsupported LG message values.
TEST(TestDecodeLG, DecodeWithNonStrictValues) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Illegal values should be rejected when strict is on.
// Illegal LG 28-bit message value.
irsend.reset();
irsend.sendLG(0x1);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false));
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG_BITS, false));
// Illegal LG 32-bit message value.
irsend.reset();
irsend.sendLG(0x1111111, LG32_BITS);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true));
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG32_BITS, irsend.capture.bits);
EXPECT_EQ(0x1111111, irsend.capture.value);
EXPECT_EQ(0x11, irsend.capture.address);
EXPECT_EQ(0x1111, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
irsend.reset();
irsend.sendLG(0x1111111, LG32_BITS);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false));
}
// Decode unsupported LG message sizes.
TEST(TestDecodeLG, DecodeWithNonStrictSizes) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Illegal sizes should be rejected when strict is on.
// Illegal LG 16-bit message size.
irsend.reset();
irsend.sendLG(irsend.encodeLG(0x07, 0x99), 16);
irsend.makeDecodeResult();
// Should fail when unexpected against different bit sizes.
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, 16, false));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(16, irsend.capture.bits);
EXPECT_EQ(0x992, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x99, irsend.capture.command);
// Illegal LG 36-bit message size.
irsend.reset();
irsend.sendLG(0x123456789, 36); // Illegal value LG 36-bit message.
irsend.makeDecodeResult();
// Should fail when unexpected against different bit sizes.
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, true));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG32_BITS, false));
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, 36, false));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(36, irsend.capture.bits);
EXPECT_EQ(0x123456789, irsend.capture.value);
EXPECT_EQ(0x1234, irsend.capture.address);
EXPECT_EQ(0x5678, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode (non-standard) 64-bit messages.
TEST(TestDecodeLG, Decode64BitMessages) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Illegal value & size LG 64-bit message.
irsend.sendLG(0xFFFFFFFFFFFFFFFF, 64);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, 64, true));
// Should work with a 'normal' match (not strict)
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, 64, false));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(64, irsend.capture.bits);
EXPECT_EQ(0xFFFFFFFFFFFFFFFF, irsend.capture.value);
EXPECT_EQ(0xFFFFFFFF, irsend.capture.address);
EXPECT_EQ(0xFFFF, irsend.capture.command);
}
// Decode a 'real' example via GlobalCache
TEST(TestDecodeLG, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// TODO(anyone): Find a Global Cache example of the LG 28-bit message.
irsend.reset();
// LG (32-bit) code from Global Cache.
uint16_t gc_test[75] = {38000, 1, 69, 341, 170, 21, 64, 21, 21, 21, 64,
21, 64, 21, 21, 21, 64, 21, 21, 21, 21, 21, 64,
21, 21, 21, 64, 21, 64, 21, 21, 21, 64, 21, 21,
21, 21, 21, 64, 21, 21, 21, 64, 21, 21, 21, 64,
21, 64, 21, 64, 21, 21, 21, 21, 21, 64, 21, 21,
21, 64, 21, 21, 21, 21, 21, 21, 21, 64, 21, 1517,
341, 85, 21, 3655};
irsend.sendGC(gc_test, 75);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeLG(&irsend.capture, LG32_BITS, true));
EXPECT_EQ(LG, irsend.capture.decode_type);
EXPECT_EQ(LG32_BITS, irsend.capture.bits);
EXPECT_EQ(0xB4B4AE51, irsend.capture.value);
EXPECT_EQ(0xB4B, irsend.capture.address);
EXPECT_EQ(0x4AE5, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Fail to decode a non-LG example via GlobalCache
TEST(TestDecodeLG, FailToDecodeNonLGExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Modified a few entries to unexpected values, based on previous test case.
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture));
ASSERT_FALSE(irrecv.decodeLG(&irsend.capture, LG_BITS, false));
}
@@ -0,0 +1,694 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "ir_Mitsubishi.h"
#include "gtest/gtest.h"
// Tests for sendMitsubishi().
// Test sending typical data only.
TEST(TestSendMitsubishi, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendMitsubishi(0xE242);
EXPECT_EQ(
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580", irsend.outputStr());
irsend.reset();
irsend.sendMitsubishi(0x0);
EXPECT_EQ(
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s53580"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s53580", irsend.outputStr());
irsend.reset();
irsend.sendMitsubishi(0x4321);
EXPECT_EQ(
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s2100"
"m300s900m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100"
"m300s53580"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s2100"
"m300s900m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100"
"m300s53580", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendMitsubishi, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendMitsubishi(0xE242, MITSUBISHI_BITS, 0); // 0 repeat.
EXPECT_EQ(
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580", irsend.outputStr());
irsend.reset();
irsend.sendMitsubishi(0xE242, MITSUBISHI_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580", irsend.outputStr());
irsend.sendMitsubishi(0xE242, MITSUBISHI_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580"
"m300s2100m300s2100m300s2100m300s900m300s900m300s900m300s2100m300s900"
"m300s900m300s2100m300s900m300s900m300s900m300s900m300s2100m300s900"
"m300s53580", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendMitsubishi, SendUsualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendMitsubishi(0x0, 8);
EXPECT_EQ(
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s53580"
"m300s900m300s900m300s900m300s900m300s900m300s900m300s900m300s900"
"m300s53580", irsend.outputStr());
irsend.reset();
irsend.sendMitsubishi(0x1234567890ABCDEF, 64);
EXPECT_EQ(
"m300s900m300s900m300s900m300s2100m300s900m300s900m300s2100m300s900"
"m300s900m300s900m300s2100m300s2100m300s900m300s2100m300s900m300s900"
"m300s900m300s2100m300s900m300s2100m300s900m300s2100m300s2100m300s900"
"m300s900m300s2100m300s2100m300s2100m300s2100m300s900m300s900m300s900"
"m300s2100m300s900m300s900m300s2100m300s900m300s900m300s900m300s900"
"m300s2100m300s900m300s2100m300s900m300s2100m300s900m300s2100m300s2100"
"m300s2100m300s2100m300s900m300s900m300s2100m300s2100m300s900m300s2100"
"m300s2100m300s2100m300s2100m300s900m300s2100m300s2100m300s2100m300s2100"
"m300s53580"
"m300s900m300s900m300s900m300s2100m300s900m300s900m300s2100m300s900"
"m300s900m300s900m300s2100m300s2100m300s900m300s2100m300s900m300s900"
"m300s900m300s2100m300s900m300s2100m300s900m300s2100m300s2100m300s900"
"m300s900m300s2100m300s2100m300s2100m300s2100m300s900m300s900m300s900"
"m300s2100m300s900m300s900m300s2100m300s900m300s900m300s900m300s900"
"m300s2100m300s900m300s2100m300s900m300s2100m300s900m300s2100m300s2100"
"m300s2100m300s2100m300s900m300s900m300s2100m300s2100m300s900m300s2100"
"m300s2100m300s2100m300s2100m300s900m300s2100m300s2100m300s2100m300s2100"
"m300s53580", irsend.outputStr());
}
// Decode normal Mitsubishi messages.
TEST(TestDecodeMitsubishi, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Mitsubishi 16-bit message.
irsend.reset();
irsend.sendMitsubishi(0xC2B8);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
irsend.reset();
irsend.sendMitsubishi(0x0);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
irsend.reset();
irsend.sendMitsubishi(0xFFFF);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits);
EXPECT_EQ(0xFFFF, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Non-standard Mitsubishi sizes should fail with strict.
irsend.reset();
// 12 bits.
irsend.sendMitsubishi(0xFFF, 12);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 12, true));
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 64, true));
// 32 bits.
irsend.sendMitsubishi(0xFFF, 32);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 12, true));
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 32, true));
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 64, true));
}
// Decode normal repeated Mitsubishi messages.
TEST(TestDecodeMitsubishi, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Mitsubishi 16-bit message with 2 repeats.
irsend.reset();
irsend.sendMitsubishi(0xC2B8, MITSUBISHI_BITS, 2);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Normal Mitsubishi 16-bit message with 0 repeats.
irsend.reset();
irsend.sendMitsubishi(0xC2B8, MITSUBISHI_BITS, 0);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits);
EXPECT_EQ(0xC2B8, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode unsupported Mitsubishi messages.
TEST(TestDecodeMitsubishi, DecodeWithNonStrictValues) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendMitsubishi(0x0, 8); // Illegal sized Mitsubishi 8-bit message.
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, 8, false));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(8, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 64, false));
irsend.reset();
// Illegal sized Mitsubishi 64-bit message.
irsend.sendMitsubishi(0xFEDCBA9876543210, 64);
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture, 64, false));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(64, irsend.capture.bits);
EXPECT_EQ(0xFEDCBA9876543210, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
// Should fail when we are after a shorter message than we got.
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, 8, false));
}
// Decode a 'real' example via GlobalCache
TEST(TestDecodeMitsubishi, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Mitsubishi "Power On" (16-bit) code from Global Cache.
uint16_t gc_test[37] = {33000, 1, 1, 10, 70, 10, 70, 10, 70, 10, 30, 10, 30,
10, 30, 10, 70, 10, 30, 10, 30, 10, 70, 10, 30,
10, 30, 10, 30, 10, 30, 10, 70, 10, 30, 10, 936};
irsend.sendGC(gc_test, 37);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeMitsubishi(&irsend.capture));
EXPECT_EQ(MITSUBISHI, irsend.capture.decode_type);
EXPECT_EQ(MITSUBISHI_BITS, irsend.capture.bits);
EXPECT_EQ(0xE242, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Fail to decode a non-Mitsubishi example via GlobalCache
TEST(TestDecodeMitsubishi, FailToDecodeNonMitsubishiExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Modified a few entries to unexpected values, based on previous test case.
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture));
ASSERT_FALSE(irrecv.decodeMitsubishi(&irsend.capture, MITSUBISHI_BITS,
false));
}
// Tests for Mitsubishi A/C methods.
// Test sending typical data only.
TEST(TestSendMitsubishiAC, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
uint8_t mitsub_code[MITSUBISHI_AC_STATE_LENGTH] = {
0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30,
0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F};
irsend.reset();
irsend.sendMitsubishiAC(mitsub_code);
EXPECT_EQ(
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m440s17100"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m440s17100", irsend.outputStr());
}
// Test sending with repeats.
TEST(TestSendMitsubishiAC, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
uint8_t mitsub_code[MITSUBISHI_AC_STATE_LENGTH] = {
0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30,
0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F};
irsend.sendMitsubishiAC(mitsub_code, MITSUBISHI_AC_STATE_LENGTH, 0);
EXPECT_EQ(
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m440s17100", irsend.outputStr());
irsend.reset();
irsend.sendMitsubishiAC(mitsub_code, MITSUBISHI_AC_STATE_LENGTH, 2);
EXPECT_EQ(
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m440s17100"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m440s17100"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m440s17100", irsend.outputStr());
}
// Test sending atypical sizes.
TEST(TestSendMitsubishiAC, SendUnexpectedSizes) {
IRsendTest irsend(4);
irsend.begin();
uint8_t mitsub_short_code[17] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20,
0x08, 0x06, 0x30, 0x45, 0x67, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t mitsub_long_code[19] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20,
0x08, 0x06, 0x30, 0x45, 0x67, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F,
0x00};
irsend.reset();
irsend.sendMitsubishiAC(mitsub_short_code, 17);
ASSERT_EQ("", irsend.outputStr());
irsend.reset();
irsend.sendMitsubishiAC(mitsub_long_code, 19);
ASSERT_EQ(
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m440s17100"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s1300m450s1300m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s1300m450s420m450s420m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s1300m450s1300m450s1300m450s1300m450s1300m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m440s17100", irsend.outputStr());
}
// Tests for IRMitsubishiAC class.
TEST(TestMitsubishiACClass, Power) {
IRMitsubishiAC mitsub(0);
mitsub.begin();
mitsub.on();
EXPECT_TRUE(mitsub.getPower());
mitsub.off();
EXPECT_FALSE(mitsub.getPower());
mitsub.setPower(true);
EXPECT_TRUE(mitsub.getPower());
mitsub.setPower(false);
EXPECT_FALSE(mitsub.getPower());
}
TEST(TestMitsubishiACClass, Temperature) {
IRMitsubishiAC mitsub(0);
mitsub.begin();
mitsub.setTemp(0);
EXPECT_EQ(MITSUBISHI_AC_MIN_TEMP, mitsub.getTemp());
mitsub.setTemp(255);
EXPECT_EQ(MITSUBISHI_AC_MAX_TEMP, mitsub.getTemp());
mitsub.setTemp(MITSUBISHI_AC_MIN_TEMP);
EXPECT_EQ(MITSUBISHI_AC_MIN_TEMP, mitsub.getTemp());
mitsub.setTemp(MITSUBISHI_AC_MAX_TEMP);
EXPECT_EQ(MITSUBISHI_AC_MAX_TEMP, mitsub.getTemp());
mitsub.setTemp(MITSUBISHI_AC_MIN_TEMP - 1);
EXPECT_EQ(MITSUBISHI_AC_MIN_TEMP, mitsub.getTemp());
mitsub.setTemp(MITSUBISHI_AC_MAX_TEMP + 1);
EXPECT_EQ(MITSUBISHI_AC_MAX_TEMP, mitsub.getTemp());
mitsub.setTemp(17);
EXPECT_EQ(17, mitsub.getTemp());
mitsub.setTemp(21);
EXPECT_EQ(21, mitsub.getTemp());
mitsub.setTemp(25);
EXPECT_EQ(25, mitsub.getTemp());
mitsub.setTemp(30);
EXPECT_EQ(30, mitsub.getTemp());
}
TEST(TestMitsubishiACClass, OperatingMode) {
IRMitsubishiAC mitsub(0);
mitsub.begin();
mitsub.setMode(MITSUBISHI_AC_AUTO);
EXPECT_EQ(MITSUBISHI_AC_AUTO, mitsub.getMode());
mitsub.setMode(MITSUBISHI_AC_COOL);
EXPECT_EQ(MITSUBISHI_AC_COOL, mitsub.getMode());
mitsub.setMode(MITSUBISHI_AC_HEAT);
EXPECT_EQ(MITSUBISHI_AC_HEAT, mitsub.getMode());
mitsub.setMode(MITSUBISHI_AC_DRY);
EXPECT_EQ(MITSUBISHI_AC_DRY, mitsub.getMode());
mitsub.setMode(MITSUBISHI_AC_AUTO + 1);
EXPECT_EQ(MITSUBISHI_AC_AUTO, mitsub.getMode());
mitsub.setMode(255);
EXPECT_EQ(MITSUBISHI_AC_AUTO, mitsub.getMode());
}
TEST(TestMitsubishiACClass, VaneMode) {
IRMitsubishiAC mitsub(0);
mitsub.begin();
mitsub.setVane(MITSUBISHI_AC_VANE_AUTO);
EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO, mitsub.getVane());
mitsub.setVane(MITSUBISHI_AC_VANE_AUTO + 1);
EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO + 1, mitsub.getVane());
mitsub.setVane(MITSUBISHI_AC_VANE_AUTO_MOVE);
EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO_MOVE, mitsub.getVane());
mitsub.setVane(MITSUBISHI_AC_VANE_AUTO_MOVE + 1);
EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO_MOVE, mitsub.getVane());
mitsub.setVane(MITSUBISHI_AC_VANE_AUTO_MOVE - 1);
EXPECT_EQ(MITSUBISHI_AC_VANE_AUTO_MOVE - 1, mitsub.getVane());
}
TEST(TestMitsubishiACClass, FanSpeed) {
IRMitsubishiAC mitsub(0);
mitsub.begin();
mitsub.setFan(MITSUBISHI_AC_FAN_AUTO);
EXPECT_EQ(MITSUBISHI_AC_FAN_AUTO, mitsub.getFan());
mitsub.setFan(255);
EXPECT_EQ(MITSUBISHI_AC_FAN_REAL_MAX, mitsub.getFan());
mitsub.setFan(MITSUBISHI_AC_FAN_MAX);
EXPECT_EQ(MITSUBISHI_AC_FAN_REAL_MAX, mitsub.getFan());
mitsub.setFan(MITSUBISHI_AC_FAN_MAX - 1);
EXPECT_EQ(MITSUBISHI_AC_FAN_MAX - 1, mitsub.getFan());
mitsub.setFan(1);
EXPECT_EQ(1, mitsub.getFan());
mitsub.setFan(2);
EXPECT_EQ(2, mitsub.getFan());
mitsub.setFan(3);
EXPECT_EQ(3, mitsub.getFan());
mitsub.setFan(4);
EXPECT_EQ(4, mitsub.getFan());
mitsub.setFan(MITSUBISHI_AC_FAN_SILENT);
EXPECT_EQ(MITSUBISHI_AC_FAN_SILENT, mitsub.getFan());
mitsub.setFan(MITSUBISHI_AC_FAN_SILENT + 1);
EXPECT_EQ(MITSUBISHI_AC_FAN_REAL_MAX, mitsub.getFan());
}
TEST(TestMitsubishiACClass, MessageConstuction) {
IRMitsubishiAC mitsub(0);
IRsendTest irsend(4);
mitsub.begin();
irsend.begin();
mitsub.setFan(1);
mitsub.setMode(MITSUBISHI_AC_COOL);
mitsub.setTemp(27);
mitsub.setVane(3);
mitsub.on();
// Check everything for kicks.
EXPECT_EQ(1, mitsub.getFan());
EXPECT_EQ(MITSUBISHI_AC_COOL, mitsub.getMode());
EXPECT_EQ(27, mitsub.getTemp());
EXPECT_EQ(3, mitsub.getVane());
EXPECT_TRUE(mitsub.getPower());
irsend.reset();
irsend.sendMitsubishiAC(mitsub.getRaw());
EXPECT_EQ(
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s1300m450s1300m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s1300m450s420"
"m440s17100"
"m3400s1750"
"m450s1300m450s1300m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s1300m450s1300"
"m450s420m450s1300m450s1300m450s420m450s420m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s1300m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420m450s420"
"m450s1300m450s1300m450s420m450s1300m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s1300m450s1300m450s420m450s420"
"m450s1300m450s420m450s420m450s1300m450s1300m450s420m450s1300m450s420"
"m450s1300m450s1300m450s1300m450s420m450s420m450s1300m450s1300m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s420m450s420m450s420m450s420m450s420"
"m450s420m450s420m450s420m450s1300m450s420m450s420m450s1300m450s420"
"m440s17100", irsend.outputStr());
}
+320
View File
@@ -0,0 +1,320 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendNEC().
// Test sending typical data only.
TEST(TestSendNEC, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendNEC(0);
EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s108080", irsend.outputStr());
irsend.sendNEC(0xAA00FF55);
EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680"
"m560s1680m560s1680m560s1680m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s560m560s1680m560s108080",
irsend.outputStr());
}
// Test sending different bit lengths.
TEST(TestSendNEC, SendSmallData) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendNEC(0xA, 4); // Send only 4 data bits.
EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s108080",
irsend.outputStr());
irsend.sendNEC(0, 8); // Send only 8 data bits.
EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s108080", irsend.outputStr());
irsend.sendNEC(0x1234567890ABCDEF, 64); // Send 64 data bits.
EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s1680m560s560m560s560"
"m560s1680m560s560m560s560m560s560m560s1680m560s1680m560s560"
"m560s1680m560s560m560s560m560s560m560s1680m560s560m560s1680"
"m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s1680"
"m560s1680m560s1680m560s560m560s560m560s560m560s1680m560s560"
"m560s560m560s1680m560s560m560s560m560s560m560s560m560s1680m560s560"
"m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s1680"
"m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680"
"m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680"
"m560s1680m560s108080", irsend.outputStr());
}
// Test sending with repeats.
TEST(TestSendNEC, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendNEC(0, 8, 0); // Send a command with 0 repeats.
EXPECT_EQ("m8960s4480m560s560m560s560m560s560m560s560m560s560m560s560m560s560"
"m560s560m560s108080", irsend.outputStr());
irsend.sendNEC(0xAA, 8, 1); // Send a command with 1 repeat.
EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s108080"
"m8960s2240m560s108080",
irsend.outputStr());
irsend.sendNEC(0xAA, 8, 3); // Send a command with 3 repeats.
EXPECT_EQ("m8960s4480m560s1680m560s560m560s1680m560s560m560s1680m560s560"
"m560s1680m560s560m560s108080"
"m8960s2240m560s108080"
"m8960s2240m560s108080"
"m8960s2240m560s108080",
irsend.outputStr());
}
// Tests for encodeNEC().
TEST(TestEncodeNEC, NormalNECEncoding) {
IRsendTest irsend(4);
EXPECT_EQ(0x807F40BF, irsend.encodeNEC(1, 2));
EXPECT_EQ(0x9A656897, irsend.encodeNEC(0x59, 0x16));
}
TEST(TestEncodeNEC, ExtendedNECEncoding) {
IRsendTest irsend(4);
EXPECT_EQ(0x9A806897, irsend.encodeNEC(0x159, 0x16));
}
TEST(TestEncodeNEC, CommandTrimmedTo8Bits) {
IRsendTest irsend(4);
EXPECT_EQ(irsend.encodeNEC(0x1, 0x2), irsend.encodeNEC(0x1, 0xF02));
EXPECT_EQ(irsend.encodeNEC(0xFFF0, 0x2), irsend.encodeNEC(0xFFF0, 0xF02));
}
// Tests for decodeNEC().
// Decode normal NEC messages.
TEST(TestDecodeNEC, NormalNECDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Synthesised Normal NEC message.
irsend.reset();
irsend.sendNEC(irsend.encodeNEC(0x1, 0x2));
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x807F40BF, irsend.capture.value);
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x2, irsend.capture.command);
// Real-life Extended NEC code from an actual capture/decode.
irsend.reset();
irsend.sendNEC(0xC1A28877);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0xC1A28877, irsend.capture.value);
EXPECT_EQ(0x4583, irsend.capture.address);
EXPECT_EQ(0x11, irsend.capture.command);
// Test strict decoding rejects a NEC-like message.
irsend.reset();
irsend.sendNEC(0x0);
irsend.makeDecodeResult();
EXPECT_FALSE(irrecv.decodeNEC(&irsend.capture));
// Synthesised Normal NEC message with a repeat.
irsend.reset();
irsend.sendNEC(irsend.encodeNEC(0x1, 0x2), 32, 1);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x807F40BF, irsend.capture.value);
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x2, irsend.capture.command);
}
// NEC-like messages without strict mode.
TEST(TestDecodeNEC, NormalNECDecodeWithoutStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendNEC(0x0);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, 32, false));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0, irsend.capture.value);
EXPECT_EQ(0, irsend.capture.address);
EXPECT_EQ(0, irsend.capture.command);
irsend.reset();
irsend.sendNEC(0x12345678);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, 32, false));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x12345678, irsend.capture.value);
EXPECT_EQ(0x2C48, irsend.capture.address);
EXPECT_EQ(0, irsend.capture.command);
}
// Short NEC-like messages (without strict naturally)
TEST(TestDecodeNEC, ShortNECDecodeWithoutStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendNEC(0x0, 16);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, 16, false));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(16, irsend.capture.bits);
EXPECT_EQ(0, irsend.capture.value);
EXPECT_EQ(0, irsend.capture.address);
EXPECT_EQ(0, irsend.capture.command);
// Expecting less than what was sent is not valid.
irsend.reset();
irsend.sendNEC(0x0, 32);
irsend.makeDecodeResult();
EXPECT_FALSE(irrecv.decodeNEC(&irsend.capture, 16, false));
// Send 16 bits of data, but fail because we are expecting 17.
irsend.reset();
irsend.sendNEC(0x0, 16);
irsend.makeDecodeResult();
EXPECT_FALSE(irrecv.decodeNEC(&irsend.capture, 17, false));
}
// Longer NEC-like messages (without strict naturally)
TEST(TestDecodeNEC, LongerNECDecodeWithoutStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendNEC(0x1234567890ABCDEF, 64);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, 64, false));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(64, irsend.capture.bits);
EXPECT_EQ(0x1234567890ABCDEF, irsend.capture.value);
EXPECT_EQ(0xD509, irsend.capture.address);
EXPECT_EQ(0, irsend.capture.command);
// Send 63 bits of data, but fail because we are expecting 64.
irsend.reset();
irsend.sendNEC(0x0, 63);
irsend.makeDecodeResult();
EXPECT_FALSE(irrecv.decodeNEC(&irsend.capture, 64, false));
}
// Incorrect decoding reported in Issue #243
// Incorrect handling of decodes when there is no gap recorded at
// the end of a command when using the interrupt code. sendRaw() best emulates
// this for unit testing purposes. sendGC() and sendXXX() will add the trailing
// gap. Users won't see this in normal use.
TEST(TestDecodeNEC, NoTrailingGap_Issue243) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
600, 1650, 650, 550, 600, 1650, 650, 1650, 650, 1650,
600, 550, 650, 1650, 650, 1650, 650, 550, 600, 1650,
650, 1650, 650, 550, 650, 550, 650, 1650, 650, 550,
650, 550, 650, 550, 600, 550, 650, 550, 650, 550,
650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
650, 1650, 650, 1650, 650, 1650, 600};
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x4BB640BF, irsend.capture.value);
EXPECT_EQ(0x6DD2, irsend.capture.address);
EXPECT_EQ(0x2, irsend.capture.command);
irsend.reset();
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x4BB640BF, irsend.capture.value);
// Add a zero length space to the message to test how it handles that as
// a end of command gap.
irsend.addGap(0);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x4BB640BF, irsend.capture.value);
}
// Inconsistent decoding for unknown in Issue #264
// Reported issues decoding an Apple Remote. Apple doesn't appear to respect
// or use the command structure/checks in the NEC protocol.
TEST(TestDecodeNEC, NonStrictNECDecode_Issue264) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Slightly modified example than reported due to poor timings that are too
// far out of spec.
uint16_t rawData[67] = {9150, 4650, 550, 600, 550, 1800, 600, 1750, 600, 1800,
550, 600, 550, 1800, 550, 1750, 600, 1750, 600, 1750,
600, 1750, 600, 1700, 600, 600, 600, 600, 550, 600,
600, 600, 600, 1750, 600, 1750, 600, 600, 550, 1800,
600, 600, 600, 600, 600, 600, 500, 600, 600, 600,
600, 600, 600, 1750, 600, 600, 600, 550, 600, 600,
600, 600, 600, 600, 600, 550, 600};
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
EXPECT_FALSE(irrecv.decodeNEC(&irsend.capture)); // Not strictly NEC
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, NEC_BITS, false));
EXPECT_EQ(0x77E1A040, irsend.capture.value);
// Do it all again, but with a normal decode.
irsend.reset();
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(NEC_LIKE, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x77E1A040, irsend.capture.value);
}
TEST(TestDecodeNEC, AutoReceiveCalibration) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Data from Issue #264, for a remote that is slightly off spec.
// Should be matched as a NEC-like message however without self-calibrating
// the timings of the short spaces is out.
uint16_t rawData[67] = {9150, 4600, 650, 600, 650, 1650, 650, 1700, 650, 1750,
650, 600, 650, 1700, 650, 1750, 650, 1750, 650, 1700,
650, 1700, 650, 1700, 650, 600, 650, 600, 650, 600,
600, 600, 650, 1750, 650, 1750, 650, 600, 650, 1700,
600, 600, 700, 550, 650, 550, 650, 600, 650, 600,
650, 600, 650, 1750, 600, 600, 650, 600, 650, 550,
650, 600, 650, 600, 650, 600, 600};
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture, NEC_BITS, false));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x77E1A040, irsend.capture.value);
}
@@ -0,0 +1,457 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for encodePanasonic().
TEST(TestEncodePanasonic, General) {
IRsendTest irsend(4);
EXPECT_EQ(0x0, irsend.encodePanasonic(0, 0, 0, 0));
EXPECT_EQ(0x101010101, irsend.encodePanasonic(1, 1, 1, 1));
EXPECT_EQ(0xFFFF, irsend.encodePanasonic(0, 0, 0, 0xFF));
EXPECT_EQ(0xFF00FF, irsend.encodePanasonic(0, 0, 0xFF, 0));
EXPECT_EQ(0xFF0000FF, irsend.encodePanasonic(0, 0xFF, 0, 0));
EXPECT_EQ(0xFFFF00000000, irsend.encodePanasonic(0xFFFF, 0, 0, 0));
EXPECT_EQ(0xFFFFFFFFFFFF, irsend.encodePanasonic(0xFFFF, 0xFF, 0xFF, 0xFF));
EXPECT_EQ(0x40040190ED7C, irsend.encodePanasonic(0x4004, 0x01, 0x90, 0xED));
}
// Tests for sendPanasonic64().
// Test sending typical data only.
TEST(TestSendPanasonic64, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendPanasonic64(0x0);
EXPECT_EQ(
"m3456s1728"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s129600", irsend.outputStr());
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C);
EXPECT_EQ(
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s129600", irsend.outputStr());
irsend.reset();
irsend.sendPanasonic64(0xFFFFFFFFFFFF);
EXPECT_EQ(
"m3456s1728"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296m432s1296"
"m432s129600", irsend.outputStr());
}
// Test sending with different repeats.
TEST(TestSendPanasonic64, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 0); // 0 repeats.
EXPECT_EQ(
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s129600", irsend.outputStr());
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 1); // 1 repeat.
EXPECT_EQ(
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s129600"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s129600", irsend.outputStr());
irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 2); // 2 repeats.
EXPECT_EQ(
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s129600"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s129600"
"m3456s1728"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s432m432s1296"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s129600", irsend.outputStr());
}
// Test sending an atypical data size.
TEST(TestSendPanasonic64, SendUnusualSize) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
irsend.sendPanasonic64(0x0, 8);
EXPECT_EQ(
"m3456s1728"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s129600", irsend.outputStr());
irsend.reset();
irsend.sendPanasonic64(0x1234567890ABCDEF, 64);
EXPECT_EQ(
"m3456s1728"
"m432s432m432s432m432s432m432s1296m432s432m432s432m432s1296m432s432"
"m432s432m432s432m432s1296m432s1296m432s432m432s1296m432s432m432s432"
"m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s1296m432s432"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s432m432s432m432s432"
"m432s1296m432s432m432s432m432s1296m432s432m432s432m432s432m432s432"
"m432s1296m432s432m432s1296m432s432m432s1296m432s432m432s1296m432s1296"
"m432s1296m432s1296m432s432m432s432m432s1296m432s1296m432s432m432s1296"
"m432s1296m432s1296m432s1296m432s432m432s1296m432s1296m432s1296m432s1296"
"m432s129600", irsend.outputStr());
}
// Tests for sendPanasonic().
TEST(TestSendPanasonic, CompareToSendPanasonic64) {
IRsendTest panasonic(4);
IRsendTest panasonic64(0);
panasonic.begin();
panasonic64.begin();
panasonic.reset();
panasonic64.reset();
panasonic.sendPanasonic(0x4004, 0x0190ED7C);
panasonic64.sendPanasonic64(0x40040190ED7C);
EXPECT_EQ(panasonic64.outputStr(), panasonic.outputStr());
panasonic.sendPanasonic(0x0, 0x0);
panasonic64.sendPanasonic64(0x0);
EXPECT_EQ(panasonic64.outputStr(), panasonic.outputStr());
panasonic.sendPanasonic(0x0, 0x0, 8);
panasonic64.sendPanasonic64(0x0, 8);
EXPECT_EQ(panasonic64.outputStr(), panasonic.outputStr());
panasonic.sendPanasonic(0x1234, 0x567890AB, 64);
panasonic64.sendPanasonic64(0x1234567890AB, 64);
EXPECT_EQ(panasonic64.outputStr(), panasonic.outputStr());
panasonic.sendPanasonic(0x1234, 0x567890AB, PANASONIC_BITS, 2);
panasonic64.sendPanasonic64(0x1234567890AB, PANASONIC_BITS, 2);
EXPECT_EQ(panasonic64.outputStr(), panasonic.outputStr());
}
// Tests for decodePanasonic().
// Decode normal Panasonic messages.
TEST(TestDecodePanasonic, NormalDecodeWithStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Panasonic 48-bit message.
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x0190ED7C, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Synthesised Normal Panasonic 48-bit message.
irsend.reset();
irsend.sendPanasonic64(irsend.encodePanasonic(0x4004, 0x12, 0x34, 0x56));
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x400412345670, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x12345670, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
// Synthesised Normal Panasonic 48-bit message.
irsend.reset();
irsend.sendPanasonic64(irsend.encodePanasonic(0x4004, 0x1, 0x1, 0x1));
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x400401010101, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x1010101, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Decode normal repeated Panasonic messages.
TEST(TestDecodePanasonic, NormalDecodeWithRepeatAndStrict) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Normal Panasonic 48-bit message with 2 repeats.
irsend.reset();
irsend.sendPanasonic64(0x40040190ED7C, PANASONIC_BITS, 2);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x190ED7C, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
irsend.makeDecodeResult(2 * PANASONIC_BITS + 4);
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
irsend.makeDecodeResult(2 * (2 * PANASONIC_BITS + 4));
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
}
// Decode Panasonic messages with unsupported values.
TEST(TestDecodePanasonic, DecodeWithNonStrictValues) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendPanasonic64(0x0); // Illegal value Panasonic 48-bit message.
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x0, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
irsend.reset();
// Illegal address/Manufacturer code. The rest is legal.
irsend.sendPanasonic64(irsend.encodePanasonic(0, 1, 2, 3));
irsend.makeDecodeResult();
// Should fail with strict on.
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x1020300, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x1020300, irsend.capture.command);
}
// Decode Panasonic messages with unsupported size/lengths.
TEST(TestDecodePanasonic, DecodeWithNonStrictSize) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
irsend.sendPanasonic64(0x12345678, 32); // Illegal size Panasonic message.
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
irsend.makeDecodeResult();
// Should fail with strict when we ask for the wrong bit size.
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, 32, true));
// Should pass if strict off.
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, 32, false));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0x12345678, irsend.capture.value);
EXPECT_EQ(0x0, irsend.capture.address);
EXPECT_EQ(0x12345678, irsend.capture.command);
// Illegal over length (56-bit) message.
irsend.reset();
irsend.sendPanasonic64(irsend.encodePanasonic(0x4004, 1, 2, 3), 56);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
// Shouldn't pass if strict off and wrong bit size.
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false));
// Re-decode with correct bit size.
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, 56, true));
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, 56, false));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(56, irsend.capture.bits);
EXPECT_EQ(0x400401020300, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x01020300, irsend.capture.command);
}
// Decode (non-standard) 64-bit messages.
TEST(TestDecodePanasonic, Decode64BitMessages) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Illegal value & size Panasonic 64-bit message.
irsend.sendPanasonic64(0xFFFFFFFFFFFFFFFF, 64);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, 64, true));
// Should work with a 'normal' match (not strict)
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, 64, false));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(64, irsend.capture.bits);
EXPECT_EQ(0xFFFFFFFFFFFFFFFF, irsend.capture.value);
EXPECT_EQ(0xFFFFFFFF, irsend.capture.address);
EXPECT_EQ(0xFFFFFFFF, irsend.capture.command);
}
// Decode a 'real' example via GlobalCache
TEST(TestDecodePanasonic, DecodeGlobalCacheExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Panasonic code from Global Cache.
uint16_t gc_test[103] = {37000, 1, 1, 126, 64, 16, 17, 16, 49, 15, 16, 16, 16,
16, 16, 16, 17, 15, 17, 15, 17, 15, 17, 15, 16, 16,
16, 16, 16, 16, 17, 15, 49, 16, 16, 16, 16, 16, 17,
15, 17, 15, 17, 15, 17, 15, 16, 16, 16, 16, 16, 16,
49, 15, 49, 16, 17, 15, 17, 15, 49, 16, 16, 16, 17,
16, 17, 15, 17, 15, 49, 16, 49, 15, 49, 16, 17, 16,
49, 15, 49, 16, 17, 15, 48, 16, 16, 16, 49, 15, 48,
16, 49, 15, 49, 16, 49, 15, 17, 15, 16, 16, 2721};
irsend.sendGC(gc_test, 103);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, true));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x0190ED7C, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040190ED7C, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x0190ED7C, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
// Fail to decode a non-Panasonic example via GlobalCache
TEST(TestDecodePanasonic, FailToDecodeNonPanasonicExample) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
// Modified a few entries to unexpected values, based on previous test case.
uint16_t gc_test[39] = {38000, 1, 1, 322, 162, 20, 61, 20, 61, 20, 20, 20, 20,
20, 20, 20, 127, 20, 61, 9, 20, 20, 61, 20, 20, 20,
61, 20, 61, 20, 61, 20, 20, 20, 20, 20, 20, 20, 884};
irsend.sendGC(gc_test, 39);
irsend.makeDecodeResult();
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture));
ASSERT_FALSE(irrecv.decodePanasonic(&irsend.capture, PANASONIC_BITS, false));
}
// Failing to decode Panasonic in Issue #245
TEST(TestDecodePanasonic, DecodeIssue245) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
uint16_t rawData[100] = {3550, 1750, 500, 450, 500, 1300, 500, 450, 500, 450,
500, 450, 500, 450, 500, 450, 500, 450, 500, 450,
500, 450, 500, 450, 500, 450, 500, 450, 500, 1300,
500, 450, 500, 450, 500, 450, 500, 450, 500, 450,
500, 450, 500, 450, 500, 450, 500, 450, 500, 1300,
500, 450, 500, 450, 500, 450, 500, 450, 500, 450,
500, 450, 500, 450, 500, 450, 500, 1300, 500, 450,
500, 1300, 500, 1300, 500, 1300, 500, 1300, 500, 450,
500, 450, 500, 1300, 500, 450, 500, 1300, 500, 1300,
500, 1300, 500, 1300, 500, 450, 500, 1300, 500, 5000};
irsend.sendRaw(rawData, 100, 37);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodePanasonic(&irsend.capture));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040100BCBD, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x100BCBD, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
irsend.reset();
irsend.sendRaw(rawData, 99, 37);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x40040100BCBD, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x100BCBD, irsend.capture.command);
EXPECT_FALSE(irsend.capture.repeat);
}
+358
View File
@@ -0,0 +1,358 @@
// Copyright 2017 David Conran
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendPronto().
TEST(TestSendPronto, CodeTooShort) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
// Less entries than the smallest possible (practical) Pronto code.
uint16_t pronto_test[5] = {0x0000, 0x0067, 0x0034, 0x0000, 0x0000};
irsend.sendPronto(pronto_test, 5);
EXPECT_EQ("", irsend.outputStr()); // Should do nothing.
}
TEST(TestSendPronto, NormalSequenceTooLong) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
// The First 'Normal' sequence is declared to be longer than the data we have.
uint16_t pronto_test[6] = {0x0000, 0x0067, 0x0010, 0x0000, 0x0000, 0x0000};
irsend.sendPronto(pronto_test, 6);
EXPECT_EQ("", irsend.outputStr()); // Should do nothing.
}
TEST(TestSendPronto, RepeatSequenceTooLong) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
// The 2nd 'Repeat' sequence is declared to be longer than the data we have.
uint16_t pronto_test[6] = {0x0000, 0x0067, 0x0000, 0x0010, 0x0000, 0x0000};
irsend.sendPronto(pronto_test, 6);
EXPECT_EQ("", irsend.outputStr()); // Should do nothing.
}
TEST(TestSendPronto, BothSequencesTooLong) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
// All sequences are declared to be longer than the data we have.
uint16_t pronto_test[6] = {0x0000, 0x0067, 0x0010, 0x0010, 0x0000, 0x0000};
irsend.sendPronto(pronto_test, 6);
EXPECT_EQ("", irsend.outputStr()); // Should do nothing.
}
TEST(TestSendPronto, MoreDataThanNeededInNormal) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
// We should handle when we are given more data than needed. (normal seq.)
uint16_t pronto_test[8] = {0x0000, 0x0067, 0x0001, 0x0000,
0x0001, 0x0002, 0x0003, 0x0004};
irsend.sendPronto(pronto_test, 8);
EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
}
TEST(TestSendPronto, MoreDataThanNeededInRepeat) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
// We should handle when we are given more data than needed. (repeat seq.)
uint16_t pronto_test[8] = {0x0000, 0x0067, 0x0000, 0x0001,
0x0001, 0x0002, 0x0003, 0x0004};
irsend.sendPronto(pronto_test, 8);
EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
}
TEST(TestSendPronto, MoreDataThanNeededInBoth) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
// We should handle when we are given more data than needed. (repeat seq.)
uint16_t pronto_test[10] = {0x0000, 0x0067, 0x0001, 0x0001,
0x0001, 0x0002, 0x0003, 0x0004, 0x5, 0x6};
irsend.sendPronto(pronto_test, 10);
EXPECT_EQ("m25s50", irsend.outputStr()); // Only send the data required.
irsend.sendPronto(pronto_test, 10, 1);
EXPECT_EQ("m25s50m75s100", irsend.outputStr()); // Only the data required.
}
TEST(TestSendPronto, ShortestValidCodeThatSendsNothing) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
uint16_t pronto_test[6] = {0x0000, 0x0067, 0x0000, 0x0000, 0x0001, 0x0002};
irsend.sendPronto(pronto_test, 6);
EXPECT_EQ("", irsend.outputStr()); // Nothing Happens.
irsend.sendPronto(pronto_test, 6, 1);
EXPECT_EQ("", irsend.outputStr()); // Twice as much Nothing Happens. ;-)
}
// Test sending a Pronto code that only has a normal (first) sequence.
// i.e. No Pronto repeat sequence.
TEST(TestSendPronto, NonRepeatingCode) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// A random Pronto code I found on the Internet that has no repeat sequence.
// It was an example of a poor Pronto code.
// It turned out to be a 4 copies of a Sony 12-bit code. Who knew!?!
uint16_t pronto_test[108] = {
0x0000, 0x0067, 0x0034, 0x0000,
0x0060, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0018, 0x0452, 0x0060, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0018, 0x0452, 0x0060, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0452, 0x0060, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018,
0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018};
// Send the Pronto code without any repeats set.
irsend.reset();
irsend.sendPronto(pronto_test, 108);
irsend.makeDecodeResult();
EXPECT_EQ(
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s600", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SONY, irsend.capture.decode_type);
EXPECT_EQ(SONY_12_BITS, irsend.capture.bits);
EXPECT_EQ(0x10, irsend.capture.value);
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
// Now try repeating it.
// As it has no repeat sequence, we shouldn't repeat it. (I think)
irsend.reset();
irsend.sendPronto(pronto_test, 108, 3);
irsend.makeDecodeResult();
EXPECT_EQ(
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s27650"
"m2400s600"
"m600s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600"
"m600s600m600s600m600s600m600s600", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SONY, irsend.capture.decode_type);
EXPECT_EQ(SONY_12_BITS, irsend.capture.bits);
EXPECT_EQ(0x10, irsend.capture.value);
EXPECT_EQ(0x1, irsend.capture.address);
EXPECT_EQ(0x0, irsend.capture.command);
}
// Test sending a Pronto code that only has a repeat sequence (Sony).
TEST(TestSendPronto, RepeatSequenceOnlyForSony) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Sony 20-bit command.
uint16_t pronto_test[46] = {
0x0000, 0x0067, 0x0000, 0x0015,
0x0060, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0030, 0x0018,
0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018,
0x0018, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018,
0x0030, 0x0018, 0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
0x0030, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0030, 0x0018,
0x0018, 0x03f6};
// Send the Pronto code without any repeats set.
irsend.reset();
irsend.sendPronto(pronto_test, 46);
irsend.makeDecodeResult();
EXPECT_EQ(
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s25350", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SONY, irsend.capture.decode_type);
EXPECT_EQ(SONY_20_BITS, irsend.capture.bits);
EXPECT_EQ(0x74B92, irsend.capture.value);
EXPECT_EQ(0x1A, irsend.capture.address);
EXPECT_EQ(0x24AE, irsend.capture.command);
// Send the Pronto code with 2 repeats.
irsend.reset();
irsend.sendPronto(pronto_test, 46, SONY_MIN_REPEAT);
irsend.makeDecodeResult();
EXPECT_EQ(
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s25350"
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s25350"
"m2400s600"
"m600s600m1200s600m1200s600m1200s600m600s600m1200s600m600s600m600s600"
"m1200s600m600s600m1200s600m1200s600m1200s600m600s600m600s600m1200s600"
"m600s600m600s600m1200s600m600s25350", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(SONY, irsend.capture.decode_type);
EXPECT_EQ(SONY_20_BITS, irsend.capture.bits);
EXPECT_EQ(0x74B92, irsend.capture.value);
EXPECT_EQ(0x1A, irsend.capture.address);
EXPECT_EQ(0x24AE, irsend.capture.command);
}
// Test sending a Pronto code that only has a repeat sequence (Panasonic).
TEST(TestSendPronto, RepeatSequenceOnlyForPanasonic) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// Panasonic Plasma TV Descrete code (Power On).
uint16_t pronto_test[104] = {
0x0000, 0x0071, 0x0000, 0x0032,
0x0080, 0x003F, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0030, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0030,
0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0030, 0x0010, 0x0030,
0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0030, 0x0010, 0x0010,
0x0010, 0x0030, 0x0010, 0x0A98};
// Send the Pronto code without any repeats set.
irsend.reset();
irsend.sendPronto(pronto_test, 104);
irsend.makeDecodeResult();
EXPECT_EQ(
"m3456s1701"
"m432s432m432s1296m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s1296m432s432m432s432"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s1296"
"m432s432m432s432m432s432m432s432m432s432m432s432m432s432m432s432"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s432"
"m432s432m432s1296m432s1296m432s1296m432s1296m432s1296m432s432m432s1296"
"m432s73224", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(PANASONIC, irsend.capture.decode_type);
EXPECT_EQ(PANASONIC_BITS, irsend.capture.bits);
EXPECT_EQ(0x400401007C7D, irsend.capture.value);
EXPECT_EQ(0x4004, irsend.capture.address);
EXPECT_EQ(0x1007C7D, irsend.capture.command);
}
// Test sending a Pronto code that has a normal & arepeat sequence (NEC).
TEST(TestSendPronto, NormalPlusRepeatSequence) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
// NEC 32 bit power on command.
uint16_t pronto_test[76] = {
0x0000, 0x006D, 0x0022, 0x0002,
0x0156, 0x00AB, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015,
0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0015, 0x0015, 0x0015,
0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040,
0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040,
0x0015, 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015,
0x0015, 0x0040, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015,
0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040,
0x0015, 0x0015, 0x0015, 0x0040, 0x0015, 0x0040, 0x0015, 0x0040,
0x0015, 0x0040, 0x0015, 0x05FD,
0x0156, 0x0055, 0x0015, 0x0E4E};
// Send the Pronto code without any repeats set.
irsend.reset();
irsend.sendPronto(pronto_test, 76);
irsend.makeDecodeResult();
EXPECT_EQ(
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
"m546s546m546s546m546s546m546s1664m546s546m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s1664m546s1664m546s1664m546s1664"
"m546s39858", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x18E710EF, irsend.capture.value);
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
// Send it again with a single repeat.
irsend.reset();
irsend.sendPronto(pronto_test, 76, 1);
irsend.makeDecodeResult();
EXPECT_EQ(
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
"m546s546m546s546m546s546m546s1664m546s546m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s1664m546s1664m546s1664m546s1664"
"m546s39858"
"m8892s2210m546s95212", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x18E710EF, irsend.capture.value);
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
// Send it again with a two repeats.
irsend.reset();
irsend.sendPronto(pronto_test, 76, 2);
irsend.makeDecodeResult();
EXPECT_EQ(
"m8892s4446"
"m546s546m546s546m546s546m546s1664m546s1664m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s546m546s1664m546s1664m546s1664"
"m546s546m546s546m546s546m546s1664m546s546m546s546m546s546m546s546"
"m546s1664m546s1664m546s1664m546s546m546s1664m546s1664m546s1664m546s1664"
"m546s39858"
"m8892s2210m546s95212"
"m8892s2210m546s95212", irsend.outputStr());
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(NEC_BITS, irsend.capture.bits);
EXPECT_EQ(0x18E710EF, irsend.capture.value);
EXPECT_EQ(0x18, irsend.capture.address);
EXPECT_EQ(0x8, irsend.capture.command);
}
Loaded 100 of 396 files, more files were not shown because too many files have changed in this diff. Show more