- code copied from Teensyduino - restructured into src/ and include/ dirsmain
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. | |||||
## 2.3.3 - 2017/03/31 | |||||
- Added ESP32 IR receive support [PR #427](https://github.com/z3t0/Arduino-IRremote/pull/425) | |||||
## 2.2.3 - 2017/03/27 | |||||
- Fix calculation of pause length in LEGO PF protocol [PR #427](https://github.com/z3t0/Arduino-IRremote/pull/427) | |||||
## 2.2.2 - 2017/01/20 | |||||
- Fixed naming bug [PR #398](https://github.com/z3t0/Arduino-IRremote/pull/398) | |||||
## 2.2.1 - 2016/07/27 | |||||
- Added tests for Lego Power Functions Protocol [PR #336](https://github.com/z3t0/Arduino-IRremote/pull/336) | |||||
## 2.2.0 - 2016/06/28 | |||||
- Added support for ATmega8535 | |||||
- Added support for ATmega16 | |||||
- Added support for ATmega32 | |||||
- Added support for ATmega164 | |||||
- Added support for ATmega324 | |||||
- Added support for ATmega644 | |||||
- Added support for ATmega1284 | |||||
- Added support for ATmega64 | |||||
- Added support for ATmega128 | |||||
[PR](https://github.com/z3t0/Arduino-IRremote/pull/324) | |||||
## 2.1.1 - 2016/05/04 | |||||
- Added Lego Power Functions Protocol [PR #309](https://github.com/z3t0/Arduino-IRremote/pull/309) | |||||
## 2.1.0 - 2016/02/20 | |||||
- Improved Debugging [PR #258](https://github.com/z3t0/Arduino-IRremote/pull/258) | |||||
- Display TIME instead of TICKS [PR #258](https://github.com/z3t0/Arduino-IRremote/pull/258) | |||||
## 2.0.4 - 2016/02/20 | |||||
- Add Panasonic and JVC to IRrecord example [PR](https://github.com/z3t0/Arduino-IRremote/pull/54) | |||||
## 2.0.3 - 2016/02/20 | |||||
- Change IRSend Raw parameter to const [PR](https://github.com/z3t0/Arduino-IRremote/pull/227) | |||||
## 2.0.2 - 2015/12/02 | |||||
- Added IRremoteInfo Sketch - [PR](https://github.com/z3t0/Arduino-IRremote/pull/241) | |||||
- Enforcing changelog.md | |||||
## 2.0.1 - 2015/07/26 - [Release](https://github.com/shirriff/Arduino-IRremote/releases/tag/BETA) | |||||
### Changes | |||||
- Updated README | |||||
- Updated Contributors | |||||
- Fixed #110 Mess | |||||
- Created Gitter Room | |||||
- Added Gitter Badge | |||||
- Standardised Code Base | |||||
- Clean Debug Output | |||||
- Optimized Send Loops | |||||
- Modularized Design | |||||
- Optimized and Updated Examples | |||||
- Improved Documentation | |||||
- Fixed and Improved many coding errors | |||||
- Fixed Aiwa RC-T501 Decoding | |||||
- Fixed Interrupt on ATmega8 | |||||
- Switched to Stable Release of @PlatformIO | |||||
### Additions | |||||
- Added Aiwa RC-T501 Protocol | |||||
- Added Denon Protocol | |||||
- Added Pronto Support | |||||
- Added Library Properties | |||||
- Added Template For New Protocols | |||||
- Added this changelog | |||||
- Added Teensy LC Support | |||||
- Added ATtiny84 Support | |||||
- Added ATtiny85 Support | |||||
- Added isIdle method | |||||
### Deletions | |||||
- Removed (Fixed) #110 | |||||
- Broke Teensy 3 / 3.1 Support | |||||
### Not Working | |||||
- Teensy 3 / 3.1 Support is in Development |
## Contributors | |||||
These are the active contributors of this project that you may contact if there is anything you need help with or if you have suggestions. | |||||
- [z3t0](https://github.com/z3t0) : Active Contributor and currently also the main contributor. | |||||
* Email: zetoslab@gmail.com | |||||
- [shirriff](https://github.com/shirriff) : An amazing person who worked to create this awesome library and provide unending support | |||||
- [AnalysIR](https:/github.com/AnalysIR): Active contributor and is amazing with providing support! | |||||
- [Informatic](https://github.com/Informatic) : Active contributor | |||||
- [fmeschia](https://github.com/fmeschia) : Active contributor | |||||
- [PaulStoffregen](https://github.com/paulstroffregen) : Active contributor | |||||
- [crash7](https://github.com/crash7) : Active contributor | |||||
- [Neco777](https://github.com/neco777) : Active contributor | |||||
- [Lauszus](https://github.com/lauszus) : Active contributor | |||||
- [csBlueChip](https://github.com/csbluechip) : Active contributor, who contributed major and vital changes to the code base. | |||||
- [Sebazzz](https://github.com/sebazz): Contributor | |||||
- [lumbric](https://github.com/lumbric): Contributor | |||||
- [ElectricRCAircraftGuy](https://github.com/electricrcaircraftguy): Active Contributor | |||||
- [philipphenkel](https://github.com/philipphenkel): Active Contributor | |||||
- [MCUdude](https://github.com/MCUdude): Contributor | |||||
- [marcmerlin](https://github.com/marcmerlin): Contributor (ESP32 port) | |||||
Note: This list is being updated constantly so please let [z3t0](https://github.com/z3t0) know if you have been missed. |
/* | |||||
* IRremote: IRsendDemo - demonstrates sending IR codes with IRsend | |||||
* An IR LED must be connected to Arduino PWM pin 3. | |||||
* Version 0.1 July, 2009 | |||||
* Copyright 2009 Ken Shirriff | |||||
* http://arcfn.com | |||||
*/ | |||||
#include "IRremote.h" | |||||
#define POWER 0x7F80 | |||||
#define AIWA_RC_T501 | |||||
IRsend irsend; | |||||
void setup() { | |||||
Serial.begin(9600); | |||||
Serial.println("Arduino Ready"); | |||||
} | |||||
void loop() { | |||||
if (Serial.read() != -1) { | |||||
irsend.sendAiwaRCT501(POWER); | |||||
delay(60); // Optional | |||||
} | |||||
} |
/* | |||||
* IRrecord: record and play back IR signals as a minimal | |||||
* An IR detector/demodulator must be connected to the input RECV_PIN. | |||||
* An IR LED must be connected to the output PWM pin 3. | |||||
* A button must be connected to the input BUTTON_PIN; this is the | |||||
* send button. | |||||
* A visible LED can be connected to STATUS_PIN to provide status. | |||||
* | |||||
* The logic is: | |||||
* If the button is pressed, send the IR code. | |||||
* If an IR code is received, record it. | |||||
* | |||||
* Version 0.11 September, 2009 | |||||
* Copyright 2009 Ken Shirriff | |||||
* http://arcfn.com | |||||
*/ | |||||
#include <IRremote.h> | |||||
int RECV_PIN = 11; | |||||
int BUTTON_PIN = 12; | |||||
int STATUS_PIN = 13; | |||||
IRrecv irrecv(RECV_PIN); | |||||
IRsend irsend; | |||||
decode_results results; | |||||
void setup() | |||||
{ | |||||
Serial.begin(9600); | |||||
irrecv.enableIRIn(); // Start the receiver | |||||
pinMode(BUTTON_PIN, INPUT); | |||||
pinMode(STATUS_PIN, OUTPUT); | |||||
} | |||||
// Storage for the recorded code | |||||
int codeType = -1; // The type of code | |||||
unsigned long codeValue; // The code value if not raw | |||||
unsigned int rawCodes[RAWBUF]; // The durations if raw | |||||
int codeLen; // The length of the code | |||||
int toggle = 0; // The RC5/6 toggle state | |||||
// Stores the code for later playback | |||||
// Most of this code is just logging | |||||
void storeCode(decode_results *results) { | |||||
codeType = results->decode_type; | |||||
//int count = results->rawlen; | |||||
if (codeType == UNKNOWN) { | |||||
Serial.println("Received unknown code, saving as raw"); | |||||
codeLen = results->rawlen - 1; | |||||
// To store raw codes: | |||||
// Drop first value (gap) | |||||
// Convert from ticks to microseconds | |||||
// Tweak marks shorter, and spaces longer to cancel out IR receiver distortion | |||||
for (int i = 1; i <= codeLen; i++) { | |||||
if (i % 2) { | |||||
// Mark | |||||
rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS; | |||||
Serial.print(" m"); | |||||
} | |||||
else { | |||||
// Space | |||||
rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS; | |||||
Serial.print(" s"); | |||||
} | |||||
Serial.print(rawCodes[i - 1], DEC); | |||||
} | |||||
Serial.println(""); | |||||
} | |||||
else { | |||||
if (codeType == NEC) { | |||||
Serial.print("Received NEC: "); | |||||
if (results->value == REPEAT) { | |||||
// Don't record a NEC repeat value as that's useless. | |||||
Serial.println("repeat; ignoring."); | |||||
return; | |||||
} | |||||
} | |||||
else if (codeType == SONY) { | |||||
Serial.print("Received SONY: "); | |||||
} | |||||
else if (codeType == PANASONIC) { | |||||
Serial.print("Received PANASONIC: "); | |||||
} | |||||
else if (codeType == JVC) { | |||||
Serial.print("Received JVC: "); | |||||
} | |||||
else if (codeType == RC5) { | |||||
Serial.print("Received RC5: "); | |||||
} | |||||
else if (codeType == RC6) { | |||||
Serial.print("Received RC6: "); | |||||
} | |||||
else { | |||||
Serial.print("Unexpected codeType "); | |||||
Serial.print(codeType, DEC); | |||||
Serial.println(""); | |||||
} | |||||
Serial.println(results->value, HEX); | |||||
codeValue = results->value; | |||||
codeLen = results->bits; | |||||
} | |||||
} | |||||
void sendCode(int repeat) { | |||||
if (codeType == NEC) { | |||||
if (repeat) { | |||||
irsend.sendNEC(REPEAT, codeLen); | |||||
Serial.println("Sent NEC repeat"); | |||||
} | |||||
else { | |||||
irsend.sendNEC(codeValue, codeLen); | |||||
Serial.print("Sent NEC "); | |||||
Serial.println(codeValue, HEX); | |||||
} | |||||
} | |||||
else if (codeType == SONY) { | |||||
irsend.sendSony(codeValue, codeLen); | |||||
Serial.print("Sent Sony "); | |||||
Serial.println(codeValue, HEX); | |||||
} | |||||
else if (codeType == PANASONIC) { | |||||
irsend.sendPanasonic(codeValue, codeLen); | |||||
Serial.print("Sent Panasonic"); | |||||
Serial.println(codeValue, HEX); | |||||
} | |||||
else if (codeType == JVC) { | |||||
irsend.sendJVC(codeValue, codeLen, false); | |||||
Serial.print("Sent JVC"); | |||||
Serial.println(codeValue, HEX); | |||||
} | |||||
else if (codeType == RC5 || codeType == RC6) { | |||||
if (!repeat) { | |||||
// Flip the toggle bit for a new button press | |||||
toggle = 1 - toggle; | |||||
} | |||||
// Put the toggle bit into the code to send | |||||
codeValue = codeValue & ~(1 << (codeLen - 1)); | |||||
codeValue = codeValue | (toggle << (codeLen - 1)); | |||||
if (codeType == RC5) { | |||||
Serial.print("Sent RC5 "); | |||||
Serial.println(codeValue, HEX); | |||||
irsend.sendRC5(codeValue, codeLen); | |||||
} | |||||
else { | |||||
irsend.sendRC6(codeValue, codeLen); | |||||
Serial.print("Sent RC6 "); | |||||
Serial.println(codeValue, HEX); | |||||
} | |||||
} | |||||
else if (codeType == UNKNOWN /* i.e. raw */) { | |||||
// Assume 38 KHz | |||||
irsend.sendRaw(rawCodes, codeLen, 38); | |||||
Serial.println("Sent raw"); | |||||
} | |||||
} | |||||
int lastButtonState; | |||||
void loop() { | |||||
// If button pressed, send the code. | |||||
int buttonState = digitalRead(BUTTON_PIN); | |||||
if (lastButtonState == HIGH && buttonState == LOW) { | |||||
Serial.println("Released"); | |||||
irrecv.enableIRIn(); // Re-enable receiver | |||||
} | |||||
if (buttonState) { | |||||
Serial.println("Pressed, sending"); | |||||
digitalWrite(STATUS_PIN, HIGH); | |||||
sendCode(lastButtonState == buttonState); | |||||
digitalWrite(STATUS_PIN, LOW); | |||||
delay(50); // Wait a bit between retransmissions | |||||
} | |||||
else if (irrecv.decode(&results)) { | |||||
digitalWrite(STATUS_PIN, HIGH); | |||||
storeCode(&results); | |||||
irrecv.resume(); // resume receiver | |||||
digitalWrite(STATUS_PIN, LOW); | |||||
} | |||||
lastButtonState = buttonState; | |||||
} |
/* | |||||
* IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv | |||||
* An IR detector/demodulator must be connected to the input RECV_PIN. | |||||
* Version 0.1 July, 2009 | |||||
* Copyright 2009 Ken Shirriff | |||||
* http://arcfn.com | |||||
*/ | |||||
#include <IRremote.h> | |||||
int RECV_PIN = 11; | |||||
IRrecv irrecv(RECV_PIN); | |||||
decode_results results; | |||||
void setup() | |||||
{ | |||||
Serial.begin(9600); | |||||
// In case the interrupt driver crashes on setup, give a clue | |||||
// to the user what's going on. | |||||
Serial.println("Enabling IRin"); | |||||
irrecv.enableIRIn(); // Start the receiver | |||||
Serial.println("Enabled IRin"); | |||||
} | |||||
void loop() { | |||||
if (irrecv.decode(&results)) { | |||||
Serial.println(results.value, HEX); | |||||
irrecv.resume(); // Receive the next value | |||||
} | |||||
delay(100); | |||||
} |
/* | |||||
* IRremote: IRrecvDump - dump details of IR codes with IRrecv | |||||
* An IR detector/demodulator must be connected to the input RECV_PIN. | |||||
* 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) | |||||
*/ | |||||
#include <IRremote.h> | |||||
/* | |||||
* Default is Arduino pin D11. | |||||
* You can change this to another available Arduino Pin. | |||||
* Your IR receiver should be connected to the pin defined here | |||||
*/ | |||||
int RECV_PIN = 11; | |||||
IRrecv irrecv(RECV_PIN); | |||||
decode_results results; | |||||
void setup() | |||||
{ | |||||
Serial.begin(9600); | |||||
irrecv.enableIRIn(); // Start the receiver | |||||
} | |||||
void dump(decode_results *results) { | |||||
// Dumps out the decode_results structure. | |||||
// Call this after IRrecv::decode() | |||||
int 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 == RC6) { | |||||
Serial.print("Decoded RC6: "); | |||||
} | |||||
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: "); | |||||
} | |||||
Serial.print(results->value, HEX); | |||||
Serial.print(" ("); | |||||
Serial.print(results->bits, DEC); | |||||
Serial.println(" bits)"); | |||||
Serial.print("Raw ("); | |||||
Serial.print(count, DEC); | |||||
Serial.print("): "); | |||||
for (int i = 1; i < count; i++) { | |||||
if (i & 1) { | |||||
Serial.print(results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
else { | |||||
Serial.write('-'); | |||||
Serial.print((unsigned long) results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
Serial.print(" "); | |||||
} | |||||
Serial.println(); | |||||
} | |||||
void loop() { | |||||
if (irrecv.decode(&results)) { | |||||
Serial.println(results.value, HEX); | |||||
dump(&results); | |||||
irrecv.resume(); // Receive the next value | |||||
} | |||||
} |
//------------------------------------------------------------------------------ | |||||
// Include the IRremote library header | |||||
// | |||||
#include <IRremote.h> | |||||
//------------------------------------------------------------------------------ | |||||
// Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838) | |||||
// | |||||
int recvPin = 11; | |||||
IRrecv irrecv(recvPin); | |||||
//+============================================================================= | |||||
// Configure the Arduino | |||||
// | |||||
void setup ( ) | |||||
{ | |||||
Serial.begin(9600); // Status message will be sent to PC at 9600 baud | |||||
irrecv.enableIRIn(); // Start the receiver | |||||
} | |||||
//+============================================================================= | |||||
// Display IR code | |||||
// | |||||
void ircode (decode_results *results) | |||||
{ | |||||
// Panasonic has an Address | |||||
if (results->decode_type == PANASONIC) { | |||||
Serial.print(results->address, HEX); | |||||
Serial.print(":"); | |||||
} | |||||
// Print Code | |||||
Serial.print(results->value, HEX); | |||||
} | |||||
//+============================================================================= | |||||
// 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 SONY: Serial.print("SONY"); break ; | |||||
case RC5: Serial.print("RC5"); break ; | |||||
case RC6: Serial.print("RC6"); 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 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 ; | |||||
} | |||||
} | |||||
//+============================================================================= | |||||
// Dump out the decode_results structure. | |||||
// | |||||
void dumpInfo (decode_results *results) | |||||
{ | |||||
// Check if the buffer overflowed | |||||
if (results->overflow) { | |||||
Serial.println("IR code too long. Edit IRremoteInt.h and increase RAWBUF"); | |||||
return; | |||||
} | |||||
// Show Encoding standard | |||||
Serial.print("Encoding : "); | |||||
encoding(results); | |||||
Serial.println(""); | |||||
// Show Code & length | |||||
Serial.print("Code : "); | |||||
ircode(results); | |||||
Serial.print(" ("); | |||||
Serial.print(results->bits, DEC); | |||||
Serial.println(" bits)"); | |||||
} | |||||
//+============================================================================= | |||||
// 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 (int i = 1; i < results->rawlen; i++) { | |||||
unsigned long x = results->rawbuf[i] * USECPERTICK; | |||||
if (!(i & 1)) { // even | |||||
Serial.print("-"); | |||||
if (x < 1000) Serial.print(" ") ; | |||||
if (x < 100) Serial.print(" ") ; | |||||
Serial.print(x, DEC); | |||||
} else { // odd | |||||
Serial.print(" "); | |||||
Serial.print("+"); | |||||
if (x < 1000) Serial.print(" ") ; | |||||
if (x < 100) Serial.print(" ") ; | |||||
Serial.print(x, DEC); | |||||
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("unsigned int "); // variable type | |||||
Serial.print("rawData["); // array name | |||||
Serial.print(results->rawlen - 1, DEC); // array size | |||||
Serial.print("] = {"); // Start declaration | |||||
// Dump data | |||||
for (int i = 1; i < results->rawlen; i++) { | |||||
Serial.print(results->rawbuf[i] * USECPERTICK, DEC); | |||||
if ( i < results->rawlen-1 ) Serial.print(","); // ',' not needed on last one | |||||
if (!(i & 1)) Serial.print(" "); | |||||
} | |||||
// End declaration | |||||
Serial.print("};"); // | |||||
// Comment | |||||
Serial.print(" // "); | |||||
encoding(results); | |||||
Serial.print(" "); | |||||
ircode(results); | |||||
// Newline | |||||
Serial.println(""); | |||||
// Now dump "known" codes | |||||
if (results->decode_type != UNKNOWN) { | |||||
// Some protocols have an address | |||||
if (results->decode_type == PANASONIC) { | |||||
Serial.print("unsigned int addr = 0x"); | |||||
Serial.print(results->address, HEX); | |||||
Serial.println(";"); | |||||
} | |||||
// All protocols have data | |||||
Serial.print("unsigned int data = 0x"); | |||||
Serial.print(results->value, HEX); | |||||
Serial.println(";"); | |||||
} | |||||
} | |||||
//+============================================================================= | |||||
// The repeating section of the code | |||||
// | |||||
void loop ( ) | |||||
{ | |||||
decode_results results; // Somewhere to store the results | |||||
if (irrecv.decode(&results)) { // Grab an IR code | |||||
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 | |||||
irrecv.resume(); // Prepare for the next value | |||||
} | |||||
} |
/* | |||||
* IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv | |||||
* An IR detector/demodulator must be connected to the input RECV_PIN. | |||||
* Version 0.1 July, 2009 | |||||
* Copyright 2009 Ken Shirriff | |||||
* http://arcfn.com | |||||
*/ | |||||
#include <IRremote.h> | |||||
int RECV_PIN = 11; | |||||
int RELAY_PIN = 4; | |||||
IRrecv irrecv(RECV_PIN); | |||||
decode_results results; | |||||
// Dumps out the decode_results structure. | |||||
// Call this after IRrecv::decode() | |||||
// void * to work around compiler issue | |||||
//void dump(void *v) { | |||||
// decode_results *results = (decode_results *)v | |||||
void dump(decode_results *results) { | |||||
int count = results->rawlen; | |||||
if (results->decode_type == UNKNOWN) { | |||||
Serial.println("Could not decode message"); | |||||
} | |||||
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 == RC6) { | |||||
Serial.print("Decoded RC6: "); | |||||
} | |||||
Serial.print(results->value, HEX); | |||||
Serial.print(" ("); | |||||
Serial.print(results->bits, DEC); | |||||
Serial.println(" bits)"); | |||||
} | |||||
Serial.print("Raw ("); | |||||
Serial.print(count, DEC); | |||||
Serial.print("): "); | |||||
for (int i = 0; i < count; i++) { | |||||
if ((i % 2) == 1) { | |||||
Serial.print(results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
else { | |||||
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
Serial.print(" "); | |||||
} | |||||
Serial.println(""); | |||||
} | |||||
void setup() | |||||
{ | |||||
pinMode(RELAY_PIN, OUTPUT); | |||||
pinMode(13, OUTPUT); | |||||
Serial.begin(9600); | |||||
irrecv.enableIRIn(); // Start the receiver | |||||
} | |||||
int on = 0; | |||||
unsigned long last = millis(); | |||||
void loop() { | |||||
if (irrecv.decode(&results)) { | |||||
// If it's been at least 1/4 second since the last | |||||
// IR received, toggle the relay | |||||
if (millis() - last > 250) { | |||||
on = !on; | |||||
digitalWrite(RELAY_PIN, on ? HIGH : LOW); | |||||
digitalWrite(13, on ? HIGH : LOW); | |||||
dump(&results); | |||||
} | |||||
last = millis(); | |||||
irrecv.resume(); // Receive the next value | |||||
} | |||||
} |
/* | |||||
* IRremote: IRremoteInfo - prints relevant config info & settings for IRremote over serial | |||||
* Intended to help identify & troubleshoot the various settings of IRremote | |||||
* For example, sometimes users are unsure of which pin is used for Tx or the RAWBUF values | |||||
* This example can be used to assist the user directly or with support. | |||||
* Intended to help identify & troubleshoot the various settings of IRremote | |||||
* Hopefully this utility will be a useful tool for support & troubleshooting for IRremote | |||||
* Check out the blog post describing the sketch via http://www.analysir.com/blog/2015/11/28/helper-utility-for-troubleshooting-irremote/ | |||||
* Version 1.0 November 2015 | |||||
* Original Author: AnalysIR - IR software & modules for Makers & Pros, visit http://www.AnalysIR.com | |||||
*/ | |||||
#include <IRremote.h> | |||||
void setup() | |||||
{ | |||||
Serial.begin(115200); //You may alter the BAUD rate here as needed | |||||
while (!Serial); //wait until Serial is established - required on some Platforms | |||||
//Runs only once per restart of the Arduino. | |||||
dumpHeader(); | |||||
dumpRAWBUF(); | |||||
dumpTIMER(); | |||||
dumpTimerPin(); | |||||
dumpClock(); | |||||
dumpPlatform(); | |||||
dumpPulseParams(); | |||||
dumpSignalParams(); | |||||
dumpArduinoIDE(); | |||||
dumpDebugMode(); | |||||
dumpProtocols(); | |||||
dumpFooter(); | |||||
} | |||||
void loop() { | |||||
//nothing to do! | |||||
} | |||||
void dumpRAWBUF() { | |||||
Serial.print(F("RAWBUF: ")); | |||||
Serial.println(RAWBUF); | |||||
} | |||||
void dumpTIMER() { | |||||
boolean flag = false; | |||||
#ifdef IR_USE_TIMER1 | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer1")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER2 | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer2")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER3 | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer3")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER4 | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer4")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER5 | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer5")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER4_HS | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer4_HS")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER_CMT | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer_CMT")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER_TPM1 | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer_TPM1")); flag = true; | |||||
#endif | |||||
#ifdef IR_USE_TIMER_TINY0 | |||||
Serial.print(F("Timer defined for use: ")); Serial.println(F("Timer_TINY0")); flag = true; | |||||
#endif | |||||
if (!flag) { | |||||
Serial.print(F("Timer Error: ")); Serial.println(F("not defined")); | |||||
} | |||||
} | |||||
void dumpTimerPin() { | |||||
Serial.print(F("IR Tx Pin: ")); | |||||
Serial.println(TIMER_PWM_PIN); | |||||
} | |||||
void dumpClock() { | |||||
Serial.print(F("MCU Clock: ")); | |||||
Serial.println(F_CPU); | |||||
} | |||||
void dumpPlatform() { | |||||
Serial.print(F("MCU Platform: ")); | |||||
#if defined(__AVR_ATmega1280__) | |||||
Serial.println(F("Arduino Mega1280")); | |||||
#elif defined(__AVR_ATmega2560__) | |||||
Serial.println(F("Arduino Mega2560")); | |||||
#elif defined(__AVR_AT90USB162__) | |||||
Serial.println(F("Teensy 1.0 / AT90USB162")); | |||||
// Teensy 2.0 | |||||
#elif defined(__AVR_ATmega32U4__) | |||||
Serial.println(F("Arduino Leonardo / Yun / Teensy 1.0 / ATmega32U4")); | |||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) | |||||
Serial.println(F("Teensy 3.0 / Teensy 3.1 / MK20DX128 / MK20DX256")); | |||||
#elif defined(__MKL26Z64__) | |||||
Serial.println(F("Teensy-LC / MKL26Z64")); | |||||
#elif defined(__AVR_AT90USB646__) | |||||
Serial.println(F("Teensy++ 1.0 / AT90USB646")); | |||||
#elif defined(__AVR_AT90USB1286__) | |||||
Serial.println(F("Teensy++ 2.0 / AT90USB1286")); | |||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) | |||||
Serial.println(F("ATmega1284")); | |||||
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) | |||||
Serial.println(F("ATmega644")); | |||||
#elif defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) || defined(__AVR_ATmega324PA__) | |||||
Serial.println(F("ATmega324")); | |||||
#elif defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164P__) | |||||
Serial.println(F("ATmega164")); | |||||
#elif defined(__AVR_ATmega128__) | |||||
Serial.println(F("ATmega128")); | |||||
#elif defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) | |||||
Serial.println(F("ATmega88")); | |||||
#elif defined(__AVR_ATmega64__) | |||||
Serial.println(F("ATmega64")); | |||||
#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega48P__) | |||||
Serial.println(F("ATmega48")); | |||||
#elif defined(__AVR_ATmega32__) | |||||
Serial.println(F("ATmega32")); | |||||
#elif defined(__AVR_ATmega16__) | |||||
Serial.println(F("ATmega16")); | |||||
#elif defined(__AVR_ATmega8535__) | |||||
Serial.println(F("ATmega8535")); | |||||
#elif defined(__AVR_ATmega8__) | |||||
Serial.println(F("Atmega8")); | |||||
#elif defined(__AVR_ATtiny84__) | |||||
Serial.println(F("ATtiny84")); | |||||
#elif defined(__AVR_ATtiny85__) | |||||
Serial.println(F("ATtiny85")); | |||||
#else | |||||
Serial.println(F("ATmega328(P) / (Duemilanove, Diecimila, LilyPad, Mini, Micro, Fio, Nano, etc)")); | |||||
#endif | |||||
} | |||||
void dumpPulseParams() { | |||||
Serial.print(F("Mark Excess: ")); Serial.print(MARK_EXCESS);; Serial.println(F(" uSecs")); | |||||
Serial.print(F("Microseconds per tick: ")); Serial.print(USECPERTICK);; Serial.println(F(" uSecs")); | |||||
Serial.print(F("Measurement tolerance: ")); Serial.print(TOLERANCE); Serial.println(F("%")); | |||||
} | |||||
void dumpSignalParams() { | |||||
Serial.print(F("Minimum Gap between IR Signals: ")); Serial.print(_GAP); Serial.println(F(" uSecs")); | |||||
} | |||||
void dumpDebugMode() { | |||||
Serial.print(F("Debug Mode: ")); | |||||
#if DEBUG | |||||
Serial.println(F("ON")); | |||||
#else | |||||
Serial.println(F("OFF (Normal)")); | |||||
#endif | |||||
} | |||||
void dumpArduinoIDE() { | |||||
Serial.print(F("Arduino IDE version: ")); | |||||
Serial.print(ARDUINO / 10000); | |||||
Serial.write('.'); | |||||
Serial.print((ARDUINO % 10000) / 100); | |||||
Serial.write('.'); | |||||
Serial.println(ARDUINO % 100); | |||||
} | |||||
void dumpProtocols() { | |||||
Serial.println(); Serial.print(F("IR PROTOCOLS ")); Serial.print(F("SEND ")); Serial.println(F("DECODE")); | |||||
Serial.print(F("============= ")); Serial.print(F("======== ")); Serial.println(F("========")); | |||||
Serial.print(F("RC5: ")); printSendEnabled(SEND_RC5); printDecodeEnabled(DECODE_RC6); | |||||
Serial.print(F("RC6: ")); printSendEnabled(SEND_RC6); printDecodeEnabled(DECODE_RC5); | |||||
Serial.print(F("NEC: ")); printSendEnabled(SEND_NEC); printDecodeEnabled(DECODE_NEC); | |||||
Serial.print(F("SONY: ")); printSendEnabled(SEND_SONY); printDecodeEnabled(DECODE_SONY); | |||||
Serial.print(F("PANASONIC: ")); printSendEnabled(SEND_PANASONIC); printDecodeEnabled(DECODE_PANASONIC); | |||||
Serial.print(F("JVC: ")); printSendEnabled(SEND_JVC); printDecodeEnabled(DECODE_JVC); | |||||
Serial.print(F("SAMSUNG: ")); printSendEnabled(SEND_SAMSUNG); printDecodeEnabled(DECODE_SAMSUNG); | |||||
Serial.print(F("WHYNTER: ")); printSendEnabled(SEND_WHYNTER); printDecodeEnabled(DECODE_WHYNTER); | |||||
Serial.print(F("AIWA_RC_T501: ")); printSendEnabled(SEND_AIWA_RC_T501); printDecodeEnabled(DECODE_AIWA_RC_T501); | |||||
Serial.print(F("LG: ")); printSendEnabled(SEND_LG); printDecodeEnabled(DECODE_LG); | |||||
Serial.print(F("SANYO: ")); printSendEnabled(SEND_SANYO); printDecodeEnabled(DECODE_SANYO); | |||||
Serial.print(F("MITSUBISHI: ")); printSendEnabled(SEND_MITSUBISHI); printDecodeEnabled(DECODE_MITSUBISHI); | |||||
Serial.print(F("DISH: ")); printSendEnabled(SEND_DISH); printDecodeEnabled(DECODE_DISH); | |||||
Serial.print(F("SHARP: ")); printSendEnabled(SEND_SHARP); printDecodeEnabled(DECODE_SHARP); | |||||
Serial.print(F("DENON: ")); printSendEnabled(SEND_DENON); printDecodeEnabled(DECODE_DENON); | |||||
Serial.print(F("PRONTO: ")); printSendEnabled(SEND_PRONTO); Serial.println(F("(Not Applicable)")); | |||||
} | |||||
void printSendEnabled(int flag) { | |||||
if (flag) { | |||||
Serial.print(F("Enabled ")); | |||||
} | |||||
else { | |||||
Serial.print(F("Disabled ")); | |||||
} | |||||
} | |||||
void printDecodeEnabled(int flag) { | |||||
if (flag) { | |||||
Serial.println(F("Enabled")); | |||||
} | |||||
else { | |||||
Serial.println(F("Disabled")); | |||||
} | |||||
} | |||||
void dumpHeader() { | |||||
Serial.println(F("IRremoteInfo - by AnalysIR (http://www.AnalysIR.com/)")); | |||||
Serial.println(F(" - A helper sketch to assist in troubleshooting issues with the library by reviewing the settings within the IRremote library")); | |||||
Serial.println(F(" - Prints out the important settings within the library, which can be configured to suit the many supported platforms")); | |||||
Serial.println(F(" - When seeking on-line support, please post or upload the output of this sketch, where appropriate")); | |||||
Serial.println(); | |||||
Serial.println(F("IRremote Library Settings")); | |||||
Serial.println(F("=========================")); | |||||
} | |||||
void dumpFooter() { | |||||
Serial.println(); | |||||
Serial.println(F("Notes: ")); | |||||
Serial.println(F(" - Most of the seetings above can be configured in the following files included as part of the library")); | |||||
Serial.println(F(" - IRremteInt.h")); | |||||
Serial.println(F(" - IRremote.h")); | |||||
Serial.println(F(" - You can save SRAM by disabling the Decode or Send features for any protocol (Near the top of IRremoteInt.h)")); | |||||
Serial.println(F(" - Some Timer conflicts, with other libraries, can be easily resolved by configuring a differnt Timer for your platform")); | |||||
} |
/* | |||||
* IRremote: IRsendDemo - demonstrates sending IR codes with IRsend | |||||
* An IR LED must be connected to Arduino PWM pin 3. | |||||
* Version 0.1 July, 2009 | |||||
* Copyright 2009 Ken Shirriff | |||||
* http://arcfn.com | |||||
*/ | |||||
#include <IRremote.h> | |||||
IRsend irsend; | |||||
void setup() | |||||
{ | |||||
} | |||||
void loop() { | |||||
for (int i = 0; i < 3; i++) { | |||||
irsend.sendSony(0xa90, 12); | |||||
delay(40); | |||||
} | |||||
delay(5000); //5 second delay between each signal burst | |||||
} |
/* | |||||
* IRremote: IRsendRawDemo - demonstrates sending IR codes with sendRaw | |||||
* An IR LED must be connected to Arduino PWM pin 3. | |||||
* Version 0.1 July, 2009 | |||||
* Copyright 2009 Ken Shirriff | |||||
* http://arcfn.com | |||||
* | |||||
* IRsendRawDemo - added by AnalysIR (via www.AnalysIR.com), 24 August 2015 | |||||
* | |||||
* This example shows how to send a RAW signal using the IRremote library. | |||||
* The example signal is actually a 32 bit NEC signal. | |||||
* Remote Control button: LGTV Power On/Off. | |||||
* Hex Value: 0x20DF10EF, 32 bits | |||||
* | |||||
* It is more efficient to use the sendNEC function to send NEC signals. | |||||
* Use of sendRaw here, serves only as an example of using the function. | |||||
* | |||||
*/ | |||||
#include <IRremote.h> | |||||
IRsend irsend; | |||||
void setup() | |||||
{ | |||||
} | |||||
void loop() { | |||||
int khz = 38; // 38kHz carrier frequency for the NEC protocol | |||||
unsigned int irSignal[] = {9000, 4500, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 560, 560, 560, 560, 560, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 560, 560, 1690, 560, 1690, 560, 1690, 560, 1690, 560, 39416, 9000, 2210, 560}; //AnalysIR Batch Export (IRremote) - RAW | |||||
irsend.sendRaw(irSignal, sizeof(irSignal) / sizeof(irSignal[0]), khz); //Note the approach used to automatically calculate the size of the array. | |||||
delay(5000); //In this example, the signal will be repeated every 5 seconds, approximately. | |||||
} |
/* | |||||
* IRremote: IRtest unittest | |||||
* Version 0.1 July, 2009 | |||||
* Copyright 2009 Ken Shirriff | |||||
* http://arcfn.com | |||||
* | |||||
* Note: to run these tests, edit IRremote/IRremote.h to add "#define TEST" | |||||
* You must then recompile the library by removing IRremote.o and restarting | |||||
* the arduino IDE. | |||||
*/ | |||||
#include <IRremote.h> | |||||
#include <IRremoteInt.h> | |||||
// Dumps out the decode_results structure. | |||||
// Call this after IRrecv::decode() | |||||
// void * to work around compiler issue | |||||
//void dump(void *v) { | |||||
// decode_results *results = (decode_results *)v | |||||
void dump(decode_results *results) { | |||||
int count = results->rawlen; | |||||
if (results->decode_type == UNKNOWN) { | |||||
Serial.println("Could not decode message"); | |||||
} | |||||
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 == RC6) { | |||||
Serial.print("Decoded RC6: "); | |||||
} | |||||
Serial.print(results->value, HEX); | |||||
Serial.print(" ("); | |||||
Serial.print(results->bits, DEC); | |||||
Serial.println(" bits)"); | |||||
} | |||||
Serial.print("Raw ("); | |||||
Serial.print(count, DEC); | |||||
Serial.print("): "); | |||||
for (int i = 0; i < count; i++) { | |||||
if ((i % 2) == 1) { | |||||
Serial.print(results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
else { | |||||
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
Serial.print(" "); | |||||
} | |||||
Serial.println(""); | |||||
} | |||||
IRrecv irrecv(0); | |||||
decode_results results; | |||||
class IRsendDummy : | |||||
public IRsend | |||||
{ | |||||
public: | |||||
// For testing, just log the marks/spaces | |||||
#define SENDLOG_LEN 128 | |||||
int sendlog[SENDLOG_LEN]; | |||||
int sendlogcnt; | |||||
IRsendDummy() : | |||||
IRsend() { | |||||
} | |||||
void reset() { | |||||
sendlogcnt = 0; | |||||
} | |||||
void mark(int time) { | |||||
sendlog[sendlogcnt] = time; | |||||
if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; | |||||
} | |||||
void space(int time) { | |||||
sendlog[sendlogcnt] = -time; | |||||
if (sendlogcnt < SENDLOG_LEN) sendlogcnt++; | |||||
} | |||||
// Copies the dummy buf into the interrupt buf | |||||
void useDummyBuf() { | |||||
int last = SPACE; | |||||
irparams.rcvstate = STATE_STOP; | |||||
irparams.rawlen = 1; // Skip the gap | |||||
for (int i = 0 ; i < sendlogcnt; i++) { | |||||
if (sendlog[i] < 0) { | |||||
if (last == MARK) { | |||||
// New space | |||||
irparams.rawbuf[irparams.rawlen++] = (-sendlog[i] - MARK_EXCESS) / USECPERTICK; | |||||
last = SPACE; | |||||
} | |||||
else { | |||||
// More space | |||||
irparams.rawbuf[irparams.rawlen - 1] += -sendlog[i] / USECPERTICK; | |||||
} | |||||
} | |||||
else if (sendlog[i] > 0) { | |||||
if (last == SPACE) { | |||||
// New mark | |||||
irparams.rawbuf[irparams.rawlen++] = (sendlog[i] + MARK_EXCESS) / USECPERTICK; | |||||
last = MARK; | |||||
} | |||||
else { | |||||
// More mark | |||||
irparams.rawbuf[irparams.rawlen - 1] += sendlog[i] / USECPERTICK; | |||||
} | |||||
} | |||||
} | |||||
if (irparams.rawlen % 2) { | |||||
irparams.rawlen--; // Remove trailing space | |||||
} | |||||
} | |||||
}; | |||||
IRsendDummy irsenddummy; | |||||
void verify(unsigned long val, int bits, int type) { | |||||
irsenddummy.useDummyBuf(); | |||||
irrecv.decode(&results); | |||||
Serial.print("Testing "); | |||||
Serial.print(val, HEX); | |||||
if (results.value == val && results.bits == bits && results.decode_type == type) { | |||||
Serial.println(": OK"); | |||||
} | |||||
else { | |||||
Serial.println(": Error"); | |||||
dump(&results); | |||||
} | |||||
} | |||||
void testNEC(unsigned long val, int bits) { | |||||
irsenddummy.reset(); | |||||
irsenddummy.sendNEC(val, bits); | |||||
verify(val, bits, NEC); | |||||
} | |||||
void testSony(unsigned long val, int bits) { | |||||
irsenddummy.reset(); | |||||
irsenddummy.sendSony(val, bits); | |||||
verify(val, bits, SONY); | |||||
} | |||||
void testRC5(unsigned long val, int bits) { | |||||
irsenddummy.reset(); | |||||
irsenddummy.sendRC5(val, bits); | |||||
verify(val, bits, RC5); | |||||
} | |||||
void testRC6(unsigned long val, int bits) { | |||||
irsenddummy.reset(); | |||||
irsenddummy.sendRC6(val, bits); | |||||
verify(val, bits, RC6); | |||||
} | |||||
void test() { | |||||
Serial.println("NEC tests"); | |||||
testNEC(0x00000000, 32); | |||||
testNEC(0xffffffff, 32); | |||||
testNEC(0xaaaaaaaa, 32); | |||||
testNEC(0x55555555, 32); | |||||
testNEC(0x12345678, 32); | |||||
Serial.println("Sony tests"); | |||||
testSony(0xfff, 12); | |||||
testSony(0x000, 12); | |||||
testSony(0xaaa, 12); | |||||
testSony(0x555, 12); | |||||
testSony(0x123, 12); | |||||
Serial.println("RC5 tests"); | |||||
testRC5(0xfff, 12); | |||||
testRC5(0x000, 12); | |||||
testRC5(0xaaa, 12); | |||||
testRC5(0x555, 12); | |||||
testRC5(0x123, 12); | |||||
Serial.println("RC6 tests"); | |||||
testRC6(0xfffff, 20); | |||||
testRC6(0x00000, 20); | |||||
testRC6(0xaaaaa, 20); | |||||
testRC6(0x55555, 20); | |||||
testRC6(0x12345, 20); | |||||
} | |||||
void setup() | |||||
{ | |||||
Serial.begin(9600); | |||||
test(); | |||||
} | |||||
void loop() { | |||||
} |
/* | |||||
* Test send/receive functions of IRremote, using a pair of Arduinos. | |||||
* | |||||
* Arduino #1 should have an IR LED connected to the send pin (3). | |||||
* Arduino #2 should have an IR detector/demodulator connected to the | |||||
* receive pin (11) and a visible LED connected to pin 3. | |||||
* | |||||
* The cycle: | |||||
* Arduino #1 will wait 2 seconds, then run through the tests. | |||||
* It repeats this forever. | |||||
* Arduino #2 will wait for at least one second of no signal | |||||
* (to synchronize with #1). It will then wait for the same test | |||||
* signals. It will log all the status to the serial port. It will | |||||
* also indicate status through the LED, which will flash each time a test | |||||
* is completed. If there is an error, it will light up for 5 seconds. | |||||
* | |||||
* The test passes if the LED flashes 19 times, pauses, and then repeats. | |||||
* The test fails if the LED lights for 5 seconds. | |||||
* | |||||
* The test software automatically decides which board is the sender and which is | |||||
* the receiver by looking for an input on the send pin, which will indicate | |||||
* the sender. You should hook the serial port to the receiver for debugging. | |||||
* | |||||
* Copyright 2010 Ken Shirriff | |||||
* http://arcfn.com | |||||
*/ | |||||
#include <IRremote.h> | |||||
int RECV_PIN = 11; | |||||
int LED_PIN = 3; | |||||
IRrecv irrecv(RECV_PIN); | |||||
IRsend irsend; | |||||
decode_results results; | |||||
#define RECEIVER 1 | |||||
#define SENDER 2 | |||||
#define ERROR 3 | |||||
int mode; | |||||
void setup() | |||||
{ | |||||
Serial.begin(9600); | |||||
// Check RECV_PIN to decide if we're RECEIVER or SENDER | |||||
if (digitalRead(RECV_PIN) == HIGH) { | |||||
mode = RECEIVER; | |||||
irrecv.enableIRIn(); | |||||
pinMode(LED_PIN, OUTPUT); | |||||
digitalWrite(LED_PIN, LOW); | |||||
Serial.println("Receiver mode"); | |||||
} | |||||
else { | |||||
mode = SENDER; | |||||
Serial.println("Sender mode"); | |||||
} | |||||
} | |||||
// Wait for the gap between tests, to synchronize with | |||||
// the sender. | |||||
// Specifically, wait for a signal followed by a gap of at last gap ms. | |||||
void waitForGap(unsigned long gap) { | |||||
Serial.println("Waiting for gap"); | |||||
while (1) { | |||||
while (digitalRead(RECV_PIN) == LOW) { | |||||
} | |||||
unsigned long time = millis(); | |||||
while (digitalRead(RECV_PIN) == HIGH) { | |||||
if (millis() - time > gap) { | |||||
return; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// Dumps out the decode_results structure. | |||||
// Call this after IRrecv::decode() | |||||
void dump(decode_results *results) { | |||||
int count = results->rawlen; | |||||
if (results->decode_type == UNKNOWN) { | |||||
Serial.println("Could not decode message"); | |||||
} | |||||
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 == RC6) { | |||||
Serial.print("Decoded RC6: "); | |||||
} | |||||
Serial.print(results->value, HEX); | |||||
Serial.print(" ("); | |||||
Serial.print(results->bits, DEC); | |||||
Serial.println(" bits)"); | |||||
} | |||||
Serial.print("Raw ("); | |||||
Serial.print(count, DEC); | |||||
Serial.print("): "); | |||||
for (int i = 0; i < count; i++) { | |||||
if ((i % 2) == 1) { | |||||
Serial.print(results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
else { | |||||
Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC); | |||||
} | |||||
Serial.print(" "); | |||||
} | |||||
Serial.println(""); | |||||
} | |||||
// Test send or receive. | |||||
// If mode is SENDER, send a code of the specified type, value, and bits | |||||
// If mode is RECEIVER, receive a code and verify that it is of the | |||||
// specified type, value, and bits. For success, the LED is flashed; | |||||
// for failure, the mode is set to ERROR. | |||||
// The motivation behind this method is that the sender and the receiver | |||||
// can do the same test calls, and the mode variable indicates whether | |||||
// to send or receive. | |||||
void test(const char *label, int type, unsigned long value, int bits) { | |||||
if (mode == SENDER) { | |||||
Serial.println(label); | |||||
if (type == NEC) { | |||||
irsend.sendNEC(value, bits); | |||||
} | |||||
else if (type == SONY) { | |||||
irsend.sendSony(value, bits); | |||||
} | |||||
else if (type == RC5) { | |||||
irsend.sendRC5(value, bits); | |||||
} | |||||
else if (type == RC6) { | |||||
irsend.sendRC6(value, bits); | |||||
} | |||||
else { | |||||
Serial.print(label); | |||||
Serial.println("Bad type!"); | |||||
} | |||||
delay(200); | |||||
} | |||||
else if (mode == RECEIVER) { | |||||
irrecv.resume(); // Receive the next value | |||||
unsigned long max_time = millis() + 30000; | |||||
Serial.print(label); | |||||
// Wait for decode or timeout | |||||
while (!irrecv.decode(&results)) { | |||||
if (millis() > max_time) { | |||||
Serial.println("Timeout receiving data"); | |||||
mode = ERROR; | |||||
return; | |||||
} | |||||
} | |||||
if (type == results.decode_type && value == results.value && bits == results.bits) { | |||||
Serial.println (": OK"); | |||||
digitalWrite(LED_PIN, HIGH); | |||||
delay(20); | |||||
digitalWrite(LED_PIN, LOW); | |||||
} | |||||
else { | |||||
Serial.println(": BAD"); | |||||
dump(&results); | |||||
mode = ERROR; | |||||
} | |||||
} | |||||
} | |||||
// Test raw send or receive. This is similar to the test method, | |||||
// except it send/receives raw data. | |||||
void testRaw(const char *label, unsigned int *rawbuf, int rawlen) { | |||||
if (mode == SENDER) { | |||||
Serial.println(label); | |||||
irsend.sendRaw(rawbuf, rawlen, 38 /* kHz */); | |||||
delay(200); | |||||
} | |||||
else if (mode == RECEIVER ) { | |||||
irrecv.resume(); // Receive the next value | |||||
unsigned long max_time = millis() + 30000; | |||||
Serial.print(label); | |||||
// Wait for decode or timeout | |||||
while (!irrecv.decode(&results)) { | |||||
if (millis() > max_time) { | |||||
Serial.println("Timeout receiving data"); | |||||
mode = ERROR; | |||||
return; | |||||
} | |||||
} | |||||
// Received length has extra first element for gap | |||||
if (rawlen != results.rawlen - 1) { | |||||
Serial.print("Bad raw length "); | |||||
Serial.println(results.rawlen, DEC); | |||||
mode = ERROR; | |||||
return; | |||||
} | |||||
for (int i = 0; i < rawlen; i++) { | |||||
long got = results.rawbuf[i+1] * USECPERTICK; | |||||
// Adjust for extra duration of marks | |||||
if (i % 2 == 0) { | |||||
got -= MARK_EXCESS; | |||||
} | |||||
else { | |||||
got += MARK_EXCESS; | |||||
} | |||||
// See if close enough, within 25% | |||||
if (rawbuf[i] * 1.25 < got || got * 1.25 < rawbuf[i]) { | |||||
Serial.println(": BAD"); | |||||
dump(&results); | |||||
mode = ERROR; | |||||
return; | |||||
} | |||||
} | |||||
Serial.println (": OK"); | |||||
digitalWrite(LED_PIN, HIGH); | |||||
delay(20); | |||||
digitalWrite(LED_PIN, LOW); | |||||
} | |||||
} | |||||
// This is the raw data corresponding to NEC 0x12345678 | |||||
unsigned int sendbuf[] = { /* NEC format */ | |||||
9000, 4500, | |||||
560, 560, 560, 560, 560, 560, 560, 1690, /* 1 */ | |||||
560, 560, 560, 560, 560, 1690, 560, 560, /* 2 */ | |||||
560, 560, 560, 560, 560, 1690, 560, 1690, /* 3 */ | |||||
560, 560, 560, 1690, 560, 560, 560, 560, /* 4 */ | |||||
560, 560, 560, 1690, 560, 560, 560, 1690, /* 5 */ | |||||
560, 560, 560, 1690, 560, 1690, 560, 560, /* 6 */ | |||||
560, 560, 560, 1690, 560, 1690, 560, 1690, /* 7 */ | |||||
560, 1690, 560, 560, 560, 560, 560, 560, /* 8 */ | |||||
560}; | |||||
void loop() { | |||||
if (mode == SENDER) { | |||||
delay(2000); // Delay for more than gap to give receiver a better chance to sync. | |||||
} | |||||
else if (mode == RECEIVER) { | |||||
waitForGap(1000); | |||||
} | |||||
else if (mode == ERROR) { | |||||
// Light up for 5 seconds for error | |||||
digitalWrite(LED_PIN, HIGH); | |||||
delay(5000); | |||||
digitalWrite(LED_PIN, LOW); | |||||
mode = RECEIVER; // Try again | |||||
return; | |||||
} | |||||
// The test suite. | |||||
test("SONY1", SONY, 0x123, 12); | |||||
test("SONY2", SONY, 0x000, 12); | |||||
test("SONY3", SONY, 0xfff, 12); | |||||
test("SONY4", SONY, 0x12345, 20); | |||||
test("SONY5", SONY, 0x00000, 20); | |||||
test("SONY6", SONY, 0xfffff, 20); | |||||
test("NEC1", NEC, 0x12345678, 32); | |||||
test("NEC2", NEC, 0x00000000, 32); | |||||
test("NEC3", NEC, 0xffffffff, 32); | |||||
test("NEC4", NEC, REPEAT, 32); | |||||
test("RC51", RC5, 0x12345678, 32); | |||||
test("RC52", RC5, 0x0, 32); | |||||
test("RC53", RC5, 0xffffffff, 32); | |||||
test("RC61", RC6, 0x12345678, 32); | |||||
test("RC62", RC6, 0x0, 32); | |||||
test("RC63", RC6, 0xffffffff, 32); | |||||
// Tests of raw sending and receiving. | |||||
// First test sending raw and receiving raw. | |||||
// Then test sending raw and receiving decoded NEC | |||||
// Then test sending NEC and receiving raw | |||||
testRaw("RAW1", sendbuf, 67); | |||||
if (mode == SENDER) { | |||||
testRaw("RAW2", sendbuf, 67); | |||||
test("RAW3", NEC, 0x12345678, 32); | |||||
} | |||||
else { | |||||
test("RAW2", NEC, 0x12345678, 32); | |||||
testRaw("RAW3", sendbuf, 67); | |||||
} | |||||
} |
/* | |||||
* IRremote: IRsendDemo - demonstrates sending IR codes with IRsend | |||||
* An IR LED must be connected to Arduino PWM pin 3. | |||||
* 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) | |||||
*/ | |||||
#include <IRremote.h> | |||||
#define PanasonicAddress 0x4004 // Panasonic address (Pre data) | |||||
#define PanasonicPower 0x100BCBD // Panasonic Power button | |||||
#define JVCPower 0xC5E8 | |||||
IRsend irsend; | |||||
void setup() | |||||
{ | |||||
} | |||||
void loop() { | |||||
irsend.sendPanasonic(PanasonicAddress,PanasonicPower); // This should turn your TV on and off | |||||
irsend.sendJVC(JVCPower, 16,0); // hex value, 16 bits, no repeat | |||||
delayMicroseconds(50); // see http://www.sbprojects.com/knowledge/ir/jvc.php for information | |||||
irsend.sendJVC(JVCPower, 16,1); // hex value, 16 bits, repeat | |||||
delayMicroseconds(50); | |||||
} |
#include <IRremote.h> | |||||
#include <Wire.h> | |||||
IRsend irsend; | |||||
// not used | |||||
int RECV_PIN = 11; | |||||
IRrecv irrecv (RECV_PIN); | |||||
const int AC_TYPE = 0; | |||||
// 0 : TOWER | |||||
// 1 : WALL | |||||
// | |||||
int AC_HEAT = 0; | |||||
// 0 : cooling | |||||
// 1 : heating | |||||
int AC_POWER_ON = 0; | |||||
// 0 : off | |||||
// 1 : on | |||||
int AC_AIR_ACLEAN = 0; | |||||
// 0 : off | |||||
// 1 : on --> power on | |||||
int AC_TEMPERATURE = 27; | |||||
// temperature : 18 ~ 30 | |||||
int AC_FLOW = 1; | |||||
// 0 : low | |||||
// 1 : mid | |||||
// 2 : high | |||||
// if AC_TYPE =1, 3 : change | |||||
// | |||||
const int AC_FLOW_TOWER[3] = {0, 4, 6}; | |||||
const int AC_FLOW_WALL[4] = {0, 2, 4, 5}; | |||||
unsigned long AC_CODE_TO_SEND; | |||||
int r = LOW; | |||||
int o_r = LOW; | |||||
byte a, b; | |||||
void ac_send_code(unsigned long code) | |||||
{ | |||||
Serial.print("code to send : "); | |||||
Serial.print(code, BIN); | |||||
Serial.print(" : "); | |||||
Serial.println(code, HEX); | |||||
irsend.sendLG(code, 28); | |||||
} | |||||
void ac_activate(int temperature, int air_flow) | |||||
{ | |||||
int AC_MSBITS1 = 8; | |||||
int AC_MSBITS2 = 8; | |||||
int AC_MSBITS3 = 0; | |||||
int AC_MSBITS4 ; | |||||
if ( AC_HEAT == 1 ) { | |||||
// heating | |||||
AC_MSBITS4 = 4; | |||||
} else { | |||||
// cooling | |||||
AC_MSBITS4 = 0; | |||||
} | |||||
int AC_MSBITS5 = temperature - 15; | |||||
int AC_MSBITS6 ; | |||||
if ( AC_TYPE == 0) { | |||||
AC_MSBITS6 = AC_FLOW_TOWER[air_flow]; | |||||
} else { | |||||
AC_MSBITS6 = AC_FLOW_WALL[air_flow]; | |||||
} | |||||
int AC_MSBITS7 = (AC_MSBITS3 + AC_MSBITS4 + AC_MSBITS5 + AC_MSBITS6) & B00001111; | |||||
AC_CODE_TO_SEND = AC_MSBITS1 << 4 ; | |||||
AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS2) << 4; | |||||
AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS3) << 4; | |||||
AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS4) << 4; | |||||
AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS5) << 4; | |||||
AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS6) << 4; | |||||
AC_CODE_TO_SEND = (AC_CODE_TO_SEND + AC_MSBITS7); | |||||
ac_send_code(AC_CODE_TO_SEND); | |||||
AC_POWER_ON = 1; | |||||
AC_TEMPERATURE = temperature; | |||||
AC_FLOW = air_flow; | |||||
} | |||||
void ac_change_air_swing(int air_swing) | |||||
{ | |||||
if ( AC_TYPE == 0) { | |||||
if ( air_swing == 1) { | |||||
AC_CODE_TO_SEND = 0x881316B; | |||||
} else { | |||||
AC_CODE_TO_SEND = 0x881317C; | |||||
} | |||||
} else { | |||||
if ( air_swing == 1) { | |||||
AC_CODE_TO_SEND = 0x8813149; | |||||
} else { | |||||
AC_CODE_TO_SEND = 0x881315A; | |||||
} | |||||
} | |||||
ac_send_code(AC_CODE_TO_SEND); | |||||
} | |||||
void ac_power_down() | |||||
{ | |||||
AC_CODE_TO_SEND = 0x88C0051; | |||||
ac_send_code(AC_CODE_TO_SEND); | |||||
AC_POWER_ON = 0; | |||||
} | |||||
void ac_air_clean(int air_clean) | |||||
{ | |||||
if ( air_clean == 1) { | |||||
AC_CODE_TO_SEND = 0x88C000C; | |||||
} else { | |||||
AC_CODE_TO_SEND = 0x88C0084; | |||||
} | |||||
ac_send_code(AC_CODE_TO_SEND); | |||||
AC_AIR_ACLEAN = air_clean; | |||||
} | |||||
void setup() | |||||
{ | |||||
Serial.begin(38400); | |||||
delay(1000); | |||||
Wire.begin(7); | |||||
Wire.onReceive(receiveEvent); | |||||
Serial.println(" - - - T E S T - - - "); | |||||
/* test | |||||
ac_activate(25, 1); | |||||
delay(5000); | |||||
ac_activate(27, 2); | |||||
delay(5000); | |||||
*/ | |||||
} | |||||
void loop() | |||||
{ | |||||
ac_activate(25, 1); | |||||
delay(5000); | |||||
ac_activate(27, 0); | |||||
delay(5000); | |||||
if ( r != o_r) { | |||||
/* | |||||
# 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 ~ 2 : flow | |||||
# 5 : temp 18 ~ 30 | |||||
# + : temp + 1 | |||||
# - : temp - 1 | |||||
# 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); | |||||
break; | |||||
case 2: | |||||
if ( b == 0 || b == 1 ) { | |||||
ac_change_air_swing(b); | |||||
} | |||||
break; | |||||
case 3: // 1 : clean on, power on | |||||
if ( b == 0 || b == 1 ) { | |||||
ac_air_clean(b); | |||||
} | |||||
break; | |||||
case 4: | |||||
if ( 0 <= b && b <= 2 ) { | |||||
ac_activate(AC_TEMPERATURE, b); | |||||
} | |||||
break; | |||||
case 5: | |||||
if (18 <= b && b <= 30 ) { | |||||
ac_activate(b, AC_FLOW); | |||||
} | |||||
break; | |||||
case '+': | |||||
if ( 18 <= AC_TEMPERATURE && AC_TEMPERATURE <= 29 ) { | |||||
ac_activate((AC_TEMPERATURE + 1), AC_FLOW); | |||||
} | |||||
break; | |||||
case '-': | |||||
if ( 19 <= AC_TEMPERATURE && AC_TEMPERATURE <= 30 ) { | |||||
ac_activate((AC_TEMPERATURE - 1), AC_FLOW); | |||||
} | |||||
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_ACLEAN == 1) { | |||||
ac_air_clean(0); | |||||
delay(100); | |||||
} | |||||
ac_activate(AC_TEMPERATURE, AC_FLOW); | |||||
} | |||||
break; | |||||
default: | |||||
if ( 18 <= a && a <= 30 ) { | |||||
if ( 0 <= b && b <= 2 ) { | |||||
ac_activate(a, b); | |||||
} | |||||
} | |||||
} | |||||
o_r = r ; | |||||
} | |||||
delay(100); | |||||
} | |||||
void receiveEvent(int howMany) | |||||
{ | |||||
a = Wire.read(); | |||||
b = Wire.read(); | |||||
r = !r ; | |||||
} | |||||
=== decoding for LG A/C ==== | |||||
- 1) remote of LG AC has two type of HDR mark/space, 8000/4000 and 3100/10000 | |||||
- 2) HDR 8000/4000 is decoded using decodeLG(IRrecvDumpV2) without problem | |||||
- 3) for HDR 3100/10000, use AnalysIR's code : http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/ | |||||
- 4) for bin output based on AnalysIR's code : https://gist.github.com/chaeplin/a3a4b4b6b887c663bfe8 | |||||
- 5) remove first two byte(11) | |||||
- 6) sample rawcode with bin output : https://gist.github.com/chaeplin/134d232e0b8cfb898860 | |||||
=== *** === | |||||
- 1) Sample raw code : https://gist.github.com/chaeplin/ab2a7ad1533c41260f0d | |||||
- 2) send raw code : https://gist.github.com/chaeplin/7c800d3166463bb51be4 | |||||
=== *** === | |||||
- (0) : Cooling or Heating | |||||
- (1) : fixed | |||||
- (2) : fixed | |||||
- (3) : special(power, swing, air clean) | |||||
- (4) : change air flow, temperature, cooling(0)/heating(4) | |||||
- (5) : temperature ( 15 + (5) = ) | |||||
- (6) : air flow | |||||
- (7) : crc ( 3 + 4 + 5 + 6 ) & B00001111 | |||||
°F = °C × 1.8 + 32 | |||||
°C = (°F − 32) / 1.8 | |||||
=== *** === | |||||
* remote / Korea / without heating | |||||
| status |(0)| (1)| (2)| (3)| (4)| (5)| (6)| (7) | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| on / 25 / mid | C |1000|1000|0000|0000|1010|0010|1100 | |||||
| on / 26 / mid | C |1000|1000|0000|0000|1011|0010|1101 | |||||
| on / 27 / mid | C |1000|1000|0000|0000|1100|0010|1110 | |||||
| on / 28 / mid | C |1000|1000|0000|0000|1101|0010|1111 | |||||
| on / 25 / high | C |1000|1000|0000|0000|1010|0100|1110 | |||||
| on / 26 / high | C |1000|1000|0000|0000|1011|0100|1111 | |||||
| on / 27 / high | C |1000|1000|0000|0000|1100|0100|0000 | |||||
| on / 28 / high | C |1000|1000|0000|0000|1101|0100|0001 | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| 1 up | C |1000|1000|0000|1000|1101|0100|1001 | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| Cool power | C |1000|1000|0001|0000|0000|1100|1101 | |||||
| energy saving | C |1000|1000|0001|0000|0000|0100|0101 | |||||
| power | C |1000|1000|0001|0000|0000|1000|1001 | |||||
| flow/up/down | C |1000|1000|0001|0011|0001|0100|1001 | |||||
| up/down off | C |1000|1000|0001|0011|0001|0101|1010 | |||||
| flow/left/right| C |1000|1000|0001|0011|0001|0110|1011 | |||||
| left/right off | C |1000|1000|0001|0011|0001|0111|1100 | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| Air clean | C |1000|1000|1100|0000|0000|0000|1100 | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| off | C |1000|1000|1100|0000|0000|0101|0001 | |||||
* remote / with heating | |||||
* converted using raw code at https://github.com/chaeplin/RaspAC/blob/master/lircd.conf | |||||
| status |(0)| (1)| (2)| (3)| (4)| (5)| (6)| (7) | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| on | C |1000|1000|0000|0000|1011|0010|1101 | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| off | C |1000|1000|1100|0000|0000|0101|0001 | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| 64 / 18 | C |1000|1000|0000|0000|0011|0100|0111 | |||||
| 66 / 19 | C |1000|1000|0000|0000|0100|0100|1000 | |||||
| 68 / 20 | C |1000|1000|0000|0000|0101|0100|1001 | |||||
| 70 / 21 | C |1000|1000|0000|0000|0110|0100|1010 | |||||
| 72 / 22 | C |1000|1000|0000|0000|0111|0100|1011 | |||||
| 74 / 23 | C |1000|1000|0000|0000|1000|0100|1100 | |||||
| 76 / 25 | C |1000|1000|0000|0000|1010|0100|1110 | |||||
| 78 / 26 | C |1000|1000|0000|0000|1011|0100|1111 | |||||
| 80 / 27 | C |1000|1000|0000|0000|1100|0100|0000 | |||||
| 82 / 28 | C |1000|1000|0000|0000|1101|0100|0001 | |||||
| 84 / 29 | C |1000|1000|0000|0000|1110|0100|0010 | |||||
| 86 / 30 | C |1000|1000|0000|0000|1111|0100|0011 | |||||
|----------------|---|----|----|----|----|----|----|---- | |||||
| heat64 | H |1000|1000|0000|0100|0011|0100|1011 | |||||
| heat66 | H |1000|1000|0000|0100|0100|0100|1100 | |||||
| heat68 | H |1000|1000|0000|0100|0101|0100|1101 | |||||
| heat70 | H |1000|1000|0000|0100|0110|0100|1110 | |||||
| heat72 | H |1000|1000|0000|0100|0111|0100|1111 | |||||
| heat74 | H |1000|1000|0000|0100|1000|0100|0000 | |||||
| heat76 | H |1000|1000|0000|0100|1001|0100|0001 | |||||
| heat78 | H |1000|1000|0000|0100|1011|0100|0011 | |||||
| heat80 | H |1000|1000|0000|0100|1100|0100|0100 | |||||
| heat82 | H |1000|1000|0000|0100|1101|0100|0101 | |||||
| heat84 | H |1000|1000|0000|0100|1110|0100|0110 | |||||
| heat86 | H |1000|1000|0000|0100|1111|0100|0111 |
/* | |||||
* LegoPowerFunctionsSendDemo: LEGO Power Functions | |||||
* Copyright (c) 2016 Philipp Henkel | |||||
*/ | |||||
#include <IRremote.h> | |||||
#include <IRremoteInt.h> | |||||
IRsend irsend; | |||||
void setup() { | |||||
} | |||||
void loop() { | |||||
// Send repeated command "channel 1, blue forward, red backward" | |||||
irsend.sendLegoPowerFunctions(0x197); | |||||
delay(2000); | |||||
// Send single command "channel 1, blue forward, red backward" | |||||
irsend.sendLegoPowerFunctions(0x197, false); | |||||
delay(2000); | |||||
} |
/* | |||||
* LegoPowerFunctionsTest: LEGO Power Functions Tests | |||||
* Copyright (c) 2016, 2017 Philipp Henkel | |||||
*/ | |||||
#include <ir_Lego_PF_BitStreamEncoder.h> | |||||
void setup() { | |||||
Serial.begin(9600); | |||||
delay(1000); // wait for reset triggered by serial connection | |||||
runBitStreamEncoderTests(); | |||||
} | |||||
void loop() { | |||||
} | |||||
void runBitStreamEncoderTests() { | |||||
Serial.println(); | |||||
Serial.println("BitStreamEncoder Tests"); | |||||
static LegoPfBitStreamEncoder bitStreamEncoder; | |||||
testStartBit(bitStreamEncoder); | |||||
testLowBit(bitStreamEncoder); | |||||
testHighBit(bitStreamEncoder); | |||||
testMessageBitCount(bitStreamEncoder); | |||||
testMessageBitCountRepeat(bitStreamEncoder); | |||||
testMessage407(bitStreamEncoder); | |||||
testMessage407Repeated(bitStreamEncoder); | |||||
testGetChannelId1(bitStreamEncoder); | |||||
testGetChannelId2(bitStreamEncoder); | |||||
testGetChannelId3(bitStreamEncoder); | |||||
testGetChannelId4(bitStreamEncoder); | |||||
testGetMessageLengthAllHigh(bitStreamEncoder); | |||||
testGetMessageLengthAllLow(bitStreamEncoder); | |||||
} | |||||
void logTestResult(bool testPassed) { | |||||
if (testPassed) { | |||||
Serial.println("OK"); | |||||
} | |||||
else { | |||||
Serial.println("FAIL ############"); | |||||
} | |||||
} | |||||
void testStartBit(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testStartBit "); | |||||
bitStreamEncoder.reset(0, false); | |||||
int startMark = bitStreamEncoder.getMarkDuration(); | |||||
int startPause = bitStreamEncoder.getPauseDuration(); | |||||
logTestResult(startMark == 158 && startPause == 1184-158); | |||||
} | |||||
void testLowBit(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testLowBit "); | |||||
bitStreamEncoder.reset(0, false); | |||||
bitStreamEncoder.next(); | |||||
int lowMark = bitStreamEncoder.getMarkDuration(); | |||||
int lowPause = bitStreamEncoder.getPauseDuration(); | |||||
logTestResult(lowMark == 158 && lowPause == 421-158); | |||||
} | |||||
void testHighBit(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testHighBit "); | |||||
bitStreamEncoder.reset(0xFFFF, false); | |||||
bitStreamEncoder.next(); | |||||
int highMark = bitStreamEncoder.getMarkDuration(); | |||||
int highPause = bitStreamEncoder.getPauseDuration(); | |||||
logTestResult(highMark == 158 && highPause == 711-158); | |||||
} | |||||
void testMessageBitCount(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testMessageBitCount "); | |||||
bitStreamEncoder.reset(0xFFFF, false); | |||||
int bitCount = 1; | |||||
while (bitStreamEncoder.next()) { | |||||
bitCount++; | |||||
} | |||||
logTestResult(bitCount == 18); | |||||
} | |||||
boolean check(LegoPfBitStreamEncoder& bitStreamEncoder, unsigned long markDuration, unsigned long pauseDuration) { | |||||
bool result = true; | |||||
result = result && bitStreamEncoder.getMarkDuration() == markDuration; | |||||
result = result && bitStreamEncoder.getPauseDuration() == pauseDuration; | |||||
return result; | |||||
} | |||||
boolean checkNext(LegoPfBitStreamEncoder& bitStreamEncoder, unsigned long markDuration, unsigned long pauseDuration) { | |||||
bool result = bitStreamEncoder.next(); | |||||
result = result && check(bitStreamEncoder, markDuration, pauseDuration); | |||||
return result; | |||||
} | |||||
boolean checkDataBitsOfMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
bool result = true; | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 553); | |||||
result = result && checkNext(bitStreamEncoder, 158, 553); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 553); | |||||
result = result && checkNext(bitStreamEncoder, 158, 263); | |||||
result = result && checkNext(bitStreamEncoder, 158, 553); | |||||
result = result && checkNext(bitStreamEncoder, 158, 553); | |||||
result = result && checkNext(bitStreamEncoder, 158, 553); | |||||
return result; | |||||
} | |||||
void testMessage407(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testMessage407 "); | |||||
bitStreamEncoder.reset(407, false); | |||||
bool result = true; | |||||
result = result && check(bitStreamEncoder, 158, 1026); | |||||
result = result && checkDataBitsOfMessage407(bitStreamEncoder); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026); | |||||
result = result && !bitStreamEncoder.next(); | |||||
logTestResult(result); | |||||
} | |||||
void testMessage407Repeated(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testMessage407Repeated "); | |||||
bitStreamEncoder.reset(407, true); | |||||
bool result = true; | |||||
result = result && check(bitStreamEncoder, 158, 1026); | |||||
result = result && checkDataBitsOfMessage407(bitStreamEncoder); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026L + 5L * 16000L - 10844L); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026); | |||||
result = result && checkDataBitsOfMessage407(bitStreamEncoder); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026L + 5L * 16000L - 10844L); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026); | |||||
result = result && checkDataBitsOfMessage407(bitStreamEncoder); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026L + 8L * 16000L - 10844L); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026); | |||||
result = result && checkDataBitsOfMessage407(bitStreamEncoder); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026L + 8L * 16000L - 10844L); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026); | |||||
result = result && checkDataBitsOfMessage407(bitStreamEncoder); | |||||
result = result && checkNext(bitStreamEncoder, 158, 1026); | |||||
result = result && !bitStreamEncoder.next(); | |||||
logTestResult(result); | |||||
} | |||||
void testMessageBitCountRepeat(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testMessageBitCountRepeat "); | |||||
bitStreamEncoder.reset(0xFFFF, true); | |||||
int bitCount = 1; | |||||
while (bitStreamEncoder.next()) { | |||||
bitCount++; | |||||
} | |||||
logTestResult(bitCount == 5*18); | |||||
} | |||||
void testGetChannelId1(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testGetChannelId1 "); | |||||
bitStreamEncoder.reset(407, false); | |||||
logTestResult(bitStreamEncoder.getChannelId() == 1); | |||||
} | |||||
void testGetChannelId2(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testGetChannelId2 "); | |||||
bitStreamEncoder.reset(4502, false); | |||||
logTestResult(bitStreamEncoder.getChannelId() == 2); | |||||
} | |||||
void testGetChannelId3(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testGetChannelId3 "); | |||||
bitStreamEncoder.reset(8597, false); | |||||
logTestResult(bitStreamEncoder.getChannelId() == 3); | |||||
} | |||||
void testGetChannelId4(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testGetChannelId4 "); | |||||
bitStreamEncoder.reset(12692, false); | |||||
logTestResult(bitStreamEncoder.getChannelId() == 4); | |||||
} | |||||
void testGetMessageLengthAllHigh(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testGetMessageLengthAllHigh "); | |||||
bitStreamEncoder.reset(0xFFFF, false); | |||||
logTestResult(bitStreamEncoder.getMessageLength() == 13744); | |||||
} | |||||
void testGetMessageLengthAllLow(LegoPfBitStreamEncoder& bitStreamEncoder) { | |||||
Serial.print(" testGetMessageLengthAllLow "); | |||||
bitStreamEncoder.reset(0x0, false); | |||||
logTestResult(bitStreamEncoder.getMessageLength() == 9104); | |||||
} |
//****************************************************************************** | |||||
// IRremote | |||||
// Version 2.0.1 June, 2015 | |||||
// 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 | |||||
//****************************************************************************** | |||||
#ifndef IRremote_h | |||||
#define IRremote_h | |||||
//------------------------------------------------------------------------------ | |||||
// The ISR header contains several useful macros the user may wish to use | |||||
// | |||||
#include "./IRremoteInt.h" | |||||
//------------------------------------------------------------------------------ | |||||
// Supported IR protocols | |||||
// Each protocol you include costs memory and, during decode, costs time | |||||
// Disable (set to 0) all the protocols you do not need/want! | |||||
// | |||||
#define DECODE_RC5 1 | |||||
#define SEND_RC5 1 | |||||
#define DECODE_RC6 1 | |||||
#define SEND_RC6 1 | |||||
#define DECODE_NEC 1 | |||||
#define SEND_NEC 1 | |||||
#define DECODE_SONY 1 | |||||
#define SEND_SONY 1 | |||||
#define DECODE_PANASONIC 1 | |||||
#define SEND_PANASONIC 1 | |||||
#define DECODE_JVC 1 | |||||
#define SEND_JVC 1 | |||||
#define DECODE_SAMSUNG 1 | |||||
#define SEND_SAMSUNG 1 | |||||
#define DECODE_WHYNTER 1 | |||||
#define SEND_WHYNTER 1 | |||||
#define DECODE_AIWA_RC_T501 1 | |||||
#define SEND_AIWA_RC_T501 1 | |||||
#define DECODE_LG 1 | |||||
#define SEND_LG 1 | |||||
#define DECODE_SANYO 1 | |||||
#define SEND_SANYO 0 // NOT WRITTEN | |||||
#define DECODE_MITSUBISHI 1 | |||||
#define SEND_MITSUBISHI 0 // NOT WRITTEN | |||||
#define DECODE_DISH 0 // NOT WRITTEN | |||||
#define SEND_DISH 1 | |||||
#define DECODE_SHARP 0 // NOT WRITTEN | |||||
#define SEND_SHARP 1 | |||||
#define DECODE_DENON 1 | |||||
#define SEND_DENON 1 | |||||
#define DECODE_PRONTO 0 // This function doe not logically make sense | |||||
#define SEND_PRONTO 1 | |||||
#define DECODE_LEGO_PF 0 // NOT WRITTEN | |||||
#define SEND_LEGO_PF 1 | |||||
//------------------------------------------------------------------------------ | |||||
// When sending a Pronto code we request to send either the "once" code | |||||
// or the "repeat" code | |||||
// If the code requested does not exist we can request to fallback on the | |||||
// other code (the one we did not explicitly request) | |||||
// | |||||
// I would suggest that "fallback" will be the standard calling method | |||||
// The last paragraph on this page discusses the rationale of this idea: | |||||
// http://www.remotecentral.com/features/irdisp2.htm | |||||
// | |||||
#define PRONTO_ONCE false | |||||
#define PRONTO_REPEAT true | |||||
#define PRONTO_FALLBACK true | |||||
#define PRONTO_NOFALLBACK false | |||||
//------------------------------------------------------------------------------ | |||||
// An enumerated list of all supported formats | |||||
// You do NOT need to remove entries from this list when disabling protocols! | |||||
// | |||||
typedef | |||||
enum { | |||||
UNKNOWN = -1, | |||||
UNUSED = 0, | |||||
RC5, | |||||
RC6, | |||||
NEC, | |||||
SONY, | |||||
PANASONIC, | |||||
JVC, | |||||
SAMSUNG, | |||||
WHYNTER, | |||||
AIWA_RC_T501, | |||||
LG, | |||||
SANYO, | |||||
MITSUBISHI, | |||||
DISH, | |||||
SHARP, | |||||
DENON, | |||||
PRONTO, | |||||
LEGO_PF, | |||||
} | |||||
decode_type_t; | |||||
//------------------------------------------------------------------------------ | |||||
// Set DEBUG to 1 for lots of lovely debug output | |||||
// | |||||
#define DEBUG 0 | |||||
//------------------------------------------------------------------------------ | |||||
// Debug directives | |||||
// | |||||
#if DEBUG | |||||
# define DBG_PRINT(...) Serial.print(__VA_ARGS__) | |||||
# define DBG_PRINTLN(...) Serial.println(__VA_ARGS__) | |||||
#else | |||||
# define DBG_PRINT(...) | |||||
# define DBG_PRINTLN(...) | |||||
#endif | |||||
//------------------------------------------------------------------------------ | |||||
// Mark & Space matching functions | |||||
// | |||||
int MATCH (int measured, int desired) ; | |||||
int MATCH_MARK (int measured_ticks, int desired_us) ; | |||||
int MATCH_SPACE (int measured_ticks, int desired_us) ; | |||||
//------------------------------------------------------------------------------ | |||||
// Results returned from the decoder | |||||
// | |||||
class decode_results | |||||
{ | |||||
public: | |||||
decode_type_t decode_type; // UNKNOWN, NEC, SONY, RC5, ... | |||||
unsigned int address; // Used by Panasonic & Sharp [16-bits] | |||||
unsigned long value; // Decoded value [max 32-bits] | |||||
int bits; // Number of bits in decoded value | |||||
volatile unsigned int *rawbuf; // Raw intervals in 50uS ticks | |||||
int rawlen; // Number of records in rawbuf | |||||
int overflow; // true iff IR raw code too long | |||||
}; | |||||
//------------------------------------------------------------------------------ | |||||
// Decoded value for NEC when a repeat code is received | |||||
// | |||||
#define REPEAT 0xFFFFFFFF | |||||
//------------------------------------------------------------------------------ | |||||
// Main class for receiving IR | |||||
// | |||||
class IRrecv | |||||
{ | |||||
public: | |||||
IRrecv (int recvpin) ; | |||||
IRrecv (int recvpin, int blinkpin); | |||||
void blink13 (int blinkflag) ; | |||||
int decode (decode_results *results) ; | |||||
void enableIRIn ( ) ; | |||||
bool isIdle ( ) ; | |||||
void resume ( ) ; | |||||
private: | |||||
long decodeHash (decode_results *results) ; | |||||
int compare (unsigned int oldval, unsigned int newval) ; | |||||
//...................................................................... | |||||
# if (DECODE_RC5 || DECODE_RC6) | |||||
// This helper function is shared by RC5 and RC6 | |||||
int getRClevel (decode_results *results, int *offset, int *used, int t1) ; | |||||
# endif | |||||
# if DECODE_RC5 | |||||
bool decodeRC5 (decode_results *results) ; | |||||
# endif | |||||
# if DECODE_RC6 | |||||
bool decodeRC6 (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_NEC | |||||
bool decodeNEC (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_SONY | |||||
bool decodeSony (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_PANASONIC | |||||
bool decodePanasonic (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_JVC | |||||
bool decodeJVC (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_SAMSUNG | |||||
bool decodeSAMSUNG (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_WHYNTER | |||||
bool decodeWhynter (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_AIWA_RC_T501 | |||||
bool decodeAiwaRCT501 (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_LG | |||||
bool decodeLG (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_SANYO | |||||
bool decodeSanyo (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_MITSUBISHI | |||||
bool decodeMitsubishi (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_DISH | |||||
bool decodeDish (decode_results *results) ; // NOT WRITTEN | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_SHARP | |||||
bool decodeSharp (decode_results *results) ; // NOT WRITTEN | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_DENON | |||||
bool decodeDenon (decode_results *results) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if DECODE_LEGO_PF | |||||
bool decodeLegoPowerFunctions (decode_results *results) ; | |||||
# endif | |||||
} ; | |||||
//------------------------------------------------------------------------------ | |||||
// Main class for sending IR | |||||
// | |||||
class IRsend | |||||
{ | |||||
public: | |||||
IRsend () { } | |||||
void custom_delay_usec (unsigned long uSecs); | |||||
void enableIROut (int khz) ; | |||||
void mark (unsigned int usec) ; | |||||
void space (unsigned int usec) ; | |||||
void sendRaw (const unsigned int buf[], unsigned int len, unsigned int hz) ; | |||||
//...................................................................... | |||||
# if SEND_RC5 | |||||
void sendRC5 (unsigned long data, int nbits) ; | |||||
# endif | |||||
# if SEND_RC6 | |||||
void sendRC6 (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_NEC | |||||
void sendNEC (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_SONY | |||||
void sendSony (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_PANASONIC | |||||
void sendPanasonic (unsigned int address, unsigned long data) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_JVC | |||||
// JVC does NOT repeat by sending a separate code (like NEC does). | |||||
// The JVC protocol repeats by skipping the header. | |||||
// To send a JVC repeat signal, send the original code value | |||||
// and set 'repeat' to true | |||||
void sendJVC (unsigned long data, int nbits, bool repeat) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_SAMSUNG | |||||
void sendSAMSUNG (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_WHYNTER | |||||
void sendWhynter (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_AIWA_RC_T501 | |||||
void sendAiwaRCT501 (int code) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_LG | |||||
void sendLG (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_SANYO | |||||
void sendSanyo ( ) ; // NOT WRITTEN | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_MISUBISHI | |||||
void sendMitsubishi ( ) ; // NOT WRITTEN | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_DISH | |||||
void sendDISH (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_SHARP | |||||
void sendSharpRaw (unsigned long data, int nbits) ; | |||||
void sendSharp (unsigned int address, unsigned int command) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_DENON | |||||
void sendDenon (unsigned long data, int nbits) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_PRONTO | |||||
void sendPronto (char* code, bool repeat, bool fallback) ; | |||||
# endif | |||||
//...................................................................... | |||||
# if SEND_LEGO_PF | |||||
void sendLegoPowerFunctions (uint16_t data, bool repeat = true) ; | |||||
# endif | |||||
} ; | |||||
#endif |
//****************************************************************************** | |||||
// IRremote | |||||
// Version 2.0.1 June, 2015 | |||||
// Copyright 2009 Ken Shirriff | |||||
// For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html | |||||
// | |||||
// Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers | |||||
// | |||||
// 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) | |||||
// Whynter A/C ARC-110WD added by Francesco Meschia | |||||
//****************************************************************************** | |||||
#ifndef IRremoteint_h | |||||
#define IRremoteint_h | |||||
//------------------------------------------------------------------------------ | |||||
// Include the right Arduino header | |||||
// | |||||
#if defined(ARDUINO) && (ARDUINO >= 100) | |||||
# include <core/Arduino.h> | |||||
#else | |||||
# if !defined(IRPRONTO) | |||||
# include <WProgram.h> | |||||
# endif | |||||
#endif | |||||
//------------------------------------------------------------------------------ | |||||
// This handles definition and access to global variables | |||||
// | |||||
#ifdef IR_GLOBAL | |||||
# define EXTERN | |||||
#else | |||||
# define EXTERN extern | |||||
#endif | |||||
//------------------------------------------------------------------------------ | |||||
// Information for the Interrupt Service Routine | |||||
// | |||||
#define RAWBUF 101 // Maximum length of raw duration buffer | |||||
typedef | |||||
struct { | |||||
// The fields are ordered to reduce memory over caused by struct-padding | |||||
uint8_t rcvstate; // State Machine state | |||||
uint8_t recvpin; // Pin connected to IR data from detector | |||||
uint8_t blinkpin; | |||||
uint8_t blinkflag; // true -> enable blinking of pin on IR processing | |||||
uint8_t rawlen; // counter of entries in rawbuf | |||||
unsigned int timer; // State timer, counts 50uS ticks. | |||||
unsigned int rawbuf[RAWBUF]; // raw data | |||||
uint8_t overflow; // Raw buffer overflow occurred | |||||
} | |||||
irparams_t; | |||||
// ISR State-Machine : Receiver States | |||||
#define STATE_IDLE 2 | |||||
#define STATE_MARK 3 | |||||
#define STATE_SPACE 4 | |||||
#define STATE_STOP 5 | |||||
#define STATE_OVERFLOW 6 | |||||
// Allow all parts of the code access to the ISR data | |||||
// NB. The data can be changed by the ISR at any time, even mid-function | |||||
// Therefore we declare it as "volatile" to stop the compiler/CPU caching it | |||||
EXTERN volatile irparams_t irparams; | |||||
//------------------------------------------------------------------------------ | |||||
// Defines for setting and clearing register bits | |||||
// | |||||
#ifndef cbi | |||||
# define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) | |||||
#endif | |||||
#ifndef sbi | |||||
# define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) | |||||
#endif | |||||
//------------------------------------------------------------------------------ | |||||
// Pulse parms are ((X*50)-100) for the Mark and ((X*50)+100) for the Space. | |||||
// First MARK is the one after the long gap | |||||
// Pulse parameters in uSec | |||||
// | |||||
// Due to sensor lag, when received, Marks tend to be 100us too long and | |||||
// Spaces tend to be 100us too short | |||||
#define MARK_EXCESS 100 | |||||
// Upper and Lower percentage tolerances in measurements | |||||
#define TOLERANCE 25 | |||||
#define LTOL (1.0 - (TOLERANCE/100.)) | |||||
#define UTOL (1.0 + (TOLERANCE/100.)) | |||||
// Minimum gap between IR transmissions | |||||
#define _GAP 5000 | |||||
#define GAP_TICKS (_GAP/USECPERTICK) | |||||
#define TICKS_LOW(us) ((int)(((us)*LTOL/USECPERTICK))) | |||||
#define TICKS_HIGH(us) ((int)(((us)*UTOL/USECPERTICK + 1))) | |||||
//------------------------------------------------------------------------------ | |||||
// IR detector output is active low | |||||
// | |||||
#define MARK 0 | |||||
#define SPACE 1 | |||||
// All board specific stuff has been moved to its own file, included here. | |||||
#include "./boarddefs.h" | |||||
#endif |
//****************************************************************************** | |||||
// IRremote | |||||
// Version 2.0.1 June, 2015 | |||||
// Copyright 2009 Ken Shirriff | |||||
// For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html | |||||
// This file contains all board specific information. It was previously contained within | |||||
// IRremoteInt.h | |||||
// Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers | |||||
// | |||||
// 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) | |||||
// Whynter A/C ARC-110WD added by Francesco Meschia | |||||
// Sparkfun Pro Micro support by Alastair McCormack | |||||
//****************************************************************************** | |||||
#ifndef boarddefs_h | |||||
#define boarddefs_h | |||||
//------------------------------------------------------------------------------ | |||||
// Defines for blinking the LED | |||||
// | |||||
#if defined(CORE_LED0_PIN) | |||||
# define BLINKLED CORE_LED0_PIN | |||||
# define BLINKLED_ON() (digitalWrite(CORE_LED0_PIN, HIGH)) | |||||
# define BLINKLED_OFF() (digitalWrite(CORE_LED0_PIN, LOW)) | |||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | |||||
# define BLINKLED 13 | |||||
# define BLINKLED_ON() (PORTB |= B10000000) | |||||
# define BLINKLED_OFF() (PORTB &= B01111111) | |||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) | |||||
# define BLINKLED 0 | |||||
# define BLINKLED_ON() (PORTD |= B00000001) | |||||
# define BLINKLED_OFF() (PORTD &= B11111110) | |||||
// No system LED on ESP32, disable blinking | |||||
#elif defined(ESP32) | |||||
# define BLINKLED 255 | |||||
# define BLINKLED_ON() 1 | |||||
# define BLINKLED_OFF() 1 | |||||
#else | |||||
# define BLINKLED 13 | |||||
# define BLINKLED_ON() (PORTB |= B00100000) | |||||
# define BLINKLED_OFF() (PORTB &= B11011111) | |||||
#endif | |||||
//------------------------------------------------------------------------------ | |||||
// CPU Frequency | |||||
// | |||||
#ifdef F_CPU | |||||
# define SYSCLOCK F_CPU // main Arduino clock | |||||
#else | |||||
# define SYSCLOCK 16000000 // main Arduino clock | |||||
#endif | |||||
// microseconds per clock interrupt tick | |||||
#define USECPERTICK 50 | |||||
//------------------------------------------------------------------------------ | |||||
// Define which timer to use | |||||
// | |||||
// Uncomment the timer you wish to use on your board. | |||||
// If you are using another library which uses timer2, you have options to | |||||
// switch IRremote to use a different timer. | |||||
// | |||||
// Sparkfun Pro Micro | |||||
#if defined(ARDUINO_AVR_PROMICRO) | |||||
//#define IR_USE_TIMER1 // tx = pin 9 | |||||
#define IR_USE_TIMER3 // tx = pin 5 | |||||
//#define IR_USE_TIMER4_HS // tx = pin 5 | |||||
// Arduino Mega | |||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | |||||
//#define IR_USE_TIMER1 // tx = pin 11 | |||||
#define IR_USE_TIMER2 // tx = pin 9 | |||||
//#define IR_USE_TIMER3 // tx = pin 5 | |||||
//#define IR_USE_TIMER4 // tx = pin 6 | |||||
//#define IR_USE_TIMER5 // tx = pin 46 | |||||
// Teensy 1.0 | |||||
#elif defined(__AVR_AT90USB162__) | |||||
#define IR_USE_TIMER1 // tx = pin 17 | |||||
// Teensy 2.0 | |||||
#elif defined(__AVR_ATmega32U4__) | |||||
//#define IR_USE_TIMER1 // tx = pin 14 | |||||
//#define IR_USE_TIMER3 // tx = pin 9 | |||||
#define IR_USE_TIMER4_HS // tx = pin 10 | |||||
// Teensy 3.0 / Teensy 3.1 | |||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||||
#define IR_USE_TIMER_CMT // tx = pin 5 | |||||
// Teensy-LC | |||||
#elif defined(__MKL26Z64__) | |||||
#define IR_USE_TIMER_TPM1 // tx = pin 16 | |||||
// Teensy 4 | |||||
#elif defined(__IMXRT1062__) | |||||
#define IR_USE_TIMER_FLEXPWM1 // tx = pin 8 | |||||
// Teensy++ 1.0 & 2.0 | |||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) | |||||
//#define IR_USE_TIMER1 // tx = pin 25 | |||||
#define IR_USE_TIMER2 // tx = pin 1 | |||||
//#define IR_USE_TIMER3 // tx = pin 16 | |||||
// MightyCore - ATmega1284 | |||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) | |||||
//#define IR_USE_TIMER1 // tx = pin 13 | |||||
#define IR_USE_TIMER2 // tx = pin 14 | |||||
//#define IR_USE_TIMER3 // tx = pin 6 | |||||
// MightyCore - ATmega164, ATmega324, ATmega644 | |||||
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \ | |||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \ | |||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \ | |||||
|| defined(__AVR_ATmega164P__) | |||||
//#define IR_USE_TIMER1 // tx = pin 13 | |||||
#define IR_USE_TIMER2 // tx = pin 14 | |||||
//MegaCore - ATmega64, ATmega128 | |||||
#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) | |||||
#define IR_USE_TIMER1 // tx = pin 13 | |||||
// MightyCore - ATmega8535, ATmega16, ATmega32 | |||||
#elif defined(__AVR_ATmega8535__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) | |||||
#define IR_USE_TIMER1 // tx = pin 13 | |||||
// Atmega8 | |||||
#elif defined(__AVR_ATmega8__) | |||||
#define IR_USE_TIMER1 // tx = pin 9 | |||||
// ATtiny84 | |||||
#elif defined(__AVR_ATtiny84__) | |||||
#define IR_USE_TIMER1 // tx = pin 6 | |||||
//ATtiny85 | |||||
#elif defined(__AVR_ATtiny85__) | |||||
#define IR_USE_TIMER_TINY0 // tx = pin 1 | |||||
#elif defined(ESP32) | |||||
#define IR_TIMER_USE_ESP32 | |||||
#else | |||||
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc | |||||
// ATmega48, ATmega88, ATmega168, ATmega328 | |||||
//#define IR_USE_TIMER1 // tx = pin 9 | |||||
#define IR_USE_TIMER2 // tx = pin 3 | |||||
#endif | |||||
//------------------------------------------------------------------------------ | |||||
// Defines for Timer | |||||
//--------------------------------------------------------- | |||||
// Timer2 (8 bits) | |||||
// | |||||
#if defined(IR_USE_TIMER2) | |||||
#define TIMER_RESET | |||||
#define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1)) | |||||
#define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1))) | |||||
#define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A)) | |||||
#define TIMER_DISABLE_INTR (TIMSK2 = 0) | |||||
#define TIMER_INTR_NAME TIMER2_COMPA_vect | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \ | |||||
TCCR2A = _BV(WGM20); \ | |||||
TCCR2B = _BV(WGM22) | _BV(CS20); \ | |||||
OCR2A = pwmval; \ | |||||
OCR2B = pwmval / 3; \ | |||||
}) | |||||
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) | |||||
//----------------- | |||||
#if (TIMER_COUNT_TOP < 256) | |||||
# define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR2A = _BV(WGM21); \ | |||||
TCCR2B = _BV(CS20); \ | |||||
OCR2A = TIMER_COUNT_TOP; \ | |||||
TCNT2 = 0; \ | |||||
}) | |||||
#else | |||||
# define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR2A = _BV(WGM21); \ | |||||
TCCR2B = _BV(CS21); \ | |||||
OCR2A = TIMER_COUNT_TOP / 8; \ | |||||
TCNT2 = 0; \ | |||||
}) | |||||
#endif | |||||
//----------------- | |||||
#if defined(CORE_OC2B_PIN) | |||||
# define TIMER_PWM_PIN CORE_OC2B_PIN // Teensy | |||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | |||||
# define TIMER_PWM_PIN 9 // Arduino Mega | |||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \ | |||||
|| defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \ | |||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \ | |||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \ | |||||
|| defined(__AVR_ATmega164P__) | |||||
# define TIMER_PWM_PIN 14 // MightyCore | |||||
#else | |||||
# define TIMER_PWM_PIN 3 // Arduino Duemilanove, Diecimila, LilyPad, etc | |||||
#endif // ATmega48, ATmega88, ATmega168, ATmega328 | |||||
//--------------------------------------------------------- | |||||
// Timer1 (16 bits) | |||||
// | |||||
#elif defined(IR_USE_TIMER1) | |||||
#define TIMER_RESET | |||||
#define TIMER_ENABLE_PWM (TCCR1A |= _BV(COM1A1)) | |||||
#define TIMER_DISABLE_PWM (TCCR1A &= ~(_BV(COM1A1))) | |||||
//----------------- | |||||
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8535__) \ | |||||
|| defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ | |||||
|| defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) | |||||
# define TIMER_ENABLE_INTR (TIMSK |= _BV(OCIE1A)) | |||||
# define TIMER_DISABLE_INTR (TIMSK &= ~_BV(OCIE1A)) | |||||
#else | |||||
# define TIMER_ENABLE_INTR (TIMSK1 = _BV(OCIE1A)) | |||||
# define TIMER_DISABLE_INTR (TIMSK1 = 0) | |||||
#endif | |||||
//----------------- | |||||
#define TIMER_INTR_NAME TIMER1_COMPA_vect | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ | |||||
TCCR1A = _BV(WGM11); \ | |||||
TCCR1B = _BV(WGM13) | _BV(CS10); \ | |||||
ICR1 = pwmval; \ | |||||
OCR1A = pwmval / 3; \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR1A = 0; \ | |||||
TCCR1B = _BV(WGM12) | _BV(CS10); \ | |||||
OCR1A = SYSCLOCK * USECPERTICK / 1000000; \ | |||||
TCNT1 = 0; \ | |||||
}) | |||||
//----------------- | |||||
#if defined(CORE_OC1A_PIN) | |||||
# define TIMER_PWM_PIN CORE_OC1A_PIN // Teensy | |||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | |||||
# define TIMER_PWM_PIN 11 // Arduino Mega | |||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \ | |||||
|| defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \ | |||||
|| defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \ | |||||
|| defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \ | |||||
|| defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \ | |||||
|| defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) \ | |||||
|| defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) | |||||
# define TIMER_PWM_PIN 13 // MightyCore, MegaCore | |||||
#elif defined(__AVR_ATtiny84__) | |||||
# define TIMER_PWM_PIN 6 | |||||
#else | |||||
# define TIMER_PWM_PIN 9 // Arduino Duemilanove, Diecimila, LilyPad, Sparkfun Pro Micro etc | |||||
#endif // ATmega48, ATmega88, ATmega168, ATmega328 | |||||
//--------------------------------------------------------- | |||||
// Timer3 (16 bits) | |||||
// | |||||
#elif defined(IR_USE_TIMER3) | |||||
#define TIMER_RESET | |||||
#define TIMER_ENABLE_PWM (TCCR3A |= _BV(COM3A1)) | |||||
#define TIMER_DISABLE_PWM (TCCR3A &= ~(_BV(COM3A1))) | |||||
#define TIMER_ENABLE_INTR (TIMSK3 = _BV(OCIE3A)) | |||||
#define TIMER_DISABLE_INTR (TIMSK3 = 0) | |||||
#define TIMER_INTR_NAME TIMER3_COMPA_vect | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ | |||||
TCCR3A = _BV(WGM31); \ | |||||
TCCR3B = _BV(WGM33) | _BV(CS30); \ | |||||
ICR3 = pwmval; \ | |||||
OCR3A = pwmval / 3; \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR3A = 0; \ | |||||
TCCR3B = _BV(WGM32) | _BV(CS30); \ | |||||
OCR3A = SYSCLOCK * USECPERTICK / 1000000; \ | |||||
TCNT3 = 0; \ | |||||
}) | |||||
//----------------- | |||||
#if defined(CORE_OC3A_PIN) | |||||
# define TIMER_PWM_PIN CORE_OC3A_PIN // Teensy | |||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(ARDUINO_AVR_PROMICRO) | |||||
# define TIMER_PWM_PIN 5 // Arduino Mega, Sparkfun Pro Micro | |||||
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) | |||||
# define TIMER_PWM_PIN 6 // MightyCore | |||||
#else | |||||
# error "Please add OC3A pin number here\n" | |||||
#endif | |||||
//--------------------------------------------------------- | |||||
// Timer4 (10 bits, high speed option) | |||||
// | |||||
#elif defined(IR_USE_TIMER4_HS) | |||||
#define TIMER_RESET | |||||
#if defined(ARDUINO_AVR_PROMICRO) // Sparkfun Pro Micro | |||||
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A0)) // Use complimentary O̅C̅4̅A̅ output on pin 5 | |||||
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A0))) // (Pro Micro does not map PC7 (32/ICP3/CLK0/OC4A) | |||||
// of ATmega32U4 ) | |||||
#else | |||||
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) | |||||
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) | |||||
#endif | |||||
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4)) | |||||
#define TIMER_DISABLE_INTR (TIMSK4 = 0) | |||||
#define TIMER_INTR_NAME TIMER4_OVF_vect | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ | |||||
TCCR4A = (1<<PWM4A); \ | |||||
TCCR4B = _BV(CS40); \ | |||||
TCCR4C = 0; \ | |||||
TCCR4D = (1<<WGM40); \ | |||||
TCCR4E = 0; \ | |||||
TC4H = pwmval >> 8; \ | |||||
OCR4C = pwmval; \ | |||||
TC4H = (pwmval / 3) >> 8; \ | |||||
OCR4A = (pwmval / 3) & 255; \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR4A = 0; \ | |||||
TCCR4B = _BV(CS40); \ | |||||
TCCR4C = 0; \ | |||||
TCCR4D = 0; \ | |||||
TCCR4E = 0; \ | |||||
TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \ | |||||
OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \ | |||||
TC4H = 0; \ | |||||
TCNT4 = 0; \ | |||||
}) | |||||
//----------------- | |||||
#if defined(CORE_OC4A_PIN) | |||||
# define TIMER_PWM_PIN CORE_OC4A_PIN // Teensy | |||||
#elif defined(ARDUINO_AVR_PROMICRO) | |||||
# define TIMER_PWM_PIN 5 // Sparkfun Pro Micro | |||||
#elif defined(__AVR_ATmega32U4__) | |||||
# define TIMER_PWM_PIN 13 // Leonardo | |||||
#else | |||||
# error "Please add OC4A pin number here\n" | |||||
#endif | |||||
//--------------------------------------------------------- | |||||
// Timer4 (16 bits) | |||||
// | |||||
#elif defined(IR_USE_TIMER4) | |||||
#define TIMER_RESET | |||||
#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) | |||||
#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) | |||||
#define TIMER_ENABLE_INTR (TIMSK4 = _BV(OCIE4A)) | |||||
#define TIMER_DISABLE_INTR (TIMSK4 = 0) | |||||
#define TIMER_INTR_NAME TIMER4_COMPA_vect | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ | |||||
TCCR4A = _BV(WGM41); \ | |||||
TCCR4B = _BV(WGM43) | _BV(CS40); \ | |||||
ICR4 = pwmval; \ | |||||
OCR4A = pwmval / 3; \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR4A = 0; \ | |||||
TCCR4B = _BV(WGM42) | _BV(CS40); \ | |||||
OCR4A = SYSCLOCK * USECPERTICK / 1000000; \ | |||||
TCNT4 = 0; \ | |||||
}) | |||||
//----------------- | |||||
#if defined(CORE_OC4A_PIN) | |||||
# define TIMER_PWM_PIN CORE_OC4A_PIN | |||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | |||||
# define TIMER_PWM_PIN 6 // Arduino Mega | |||||
#else | |||||
# error "Please add OC4A pin number here\n" | |||||
#endif | |||||
//--------------------------------------------------------- | |||||
// Timer5 (16 bits) | |||||
// | |||||
#elif defined(IR_USE_TIMER5) | |||||
#define TIMER_RESET | |||||
#define TIMER_ENABLE_PWM (TCCR5A |= _BV(COM5A1)) | |||||
#define TIMER_DISABLE_PWM (TCCR5A &= ~(_BV(COM5A1))) | |||||
#define TIMER_ENABLE_INTR (TIMSK5 = _BV(OCIE5A)) | |||||
#define TIMER_DISABLE_INTR (TIMSK5 = 0) | |||||
#define TIMER_INTR_NAME TIMER5_COMPA_vect | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ | |||||
TCCR5A = _BV(WGM51); \ | |||||
TCCR5B = _BV(WGM53) | _BV(CS50); \ | |||||
ICR5 = pwmval; \ | |||||
OCR5A = pwmval / 3; \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR5A = 0; \ | |||||
TCCR5B = _BV(WGM52) | _BV(CS50); \ | |||||
OCR5A = SYSCLOCK * USECPERTICK / 1000000; \ | |||||
TCNT5 = 0; \ | |||||
}) | |||||
//----------------- | |||||
#if defined(CORE_OC5A_PIN) | |||||
# define TIMER_PWM_PIN CORE_OC5A_PIN | |||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | |||||
# define TIMER_PWM_PIN 46 // Arduino Mega | |||||
#else | |||||
# error "Please add OC5A pin number here\n" | |||||
#endif | |||||
//--------------------------------------------------------- | |||||
// Special carrier modulator timer | |||||
// | |||||
#elif defined(IR_USE_TIMER_CMT) | |||||
#define TIMER_RESET ({ \ | |||||
uint8_t tmp __attribute__((unused)) = CMT_MSC; \ | |||||
CMT_CMD2 = 30; \ | |||||
}) | |||||
#define TIMER_ENABLE_PWM do { \ | |||||
CORE_PIN5_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE | PORT_PCR_SRE; \ | |||||
} while(0) | |||||
#define TIMER_DISABLE_PWM do { \ | |||||
CORE_PIN5_CONFIG = PORT_PCR_MUX(1) | PORT_PCR_DSE | PORT_PCR_SRE; \ | |||||
} while(0) | |||||
#define TIMER_ENABLE_INTR NVIC_ENABLE_IRQ(IRQ_CMT) | |||||
#define TIMER_DISABLE_INTR NVIC_DISABLE_IRQ(IRQ_CMT) | |||||
#define TIMER_INTR_NAME cmt_isr | |||||
//----------------- | |||||
#ifdef ISR | |||||
# undef ISR | |||||
#endif | |||||
#define ISR(f) void f(void) | |||||
//----------------- | |||||
#define CMT_PPS_DIV ((F_BUS + 7999999) / 8000000) | |||||
#if F_BUS < 8000000 | |||||
#error IRremote requires at least 8 MHz on Teensy 3.x | |||||
#endif | |||||
//----------------- | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
SIM_SCGC4 |= SIM_SCGC4_CMT; \ | |||||
SIM_SOPT2 |= SIM_SOPT2_PTD7PAD; \ | |||||
CMT_PPS = CMT_PPS_DIV - 1; \ | |||||
CMT_CGH1 = ((F_BUS / CMT_PPS_DIV / 3000) + ((val)/2)) / (val); \ | |||||
CMT_CGL1 = ((F_BUS / CMT_PPS_DIV / 1500) + ((val)/2)) / (val); \ | |||||
CMT_CMD1 = 0; \ | |||||
CMT_CMD2 = 30; \ | |||||
CMT_CMD3 = 0; \ | |||||
CMT_CMD4 = 0; \ | |||||
CMT_OC = 0x60; \ | |||||
CMT_MSC = 0x01; \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
SIM_SCGC4 |= SIM_SCGC4_CMT; \ | |||||
CMT_PPS = CMT_PPS_DIV - 1; \ | |||||
CMT_CGH1 = 1; \ | |||||
CMT_CGL1 = 1; \ | |||||
CMT_CMD1 = 0; \ | |||||
CMT_CMD2 = 30; \ | |||||
CMT_CMD3 = 0; \ | |||||
CMT_CMD4 = (F_BUS / 160000 + CMT_PPS_DIV / 2) / CMT_PPS_DIV - 31; \ | |||||
CMT_OC = 0; \ | |||||
CMT_MSC = 0x03; \ | |||||
}) | |||||
#define TIMER_PWM_PIN 5 | |||||
// defines for TPM1 timer on Teensy-LC | |||||
#elif defined(IR_USE_TIMER_TPM1) | |||||
#define TIMER_RESET FTM1_SC |= FTM_SC_TOF; | |||||
#define TIMER_ENABLE_PWM CORE_PIN16_CONFIG = PORT_PCR_MUX(3)|PORT_PCR_DSE|PORT_PCR_SRE | |||||
#define TIMER_DISABLE_PWM CORE_PIN16_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_SRE | |||||
#define TIMER_ENABLE_INTR NVIC_ENABLE_IRQ(IRQ_FTM1) | |||||
#define TIMER_DISABLE_INTR NVIC_DISABLE_IRQ(IRQ_FTM1) | |||||
#define TIMER_INTR_NAME ftm1_isr | |||||
#ifdef ISR | |||||
#undef ISR | |||||
#endif | |||||
#define ISR(f) void f(void) | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
SIM_SCGC6 |= SIM_SCGC6_TPM1; \ | |||||
FTM1_SC = 0; \ | |||||
FTM1_CNT = 0; \ | |||||
FTM1_MOD = (F_PLL/2000) / val - 1; \ | |||||
FTM1_C0V = (F_PLL/6000) / val - 1; \ | |||||
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0); \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
SIM_SCGC6 |= SIM_SCGC6_TPM1; \ | |||||
FTM1_SC = 0; \ | |||||
FTM1_CNT = 0; \ | |||||
FTM1_MOD = (F_PLL/40000) - 1; \ | |||||
FTM1_C0V = 0; \ | |||||
FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0) | FTM_SC_TOF | FTM_SC_TOIE; \ | |||||
}) | |||||
#define TIMER_PWM_PIN 16 | |||||
// defines for FlexPWM1 timer on Teensy 4 | |||||
#elif defined(IR_USE_TIMER_FLEXPWM1) | |||||
#define TIMER_RESET FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF; | |||||
#define TIMER_ENABLE_PWM FLEXPWM1_OUTEN |= FLEXPWM_OUTEN_PWMA_EN(8), \ | |||||
IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 6 | |||||
#define TIMER_DISABLE_PWM IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 5, \ | |||||
FLEXPWM1_OUTEN &= ~FLEXPWM_OUTEN_PWMA_EN(8) | |||||
#define TIMER_ENABLE_INTR attachInterruptVector(IRQ_FLEXPWM1_3, pwm1_3_isr),\ | |||||
FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF, \ | |||||
FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_RIE, \ | |||||
NVIC_ENABLE_IRQ(IRQ_FLEXPWM1_3) | |||||
#define TIMER_DISABLE_INTR NVIC_DISABLE_IRQ(IRQ_FLEXPWM1_3) | |||||
#define TIMER_INTR_NAME pwm1_3_isr | |||||
#define TIMER_INT_DECLARE void pwm1_3_isr(void); | |||||
#ifdef ISR | |||||
#undef ISR | |||||
#endif | |||||
#define ISR(f) void f(void) | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
uint32_t period = (float)F_BUS_ACTUAL / (float)((val) * 2000); \ | |||||
uint32_t prescale = 0; \ | |||||
while (period > 32767) { \ | |||||
period = period >> 1; \ | |||||
if (prescale < 7) prescale++; \ | |||||
} \ | |||||
FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(8); \ | |||||
FLEXPWM1_FSTS0 = 0x0008; \ | |||||
FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8); \ | |||||
FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP; \ | |||||
FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale); \ | |||||
FLEXPWM1_SM3INIT = -period; \ | |||||
FLEXPWM1_SM3VAL0 = 0; \ | |||||
FLEXPWM1_SM3VAL1 = period; \ | |||||
FLEXPWM1_SM3VAL2 = -(period / 3); \ | |||||
FLEXPWM1_SM3VAL3 = period / 3; \ | |||||
FLEXPWM1_SM3VAL4 = 0; \ | |||||
FLEXPWM1_SM3VAL5 = 0; \ | |||||
FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8) | FLEXPWM_MCTRL_RUN(8); \ | |||||
}) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
uint32_t period = (float)F_BUS_ACTUAL * (float)USECPERTICK * 0.0000005f; \ | |||||
uint32_t prescale = 0; \ | |||||
while (period > 32767) { \ | |||||
period = period >> 1; \ | |||||
if (prescale < 7) prescale++; \ | |||||
} \ | |||||
FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(8); \ | |||||
FLEXPWM1_FSTS0 = 0x0008; \ | |||||
FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8); \ | |||||
FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP; \ | |||||
FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale); \ | |||||
FLEXPWM1_SM3INIT = -period; \ | |||||
FLEXPWM1_SM3VAL0 = 0; \ | |||||
FLEXPWM1_SM3VAL1 = period; \ | |||||
FLEXPWM1_SM3VAL2 = 0; \ | |||||
FLEXPWM1_SM3VAL3 = 0; \ | |||||
FLEXPWM1_SM3VAL4 = 0; \ | |||||
FLEXPWM1_SM3VAL5 = 0; \ | |||||
FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8) | FLEXPWM_MCTRL_RUN(8); \ | |||||
}) | |||||
#define TIMER_PWM_PIN 7 | |||||
// defines for timer_tiny0 (8 bits) | |||||
#elif defined(IR_USE_TIMER_TINY0) | |||||
#define TIMER_RESET | |||||
#define TIMER_ENABLE_PWM (TCCR0A |= _BV(COM0B1)) | |||||
#define TIMER_DISABLE_PWM (TCCR0A &= ~(_BV(COM0B1))) | |||||
#define TIMER_ENABLE_INTR (TIMSK |= _BV(OCIE0A)) | |||||
#define TIMER_DISABLE_INTR (TIMSK &= ~(_BV(OCIE0A))) | |||||
#define TIMER_INTR_NAME TIMER0_COMPA_vect | |||||
#define TIMER_CONFIG_KHZ(val) ({ \ | |||||
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \ | |||||
TCCR0A = _BV(WGM00); \ | |||||
TCCR0B = _BV(WGM02) | _BV(CS00); \ | |||||
OCR0A = pwmval; \ | |||||
OCR0B = pwmval / 3; \ | |||||
}) | |||||
#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) | |||||
#if (TIMER_COUNT_TOP < 256) | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR0A = _BV(WGM01); \ | |||||
TCCR0B = _BV(CS00); \ | |||||
OCR0A = TIMER_COUNT_TOP; \ | |||||
TCNT0 = 0; \ | |||||
}) | |||||
#else | |||||
#define TIMER_CONFIG_NORMAL() ({ \ | |||||
TCCR0A = _BV(WGM01); \ | |||||
TCCR0B = _BV(CS01); \ | |||||
OCR0A = TIMER_COUNT_TOP / 8; \ | |||||
TCNT0 = 0; \ | |||||
}) | |||||
#endif | |||||
#define TIMER_PWM_PIN 1 /* ATtiny85 */ | |||||
//--------------------------------------------------------- | |||||
// ESP32 (ESP8266 should likely be added here too) | |||||
// | |||||
// ESP32 has it own timer API and does not use these macros, but to avoid ifdef'ing | |||||
// them out in the common code, they are defined to no-op. This allows the code to compile | |||||
// (which it wouldn't otherwise) but irsend will not work until ESP32 specific code is written | |||||
// for that -- merlin | |||||
// As a warning, sending timing specific code from an ESP32 can be challenging if you need 100% | |||||
// reliability because the arduino code may be interrupted and cause your sent waveform to be the | |||||
// wrong length. This is specifically an issue for neopixels which require 800Khz resolution. | |||||
// IR may just work as is with the common code since it's lower frequency, but if not, the other | |||||
// way to do this on ESP32 is using the RMT built in driver like in this incomplete library below | |||||
// https://github.com/ExploreEmbedded/ESP32_RMT | |||||
#elif defined(IR_TIMER_USE_ESP32) | |||||
#define TIMER_RESET | |||||
#define TIMER_ENABLE_PWM | |||||
#define TIMER_DISABLE_PWM Serial.println("IRsend not implemented for ESP32 yet"); | |||||
#define TIMER_ENABLE_INTR | |||||
#define TIMER_DISABLE_INTR | |||||
#define TIMER_INTR_NAME | |||||
//--------------------------------------------------------- | |||||
// Unknown Timer | |||||
// | |||||
#else | |||||
# error "Internal code configuration error, no known IR_USE_TIMER# defined\n" | |||||
#endif | |||||
#endif // ! boarddefs_h |
//============================================================================== | |||||
// L EEEEEE EEEE OOOO | |||||
// L E E O O | |||||
// L EEEE E EEE O O | |||||
// L E E E O O LEGO Power Functions | |||||
// LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016, 2017 Philipp Henkel | |||||
//============================================================================== | |||||
//+============================================================================= | |||||
// | |||||
class LegoPfBitStreamEncoder { | |||||
private: | |||||
uint16_t data; | |||||
bool repeatMessage; | |||||
uint8_t messageBitIdx; | |||||
uint8_t repeatCount; | |||||
uint16_t messageLength; | |||||
public: | |||||
// HIGH data bit = IR mark + high pause | |||||
// LOW data bit = IR mark + low pause | |||||
static const uint16_t LOW_BIT_DURATION = 421; | |||||
static const uint16_t HIGH_BIT_DURATION = 711; | |||||
static const uint16_t START_BIT_DURATION = 1184; | |||||
static const uint16_t STOP_BIT_DURATION = 1184; | |||||
static const uint8_t IR_MARK_DURATION = 158; | |||||
static const uint16_t HIGH_PAUSE_DURATION = HIGH_BIT_DURATION - IR_MARK_DURATION; | |||||
static const uint16_t LOW_PAUSE_DURATION = LOW_BIT_DURATION - IR_MARK_DURATION; | |||||
static const uint16_t START_PAUSE_DURATION = START_BIT_DURATION - IR_MARK_DURATION; | |||||
static const uint16_t STOP_PAUSE_DURATION = STOP_BIT_DURATION - IR_MARK_DURATION; | |||||
static const uint8_t MESSAGE_BITS = 18; | |||||
static const uint16_t MAX_MESSAGE_LENGTH = 16000; | |||||
void reset(uint16_t data, bool repeatMessage) { | |||||
this->data = data; | |||||
this->repeatMessage = repeatMessage; | |||||
messageBitIdx = 0; | |||||
repeatCount = 0; | |||||
messageLength = getMessageLength(); | |||||
} | |||||
int getChannelId() const { return 1 + ((data >> 12) & 0x3); } | |||||
uint16_t getMessageLength() const { | |||||
// Sum up all marks | |||||
uint16_t length = MESSAGE_BITS * IR_MARK_DURATION; | |||||
// Sum up all pauses | |||||
length += START_PAUSE_DURATION; | |||||
for (unsigned long mask = 1UL << 15; mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
length += HIGH_PAUSE_DURATION; | |||||
} else { | |||||
length += LOW_PAUSE_DURATION; | |||||
} | |||||
} | |||||
length += STOP_PAUSE_DURATION; | |||||
return length; | |||||
} | |||||
boolean next() { | |||||
messageBitIdx++; | |||||
if (messageBitIdx >= MESSAGE_BITS) { | |||||
repeatCount++; | |||||
messageBitIdx = 0; | |||||
} | |||||
if (repeatCount >= 1 && !repeatMessage) { | |||||
return false; | |||||
} else if (repeatCount >= 5) { | |||||
return false; | |||||
} else { | |||||
return true; | |||||
} | |||||
} | |||||
uint8_t getMarkDuration() const { return IR_MARK_DURATION; } | |||||
uint32_t getPauseDuration() const { | |||||
if (messageBitIdx == 0) | |||||
return START_PAUSE_DURATION; | |||||
else if (messageBitIdx < MESSAGE_BITS - 1) { | |||||
return getDataBitPause(); | |||||
} else { | |||||
return getStopPause(); | |||||
} | |||||
} | |||||
private: | |||||
uint16_t getDataBitPause() const { | |||||
const int pos = MESSAGE_BITS - 2 - messageBitIdx; | |||||
const bool isHigh = data & (1 << pos); | |||||
return isHigh ? HIGH_PAUSE_DURATION : LOW_PAUSE_DURATION; | |||||
} | |||||
uint32_t getStopPause() const { | |||||
if (repeatMessage) { | |||||
return getRepeatStopPause(); | |||||
} else { | |||||
return STOP_PAUSE_DURATION; | |||||
} | |||||
} | |||||
uint32_t getRepeatStopPause() const { | |||||
if (repeatCount == 0 || repeatCount == 1) { | |||||
return STOP_PAUSE_DURATION + (uint32_t)5 * MAX_MESSAGE_LENGTH - messageLength; | |||||
} else if (repeatCount == 2 || repeatCount == 3) { | |||||
return STOP_PAUSE_DURATION | |||||
+ (uint32_t)(6 + 2 * getChannelId()) * MAX_MESSAGE_LENGTH - messageLength; | |||||
} else { | |||||
return STOP_PAUSE_DURATION; | |||||
} | |||||
} | |||||
}; |
//****************************************************************************** | |||||
// IRremote | |||||
// Version 2.0.1 June, 2015 | |||||
// Copyright 2009 Ken Shirriff | |||||
// For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html | |||||
// | |||||
// Modified by Paul Stoffregen <paul@pjrc.com> to support other boards and timers | |||||
// Modified by Mitra Ardron <mitra@mitra.biz> | |||||
// Added Sanyo and Mitsubishi controllers | |||||
// Modified Sony to spot the repeat codes that some Sony's send | |||||
// | |||||
// 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 | |||||
//****************************************************************************** | |||||
// Defining IR_GLOBAL here allows us to declare the instantiation of global variables | |||||
#define IR_GLOBAL | |||||
# include "irr/IRremote.h" | |||||
# include "irr/IRremoteInt.h" | |||||
#undef IR_GLOBAL | |||||
#ifndef IR_TIMER_USE_ESP32 | |||||
#include <core/avr/interrupt.h> | |||||
#endif | |||||
//+============================================================================= | |||||
// The match functions were (apparently) originally MACROs to improve code speed | |||||
// (although this would have bloated the code) hence the names being CAPS | |||||
// A later release implemented debug output and so they needed to be converted | |||||
// to functions. | |||||
// I tried to implement a dual-compile mode (DEBUG/non-DEBUG) but for some | |||||
// reason, no matter what I did I could not get them to function as macros again. | |||||
// I have found a *lot* of bugs in the Arduino compiler over the last few weeks, | |||||
// and I am currently assuming that one of these bugs is my problem. | |||||
// I may revisit this code at a later date and look at the assembler produced | |||||
// in a hope of finding out what is going on, but for now they will remain as | |||||
// functions even in non-DEBUG mode | |||||
// | |||||
int MATCH (int measured, int desired) | |||||
{ | |||||
DBG_PRINT(F("Testing: ")); | |||||
DBG_PRINT(TICKS_LOW(desired), DEC); | |||||
DBG_PRINT(F(" <= ")); | |||||
DBG_PRINT(measured, DEC); | |||||
DBG_PRINT(F(" <= ")); | |||||
DBG_PRINT(TICKS_HIGH(desired), DEC); | |||||
bool passed = ((measured >= TICKS_LOW(desired)) && (measured <= TICKS_HIGH(desired))); | |||||
if (passed) { | |||||
DBG_PRINTLN(F("?; passed")); | |||||
} else { | |||||
DBG_PRINTLN(F("?; FAILED")); | |||||
} | |||||
return passed; | |||||
} | |||||
//+======================================================== | |||||
// Due to sensor lag, when received, Marks tend to be 100us too long | |||||
// | |||||
int MATCH_MARK (int measured_ticks, int desired_us) | |||||
{ | |||||
DBG_PRINT(F("Testing mark (actual vs desired): ")); | |||||
DBG_PRINT(measured_ticks * USECPERTICK, DEC); | |||||
DBG_PRINT(F("us vs ")); | |||||
DBG_PRINT(desired_us, DEC); | |||||
DBG_PRINT("us"); | |||||
DBG_PRINT(": "); | |||||
DBG_PRINT(TICKS_LOW(desired_us + MARK_EXCESS) * USECPERTICK, DEC); | |||||
DBG_PRINT(F(" <= ")); | |||||
DBG_PRINT(measured_ticks * USECPERTICK, DEC); | |||||
DBG_PRINT(F(" <= ")); | |||||
DBG_PRINT(TICKS_HIGH(desired_us + MARK_EXCESS) * USECPERTICK, DEC); | |||||
bool passed = ((measured_ticks >= TICKS_LOW (desired_us + MARK_EXCESS)) | |||||
&& (measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS))); | |||||
if (passed) { | |||||
DBG_PRINTLN(F("?; passed")); | |||||
} else { | |||||
DBG_PRINTLN(F("?; FAILED")); | |||||
} | |||||
return passed; | |||||
} | |||||
//+======================================================== | |||||
// Due to sensor lag, when received, Spaces tend to be 100us too short | |||||
// | |||||
int MATCH_SPACE (int measured_ticks, int desired_us) | |||||
{ | |||||
DBG_PRINT(F("Testing space (actual vs desired): ")); | |||||
DBG_PRINT(measured_ticks * USECPERTICK, DEC); | |||||
DBG_PRINT(F("us vs ")); | |||||
DBG_PRINT(desired_us, DEC); | |||||
DBG_PRINT("us"); | |||||
DBG_PRINT(": "); | |||||
DBG_PRINT(TICKS_LOW(desired_us - MARK_EXCESS) * USECPERTICK, DEC); | |||||
DBG_PRINT(F(" <= ")); | |||||
DBG_PRINT(measured_ticks * USECPERTICK, DEC); | |||||
DBG_PRINT(F(" <= ")); | |||||
DBG_PRINT(TICKS_HIGH(desired_us - MARK_EXCESS) * USECPERTICK, DEC); | |||||
bool passed = ((measured_ticks >= TICKS_LOW (desired_us - MARK_EXCESS)) | |||||
&& (measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS))); | |||||
if (passed) { | |||||
DBG_PRINTLN(F("?; passed")); | |||||
} else { | |||||
DBG_PRINTLN(F("?; FAILED")); | |||||
} | |||||
return passed; | |||||
} | |||||
//+============================================================================= | |||||
// Interrupt Service Routine - Fires every 50uS | |||||
// TIMER2 interrupt code to collect raw data. | |||||
// Widths of alternating SPACE, MARK are recorded in rawbuf. | |||||
// Recorded in ticks of 50uS [microseconds, 0.000050 seconds] | |||||
// 'rawlen' counts the number of entries recorded so far. | |||||
// First entry is the SPACE between transmissions. | |||||
// As soon as a the first [SPACE] entry gets long: | |||||
// Ready is set; State switches to IDLE; Timing of SPACE continues. | |||||
// As soon as first MARK arrives: | |||||
// Gap width is recorded; Ready is cleared; New logging starts | |||||
// | |||||
#ifdef IR_TIMER_USE_ESP32 | |||||
void IRTimer() | |||||
#else | |||||
ISR (TIMER_INTR_NAME) | |||||
#endif | |||||
{ | |||||
TIMER_RESET; | |||||
// Read if IR Receiver -> SPACE [xmt LED off] or a MARK [xmt LED on] | |||||
// digitalRead() is very slow. Optimisation is possible, but makes the code unportable | |||||
uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin); | |||||
irparams.timer++; // One more 50uS tick | |||||
if (irparams.rawlen >= RAWBUF) irparams.rcvstate = STATE_OVERFLOW ; // Buffer overflow | |||||
switch(irparams.rcvstate) { | |||||
//...................................................................... | |||||
case STATE_IDLE: // In the middle of a gap | |||||
if (irdata == MARK) { | |||||
if (irparams.timer < GAP_TICKS) { // Not big enough to be a gap. | |||||
irparams.timer = 0; | |||||
} else { | |||||
// Gap just ended; Record duration; Start recording transmission | |||||
irparams.overflow = false; | |||||
irparams.rawlen = 0; | |||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer; | |||||
irparams.timer = 0; | |||||
irparams.rcvstate = STATE_MARK; | |||||
} | |||||
} | |||||
break; | |||||
//...................................................................... | |||||
case STATE_MARK: // Timing Mark | |||||
if (irdata == SPACE) { // Mark ended; Record time | |||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer; | |||||
irparams.timer = 0; | |||||
irparams.rcvstate = STATE_SPACE; | |||||
} | |||||
break; | |||||
//...................................................................... | |||||
case STATE_SPACE: // Timing Space | |||||
if (irdata == MARK) { // Space just ended; Record time | |||||
irparams.rawbuf[irparams.rawlen++] = irparams.timer; | |||||
irparams.timer = 0; | |||||
irparams.rcvstate = STATE_MARK; | |||||
} else if (irparams.timer > GAP_TICKS) { // Space | |||||
// A long Space, indicates gap between codes | |||||
// Flag the current code as ready for processing | |||||
// Switch to STOP | |||||
// Don't reset timer; keep counting Space width | |||||
irparams.rcvstate = STATE_STOP; | |||||
} | |||||
break; | |||||
//...................................................................... | |||||
case STATE_STOP: // Waiting; Measuring Gap | |||||
if (irdata == MARK) irparams.timer = 0 ; // Reset gap timer | |||||
break; | |||||
//...................................................................... | |||||
case STATE_OVERFLOW: // Flag up a read overflow; Stop the State Machine | |||||
irparams.overflow = true; | |||||
irparams.rcvstate = STATE_STOP; | |||||
break; | |||||
} | |||||
// If requested, flash LED while receiving IR data | |||||
if (irparams.blinkflag) { | |||||
if (irdata == MARK) | |||||
if (irparams.blinkpin) digitalWrite(irparams.blinkpin, HIGH); // Turn user defined pin LED on | |||||
else BLINKLED_ON() ; // if no user defined LED pin, turn default LED pin for the hardware on | |||||
else if (irparams.blinkpin) digitalWrite(irparams.blinkpin, LOW); // Turn user defined pin LED on | |||||
else BLINKLED_OFF() ; // if no user defined LED pin, turn default LED pin for the hardware on | |||||
} | |||||
} |
#define TEST 0 | |||||
#if TEST | |||||
# define SEND_PRONTO 1 | |||||
# define PRONTO_ONCE false | |||||
# define PRONTO_REPEAT true | |||||
# define PRONTO_FALLBACK true | |||||
# define PRONTO_NOFALLBACK false | |||||
#endif | |||||
#if SEND_PRONTO | |||||
//****************************************************************************** | |||||
#if TEST | |||||
# include <stdio.h> | |||||
void enableIROut (int freq) { printf("\nFreq = %d KHz\n", freq); } | |||||
void mark (int t) { printf("+%d," , t); } | |||||
void space (int t) { printf("-%d, ", t); } | |||||
#else | |||||
# include "irr/IRremote.h" | |||||
#endif // TEST | |||||
//+============================================================================= | |||||
// Check for a valid hex digit | |||||
// | |||||
bool ishex (char ch) | |||||
{ | |||||
return ( ((ch >= '0') && (ch <= '9')) || | |||||
((ch >= 'A') && (ch <= 'F')) || | |||||
((ch >= 'a') && (ch <= 'f')) ) ? true : false ; | |||||
} | |||||
//+============================================================================= | |||||
// Check for a valid "blank" ... '\0' is a valid "blank" | |||||
// | |||||
bool isblank (char ch) | |||||
{ | |||||
return ((ch == ' ') || (ch == '\t') || (ch == '\0')) ? true : false ; | |||||
} | |||||
//+============================================================================= | |||||
// Bypass spaces | |||||
// | |||||
bool byp (char** pcp) | |||||
{ | |||||
while (isblank(**pcp)) (*pcp)++ ; | |||||
} | |||||
//+============================================================================= | |||||
// Hex-to-Byte : Decode a hex digit | |||||
// We assume the character has already been validated | |||||
// | |||||
uint8_t htob (char ch) | |||||
{ | |||||
if ((ch >= '0') && (ch <= '9')) return ch - '0' ; | |||||
if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10 ; | |||||
if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10 ; | |||||
} | |||||
//+============================================================================= | |||||
// Hex-to-Word : Decode a block of 4 hex digits | |||||
// We assume the string has already been validated | |||||
// and the pointer being passed points at the start of a block of 4 hex digits | |||||
// | |||||
uint16_t htow (char* cp) | |||||
{ | |||||
return ( (htob(cp[0]) << 12) | (htob(cp[1]) << 8) | | |||||
(htob(cp[2]) << 4) | (htob(cp[3]) ) ) ; | |||||
} | |||||
//+============================================================================= | |||||
// | |||||
bool sendPronto (char* s, bool repeat, bool fallback) | |||||
{ | |||||
int i; | |||||
int len; | |||||
int skip; | |||||
char* cp; | |||||
uint16_t freq; // Frequency in KHz | |||||
uint8_t usec; // pronto uSec/tick | |||||
uint8_t once; | |||||
uint8_t rpt; | |||||
// Validate the string | |||||
for (cp = s; *cp; cp += 4) { | |||||
byp(&cp); | |||||
if ( !ishex(cp[0]) || !ishex(cp[1]) || | |||||
!ishex(cp[2]) || !ishex(cp[3]) || !isblank(cp[4]) ) return false ; | |||||
} | |||||
// We will use cp to traverse the string | |||||
cp = s; | |||||
// Check mode = Oscillated/Learned | |||||
byp(&cp); | |||||
if (htow(cp) != 0000) return false; | |||||
cp += 4; | |||||
// Extract & set frequency | |||||
byp(&cp); | |||||
freq = (int)(1000000 / (htow(cp) * 0.241246)); // Rounding errors will occur, tolerance is +/- 10% | |||||
usec = (int)(((1.0 / freq) * 1000000) + 0.5); // Another rounding error, thank Cod for analogue electronics | |||||
freq /= 1000; // This will introduce a(nother) rounding error which we do not want in the usec calcualtion | |||||
cp += 4; | |||||
// Get length of "once" code | |||||
byp(&cp); | |||||
once = htow(cp); | |||||
cp += 4; | |||||
// Get length of "repeat" code | |||||
byp(&cp); | |||||
rpt = htow(cp); | |||||
cp += 4; | |||||
// Which code are we sending? | |||||
if (fallback) { // fallback on the "other" code if "this" code is not present | |||||
if (!repeat) { // requested 'once' | |||||
if (once) len = once * 2, skip = 0 ; // if once exists send it | |||||
else len = rpt * 2, skip = 0 ; // else send repeat code | |||||
} else { // requested 'repeat' | |||||
if (rpt) len = rpt * 2, skip = 0 ; // if rpt exists send it | |||||
else len = once * 2, skip = 0 ; // else send once code | |||||
} | |||||
} else { // Send what we asked for, do not fallback if the code is empty! | |||||
if (!repeat) len = once * 2, skip = 0 ; // 'once' starts at 0 | |||||
else len = rpt * 2, skip = once ; // 'repeat' starts where 'once' ends | |||||
} | |||||
// Skip to start of code | |||||
for (i = 0; i < skip; i++, cp += 4) byp(&cp) ; | |||||
// Send code | |||||
enableIROut(freq); | |||||
for (i = 0; i < len; i++) { | |||||
byp(&cp); | |||||
if (i & 1) space(htow(cp) * usec); | |||||
else mark (htow(cp) * usec); | |||||
cp += 4; | |||||
} | |||||
} | |||||
//+============================================================================= | |||||
#if TEST | |||||
int main ( ) | |||||
{ | |||||
char prontoTest[] = | |||||
"0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 " // 10 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 20 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 30 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 40 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 50 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 60 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 70 | |||||
"0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 " // 80 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 90 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 100 | |||||
"0010 0030 0010 0aa6"; // 104 | |||||
sendPronto(prontoTest, PRONTO_ONCE, PRONTO_FALLBACK); // once code | |||||
sendPronto(prontoTest, PRONTO_REPEAT, PRONTO_FALLBACK); // repeat code | |||||
sendPronto(prontoTest, PRONTO_ONCE, PRONTO_NOFALLBACK); // once code | |||||
sendPronto(prontoTest, PRONTO_REPEAT, PRONTO_NOFALLBACK); // repeat code | |||||
return 0; | |||||
} | |||||
#endif // TEST | |||||
#endif // SEND_PRONTO | |||||
#if 0 | |||||
//****************************************************************************** | |||||
// Sources: | |||||
// http://www.remotecentral.com/features/irdisp2.htm | |||||
// http://www.hifi-remote.com/wiki/index.php?title=Working_With_Pronto_Hex | |||||
//****************************************************************************** | |||||
#include <stdint.h> | |||||
#include <stdio.h> | |||||
#define IRPRONTO | |||||
#include "irr/IRremoteInt.h" // The Arduino IRremote library defines USECPERTICK | |||||
//------------------------------------------------------------------------------ | |||||
// Source: https://www.google.co.uk/search?q=DENON+MASTER+IR+Hex+Command+Sheet | |||||
// -> http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls | |||||
// | |||||
char prontoTest[] = | |||||
"0000 0070 0000 0032 0080 0040 0010 0010 0010 0030 " // 10 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 20 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 30 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 40 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 50 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0010 " // 60 | |||||
"0010 0010 0010 0010 0010 0010 0010 0010 0010 0010 " // 70 | |||||
"0010 0010 0010 0030 0010 0010 0010 0030 0010 0010 " // 80 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 90 | |||||
"0010 0010 0010 0030 0010 0010 0010 0010 0010 0030 " // 100 | |||||
"0010 0030 0010 0aa6"; // 104 | |||||
//------------------------------------------------------------------------------ | |||||
// This is the longest code we can support | |||||
#define CODEMAX 200 | |||||
//------------------------------------------------------------------------------ | |||||
// This is the data we pull out of the pronto code | |||||
typedef | |||||
struct { | |||||
int freq; // Carrier frequency (in Hz) | |||||
int usec; // uSec per tick (based on freq) | |||||
int codeLen; // Length of code | |||||
uint16_t code[CODEMAX]; // Code in hex | |||||
int onceLen; // Length of "once" transmit | |||||
uint16_t* once; // Pointer to start within 'code' | |||||
int rptLen; // Length of "repeat" transmit | |||||
uint16_t* rpt; // Pointer to start within 'code' | |||||
} | |||||
pronto_t; | |||||
//------------------------------------------------------------------------------ | |||||
// From what I have seen, the only time we go over 8-bits is the 'space' | |||||
// on the end which creates the lead-out/inter-code gap. Assuming I'm right, | |||||
// we can code this up as a special case and otherwise halve the size of our | |||||
// data! | |||||
// Ignoring the first four values (the config data) and the last value | |||||
// (the lead-out), if you find a protocol that uses values greater than 00fe | |||||
// we are going to have to revisit this code! | |||||
// | |||||
// | |||||
// So, the 0th byte will be the carrier frequency in Khz (NOT Hz) | |||||
// " 1st " " " " length of the "once" code | |||||
// " 2nd " " " " length of the "repeat" code | |||||
// | |||||
// Thereafter, odd bytes will be Mark lengths as a multiple of USECPERTICK uS | |||||
// even " " " Space " " " " " " " | |||||
// | |||||
// Any occurence of "FF" in either a Mark or a Space will indicate | |||||
// "Use the 16-bit FF value" which will also be a multiple of USECPERTICK uS | |||||
// | |||||
// | |||||
// As a point of comparison, the test code (prontoTest[]) is 520 bytes | |||||
// (yes, more than 0.5KB of our Arduino's precious 32KB) ... after conversion | |||||
// to pronto hex that goes down to ((520/5)*2) = 208 bytes ... once converted to | |||||
// our format we are down to ((208/2) -1 -1 +2) = 104 bytes | |||||
// | |||||
// In fariness this is still very memory-hungry | |||||
// ...As a rough guide: | |||||
// 10 codes cost 1K of memory (this will vary depending on the protocol). | |||||
// | |||||
// So if you're building a complex remote control, you will probably need to | |||||
// keep the codes on an external memory device (not in the Arduino sketch) and | |||||
// load them as you need them. Hmmm. | |||||
// | |||||
// This dictates that "Oscillated Pronto Codes" are probably NOT the way forward | |||||
// | |||||
// For example, prontoTest[] happens to be: A 48-bit IR code in Denon format | |||||
// So we know it starts with 80/40 (Denon header) | |||||
// and ends with 10/aa6 (Denon leadout) | |||||
// and all (48) bits in between are either 10/10 (Denon 0) | |||||
// or 10/30 (Denon 1) | |||||
// So we could easily store this data in 1-byte ("Denon") | |||||
// + 1-byte (Length=48) | |||||
// + 6-bytes (IR code) | |||||
// At 8-bytes per code, we can store 128 codes in 1KB or memory - that's a lot | |||||
// better than the 2 (two) we started off with! | |||||
// | |||||
// And serendipitously, by reducing the amount of data, our program will run | |||||
// a LOT faster! | |||||
// | |||||
// Again, I repeat, even after you have spent time converting the "Oscillated | |||||
// Pronto Codes" in to IRremote format, it will be a LOT more memory-hungry | |||||
// than using sendDenon() (or whichever) ...BUT these codes are easily | |||||
// available on the internet, so we'll support them! | |||||
// | |||||
typedef | |||||
struct { | |||||
uint16_t FF; | |||||
uint8_t code[CODEMAX]; | |||||
} | |||||
irCode_t; | |||||
//------------------------------------------------------------------------------ | |||||
#define DEBUGF(...) printf(__VA_ARGS__) | |||||
//+============================================================================= | |||||
// String must be block of 4 hex digits separated with blanks | |||||
// | |||||
bool validate (char* cp, int* len) | |||||
{ | |||||
for (*len = 0; *cp; (*len)++, cp += 4) { | |||||
byp(&cp); | |||||
if ( !ishex(cp[0]) || !ishex(cp[1]) || | |||||
!ishex(cp[2]) || !ishex(cp[3]) || !isblank(cp[4]) ) return false ; | |||||
} | |||||
return true; | |||||
} | |||||
//+============================================================================= | |||||
// Hex-to-Byte : Decode a hex digit | |||||
// We assume the character has already been validated | |||||
// | |||||
uint8_t htob (char ch) | |||||
{ | |||||
if ((ch >= '0') && (ch <= '9')) return ch - '0' ; | |||||
if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10 ; | |||||
if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10 ; | |||||
} | |||||
//+============================================================================= | |||||
// Hex-to-Word : Decode a block of 4 hex digits | |||||
// We assume the string has already been validated | |||||
// and the pointer being passed points at the start of a block of 4 hex digits | |||||
// | |||||
uint16_t htow (char* cp) | |||||
{ | |||||
return ( (htob(cp[0]) << 12) | (htob(cp[1]) << 8) | | |||||
(htob(cp[2]) << 4) | (htob(cp[3]) ) ) ; | |||||
} | |||||
//+============================================================================= | |||||
// Convert the pronto string in to data | |||||
// | |||||
bool decode (char* s, pronto_t* p, irCode_t* ir) | |||||
{ | |||||
int i, len; | |||||
char* cp; | |||||
// Validate the Pronto string | |||||
if (!validate(s, &p->codeLen)) { | |||||
DEBUGF("Invalid pronto string\n"); | |||||
return false ; | |||||
} | |||||
DEBUGF("Found %d hex codes\n", p->codeLen); | |||||
// Allocate memory to store the decoded string | |||||
//if (!(p->code = malloc(p->len))) { | |||||
// DEBUGF("Memory allocation failed\n"); | |||||
// return false ; | |||||
//} | |||||
// Check in case our code is too long | |||||
if (p->codeLen > CODEMAX) { | |||||
DEBUGF("Code too long, edit CODEMAX and recompile\n"); | |||||
return false ; | |||||
} | |||||
// Decode the string | |||||
cp = s; | |||||
for (i = 0; i < p->codeLen; i++, cp += 4) { | |||||
byp(&cp); | |||||
p->code[i] = htow(cp); | |||||
} | |||||
// Announce our findings | |||||
DEBUGF("Input: |%s|\n", s); | |||||
DEBUGF("Found: |"); | |||||
for (i = 0; i < p->codeLen; i++) DEBUGF("%04x ", p->code[i]) ; | |||||
DEBUGF("|\n"); | |||||
DEBUGF("Form [%04X] : ", p->code[0]); | |||||
if (p->code[0] == 0x0000) DEBUGF("Oscillated (Learned)\n"); | |||||
else if (p->code[0] == 0x0100) DEBUGF("Unmodulated\n"); | |||||
else DEBUGF("Unknown\n"); | |||||
if (p->code[0] != 0x0000) return false ; // Can only handle Oscillated | |||||
// Calculate the carrier frequency (+/- 10%) & uSecs per pulse | |||||
// Pronto uses a crystal which generates a timeabse of 0.241246 | |||||
p->freq = (int)(1000000 / (p->code[1] * 0.241246)); | |||||
p->usec = (int)(((1.0 / p->freq) * 1000000) + 0.5); | |||||
ir->code[0] = p->freq / 1000; | |||||
DEBUGF("Freq [%04X] : %d Hz (%d uS/pluse) -> %d KHz\n", | |||||
p->code[1], p->freq, p->usec, ir->code[0]); | |||||
// Set the length & start pointer for the "once" code | |||||
p->onceLen = p->code[2]; | |||||
p->once = &p->code[4]; | |||||
ir->code[1] = p->onceLen; | |||||
DEBUGF("Once [%04X] : %d\n", p->code[2], p->onceLen); | |||||
// Set the length & start pointer for the "repeat" code | |||||
p->rptLen = p->code[3]; | |||||
p->rpt = &p->code[4 + p->onceLen]; | |||||
ir->code[2] = p->rptLen; | |||||
DEBUGF("Rpt [%04X] : %d\n", p->code[3], p->rptLen); | |||||
// Check everything tallies | |||||
if (1 + 1 + 1 + 1 + (p->onceLen * 2) + (p->rptLen * 2) != p->codeLen) { | |||||
DEBUGF("Bad code length\n"); | |||||
return false; | |||||
} | |||||
// Convert the IR data to our new format | |||||
ir->FF = p->code[p->codeLen - 1]; | |||||
len = (p->onceLen * 2) + (p->rptLen * 2); | |||||
DEBUGF("Encoded: |"); | |||||
for (i = 0; i < len; i++) { | |||||
if (p->code[i+4] == ir->FF) { | |||||
ir->code[i+3] = 0xFF; | |||||
} else if (p->code[i+4] > 0xFE) { | |||||
DEBUGF("\n%04X : Mark/Space overflow\n", p->code[i+4]); | |||||
return false; | |||||
} else { | |||||
ir->code[i+3] = (p->code[i+4] * p->usec) / USECPERTICK; | |||||
} | |||||
DEBUGF("%s%d", !i ? "" : (i&1 ? "," : ", "), ir->code[i+3]); | |||||
} | |||||
DEBUGF("|\n"); | |||||
ir->FF = (ir->FF * p->usec) / USECPERTICK; | |||||
DEBUGF("FF -> %d\n", ir->FF); | |||||
return true; | |||||
} | |||||
//+============================================================================= | |||||
// | |||||
void irDump (irCode_t* ir) | |||||
{ | |||||
int i, len; | |||||
printf("uint8_t buttonName[%d] = {", len); | |||||
printf("%d,%d, ", (ir->FF >> 8), ir->FF & 0xFF); | |||||
printf("%d,%d,%d, ", ir->code[0], ir->code[1], ir->code[2]); | |||||
len = (ir->code[1] * 2) + (ir->code[2] * 2); | |||||
for (i = 0; i < len; i++) { | |||||
printf("%s%d", !i ? "" : (i&1 ? "," : ", "), ir->code[i+3]); | |||||
} | |||||
printf("};\n"); | |||||
} | |||||
//+============================================================================= | |||||
// | |||||
int main ( ) | |||||
{ | |||||
pronto_t pCode; | |||||
irCode_t irCode; | |||||
decode(prontoTest, &pCode, &irCode); | |||||
irDump(&irCode); | |||||
return 0; | |||||
} | |||||
#endif //0 |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
#ifdef TIMER_INT_DECLARE | |||||
TIMER_INT_DECLARE | |||||
#endif | |||||
#ifdef IR_TIMER_USE_ESP32 | |||||
hw_timer_t *timer; | |||||
void IRTimer(); // defined in IRremote.cpp | |||||
#endif | |||||
//+============================================================================= | |||||
// Decodes the received IR message | |||||
// Returns 0 if no data ready, 1 if data ready. | |||||
// Results of decoding are stored in results | |||||
// | |||||
int IRrecv::decode (decode_results *results) | |||||
{ | |||||
results->rawbuf = irparams.rawbuf; | |||||
results->rawlen = irparams.rawlen; | |||||
results->overflow = irparams.overflow; | |||||
if (irparams.rcvstate != STATE_STOP) return false ; | |||||
#if DECODE_NEC | |||||
DBG_PRINTLN("Attempting NEC decode"); | |||||
if (decodeNEC(results)) return true ; | |||||
#endif | |||||
#if DECODE_SONY | |||||
DBG_PRINTLN("Attempting Sony decode"); | |||||
if (decodeSony(results)) return true ; | |||||
#endif | |||||
#if DECODE_SANYO | |||||
DBG_PRINTLN("Attempting Sanyo decode"); | |||||
if (decodeSanyo(results)) return true ; | |||||
#endif | |||||
#if DECODE_MITSUBISHI | |||||
DBG_PRINTLN("Attempting Mitsubishi decode"); | |||||
if (decodeMitsubishi(results)) return true ; | |||||
#endif | |||||
#if DECODE_RC5 | |||||
DBG_PRINTLN("Attempting RC5 decode"); | |||||
if (decodeRC5(results)) return true ; | |||||
#endif | |||||
#if DECODE_RC6 | |||||
DBG_PRINTLN("Attempting RC6 decode"); | |||||
if (decodeRC6(results)) return true ; | |||||
#endif | |||||
#if DECODE_PANASONIC | |||||
DBG_PRINTLN("Attempting Panasonic decode"); | |||||
if (decodePanasonic(results)) return true ; | |||||
#endif | |||||
#if DECODE_LG | |||||
DBG_PRINTLN("Attempting LG decode"); | |||||
if (decodeLG(results)) return true ; | |||||
#endif | |||||
#if DECODE_JVC | |||||
DBG_PRINTLN("Attempting JVC decode"); | |||||
if (decodeJVC(results)) return true ; | |||||
#endif | |||||
#if DECODE_SAMSUNG | |||||
DBG_PRINTLN("Attempting SAMSUNG decode"); | |||||
if (decodeSAMSUNG(results)) return true ; | |||||
#endif | |||||
#if DECODE_WHYNTER | |||||
DBG_PRINTLN("Attempting Whynter decode"); | |||||
if (decodeWhynter(results)) return true ; | |||||
#endif | |||||
#if DECODE_AIWA_RC_T501 | |||||
DBG_PRINTLN("Attempting Aiwa RC-T501 decode"); | |||||
if (decodeAiwaRCT501(results)) return true ; | |||||
#endif | |||||
#if DECODE_DENON | |||||
DBG_PRINTLN("Attempting Denon decode"); | |||||
if (decodeDenon(results)) return true ; | |||||
#endif | |||||
#if DECODE_LEGO_PF | |||||
DBG_PRINTLN("Attempting Lego Power Functions"); | |||||
if (decodeLegoPowerFunctions(results)) 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 | |||||
resume(); | |||||
return false; | |||||
} | |||||
//+============================================================================= | |||||
IRrecv::IRrecv (int recvpin) | |||||
{ | |||||
irparams.recvpin = recvpin; | |||||
irparams.blinkflag = 0; | |||||
} | |||||
IRrecv::IRrecv (int recvpin, int blinkpin) | |||||
{ | |||||
irparams.recvpin = recvpin; | |||||
irparams.blinkpin = blinkpin; | |||||
pinMode(blinkpin, OUTPUT); | |||||
irparams.blinkflag = 0; | |||||
} | |||||
//+============================================================================= | |||||
// initialization | |||||
// | |||||
void IRrecv::enableIRIn ( ) | |||||
{ | |||||
// Interrupt Service Routine - Fires every 50uS | |||||
#ifdef ESP32 | |||||
// ESP32 has a proper API to setup timers, no weird chip macros needed | |||||
// simply call the readable API versions :) | |||||
// 3 timers, choose #1, 80 divider nanosecond precision, 1 to count up | |||||
timer = timerBegin(1, 80, 1); | |||||
timerAttachInterrupt(timer, &IRTimer, 1); | |||||
// every 50ns, autoreload = true | |||||
timerAlarmWrite(timer, 50, true); | |||||
timerAlarmEnable(timer); | |||||
#else | |||||
cli(); | |||||
// Setup pulse clock timer interrupt | |||||
// Prescale /8 (16M/8 = 0.5 microseconds per tick) | |||||
// Therefore, the timer interval can range from 0.5 to 128 microseconds | |||||
// Depending on the reset value (255 to 0) | |||||
TIMER_CONFIG_NORMAL(); | |||||
// Timer2 Overflow Interrupt Enable | |||||
TIMER_ENABLE_INTR; | |||||
TIMER_RESET; | |||||
sei(); // enable interrupts | |||||
#endif | |||||
// Initialize state machine variables | |||||
irparams.rcvstate = STATE_IDLE; | |||||
irparams.rawlen = 0; | |||||
// Set pin modes | |||||
pinMode(irparams.recvpin, INPUT); | |||||
} | |||||
//+============================================================================= | |||||
// Enable/disable blinking of pin 13 on IR processing | |||||
// | |||||
void IRrecv::blink13 (int blinkflag) | |||||
{ | |||||
irparams.blinkflag = blinkflag; | |||||
if (blinkflag) pinMode(BLINKLED, OUTPUT) ; | |||||
} | |||||
//+============================================================================= | |||||
// Return if receiving new IR signals | |||||
// | |||||
bool IRrecv::isIdle ( ) | |||||
{ | |||||
return (irparams.rcvstate == STATE_IDLE || irparams.rcvstate == STATE_STOP) ? true : false; | |||||
} | |||||
//+============================================================================= | |||||
// Restart the ISR state machine | |||||
// | |||||
void IRrecv::resume ( ) | |||||
{ | |||||
irparams.rcvstate = STATE_IDLE; | |||||
irparams.rawlen = 0; | |||||
} | |||||
//+============================================================================= | |||||
// 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% | |||||
// | |||||
int IRrecv::compare (unsigned int oldval, unsigned int newval) | |||||
{ | |||||
if (newval < oldval * .8) return 0 ; | |||||
else if (oldval < newval * .8) return 2 ; | |||||
else return 1 ; | |||||
} | |||||
//+============================================================================= | |||||
// Use FNV hash algorithm: http://isthe.com/chongo/tech/comp/fnv/#FNV-param | |||||
// 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. | |||||
// | |||||
#define FNV_PRIME_32 16777619 | |||||
#define FNV_BASIS_32 2166136261 | |||||
long IRrecv::decodeHash (decode_results *results) | |||||
{ | |||||
long hash = FNV_BASIS_32; | |||||
// Require at least 6 samples to prevent triggering on noise | |||||
if (results->rawlen < 6) return false ; | |||||
for (int i = 1; (i + 2) < results->rawlen; i++) { | |||||
int value = compare(results->rawbuf[i], results->rawbuf[i+2]); | |||||
// Add value into the hash | |||||
hash = (hash * FNV_PRIME_32) ^ value; | |||||
} | |||||
results->value = hash; | |||||
results->bits = 32; | |||||
results->decode_type = UNKNOWN; | |||||
return true; | |||||
} |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
//+============================================================================= | |||||
void IRsend::sendRaw (const unsigned int buf[], unsigned int len, unsigned int hz) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(hz); | |||||
for (unsigned int i = 0; i < len; i++) { | |||||
if (i & 1) space(buf[i]) ; | |||||
else mark (buf[i]) ; | |||||
} | |||||
space(0); // Always end with the LED off | |||||
} | |||||
//+============================================================================= | |||||
// Sends an IR mark for the specified number of microseconds. | |||||
// The mark output is modulated at the PWM frequency. | |||||
// | |||||
void IRsend::mark (unsigned int time) | |||||
{ | |||||
TIMER_ENABLE_PWM; // Enable pin 3 PWM output | |||||
if (time > 0) custom_delay_usec(time); | |||||
} | |||||
//+============================================================================= | |||||
// Leave pin off for time (given in microseconds) | |||||
// Sends an IR space for the specified number of microseconds. | |||||
// A space is no output, so the PWM output is disabled. | |||||
// | |||||
void IRsend::space (unsigned int time) | |||||
{ | |||||
TIMER_DISABLE_PWM; // Disable pin 3 PWM output | |||||
if (time > 0) IRsend::custom_delay_usec(time); | |||||
} | |||||
//+============================================================================= | |||||
// Enables IR output. The khz value controls the modulation frequency in kilohertz. | |||||
// The IR output will be on pin 3 (OC2B). | |||||
// This routine is designed for 36-40KHz; if you use it for other values, it's up to you | |||||
// to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.) | |||||
// TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B | |||||
// controlling the duty cycle. | |||||
// There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A) | |||||
// To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin. | |||||
// A few hours staring at the ATmega documentation and this will all make sense. | |||||
// See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details. | |||||
// | |||||
void IRsend::enableIROut (int khz) | |||||
{ | |||||
// FIXME: implement ESP32 support, see IR_TIMER_USE_ESP32 in boarddefs.h | |||||
#ifndef ESP32 | |||||
// Disable the Timer2 Interrupt (which is used for receiving IR) | |||||
TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt | |||||
pinMode(TIMER_PWM_PIN, OUTPUT); | |||||
digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low | |||||
// COM2A = 00: disconnect OC2A | |||||
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted | |||||
// WGM2 = 101: phase-correct PWM with OCRA as top | |||||
// CS2 = 000: no prescaling | |||||
// The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. | |||||
TIMER_CONFIG_KHZ(khz); | |||||
#endif | |||||
} | |||||
//+============================================================================= | |||||
// Custom delay function that circumvents Arduino's delayMicroseconds limit | |||||
void IRsend::custom_delay_usec(unsigned long uSecs) { | |||||
if (uSecs > 4) { | |||||
unsigned long start = micros(); | |||||
unsigned long endMicros = start + uSecs - 4; | |||||
if (endMicros < start) { // Check if overflow | |||||
while ( micros() > start ) {} // wait until overflow | |||||
} | |||||
while ( micros() < endMicros ) {} // normal wait | |||||
} | |||||
//else { | |||||
// __asm__("nop\n\t"); // must have or compiler optimizes out | |||||
//} | |||||
} | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
// Lirc file http://lirc.sourceforge.net/remotes/aiwa/RC-T501 | |||||
#define AIWA_RC_T501_HZ 38 | |||||
#define AIWA_RC_T501_BITS 15 | |||||
#define AIWA_RC_T501_PRE_BITS 26 | |||||
#define AIWA_RC_T501_POST_BITS 1 | |||||
#define AIWA_RC_T501_SUM_BITS (AIWA_RC_T501_PRE_BITS + AIWA_RC_T501_BITS + AIWA_RC_T501_POST_BITS) | |||||
#define AIWA_RC_T501_HDR_MARK 8800 | |||||
#define AIWA_RC_T501_HDR_SPACE 4500 | |||||
#define AIWA_RC_T501_BIT_MARK 500 | |||||
#define AIWA_RC_T501_ONE_SPACE 600 | |||||
#define AIWA_RC_T501_ZERO_SPACE 1700 | |||||
//+============================================================================= | |||||
#if SEND_AIWA_RC_T501 | |||||
void IRsend::sendAiwaRCT501 (int code) | |||||
{ | |||||
unsigned long pre = 0x0227EEC0; // 26-bits | |||||
// Set IR carrier frequency | |||||
enableIROut(AIWA_RC_T501_HZ); | |||||
// Header | |||||
mark(AIWA_RC_T501_HDR_MARK); | |||||
space(AIWA_RC_T501_HDR_SPACE); | |||||
// Send "pre" data | |||||
for (unsigned long mask = 1UL << (26 - 1); mask; mask >>= 1) { | |||||
mark(AIWA_RC_T501_BIT_MARK); | |||||
if (pre & mask) space(AIWA_RC_T501_ONE_SPACE) ; | |||||
else space(AIWA_RC_T501_ZERO_SPACE) ; | |||||
} | |||||
//-v- THIS CODE LOOKS LIKE IT MIGHT BE WRONG - CHECK! | |||||
// it only send 15bits and ignores the top bit | |||||
// then uses TOPBIT which is 0x80000000 to check the bit code | |||||
// I suspect TOPBIT should be changed to 0x00008000 | |||||
// Skip first code bit | |||||
code <<= 1; | |||||
// Send code | |||||
for (int i = 0; i < 15; i++) { | |||||
mark(AIWA_RC_T501_BIT_MARK); | |||||
if (code & 0x80000000) space(AIWA_RC_T501_ONE_SPACE) ; | |||||
else space(AIWA_RC_T501_ZERO_SPACE) ; | |||||
code <<= 1; | |||||
} | |||||
//-^- THIS CODE LOOKS LIKE IT MIGHT BE WRONG - CHECK! | |||||
// POST-DATA, 1 bit, 0x0 | |||||
mark(AIWA_RC_T501_BIT_MARK); | |||||
space(AIWA_RC_T501_ZERO_SPACE); | |||||
mark(AIWA_RC_T501_BIT_MARK); | |||||
space(0); | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if DECODE_AIWA_RC_T501 | |||||
bool IRrecv::decodeAiwaRCT501 (decode_results *results) | |||||
{ | |||||
int data = 0; | |||||
int offset = 1; | |||||
// Check SIZE | |||||
if (irparams.rawlen < 2 * (AIWA_RC_T501_SUM_BITS) + 4) return false ; | |||||
// Check HDR Mark/Space | |||||
if (!MATCH_MARK (results->rawbuf[offset++], AIWA_RC_T501_HDR_MARK )) return false ; | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], AIWA_RC_T501_HDR_SPACE)) return false ; | |||||
offset += 26; // skip pre-data - optional | |||||
while(offset < irparams.rawlen - 4) { | |||||
if (MATCH_MARK(results->rawbuf[offset], AIWA_RC_T501_BIT_MARK)) offset++ ; | |||||
else return false ; | |||||
// ONE & ZERO | |||||
if (MATCH_SPACE(results->rawbuf[offset], AIWA_RC_T501_ONE_SPACE)) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], AIWA_RC_T501_ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else break ; // End of one & zero detected | |||||
offset++; | |||||
} | |||||
results->bits = (offset - 1) / 2; | |||||
if (results->bits < 42) return false ; | |||||
results->value = data; | |||||
results->decode_type = AIWA_RC_T501; | |||||
return true; | |||||
} | |||||
#endif |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
// Reverse Engineered by looking at RAW dumps generated by IRremote | |||||
// I have since discovered that Denon publish all their IR codes: | |||||
// https://www.google.co.uk/search?q=DENON+MASTER+IR+Hex+Command+Sheet | |||||
// -> http://assets.denon.com/documentmaster/us/denon%20master%20ir%20hex.xls | |||||
// Having looked at the official Denon Pronto sheet and reverse engineered | |||||
// the timing values from it, it is obvious that Denon have a range of | |||||
// different timings and protocols ...the values here work for my AVR-3801 Amp! | |||||
//============================================================================== | |||||
// 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 | |||||
//============================================================================== | |||||
#define BITS 14 // The number of bits in the command | |||||
#define HDR_MARK 300 // The length of the Header:Mark | |||||
#define HDR_SPACE 750 // The lenght of the Header:Space | |||||
#define BIT_MARK 300 // The length of a Bit:Mark | |||||
#define ONE_SPACE 1800 // The length of a Bit:Space for 1's | |||||
#define ZERO_SPACE 750 // The length of a Bit:Space for 0's | |||||
//+============================================================================= | |||||
// | |||||
#if SEND_DENON | |||||
void IRsend::sendDenon (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(38); | |||||
// Header | |||||
mark (HDR_MARK); | |||||
space(HDR_SPACE); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark (BIT_MARK); | |||||
space(ONE_SPACE); | |||||
} else { | |||||
mark (BIT_MARK); | |||||
space(ZERO_SPACE); | |||||
} | |||||
} | |||||
// Footer | |||||
mark(BIT_MARK); | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
// | |||||
#if DECODE_DENON | |||||
bool IRrecv::decodeDenon (decode_results *results) | |||||
{ | |||||
unsigned long data = 0; // Somewhere to build our code | |||||
int offset = 1; // Skip the Gap reading | |||||
// Check we have the right amount of data | |||||
if (irparams.rawlen != 1 + 2 + (2 * BITS) + 1) return false ; | |||||
// Check initial Mark+Space match | |||||
if (!MATCH_MARK (results->rawbuf[offset++], HDR_MARK )) return false ; | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], HDR_SPACE)) return false ; | |||||
// Read the bits in | |||||
for (int i = 0; i < BITS; i++) { | |||||
// Each bit looks like: MARK + SPACE_1 -> 1 | |||||
// or : MARK + SPACE_0 -> 0 | |||||
if (!MATCH_MARK(results->rawbuf[offset++], BIT_MARK)) return false ; | |||||
// IR data is big-endian, so we shuffle it in from the right: | |||||
if (MATCH_SPACE(results->rawbuf[offset], ONE_SPACE)) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Success | |||||
results->bits = BITS; | |||||
results->value = data; | |||||
results->decode_type = DENON; | |||||
return true; | |||||
} | |||||
#endif |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
// Sharp and DISH support by Todd Treece ( http://unionbridge.org/design/ircommand ) | |||||
// | |||||
// The sned function needs to be repeated 4 times | |||||
// | |||||
// Only send the last for characters of the hex. | |||||
// I.E. Use 0x1C10 instead of 0x0000000000001C10 as listed in the LIRC file. | |||||
// | |||||
// 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 | |||||
#define DISH_BITS 16 | |||||
#define DISH_HDR_MARK 400 | |||||
#define DISH_HDR_SPACE 6100 | |||||
#define DISH_BIT_MARK 400 | |||||
#define DISH_ONE_SPACE 1700 | |||||
#define DISH_ZERO_SPACE 2800 | |||||
#define DISH_RPT_SPACE 6200 | |||||
//+============================================================================= | |||||
#if SEND_DISH | |||||
void IRsend::sendDISH (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(56); | |||||
mark(DISH_HDR_MARK); | |||||
space(DISH_HDR_SPACE); | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark(DISH_BIT_MARK); | |||||
space(DISH_ONE_SPACE); | |||||
} else { | |||||
mark(DISH_BIT_MARK); | |||||
space(DISH_ZERO_SPACE); | |||||
} | |||||
} | |||||
mark(DISH_HDR_MARK); //added 26th March 2016, by AnalysIR ( https://www.AnalysIR.com ) | |||||
} | |||||
#endif | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
//============================================================================== | |||||
// JJJJJ V V CCCC | |||||
// J V V C | |||||
// J V V C | |||||
// J J V V C | |||||
// J V CCCC | |||||
//============================================================================== | |||||
#define JVC_BITS 16 | |||||
#define JVC_HDR_MARK 8000 | |||||
#define JVC_HDR_SPACE 4000 | |||||
#define JVC_BIT_MARK 600 | |||||
#define JVC_ONE_SPACE 1600 | |||||
#define JVC_ZERO_SPACE 550 | |||||
#define JVC_RPT_LENGTH 60000 | |||||
//+============================================================================= | |||||
// JVC does NOT repeat by sending a separate code (like NEC does). | |||||
// The JVC protocol repeats by skipping the header. | |||||
// To send a JVC repeat signal, send the original code value | |||||
// and set 'repeat' to true | |||||
// | |||||
#if SEND_JVC | |||||
void IRsend::sendJVC (unsigned long data, int nbits, bool repeat) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(38); | |||||
// Only send the Header if this is NOT a repeat command | |||||
if (!repeat){ | |||||
mark(JVC_HDR_MARK); | |||||
space(JVC_HDR_SPACE); | |||||
} | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark(JVC_BIT_MARK); | |||||
space(JVC_ONE_SPACE); | |||||
} else { | |||||
mark(JVC_BIT_MARK); | |||||
space(JVC_ZERO_SPACE); | |||||
} | |||||
} | |||||
// Footer | |||||
mark(JVC_BIT_MARK); | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if DECODE_JVC | |||||
bool IRrecv::decodeJVC (decode_results *results) | |||||
{ | |||||
long data = 0; | |||||
int offset = 1; // Skip first space | |||||
// Check for repeat | |||||
if ( (irparams.rawlen - 1 == 33) | |||||
&& MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK) | |||||
&& MATCH_MARK(results->rawbuf[irparams.rawlen-1], JVC_BIT_MARK) | |||||
) { | |||||
results->bits = 0; | |||||
results->value = REPEAT; | |||||
results->decode_type = JVC; | |||||
return true; | |||||
} | |||||
// Initial mark | |||||
if (!MATCH_MARK(results->rawbuf[offset++], JVC_HDR_MARK)) return false ; | |||||
if (irparams.rawlen < (2 * JVC_BITS) + 1 ) return false ; | |||||
// Initial space | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], JVC_HDR_SPACE)) return false ; | |||||
for (int i = 0; i < JVC_BITS; i++) { | |||||
if (!MATCH_MARK(results->rawbuf[offset++], JVC_BIT_MARK)) return false ; | |||||
if (MATCH_SPACE(results->rawbuf[offset], JVC_ONE_SPACE)) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], JVC_ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Stop bit | |||||
if (!MATCH_MARK(results->rawbuf[offset], JVC_BIT_MARK)) return false ; | |||||
// Success | |||||
results->bits = JVC_BITS; | |||||
results->value = data; | |||||
results->decode_type = JVC; | |||||
return true; | |||||
} | |||||
#endif | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
//============================================================================== | |||||
// L GGGG | |||||
// L G | |||||
// L G GG | |||||
// L G G | |||||
// LLLLL GGG | |||||
//============================================================================== | |||||
#define LG_BITS 28 | |||||
#define LG_HDR_MARK 8000 | |||||
#define LG_HDR_SPACE 4000 | |||||
#define LG_BIT_MARK 600 | |||||
#define LG_ONE_SPACE 1600 | |||||
#define LG_ZERO_SPACE 550 | |||||
#define LG_RPT_LENGTH 60000 | |||||
//+============================================================================= | |||||
#if DECODE_LG | |||||
bool IRrecv::decodeLG (decode_results *results) | |||||
{ | |||||
long data = 0; | |||||
int offset = 1; // Skip first space | |||||
// Check we have the right amount of data | |||||
if (irparams.rawlen < (2 * LG_BITS) + 1 ) return false ; | |||||
// Initial mark/space | |||||
if (!MATCH_MARK(results->rawbuf[offset++], LG_HDR_MARK)) return false ; | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], LG_HDR_SPACE)) return false ; | |||||
for (int i = 0; i < LG_BITS; i++) { | |||||
if (!MATCH_MARK(results->rawbuf[offset++], LG_BIT_MARK)) return false ; | |||||
if (MATCH_SPACE(results->rawbuf[offset], LG_ONE_SPACE)) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], LG_ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Stop bit | |||||
if (!MATCH_MARK(results->rawbuf[offset], LG_BIT_MARK)) return false ; | |||||
// Success | |||||
results->bits = LG_BITS; | |||||
results->value = data; | |||||
results->decode_type = LG; | |||||
return true; | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if SEND_LG | |||||
void IRsend::sendLG (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(38); | |||||
// Header | |||||
mark(LG_HDR_MARK); | |||||
space(LG_HDR_SPACE); | |||||
mark(LG_BIT_MARK); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
space(LG_ONE_SPACE); | |||||
mark(LG_BIT_MARK); | |||||
} else { | |||||
space(LG_ZERO_SPACE); | |||||
mark(LG_BIT_MARK); | |||||
} | |||||
} | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
#include "irr/ir_Lego_PF_BitStreamEncoder.h" | |||||
//============================================================================== | |||||
// L EEEEEE EEEE OOOO | |||||
// L E E O O | |||||
// L EEEE E EEE O O | |||||
// L E E E O O LEGO Power Functions | |||||
// LLLLLL EEEEEE EEEE OOOO Copyright (c) 2016 Philipp Henkel | |||||
//============================================================================== | |||||
// Supported Devices | |||||
// LEGO® Power Functions IR Receiver 8884 | |||||
//+============================================================================= | |||||
// | |||||
#if SEND_LEGO_PF | |||||
#if DEBUG | |||||
namespace { | |||||
void logFunctionParameters(uint16_t data, bool repeat) { | |||||
DBG_PRINT("sendLegoPowerFunctions(data="); | |||||
DBG_PRINT(data); | |||||
DBG_PRINT(", repeat="); | |||||
DBG_PRINTLN(repeat?"true)" : "false)"); | |||||
} | |||||
} // anonymous namespace | |||||
#endif // DEBUG | |||||
void IRsend::sendLegoPowerFunctions(uint16_t data, bool repeat) | |||||
{ | |||||
#if DEBUG | |||||
::logFunctionParameters(data, repeat); | |||||
#endif // DEBUG | |||||
enableIROut(38); | |||||
static LegoPfBitStreamEncoder bitStreamEncoder; | |||||
bitStreamEncoder.reset(data, repeat); | |||||
do { | |||||
mark(bitStreamEncoder.getMarkDuration()); | |||||
space(bitStreamEncoder.getPauseDuration()); | |||||
} while (bitStreamEncoder.next()); | |||||
} | |||||
#endif // SEND_LEGO_PF |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
// Looks like Sony except for timings, 48 chars of data and time/space different | |||||
#define MITSUBISHI_BITS 16 | |||||
// Mitsubishi RM 75501 | |||||
// 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7 | |||||
// #define MITSUBISHI_HDR_MARK 250 // seen range 3500 | |||||
#define MITSUBISHI_HDR_SPACE 350 // 7*50+100 | |||||
#define MITSUBISHI_ONE_MARK 1950 // 41*50-100 | |||||
#define MITSUBISHI_ZERO_MARK 750 // 17*50-100 | |||||
// #define MITSUBISHI_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround | |||||
// #define MITSUBISHI_RPT_LENGTH 45000 | |||||
//+============================================================================= | |||||
#if DECODE_MITSUBISHI | |||||
bool IRrecv::decodeMitsubishi (decode_results *results) | |||||
{ | |||||
// Serial.print("?!? decoding Mitsubishi:");Serial.print(irparams.rawlen); Serial.print(" want "); Serial.println( 2 * MITSUBISHI_BITS + 2); | |||||
long data = 0; | |||||
if (irparams.rawlen < 2 * MITSUBISHI_BITS + 2) return false ; | |||||
int offset = 0; // Skip first space | |||||
// Initial space | |||||
#if 0 | |||||
// Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay | |||||
Serial.print("IR Gap: "); | |||||
Serial.println( results->rawbuf[offset]); | |||||
Serial.println( "test against:"); | |||||
Serial.println(results->rawbuf[offset]); | |||||
#endif | |||||
#if 0 | |||||
// Not seeing double keys from Mitsubishi | |||||
if (results->rawbuf[offset] < MITSUBISHI_DOUBLE_SPACE_USECS) { | |||||
// Serial.print("IR Gap found: "); | |||||
results->bits = 0; | |||||
results->value = REPEAT; | |||||
results->decode_type = MITSUBISHI; | |||||
return true; | |||||
} | |||||
#endif | |||||
offset++; | |||||
// Typical | |||||
// 14200 7 41 7 42 7 42 7 17 7 17 7 18 7 41 7 18 7 17 7 17 7 18 7 41 8 17 7 17 7 18 7 17 7 | |||||
// Initial Space | |||||
if (!MATCH_MARK(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) return false ; | |||||
offset++; | |||||
while (offset + 1 < irparams.rawlen) { | |||||
if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ONE_MARK)) data = (data << 1) | 1 ; | |||||
else if (MATCH_MARK(results->rawbuf[offset], MITSUBISHI_ZERO_MARK)) data <<= 1 ; | |||||
else return false ; | |||||
offset++; | |||||
if (!MATCH_SPACE(results->rawbuf[offset], MITSUBISHI_HDR_SPACE)) break ; | |||||
offset++; | |||||
} | |||||
// Success | |||||
results->bits = (offset - 1) / 2; | |||||
if (results->bits < MITSUBISHI_BITS) { | |||||
results->bits = 0; | |||||
return false; | |||||
} | |||||
results->value = data; | |||||
results->decode_type = MITSUBISHI; | |||||
return true; | |||||
} | |||||
#endif | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
//============================================================================== | |||||
// N N EEEEE CCCC | |||||
// NN N E C | |||||
// N N N EEE C | |||||
// N NN E C | |||||
// N N EEEEE CCCC | |||||
//============================================================================== | |||||
#define NEC_BITS 32 | |||||
#define NEC_HDR_MARK 9000 | |||||
#define NEC_HDR_SPACE 4500 | |||||
#define NEC_BIT_MARK 560 | |||||
#define NEC_ONE_SPACE 1690 | |||||
#define NEC_ZERO_SPACE 560 | |||||
#define NEC_RPT_SPACE 2250 | |||||
//+============================================================================= | |||||
#if SEND_NEC | |||||
void IRsend::sendNEC (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(38); | |||||
// Header | |||||
mark(NEC_HDR_MARK); | |||||
space(NEC_HDR_SPACE); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark(NEC_BIT_MARK); | |||||
space(NEC_ONE_SPACE); | |||||
} else { | |||||
mark(NEC_BIT_MARK); | |||||
space(NEC_ZERO_SPACE); | |||||
} | |||||
} | |||||
// Footer | |||||
mark(NEC_BIT_MARK); | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
// NECs have a repeat only 4 items long | |||||
// | |||||
#if DECODE_NEC | |||||
bool IRrecv::decodeNEC (decode_results *results) | |||||
{ | |||||
long data = 0; // We decode in to here; Start with nothing | |||||
int offset = 1; // Index in to results; Skip first entry!? | |||||
// Check header "mark" | |||||
if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) return false ; | |||||
offset++; | |||||
// Check for repeat | |||||
if ( (irparams.rawlen == 4) | |||||
&& MATCH_SPACE(results->rawbuf[offset ], NEC_RPT_SPACE) | |||||
&& MATCH_MARK (results->rawbuf[offset+1], NEC_BIT_MARK ) | |||||
) { | |||||
results->bits = 0; | |||||
results->value = REPEAT; | |||||
results->decode_type = NEC; | |||||
return true; | |||||
} | |||||
// Check we have enough data | |||||
if (irparams.rawlen < (2 * NEC_BITS) + 4) return false ; | |||||
// Check header "space" | |||||
if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) return false ; | |||||
offset++; | |||||
// Build the data | |||||
for (int i = 0; i < NEC_BITS; i++) { | |||||
// Check data "mark" | |||||
if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) return false ; | |||||
offset++; | |||||
// Suppend this bit | |||||
if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE )) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Success | |||||
results->bits = NEC_BITS; | |||||
results->value = data; | |||||
results->decode_type = NEC; | |||||
return true; | |||||
} | |||||
#endif |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
#define PANASONIC_BITS 48 | |||||
#define PANASONIC_HDR_MARK 3502 | |||||
#define PANASONIC_HDR_SPACE 1750 | |||||
#define PANASONIC_BIT_MARK 502 | |||||
#define PANASONIC_ONE_SPACE 1244 | |||||
#define PANASONIC_ZERO_SPACE 400 | |||||
//+============================================================================= | |||||
#if SEND_PANASONIC | |||||
void IRsend::sendPanasonic (unsigned int address, unsigned long data) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(35); | |||||
// Header | |||||
mark(PANASONIC_HDR_MARK); | |||||
space(PANASONIC_HDR_SPACE); | |||||
// Address | |||||
for (unsigned long mask = 1UL << (16 - 1); mask; mask >>= 1) { | |||||
mark(PANASONIC_BIT_MARK); | |||||
if (address & mask) space(PANASONIC_ONE_SPACE) ; | |||||
else space(PANASONIC_ZERO_SPACE) ; | |||||
} | |||||
// Data | |||||
for (unsigned long mask = 1UL << (32 - 1); mask; mask >>= 1) { | |||||
mark(PANASONIC_BIT_MARK); | |||||
if (data & mask) space(PANASONIC_ONE_SPACE) ; | |||||
else space(PANASONIC_ZERO_SPACE) ; | |||||
} | |||||
// Footer | |||||
mark(PANASONIC_BIT_MARK); | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if DECODE_PANASONIC | |||||
bool IRrecv::decodePanasonic (decode_results *results) | |||||
{ | |||||
unsigned long long data = 0; | |||||
int offset = 1; | |||||
if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_HDR_MARK )) return false ; | |||||
if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_HDR_SPACE)) return false ; | |||||
// decode address | |||||
for (int i = 0; i < PANASONIC_BITS; i++) { | |||||
if (!MATCH_MARK(results->rawbuf[offset++], PANASONIC_BIT_MARK)) return false ; | |||||
if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ONE_SPACE )) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset],PANASONIC_ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
results->value = (unsigned long)data; | |||||
results->address = (unsigned int)(data >> 32); | |||||
results->decode_type = PANASONIC; | |||||
results->bits = PANASONIC_BITS; | |||||
return true; | |||||
} | |||||
#endif | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
//+============================================================================= | |||||
// 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. | |||||
// t1 is the time interval for a single bit in microseconds. | |||||
// Returns -1 for error (measured time interval is not a multiple of t1). | |||||
// | |||||
#if (DECODE_RC5 || DECODE_RC6) | |||||
int IRrecv::getRClevel (decode_results *results, int *offset, int *used, int t1) | |||||
{ | |||||
int width; | |||||
int val; | |||||
int correction; | |||||
int avail; | |||||
if (*offset >= results->rawlen) return SPACE ; // After end of recorded buffer, assume SPACE. | |||||
width = results->rawbuf[*offset]; | |||||
val = ((*offset) % 2) ? MARK : SPACE; | |||||
correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS; | |||||
if (MATCH(width, ( t1) + correction)) avail = 1 ; | |||||
else if (MATCH(width, (2*t1) + correction)) avail = 2 ; | |||||
else if (MATCH(width, (3*t1) + correction)) avail = 3 ; | |||||
else return -1 ; | |||||
(*used)++; | |||||
if (*used >= avail) { | |||||
*used = 0; | |||||
(*offset)++; | |||||
} | |||||
DBG_PRINTLN( (val == MARK) ? "MARK" : "SPACE" ); | |||||
return val; | |||||
} | |||||
#endif | |||||
//============================================================================== | |||||
// RRRR CCCC 55555 | |||||
// R R C 5 | |||||
// RRRR C 5555 | |||||
// R R C 5 | |||||
// R R CCCC 5555 | |||||
// | |||||
// NB: First bit must be a one (start bit) | |||||
// | |||||
#define MIN_RC5_SAMPLES 11 | |||||
#define RC5_T1 889 | |||||
#define RC5_RPT_LENGTH 46000 | |||||
//+============================================================================= | |||||
#if SEND_RC5 | |||||
void IRsend::sendRC5 (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(36); | |||||
// Start | |||||
mark(RC5_T1); | |||||
space(RC5_T1); | |||||
mark(RC5_T1); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
space(RC5_T1); // 1 is space, then mark | |||||
mark(RC5_T1); | |||||
} else { | |||||
mark(RC5_T1); | |||||
space(RC5_T1); | |||||
} | |||||
} | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if DECODE_RC5 | |||||
bool IRrecv::decodeRC5 (decode_results *results) | |||||
{ | |||||
int nbits; | |||||
long data = 0; | |||||
int used = 0; | |||||
int offset = 1; // Skip gap space | |||||
if (irparams.rawlen < MIN_RC5_SAMPLES + 2) return false ; | |||||
// Get start bits | |||||
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return false ; | |||||
if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return false ; | |||||
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return false ; | |||||
for (nbits = 0; offset < irparams.rawlen; nbits++) { | |||||
int levelA = getRClevel(results, &offset, &used, RC5_T1); | |||||
int levelB = getRClevel(results, &offset, &used, RC5_T1); | |||||
if ((levelA == SPACE) && (levelB == MARK )) data = (data << 1) | 1 ; | |||||
else if ((levelA == MARK ) && (levelB == SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
} | |||||
// Success | |||||
results->bits = nbits; | |||||
results->value = data; | |||||
results->decode_type = RC5; | |||||
return true; | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
// RRRR CCCC 6666 | |||||
// R R C 6 | |||||
// RRRR C 6666 | |||||
// R R C 6 6 | |||||
// R R CCCC 666 | |||||
// | |||||
// NB : Caller needs to take care of flipping the toggle bit | |||||
// | |||||
#define MIN_RC6_SAMPLES 1 | |||||
#define RC6_HDR_MARK 2666 | |||||
#define RC6_HDR_SPACE 889 | |||||
#define RC6_T1 444 | |||||
#define RC6_RPT_LENGTH 46000 | |||||
#if SEND_RC6 | |||||
void IRsend::sendRC6 (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(36); | |||||
// Header | |||||
mark(RC6_HDR_MARK); | |||||
space(RC6_HDR_SPACE); | |||||
// Start bit | |||||
mark(RC6_T1); | |||||
space(RC6_T1); | |||||
// Data | |||||
for (unsigned long i = 1, mask = 1UL << (nbits - 1); mask; i++, mask >>= 1) { | |||||
// The fourth bit we send is a "double width trailer bit" | |||||
int t = (i == 4) ? (RC6_T1 * 2) : (RC6_T1) ; | |||||
if (data & mask) { | |||||
mark(t); | |||||
space(t); | |||||
} else { | |||||
space(t); | |||||
mark(t); | |||||
} | |||||
} | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if DECODE_RC6 | |||||
bool IRrecv::decodeRC6 (decode_results *results) | |||||
{ | |||||
int nbits; | |||||
long data = 0; | |||||
int used = 0; | |||||
int offset = 1; // Skip first space | |||||
if (results->rawlen < MIN_RC6_SAMPLES) return false ; | |||||
// Initial mark | |||||
if (!MATCH_MARK(results->rawbuf[offset++], RC6_HDR_MARK)) return false ; | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], RC6_HDR_SPACE)) return false ; | |||||
// Get start bit (1) | |||||
if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return false ; | |||||
if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return false ; | |||||
for (nbits = 0; offset < results->rawlen; nbits++) { | |||||
int levelA, levelB; // Next two levels | |||||
levelA = getRClevel(results, &offset, &used, RC6_T1); | |||||
if (nbits == 3) { | |||||
// T bit is double wide; make sure second half matches | |||||
if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return false; | |||||
} | |||||
levelB = getRClevel(results, &offset, &used, RC6_T1); | |||||
if (nbits == 3) { | |||||
// T bit is double wide; make sure second half matches | |||||
if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return false; | |||||
} | |||||
if ((levelA == MARK ) && (levelB == SPACE)) data = (data << 1) | 1 ; // inverted compared to RC5 | |||||
else if ((levelA == SPACE) && (levelB == MARK )) data = (data << 1) | 0 ; // ... | |||||
else return false ; // Error | |||||
} | |||||
// Success | |||||
results->bits = nbits; | |||||
results->value = data; | |||||
results->decode_type = RC6; | |||||
return true; | |||||
} | |||||
#endif |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
#define SAMSUNG_BITS 32 | |||||
#define SAMSUNG_HDR_MARK 5000 | |||||
#define SAMSUNG_HDR_SPACE 5000 | |||||
#define SAMSUNG_BIT_MARK 560 | |||||
#define SAMSUNG_ONE_SPACE 1600 | |||||
#define SAMSUNG_ZERO_SPACE 560 | |||||
#define SAMSUNG_RPT_SPACE 2250 | |||||
//+============================================================================= | |||||
#if SEND_SAMSUNG | |||||
void IRsend::sendSAMSUNG (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(38); | |||||
// Header | |||||
mark(SAMSUNG_HDR_MARK); | |||||
space(SAMSUNG_HDR_SPACE); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark(SAMSUNG_BIT_MARK); | |||||
space(SAMSUNG_ONE_SPACE); | |||||
} else { | |||||
mark(SAMSUNG_BIT_MARK); | |||||
space(SAMSUNG_ZERO_SPACE); | |||||
} | |||||
} | |||||
// Footer | |||||
mark(SAMSUNG_BIT_MARK); | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
// SAMSUNGs have a repeat only 4 items long | |||||
// | |||||
#if DECODE_SAMSUNG | |||||
bool IRrecv::decodeSAMSUNG (decode_results *results) | |||||
{ | |||||
long data = 0; | |||||
int offset = 1; // Skip first space | |||||
// Initial mark | |||||
if (!MATCH_MARK(results->rawbuf[offset], SAMSUNG_HDR_MARK)) return false ; | |||||
offset++; | |||||
// Check for repeat | |||||
if ( (irparams.rawlen == 4) | |||||
&& MATCH_SPACE(results->rawbuf[offset], SAMSUNG_RPT_SPACE) | |||||
&& MATCH_MARK(results->rawbuf[offset+1], SAMSUNG_BIT_MARK) | |||||
) { | |||||
results->bits = 0; | |||||
results->value = REPEAT; | |||||
results->decode_type = SAMSUNG; | |||||
return true; | |||||
} | |||||
if (irparams.rawlen < (2 * SAMSUNG_BITS) + 4) return false ; | |||||
// Initial space | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], SAMSUNG_HDR_SPACE)) return false ; | |||||
for (int i = 0; i < SAMSUNG_BITS; i++) { | |||||
if (!MATCH_MARK(results->rawbuf[offset++], SAMSUNG_BIT_MARK)) return false ; | |||||
if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ONE_SPACE)) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], SAMSUNG_ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Success | |||||
results->bits = SAMSUNG_BITS; | |||||
results->value = data; | |||||
results->decode_type = SAMSUNG; | |||||
return true; | |||||
} | |||||
#endif | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
// I think this is a Sanyo decoder: Serial = SA 8650B | |||||
// Looks like Sony except for timings, 48 chars of data and time/space different | |||||
#define SANYO_BITS 12 | |||||
#define SANYO_HDR_MARK 3500 // seen range 3500 | |||||
#define SANYO_HDR_SPACE 950 // seen 950 | |||||
#define SANYO_ONE_MARK 2400 // seen 2400 | |||||
#define SANYO_ZERO_MARK 700 // seen 700 | |||||
#define SANYO_DOUBLE_SPACE_USECS 800 // usually ssee 713 - not using ticks as get number wrapround | |||||
#define SANYO_RPT_LENGTH 45000 | |||||
//+============================================================================= | |||||
#if DECODE_SANYO | |||||
bool IRrecv::decodeSanyo (decode_results *results) | |||||
{ | |||||
long data = 0; | |||||
int offset = 0; // Skip first space <-- CHECK THIS! | |||||
if (irparams.rawlen < (2 * SANYO_BITS) + 2) return false ; | |||||
#if 0 | |||||
// Put this back in for debugging - note can't use #DEBUG as if Debug on we don't see the repeat cos of the delay | |||||
Serial.print("IR Gap: "); | |||||
Serial.println( results->rawbuf[offset]); | |||||
Serial.println( "test against:"); | |||||
Serial.println(results->rawbuf[offset]); | |||||
#endif | |||||
// Initial space | |||||
if (results->rawbuf[offset] < SANYO_DOUBLE_SPACE_USECS) { | |||||
//Serial.print("IR Gap found: "); | |||||
results->bits = 0; | |||||
results->value = REPEAT; | |||||
results->decode_type = SANYO; | |||||
return true; | |||||
} | |||||
offset++; | |||||
// Initial mark | |||||
if (!MATCH_MARK(results->rawbuf[offset++], SANYO_HDR_MARK)) return false ; | |||||
// Skip Second Mark | |||||
if (!MATCH_MARK(results->rawbuf[offset++], SANYO_HDR_MARK)) return false ; | |||||
while (offset + 1 < irparams.rawlen) { | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], SANYO_HDR_SPACE)) break ; | |||||
if (MATCH_MARK(results->rawbuf[offset], SANYO_ONE_MARK)) data = (data << 1) | 1 ; | |||||
else if (MATCH_MARK(results->rawbuf[offset], SANYO_ZERO_MARK)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Success | |||||
results->bits = (offset - 1) / 2; | |||||
if (results->bits < 12) { | |||||
results->bits = 0; | |||||
return false; | |||||
} | |||||
results->value = data; | |||||
results->decode_type = SANYO; | |||||
return true; | |||||
} | |||||
#endif |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
// Sharp and DISH support by Todd Treece: http://unionbridge.org/design/ircommand | |||||
// | |||||
// The send function has the necessary repeat built in because of the need to | |||||
// invert the signal. | |||||
// | |||||
// Sharp protocol documentation: | |||||
// http://www.sbprojects.com/knowledge/ir/sharp.htm | |||||
// | |||||
// Here is the LIRC file I found that seems to match the remote codes from the | |||||
// oscilloscope: | |||||
// Sharp LCD TV: | |||||
// http://lirc.sourceforge.net/remotes/sharp/GA538WJSA | |||||
#define SHARP_BITS 15 | |||||
#define SHARP_BIT_MARK 245 | |||||
#define SHARP_ONE_SPACE 1805 | |||||
#define SHARP_ZERO_SPACE 795 | |||||
#define SHARP_GAP 600000 | |||||
#define SHARP_RPT_SPACE 3000 | |||||
#define SHARP_TOGGLE_MASK 0x3FF | |||||
//+============================================================================= | |||||
#if SEND_SHARP | |||||
void IRsend::sendSharpRaw (unsigned long data, int nbits) | |||||
{ | |||||
enableIROut(38); | |||||
// Sending codes in bursts of 3 (normal, inverted, normal) makes transmission | |||||
// much more reliable. That's the exact behaviour of CD-S6470 remote control. | |||||
for (int n = 0; n < 3; n++) { | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark(SHARP_BIT_MARK); | |||||
space(SHARP_ONE_SPACE); | |||||
} else { | |||||
mark(SHARP_BIT_MARK); | |||||
space(SHARP_ZERO_SPACE); | |||||
} | |||||
} | |||||
mark(SHARP_BIT_MARK); | |||||
space(SHARP_ZERO_SPACE); | |||||
delay(40); | |||||
data = data ^ SHARP_TOGGLE_MASK; | |||||
} | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
// Sharp send compatible with data obtained through decodeSharp() | |||||
// ^^^^^^^^^^^^^ FUNCTION MISSING! | |||||
// | |||||
#if SEND_SHARP | |||||
void IRsend::sendSharp (unsigned int address, unsigned int command) | |||||
{ | |||||
sendSharpRaw((address << 10) | (command << 2) | 2, SHARP_BITS); | |||||
} | |||||
#endif |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
#define SONY_BITS 12 | |||||
#define SONY_HDR_MARK 2400 | |||||
#define SONY_HDR_SPACE 600 | |||||
#define SONY_ONE_MARK 1200 | |||||
#define SONY_ZERO_MARK 600 | |||||
#define SONY_RPT_LENGTH 45000 | |||||
#define SONY_DOUBLE_SPACE_USECS 500 // usually ssee 713 - not using ticks as get number wrapround | |||||
//+============================================================================= | |||||
#if SEND_SONY | |||||
void IRsend::sendSony (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(40); | |||||
// Header | |||||
mark(SONY_HDR_MARK); | |||||
space(SONY_HDR_SPACE); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark(SONY_ONE_MARK); | |||||
space(SONY_HDR_SPACE); | |||||
} else { | |||||
mark(SONY_ZERO_MARK); | |||||
space(SONY_HDR_SPACE); | |||||
} | |||||
} | |||||
// We will have ended with LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if DECODE_SONY | |||||
bool IRrecv::decodeSony (decode_results *results) | |||||
{ | |||||
long data = 0; | |||||
int offset = 0; // Dont skip first space, check its size | |||||
if (irparams.rawlen < (2 * SONY_BITS) + 2) return false ; | |||||
// Some Sony's deliver repeats fast after first | |||||
// unfortunately can't spot difference from of repeat from two fast clicks | |||||
if (results->rawbuf[offset] < SONY_DOUBLE_SPACE_USECS) { | |||||
// Serial.print("IR Gap found: "); | |||||
results->bits = 0; | |||||
results->value = REPEAT; | |||||
# ifdef DECODE_SANYO | |||||
results->decode_type = SANYO; | |||||
# else | |||||
results->decode_type = UNKNOWN; | |||||
# endif | |||||
return true; | |||||
} | |||||
offset++; | |||||
// Initial mark | |||||
if (!MATCH_MARK(results->rawbuf[offset++], SONY_HDR_MARK)) return false ; | |||||
while (offset + 1 < irparams.rawlen) { | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], SONY_HDR_SPACE)) break ; | |||||
if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) data = (data << 1) | 1 ; | |||||
else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Success | |||||
results->bits = (offset - 1) / 2; | |||||
if (results->bits < 12) { | |||||
results->bits = 0; | |||||
return false; | |||||
} | |||||
results->value = data; | |||||
results->decode_type = SONY; | |||||
return true; | |||||
} | |||||
#endif | |||||
/* | |||||
Assuming the protocol we are adding is for the (imaginary) manufacturer: Shuzu | |||||
Our fantasy protocol is a standard protocol, so we can use this standard | |||||
template without too much work. Some protocols are quite unique and will require | |||||
considerably more work in this file! It is way beyond the scope of this text to | |||||
explain how to reverse engineer "unusual" IR protocols. But, unless you own an | |||||
oscilloscope, the starting point is probably to use the rawDump.ino sketch and | |||||
try to spot the pattern! | |||||
Before you start, make sure the IR library is working OK: | |||||
# Open up the Arduino IDE | |||||
# Load up the rawDump.ino example sketch | |||||
# Run it | |||||
Now we can start to add our new protocol... | |||||
1. Copy this file to : ir_Shuzu.cpp | |||||
2. Replace all occurrences of "Shuzu" with the name of your protocol. | |||||
3. Tweak the #defines to suit your protocol. | |||||
4. If you're lucky, tweaking the #defines will make the default send() function | |||||
work. | |||||
5. Again, if you're lucky, tweaking the #defines will have made the default | |||||
decode() function work. | |||||
You have written the code to support your new protocol! | |||||
Now you must do a few things to add it to the IRremote system: | |||||
1. Open IRremote.h and make the following changes: | |||||
REMEMEBER to change occurences of "SHUZU" with the name of your protocol | |||||
A. At the top, in the section "Supported Protocols", add: | |||||
#define DECODE_SHUZU 1 | |||||
#define SEND_SHUZU 1 | |||||
B. In the section "enumerated list of all supported formats", add: | |||||
SHUZU, | |||||
to the end of the list (notice there is a comma after the protocol name) | |||||
C. Further down in "Main class for receiving IR", add: | |||||
//...................................................................... | |||||
#if DECODE_SHUZU | |||||
bool decodeShuzu (decode_results *results) ; | |||||
#endif | |||||
D. Further down in "Main class for sending IR", add: | |||||
//...................................................................... | |||||
#if SEND_SHUZU | |||||
void sendShuzu (unsigned long data, int nbits) ; | |||||
#endif | |||||
E. Save your changes and close the file | |||||
2. Now open irRecv.cpp and make the following change: | |||||
A. In the function IRrecv::decode(), add: | |||||
#ifdef DECODE_NEC | |||||
DBG_PRINTLN("Attempting Shuzu decode"); | |||||
if (decodeShuzu(results)) return true ; | |||||
#endif | |||||
B. Save your changes and close the file | |||||
You will probably want to add your new protocol to the example sketch | |||||
3. Open MyDocuments\Arduino\libraries\IRremote\examples\IRrecvDumpV2.ino | |||||
A. In the encoding() function, add: | |||||
case SHUZU: Serial.print("SHUZU"); break ; | |||||
Now open the Arduino IDE, load up the rawDump.ino sketch, and run it. | |||||
Hopefully it will compile and upload. | |||||
If it doesn't, you've done something wrong. Check your work. | |||||
If you can't get it to work - seek help from somewhere. | |||||
If you get this far, I will assume you have successfully added your new protocol | |||||
There is one last thing to do. | |||||
1. Delete this giant instructional comment. | |||||
2. Send a copy of your work to us so we can include it in the library and | |||||
others may benefit from your hard work and maybe even write a song about how | |||||
great you are for helping them! :) | |||||
Regards, | |||||
BlueChip | |||||
*/ | |||||
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.h" | |||||
//============================================================================== | |||||
// | |||||
// | |||||
// S H U Z U | |||||
// | |||||
// | |||||
//============================================================================== | |||||
#define BITS 32 // The number of bits in the command | |||||
#define HDR_MARK 1000 // The length of the Header:Mark | |||||
#define HDR_SPACE 2000 // The lenght of the Header:Space | |||||
#define BIT_MARK 3000 // The length of a Bit:Mark | |||||
#define ONE_SPACE 4000 // The length of a Bit:Space for 1's | |||||
#define ZERO_SPACE 5000 // The length of a Bit:Space for 0's | |||||
#define OTHER 1234 // Other things you may need to define | |||||
//+============================================================================= | |||||
// | |||||
#if SEND_SHUZU | |||||
void IRsend::sendShuzu (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(38); | |||||
// Header | |||||
mark (HDR_MARK); | |||||
space(HDR_SPACE); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark (BIT_MARK); | |||||
space(ONE_SPACE); | |||||
} else { | |||||
mark (BIT_MARK); | |||||
space(ZERO_SPACE); | |||||
} | |||||
} | |||||
// Footer | |||||
mark(BIT_MARK); | |||||
space(0); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
// | |||||
#if DECODE_SHUZU | |||||
bool IRrecv::decodeShuzu (decode_results *results) | |||||
{ | |||||
unsigned long data = 0; // Somewhere to build our code | |||||
int offset = 1; // Skip the Gap reading | |||||
// Check we have the right amount of data | |||||
if (irparams.rawlen != 1 + 2 + (2 * BITS) + 1) return false ; | |||||
// Check initial Mark+Space match | |||||
if (!MATCH_MARK (results->rawbuf[offset++], HDR_MARK )) return false ; | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], HDR_SPACE)) return false ; | |||||
// Read the bits in | |||||
for (int i = 0; i < SHUZU_BITS; i++) { | |||||
// Each bit looks like: MARK + SPACE_1 -> 1 | |||||
// or : MARK + SPACE_0 -> 0 | |||||
if (!MATCH_MARK(results->rawbuf[offset++], BIT_MARK)) return false ; | |||||
// IR data is big-endian, so we shuffle it in from the right: | |||||
if (MATCH_SPACE(results->rawbuf[offset], ONE_SPACE)) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// Success | |||||
results->bits = BITS; | |||||
results->value = data; | |||||
results->decode_type = SHUZU; | |||||
return true; | |||||
} | |||||
#endif |
#include "irr/IRremote.h" | |||||
#include "irr/IRremoteInt.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 | |||||
//============================================================================== | |||||
#define WHYNTER_BITS 32 | |||||
#define WHYNTER_HDR_MARK 2850 | |||||
#define WHYNTER_HDR_SPACE 2850 | |||||
#define WHYNTER_BIT_MARK 750 | |||||
#define WHYNTER_ONE_MARK 750 | |||||
#define WHYNTER_ONE_SPACE 2150 | |||||
#define WHYNTER_ZERO_MARK 750 | |||||
#define WHYNTER_ZERO_SPACE 750 | |||||
//+============================================================================= | |||||
#if SEND_WHYNTER | |||||
void IRsend::sendWhynter (unsigned long data, int nbits) | |||||
{ | |||||
// Set IR carrier frequency | |||||
enableIROut(38); | |||||
// Start | |||||
mark(WHYNTER_ZERO_MARK); | |||||
space(WHYNTER_ZERO_SPACE); | |||||
// Header | |||||
mark(WHYNTER_HDR_MARK); | |||||
space(WHYNTER_HDR_SPACE); | |||||
// Data | |||||
for (unsigned long mask = 1UL << (nbits - 1); mask; mask >>= 1) { | |||||
if (data & mask) { | |||||
mark(WHYNTER_ONE_MARK); | |||||
space(WHYNTER_ONE_SPACE); | |||||
} else { | |||||
mark(WHYNTER_ZERO_MARK); | |||||
space(WHYNTER_ZERO_SPACE); | |||||
} | |||||
} | |||||
// Footer | |||||
mark(WHYNTER_ZERO_MARK); | |||||
space(WHYNTER_ZERO_SPACE); // Always end with the LED off | |||||
} | |||||
#endif | |||||
//+============================================================================= | |||||
#if DECODE_WHYNTER | |||||
bool IRrecv::decodeWhynter (decode_results *results) | |||||
{ | |||||
long data = 0; | |||||
int offset = 1; // skip initial space | |||||
// Check we have the right amount of data | |||||
if (irparams.rawlen < (2 * WHYNTER_BITS) + 6) return false ; | |||||
// Sequence begins with a bit mark and a zero space | |||||
if (!MATCH_MARK (results->rawbuf[offset++], WHYNTER_BIT_MARK )) return false ; | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], WHYNTER_ZERO_SPACE)) return false ; | |||||
// header mark and space | |||||
if (!MATCH_MARK (results->rawbuf[offset++], WHYNTER_HDR_MARK )) return false ; | |||||
if (!MATCH_SPACE(results->rawbuf[offset++], WHYNTER_HDR_SPACE)) return false ; | |||||
// data bits | |||||
for (int i = 0; i < WHYNTER_BITS; i++) { | |||||
if (!MATCH_MARK(results->rawbuf[offset++], WHYNTER_BIT_MARK)) return false ; | |||||
if (MATCH_SPACE(results->rawbuf[offset], WHYNTER_ONE_SPACE )) data = (data << 1) | 1 ; | |||||
else if (MATCH_SPACE(results->rawbuf[offset], WHYNTER_ZERO_SPACE)) data = (data << 1) | 0 ; | |||||
else return false ; | |||||
offset++; | |||||
} | |||||
// trailing mark | |||||
if (!MATCH_MARK(results->rawbuf[offset], WHYNTER_BIT_MARK)) return false ; | |||||
// Success | |||||
results->bits = WHYNTER_BITS; | |||||
results->value = data; | |||||
results->decode_type = WHYNTER; | |||||
return true; | |||||
} | |||||
#endif | |||||