publish libraries to avoid users to have to download them one by one
This commit is contained in:
1 parent
93c075e880
commit
f0546fab8c
396 files changed
+536928
No files matched your search
@@ -0,0 +1,3 @@
|
||||
set noparent
|
||||
root=src
|
||||
linelength=80
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
# IRremote ESP8266 Library
|
||||
|
||||
[](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}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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}
|
||||
@@ -0,0 +1 @@
|
||||
filter=-build/include,+build/include_alpha,+build/include_order,+build/include_what_you_use
|
||||
@@ -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 -------------------
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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.
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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 $@
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
Reference in new issue
Block a user