- code copied from Teensyduino - restructured into src/ and include/ dirsmain
@@ -0,0 +1,458 @@ | |||
GNU LESSER GENERAL PUBLIC LICENSE | |||
Version 2.1, February 1999 | |||
Copyright (C) 1991, 1999 Free Software Foundation, Inc. | |||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
Everyone is permitted to copy and distribute verbatim copies | |||
of this license document, but changing it is not allowed. | |||
[This is the first released version of the Lesser GPL. It also counts | |||
as the successor of the GNU Library Public License, version 2, hence | |||
the version number 2.1.] | |||
Preamble | |||
The licenses for most software are designed to take away your | |||
freedom to share and change it. By contrast, the GNU General Public | |||
Licenses are intended to guarantee your freedom to share and change | |||
free software--to make sure the software is free for all its users. | |||
This license, the Lesser General Public License, applies to some | |||
specially designated software packages--typically libraries--of the | |||
Free Software Foundation and other authors who decide to use it. You | |||
can use it too, but we suggest you first think carefully about whether | |||
this license or the ordinary General Public License is the better | |||
strategy to use in any particular case, based on the explanations below. | |||
When we speak of free software, we are referring to freedom of use, | |||
not price. Our General Public Licenses are designed to make sure that | |||
you have the freedom to distribute copies of free software (and charge | |||
for this service if you wish); that you receive source code or can get | |||
it if you want it; that you can change the software and use pieces of | |||
it in new free programs; and that you are informed that you can do | |||
these things. | |||
To protect your rights, we need to make restrictions that forbid | |||
distributors to deny you these rights or to ask you to surrender these | |||
rights. These restrictions translate to certain responsibilities for | |||
you if you distribute copies of the library or if you modify it. | |||
For example, if you distribute copies of the library, whether gratis | |||
or for a fee, you must give the recipients all the rights that we gave | |||
you. You must make sure that they, too, receive or can get the source | |||
code. If you link other code with the library, you must provide | |||
complete object files to the recipients, so that they can relink them | |||
with the library after making changes to the library and recompiling | |||
it. And you must show them these terms so they know their rights. | |||
We protect your rights with a two-step method: (1) we copyright the | |||
library, and (2) we offer you this license, which gives you legal | |||
permission to copy, distribute and/or modify the library. | |||
To protect each distributor, we want to make it very clear that | |||
there is no warranty for the free library. Also, if the library is | |||
modified by someone else and passed on, the recipients should know | |||
that what they have is not the original version, so that the original | |||
author's reputation will not be affected by problems that might be | |||
introduced by others. | |||
Finally, software patents pose a constant threat to the existence of | |||
any free program. We wish to make sure that a company cannot | |||
effectively restrict the users of a free program by obtaining a | |||
restrictive license from a patent holder. Therefore, we insist that | |||
any patent license obtained for a version of the library must be | |||
consistent with the full freedom of use specified in this license. | |||
Most GNU software, including some libraries, is covered by the | |||
ordinary GNU General Public License. This license, the GNU Lesser | |||
General Public License, applies to certain designated libraries, and | |||
is quite different from the ordinary General Public License. We use | |||
this license for certain libraries in order to permit linking those | |||
libraries into non-free programs. | |||
When a program is linked with a library, whether statically or using | |||
a shared library, the combination of the two is legally speaking a | |||
combined work, a derivative of the original library. The ordinary | |||
General Public License therefore permits such linking only if the | |||
entire combination fits its criteria of freedom. The Lesser General | |||
Public License permits more lax criteria for linking other code with | |||
the library. | |||
We call this license the "Lesser" General Public License because it | |||
does Less to protect the user's freedom than the ordinary General | |||
Public License. It also provides other free software developers Less | |||
of an advantage over competing non-free programs. These disadvantages | |||
are the reason we use the ordinary General Public License for many | |||
libraries. However, the Lesser license provides advantages in certain | |||
special circumstances. | |||
For example, on rare occasions, there may be a special need to | |||
encourage the widest possible use of a certain library, so that it becomes | |||
a de-facto standard. To achieve this, non-free programs must be | |||
allowed to use the library. A more frequent case is that a free | |||
library does the same job as widely used non-free libraries. In this | |||
case, there is little to gain by limiting the free library to free | |||
software only, so we use the Lesser General Public License. | |||
In other cases, permission to use a particular library in non-free | |||
programs enables a greater number of people to use a large body of | |||
free software. For example, permission to use the GNU C Library in | |||
non-free programs enables many more people to use the whole GNU | |||
operating system, as well as its variant, the GNU/Linux operating | |||
system. | |||
Although the Lesser General Public License is Less protective of the | |||
users' freedom, it does ensure that the user of a program that is | |||
linked with the Library has the freedom and the wherewithal to run | |||
that program using a modified version of the Library. | |||
The precise terms and conditions for copying, distribution and | |||
modification follow. Pay close attention to the difference between a | |||
"work based on the library" and a "work that uses the library". The | |||
former contains code derived from the library, whereas the latter must | |||
be combined with the library in order to run. | |||
GNU LESSER GENERAL PUBLIC LICENSE | |||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
0. This License Agreement applies to any software library or other | |||
program which contains a notice placed by the copyright holder or | |||
other authorized party saying it may be distributed under the terms of | |||
this Lesser General Public License (also called "this License"). | |||
Each licensee is addressed as "you". | |||
A "library" means a collection of software functions and/or data | |||
prepared so as to be conveniently linked with application programs | |||
(which use some of those functions and data) to form executables. | |||
The "Library", below, refers to any such software library or work | |||
which has been distributed under these terms. A "work based on the | |||
Library" means either the Library or any derivative work under | |||
copyright law: that is to say, a work containing the Library or a | |||
portion of it, either verbatim or with modifications and/or translated | |||
straightforwardly into another language. (Hereinafter, translation is | |||
included without limitation in the term "modification".) | |||
"Source code" for a work means the preferred form of the work for | |||
making modifications to it. For a library, complete source code means | |||
all the source code for all modules it contains, plus any associated | |||
interface definition files, plus the scripts used to control compilation | |||
and installation of the library. | |||
Activities other than copying, distribution and modification are not | |||
covered by this License; they are outside its scope. The act of | |||
running a program using the Library is not restricted, and output from | |||
such a program is covered only if its contents constitute a work based | |||
on the Library (independent of the use of the Library in a tool for | |||
writing it). Whether that is true depends on what the Library does | |||
and what the program that uses the Library does. | |||
1. You may copy and distribute verbatim copies of the Library's | |||
complete source code as you receive it, in any medium, provided that | |||
you conspicuously and appropriately publish on each copy an | |||
appropriate copyright notice and disclaimer of warranty; keep intact | |||
all the notices that refer to this License and to the absence of any | |||
warranty; and distribute a copy of this License along with the | |||
Library. | |||
You may charge a fee for the physical act of transferring a copy, | |||
and you may at your option offer warranty protection in exchange for a | |||
fee. | |||
2. You may modify your copy or copies of the Library or any portion | |||
of it, thus forming a work based on the Library, and copy and | |||
distribute such modifications or work under the terms of Section 1 | |||
above, provided that you also meet all of these conditions: | |||
a) The modified work must itself be a software library. | |||
b) You must cause the files modified to carry prominent notices | |||
stating that you changed the files and the date of any change. | |||
c) You must cause the whole of the work to be licensed at no | |||
charge to all third parties under the terms of this License. | |||
d) If a facility in the modified Library refers to a function or a | |||
table of data to be supplied by an application program that uses | |||
the facility, other than as an argument passed when the facility | |||
is invoked, then you must make a good faith effort to ensure that, | |||
in the event an application does not supply such function or | |||
table, the facility still operates, and performs whatever part of | |||
its purpose remains meaningful. | |||
(For example, a function in a library to compute square roots has | |||
a purpose that is entirely well-defined independent of the | |||
application. Therefore, Subsection 2d requires that any | |||
application-supplied function or table used by this function must | |||
be optional: if the application does not supply it, the square | |||
root function must still compute square roots.) | |||
These requirements apply to the modified work as a whole. If | |||
identifiable sections of that work are not derived from the Library, | |||
and can be reasonably considered independent and separate works in | |||
themselves, then this License, and its terms, do not apply to those | |||
sections when you distribute them as separate works. But when you | |||
distribute the same sections as part of a whole which is a work based | |||
on the Library, the distribution of the whole must be on the terms of | |||
this License, whose permissions for other licensees extend to the | |||
entire whole, and thus to each and every part regardless of who wrote | |||
it. | |||
Thus, it is not the intent of this section to claim rights or contest | |||
your rights to work written entirely by you; rather, the intent is to | |||
exercise the right to control the distribution of derivative or | |||
collective works based on the Library. | |||
In addition, mere aggregation of another work not based on the Library | |||
with the Library (or with a work based on the Library) on a volume of | |||
a storage or distribution medium does not bring the other work under | |||
the scope of this License. | |||
3. You may opt to apply the terms of the ordinary GNU General Public | |||
License instead of this License to a given copy of the Library. To do | |||
this, you must alter all the notices that refer to this License, so | |||
that they refer to the ordinary GNU General Public License, version 2, | |||
instead of to this License. (If a newer version than version 2 of the | |||
ordinary GNU General Public License has appeared, then you can specify | |||
that version instead if you wish.) Do not make any other change in | |||
these notices. | |||
Once this change is made in a given copy, it is irreversible for | |||
that copy, so the ordinary GNU General Public License applies to all | |||
subsequent copies and derivative works made from that copy. | |||
This option is useful when you wish to copy part of the code of | |||
the Library into a program that is not a library. | |||
4. You may copy and distribute the Library (or a portion or | |||
derivative of it, under Section 2) in object code or executable form | |||
under the terms of Sections 1 and 2 above provided that you accompany | |||
it with the complete corresponding machine-readable source code, which | |||
must be distributed under the terms of Sections 1 and 2 above on a | |||
medium customarily used for software interchange. | |||
If distribution of object code is made by offering access to copy | |||
from a designated place, then offering equivalent access to copy the | |||
source code from the same place satisfies the requirement to | |||
distribute the source code, even though third parties are not | |||
compelled to copy the source along with the object code. | |||
5. A program that contains no derivative of any portion of the | |||
Library, but is designed to work with the Library by being compiled or | |||
linked with it, is called a "work that uses the Library". Such a | |||
work, in isolation, is not a derivative work of the Library, and | |||
therefore falls outside the scope of this License. | |||
However, linking a "work that uses the Library" with the Library | |||
creates an executable that is a derivative of the Library (because it | |||
contains portions of the Library), rather than a "work that uses the | |||
library". The executable is therefore covered by this License. | |||
Section 6 states terms for distribution of such executables. | |||
When a "work that uses the Library" uses material from a header file | |||
that is part of the Library, the object code for the work may be a | |||
derivative work of the Library even though the source code is not. | |||
Whether this is true is especially significant if the work can be | |||
linked without the Library, or if the work is itself a library. The | |||
threshold for this to be true is not precisely defined by law. | |||
If such an object file uses only numerical parameters, data | |||
structure layouts and accessors, and small macros and small inline | |||
functions (ten lines or less in length), then the use of the object | |||
file is unrestricted, regardless of whether it is legally a derivative | |||
work. (Executables containing this object code plus portions of the | |||
Library will still fall under Section 6.) | |||
Otherwise, if the work is a derivative of the Library, you may | |||
distribute the object code for the work under the terms of Section 6. | |||
Any executables containing that work also fall under Section 6, | |||
whether or not they are linked directly with the Library itself. | |||
6. As an exception to the Sections above, you may also combine or | |||
link a "work that uses the Library" with the Library to produce a | |||
work containing portions of the Library, and distribute that work | |||
under terms of your choice, provided that the terms permit | |||
modification of the work for the customer's own use and reverse | |||
engineering for debugging such modifications. | |||
You must give prominent notice with each copy of the work that the | |||
Library is used in it and that the Library and its use are covered by | |||
this License. You must supply a copy of this License. If the work | |||
during execution displays copyright notices, you must include the | |||
copyright notice for the Library among them, as well as a reference | |||
directing the user to the copy of this License. Also, you must do one | |||
of these things: | |||
a) Accompany the work with the complete corresponding | |||
machine-readable source code for the Library including whatever | |||
changes were used in the work (which must be distributed under | |||
Sections 1 and 2 above); and, if the work is an executable linked | |||
with the Library, with the complete machine-readable "work that | |||
uses the Library", as object code and/or source code, so that the | |||
user can modify the Library and then relink to produce a modified | |||
executable containing the modified Library. (It is understood | |||
that the user who changes the contents of definitions files in the | |||
Library will not necessarily be able to recompile the application | |||
to use the modified definitions.) | |||
b) Use a suitable shared library mechanism for linking with the | |||
Library. A suitable mechanism is one that (1) uses at run time a | |||
copy of the library already present on the user's computer system, | |||
rather than copying library functions into the executable, and (2) | |||
will operate properly with a modified version of the library, if | |||
the user installs one, as long as the modified version is | |||
interface-compatible with the version that the work was made with. | |||
c) Accompany the work with a written offer, valid for at | |||
least three years, to give the same user the materials | |||
specified in Subsection 6a, above, for a charge no more | |||
than the cost of performing this distribution. | |||
d) If distribution of the work is made by offering access to copy | |||
from a designated place, offer equivalent access to copy the above | |||
specified materials from the same place. | |||
e) Verify that the user has already received a copy of these | |||
materials or that you have already sent this user a copy. | |||
For an executable, the required form of the "work that uses the | |||
Library" must include any data and utility programs needed for | |||
reproducing the executable from it. However, as a special exception, | |||
the materials to be distributed need not include anything that is | |||
normally distributed (in either source or binary form) with the major | |||
components (compiler, kernel, and so on) of the operating system on | |||
which the executable runs, unless that component itself accompanies | |||
the executable. | |||
It may happen that this requirement contradicts the license | |||
restrictions of other proprietary libraries that do not normally | |||
accompany the operating system. Such a contradiction means you cannot | |||
use both them and the Library together in an executable that you | |||
distribute. | |||
7. You may place library facilities that are a work based on the | |||
Library side-by-side in a single library together with other library | |||
facilities not covered by this License, and distribute such a combined | |||
library, provided that the separate distribution of the work based on | |||
the Library and of the other library facilities is otherwise | |||
permitted, and provided that you do these two things: | |||
a) Accompany the combined library with a copy of the same work | |||
based on the Library, uncombined with any other library | |||
facilities. This must be distributed under the terms of the | |||
Sections above. | |||
b) Give prominent notice with the combined library of the fact | |||
that part of it is a work based on the Library, and explaining | |||
where to find the accompanying uncombined form of the same work. | |||
8. You may not copy, modify, sublicense, link with, or distribute | |||
the Library except as expressly provided under this License. Any | |||
attempt otherwise to copy, modify, sublicense, link with, or | |||
distribute the Library is void, and will automatically terminate your | |||
rights under this License. However, parties who have received copies, | |||
or rights, from you under this License will not have their licenses | |||
terminated so long as such parties remain in full compliance. | |||
9. You are not required to accept this License, since you have not | |||
signed it. However, nothing else grants you permission to modify or | |||
distribute the Library or its derivative works. These actions are | |||
prohibited by law if you do not accept this License. Therefore, by | |||
modifying or distributing the Library (or any work based on the | |||
Library), you indicate your acceptance of this License to do so, and | |||
all its terms and conditions for copying, distributing or modifying | |||
the Library or works based on it. | |||
10. Each time you redistribute the Library (or any work based on the | |||
Library), the recipient automatically receives a license from the | |||
original licensor to copy, distribute, link with or modify the Library | |||
subject to these terms and conditions. You may not impose any further | |||
restrictions on the recipients' exercise of the rights granted herein. | |||
You are not responsible for enforcing compliance by third parties with | |||
this License. | |||
11. If, as a consequence of a court judgment or allegation of patent | |||
infringement or for any other reason (not limited to patent issues), | |||
conditions are imposed on you (whether by court order, agreement or | |||
otherwise) that contradict the conditions of this License, they do not | |||
excuse you from the conditions of this License. If you cannot | |||
distribute so as to satisfy simultaneously your obligations under this | |||
License and any other pertinent obligations, then as a consequence you | |||
may not distribute the Library at all. For example, if a patent | |||
license would not permit royalty-free redistribution of the Library by | |||
all those who receive copies directly or indirectly through you, then | |||
the only way you could satisfy both it and this License would be to | |||
refrain entirely from distribution of the Library. | |||
If any portion of this section is held invalid or unenforceable under any | |||
particular circumstance, the balance of the section is intended to apply, | |||
and the section as a whole is intended to apply in other circumstances. | |||
It is not the purpose of this section to induce you to infringe any | |||
patents or other property right claims or to contest validity of any | |||
such claims; this section has the sole purpose of protecting the | |||
integrity of the free software distribution system which is | |||
implemented by public license practices. Many people have made | |||
generous contributions to the wide range of software distributed | |||
through that system in reliance on consistent application of that | |||
system; it is up to the author/donor to decide if he or she is willing | |||
to distribute software through any other system and a licensee cannot | |||
impose that choice. | |||
This section is intended to make thoroughly clear what is believed to | |||
be a consequence of the rest of this License. | |||
12. If the distribution and/or use of the Library is restricted in | |||
certain countries either by patents or by copyrighted interfaces, the | |||
original copyright holder who places the Library under this License may add | |||
an explicit geographical distribution limitation excluding those countries, | |||
so that distribution is permitted only in or among countries not thus | |||
excluded. In such case, this License incorporates the limitation as if | |||
written in the body of this License. | |||
13. The Free Software Foundation may publish revised and/or new | |||
versions of the Lesser General Public License from time to time. | |||
Such new versions will be similar in spirit to the present version, | |||
but may differ in detail to address new problems or concerns. | |||
Each version is given a distinguishing version number. If the Library | |||
specifies a version number of this License which applies to it and | |||
"any later version", you have the option of following the terms and | |||
conditions either of that version or of any later version published by | |||
the Free Software Foundation. If the Library does not specify a | |||
license version number, you may choose any version ever published by | |||
the Free Software Foundation. | |||
14. If you wish to incorporate parts of the Library into other free | |||
programs whose distribution conditions are incompatible with these, | |||
write to the author to ask for permission. For software which is | |||
copyrighted by the Free Software Foundation, write to the Free | |||
Software Foundation; we sometimes make exceptions for this. Our | |||
decision will be guided by the two goals of preserving the free status | |||
of all derivatives of our free software and of promoting the sharing | |||
and reuse of software generally. | |||
NO WARRANTY | |||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | |||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | |||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | |||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | |||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | |||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | |||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | |||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | |||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | |||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | |||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | |||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | |||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |||
DAMAGES. | |||
@@ -0,0 +1,78 @@ | |||
## 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 |
@@ -0,0 +1,22 @@ | |||
## 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. |
@@ -0,0 +1,26 @@ | |||
/* | |||
* 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 | |||
} | |||
} |
@@ -0,0 +1,183 @@ | |||
/* | |||
* 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; | |||
} |
@@ -0,0 +1,33 @@ | |||
/* | |||
* 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); | |||
} |
@@ -0,0 +1,95 @@ | |||
/* | |||
* 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 | |||
} | |||
} |
@@ -0,0 +1,177 @@ | |||
//------------------------------------------------------------------------------ | |||
// 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 | |||
} | |||
} |
@@ -0,0 +1,85 @@ | |||
/* | |||
* 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 | |||
} | |||
} |
@@ -0,0 +1,230 @@ | |||
/* | |||
* 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")); | |||
} |
@@ -0,0 +1,24 @@ | |||
/* | |||
* 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 | |||
} |
@@ -0,0 +1,37 @@ | |||
/* | |||
* 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. | |||
} |
@@ -0,0 +1,190 @@ | |||
/* | |||
* 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() { | |||
} |
@@ -0,0 +1,290 @@ | |||
/* | |||
* 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); | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
/* | |||
* 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); | |||
} |
@@ -0,0 +1,263 @@ | |||
#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 ; | |||
} | |||
@@ -0,0 +1,93 @@ | |||
=== 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 |
@@ -0,0 +1,22 @@ | |||
/* | |||
* 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); | |||
} |
@@ -0,0 +1,193 @@ | |||
/* | |||
* 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); | |||
} |
@@ -0,0 +1,344 @@ | |||
//****************************************************************************** | |||
// 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 |
@@ -0,0 +1,113 @@ | |||
//****************************************************************************** | |||
// 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 |
@@ -0,0 +1,661 @@ | |||
//****************************************************************************** | |||
// 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 |
@@ -0,0 +1,115 @@ | |||
//============================================================================== | |||
// 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; | |||
} | |||
} | |||
}; |
@@ -0,0 +1,203 @@ | |||
//****************************************************************************** | |||
// 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 | |||
} | |||
} |
@@ -0,0 +1,513 @@ | |||
#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 |
@@ -0,0 +1,239 @@ | |||
#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; | |||
} |
@@ -0,0 +1,90 @@ | |||
#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 | |||
//} | |||
} | |||
@@ -0,0 +1,105 @@ | |||
#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 |
@@ -0,0 +1,94 @@ | |||
#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 |
@@ -0,0 +1,54 @@ | |||
#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 | |||
@@ -0,0 +1,101 @@ | |||
#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 | |||
@@ -0,0 +1,80 @@ | |||
#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 | |||
@@ -0,0 +1,46 @@ | |||
#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 |
@@ -0,0 +1,85 @@ | |||
#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 | |||
@@ -0,0 +1,98 @@ | |||
#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 |
@@ -0,0 +1,78 @@ | |||
#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 | |||
@@ -0,0 +1,207 @@ | |||
#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 |
@@ -0,0 +1,92 @@ | |||
#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 | |||
@@ -0,0 +1,76 @@ | |||
#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 |
@@ -0,0 +1,71 @@ | |||
#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 |
@@ -0,0 +1,95 @@ | |||
#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 | |||
@@ -0,0 +1,179 @@ | |||
/* | |||
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 |
@@ -0,0 +1,91 @@ | |||
#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 | |||