| @@ -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 | |||