From d571669182f4aa5e15c036f8c0c53f1c792f1a3a Mon Sep 17 00:00:00 2001 From: "Mr.Blinky" Date: Mon, 10 Sep 2018 21:01:23 +0200 Subject: [PATCH] added board package source (part 3 libraries) --- .../libraries/ArdVoice/LICENSE.md | 201 ++++++ .../libraries/ArdVoice/README.md | 47 ++ .../examples/Sample1-Basic/Sample1-Basic.ino | 27 + .../ArdVoice/examples/Sample1-Basic/voices.h | 534 ++++++++++++++++ .../Sample2-Complex/Sample2-Complex.ino | 135 ++++ .../examples/Sample2-Complex/bitmaps.h | 197 ++++++ .../examples/Sample2-Complex/voices.h | 594 ++++++++++++++++++ .../ArdVoice/extras/assets/merry.wav | Bin 0 -> 189205 bytes .../libraries/ArdVoice/extras/assets/one.wav | Bin 0 -> 3251 bytes .../ArdVoice/extras/assets/three.wav | Bin 0 -> 3733 bytes .../libraries/ArdVoice/extras/assets/two.wav | Bin 0 -> 3744 bytes .../ArdVoice/extras/vocoder/vocoder0.2.jar | Bin 0 -> 12346 bytes .../libraries/ArdVoice/keywords.txt | 23 + .../libraries/ArdVoice/library.properties | 9 + .../libraries/ArdVoice/src/ArdVoice.cpp | 219 +++++++ .../libraries/ArdVoice/src/ArdVoice.h | 54 ++ .../libraries/Arduboy-TinyFont/LICENSE | 29 + .../libraries/Arduboy-TinyFont/README.md | 141 +++++ .../Arduboy-TinyFont/bitmaps/4x4font.psd | Bin 0 -> 194420 bytes .../bitmaps/tinyfont-preview.png | Bin 0 -> 3712 bytes .../Arduboy-TinyFont/bitmaps/tinyfont_8x8.png | Bin 0 -> 690 bytes .../TinyfontSample/TinyfontSample.ino | 47 ++ .../libraries/Arduboy-TinyFont/keywords.txt | 7 + .../libraries/Arduboy-TinyFont/library.json | 21 + .../Arduboy-TinyFont/library.properties | 10 + .../Arduboy-TinyFont/src/Tinyfont.cpp | 123 ++++ .../libraries/Arduboy-TinyFont/src/Tinyfont.h | 109 ++++ .../Arduboy-TinyFont/src/TinyfontSprite.c | 36 ++ .../libraries/ArduboyTones/LICENSE.txt | 19 + .../libraries/ArduboyTones/README.md | 222 +++++++ .../ArduboyTonesTest/ArduboyTonesTest.ino | 228 +++++++ .../libraries/ArduboyTones/extras/Doxyfile | 329 ++++++++++ .../extras/docs/FILE_DESCRIPTIONS.md | 22 + .../libraries/ArduboyTones/keywords.txt | 30 + .../libraries/ArduboyTones/library.json | 14 + .../libraries/ArduboyTones/library.properties | 9 + .../ArduboyTones/src/ArduboyTones.cpp | 287 +++++++++ .../libraries/ArduboyTones/src/ArduboyTones.h | 305 +++++++++ .../ArduboyTones/src/ArduboyTonesPitches.h | 254 ++++++++ .../libraries/EEPROM/README.md | 139 ++++ .../examples/eeprom_clear/eeprom_clear.ino | 39 ++ .../EEPROM/examples/eeprom_crc/eeprom_crc.ino | 52 ++ .../EEPROM/examples/eeprom_get/eeprom_get.ino | 68 ++ .../eeprom_iteration/eeprom_iteration.ino | 57 ++ .../EEPROM/examples/eeprom_put/eeprom_put.ino | 58 ++ .../examples/eeprom_read/eeprom_read.ino | 56 ++ .../examples/eeprom_update/eeprom_update.ino | 71 +++ .../examples/eeprom_write/eeprom_write.ino | 60 ++ .../libraries/EEPROM/keywords.txt | 22 + .../libraries/EEPROM/library.properties | 10 + .../libraries/EEPROM/src/EEPROM.h | 146 +++++ .../libraries/FixedPointsArduino/LICENCE | 201 ++++++ .../libraries/FixedPointsArduino/README.md | 176 ++++++ .../FixedPointCalculations.ino | 171 +++++ .../extras/AFixedPointPrimer.md | 69 ++ .../FixedPointsArduino/extras/Credits.md | 14 + .../FixedPointsArduino/extras/Hello.txt | 8 + .../FixedPointsArduino/extras/Important.txt | 6 + .../libraries/FixedPointsArduino/keywords.txt | 47 ++ .../libraries/FixedPointsArduino/library.json | 18 + .../FixedPointsArduino/library.properties | 10 + .../FixedPointsArduino/src/FixedPoints.h | 15 + .../src/FixedPoints/Details.h | 205 ++++++ .../src/FixedPoints/FixedPoints.h | 20 + .../src/FixedPoints/SFixed.h | 219 +++++++ .../src/FixedPoints/SFixedFreeFunctions.h | 323 ++++++++++ .../src/FixedPoints/SFixedMemberFunctions.h | 273 ++++++++ .../src/FixedPoints/UFixed.h | 220 +++++++ .../src/FixedPoints/UFixedFreeFunctions.h | 323 ++++++++++ .../src/FixedPoints/UFixedMemberFunctions.h | 258 ++++++++ .../src/FixedPoints/Utils.h | 256 ++++++++ .../src/FixedPointsCommon.h | 15 + .../src/FixedPointsCommon/FixedPointsCommon.h | 18 + .../src/FixedPointsCommon/SFixedCommon.h | 29 + .../src/FixedPointsCommon/UFixedCommon.h | 29 + .../libraries/HID/keywords.txt | 21 + .../libraries/HID/library.properties | 9 + .../libraries/HID/src/HID.cpp | 162 +++++ board-package-source/libraries/HID/src/HID.h | 125 ++++ .../BarometricPressureSensor.ino | 143 +++++ .../DigitalPotControl/DigitalPotControl.ino | 71 +++ .../libraries/SPI/keywords.txt | 36 ++ .../libraries/SPI/library.properties | 10 + .../libraries/SPI/src/SPI.cpp | 201 ++++++ board-package-source/libraries/SPI/src/SPI.h | 324 ++++++++++ .../SoftwareSerialExample.ino | 55 ++ .../TwoPortReceive/TwoPortReceive.ino | 91 +++ .../libraries/SoftwareSerial/keywords.txt | 30 + .../SoftwareSerial/library.properties | 10 + .../SoftwareSerial/src/SoftwareSerial.cpp | 486 ++++++++++++++ .../SoftwareSerial/src/SoftwareSerial.h | 123 ++++ 91 files changed, 9880 insertions(+) create mode 100644 board-package-source/libraries/ArdVoice/LICENSE.md create mode 100644 board-package-source/libraries/ArdVoice/README.md create mode 100644 board-package-source/libraries/ArdVoice/examples/Sample1-Basic/Sample1-Basic.ino create mode 100644 board-package-source/libraries/ArdVoice/examples/Sample1-Basic/voices.h create mode 100644 board-package-source/libraries/ArdVoice/examples/Sample2-Complex/Sample2-Complex.ino create mode 100644 board-package-source/libraries/ArdVoice/examples/Sample2-Complex/bitmaps.h create mode 100644 board-package-source/libraries/ArdVoice/examples/Sample2-Complex/voices.h create mode 100644 board-package-source/libraries/ArdVoice/extras/assets/merry.wav create mode 100644 board-package-source/libraries/ArdVoice/extras/assets/one.wav create mode 100644 board-package-source/libraries/ArdVoice/extras/assets/three.wav create mode 100644 board-package-source/libraries/ArdVoice/extras/assets/two.wav create mode 100644 board-package-source/libraries/ArdVoice/extras/vocoder/vocoder0.2.jar create mode 100644 board-package-source/libraries/ArdVoice/keywords.txt create mode 100644 board-package-source/libraries/ArdVoice/library.properties create mode 100644 board-package-source/libraries/ArdVoice/src/ArdVoice.cpp create mode 100644 board-package-source/libraries/ArdVoice/src/ArdVoice.h create mode 100644 board-package-source/libraries/Arduboy-TinyFont/LICENSE create mode 100644 board-package-source/libraries/Arduboy-TinyFont/README.md create mode 100644 board-package-source/libraries/Arduboy-TinyFont/bitmaps/4x4font.psd create mode 100644 board-package-source/libraries/Arduboy-TinyFont/bitmaps/tinyfont-preview.png create mode 100644 board-package-source/libraries/Arduboy-TinyFont/bitmaps/tinyfont_8x8.png create mode 100644 board-package-source/libraries/Arduboy-TinyFont/examples/TinyfontSample/TinyfontSample.ino create mode 100644 board-package-source/libraries/Arduboy-TinyFont/keywords.txt create mode 100644 board-package-source/libraries/Arduboy-TinyFont/library.json create mode 100644 board-package-source/libraries/Arduboy-TinyFont/library.properties create mode 100644 board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.cpp create mode 100644 board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.h create mode 100644 board-package-source/libraries/Arduboy-TinyFont/src/TinyfontSprite.c create mode 100644 board-package-source/libraries/ArduboyTones/LICENSE.txt create mode 100644 board-package-source/libraries/ArduboyTones/README.md create mode 100644 board-package-source/libraries/ArduboyTones/examples/ArduboyTonesTest/ArduboyTonesTest.ino create mode 100644 board-package-source/libraries/ArduboyTones/extras/Doxyfile create mode 100644 board-package-source/libraries/ArduboyTones/extras/docs/FILE_DESCRIPTIONS.md create mode 100644 board-package-source/libraries/ArduboyTones/keywords.txt create mode 100644 board-package-source/libraries/ArduboyTones/library.json create mode 100644 board-package-source/libraries/ArduboyTones/library.properties create mode 100644 board-package-source/libraries/ArduboyTones/src/ArduboyTones.cpp create mode 100644 board-package-source/libraries/ArduboyTones/src/ArduboyTones.h create mode 100644 board-package-source/libraries/ArduboyTones/src/ArduboyTonesPitches.h create mode 100644 board-package-source/libraries/EEPROM/README.md create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino create mode 100644 board-package-source/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino create mode 100644 board-package-source/libraries/EEPROM/keywords.txt create mode 100644 board-package-source/libraries/EEPROM/library.properties create mode 100644 board-package-source/libraries/EEPROM/src/EEPROM.h create mode 100644 board-package-source/libraries/FixedPointsArduino/LICENCE create mode 100644 board-package-source/libraries/FixedPointsArduino/README.md create mode 100644 board-package-source/libraries/FixedPointsArduino/examples/FixedPointCalculations/FixedPointCalculations.ino create mode 100644 board-package-source/libraries/FixedPointsArduino/extras/AFixedPointPrimer.md create mode 100644 board-package-source/libraries/FixedPointsArduino/extras/Credits.md create mode 100644 board-package-source/libraries/FixedPointsArduino/extras/Hello.txt create mode 100644 board-package-source/libraries/FixedPointsArduino/extras/Important.txt create mode 100644 board-package-source/libraries/FixedPointsArduino/keywords.txt create mode 100644 board-package-source/libraries/FixedPointsArduino/library.json create mode 100644 board-package-source/libraries/FixedPointsArduino/library.properties create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Details.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/FixedPoints.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixed.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedFreeFunctions.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedMemberFunctions.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixed.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedFreeFunctions.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedMemberFunctions.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Utils.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/FixedPointsCommon.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/SFixedCommon.h create mode 100644 board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/UFixedCommon.h create mode 100644 board-package-source/libraries/HID/keywords.txt create mode 100644 board-package-source/libraries/HID/library.properties create mode 100644 board-package-source/libraries/HID/src/HID.cpp create mode 100644 board-package-source/libraries/HID/src/HID.h create mode 100644 board-package-source/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino create mode 100644 board-package-source/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino create mode 100644 board-package-source/libraries/SPI/keywords.txt create mode 100644 board-package-source/libraries/SPI/library.properties create mode 100644 board-package-source/libraries/SPI/src/SPI.cpp create mode 100644 board-package-source/libraries/SPI/src/SPI.h create mode 100644 board-package-source/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino create mode 100644 board-package-source/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino create mode 100644 board-package-source/libraries/SoftwareSerial/keywords.txt create mode 100644 board-package-source/libraries/SoftwareSerial/library.properties create mode 100644 board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.cpp create mode 100644 board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.h diff --git a/board-package-source/libraries/ArdVoice/LICENSE.md b/board-package-source/libraries/ArdVoice/LICENSE.md new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/board-package-source/libraries/ArdVoice/LICENSE.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/board-package-source/libraries/ArdVoice/README.md b/board-package-source/libraries/ArdVoice/README.md new file mode 100644 index 0000000..aa66002 --- /dev/null +++ b/board-package-source/libraries/ArdVoice/README.md @@ -0,0 +1,47 @@ +# ArdVoice: A library to play audio (voices) on the Arduboy +By @igvina +## Features: +### Voice library: +* Play compressed audio (works better with voices) +* Good speed but can cause slowdowns on 60 fps games +* Configurable speed (from 0.8 to 1.4) + +### Voice compressor (vocoder): +* Works with wav (only 8000 Hz, mono, 1 byte PCM_UNSIGNED). I recommend Audacity to convert to this format +* Configurable quality (from 0 to 10), default is 4 +* Good compression (from 88 bytes/s to 530 bytes/s) + +## Video: + + + +## Usage: +### Vocoder (v0.2): +* Syntax: java -jar vocoder0.2.jar audio.wav [-options] + * options: + * -q VALUE Quality (0 - 10) default: 4 + * -gs SKETCH_FOLDER Generate sketch code + * -v Play compressed voice + * -anp PREFIX Array name prefix + * -ver Show vocoder version + + * examples: + + "java -jar vocoder.jar dog.wav -gs DOG -v -q 6" + "java -jar vocoder.jar merry.wav -v" + +### Voice library (v0.1): + +* Install the ArdVoice library in the Arduino IDE. +* Add in .ino file: + * `#include ` + * `ArdVoice ardvoice;` +* To play voice call function: ardvoice.playVoice (...). + +#### Methods: +* `void playVoice(const char *audio);` +* `void playVoice(const char *audio, uint16_t startTime, uint16_t endTime, float speed);` +* `void stopVoice();` +* `boolean isVoicePlaying();` diff --git a/board-package-source/libraries/ArdVoice/examples/Sample1-Basic/Sample1-Basic.ino b/board-package-source/libraries/ArdVoice/examples/Sample1-Basic/Sample1-Basic.ino new file mode 100644 index 0000000..895aa10 --- /dev/null +++ b/board-package-source/libraries/ArdVoice/examples/Sample1-Basic/Sample1-Basic.ino @@ -0,0 +1,27 @@ +#include +#include +#include "voices.h" + +Arduboy2 arduboy; +ArdVoice ardvoice; + +void setup() { + arduboy.begin(); + arduboy.setFrameRate(30); + ardvoice.playVoice(merry_q6); +} + + +void loop() { + if (!(arduboy.nextFrame())) + return; + + if (arduboy.pressed(B_BUTTON)){ + ardvoice.playVoice(merry_q6); + } + + if (arduboy.pressed(A_BUTTON)){ + ardvoice.stopVoice(); + } +} + diff --git a/board-package-source/libraries/ArdVoice/examples/Sample1-Basic/voices.h b/board-package-source/libraries/ArdVoice/examples/Sample1-Basic/voices.h new file mode 100644 index 0000000..22fe661 --- /dev/null +++ b/board-package-source/libraries/ArdVoice/examples/Sample1-Basic/voices.h @@ -0,0 +1,534 @@ +const uint8_t merry_q6[] PROGMEM ={ +0x1c, 0x64, 0x12, 0x00, 0x42, 0x39, 0x42, 0x38, 0x37, 0x43, 0x19, 0x00, 0x2b, 0x33, 0x43, 0x3f, +0x3d, 0x35, 0x7e, 0x00, 0x2c, 0x3e, 0x37, 0x47, 0x40, 0x41, 0x00, 0x00, 0x27, 0x3a, 0x46, 0x3d, +0x47, 0x46, 0x07, 0x0c, 0x92, 0xf3, 0x0e, 0x6e, 0x20, 0x51, 0x07, 0x1d, 0x89, 0x7f, 0x19, 0x65, +0x27, 0x54, 0x22, 0x19, 0x80, 0x65, 0x27, 0x5a, 0x37, 0x4a, 0x18, 0x0b, 0x8e, 0x7c, 0x17, 0x69, +0x29, 0x4d, 0x2f, 0x03, 0x9a, 0xf0, 0x18, 0x69, 0x1a, 0x50, 0x02, 0x02, 0x9d, 0xe5, 0x01, 0x6e, +0x21, 0x4b, 0x01, 0x01, 0x8f, 0x6a, 0x33, 0x4c, 0x38, 0x43, 0x07, 0x02, 0x85, 0x6d, 0x27, 0x59, +0x27, 0x56, 0x07, 0x27, 0x81, 0x7c, 0x13, 0x6c, 0x1e, 0x5b, 0x23, 0x44, 0x83, 0x73, 0x20, 0x62, +0x27, 0x58, 0x23, 0x22, 0x8d, 0xfd, 0x0e, 0x67, 0x2d, 0x52, 0x18, 0x09, 0x9b, 0xe9, 0x0f, 0x4b, +0x4b, 0x3a, 0x17, 0x07, 0x96, 0xfa, 0x20, 0x5e, 0x2f, 0x47, 0x17, 0x00, 0x97, 0xfe, 0x1b, 0x66, +0x2d, 0x41, 0x03, 0x01, 0x95, 0xf9, 0x21, 0x51, 0x3d, 0x43, 0x07, 0x02, 0x94, 0xf6, 0x15, 0x5a, +0x36, 0x4a, 0x0c, 0x11, 0x95, 0xe7, 0x91, 0xf8, 0x16, 0x55, 0x3d, 0x37, 0x89, 0x7f, 0x10, 0x69, +0x23, 0x51, 0x3d, 0x43, 0x8b, 0x79, 0x14, 0x66, 0x25, 0x52, 0x3d, 0x41, 0x8b, 0x76, 0x18, 0x66, +0x1c, 0x57, 0x3d, 0x36, 0x87, 0x6d, 0x1b, 0x64, 0x23, 0x53, 0x3d, 0x33, 0x8e, 0x7c, 0x13, 0x68, +0x27, 0x4a, 0x3d, 0x34, 0x88, 0x76, 0x12, 0x6f, 0x1f, 0x50, 0x3d, 0x2d, 0x8b, 0xfe, 0x07, 0x77, +0x1b, 0x50, 0x3e, 0x37, 0x83, 0x70, 0x11, 0x71, 0x1f, 0x55, 0x3e, 0x2f, 0x82, 0x68, 0x1b, 0x62, +0x2d, 0x51, 0x3d, 0x4a, 0x85, 0x6b, 0x1b, 0x63, 0x31, 0x4c, 0x3d, 0x3c, 0x86, 0x6f, 0x19, 0x66, +0x2c, 0x4d, 0x3d, 0x21, 0x90, 0x7f, 0x10, 0x71, 0x20, 0x4c, 0x3e, 0x13, 0x90, 0xff, 0x0c, 0x74, +0x15, 0x56, 0x3e, 0x0a, 0x95, 0xef, 0x8a, 0x79, 0x1c, 0x50, 0x08, 0x08, 0x92, 0x71, 0x33, 0x46, +0x3d, 0x43, 0x08, 0x24, 0x94, 0xfe, 0x20, 0x57, 0x34, 0x47, 0x5a, 0x31, 0x91, 0xfc, 0x17, 0x68, +0x1d, 0x54, 0x10, 0x41, 0x8b, 0x65, 0x30, 0x61, 0x1b, 0x52, 0x07, 0x3b, 0x8e, 0x68, 0x31, 0x63, +0x1f, 0x4c, 0x59, 0x3f, 0x8f, 0x6f, 0x2d, 0x5f, 0x2a, 0x45, 0x59, 0x4f, 0x8e, 0x75, 0x29, 0x56, +0x34, 0x42, 0x59, 0x4d, 0x8a, 0x6e, 0x2b, 0x55, 0x34, 0x48, 0x59, 0x54, 0x86, 0x6a, 0x2b, 0x53, +0x37, 0x46, 0x59, 0x3e, 0x8a, 0x6e, 0x1c, 0x63, 0x31, 0x47, 0x07, 0x2b, 0x87, 0x6c, 0x18, 0x6b, +0x2a, 0x4a, 0x59, 0x37, 0x90, 0x77, 0x1f, 0x66, 0x23, 0x4d, 0x10, 0x38, 0x92, 0xfb, 0x1e, 0x5e, +0x27, 0x4d, 0x10, 0x21, 0x94, 0x7e, 0x25, 0x58, 0x2f, 0x45, 0x1a, 0x0f, 0x91, 0x78, 0x2e, 0x45, +0x3e, 0x44, 0x09, 0x0b, 0x91, 0x72, 0x2b, 0x54, 0x33, 0x49, 0x09, 0x17, 0x99, 0xf4, 0x25, 0x4f, +0x2f, 0x4b, 0x36, 0x1f, 0x97, 0xf2, 0x19, 0x58, 0x34, 0x47, 0x09, 0x35, 0x96, 0xf8, 0x1e, 0x55, +0x33, 0x47, 0x09, 0x34, 0x96, 0xf1, 0x0a, 0x64, 0x2d, 0x49, 0x36, 0x34, 0x94, 0xf8, 0x0d, 0x6f, +0x22, 0x4d, 0x09, 0x42, 0x94, 0xf4, 0x0f, 0x64, 0x2d, 0x48, 0x35, 0x39, 0x90, 0x78, 0x24, 0x59, +0x33, 0x46, 0x09, 0x3a, 0x8c, 0x6e, 0x29, 0x59, 0x2c, 0x4d, 0x35, 0x36, 0x91, 0xfe, 0x1b, 0x68, +0x21, 0x4f, 0x08, 0x35, 0x92, 0xfc, 0x17, 0x62, 0x29, 0x4a, 0x09, 0x2d, 0x94, 0xf8, 0x16, 0x58, +0x35, 0x47, 0x09, 0x18, 0x99, 0xe7, 0x84, 0x69, 0x31, 0x45, 0x10, 0x13, 0x9a, 0xe8, 0x83, 0x6a, +0x29, 0x48, 0x35, 0x0c, 0x96, 0xf5, 0x18, 0x58, 0x33, 0x45, 0x0e, 0x03, 0x92, 0xfe, 0x11, 0x61, +0x2a, 0x4b, 0x09, 0x03, 0x8e, 0x6f, 0x26, 0x53, 0x29, 0x53, 0x07, 0x1a, 0x98, 0xef, 0x03, 0x6f, +0x23, 0x49, 0x07, 0x54, 0x92, 0xf4, 0x0f, 0x5b, 0x32, 0x43, 0x07, 0x5f, 0x89, 0x7d, 0x16, 0x60, +0x2e, 0x47, 0x22, 0x5c, 0x88, 0x79, 0x1a, 0x56, 0x2f, 0x48, 0x22, 0x43, 0x8f, 0xf8, 0x10, 0x57, +0x31, 0x46, 0x07, 0x3c, 0x8c, 0x7f, 0x16, 0x5e, 0x26, 0x4d, 0x07, 0x30, 0x86, 0x6a, 0x24, 0x60, +0x28, 0x4a, 0x07, 0x2d, 0x8d, 0x7e, 0x12, 0x5e, 0x31, 0x49, 0x07, 0x1b, 0x97, 0xef, 0x03, 0x67, +0x28, 0x4e, 0x22, 0x13, 0x97, 0xf6, 0x1b, 0x46, 0x4c, 0x3b, 0x59, 0x0d, 0x97, 0x7f, 0x3a, 0x37, +0x46, 0x3e, 0x23, 0x07, 0x9c, 0xe8, 0x0a, 0x4b, 0x4b, 0x3a, 0x5a, 0x04, 0x95, 0x7f, 0x1e, 0x49, +0x47, 0x40, 0x67, 0x03, 0x9a, 0xf3, 0x14, 0x5d, 0x33, 0x45, 0x63, 0x02, 0x95, 0x7c, 0x1c, 0x65, +0x22, 0x50, 0x07, 0x02, 0x94, 0xfa, 0x15, 0x5c, 0x29, 0x4b, 0x08, 0x14, 0x94, 0xee, 0x87, 0x72, +0x1f, 0x51, 0x5b, 0x1b, 0x92, 0xf2, 0x84, 0x71, 0x1e, 0x53, 0x00, 0x17, 0x94, 0xf9, 0x16, 0x57, +0x30, 0x4b, 0x23, 0x19, 0x90, 0x71, 0x28, 0x58, 0x2e, 0x48, 0x5a, 0x0f, 0x9a, 0xe7, 0x85, 0x6e, +0x28, 0x49, 0x23, 0x0c, 0x9d, 0xe3, 0x91, 0x7f, 0x1d, 0x4b, 0x23, 0x05, 0x9f, 0xde, 0x96, 0x77, +0x29, 0x48, 0x3f, 0x05, 0x9e, 0xe1, 0x8f, 0x71, 0x2a, 0x46, 0x23, 0x0c, 0x89, 0x70, 0x08, 0xfc, +0x18, 0x50, 0x23, 0x02, 0x98, 0xef, 0x0d, 0x6b, 0x24, 0x4d, 0x23, 0x01, 0x97, 0xf8, 0x1e, 0x57, +0x36, 0x45, 0x22, 0x00, 0x97, 0xef, 0x0e, 0x5e, 0x34, 0x47, 0x17, 0x00, 0x8c, 0x71, 0x38, 0x3f, +0x39, 0x4b, 0x23, 0x00, 0x84, 0x6e, 0x31, 0x44, 0x3a, 0x49, 0x22, 0x00, 0x00, 0x64, 0x34, 0x45, +0x3c, 0x48, 0x08, 0x04, 0x08, 0xf7, 0x20, 0x5d, 0x3f, 0x43, 0x15, 0x30, 0x19, 0x73, 0x29, 0x55, +0x35, 0x4b, 0x07, 0x36, 0x03, 0x6d, 0x18, 0x61, 0x25, 0x59, 0x23, 0x2b, 0x8d, 0x7e, 0x17, 0x6b, +0x1d, 0x56, 0x3e, 0x12, 0x97, 0xf1, 0x14, 0x5b, 0x2d, 0x4c, 0x3d, 0x05, 0x99, 0xef, 0x0f, 0x58, +0x3c, 0x3f, 0x00, 0x01, 0x91, 0xff, 0x13, 0x50, 0x44, 0x40, 0x3d, 0x01, 0x85, 0x76, 0x15, 0x50, +0x3b, 0x3d, 0x07, 0x24, 0x05, 0x74, 0x29, 0x4c, 0x3c, 0x48, 0x4c, 0x59, 0x01, 0x75, 0x20, 0x56, +0x37, 0x48, 0x0c, 0x4f, 0x82, 0x72, 0x20, 0x5c, 0x29, 0x51, 0x22, 0x32, 0x80, 0x73, 0x17, 0x60, +0x26, 0x56, 0x0c, 0x1a, 0x87, 0x7a, 0x15, 0x56, 0x33, 0x50, 0x0c, 0x07, 0x94, 0xf2, 0x13, 0x49, +0x47, 0x41, 0x30, 0x02, 0x89, 0x75, 0x18, 0x50, 0x34, 0x49, 0x0c, 0x04, 0x91, 0x7d, 0x1a, 0x67, +0x1e, 0x50, 0x0c, 0x34, 0x85, 0x6f, 0x2d, 0x4e, 0x35, 0x4c, 0x14, 0x76, 0x09, 0x66, 0x17, 0x5f, +0x2c, 0x4b, 0x65, 0x60, 0x8c, 0xf9, 0x02, 0x6c, 0x23, 0x4e, 0x65, 0x71, 0x88, 0x72, 0x25, 0x47, +0x3c, 0x44, 0x64, 0x85, 0x03, 0x61, 0x34, 0x54, 0x23, 0x4d, 0x65, 0x7e, 0x87, 0x77, 0x13, 0x71, +0x13, 0x53, 0x65, 0x6c, 0x88, 0x73, 0x28, 0x57, 0x2b, 0x4c, 0x28, 0x66, 0x00, 0x5b, 0x32, 0x55, +0x33, 0x49, 0x0a, 0x55, 0x06, 0x54, 0x42, 0x4c, 0x26, 0x55, 0x29, 0x58, 0x0c, 0x57, 0x35, 0x56, +0x29, 0x4b, 0x65, 0x4d, 0x15, 0x46, 0x3b, 0x59, 0x31, 0x4d, 0x28, 0x49, 0x22, 0x4b, 0x2b, 0x53, +0x39, 0x51, 0x28, 0x44, 0x1d, 0x57, 0x2e, 0x52, 0x31, 0x48, 0x10, 0x31, 0x27, 0x5c, 0x39, 0x50, +0x30, 0x3f, 0x04, 0x16, 0x13, 0x73, 0x26, 0x4f, 0x37, 0x3e, 0x04, 0x09, 0x84, 0x70, 0x2c, 0x4c, +0x37, 0x49, 0x29, 0x1e, 0x86, 0x70, 0x24, 0x50, 0x34, 0x4f, 0x0b, 0x66, 0x00, 0x71, 0x1c, 0x60, +0x2b, 0x4e, 0x0b, 0x73, 0x06, 0x66, 0x2e, 0x4b, 0x36, 0x4d, 0x0b, 0x6a, 0x09, 0x63, 0x28, 0x4d, +0x36, 0x51, 0x2b, 0x4c, 0x10, 0x5d, 0x2e, 0x4d, 0x37, 0x4e, 0x23, 0x3a, 0x0c, 0x6f, 0x25, 0x53, +0x30, 0x53, 0x1a, 0x22, 0x18, 0x65, 0x36, 0x4b, 0x37, 0x57, 0x11, 0x0f, 0x11, 0x75, 0x20, 0x60, +0x2e, 0x4b, 0x0b, 0x3b, 0x1f, 0x66, 0x2a, 0x57, 0x29, 0x49, 0x29, 0x60, 0x09, 0x6a, 0x25, 0x5b, +0x20, 0x56, 0x47, 0x77, 0x06, 0x67, 0x1e, 0x60, 0x27, 0x54, 0x0a, 0x48, 0x04, 0x6a, 0x23, 0x59, +0x25, 0x59, 0x0a, 0x07, 0x8d, 0x71, 0x27, 0x50, 0x1e, 0x5c, 0x17, 0x06, 0x12, 0x56, 0x37, 0x55, +0x20, 0x4f, 0x22, 0x40, 0x1a, 0x6b, 0x2e, 0x53, 0x3a, 0x44, 0x22, 0x7f, 0x09, 0x68, 0x28, 0x5c, +0x27, 0x50, 0x22, 0xb5, 0x04, 0x69, 0x2a, 0x58, 0x2e, 0x4b, 0x59, 0xbc, 0x04, 0x5e, 0x36, 0x57, +0x2f, 0x4a, 0x11, 0x98, 0x84, 0x60, 0x34, 0x56, 0x32, 0x44, 0x59, 0x8b, 0x8a, 0x76, 0x22, 0x56, +0x36, 0x43, 0x59, 0x55, 0x93, 0xf7, 0x1a, 0x4f, 0x41, 0x3c, 0x59, 0x33, 0x93, 0xf9, 0x15, 0x67, +0x1d, 0x51, 0x58, 0x1c, 0x92, 0x7d, 0x18, 0x69, 0x16, 0x57, 0x59, 0x14, 0x93, 0xfd, 0x16, 0x72, +0x09, 0x5e, 0x59, 0x0d, 0x92, 0x76, 0x36, 0x43, 0x2a, 0x52, 0x23, 0x0b, 0x93, 0x7f, 0x29, 0x4a, +0x33, 0x48, 0x57, 0x07, 0x8e, 0x77, 0x18, 0x5f, 0x28, 0x50, 0x58, 0x07, 0x8a, 0x68, 0x23, 0x63, +0x28, 0x4b, 0x22, 0x06, 0x8f, 0x6d, 0x36, 0x4f, 0x33, 0x47, 0x23, 0x06, 0x83, 0x64, 0x2c, 0x5c, +0x2b, 0x49, 0x01, 0x09, 0x82, 0xf5, 0x11, 0x75, 0x17, 0x5f, 0x15, 0x4c, 0x84, 0xf9, 0x07, 0x70, +0x1e, 0x58, 0x24, 0x66, 0x09, 0x6a, 0x22, 0x5d, 0x21, 0x5b, 0x3d, 0x78, 0x0d, 0x6e, 0x21, 0x60, +0x22, 0x54, 0x3d, 0x81, 0x0c, 0x68, 0x21, 0x60, 0x26, 0x56, 0x3d, 0x7d, 0x05, 0x68, 0x29, 0x5c, +0x1a, 0x5f, 0x3d, 0x9d, 0x08, 0x61, 0x2e, 0x55, 0x27, 0x57, 0x3e, 0x8b, 0x09, 0x63, 0x2f, 0x5a, +0x25, 0x57, 0x3e, 0x75, 0x06, 0x67, 0x29, 0x5f, 0x1e, 0x5c, 0x3e, 0x83, 0x0c, 0x61, 0x2a, 0x5c, +0x28, 0x53, 0x3e, 0x6c, 0x07, 0x64, 0x27, 0x5f, 0x2b, 0x4f, 0x3d, 0x69, 0x04, 0x65, 0x29, 0x5d, +0x29, 0x4f, 0x3d, 0x5c, 0x02, 0x63, 0x2b, 0x5b, 0x27, 0x51, 0x3d, 0x4a, 0x83, 0x72, 0x18, 0x66, +0x1e, 0x55, 0x3d, 0x39, 0x82, 0x73, 0x15, 0x64, 0x1f, 0x53, 0x3d, 0x3c, 0x03, 0x69, 0x1f, 0x5b, +0x20, 0x55, 0x3e, 0x3b, 0x05, 0x64, 0x24, 0x5c, 0x27, 0x4d, 0x3e, 0x2c, 0x85, 0x7a, 0x0e, 0x69, +0x25, 0x4d, 0x3e, 0x32, 0x87, 0x79, 0x14, 0x66, 0x25, 0x53, 0x3e, 0x28, 0x8d, 0xf8, 0x08, 0x6f, +0x23, 0x52, 0x3e, 0x1e, 0x8f, 0xf3, 0x04, 0x73, 0x1c, 0x55, 0x3d, 0x14, 0x95, 0xe7, 0x8f, 0xfa, +0x11, 0x5b, 0x3e, 0x12, 0x91, 0xef, 0x83, 0x78, 0x1b, 0x56, 0x3e, 0x12, 0x90, 0xf5, 0x0a, 0x65, +0x25, 0x55, 0x3e, 0x11, 0x8f, 0xf2, 0x84, 0x78, 0x1e, 0x51, 0x3e, 0x0c, 0x91, 0xee, 0x88, 0x7a, +0x14, 0x58, 0x3e, 0x0f, 0x8f, 0xf1, 0x83, 0x7a, 0x17, 0x56, 0x3e, 0x0a, 0x91, 0xee, 0x87, 0xfe, +0x10, 0x5d, 0x3d, 0x07, 0x91, 0xf4, 0x0d, 0x65, 0x1c, 0x5c, 0x3d, 0x04, 0x8f, 0xf3, 0x08, 0x6c, +0x16, 0x61, 0x3d, 0x03, 0x86, 0x7f, 0x11, 0x68, 0x0f, 0x63, 0x3d, 0x02, 0x84, 0x76, 0x1b, 0x5b, +0x14, 0x60, 0x3d, 0x01, 0x8b, 0x78, 0x22, 0x55, 0x21, 0x56, 0x28, 0x01, 0x91, 0x75, 0x13, 0x6e, +0x0b, 0x5c, 0x2a, 0x01, 0x85, 0x5b, 0x21, 0x5a, 0x2e, 0x47, 0x2e, 0x03, 0x8e, 0x7c, 0x18, 0x52, +0x2b, 0x4c, 0x31, 0x0a, 0x89, 0xfc, 0x12, 0x54, 0x35, 0x3d, 0x30, 0x1a, 0x0f, 0x6b, 0x1a, 0x4c, +0x2a, 0x47, 0x22, 0x28, 0x20, 0x55, 0x23, 0x3b, 0x2d, 0x4d, 0x22, 0x2c, 0x1a, 0x55, 0x24, 0x3a, +0x3e, 0x40, 0x23, 0x26, 0x15, 0x54, 0x22, 0x40, 0x39, 0x45, 0x22, 0x22, 0x17, 0x4d, 0x21, 0x3e, +0x3f, 0x47, 0x22, 0x1f, 0x12, 0x49, 0x27, 0x46, 0x34, 0x4b, 0x22, 0x1a, 0x0c, 0x4b, 0x2f, 0x40, +0x37, 0x4a, 0x22, 0x1e, 0x05, 0x55, 0x22, 0x51, 0x30, 0x4a, 0x22, 0x12, 0x83, 0x5c, 0x24, 0x4f, +0x30, 0x4c, 0x20, 0x11, 0x83, 0x5f, 0x1a, 0x54, 0x2a, 0x55, 0x22, 0x10, 0x06, 0x47, 0x38, 0x3a, +0x31, 0x57, 0x22, 0x0b, 0x84, 0x57, 0x32, 0x37, 0x39, 0x54, 0x22, 0x07, 0x80, 0x57, 0x28, 0x3d, +0x38, 0x53, 0x24, 0x03, 0x8c, 0x57, 0x37, 0x47, 0x3d, 0x41, 0x22, 0x03, 0x8d, 0x4e, 0x4b, 0x44, +0x26, 0x52, 0x1d, 0x07, 0x85, 0x41, 0x4b, 0x36, 0x4c, 0x3f, 0x19, 0x31, 0x2c, 0x1b, 0x3a, 0x30, +0x4b, 0x57, 0x16, 0x71, 0x2f, 0x26, 0x35, 0x25, 0x54, 0x5c, 0x13, 0xd5, 0x28, 0x2c, 0x44, 0x24, +0x4f, 0x59, 0x13, 0xd1, 0x1a, 0x3b, 0x42, 0x22, 0x52, 0x52, 0x14, 0x71, 0x00, 0x62, 0x2d, 0x3a, +0x4b, 0x40, 0x50, 0x34, 0x81, 0x5c, 0x35, 0x42, 0x3c, 0x4b, 0x3d, 0x4c, 0x23, 0x28, 0x54, 0x40, +0x30, 0x56, 0x3e, 0x3f, 0x29, 0x22, 0x5a, 0x42, 0x36, 0x4d, 0x3e, 0x2c, 0x2d, 0x1d, 0x5c, 0x47, +0x35, 0x4c, 0x3d, 0x21, 0x2b, 0x1a, 0x5d, 0x42, 0x2b, 0x5b, 0x3d, 0x1b, 0x36, 0x17, 0x50, 0x4c, +0x34, 0x51, 0x80, 0x18, 0x4c, 0x16, 0x39, 0x4f, 0x45, 0x4c, 0x80, 0x12, 0x54, 0x0f, 0x35, 0x4d, +0x40, 0x4c, 0x80, 0x0f, 0x53, 0x1a, 0x34, 0x48, 0x42, 0x4d, 0x80, 0x0b, 0x69, 0x22, 0x10, 0x3c, +0x5b, 0x4f, 0x80, 0x09, 0x6e, 0x27, 0x08, 0x31, 0x58, 0x55, 0x18, 0x05, 0x48, 0x1b, 0x10, 0x34, +0x53, 0x55, 0x18, 0x07, 0x32, 0x32, 0x05, 0x36, 0x42, 0x67, 0x17, 0x0e, 0x37, 0x30, 0x06, 0x30, +0x46, 0x67, 0x16, 0x29, 0x27, 0x3a, 0x1e, 0x2a, 0x4a, 0x59, 0x14, 0x29, 0x0f, 0x4b, 0x2a, 0x38, +0x3c, 0x51, 0x14, 0x2f, 0x04, 0x54, 0x2c, 0x43, 0x29, 0x58, 0x14, 0x3a, 0x04, 0x55, 0x2f, 0x41, +0x2e, 0x53, 0x13, 0x3b, 0x07, 0x41, 0x42, 0x3c, 0x2f, 0x59, 0x12, 0x4d, 0x14, 0x24, 0x56, 0x3c, +0x34, 0x59, 0x12, 0xa1, 0x18, 0x26, 0x53, 0x40, 0x3a, 0x4e, 0x11, 0xd8, 0x12, 0x34, 0x57, 0x3f, +0x3a, 0x45, 0x10, 0xf3, 0x18, 0x33, 0x56, 0x46, 0x33, 0x46, 0x10, 0xdd, 0x16, 0x3e, 0x3f, 0x52, +0x3c, 0x3e, 0x10, 0x7f, 0x12, 0x3c, 0x42, 0x46, 0x42, 0x44, 0x11, 0x30, 0x1b, 0x3c, 0x2c, 0x3c, +0x41, 0x4b, 0x12, 0x31, 0x20, 0x2f, 0x2e, 0x39, 0x4a, 0x4b, 0x14, 0x16, 0x1d, 0x2a, 0x36, 0x30, +0x4b, 0x51, 0x15, 0x33, 0x23, 0x2d, 0x31, 0x39, 0x45, 0x4f, 0x15, 0xc5, 0x2b, 0x32, 0x3d, 0x36, +0x3c, 0x52, 0x15, 0xdb, 0x27, 0x34, 0x45, 0x30, 0x3e, 0x5b, 0x3d, 0xf0, 0x25, 0x3c, 0x39, 0x3a, +0x42, 0x57, 0x3d, 0xfc, 0x20, 0x3f, 0x39, 0x3e, 0x40, 0x57, 0x15, 0xaa, 0x17, 0x4a, 0x2e, 0x3f, +0x43, 0x52, 0x3e, 0x77, 0x8c, 0x7c, 0x19, 0x46, 0x43, 0x47, 0x16, 0x48, 0x83, 0x69, 0x21, 0x3f, +0x4d, 0x42, 0x17, 0x4d, 0x80, 0x61, 0x24, 0x4d, 0x3a, 0x4c, 0x17, 0x7c, 0x14, 0x4e, 0x26, 0x40, +0x47, 0x4d, 0x17, 0x7e, 0x2a, 0x3b, 0x32, 0x36, 0x40, 0x4f, 0x17, 0x6e, 0x2b, 0x38, 0x29, 0x38, +0x4f, 0x49, 0x17, 0x47, 0x14, 0x53, 0x26, 0x40, 0x5b, 0x30, 0x22, 0x11, 0x86, 0x64, 0x3d, 0x46, +0x37, 0x4b, 0x22, 0x09, 0x8c, 0x75, 0x2c, 0x4f, 0x35, 0x4a, 0x22, 0x06, 0x83, 0x62, 0x30, 0x4e, +0x41, 0x3e, 0x2d, 0x05, 0x11, 0x5d, 0x4d, 0x31, 0x3f, 0x3c, 0x0b, 0x05, 0x21, 0x50, 0x52, 0x3f, +0x3e, 0x3d, 0x0d, 0x0d, 0x1d, 0x5f, 0x35, 0x3e, 0x3d, 0x39, 0x1d, 0x1e, 0x80, 0x54, 0x3c, 0x3a, +0x39, 0x4a, 0x1d, 0x5b, 0x06, 0x51, 0x37, 0x36, 0x40, 0x4f, 0x1c, 0x64, 0x0a, 0x52, 0x34, 0x3f, +0x3e, 0x4b, 0x49, 0x6d, 0x08, 0x52, 0x36, 0x35, 0x4d, 0x43, 0x1c, 0x48, 0x0e, 0x4b, 0x36, 0x33, +0x54, 0x3d, 0x1c, 0x10, 0x0d, 0x47, 0x3f, 0x31, 0x4b, 0x41, 0x1c, 0x06, 0x10, 0x3f, 0x42, 0x3d, +0x45, 0x47, 0x29, 0x03, 0x05, 0x4e, 0x35, 0x42, 0x4d, 0x3a, 0x29, 0x04, 0x07, 0x59, 0x35, 0x40, +0x44, 0x3d, 0x04, 0x03, 0x14, 0x54, 0x3d, 0x47, 0x35, 0x3b, 0x1c, 0x01, 0x21, 0x4c, 0x35, 0x47, +0x3d, 0x46, 0x2f, 0x02, 0x28, 0x41, 0x40, 0x3e, 0x3e, 0x31, 0x2e, 0x01, 0x2c, 0x38, 0x4b, 0x45, +0x36, 0x3b, 0x06, 0x01, 0x31, 0x2a, 0x48, 0x3c, 0x3b, 0x46, 0x15, 0x01, 0x3c, 0x17, 0x38, 0x4f, +0x2b, 0x4a, 0x1e, 0x01, 0x81, 0x3b, 0x39, 0x47, 0x4d, 0x3c, 0x1e, 0x04, 0x87, 0x55, 0x20, 0x54, +0x46, 0x3b, 0x1c, 0x17, 0x8b, 0x58, 0x41, 0x50, 0x1b, 0x57, 0x1c, 0x38, 0x05, 0x46, 0x49, 0x40, +0x36, 0x51, 0x1c, 0x40, 0x81, 0x51, 0x52, 0x33, 0x3f, 0x4a, 0x1c, 0x57, 0x81, 0x50, 0x4f, 0x33, +0x3c, 0x49, 0x1d, 0x27, 0x84, 0x4e, 0x49, 0x3b, 0x3a, 0x4b, 0x29, 0x0b, 0x8f, 0x6f, 0x1d, 0x5d, +0x37, 0x41, 0x2a, 0x07, 0x8d, 0x61, 0x33, 0x4b, 0x3e, 0x43, 0x0b, 0x05, 0x87, 0x55, 0x46, 0x45, +0x37, 0x49, 0x29, 0x04, 0x89, 0x57, 0x4e, 0x3d, 0x33, 0x4c, 0x29, 0x04, 0x08, 0x41, 0x4b, 0x4b, +0x32, 0x47, 0x29, 0x02, 0x12, 0x32, 0x58, 0x4d, 0x22, 0x51, 0x1d, 0x01, 0x2e, 0x1c, 0x52, 0x4f, +0x3c, 0x45, 0x04, 0x01, 0x33, 0x1e, 0x55, 0x53, 0x2a, 0x49, 0x1d, 0x00, 0x00, 0x3a, 0x54, 0x41, +0x22, 0x55, 0x22, 0x00, 0x8a, 0x47, 0x45, 0x44, 0x3d, 0x44, 0x23, 0x01, 0x85, 0x36, 0x52, 0x46, +0x33, 0x4a, 0x22, 0x01, 0x8a, 0x4c, 0x50, 0x39, 0x30, 0x4d, 0x1e, 0x0e, 0x15, 0x35, 0x45, 0x3f, +0x30, 0x4c, 0x1d, 0x27, 0x1f, 0x4c, 0x23, 0x39, 0x48, 0x3f, 0x1d, 0x1e, 0x11, 0x60, 0x12, 0x4a, +0x3c, 0x46, 0x1d, 0x1e, 0x15, 0x59, 0x0f, 0x4c, 0x3b, 0x48, 0x1d, 0x1f, 0x1c, 0x4e, 0x1b, 0x41, +0x45, 0x43, 0x1d, 0x1e, 0x1e, 0x46, 0x23, 0x36, 0x4c, 0x46, 0x1d, 0x1c, 0x17, 0x46, 0x28, 0x35, +0x55, 0x3d, 0x1c, 0x1d, 0x14, 0x51, 0x21, 0x37, 0x55, 0x3c, 0x1c, 0x18, 0x1c, 0x43, 0x28, 0x34, +0x57, 0x3d, 0x1c, 0x15, 0x19, 0x41, 0x32, 0x28, 0x54, 0x46, 0x1c, 0x0d, 0x17, 0x2e, 0x47, 0x25, +0x45, 0x56, 0x1c, 0x07, 0x02, 0x36, 0x5c, 0x25, 0x40, 0x50, 0x1d, 0x03, 0x82, 0x3e, 0x44, 0x3c, +0x4a, 0x41, 0x1d, 0x02, 0x86, 0x48, 0x3b, 0x3c, 0x54, 0x3a, 0x1d, 0x02, 0x90, 0x5c, 0x30, 0x53, +0x41, 0x3a, 0x1b, 0x06, 0x85, 0x43, 0x44, 0x44, 0x49, 0x38, 0x18, 0x37, 0x18, 0x35, 0x3a, 0x32, +0x52, 0x47, 0x3d, 0x8b, 0x24, 0x38, 0x32, 0x33, 0x51, 0x4b, 0x11, 0xbe, 0x20, 0x3f, 0x2e, 0x39, +0x55, 0x48, 0x33, 0xd8, 0x24, 0x3a, 0x3a, 0x33, 0x4f, 0x4f, 0x34, 0x8c, 0x20, 0x3b, 0x2d, 0x42, +0x5b, 0x3d, 0x11, 0x48, 0x16, 0x4a, 0x30, 0x39, 0x4b, 0x48, 0x1d, 0x33, 0x1f, 0x31, 0x3c, 0x41, +0x47, 0x46, 0x1d, 0x30, 0x3b, 0x1d, 0x40, 0x58, 0x44, 0x41, 0x35, 0x24, 0x41, 0x23, 0x41, 0x50, +0x49, 0x45, 0x80, 0x1f, 0x40, 0x26, 0x4f, 0x4b, 0x3e, 0x4d, 0x80, 0x13, 0x47, 0x15, 0x4a, 0x59, +0x44, 0x40, 0x80, 0x0f, 0x4f, 0x16, 0x33, 0x5c, 0x51, 0x41, 0x80, 0x09, 0x5a, 0x22, 0x21, 0x49, +0x54, 0x4a, 0x80, 0x0b, 0x74, 0x33, 0x24, 0x3c, 0x42, 0x49, 0x80, 0x05, 0x72, 0x3b, 0x23, 0x3d, +0x51, 0x55, 0x14, 0x07, 0x55, 0x15, 0x13, 0x2f, 0x48, 0x5b, 0x15, 0x0b, 0x3d, 0x28, 0x0c, 0x33, +0x4d, 0x5a, 0x13, 0x2e, 0x2a, 0x40, 0x16, 0x36, 0x3b, 0x5e, 0x11, 0x47, 0x16, 0x54, 0x11, 0x45, +0x3c, 0x50, 0x11, 0x3c, 0x19, 0x48, 0x18, 0x45, 0x40, 0x4e, 0x35, 0x2f, 0x14, 0x42, 0x26, 0x47, +0x3a, 0x4e, 0x35, 0x1c, 0x08, 0x45, 0x27, 0x4c, 0x44, 0x42, 0x11, 0x1b, 0x02, 0x51, 0x1d, 0x50, +0x49, 0x3e, 0x10, 0x42, 0x11, 0x39, 0x34, 0x44, 0x49, 0x42, 0x10, 0x69, 0x1c, 0x31, 0x31, 0x45, +0x54, 0x47, 0x0e, 0x89, 0x13, 0x38, 0x45, 0x43, 0x3c, 0x51, 0x0d, 0xc1, 0x15, 0x49, 0x38, 0x46, +0x44, 0x42, 0x0c, 0x96, 0x19, 0x49, 0x2c, 0x4b, 0x40, 0x52, 0x2d, 0xb3, 0x1f, 0x3f, 0x37, 0x49, +0x40, 0x4a, 0x0d, 0xa3, 0x1d, 0x3a, 0x3f, 0x48, 0x3b, 0x49, 0x0f, 0x18, 0x09, 0x48, 0x2e, 0x43, +0x4a, 0x3f, 0x35, 0x0e, 0x2a, 0x22, 0x27, 0x3c, 0x45, 0x58, 0x11, 0x16, 0x25, 0x2f, 0x20, 0x3b, +0x46, 0x58, 0x10, 0x7e, 0x36, 0x1f, 0x27, 0x43, 0x51, 0x51, 0x10, 0xff, 0x27, 0x32, 0x30, 0x4b, +0x49, 0x41, 0x35, 0xff, 0x2b, 0x38, 0x38, 0x47, 0x42, 0x41, 0x35, 0xe5, 0x26, 0x33, 0x3e, 0x47, +0x41, 0x48, 0x35, 0xd2, 0x1b, 0x48, 0x30, 0x4a, 0x44, 0x4b, 0x11, 0x9e, 0x14, 0x55, 0x2a, 0x4b, +0x38, 0x51, 0x12, 0x65, 0x81, 0x69, 0x1f, 0x49, 0x3f, 0x4c, 0x14, 0x34, 0x83, 0x5c, 0x33, 0x42, +0x3c, 0x4c, 0x14, 0x4d, 0x15, 0x51, 0x1d, 0x49, 0x3c, 0x55, 0x14, 0x82, 0x1e, 0x4b, 0x25, 0x46, +0x3d, 0x4e, 0x15, 0x7f, 0x26, 0x42, 0x31, 0x42, 0x44, 0x40, 0x15, 0x63, 0x2c, 0x3b, 0x34, 0x34, +0x4f, 0x3d, 0x1a, 0x2f, 0x1e, 0x4c, 0x2c, 0x38, 0x56, 0x31, 0x34, 0x08, 0x07, 0x59, 0x3a, 0x4a, +0x30, 0x4e, 0x16, 0x05, 0x1c, 0x48, 0x45, 0x3c, 0x37, 0x4c, 0x02, 0x06, 0x17, 0x44, 0x48, 0x49, +0x3b, 0x49, 0x17, 0x10, 0x02, 0x62, 0x40, 0x49, 0x33, 0x4f, 0x17, 0x25, 0x0e, 0x61, 0x38, 0x44, +0x37, 0x44, 0x17, 0x51, 0x81, 0x5d, 0x36, 0x46, 0x2a, 0x50, 0x17, 0x7a, 0x09, 0x4e, 0x3e, 0x47, +0x2c, 0x53, 0x16, 0xab, 0x0b, 0x5c, 0x28, 0x44, 0x3d, 0x48, 0x16, 0x96, 0x03, 0x5b, 0x29, 0x43, +0x47, 0x43, 0x17, 0x32, 0x85, 0x64, 0x26, 0x49, 0x44, 0x42, 0x23, 0x11, 0x8b, 0x78, 0x1a, 0x47, +0x47, 0x37, 0x22, 0x07, 0x83, 0x6b, 0x2d, 0x47, 0x2a, 0x4b, 0x17, 0x05, 0x82, 0x64, 0x40, 0x3a, +0x3e, 0x4a, 0x02, 0x05, 0x0e, 0x44, 0x53, 0x38, 0x35, 0x4b, 0x02, 0x04, 0x15, 0x2e, 0x61, 0x3e, +0x34, 0x4f, 0x17, 0x03, 0x18, 0x36, 0x61, 0x43, 0x37, 0x56, 0x0c, 0x02, 0x29, 0x36, 0x56, 0x44, +0x3a, 0x53, 0x02, 0x01, 0x32, 0x31, 0x4f, 0x45, 0x45, 0x4e, 0x17, 0x00, 0x14, 0x3c, 0x43, 0x47, +0x32, 0x45, 0x23, 0x02, 0x92, 0x63, 0x34, 0x4a, 0x43, 0x39, 0x59, 0x0a, 0x97, 0xf5, 0x1b, 0x47, +0x49, 0x39, 0x22, 0x15, 0x97, 0xf1, 0x11, 0x5a, 0x35, 0x43, 0x23, 0x26, 0x94, 0x7e, 0x32, 0x3b, +0x44, 0x42, 0x23, 0x33, 0x8c, 0x6b, 0x3b, 0x41, 0x32, 0x51, 0x59, 0x2a, 0x89, 0x69, 0x3f, 0x31, +0x46, 0x4c, 0x23, 0x19, 0x89, 0x6b, 0x41, 0x27, 0x55, 0x44, 0x59, 0x0c, 0x92, 0xf2, 0x10, 0x55, +0x3c, 0x48, 0x2d, 0x09, 0x8b, 0x6a, 0x3f, 0x2d, 0x53, 0x3e, 0x58, 0x05, 0x04, 0x4b, 0x5f, 0x30, +0x43, 0x4c, 0x17, 0x05, 0x11, 0x30, 0x5b, 0x48, 0x3a, 0x41, 0x22, 0x04, 0x30, 0x32, 0x50, 0x47, +0x34, 0x4e, 0x0c, 0x04, 0x3f, 0x27, 0x53, 0x40, 0x32, 0x52, 0x02, 0x02, 0x3e, 0x23, 0x44, 0x5a, +0x3a, 0x4b, 0x22, 0x01, 0x16, 0x27, 0x54, 0x4a, 0x26, 0x48, 0x29, 0x00, 0x85, 0x42, 0x47, 0x45, +0x33, 0x4a, 0x2a, 0x00, 0x83, 0x3d, 0x4b, 0x46, 0x33, 0x49, 0x29, 0x00, 0x90, 0x5a, 0x4c, 0x38, +0x32, 0x4b, 0x26, 0x02, 0x87, 0x50, 0x43, 0x44, 0x2f, 0x49, 0x23, 0x0c, 0x15, 0x3e, 0x38, 0x37, +0x3e, 0x4a, 0x22, 0x14, 0x12, 0x5a, 0x1e, 0x3c, 0x4a, 0x3a, 0x22, 0x12, 0x0c, 0x62, 0x0c, 0x52, +0x3d, 0x40, 0x21, 0x0f, 0x11, 0x59, 0x0e, 0x52, 0x3b, 0x47, 0x22, 0x0f, 0x0f, 0x5b, 0x10, 0x52, +0x3e, 0x41, 0x22, 0x10, 0x14, 0x52, 0x0f, 0x4d, 0x45, 0x43, 0x59, 0x0d, 0x18, 0x4b, 0x0e, 0x47, +0x4e, 0x45, 0x23, 0x0b, 0x1d, 0x42, 0x14, 0x3f, 0x56, 0x43, 0x22, 0x0b, 0x1a, 0x3d, 0x22, 0x37, +0x56, 0x44, 0x22, 0x08, 0x0d, 0x39, 0x41, 0x30, 0x44, 0x4e, 0x21, 0x02, 0x0b, 0x29, 0x4e, 0x34, +0x41, 0x4e, 0x22, 0x01, 0x8b, 0x4f, 0x39, 0x41, 0x4b, 0x3c, 0x23, 0x00, 0x8d, 0x52, 0x33, 0x49, +0x43, 0x42, 0x23, 0x01, 0x92, 0x64, 0x23, 0x5d, 0x3b, 0x3d, 0x22, 0x01, 0x91, 0x53, 0x48, 0x44, +0x3f, 0x3d, 0x1b, 0x07, 0x93, 0x70, 0x2b, 0x55, 0x2a, 0x46, 0x13, 0x58, 0x09, 0x40, 0x4b, 0x35, +0x3c, 0x4d, 0x0d, 0x96, 0x11, 0x38, 0x53, 0x32, 0x41, 0x4c, 0x2d, 0xb8, 0x1a, 0x34, 0x44, 0x3e, +0x4a, 0x42, 0x2d, 0xc9, 0x1e, 0x41, 0x2e, 0x3f, 0x55, 0x3b, 0x0e, 0x8b, 0x18, 0x4c, 0x29, 0x3a, +0x46, 0x47, 0x13, 0x4d, 0x19, 0x46, 0x3f, 0x3f, 0x3b, 0x3e, 0x2c, 0x41, 0x33, 0x2a, 0x50, 0x42, +0x36, 0x46, 0x18, 0x3e, 0x3d, 0x22, 0x5a, 0x51, 0x39, 0x46, 0x80, 0x23, 0x41, 0x15, 0x4f, 0x58, +0x35, 0x41, 0x80, 0x1c, 0x53, 0x24, 0x49, 0x50, 0x2e, 0x3c, 0x80, 0x0f, 0x53, 0x24, 0x44, 0x4f, +0x32, 0x3a, 0x80, 0x0d, 0x6a, 0x37, 0x39, 0x4d, 0x3e, 0x3a, 0x80, 0x0c, 0x6f, 0x38, 0x32, 0x46, +0x40, 0x40, 0x80, 0x0c, 0xfe, 0x47, 0x2f, 0x49, 0x4b, 0x46, 0x80, 0x07, 0xff, 0x47, 0x31, 0x3e, +0x4c, 0x4e, 0x80, 0x0b, 0x67, 0x29, 0x10, 0x28, 0x40, 0x53, 0x10, 0x09, 0x3a, 0x25, 0x10, 0x2e, +0x42, 0x6d, 0x0f, 0x10, 0x31, 0x36, 0x02, 0x38, 0x40, 0x6c, 0x0e, 0x15, 0x31, 0x35, 0x04, 0x37, +0x46, 0x66, 0x0d, 0x12, 0x29, 0x32, 0x0a, 0x40, 0x4b, 0x5c, 0x2d, 0x16, 0x0c, 0x3a, 0x39, 0x4b, +0x1e, 0x62, 0x0c, 0x17, 0x0b, 0x2e, 0x4e, 0x47, 0x22, 0x5a, 0x0c, 0x1a, 0x86, 0x3d, 0x64, 0x44, +0x0e, 0x5e, 0x0c, 0x18, 0x82, 0x3a, 0x51, 0x57, 0x19, 0x53, 0x0b, 0x46, 0x85, 0x49, 0x53, 0x48, +0x20, 0x58, 0x0b, 0xe0, 0x02, 0x3f, 0x60, 0x38, 0x32, 0x52, 0x29, 0xc3, 0x0a, 0x4a, 0x2f, 0x5c, +0x45, 0x39, 0x0a, 0xec, 0x13, 0x41, 0x32, 0x61, 0x41, 0x37, 0x0a, 0xf9, 0x18, 0x43, 0x2d, 0x65, +0x3f, 0x38, 0x0a, 0xeb, 0x1e, 0x32, 0x3d, 0x58, 0x41, 0x3f, 0x0b, 0x53, 0x11, 0x31, 0x4e, 0x49, +0x37, 0x4c, 0x2c, 0x15, 0x11, 0x3f, 0x22, 0x44, 0x5b, 0x3a, 0x0d, 0x32, 0x06, 0x55, 0x2c, 0x45, +0x46, 0x3b, 0x06, 0x51, 0x11, 0x42, 0x37, 0x48, 0x3d, 0x43, 0x2c, 0xff, 0x22, 0x2f, 0x4c, 0x45, +0x33, 0x56, 0x0c, 0xff, 0x23, 0x34, 0x2e, 0x55, 0x47, 0x4a, 0x2d, 0xff, 0x2c, 0x33, 0x30, 0x49, +0x46, 0x54, 0x2d, 0xff, 0x25, 0x3b, 0x31, 0x49, 0x40, 0x54, 0x2e, 0xfa, 0x0f, 0x53, 0x37, 0x47, +0x36, 0x55, 0x2f, 0x98, 0x04, 0x60, 0x2f, 0x45, 0x3f, 0x4f, 0x0e, 0x72, 0x86, 0x67, 0x30, 0x4a, +0x2e, 0x55, 0x0f, 0x52, 0x0b, 0x53, 0x25, 0x52, 0x30, 0x5b, 0x0f, 0x52, 0x1d, 0x48, 0x1c, 0x48, +0x42, 0x57, 0x10, 0x57, 0x29, 0x3d, 0x22, 0x3d, 0x43, 0x5a, 0x10, 0x3b, 0x31, 0x2f, 0x24, 0x39, +0x54, 0x4b, 0x12, 0x21, 0x2a, 0x38, 0x22, 0x33, 0x5b, 0x3e, 0x1d, 0x05, 0x24, 0x3f, 0x28, 0x40, +0x47, 0x41, 0x1d, 0x02, 0x33, 0x3c, 0x32, 0x3f, 0x49, 0x53, 0x1c, 0x09, 0x81, 0x5a, 0x42, 0x46, +0x34, 0x4e, 0x4d, 0x22, 0x8f, 0xf5, 0x0c, 0x65, 0x27, 0x4f, 0x1c, 0x2b, 0x90, 0xf5, 0x08, 0x71, +0x1a, 0x56, 0x1c, 0x39, 0x8e, 0x7e, 0x16, 0x65, 0x21, 0x50, 0x3b, 0x6d, 0x01, 0x56, 0x39, 0x4c, +0x25, 0x58, 0x3b, 0xc8, 0x0c, 0x4d, 0x36, 0x42, 0x3a, 0x50, 0x13, 0xf7, 0x13, 0x44, 0x3e, 0x3d, +0x3c, 0x52, 0x3c, 0x99, 0x07, 0x56, 0x32, 0x40, 0x3f, 0x4c, 0x1c, 0x45, 0x83, 0x5e, 0x39, 0x4a, +0x2b, 0x50, 0x1c, 0x22, 0x87, 0x6d, 0x34, 0x4e, 0x28, 0x54, 0x0b, 0x19, 0x85, 0x70, 0x35, 0x4f, +0x2b, 0x5a, 0x5c, 0x19, 0x82, 0x6d, 0x34, 0x51, 0x29, 0x59, 0x5c, 0x15, 0x82, 0x6d, 0x32, 0x51, +0x2a, 0x59, 0x0b, 0x13, 0x86, 0x72, 0x32, 0x4c, 0x33, 0x51, 0x3d, 0x11, 0x06, 0x4e, 0x65, 0x26, +0x43, 0x4f, 0x10, 0x05, 0x89, 0x75, 0x32, 0x50, 0x24, 0x5c, 0x16, 0x03, 0x93, 0x78, 0x31, 0x42, +0x35, 0x4a, 0x54, 0x09, 0x91, 0xff, 0x16, 0x57, 0x30, 0x44, 0x1d, 0x1b, 0x89, 0x61, 0x38, 0x46, +0x34, 0x49, 0x4e, 0x2a, 0x01, 0x3d, 0x52, 0x49, 0x27, 0x53, 0x1c, 0x3d, 0x85, 0x4d, 0x52, 0x3c, +0x2c, 0x57, 0x1c, 0x33, 0x00, 0x4b, 0x4c, 0x39, 0x32, 0x57, 0x1c, 0x2a, 0x09, 0x43, 0x4f, 0x33, +0x37, 0x51, 0x1e, 0x0e, 0x01, 0x44, 0x4b, 0x2f, 0x44, 0x47, 0x2c, 0x04, 0x83, 0x4a, 0x4c, 0x2a, +0x49, 0x46, 0x0d, 0x02, 0x12, 0x3c, 0x43, 0x3f, 0x31, 0x4e, 0x4d, 0x01, 0x16, 0x35, 0x56, 0x3f, +0x31, 0x48, 0x29, 0x01, 0x21, 0x30, 0x53, 0x45, 0x30, 0x4c, 0x1d, 0x01, 0x2f, 0x35, 0x48, 0x47, +0x39, 0x48, 0x1e, 0x01, 0x35, 0x31, 0x49, 0x46, 0x37, 0x4b, 0x00, 0x00, 0x3f, 0x37, 0x52, 0x4b, +0x38, 0x43, 0x16, 0x00, 0x0a, 0x3f, 0x42, 0x38, 0x40, 0x42, 0x1f, 0x04, 0x94, 0x77, 0x1d, 0x50, +0x43, 0x40, 0x24, 0x05, 0x8f, 0x66, 0x36, 0x41, 0x3f, 0x45, 0x24, 0x0c, 0x8e, 0x70, 0x2d, 0x46, +0x3a, 0x4e, 0x15, 0x12, 0x8d, 0x77, 0x26, 0x4b, 0x31, 0x54, 0x23, 0x1e, 0x8e, 0x78, 0x18, 0x62, +0x20, 0x54, 0x20, 0x0c, 0x92, 0xfd, 0x14, 0x5b, 0x20, 0x55, 0x23, 0x04, 0x91, 0x7f, 0x01, 0x69, +0x28, 0x4f, 0x23, 0x03, 0x82, 0x58, 0x1b, 0x50, 0x43, 0x43, 0x22, 0x18, 0x03, 0x5b, 0x30, 0x43, +0x2f, 0x55, 0x23, 0x2b, 0x0a, 0x62, 0x24, 0x4d, 0x2f, 0x4e, 0x23, 0x39, 0x03, 0x6b, 0x18, 0x5d, +0x28, 0x4f, 0x23, 0x43, 0x06, 0x63, 0x22, 0x54, 0x35, 0x4b, 0x29, 0x2a, 0x84, 0x6c, 0x23, 0x55, +0x2a, 0x50, 0x29, 0x12, 0x8c, 0x7d, 0x18, 0x57, 0x2f, 0x4b, 0x2a, 0x09, 0x85, 0x67, 0x2d, 0x40, +0x3c, 0x44, 0x2c, 0x05, 0x02, 0x65, 0x18, 0x4f, 0x31, 0x47, 0x26, 0x0a, 0x80, 0x5b, 0x30, 0x3b, +0x3e, 0x45, 0x29, 0x1e, 0x03, 0x56, 0x3e, 0x3c, 0x44, 0x3e, 0x20, 0x3f, 0x01, 0x65, 0x26, 0x55, +0x26, 0x54, 0x51, 0x59, 0x80, 0x6e, 0x22, 0x5d, 0x30, 0x52, 0x29, 0x48, 0x83, 0x6a, 0x21, 0x58, +0x2b, 0x55, 0x1e, 0x61, 0x85, 0x7a, 0x1b, 0x67, 0x1c, 0x5c, 0x1d, 0x56, 0x86, 0x78, 0x25, 0x57, +0x27, 0x5a, 0x1d, 0x5a, 0x87, 0x7e, 0x1e, 0x58, 0x31, 0x53, 0x1c, 0x6f, 0x03, 0x69, 0x32, 0x48, +0x36, 0x50, 0x1c, 0x83, 0x0b, 0x56, 0x3f, 0x43, 0x3e, 0x50, 0x1c, 0x49, 0x0d, 0x47, 0x55, 0x31, +0x3f, 0x54, 0x29, 0x26, 0x82, 0x5e, 0x34, 0x4f, 0x2f, 0x4f, 0x29, 0x23, 0x86, 0x74, 0x15, 0x6b, +0x1e, 0x55, 0x29, 0x26, 0x84, 0x72, 0x1a, 0x63, 0x22, 0x58, 0x29, 0x25, 0x85, 0x72, 0x22, 0x51, +0x2c, 0x53, 0x29, 0x1d, 0x06, 0x69, 0x22, 0x5d, 0x23, 0x55, 0x28, 0x08, 0x82, 0x66, 0x30, 0x51, +0x23, 0x57, 0x16, 0x0b, 0x05, 0x64, 0x23, 0x57, 0x2a, 0x4e, 0x1a, 0x46, 0x08, 0x68, 0x14, 0x59, +0x2e, 0x49, 0x11, 0x78, 0x0b, 0x59, 0x22, 0x56, 0x37, 0x43, 0x10, 0x60, 0x05, 0x66, 0x15, 0x69, +0x26, 0x4a, 0x0f, 0x8f, 0x0d, 0x65, 0x0e, 0x68, 0x28, 0x4a, 0x11, 0x65, 0x05, 0x61, 0x0b, 0x65, +0x34, 0x42, 0x10, 0x62, 0x0f, 0x54, 0x0d, 0x60, 0x39, 0x45, 0x0f, 0x4b, 0x10, 0x55, 0x0d, 0x68, +0x31, 0x44, 0x0f, 0x44, 0x0b, 0x5c, 0x0d, 0x6a, 0x33, 0x41, 0x0f, 0x54, 0x0a, 0x58, 0x15, 0x68, +0x34, 0x3f, 0x10, 0x3e, 0x0f, 0x58, 0x11, 0x65, 0x33, 0x3d, 0x10, 0x2e, 0x09, 0x5d, 0x0b, 0x6a, +0x33, 0x3c, 0x10, 0x23, 0x09, 0x55, 0x0a, 0x6c, 0x37, 0x3e, 0x10, 0x12, 0x85, 0x6a, 0x82, 0x78, +0x22, 0x4f, 0x10, 0x0a, 0x94, 0xf5, 0x8f, 0xfa, 0x11, 0x55, 0x11, 0x09, 0x86, 0x5a, 0x10, 0x6d, +0x37, 0x3f, 0x12, 0x09, 0x8a, 0x5c, 0x18, 0x65, 0x34, 0x45, 0x17, 0x12, 0x39, 0x22, 0x0e, 0x42, +0x49, 0x5a, 0x43, 0x48, 0x18, 0x47, 0x2e, 0x45, 0x3b, 0x4b, 0x23, 0x4e, 0x00, 0x5c, 0x32, 0x46, +0x3d, 0x48, 0x18, 0x4f, 0x83, 0x63, 0x34, 0x3e, 0x40, 0x44, 0x16, 0x31, 0x85, 0x62, 0x34, 0x3d, +0x3a, 0x4b, 0x17, 0x23, 0x86, 0x56, 0x46, 0x37, 0x33, 0x4f, 0x18, 0x1c, 0x8f, 0x6e, 0x2a, 0x49, +0x3f, 0x3e, 0x19, 0x13, 0x8f, 0x61, 0x3f, 0x44, 0x42, 0x35, 0x19, 0x12, 0x8e, 0x56, 0x54, 0x36, +0x40, 0x3c, 0x19, 0x10, 0x88, 0x47, 0x56, 0x41, 0x33, 0x41, 0x18, 0x0e, 0x89, 0x4f, 0x49, 0x3f, +0x3e, 0x3e, 0x17, 0x14, 0x04, 0x43, 0x3a, 0x46, 0x46, 0x3a, 0x16, 0x1f, 0x07, 0x54, 0x21, 0x45, +0x51, 0x39, 0x19, 0x1d, 0x10, 0x4e, 0x16, 0x4d, 0x56, 0x33, 0x45, 0x18, 0x17, 0x49, 0x12, 0x4b, +0x53, 0x3c, 0x46, 0x11, 0x19, 0x40, 0x12, 0x4d, 0x51, 0x41, 0x18, 0x08, 0x24, 0x3b, 0x04, 0x44, +0x4e, 0x53, 0x17, 0x0e, 0x2d, 0x38, 0x04, 0x3a, 0x52, 0x55, 0x3d, 0x39, 0x14, 0x57, 0x0e, 0x4f, +0x46, 0x45, 0x3f, 0x42, 0x0d, 0x65, 0x09, 0x5a, 0x41, 0x42, 0x3e, 0x65, 0x03, 0x71, 0x09, 0x5b, +0x3e, 0x42, 0x3d, 0x6f, 0x06, 0x6b, 0x11, 0x55, 0x40, 0x41, 0x3e, 0x86, 0x0e, 0x63, 0x1b, 0x47, +0x4a, 0x3e, 0x3e, 0x72, 0x06, 0x64, 0x23, 0x49, 0x45, 0x42, 0x16, 0x7b, 0x12, 0x56, 0x2e, 0x40, +0x45, 0x46, 0x3d, 0x6e, 0x0e, 0x59, 0x28, 0x41, 0x44, 0x45, 0x3f, 0x63, 0x16, 0x50, 0x28, 0x3e, +0x45, 0x4c, 0x3d, 0x7f, 0x25, 0x47, 0x2e, 0x34, 0x42, 0x53, 0x14, 0x90, 0x21, 0x4c, 0x2c, 0x36, +0x44, 0x4e, 0x14, 0x8c, 0x27, 0x3e, 0x31, 0x32, 0x3e, 0x59, 0x3e, 0x76, 0x1d, 0x43, 0x33, 0x36, +0x3f, 0x58, 0x3e, 0x72, 0x19, 0x4c, 0x2d, 0x38, 0x45, 0x54, 0x06, 0x3e, 0x0c, 0x57, 0x2f, 0x37, +0x46, 0x4f, 0x3e, 0x31, 0x04, 0x5c, 0x33, 0x37, 0x3f, 0x52, 0x3e, 0x21, 0x03, 0x5b, 0x32, 0x33, +0x46, 0x4e, 0x3e, 0x16, 0x06, 0x50, 0x38, 0x37, 0x3b, 0x56, 0x3e, 0x0e, 0x83, 0x5c, 0x40, 0x2a, +0x3d, 0x52, 0x15, 0x09, 0x86, 0x6a, 0x2e, 0x38, 0x39, 0x4d, 0x15, 0x07, 0x02, 0x64, 0x31, 0x44, +0x2f, 0x53, 0x15, 0x04, 0x8b, 0x7d, 0x28, 0x44, 0x36, 0x4d, 0x15, 0x06, 0x02, 0x69, 0x39, 0x41, +0x32, 0x50, 0x00, 0x04, 0x83, 0x72, 0x38, 0x3f, 0x37, 0x4f, 0x15, 0x03, 0x04, 0x74, 0x39, 0x4b, +0x33, 0x58, 0x15, 0x02, 0x81, 0xf8, 0x26, 0x5a, 0x2f, 0x58, 0x15, 0x02, 0x01, 0xf8, 0x26, 0x5d, +0x2f, 0x59, 0x15, 0x02, 0x83, 0xf8, 0x21, 0x5e, 0x2b, 0x5b, 0x00, 0x01, 0x08, 0x79, 0x33, 0x55, +0x34, 0x57, 0x00, 0x01, 0x07, 0x78, 0x2f, 0x55, 0x3c, 0x52, 0x15, 0x01, 0x8c, 0xfd, 0x19, 0x50, +0x2c, 0x4f, 0x29, 0x01, 0x89, 0x76, 0x28, 0x3c, 0x3a, 0x49, 0x29, 0x01, 0x88, 0x71, 0x2a, 0x3a, +0x3f, 0x44, 0x29, 0x00, 0x87, 0x70, 0x2a, 0x37, 0x4a, 0x3d, 0x2a, 0x02, 0x11, 0x63, 0x25, 0x37, +0x37, 0x4b, 0x2d, 0x02, 0x82, 0x67, 0x20, 0x32, 0x49, 0x48, 0x29, 0x04, 0x8a, 0x6e, 0x21, 0x36, +0x47, 0x49, 0x26, 0x0b, 0x0e, 0x3d, 0x44, 0x27, 0x42, 0x55, 0x24, 0x11, 0x82, 0x4d, 0x4c, 0x24, +0x45, 0x4c, 0x23, 0x15, 0x85, 0x4d, 0x54, 0x25, 0x39, 0x53, 0x22, 0x14, 0x03, 0x3a, 0x5c, 0x2b, +0x2e, 0x5c, 0x22, 0x11, 0x04, 0x40, 0x4c, 0x2d, 0x3c, 0x54, 0x22, 0x10, 0x09, 0x2d, 0x5f, 0x2f, +0x31, 0x59, 0x22, 0x11, 0x09, 0x37, 0x47, 0x38, 0x44, 0x4c, 0x22, 0x0e, 0x0b, 0x36, 0x4f, 0x28, +0x43, 0x55, 0x22, 0x0b, 0x0a, 0x3d, 0x49, 0x21, 0x4b, 0x50, 0x23, 0x02, 0x83, 0x3c, 0x5c, 0x2c, +0x4a, 0x3a, 0x22, 0x00, 0x8f, 0x61, 0x45, 0x38, 0x4c, 0x35, 0x59, 0x00, 0x93, 0x5a, 0x58, 0x2e, +0x45, 0x3b, 0x22, 0x00, 0x8e, 0x56, 0x5a, 0x34, 0x39, 0x45, 0x22, 0x01, 0x16, 0x40, 0x30, 0x51, +0x44, 0x3a, 0x23, 0x01, 0x2e, 0x31, 0x41, 0x25, 0x3c, 0x56, 0x01, 0x02, 0x41, 0x4c, 0x44, 0x22, +0x39, 0x3d, 0x0a, 0x02, 0x3a, 0x45, 0x32, 0x26, 0x41, 0x3d, 0x1d, 0x13, 0x01, 0x66, 0x21, 0x43, +0x43, 0x3a, 0x1b, 0x32, 0x05, 0x50, 0x47, 0x30, 0x4a, 0x3c, 0x1b, 0x43, 0x00, 0x4c, 0x51, 0x38, +0x3e, 0x43, 0x1a, 0x49, 0x8d, 0x71, 0x38, 0x48, 0x2d, 0x4c, 0x18, 0x56, 0x83, 0x61, 0x40, 0x4c, +0x2a, 0x4c, 0x18, 0x49, 0x8c, 0x6c, 0x3e, 0x4b, 0x30, 0x48, 0x17, 0x68, 0x89, 0x61, 0x47, 0x45, +0x2d, 0x4a, 0x41, 0x9f, 0x05, 0x57, 0x4d, 0x46, 0x30, 0x49, 0x16, 0x94, 0x06, 0x54, 0x52, 0x42, +0x37, 0x48, 0x16, 0xca, 0x0b, 0x54, 0x43, 0x48, 0x39, 0x41, 0x15, 0xfc, 0x0d, 0x54, 0x45, 0x44, +0x3a, 0x43, 0x15, 0xe8, 0x13, 0x4b, 0x4d, 0x3a, 0x3d, 0x4d, 0x15, 0xff, 0x17, 0x4b, 0x43, 0x37, +0x4a, 0x4a, 0x15, 0xe2, 0x1f, 0x44, 0x38, 0x33, 0x54, 0x4f, 0x15, 0xb0, 0x27, 0x3e, 0x33, 0x2b, +0x53, 0x51, 0x15, 0x6f, 0x25, 0x3d, 0x37, 0x23, 0x52, 0x54, 0x15, 0x09, 0x08, 0x42, 0x3e, 0x38, +0x5f, 0x2a, 0x17, 0x0a, 0x1d, 0x35, 0x34, 0x39, 0x4b, 0x43, 0x15, 0x31, 0x18, 0x49, 0x26, 0x37, +0x55, 0x41, 0x15, 0x46, 0x1f, 0x44, 0x26, 0x35, 0x56, 0x45, 0x15, 0x44, 0x19, 0x44, 0x23, 0x41, +0x52, 0x44, 0x3e, 0x39, 0x12, 0x3e, 0x2a, 0x4d, 0x59, 0x32, 0x3e, 0x27, 0x06, 0x48, 0x22, 0x5a, +0x56, 0x2c, 0x3e, 0x13, 0x8c, 0x65, 0x16, 0x6c, 0x39, 0x38, 0x3d, 0x10, 0x91, 0x74, 0x08, 0x78, +0x30, 0x39, 0x3d, 0x12, 0x91, 0x72, 0x0b, 0x72, 0x3a, 0x35, 0x3d, 0x0e, 0x96, 0xf4, 0x8b, 0xf9, +0x22, 0x41, 0x15, 0x0c, 0x8d, 0x6f, 0x2c, 0x41, 0x53, 0x2d, 0x00, 0x09, 0x83, 0x5a, 0x42, 0x3e, +0x4d, 0x39, 0x00, 0x0a, 0x83, 0x53, 0x46, 0x40, 0x4b, 0x39, 0x00, 0x03, 0x92, 0x64, 0x53, 0x2d, +0x4c, 0x3b, 0x29, 0x03, 0x91, 0x62, 0x49, 0x41, 0x3f, 0x3e, 0x3e, 0x01, 0x92, 0x62, 0x44, 0x45, +0x41, 0x39, 0x00, 0x02, 0x06, 0x2e, 0x60, 0x43, 0x3f, 0x3d, 0x00, 0x0a, 0x22, 0x14, 0x6c, 0x47, +0x32, 0x4e, 0x0c, 0x15, 0x23, 0x22, 0x66, 0x41, 0x2c, 0x58, 0x17, 0x1a, 0x85, 0x58, 0x34, 0x3a, +0x51, 0x3a, 0x15, 0x25, 0x07, 0x4c, 0x34, 0x35, 0x50, 0x40, 0x15, 0x2c, 0x0e, 0x42, 0x39, 0x38, +0x43, 0x47, 0x15, 0x20, 0x0e, 0x37, 0x47, 0x40, 0x3d, 0x43, 0x3e, 0x1f, 0x0c, 0x3d, 0x41, 0x40, +0x3d, 0x44, 0x3d, 0x1c, 0x01, 0x42, 0x4a, 0x3a, 0x41, 0x42, 0x3d, 0x19, 0x05, 0x3c, 0x4c, 0x3a, +0x3a, 0x49, 0x3d, 0x19, 0x83, 0x49, 0x47, 0x37, 0x42, 0x42, 0x15, 0x1e, 0x0c, 0x33, 0x4e, 0x38, +0x3b, 0x4a, 0x15, 0x27, 0x12, 0x3e, 0x3a, 0x38, 0x46, 0x47, 0x16, 0x26, 0x0a, 0x4a, 0x2d, 0x3c, +0x53, 0x3c, 0x17, 0x25, 0x12, 0x4d, 0x23, 0x3c, 0x5b, 0x36, 0x17, 0x25, 0x1c, 0x3f, 0x25, 0x3b, +0x5b, 0x39, 0x15, 0x1d, 0x19, 0x3e, 0x1e, 0x43, 0x57, 0x3c, 0x18, 0x14, 0x27, 0x3c, 0x0d, 0x36, +0x52, 0x53, 0x17, 0x1b, 0x2b, 0x35, 0x1b, 0x2d, 0x54, 0x51, 0x17, 0x27, 0x27, 0x3c, 0x1f, 0x2c, +0x4c, 0x54, 0x17, 0x20, 0x20, 0x3b, 0x26, 0x30, 0x4d, 0x4e, 0x17, 0x20, 0x15, 0x37, 0x35, 0x39, +0x4c, 0x43, 0x17, 0x1e, 0x0d, 0x41, 0x2e, 0x40, 0x53, 0x3a, 0x17, 0x18, 0x05, 0x43, 0x34, 0x44, +0x54, 0x34, 0x17, 0x1d, 0x06, 0x3a, 0x45, 0x3c, 0x4c, 0x3c, 0x16, 0x1b, 0x00, 0x3c, 0x58, 0x31, +0x40, 0x44, 0x17, 0x12, 0x83, 0x42, 0x4a, 0x3e, 0x49, 0x39, 0x17, 0x0f, 0x82, 0x45, 0x39, 0x4a, +0x4a, 0x37, 0x18, 0x0d, 0x87, 0x49, 0x3b, 0x4f, 0x3f, 0x3b, 0x18, 0x0a, 0x8a, 0x4b, 0x45, 0x49, +0x3c, 0x3c, 0x17, 0x0c, 0x91, 0x61, 0x3c, 0x3f, 0x46, 0x3a, 0x17, 0x09, 0x8c, 0x58, 0x2a, 0x58, +0x48, 0x30, 0x17, 0x05, 0x93, 0x68, 0x1f, 0x67, 0x3a, 0x36, 0x17, 0x05, 0x95, 0x68, 0x35, 0x57, +0x32, 0x3e, 0x18, 0x04, 0x90, 0x5a, 0x41, 0x42, 0x44, 0x3b, 0x18, 0x08, 0x92, 0x65, 0x3a, 0x42, +0x46, 0x38, 0x17, 0x03, 0x9b, 0xf2, 0x14, 0x5b, 0x3b, 0x39, 0x17, 0x03, 0x98, 0x7e, 0x22, 0x54, +0x43, 0x34, 0x18, 0x04, 0x99, 0xf8, 0x24, 0x47, 0x46, 0x36, 0x18, 0x03, 0x98, 0xf7, 0x29, 0x3f, +0x4d, 0x38, 0x59, 0x02, 0x98, 0xf3, 0x25, 0x43, 0x4c, 0x39, 0x59, 0x02, 0x9a, 0xec, 0x15, 0x50, +0x44, 0x3c, 0x02, 0x02, 0x96, 0xf7, 0x23, 0x4b, 0x46, 0x3d, 0x59, 0x03, 0x91, 0x74, 0x38, 0x40, +0x48, 0x3e, 0x59, 0x02, 0x95, 0xfe, 0x31, 0x38, 0x54, 0x39, 0x59, 0x02, 0x9a, 0xe9, 0x0e, 0x59, +0x3a, 0x44, 0x59, 0x02, 0x9a, 0xe9, 0x0a, 0x5c, 0x3a, 0x42, 0x2d, 0x01, 0x9a, 0xec, 0x1b, 0x42, +0x51, 0x39, 0x02, 0x01, 0x9b, 0xe8, 0x0f, 0x50, 0x48, 0x3c, 0x18, 0x02, 0x94, 0x72, 0x37, 0x42, +0x47, 0x38, 0x59, 0x04, 0x95, 0x74, 0x34, 0x43, 0x43, 0x3a, 0x20, 0x07, 0x95, 0x62, 0x4f, 0x31, +0x4d, 0x36, 0x19, 0x1a, 0x93, 0x5f, 0x59, 0x2d, 0x30, 0x51, 0x18, 0x42, 0x88, 0x5b, 0x44, 0x35, +0x3d, 0x4b, 0x18, 0x4a, 0x06, 0x51, 0x2c, 0x45, 0x4d, 0x43, 0x17, 0x3c, 0x80, 0x5e, 0x20, 0x4f, +0x46, 0x47, 0x17, 0x3b, 0x01, 0x56, 0x26, 0x51, 0x4c, 0x40, 0x43, 0x41, 0x05, 0x4d, 0x34, 0x4b, +0x49, 0x44, 0x18, 0x39, 0x87, 0x63, 0x25, 0x55, 0x40, 0x47, 0x18, 0x49, 0x04, 0x4c, 0x3a, 0x45, +0x47, 0x48, 0x18, 0x3e, 0x82, 0x5e, 0x26, 0x53, 0x3e, 0x4c, 0x18, 0x4c, 0x87, 0x75, 0x0d, 0x67, +0x2c, 0x54, 0x17, 0x61, 0x08, 0x50, 0x32, 0x47, 0x45, 0x4a, 0x17, 0x73, 0x15, 0x43, 0x34, 0x43, +0x4f, 0x43, 0x18, 0x66, 0x04, 0x5c, 0x26, 0x51, 0x36, 0x4c, 0x19, 0x1d, 0x93, 0xf7, 0x07, 0x69, +0x28, 0x4d, 0x19, 0x1a, 0x8c, 0x74, 0x20, 0x53, 0x36, 0x43, 0x19, 0x1f, 0x91, 0x7d, 0x1b, 0x4d, +0x39, 0x48, 0x18, 0x23, 0x90, 0xf3, 0x89, 0x71, 0x20, 0x53, 0x18, 0x3f, 0x81, 0x74, 0x11, 0x5e, +0x22, 0x52, 0x17, 0x84, 0x10, 0x53, 0x34, 0x44, 0x31, 0x52, 0x17, 0x8b, 0x1b, 0x3f, 0x35, 0x42, +0x47, 0x4e, 0x16, 0xae, 0x15, 0x54, 0x2b, 0x48, 0x3f, 0x51, 0x15, 0xaa, 0x21, 0x48, 0x2e, 0x47, +0x4b, 0x46, 0x14, 0xae, 0x1e, 0x48, 0x2a, 0x4d, 0x46, 0x4a, 0x14, 0xb0, 0x15, 0x4d, 0x32, 0x48, +0x3e, 0x4d, 0x13, 0xc7, 0x0e, 0x54, 0x37, 0x3f, 0x3d, 0x50, 0x14, 0x96, 0x0a, 0x57, 0x38, 0x44, +0x3c, 0x51, 0x15, 0x84, 0x07, 0x5e, 0x28, 0x57, 0x34, 0x4f, 0x3f, 0x7b, 0x02, 0x65, 0x24, 0x57, +0x35, 0x4c, 0x15, 0x51, 0x84, 0x69, 0x21, 0x5c, 0x31, 0x4d, 0x3e, 0x41, 0x86, 0x5d, 0x3e, 0x49, +0x2c, 0x53, 0x15, 0x35, 0x8b, 0x6e, 0x33, 0x4b, 0x2d, 0x4e, 0x15, 0x18, 0x8d, 0x65, 0x3a, 0x44, +0x37, 0x45, 0x15, 0x0c, 0x8a, 0x57, 0x43, 0x44, 0x43, 0x39, 0x52, 0x06, 0x8c, 0x63, 0x32, 0x4e, +0x45, 0x36, 0x28, 0x05, 0x03, 0x4e, 0x33, 0x51, 0x3d, 0x3d, 0x18, 0x05, 0x08, 0x4a, 0x39, 0x48, +0x42, 0x37, 0x1a, 0x0d, 0x04, 0x47, 0x46, 0x3e, 0x41, 0x3f, 0x18, 0x2e, 0x02, 0x52, 0x3b, 0x41, +0x46, 0x38, 0x17, 0x49, 0x81, 0x55, 0x47, 0x3e, 0x34, 0x47, 0x17, 0x50, 0x05, 0x4c, 0x47, 0x44, +0x2c, 0x4f, 0x17, 0x2b, 0x8b, 0x5b, 0x4e, 0x40, 0x22, 0x57, 0x18, 0x34, 0x87, 0x64, 0x33, 0x46, +0x33, 0x4e, 0x18, 0x2c, 0x8c, 0x6c, 0x36, 0x3c, 0x39, 0x4b, 0x18, 0x23, 0x89, 0x54, 0x50, 0x41, +0x1d, 0x5d, 0x18, 0x21, 0x8a, 0x58, 0x51, 0x32, 0x30, 0x55, 0x17, 0x32, 0x82, 0x59, 0x3f, 0x37, +0x3a, 0x4f, 0x17, 0x3c, 0x12, 0x45, 0x3f, 0x39, 0x32, 0x59, 0x18, 0x2c, 0x12, 0x41, 0x3c, 0x35, +0x43, 0x51, 0x19, 0x33, 0x10, 0x45, 0x3c, 0x3c, 0x57, 0x3f, 0x18, 0x1d, 0x25, 0x31, 0x30, 0x3f, +0x53, 0x40, 0x19, 0x0d, 0x28, 0x27, 0x32, 0x48, 0x4d, 0x3d, 0x25, 0x06, 0x31, 0x23, 0x2a, 0x43, +0x44, 0x49, 0x23, 0x09, 0x29, 0x25, 0x2e, 0x4f, 0x42, 0x45, 0x20, 0x10, 0x26, 0x34, 0x2d, 0x40, +0x4a, 0x41, 0x1e, 0x1a, 0x25, 0x3e, 0x1e, 0x32, 0x52, 0x4c, 0x1d, 0x1d, 0x14, 0x3a, 0x37, 0x38, +0x46, 0x49, 0x1c, 0x17, 0x16, 0x36, 0x3d, 0x37, 0x3d, 0x53, 0x1c, 0x10, 0x07, 0x3f, 0x43, 0x3a, +0x42, 0x45, 0x1c, 0x0b, 0x88, 0x59, 0x2f, 0x49, 0x3b, 0x46, 0x1d, 0x0a, 0x8f, 0x62, 0x30, 0x4f, +0x34, 0x47, 0x1d, 0x08, 0x93, 0x6e, 0x28, 0x58, 0x35, 0x3f, 0x1d, 0x08, 0x95, 0x75, 0x22, 0x5f, +0x2e, 0x42, 0x1d, 0x09, 0x8f, 0x69, 0x30, 0x46, 0x45, 0x39, 0x1d, 0x0a, 0x8b, 0x60, 0x34, 0x44, +0x45, 0x3c, 0x1e, 0x07, 0x94, 0x69, 0x40, 0x3b, 0x42, 0x3e, 0x1e, 0x0a, 0x8e, 0x5a, 0x40, 0x42, +0x47, 0x36, 0x1f, 0x0a, 0x87, 0x3c, 0x65, 0x3b, 0x34, 0x42, 0x24, 0x07, 0x8d, 0x40, 0x6c, 0x3d, +0x1f, 0x54, 0x24, 0x0a, 0x92, 0x56, 0x5d, 0x3e, 0x24, 0x53, 0x25, 0x0a, 0x8a, 0x49, 0x56, 0x44, +0x30, 0x46, 0x26, 0x0e, 0x8c, 0x48, 0x64, 0x45, 0x1d, 0x52, 0x25, 0x17, 0x8c, 0x5e, 0x46, 0x4a, +0x33, 0x43, 0x23, 0x2f, 0x0a, 0x3d, 0x5a, 0x50, 0x29, 0x45, 0x23, 0x30, 0x0d, 0x3a, 0x5c, 0x4d, +0x2b, 0x41, 0x23, 0x28, 0x80, 0x43, 0x62, 0x45, 0x26, 0x48, 0x23, 0x2c, 0x06, 0x43, 0x56, 0x4b, +0x31, 0x40, 0x24, 0x1b, 0x82, 0x55, 0x47, 0x48, 0x3e, 0x35, 0x24, 0x19, 0x81, 0x4a, 0x59, 0x46, +0x2a, 0x46, 0x22, 0x21, 0x03, 0x3d, 0x6a, 0x40, 0x22, 0x4c, 0x21, 0x24, 0x04, 0x3e, 0x69, 0x3f, +0x23, 0x4e, 0x21, 0x12, 0x90, 0x64, 0x56, 0x37, 0x2e, 0x4f, 0x23, 0x0c, 0x92, 0x76, 0x36, 0x39, +0x48, 0x3d, 0x24, 0x0b, 0x8a, 0x57, 0x53, 0x37, 0x36, 0x4e, 0x24, 0x08, 0x88, 0x59, 0x51, 0x33, +0x35, 0x50, 0x23, 0x08, 0x8d, 0x6b, 0x3e, 0x33, 0x45, 0x3e, 0x22, 0x06, 0x96, 0xfd, 0x33, 0x2d, +0x51, 0x3e, 0x23, 0x03, 0x9b, 0xee, 0x1f, 0x3f, 0x4e, 0x37, 0x23, 0x03, 0x99, 0xf8, 0x2e, 0x41, +0x41, 0x3d, 0x23, 0x03, 0x95, 0x70, 0x3d, 0x46, 0x3a, 0x3e, 0x23, 0x03, 0x97, 0x7e, 0x2f, 0x49, +0x3f, 0x3b, 0x23, 0x03, 0x99, 0xf8, 0x2f, 0x42, 0x42, 0x3e, 0x23, 0x04, 0x94, 0x6d, 0x45, 0x38, +0x45, 0x3e, 0x23, 0x03, 0x8a, 0x55, 0x4c, 0x4b, 0x2c, 0x4d, 0x07, 0x01, 0x0e, 0x3f, 0x46, 0x50, +0x38, 0x42, 0x08, 0x01, 0x22, 0x43, 0x4b, 0x3f, 0x39, 0x57, 0x19, 0x00, 0x27, 0x45, 0x42, 0x46, +0x38, 0x4e, 0x23, 0x00, 0x2a, 0x47, 0x4c, 0x4a, 0x38, 0x50, 0x08, 0x00, 0x29, 0x3e, 0x4d, 0x3a, +0x3e, 0x47, 0x08, 0x00, 0x25, 0x46, 0x46, 0x40, 0x40, 0x4b, 0x42, 0x00, 0x23, 0x44, 0x3e, 0x43, +0x42, 0x46, 0x08, 0x00, 0x1f, 0x41, 0x45, 0x47, 0x44, 0x39, 0x07, 0x00, 0x1a, 0x4e, 0x43, 0x47, +0x3d, 0x3f, 0x13, 0x00, 0x18, 0x4a, 0x44, 0x52, 0x33, 0x3d, 0x24, 0x00, 0x23, 0x3f, 0x4a, 0x41, +0x45, 0x41, 0x23, 0x00, 0x0e, 0x41, 0x3f, 0x3f, 0x35, 0x42, 0x28, 0x02, 0x13, 0x69, 0x1e, 0x34, +0x39, 0x3d, 0x1e, 0x05, 0x15, 0x48, 0x34, 0x1d, 0x52, 0x45, 0x18, 0x0e, 0x80, 0x66, 0x0f, 0x45, +0x44, 0x48, 0x14, 0x13, 0x87, 0x69, 0x0a, 0x55, 0x3f, 0x47, 0x12, 0x1e, 0x80, 0x50, 0x29, 0x47, +0x3d, 0x4b, 0x12, 0x2d, 0x04, 0x4b, 0x2a, 0x47, 0x41, 0x48, 0x12, 0x32, 0x11, 0x3c, 0x30, 0x3e, +0x4b, 0x46, 0x12, 0x51, 0x15, 0x36, 0x39, 0x3c, 0x46, 0x4c, 0x12, 0x4d, 0x83, 0x51, 0x3f, 0x3c, +0x36, 0x50, 0x12, 0x81, 0x18, 0x32, 0x43, 0x36, 0x45, 0x4e, 0x11, 0x83, 0x24, 0x2a, 0x41, 0x32, +0x43, 0x59, 0x11, 0x8b, 0x26, 0x33, 0x3d, 0x36, 0x41, 0x52, 0x12, 0x22, 0x19, 0x3c, 0x37, 0x45, +0x46, 0x3f, 0x23, 0x09, 0x89, 0x63, 0x2e, 0x48, 0x4b, 0x39, 0x59, 0x08, 0x8f, 0x70, 0x2d, 0x4b, +0x43, 0x3a, 0x5a, 0x0b, 0x8d, 0x6c, 0x34, 0x4b, 0x3c, 0x42, 0x07, 0x0a, 0x83, 0x5c, 0x47, 0x2e, +0x56, 0x39, 0x22, 0x0d, 0x11, 0x4b, 0x36, 0x4d, 0x3d, 0x45, 0x22, 0x09, 0x1f, 0x2b, 0x4a, 0x49, +0x52, 0x37, 0x0a, 0x0b, 0x2e, 0x53, 0x1f, 0x48, 0x3a, 0x44, 0x1c, 0x28, 0x0d, 0x55, 0x20, 0x4e, +0x3e, 0x44, 0x14, 0x53, 0x03, 0x61, 0x27, 0x4f, 0x33, 0x49, 0x10, 0xae, 0x81, 0x5d, 0x31, 0x53, +0x3a, 0x44, 0x0f, 0xfc, 0x0f, 0x4d, 0x3d, 0x52, 0x36, 0x4a, 0x30, 0xff, 0x10, 0x53, 0x36, 0x5c, +0x34, 0x48, 0x0e, 0xf5, 0x0d, 0x5a, 0x2f, 0x67, 0x2e, 0x46, 0x0d, 0xed, 0x12, 0x59, 0x30, 0x67, +0x2d, 0x46, 0x2d, 0xff, 0x0b, 0x68, 0x2a, 0x6c, 0x25, 0x4d, 0x0c, 0xff, 0x0c, 0x61, 0x35, 0x64, +0x24, 0x4e, 0x0c, 0xff, 0x06, 0x69, 0x2b, 0x6b, 0x24, 0x4b, 0x0c, 0xff, 0x0e, 0x62, 0x2b, 0x64, +0x32, 0x43, 0x0c, 0xff, 0x0e, 0x62, 0x31, 0x5c, 0x31, 0x45, 0x0c, 0xff, 0x05, 0x71, 0x2f, 0x5a, +0x28, 0x55, 0x0c, 0xeb, 0x0f, 0x62, 0x30, 0x4c, 0x40, 0x4d, 0x2d, 0xe7, 0x1d, 0x56, 0x29, 0x43, +0x43, 0x4e, 0x0d, 0xa4, 0x1b, 0x50, 0x20, 0x43, 0x47, 0x59, 0x0e, 0x92, 0x1b, 0x51, 0x1a, 0x48, +0x3d, 0x5f, 0x08, 0x2c, 0x12, 0x53, 0x2d, 0x4c, 0x49, 0x3e, 0x13, 0x27, 0x08, 0x57, 0x2c, 0x46, +0x4d, 0x42, 0x11, 0x88, 0x18, 0x50, 0x1e, 0x4b, 0x43, 0x45, 0x11, 0x70, 0x0d, 0x56, 0x1b, 0x50, +0x44, 0x43, 0x35, 0x74, 0x0a, 0x55, 0x1f, 0x51, 0x4b, 0x3f, 0x10, 0x75, 0x0d, 0x47, 0x2d, 0x53, +0x4e, 0x35, 0x11, 0x69, 0x0c, 0x50, 0x26, 0x53, 0x4f, 0x32, 0x11, 0x2f, 0x88, 0x6b, 0x1e, 0x5c, +0x3a, 0x3a, 0x5a, 0x22, 0x8f, 0xff, 0x0d, 0x61, 0x30, 0x42, 0x11, 0x1c, 0x90, 0x7e, 0x10, 0x5e, +0x32, 0x44, 0x11, 0x1b, 0x85, 0x64, 0x2a, 0x51, 0x3f, 0x3c, 0x5a, 0x22, 0x87, 0x6c, 0x3a, 0x43, +0x40, 0x46, 0x5a, 0x10, 0x8e, 0x6e, 0x40, 0x37, 0x4d, 0x3b, 0x11, 0x0b, 0x0a, 0x31, 0x72, 0x3b, +0x2b, 0x4f, 0x36, 0x07, 0x15, 0x43, 0x4b, 0x4c, 0x2a, 0x50, 0x4f, 0x04, 0x87, 0x70, 0x2a, 0x5e, +0x20, 0x4f, 0x09, 0x09, 0x91, 0xf9, 0x12, 0x6b, 0x1c, 0x58, 0x09, 0x0f, 0x91, 0xf3, 0x00, 0x70, +0x1e, 0x57, 0x26, 0x19, 0x91, 0x7b, 0x1a, 0x61, 0x2a, 0x4b, 0x17, 0x36, 0x8c, 0x5a, 0x3b, 0x5d, +0x23, 0x4c, 0x17, 0x47, 0x90, 0x60, 0x3e, 0x65, 0x11, 0x52, 0x17, 0x47, 0x8a, 0x5a, 0x3b, 0x65, +0x15, 0x4f, 0x16, 0x5e, 0x87, 0x5a, 0x3d, 0x64, 0x17, 0x52, 0x15, 0x60, 0x89, 0x5d, 0x3a, 0x64, +0x16, 0x53, 0x15, 0x66, 0x87, 0x68, 0x2e, 0x60, 0x1f, 0x53, 0x15, 0x5c, 0x88, 0x5e, 0x3b, 0x59, +0x1a, 0x59, 0x14, 0x4c, 0x8a, 0x62, 0x40, 0x4d, 0x1f, 0x57, 0x15, 0x2b, 0x8b, 0x68, 0x31, 0x52, +0x22, 0x55, 0x10, 0x15, 0x81, 0x66, 0x26, 0x5e, 0x1d, 0x55, 0x35, 0x0e, 0x02, 0x60, 0x2b, 0x57, +0x2a, 0x4f, 0x14, 0x06, 0x04, 0x64, 0x31, 0x49, 0x37, 0x44, 0x11, 0x04, 0x1b, 0x4e, 0x46, 0x3c, +0x3c, 0x3e, 0x08, 0x0c, 0x16, 0x4f, 0x4d, 0x4e, 0x22, 0x5c, 0x07, 0x12, 0x05, 0x68, 0x29, 0x60, +0x20, 0x5c, 0x10, 0x43, 0x84, 0x70, 0x1e, 0x55, 0x2d, 0x4c, 0x08, 0xb9, 0x0d, 0x5b, 0x2d, 0x47, +0x30, 0x53, 0x22, 0xf4, 0x1c, 0x4f, 0x2c, 0x46, 0x33, 0x56, 0x21, 0xff, 0x2a, 0x48, 0x25, 0x49, +0x49, 0x4e, 0x22, 0xcb, 0x24, 0x4b, 0x2d, 0x46, 0x43, 0x4a, 0x08, 0x8c, 0x22, 0x42, 0x30, 0x49, +0x48, 0x40, 0x08, 0x34, 0x06, 0x5d, 0x30, 0x54, 0x30, 0x4a, 0x5a, 0x17, 0x8a, 0x6c, 0x28, 0x5b, +0x2b, 0x49, 0x23, 0x14, 0x83, 0x61, 0x38, 0x49, 0x3b, 0x46, 0x59, 0x0e, 0x83, 0x6e, 0x23, 0x5f, +0x28, 0x54, 0x23, 0x0e, 0x02, 0x60, 0x2a, 0x61, 0x26, 0x54, 0x15, 0x0b, 0x08, 0x5d, 0x33, 0x4d, +0x2b, 0x51, 0x15, 0x0a, 0x14, 0x4d, 0x33, 0x40, 0x3c, 0x4b, 0x23, 0x05, 0x12, 0x44, 0x47, 0x33, +0x34, 0x4e, 0x23, 0x01, 0x82, 0x53, 0x3b, 0x4c, 0x2e, 0x46, 0x25, 0x03, 0x91, 0x65, 0x2e, 0x55, +0x3e, 0x38, 0x25, 0x06, 0x96, 0x74, 0x24, 0x5e, 0x38, 0x3a, 0x24, 0x08, 0x91, 0x65, 0x39, 0x4b, +0x36, 0x49, 0x23, 0x11, 0x8d, 0x69, 0x36, 0x4a, 0x30, 0x4e, 0x22, 0x17, 0x8d, 0x6c, 0x33, 0x4f, +0x2e, 0x4d, 0x23, 0x14, 0x8c, 0x71, 0x28, 0x4f, 0x2e, 0x51, 0x23, 0x0e, 0x80, 0x5d, 0x36, 0x3d, +0x36, 0x4f, 0x23, 0x10, 0x81, 0x5c, 0x34, 0x4a, 0x34, 0x4b, 0x23, 0x07, 0x82, 0x56, 0x47, 0x36, +0x42, 0x47, 0x3e, 0x03, 0x0c, 0x42, 0x5b, 0x34, 0x3c, 0x4d, 0x07, 0x02, 0x0d, 0x4d, 0x49, 0x3c, +0x40, 0x42, 0x80, 0x01, 0x28, 0x35, 0x4f, 0x3a, 0x38, 0x43, 0x06, 0x00, 0x39, 0x36, 0x3e, 0x4d, +0x42, 0x40, 0x08, 0x00, 0x35, 0x27, 0x51, 0x49, 0x37, 0x43, 0x08, 0x00, 0x31, 0x2c, 0x47, 0x47, +0x3a, 0x4a, 0x36, 0x00, 0x3c, 0x2f, 0x50, 0x42, 0x35, 0x40, 0x1f, 0x00, 0x26, 0x2d, 0x4b, 0x3d, +0x36, 0x4a, 0x20, 0x02, 0x91, 0x67, 0x3d, 0x47, 0x39, 0x3f, 0x16, 0x07, 0x92, 0x6a, 0x3b, 0x48, +0x38, 0x3f, 0x15, 0x14, 0x8b, 0x70, 0x27, 0x4d, 0x3d, 0x40, 0x28, 0x1e, 0x80, 0x5d, 0x34, 0x4a, +0x35, 0x4a, 0x27, 0x19, 0x01, 0x67, 0x27, 0x49, 0x36, 0x4c, 0x26, 0x0b, 0x88, 0x6d, 0x1c, 0x50, +0x38, 0x4a, 0x28, 0x03, 0x87, 0x5c, 0x30, 0x46, 0x3e, 0x40, 0x25, 0x02, 0x83, 0x54, 0x23, 0x4e, +0x3f, 0x46, 0x23, 0x07, 0x86, 0x57, 0x3c, 0x3f, 0x32, 0x53, 0x24, 0x14, 0x09, 0x4e, 0x34, 0x49, +0x35, 0x48, 0x3e, 0x31, 0x05, 0x60, 0x25, 0x50, 0x2f, 0x4e, 0x23, 0x3b, 0x01, 0x6c, 0x21, 0x4f, +0x33, 0x4c, 0x22, 0x41, 0x10, 0x56, 0x36, 0x47, 0x34, 0x4a, 0x28, 0x1d, 0x83, 0x70, 0x1e, 0x54, +0x2f, 0x49, 0x28, 0x0e, 0x13, 0x4a, 0x34, 0x41, 0x3b, 0x3f, 0x2f, 0x0b, 0x28, 0x44, 0x28, 0x44, +0x35, 0x3a, 0x30, 0x0b, 0x2b, 0x3c, 0x35, 0x35, 0x3e, 0x3a, 0x29, 0x21, 0x0b, 0x5a, 0x30, 0x40, +0x3a, 0x43, 0x2a, 0x2d, 0x82, 0x70, 0x19, 0x55, 0x2e, 0x4a, 0x29, 0x4a, 0x87, 0x76, 0x16, 0x63, +0x2a, 0x4f, 0x29, 0x66, 0x0d, 0x60, 0x28, 0x56, 0x29, 0x51, 0x29, 0x83, 0x13, 0x59, 0x37, 0x44, +0x2f, 0x4f, 0x1d, 0x90, 0x0a, 0x53, 0x3f, 0x50, 0x2e, 0x52, 0x1d, 0x71, 0x09, 0x65, 0x2f, 0x59, +0x2c, 0x55, 0x1d, 0x9a, 0x10, 0x5f, 0x34, 0x55, 0x2d, 0x50, 0x1c, 0x8d, 0x07, 0x6a, 0x2e, 0x58, +0x2c, 0x54, 0x1c, 0x6b, 0x12, 0x52, 0x4a, 0x4c, 0x2f, 0x5b, 0x29, 0x76, 0x04, 0x5f, 0x29, 0x5b, +0x33, 0x48, 0x0b, 0x66, 0x11, 0x49, 0x47, 0x41, 0x3a, 0x4c, 0x29, 0x30, 0x04, 0x5d, 0x34, 0x50, +0x2a, 0x57, 0x29, 0x2f, 0x08, 0x58, 0x31, 0x50, 0x2d, 0x57, 0x29, 0x28, 0x0c, 0x5a, 0x27, 0x52, +0x2a, 0x57, 0x28, 0x13, 0x80, 0x78, 0x09, 0x6e, 0x1c, 0x53, 0x10, 0x09, 0x8c, 0xff, 0x15, 0x61, +0x23, 0x51, 0x35, 0x14, 0x82, 0x69, 0x2a, 0x4f, 0x3a, 0x4b, 0x47, 0x51, 0x81, 0x64, 0x26, 0x55, +0x3c, 0x3f, 0x10, 0x7c, 0x03, 0x6a, 0x13, 0x64, 0x36, 0x43, 0x35, 0x98, 0x09, 0x58, 0x1f, 0x5d, +0x3a, 0x3d, 0x11, 0xb3, 0x0a, 0x52, 0x22, 0x5b, 0x33, 0x44, 0x34, 0x7b, 0x07, 0x5b, 0x11, 0x61, +0x36, 0x43, 0x36, 0x69, 0x0e, 0x56, 0x08, 0x65, 0x36, 0x48, 0x0c, 0x67, 0x16, 0x56, 0x02, 0x60, +0x34, 0x4f, 0x0c, 0x63, 0x17, 0x53, 0x0a, 0x61, 0x3a, 0x47, 0x10, 0x4e, 0x14, 0x4e, 0x18, 0x5c, +0x3e, 0x3d, 0x35, 0x46, 0x0d, 0x52, 0x15, 0x5e, 0x3a, 0x41, 0x10, 0x31, 0x08, 0x53, 0x14, 0x64, +0x3a, 0x40, 0x10, 0x0f, 0x91, 0x72, 0x0f, 0x6e, 0x2c, 0x42, 0x11, 0x0a, 0x97, 0xfd, 0x0b, 0x72, +0x1f, 0x4a, 0x38, 0x05, 0x93, 0x6f, 0x10, 0x72, 0x27, 0x47, 0x14, 0x05, 0x87, 0x57, 0x1d, 0x55, +0x3c, 0x48, 0x18, 0x0c, 0x8c, 0x6e, 0x26, 0x50, 0x22, 0x51, 0x18, 0x36, 0x1d, 0x46, 0x37, 0x4d, +0x21, 0x45, 0x18, 0x6d, 0x15, 0x45, 0x3a, 0x4e, 0x31, 0x46, 0x12, 0x6c, 0x12, 0x4f, 0x33, 0x47, +0x2c, 0x4d, 0x11, 0x74, 0x01, 0x61, 0x2f, 0x49, 0x38, 0x45, 0x11, 0x5e, 0x81, 0x62, 0x28, 0x53, +0x2e, 0x4b, 0x17, 0x32, 0x8b, 0x75, 0x19, 0x51, 0x35, 0x49, 0x17, 0x28, 0x05, 0x52, 0x35, 0x3d, +0x3f, 0x45, 0x17, 0x1b, 0x02, 0x52, 0x36, 0x42, 0x33, 0x4c, 0x18, 0x0f, 0x0c, 0x42, 0x30, 0x39, +0x49, 0x48, 0x17, 0x09, 0x81, 0x48, 0x3f, 0x40, 0x2f, 0x53, 0x17, 0x09, 0x16, 0x27, 0x42, 0x3c, +0x39, 0x54, 0x17, 0x0b, 0x17, 0x2a, 0x3c, 0x3f, 0x38, 0x54, 0x16, 0x11, 0x26, 0x31, 0x20, 0x31, +0x51, 0x50, 0x41, 0x0e, 0x2f, 0x37, 0x07, 0x33, 0x4f, 0x5a, 0x18, 0x0a, 0x38, 0x30, 0x81, 0x34, +0x50, 0x61, 0x45, 0x08, 0x3d, 0x2c, 0x86, 0x31, 0x51, 0x65, 0x19, 0x17, 0x14, 0x59, 0x0f, 0x55, +0x30, 0x45, 0x15, 0x34, 0x19, 0x61, 0x18, 0x4b, 0x2f, 0x3e, 0x3e, 0x60, 0x0e, 0x56, 0x23, 0x53, +0x3a, 0x40, 0x3d, 0x6c, 0x07, 0x61, 0x19, 0x5b, 0x3a, 0x41, 0x3e, 0x71, 0x06, 0x64, 0x16, 0x56, +0x43, 0x3c, 0x3e, 0x66, 0x88, 0xfe, 0x83, 0x6f, 0x2d, 0x43, 0x3e, 0x68, 0x84, 0x75, 0x0a, 0x65, +0x35, 0x40, 0x3e, 0x76, 0x82, 0x76, 0x06, 0x69, 0x2f, 0x46, 0x3d, 0x6c, 0x85, 0x79, 0x09, 0x65, +0x2c, 0x4a, 0x3e, 0x56, 0x8c, 0xfb, 0x05, 0x6a, 0x27, 0x4d, 0x3e, 0x5e, 0x87, 0x7e, 0x0a, 0x67, +0x29, 0x4c, 0x15, 0x69, 0x82, 0x78, 0x0f, 0x60, 0x29, 0x4d, 0x15, 0x6c, 0x82, 0x7b, 0x04, 0x67, +0x29, 0x4a, 0x3d, 0x65, 0x01, 0x73, 0x0e, 0x5c, 0x35, 0x41, 0x3d, 0x5e, 0x83, 0x7e, 0x00, 0x69, +0x31, 0x43, 0x3f, 0x60, 0x84, 0x7a, 0x07, 0x66, 0x32, 0x47, 0x3d, 0x5b, 0x82, 0x7c, 0x03, 0x64, +0x30, 0x47, 0x3e, 0x6e, 0x02, 0x6e, 0x0d, 0x5e, 0x31, 0x4b, 0x15, 0x57, 0x81, 0x6e, 0x13, 0x5b, +0x31, 0x49, 0x3e, 0x64, 0x06, 0x6a, 0x11, 0x57, 0x3d, 0x41, 0x3e, 0x6d, 0x04, 0x6f, 0x0a, 0x5d, +0x31, 0x4a, 0x3e, 0x56, 0x02, 0x70, 0x03, 0x62, 0x2f, 0x4d, 0x3f, 0x4e, 0x86, 0x7c, 0x80, 0x6b, +0x2e, 0x48, 0x3e, 0x5c, 0x85, 0x79, 0x07, 0x65, 0x31, 0x43, 0x3e, 0x5b, 0x83, 0x7c, 0x06, 0x62, +0x2d, 0x49, 0x3e, 0x42, 0x83, 0x73, 0x1b, 0x4a, 0x3c, 0x46, 0x3e, 0x57, 0x0c, 0x68, 0x1e, 0x47, +0x3e, 0x42, 0x15, 0x4e, 0x0b, 0x66, 0x1c, 0x48, 0x3c, 0x46, 0x3e, 0x50, 0x84, 0xfb, 0x84, 0x67, +0x2b, 0x48, 0x3e, 0x4b, 0x82, 0x7b, 0x0b, 0x58, 0x38, 0x42, 0x3e, 0x3e, 0x85, 0x7b, 0x10, 0x56, +0x34, 0x48, 0x3e, 0x4a, 0x05, 0x6b, 0x1b, 0x50, 0x31, 0x4e, 0x3e, 0x3f, 0x8a, 0xfc, 0x0c, 0x59, +0x30, 0x4c, 0x15, 0x39, 0x82, 0x73, 0x1e, 0x4b, 0x36, 0x4c, 0x3e, 0x36, 0x85, 0x7a, 0x13, 0x50, +0x36, 0x4c, 0x3e, 0x31, 0x02, 0x68, 0x2b, 0x44, 0x36, 0x4d, 0x3f, 0x43, 0x05, 0x74, 0x14, 0x53, +0x33, 0x47, 0x3e, 0x2f, 0x83, 0x71, 0x1d, 0x50, 0x34, 0x4a, 0x3e, 0x27, 0x87, 0x78, 0x0f, 0x5f, +0x2a, 0x4d, 0x3e, 0x2b, 0x82, 0x6a, 0x1c, 0x59, 0x2c, 0x4f, 0x3d, 0x24, 0x82, 0x6b, 0x23, 0x53, +0x26, 0x55, 0x3e, 0x1e, 0x81, 0x65, 0x38, 0x45, 0x2f, 0x54, 0x3e, 0x1b, 0x01, 0x68, 0x2f, 0x52, +0x1e, 0x5a, 0x3e, 0x15, 0x81, 0x6b, 0x2c, 0x5b, 0x14, 0x64, 0x3e, 0x16, 0x8a, 0xf6, 0x0a, 0x69, +0x23, 0x50, 0x3e, 0x12, 0x8d, 0xf2, 0x09, 0x6c, 0x1f, 0x55, 0x3d, 0x0f, 0x8a, 0xfa, 0x17, 0x64, +0x1f, 0x5b, 0x3d, 0x11, 0x87, 0xfb, 0x16, 0x6a, 0x1f, 0x5b, 0x3d, 0x0f, 0x83, 0x7b, 0x21, 0x60, +0x22, 0x5b, 0x3e, 0x0f, 0x8b, 0xf1, 0x03, 0x73, 0x1d, 0x56, 0x3e, 0x0b, 0x93, 0xe5, 0x91, 0xf8, +0x12, 0x59, 0x3e, 0x08, 0x91, 0xec, 0x09, 0x67, 0x27, 0x54, 0x3e, 0x06, 0x90, 0xf6, 0x1d, 0x61, +0x20, 0x5a, 0x3e, 0x06, 0x94, 0xe7, 0x8c, 0x7f, 0x1a, 0x55, 0x3d, 0x04, 0x96, 0xe5, 0x87, 0x6f, +0x25, 0x53, 0x3d, 0x05, 0x8f, 0xee, 0x0c, 0x66, 0x25, 0x57, 0x3e, 0x04, 0x8c, 0xf6, 0x20, 0x54, +0x2f, 0x55, 0x3e, 0x02, 0x95, 0xe7, 0x82, 0x6d, 0x27, 0x51, 0x3e, 0x01, 0x93, 0xe9, 0x01, 0x6f, +0x24, 0x52, 0x15, 0x01, 0x8d, 0xfb, 0x2d, 0x4a, 0x35, 0x4f, 0x15, 0x01, 0x8d, 0x7e, 0x2d, 0x4e, +0x32, 0x4e, 0x15, 0x00, 0x05, 0x65, 0x2b, 0x53, 0x39, 0x52, 0x15, 0x00, 0x01, 0x7c, 0x16, 0x59, +0x39, 0x4a, 0x2a, 0x00, 0x06, 0x61, 0x38, 0x39, 0x3b, 0x38, 0x00, 0x00, 0x83, 0x5b, 0x3d, 0x35, +0x43, 0x34, 0x15, 0x00, 0x10, 0x4e, 0x43, 0x3f, 0x37, 0x3d, 0x00, 0x00, 0x04, 0x53, 0x3f, 0x36, +0x2d, 0x47, 0x00, 0x00, 0x05, 0x57, 0x36, 0x34, 0x3b, 0x3f, 0x01, 0x00, 0x29, 0x48, 0x38, 0x34, +0x3e, 0x39, 0x15, 0x00, 0x2b, 0x5a, 0x38, 0x3f, 0x3c, 0x3c, 0x15, 0x00, 0x2b, 0x5a, 0x40, 0x47, +0x3c, 0x3a, 0x15, 0x00, 0x2b, 0x5e, 0x3f, 0x43, 0x3f, 0x3f, 0x00, 0x00, 0x2c, 0x4c, 0x41, 0x37, +0x3a, 0x42, 0x00, 0x00, 0x26, 0x4f, 0x32, 0x3d, 0x2f, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, +}; + +//File: merry.wav +//Time: 23670 ms +//Size: 8418 bytes +//Quality: 6 diff --git a/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/Sample2-Complex.ino b/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/Sample2-Complex.ino new file mode 100644 index 0000000..8c09bc0 --- /dev/null +++ b/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/Sample2-Complex.ino @@ -0,0 +1,135 @@ +#include +#include +#include "voices.h" +#include "bitmaps.h" + +#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0])) + +Arduboy2 arduboy; +ArdVoice ardvoice; +#define ARDBITMAP_SBUF arduboy.getBuffer() +#include +ArdBitmap ardbitmap; +unsigned long initTime; + +int voice_segment = 0; +boolean onePlayed = false; +boolean twoPlayed = false; +boolean threePlayed = false; +boolean merryPlayed = false; + +void setup() { + arduboy.begin(); + arduboy.invert(!arduboy.audio.enabled()); + arduboy.setFrameRate(60); + initTime = millis(); +} + + +void loop() { + if (!(arduboy.nextFrame())) + return; + + arduboy.clear(); + unsigned long myTime = (millis()-initTime); + float resize1 = abs(sin((millis()-initTime)/ (1000.0/(PI)))); + float resize2 = abs(sin((millis()-initTime - 3000)/ (4000.0/(PI)))); + float resize3 = abs(sin((millis()-initTime - 7000)/ (8000.0/(PI)))); + + if (myTime < 7000){ + setContrast((myTime > 3000 ? resize2 :resize1) * 255); + ardbitmap.drawCompressedResized(WIDTH / 2, HEIGHT / 2, myTime < 1000 ? NUMBER_3 : + myTime < 2000 ? NUMBER_2 : + myTime < 3000 ? NUMBER_1 : + MERRY_CHRISTMAS , WHITE, ALIGN_CENTER, MIRROR_NONE, myTime > 3000 ? resize2 :resize1); + + } else { + + int contrast = resize3 * 255; + setContrast(contrast); + ardbitmap.drawCompressedResized(WIDTH/2, HEIGHT, DOG[ (myTime/80)% ARRAY_LEN(DOG)], WHITE, ALIGN_H_CENTER | ALIGN_V_BOTTOM, MIRROR_NONE, resize3 ); + + } + + //VOICES + if (myTime > 250 && !threePlayed){ + threePlayed = true; + ardvoice.playVoice(three_q6); + } + + if (myTime > 1250 && !twoPlayed){ + twoPlayed = true; + ardvoice.playVoice(two_q6); + } + + if (myTime > 2300 && !onePlayed){ + onePlayed = true; + ardvoice.playVoice(one_q6); + } + + if (myTime > 3200){ + + if(!ardvoice.isVoicePlaying()) { + switch(voice_segment){ + case 0: + ardvoice.playVoice(merry_q6); + voice_segment++; + break; + case 1: + ardvoice.playVoice(merry_q6, 4400, 0, 1.0); + voice_segment++; + break; + case 2: + ardvoice.playVoice(merry_q6, 4400, 13500, 0.8); + voice_segment++; + break; + case 3: + ardvoice.playVoice(merry_q6, 4400, 11500, 1.3); + voice_segment++; + break; + case 4: + ardvoice.playVoice(merry_q6, 11500, 13500, 1.4); + voice_segment++; + break; + default: + break; + } + } + } + + //Reset demo + if(arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON)){ + initTime = millis(); + voice_segment = 0; + onePlayed = false; + twoPlayed = false; + threePlayed = false; + merryPlayed = false; + } + if(arduboy.pressed(UP_BUTTON)){ + arduboy.audio.on(); + arduboy.invert(false); + } + if(arduboy.pressed(DOWN_BUTTON)){ + arduboy.audio.off(); + arduboy.invert(true); + } + + arduboy.display(); +} + + + +void setContrast(uint8_t contrast){ + + arduboy.LCDCommandMode(); + SPI.transfer(0xd9); + SPI.transfer(0x2f); + SPI.transfer(0xdb); + SPI.transfer(0x00); + + SPI.transfer(0x81); // contrast command + SPI.transfer(contrast); + arduboy.LCDDataMode(); +} + diff --git a/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/bitmaps.h b/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/bitmaps.h new file mode 100644 index 0000000..1590592 --- /dev/null +++ b/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/bitmaps.h @@ -0,0 +1,197 @@ + +const uint8_t NUMBER_1[] PROGMEM ={ +0x3f, 0xbf, 0xff, 0x0c, 0x72, 0x1b, 0x87, 0xbd, 0xf7, 0xde, 0x7b, 0xff, 0x3b, 0xda, 0xfb, 0xb0, +0x2e, 0xe3, 0xd6, 0xa3, 0x3f, 0xf7, 0xdf, 0x4f, 0x2e, 0xeb, 0xb2, 0x2e, 0xeb, 0x70, 0xc8, 0xef, +0xfe, 0x77, 0xf8, 0xbb, 0xff, 0x1d, 0xfe, 0xee, 0x7f, 0x87, 0xbf, 0xfb, 0xdf, 0xe1, 0xef, 0xfe, +0xa7, 0x78, 0x59, 0x97, 0x75, 0x59, 0x97, 0x75, 0x59, 0x97, 0x75, 0x59, 0xe3, 0xef, 0x03, +}; + +const uint8_t NUMBER_2[] PROGMEM ={ +0x3f, 0xff, 0x7f, 0x1f, 0x8e, 0xe3, 0x32, 0xf7, 0x9e, 0x97, 0x75, 0x59, 0x97, 0x75, 0x59, 0x87, +0xbd, 0x0f, 0xeb, 0x94, 0x7f, 0x3b, 0x87, 0xfc, 0x8c, 0xec, 0xcb, 0x3a, 0xfc, 0xc4, 0xce, 0x7f, +0x15, 0xd3, 0xab, 0x57, 0xaf, 0x5e, 0xbd, 0xbe, 0x1f, 0xfd, 0xbd, 0xff, 0xce, 0x38, 0x5d, 0xfc, +0x9d, 0x1e, 0xfe, 0x51, 0x71, 0xdb, 0xfd, 0x99, 0xdc, 0x76, 0xff, 0x19, 0x71, 0xdb, 0xfd, 0x99, +0x5e, 0x0e, 0xfd, 0x37, 0xb5, 0xfb, 0x93, 0x59, 0x71, 0xac, 0xcb, 0xba, 0xac, 0xcb, 0xba, 0xac, +0x4b, 0xfe, 0x5d, 0x8c, 0x75, 0x59, 0x97, 0x75, 0x59, 0x97, 0x75, 0x59, 0x97, 0x75, 0x59, 0x97, +0x75, 0x59, 0x97, 0x75, 0x59, 0x97, 0x75, 0x59, 0x97, 0x3f, 0x09, +}; + + +const uint8_t NUMBER_3[] PROGMEM ={ +0x3f, 0xbf, 0x7f, 0x96, 0x9c, 0xd6, 0x61, 0xef, 0xc3, 0xba, 0xac, 0xcb, 0xba, 0xac, 0xcb, 0xba, +0xac, 0xc3, 0xde, 0x87, 0x75, 0xca, 0x3f, 0x95, 0x13, 0xbf, 0xab, 0xf3, 0x32, 0xfb, 0x2b, 0x67, +0xfe, 0x1d, 0xac, 0xde, 0x7a, 0xeb, 0xad, 0xb7, 0xde, 0x7a, 0xfb, 0xc2, 0xcf, 0xfd, 0xa7, 0x75, +0xeb, 0xad, 0x47, 0x7e, 0x0a, 0x9b, 0xe5, 0x68, 0x16, 0xff, 0x2a, 0x7a, 0xeb, 0xad, 0xb7, 0xde, +0xba, 0x6c, 0xdb, 0xba, 0x7a, 0x5a, 0xfb, 0x07, 0xff, 0x1b, 0xf8, 0x9d, 0xdf, 0xf9, 0xbd, 0x7f, +0xff, 0xac, 0x5f, 0x78, 0xea, 0x6d, 0x8c, 0x5f, 0x39, 0xf3, 0xef, 0x81, 0xe3, 0xb8, 0xcc, 0x7d, +0x58, 0x97, 0x71, 0xeb, 0xad, 0xb7, 0xde, 0x7a, 0x1b, 0x97, 0x75, 0xd8, 0xf3, 0x32, 0xfe, 0x3a, +}; + + + +const uint8_t DOG_0[] PROGMEM ={ +0x7f, 0xbf, 0xff, 0xec, 0xbc, 0x7a, 0xf5, 0xea, 0xd5, 0xab, 0xff, 0x1d, 0xe1, 0xb4, 0x0e, 0x7b, +0xd6, 0x91, 0x95, 0xdb, 0x38, 0x1c, 0xd6, 0x29, 0x7f, 0x8d, 0x9c, 0xe6, 0x3c, 0xf5, 0xe8, 0x5f, +0xc7, 0x6b, 0x6e, 0xe3, 0x32, 0xf7, 0x61, 0x9d, 0x7a, 0xcb, 0xd5, 0xab, 0x9f, 0xde, 0xf3, 0x32, +0xf7, 0xde, 0x7b, 0x1f, 0xd6, 0x65, 0xee, 0xbd, 0xf7, 0xde, 0x7b, 0x1f, 0xc6, 0x91, 0xbf, 0xf2, +0x38, 0xec, 0x79, 0xca, 0x95, 0xe9, 0xb1, 0xa7, 0x75, 0xd8, 0xfb, 0x30, 0xe7, 0x29, 0xff, 0x1c, +0xb9, 0x7a, 0x14, 0xfe, 0xb8, 0xb9, 0x8d, 0xcb, 0xba, 0xfc, 0x89, 0xb9, 0xe6, 0xd6, 0xd3, 0xba, +0xac, 0xcb, 0x3a, 0xf5, 0xe8, 0x71, 0x1c, 0x2e, 0xf9, 0xe7, 0xcb, 0x35, 0xa7, 0x75, 0xd8, 0x7b, +0xef, 0x7d, 0x58, 0x97, 0x75, 0x59, 0x87, 0xbd, 0xf7, 0x3c, 0xe5, 0x9f, 0xd6, 0x89, 0xcf, 0x38, +0x7a, 0xeb, 0x2d, 0xdf, 0xe7, 0xd6, 0x5b, 0x4f, 0x7b, 0xdc, 0xc6, 0x65, 0xf6, 0xf7, 0x73, 0xcd, +0x6d, 0x5c, 0xe6, 0x3e, 0x8c, 0x5b, 0xfe, 0xe3, 0xf1, 0x05, 0x4e, 0x27, 0x3e, 0xd3, 0xc3, 0xc5, +0xcf, 0xe4, 0x74, 0xf0, 0x3d, 0xf3, 0x77, 0x70, 0x1c, 0x87, 0xc3, 0x38, 0xf2, 0xdf, 0xa7, 0xd5, +0x5b, 0x4f, 0x6b, 0xff, 0x98, 0xee, 0x0f, 0x60, 0x2e, 0xeb, 0x32, 0x3e, 0xd2, 0xc3, 0x61, 0x1c, +0xf9, 0xef, 0x2d, 0xc7, 0xde, 0xb6, 0x1f, 0x9d, 0xfb, 0xdf, 0x38, +}; + +const uint8_t DOG_1[] PROGMEM ={ +0x7f, 0xff, 0xff, 0xfb, 0x88, 0xe3, 0x38, 0xec, 0x79, 0x59, 0x97, 0x75, 0x59, 0x97, 0x75, 0x59, +0x97, 0x75, 0x99, 0x7b, 0xcf, 0x53, 0x8f, 0xfe, 0xb9, 0xb9, 0x7a, 0xcd, 0x69, 0x1d, 0xf6, 0xde, +0x7b, 0x9e, 0x7a, 0xf4, 0x9f, 0x23, 0xb7, 0x3d, 0x8e, 0xfc, 0xb9, 0x3d, 0xf6, 0x36, 0x2e, 0xeb, +0xb2, 0x2e, 0xeb, 0xb2, 0x2e, 0xeb, 0xb0, 0x4f, 0x5e, 0x3d, 0xe6, 0xea, 0x5f, 0x79, 0xe4, 0xef, +0xea, 0x35, 0xb7, 0x71, 0x99, 0xfb, 0x30, 0x6e, 0x79, 0xc6, 0x95, 0x7f, 0xee, 0x39, 0xcd, 0xc3, +0xba, 0xac, 0xcb, 0x3a, 0xec, 0xbd, 0xf7, 0xde, 0x7b, 0x9e, 0xfa, 0xb7, 0x40, 0x4e, 0x92, 0xcb, +0xdc, 0x7b, 0xef, 0xbd, 0xf7, 0xde, 0x7b, 0xef, 0xbd, 0x0f, 0xeb, 0x32, 0x6e, 0xf9, 0x0c, 0x93, +0x4e, 0x07, 0x3f, 0x29, 0x47, 0x3e, 0x3e, 0x6e, 0xf9, 0x73, 0x72, 0x1c, 0x87, 0xc3, 0x38, 0xfa, +0x9f, 0x0b, 0x8e, 0xe3, 0x32, 0xf7, 0x9e, 0x97, 0x71, 0xeb, 0xd1, 0xc9, 0xe7, 0xc7, 0x38, 0xcd, +0xf5, 0x15, 0x8e, 0xe3, 0x30, 0x4f, 0xf9, 0x0d, 0xb4, 0xae, 0x5c, 0xf9, 0x6f, 0x56, 0x18, 0xeb, +0xb2, 0x2e, 0xeb, 0xb2, 0x2e, 0xea, 0x85, 0xf2, 0x88, 0x6b, 0x6e, 0xb9, 0x3a, 0xb9, 0x7a, 0xec, +0x69, 0xae, 0xc5, 0x68, 0x87, 0x9f, 0xfe, 0xef, 0x19, 0x57, 0xaf, 0x5e, 0xbd, 0x7a, 0xf5, 0xb7, +0xce, 0xbd, 0xf7, 0xde, 0x7b, 0xef, 0x3d, 0x2f, 0xe3, 0x5f, 0x1d, +}; + +const uint8_t DOG_2[] PROGMEM ={ +0x7f, 0xff, 0xff, 0xb9, 0xf4, 0xea, 0xd5, 0x2b, 0xff, 0xfe, 0xb9, 0x7a, 0xcd, 0xad, 0xb7, 0xde, +0x7a, 0xeb, 0xad, 0xb7, 0x1e, 0xbd, 0xfa, 0x35, 0xaf, 0x5e, 0xbd, 0x7a, 0xf5, 0xea, 0xd5, 0xab, +0x57, 0xbf, 0x74, 0xea, 0x2d, 0x57, 0xaf, 0xfc, 0x1e, 0x8e, 0xe3, 0xb2, 0x2e, 0xeb, 0xb2, 0x2e, +0xeb, 0xf0, 0x4f, 0xab, 0x87, 0xc3, 0xb8, 0xe5, 0x9f, 0x39, 0x57, 0xaf, 0x39, 0x7a, 0xf5, 0xea, +0x35, 0xb7, 0x71, 0x38, 0xf4, 0x5f, 0x4d, 0x4e, 0x73, 0xfd, 0xab, 0xe6, 0x9a, 0xdb, 0x38, 0x1c, +0xc6, 0x91, 0x3f, 0x2e, 0xe5, 0x60, 0xb3, 0x32, 0x92, 0xae, 0xd2, 0xbd, 0xf7, 0xde, 0x7b, 0xef, +0xbd, 0xf7, 0xde, 0x87, 0x75, 0xea, 0xd1, 0xe5, 0xb1, 0xa7, 0x79, 0x18, 0xb7, 0xfc, 0xa9, 0x74, +0x8d, 0xcb, 0xdc, 0x87, 0x71, 0xcb, 0xd5, 0xab, 0xbf, 0xce, 0xab, 0xbf, 0xc2, 0x63, 0x4f, 0x73, +0x1f, 0xd6, 0xa9, 0x47, 0xfe, 0x5d, 0x70, 0xf5, 0x9a, 0x5b, 0x6f, 0xbd, 0xf5, 0xe8, 0x95, 0xdf, +0xcb, 0xfc, 0xbe, 0x97, 0xfd, 0xf9, 0x53, 0xae, 0xbc, 0xf7, 0xd6, 0x5b, 0x17, 0x23, 0x9d, 0x09, +0x1f, 0xfd, 0xbc, 0xd7, 0x8c, 0xb4, 0x1d, 0x2e, 0x17, 0x9f, 0xee, 0xf8, 0xa7, 0xed, 0xba, 0xf1, +0xa5, 0x8c, 0x23, 0x9f, 0xf3, 0x38, 0x0e, 0x7b, 0x9e, 0xf2, 0x8c, 0x6b, 0xbe, 0xc8, 0x70, 0xcf, +0xc3, 0xde, 0x7b, 0x9e, 0xfc, 0x31, 0x73, 0xef, 0x79, 0x99, 0xfb, 0xb0, 0x4e, 0x3d, 0xf2, 0xcf, +0x3f, 0xa7, 0x39, 0x2f, 0xe3, 0xc8, 0xf4, 0xd8, 0x5b, 0x6f, 0xe3, 0xf2, 0x13, 0xb8, 0xe6, 0xd6, +0x5b, 0x6f, 0x3d, 0xf2, 0xef, 0x16, +}; + +const uint8_t DOG_3[] PROGMEM ={ +0x7f, 0xff, 0xff, 0x39, 0xf3, 0xd8, 0x5b, 0x6f, 0xbd, 0xf5, 0x36, 0x2e, 0xeb, 0xb0, 0xf7, 0x3e, +0xac, 0x53, 0x8f, 0xfc, 0xe7, 0xcb, 0x63, 0x6f, 0xbd, 0xf5, 0xd6, 0x5b, 0x6f, 0x3d, 0x48, 0x49, +0xfe, 0x9c, 0x1c, 0x7b, 0xeb, 0xad, 0xb7, 0x8e, 0x7f, 0x0f, 0x5e, 0xbd, 0x7a, 0xf5, 0x38, 0x0e, +0x7b, 0x5e, 0xc6, 0x2d, 0x57, 0xaf, 0x5e, 0xbd, 0x7a, 0xf5, 0xea, 0xd5, 0xab, 0xd7, 0xdc, 0x72, +0xf5, 0xea, 0x3f, 0x03, 0x8e, 0x3d, 0xad, 0xcb, 0xba, 0xac, 0xcb, 0xba, 0xac, 0xcb, 0x3a, 0xec, +0xbd, 0xe7, 0x8d, 0xbf, 0x13, 0xc7, 0x71, 0x99, 0xf3, 0xd4, 0xa3, 0xcb, 0xe3, 0xb8, 0xac, 0xc3, +0xde, 0xe3, 0x9f, 0x3a, 0xc3, 0x59, 0x3b, 0x86, 0x8b, 0xe9, 0xb1, 0xb7, 0xde, 0x7a, 0xeb, 0x2d, +0x57, 0xfe, 0x06, 0x2c, 0x36, 0xcb, 0x95, 0x66, 0xa5, 0x59, 0x69, 0x56, 0xed, 0xba, 0xac, 0xcb, +0xdc, 0x87, 0x71, 0xf4, 0xb3, 0x1c, 0xc7, 0xe1, 0x10, 0xf8, 0x0b, 0xce, 0xcb, 0xb8, 0xf5, 0xe8, +0xd5, 0x9f, 0xc3, 0xd5, 0x63, 0x8f, 0xfc, 0xb1, 0x28, 0x17, 0xc9, 0x65, 0x9d, 0x72, 0xe5, 0x99, +0xc7, 0x9e, 0xe6, 0x3e, 0x8c, 0xbf, 0xed, 0x5a, 0x47, 0xaf, 0xbc, 0xe3, 0x9a, 0xdb, 0xb8, 0xcc, +0x7d, 0x58, 0x97, 0x71, 0xeb, 0x69, 0xfb, 0x03, 0xb8, 0x1d, 0xfc, 0xe7, 0xe0, 0xd5, 0xab, 0xa3, +0x6d, 0x56, 0xda, 0xe6, 0x93, 0xac, 0x0f, 0x71, 0xec, 0x69, 0x5d, 0xd6, 0x65, 0x1c, 0xf9, 0x3b, +0x79, 0xb9, 0xe4, 0x23, 0xe3, 0x70, 0xc9, 0x95, 0x1f, 0xbe, 0xf8, 0x01, 0x23, 0xff, 0x8c, 0x3c, +0xad, 0xcb, 0xba, 0xac, 0xcb, 0xb8, 0xe5, 0xdf, 0xce, 0xa1, 0x47, 0xaf, 0xae, 0x0c, 0x47, 0x47, +0xf2, 0x27, 0xe1, 0x9a, 0xd3, 0x3a, 0x1c, 0xc6, 0xd1, 0x57, 0xb9, 0xf5, 0xd6, 0x45, 0x67, 0xfe, +0x03, 0x00, +}; + +const uint8_t DOG_4[] PROGMEM ={ +0x7f, 0xff, 0xff, 0xf9, 0xf3, 0xbf, 0x8e, 0x5e, 0x3d, 0xf6, 0x36, 0x2e, 0x73, 0xef, 0xbd, 0xf7, +0xbc, 0xac, 0xcb, 0xb8, 0x55, 0x13, 0x4b, 0x19, 0x94, 0xbf, 0x89, 0xc7, 0x71, 0x99, 0xf3, 0xb2, +0x4e, 0xbd, 0xf5, 0xe6, 0xef, 0xe1, 0x38, 0x2e, 0x73, 0x5e, 0xc6, 0x62, 0x74, 0xb8, 0x1c, 0x1d, +0xac, 0x71, 0x59, 0x97, 0x75, 0x59, 0x97, 0x71, 0xeb, 0xd1, 0xe5, 0xd5, 0x63, 0x6f, 0xb9, 0xfa, +0x73, 0xb9, 0xfa, 0xaf, 0xd0, 0xab, 0x3f, 0x87, 0x6b, 0x4e, 0x73, 0x7e, 0xc4, 0x4b, 0xec, 0xe8, +0x28, 0xdd, 0xf3, 0x32, 0x8e, 0xfe, 0x19, 0xb8, 0xcd, 0xf5, 0x1f, 0x02, 0xb6, 0xcd, 0x68, 0x9b, +0xd1, 0xc1, 0xea, 0xad, 0xb7, 0xde, 0x7a, 0xeb, 0x2d, 0x57, 0xff, 0x9a, 0x39, 0xad, 0xcb, 0xdc, +0x7b, 0x1f, 0xd6, 0xa9, 0x47, 0xfe, 0x4a, 0x63, 0xdf, 0xbc, 0x7a, 0xf5, 0xea, 0xb1, 0xa7, 0x75, +0xd8, 0xf3, 0xb2, 0x4e, 0xbd, 0xf5, 0xd6, 0x5b, 0x6f, 0xbd, 0xf5, 0xd6, 0xd3, 0xba, 0xac, 0xc3, +0xde, 0xf3, 0xd4, 0xa3, 0x57, 0xaf, 0x7c, 0x9a, 0x99, 0x66, 0xb4, 0x6d, 0x56, 0xed, 0x8c, 0x39, +0xac, 0x4b, 0xf0, 0x84, 0xdc, 0xd0, 0x26, 0x7a, 0xe5, 0x63, 0x73, 0xef, 0xc3, 0x3a, 0xec, 0x79, +0xca, 0x67, 0x38, 0x8e, 0x43, 0x06, 0xbf, 0xcc, 0xab, 0xc7, 0xde, 0xc6, 0x65, 0xee, 0xc3, 0xb8, +0xe5, 0x9f, 0x2b, 0xd7, 0xdc, 0xc6, 0x65, 0xce, 0xcb, 0xba, 0xac, 0xcb, 0xba, 0xac, 0xcb, 0xba, +0xac, 0xcb, 0x3a, 0xec, 0x79, 0xf2, 0x73, 0x39, 0xad, 0xc3, 0xde, 0xf3, 0xb2, 0x4e, 0xb9, 0xb2, +0x3d, 0xdc, 0xf8, 0x4c, 0x0f, 0x17, 0xff, 0x6b, 0x3d, 0xc7, 0x2d, 0x57, 0xaf, 0x2e, 0x97, 0x63, +0xe4, 0xbf, 0x90, +}; + +const uint8_t DOG_5[] PROGMEM ={ +0x7f, 0xbf, 0x3f, 0xd3, 0xab, 0xc7, 0xde, 0x7a, 0xeb, 0x69, 0x5d, 0xd6, 0x65, 0x5d, 0xd6, 0x65, +0x9d, 0x7a, 0xeb, 0xd1, 0x7f, 0xdd, 0x5e, 0xbd, 0x7a, 0xf5, 0xea, 0x1f, 0x9a, 0x8b, 0x7a, 0x02, +0x6f, 0xbd, 0xf5, 0xe8, 0xd5, 0xab, 0x57, 0x8f, 0xbd, 0xf5, 0xd6, 0xd3, 0x3a, 0xec, 0x79, 0x19, +0xb7, 0x3c, 0xe3, 0xd8, 0xd3, 0xba, 0xac, 0x53, 0x6f, 0xbd, 0xf5, 0xd6, 0x5b, 0x6f, 0xbd, 0x8d, +0xcb, 0xba, 0xac, 0xc3, 0xde, 0x7b, 0x5e, 0xd6, 0x65, 0x5d, 0xd6, 0x65, 0x5d, 0xd6, 0x65, 0xee, +0xbd, 0xf7, 0xde, 0x7b, 0x1f, 0xd6, 0xa9, 0xb7, 0x74, 0xd5, 0xce, 0x98, 0x03, 0x1f, 0xce, 0x69, +0x5d, 0xd6, 0x65, 0x1d, 0xf6, 0xbc, 0x8c, 0x23, 0xff, 0xbc, 0xc6, 0xfa, 0x8f, 0x95, 0xc7, 0x8e, +0xf4, 0x97, 0x72, 0xf5, 0x9a, 0xd3, 0x9c, 0xa7, 0x5c, 0xb9, 0x73, 0xf5, 0xd8, 0xd3, 0xba, 0x8c, +0x23, 0x7f, 0x16, 0x8f, 0xe3, 0x32, 0xf7, 0x3c, 0xe5, 0x5f, 0x47, 0x6e, 0xe3, 0x32, 0xf7, 0x61, +0x5d, 0xd6, 0xa9, 0xb7, 0xde, 0x7a, 0xeb, 0x69, 0x5d, 0xd6, 0x65, 0xdc, 0xf2, 0x73, 0xbd, 0x5c, +0xf8, 0x7d, 0x5e, 0x3d, 0xe6, 0xea, 0xd5, 0xab, 0x57, 0x8f, 0x3d, 0xcd, 0x7d, 0x58, 0x97, 0x75, +0x19, 0xb7, 0x1e, 0xfd, 0xb5, 0xb9, 0x8d, 0xc3, 0xde, 0x87, 0x75, 0x59, 0x97, 0x75, 0xea, 0x6d, +0x5c, 0xd6, 0x25, 0xbf, 0x93, 0xe3, 0xb8, 0xac, 0xc3, 0x9e, 0x97, 0x71, 0xcb, 0x95, 0x3f, 0xcd, +0x65, 0x5d, 0xc6, 0xad, 0x47, 0x27, 0xd7, 0xdc, 0xc6, 0xe1, 0xb0, 0x4e, 0xb9, 0xf2, 0x8f, 0x7f, +0x8f, 0xdf, 0x91, 0x8e, 0x71, 0x99, 0x7b, 0xcf, 0xcb, 0x3a, 0xf5, 0x96, 0xab, 0x57, 0x97, 0xd7, +0xdc, 0x7a, 0xeb, 0x2d, 0xd7, 0xdc, 0x3a, 0xd2, 0xff, 0xa0, 0xe5, 0xb4, 0xc7, 0x91, 0xcf, 0xe4, +0x72, 0x18, 0x47, 0xfe, 0xbb, 0xcd, 0x71, 0x1c, 0x0e, 0xe3, 0xe8, 0xd5, 0xc9, 0x72, 0x74, 0x38, +0x3a, 0x1c, 0x1d, 0x8e, 0xe1, 0x4f, 0x05, +}; + +const uint8_t DOG_6[] PROGMEM ={ +0x7f, 0xff, 0xbf, 0x8d, 0xc5, 0x74, 0x39, 0x32, 0x4d, 0x76, 0xe8, 0x9e, 0x87, 0x3d, 0x2f, 0xe3, +0xe8, 0xf2, 0xd8, 0xd3, 0x3a, 0x1c, 0xd6, 0x29, 0xff, 0x15, 0xcf, 0x6d, 0x1c, 0xf6, 0x3c, 0xf5, +0xc8, 0xe6, 0x9a, 0x5b, 0x6f, 0xbd, 0xf5, 0xd6, 0x5b, 0x6f, 0xbd, 0xf5, 0xd6, 0xd3, 0x3a, 0xec, +0x7d, 0x58, 0xa7, 0x1e, 0xfd, 0x7b, 0x76, 0xdc, 0x7a, 0x1b, 0x97, 0x39, 0x4f, 0xfe, 0x7b, 0xe2, +0xd8, 0xcb, 0x61, 0x9d, 0x7a, 0x1b, 0x87, 0xc3, 0x38, 0x7a, 0xed, 0xe1, 0xd0, 0x7f, 0x1d, 0x5e, +0xbd, 0x7a, 0xf5, 0xea, 0xb1, 0xb7, 0xde, 0x7a, 0x5a, 0x87, 0xc3, 0xba, 0xac, 0xcb, 0x6a, 0xfd, +0x34, 0x57, 0xaf, 0x5e, 0x3d, 0x8e, 0xc3, 0x61, 0x1c, 0xf9, 0xc1, 0x1e, 0xf6, 0xde, 0xfb, 0xb0, +0x4e, 0x3d, 0xfa, 0x8c, 0x63, 0x4f, 0x73, 0xef, 0x1d, 0xb3, 0x2d, 0x7f, 0x6c, 0xfe, 0xd5, 0x3b, +0x59, 0x8e, 0x5f, 0xc2, 0x35, 0xb7, 0x71, 0x59, 0x97, 0x75, 0xea, 0x11, 0x33, 0x86, 0xa3, 0xc3, +0xd1, 0x5b, 0x6f, 0xbd, 0x8d, 0xcb, 0x3a, 0xec, 0x79, 0x59, 0x97, 0x75, 0x59, 0x97, 0x75, 0xea, +0xad, 0xb7, 0xde, 0x7a, 0xeb, 0x2d, 0x57, 0x9f, 0x73, 0x1c, 0x87, 0xc3, 0xba, 0x04, 0xfe, 0x96, +0xe8, 0x65, 0xee, 0xc3, 0xba, 0x8c, 0x5b, 0x8f, 0x5e, 0xbd, 0x7a, 0xcd, 0xad, 0xa7, 0x75, 0x59, +0x97, 0x71, 0xcb, 0x95, 0xff, 0x4e, 0x78, 0xb9, 0xe4, 0xb3, 0x1c, 0xc7, 0xe1, 0x30, 0x8e, 0x5e, +0xc7, 0xbc, 0x8c, 0x5b, 0xae, 0x7c, 0x36, 0xa7, 0x39, 0x4f, 0xf9, 0xaf, 0xd7, 0xca, 0x67, 0x72, +0x39, 0x8c, 0x23, 0x7f, 0x1e, 0x8f, 0x3d, 0xcd, 0x79, 0x19, 0x47, 0x5f, 0xe5, 0xb4, 0x0e, 0x7b, +0x5e, 0xd6, 0x65, 0x5d, 0xc6, 0x7f, 0x45, 0x32, 0x8f, 0x5e, 0xbd, 0x3a, 0x59, 0x8e, 0x7f, 0x10, +0x1e, 0x7b, 0xeb, 0x69, 0x5d, 0xd6, 0x65, 0xdc, 0xfa, 0xab, 0x00, +}; + +const uint8_t *DOG[] = { +DOG_0, +DOG_1, +DOG_2, +DOG_3, +DOG_4, +DOG_5, +DOG_6, +}; + +const uint8_t MERRY_CHRISTMAS[] PROGMEM ={ +0x7f, 0xff, 0x7f, 0xec, 0x75, 0x59, 0x97, 0xf1, 0x63, 0x7a, 0x59, 0x97, 0x75, 0xc9, 0x7f, 0x57, +0x3f, 0x92, 0xcd, 0xe9, 0xc4, 0xe3, 0x83, 0xdb, 0xc3, 0x78, 0x7f, 0xf7, 0x72, 0x58, 0xc3, 0x36, +0x2b, 0xcd, 0xe8, 0xb8, 0xcc, 0xf5, 0x7a, 0xf5, 0xb6, 0x1a, 0x47, 0x56, 0xea, 0x9b, 0xd5, 0xdb, +0x6a, 0x1c, 0x59, 0xa9, 0x57, 0x66, 0x7b, 0xeb, 0x7e, 0xbc, 0xc6, 0xad, 0x63, 0xf8, 0x2f, 0xf8, +0xfd, 0x3d, 0xfb, 0xc9, 0x78, 0xb2, 0xc6, 0xb3, 0xf7, 0x4f, 0x6e, 0xbc, 0x61, 0xa5, 0x59, 0x69, +0x56, 0x86, 0xcb, 0x8c, 0xbc, 0x7b, 0xff, 0xbd, 0xf7, 0xdf, 0xe5, 0x74, 0x62, 0x73, 0xf4, 0xd1, +0xc1, 0x7f, 0xcf, 0x5c, 0xbd, 0xf2, 0x39, 0xaf, 0x7c, 0xce, 0xab, 0x5f, 0xf7, 0xea, 0xd5, 0xaf, +0x7b, 0xf5, 0xeb, 0x5e, 0xfd, 0xae, 0x87, 0x98, 0x59, 0x8f, 0x63, 0xfe, 0xab, 0xe1, 0xea, 0xd5, +0xab, 0x1f, 0xef, 0xad, 0x7f, 0x3d, 0x6f, 0xbd, 0xf9, 0x1f, 0x9f, 0xdd, 0x37, 0x7b, 0xdc, 0x7a, +0x1b, 0x87, 0x4b, 0x17, 0xa3, 0x79, 0xf2, 0x7e, 0x89, 0x87, 0x98, 0x1d, 0xba, 0xe7, 0xc9, 0xf7, +0xdd, 0xfb, 0x22, 0x1e, 0x62, 0xb6, 0x2f, 0x1a, 0xb3, 0x63, 0x7a, 0xe7, 0x38, 0x0e, 0x7b, 0xc7, +0xec, 0xd0, 0xc3, 0x3a, 0x79, 0x8b, 0xe9, 0xfb, 0xc6, 0xec, 0x3c, 0xde, 0x7b, 0x9d, 0x34, 0x3b, +0x74, 0xef, 0xc3, 0x38, 0x05, 0x0f, 0x31, 0x7b, 0x1f, 0xc6, 0xb7, 0xc6, 0x65, 0xee, 0x98, 0x1d, +0xba, 0xe7, 0xc9, 0xe7, 0x39, 0xcd, 0x5d, 0xb2, 0x63, 0xf6, 0xbc, 0x8c, 0x57, 0xa3, 0xcf, 0x46, +0xbf, 0x96, 0xcb, 0xde, 0x25, 0x6f, 0xde, 0x7f, 0xe7, 0xfd, 0xfb, 0xf7, 0xdf, 0x7b, 0x7f, 0xb7, +0x23, 0x75, 0x6b, 0xd2, 0xac, 0x0c, 0x03, 0x51, 0x0f, 0x31, 0x7d, 0xf7, 0x7e, 0xf2, 0x9d, 0xf7, +0xef, 0xdf, 0x7f, 0xe7, 0xfd, 0xbd, 0xd1, 0x8b, 0x3a, 0x92, 0xba, 0xad, 0x89, 0xfa, 0xfe, 0x6e, +0x9b, 0x69, 0xad, 0x59, 0x69, 0x96, 0xc1, 0xb0, 0x34, 0x3b, 0xbc, 0xe7, 0xd8, 0xd3, 0xba, 0xac, +0xcb, 0xba, 0x8c, 0x5b, 0x9e, 0xe7, 0xb2, 0x2e, 0xf9, 0xd8, 0xba, 0xac, 0x2f, 0xad, 0xcb, 0xfa, +0xf2, 0xba, 0xac, 0xc7, 0xde, 0xc6, 0x65, 0x5d, 0xd6, 0x65, 0xdc, 0xf2, 0xb1, 0x71, 0x59, 0x97, +0xf5, 0x38, 0x97, 0x75, 0xc9, 0xfb, 0x5c, 0xd6, 0x25, 0x1f, 0x5b, 0x97, 0xf5, 0x36, 0xa7, 0x75, +0x59, 0x97, 0x71, 0xec, 0x65, 0x5d, 0xf2, 0xba, 0xa7, 0x75, 0x59, 0x97, 0x75, 0xea, 0x91, 0x0d, +}; + + diff --git a/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/voices.h b/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/voices.h new file mode 100644 index 0000000..efd8d84 --- /dev/null +++ b/board-package-source/libraries/ArdVoice/examples/Sample2-Complex/voices.h @@ -0,0 +1,594 @@ + + +const uint8_t one_q6[] PROGMEM ={ +0x13, 0x60, 0x37, 0x00, 0x94, 0x5d, 0x30, 0x4e, 0x61, 0x24, 0x30, 0x01, 0x91, 0x5f, 0x33, 0x48, +0x4e, 0x38, 0x2b, 0x05, 0x90, 0x5a, 0x37, 0x49, 0x4c, 0x3a, 0x26, 0x07, 0x88, 0x47, 0x3e, 0x50, +0x44, 0x3d, 0x23, 0x0f, 0x87, 0x48, 0x3b, 0x52, 0x43, 0x40, 0x1c, 0x07, 0x98, 0xfe, 0x08, 0x77, +0x3a, 0x35, 0x16, 0x1e, 0x93, 0x72, 0x0c, 0x7d, 0x36, 0x34, 0x11, 0x8a, 0x95, 0xf9, 0x83, 0xf5, +0x20, 0x3e, 0x0e, 0xff, 0x8b, 0x71, 0x0c, 0x7e, 0x2b, 0x3b, 0x0d, 0xff, 0x8d, 0x7a, 0x0b, 0x77, +0x26, 0x43, 0x2d, 0xff, 0x91, 0xf3, 0x88, 0xf6, 0x10, 0x4c, 0x0d, 0xff, 0x95, 0xeb, 0x8e, 0xef, +0x84, 0x5c, 0x0e, 0xff, 0x90, 0xf5, 0x84, 0xfe, 0x07, 0x5b, 0x10, 0xff, 0x8c, 0xfb, 0x01, 0x75, +0x11, 0x5b, 0x13, 0x51, 0x93, 0xf0, 0x8b, 0xfd, 0x03, 0x67, 0x1f, 0x05, 0x92, 0x79, 0x05, 0x67, +0x30, 0x4a, 0x26, 0x02, 0x94, 0x7a, 0x0a, 0x59, 0x3f, 0x45, 0x0c, 0x02, 0x8e, 0x69, 0x2f, 0x3d, +0x42, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +//File: one.wav +//Time: 427 ms +//Size: 154 bytes +//Quality: 6 + +const uint8_t two_q6[] PROGMEM ={ +0x16, 0x60, 0x00, 0x02, 0x1a, 0x40, 0x3b, 0x35, 0x40, 0x3d, 0x0f, 0x08, 0x2a, 0x3a, 0x3b, 0x40, +0x2b, 0x48, 0x30, 0x06, 0x21, 0x4e, 0x2e, 0x3f, 0x27, 0x49, 0x11, 0x50, 0x86, 0x5a, 0x29, 0x4f, +0x40, 0x4a, 0x10, 0xfb, 0x8d, 0x75, 0x11, 0x6e, 0x16, 0x5f, 0x09, 0x2e, 0x8c, 0xf5, 0x84, 0xff, +0x09, 0x58, 0x24, 0x3d, 0x09, 0x6c, 0x03, 0x67, 0x30, 0x4f, 0x08, 0xb1, 0x08, 0x72, 0x00, 0x75, +0x1f, 0x5a, 0x0a, 0xff, 0x85, 0x74, 0x13, 0x79, 0x07, 0x5d, 0x0c, 0xff, 0x8f, 0xfa, 0x07, 0x6e, +0x28, 0x49, 0x0d, 0xa4, 0x92, 0xfc, 0x0a, 0x7c, 0x0c, 0x5b, 0x0e, 0x40, 0x90, 0x78, 0x06, 0xfe, +0x13, 0x58, 0x10, 0x23, 0x8e, 0x6c, 0x0f, 0x71, 0x2e, 0x49, 0x12, 0x12, 0x8a, 0x5d, 0x19, 0x6f, +0x28, 0x50, 0x17, 0x0e, 0x94, 0x61, 0x39, 0x5a, 0x26, 0x4d, 0x1c, 0x06, 0x98, 0x64, 0x41, 0x5d, +0x1e, 0x4c, 0x21, 0x02, 0x9a, 0x6d, 0x3c, 0x58, 0x28, 0x48, 0x27, 0x00, 0x9e, 0x78, 0x48, 0x60, +0x02, 0x5a, 0x2f, 0x00, 0x93, 0x52, 0x45, 0x48, 0x42, 0x3d, 0x36, 0x01, 0x8e, 0x52, 0x46, 0x37, +0x48, 0x41, 0x01, 0x00, 0x58, 0x22, 0x30, 0x3d, 0x31, 0x2c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, +}; + +//File: two.wav +//Time: 495 ms +//Size: 178 bytes +//Quality: 6 + +const uint8_t three_q6[] PROGMEM ={ +0x16, 0x60, 0x00, 0x00, 0x06, 0x52, 0x2f, 0x4b, 0x41, 0x2e, 0x00, 0x00, 0x8f, 0x6b, 0x1d, 0x5c, +0x25, 0x4e, 0x28, 0x03, 0x98, 0xf4, 0x02, 0x79, 0x0f, 0x5a, 0x23, 0x04, 0x9b, 0xed, 0x06, 0x63, +0x26, 0x4f, 0x1d, 0x0a, 0x9d, 0xe9, 0x15, 0x45, 0x39, 0x48, 0x16, 0x23, 0x9d, 0xe5, 0x00, 0x53, +0x33, 0x4f, 0x11, 0x69, 0x97, 0xec, 0x80, 0x5f, 0x21, 0x5e, 0x0e, 0xf1, 0x8d, 0xf6, 0x84, 0x6a, +0x21, 0x5e, 0x0b, 0xff, 0x83, 0xf8, 0x8e, 0x78, 0x21, 0x5e, 0x0a, 0xb8, 0x02, 0xfd, 0x8d, 0x75, +0x15, 0x69, 0x0a, 0xcf, 0x10, 0x6e, 0x01, 0x60, 0x21, 0x62, 0x0b, 0x9b, 0x15, 0x63, 0x82, 0x59, +0x30, 0x5d, 0x0d, 0x6b, 0x1a, 0x53, 0x12, 0x45, 0x3e, 0x5a, 0x0e, 0x47, 0x23, 0x48, 0x0c, 0x3c, +0x41, 0x60, 0x10, 0x2e, 0x2e, 0x2e, 0x1a, 0x35, 0x4f, 0x58, 0x11, 0x16, 0x2d, 0x31, 0x1c, 0x2d, +0x51, 0x5c, 0x16, 0x0e, 0x2f, 0x2c, 0x16, 0x34, 0x4d, 0x5d, 0x1f, 0x08, 0x15, 0x3a, 0x27, 0x39, +0x50, 0x4c, 0x2a, 0x02, 0x1f, 0x2c, 0x24, 0x36, 0x50, 0x55, 0x12, 0x01, 0x21, 0x28, 0x24, 0x35, +0x53, 0x52, 0x22, 0x02, 0x87, 0x66, 0x28, 0x4c, 0x3a, 0x3e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, +}; + +//File: three.wav +//Time: 495 ms +//Size: 178 bytes +//Quality: 6 + +const uint8_t merry_q6[] PROGMEM ={ +0x1c, 0x64, 0x12, 0x00, 0x42, 0x39, 0x42, 0x38, 0x37, 0x43, 0x19, 0x00, 0x2b, 0x33, 0x43, 0x3f, +0x3d, 0x35, 0x7e, 0x00, 0x2c, 0x3e, 0x37, 0x47, 0x40, 0x41, 0x00, 0x00, 0x27, 0x3a, 0x46, 0x3d, +0x47, 0x46, 0x07, 0x0c, 0x92, 0xf3, 0x0e, 0x6e, 0x20, 0x51, 0x07, 0x1d, 0x89, 0x7f, 0x19, 0x65, +0x27, 0x54, 0x22, 0x19, 0x80, 0x65, 0x27, 0x5a, 0x37, 0x4a, 0x18, 0x0b, 0x8e, 0x7c, 0x17, 0x69, +0x29, 0x4d, 0x2f, 0x03, 0x9a, 0xf0, 0x18, 0x69, 0x1a, 0x50, 0x02, 0x02, 0x9d, 0xe5, 0x01, 0x6e, +0x21, 0x4b, 0x01, 0x01, 0x8f, 0x6a, 0x33, 0x4c, 0x38, 0x43, 0x07, 0x02, 0x85, 0x6d, 0x27, 0x59, +0x27, 0x56, 0x07, 0x27, 0x81, 0x7c, 0x13, 0x6c, 0x1e, 0x5b, 0x23, 0x44, 0x83, 0x73, 0x20, 0x62, +0x27, 0x58, 0x23, 0x22, 0x8d, 0xfd, 0x0e, 0x67, 0x2d, 0x52, 0x18, 0x09, 0x9b, 0xe9, 0x0f, 0x4b, +0x4b, 0x3a, 0x17, 0x07, 0x96, 0xfa, 0x20, 0x5e, 0x2f, 0x47, 0x17, 0x00, 0x97, 0xfe, 0x1b, 0x66, +0x2d, 0x41, 0x03, 0x01, 0x95, 0xf9, 0x21, 0x51, 0x3d, 0x43, 0x07, 0x02, 0x94, 0xf6, 0x15, 0x5a, +0x36, 0x4a, 0x0c, 0x11, 0x95, 0xe7, 0x91, 0xf8, 0x16, 0x55, 0x3d, 0x37, 0x89, 0x7f, 0x10, 0x69, +0x23, 0x51, 0x3d, 0x43, 0x8b, 0x79, 0x14, 0x66, 0x25, 0x52, 0x3d, 0x41, 0x8b, 0x76, 0x18, 0x66, +0x1c, 0x57, 0x3d, 0x36, 0x87, 0x6d, 0x1b, 0x64, 0x23, 0x53, 0x3d, 0x33, 0x8e, 0x7c, 0x13, 0x68, +0x27, 0x4a, 0x3d, 0x34, 0x88, 0x76, 0x12, 0x6f, 0x1f, 0x50, 0x3d, 0x2d, 0x8b, 0xfe, 0x07, 0x77, +0x1b, 0x50, 0x3e, 0x37, 0x83, 0x70, 0x11, 0x71, 0x1f, 0x55, 0x3e, 0x2f, 0x82, 0x68, 0x1b, 0x62, +0x2d, 0x51, 0x3d, 0x4a, 0x85, 0x6b, 0x1b, 0x63, 0x31, 0x4c, 0x3d, 0x3c, 0x86, 0x6f, 0x19, 0x66, +0x2c, 0x4d, 0x3d, 0x21, 0x90, 0x7f, 0x10, 0x71, 0x20, 0x4c, 0x3e, 0x13, 0x90, 0xff, 0x0c, 0x74, +0x15, 0x56, 0x3e, 0x0a, 0x95, 0xef, 0x8a, 0x79, 0x1c, 0x50, 0x08, 0x08, 0x92, 0x71, 0x33, 0x46, +0x3d, 0x43, 0x08, 0x24, 0x94, 0xfe, 0x20, 0x57, 0x34, 0x47, 0x5a, 0x31, 0x91, 0xfc, 0x17, 0x68, +0x1d, 0x54, 0x10, 0x41, 0x8b, 0x65, 0x30, 0x61, 0x1b, 0x52, 0x07, 0x3b, 0x8e, 0x68, 0x31, 0x63, +0x1f, 0x4c, 0x59, 0x3f, 0x8f, 0x6f, 0x2d, 0x5f, 0x2a, 0x45, 0x59, 0x4f, 0x8e, 0x75, 0x29, 0x56, +0x34, 0x42, 0x59, 0x4d, 0x8a, 0x6e, 0x2b, 0x55, 0x34, 0x48, 0x59, 0x54, 0x86, 0x6a, 0x2b, 0x53, +0x37, 0x46, 0x59, 0x3e, 0x8a, 0x6e, 0x1c, 0x63, 0x31, 0x47, 0x07, 0x2b, 0x87, 0x6c, 0x18, 0x6b, +0x2a, 0x4a, 0x59, 0x37, 0x90, 0x77, 0x1f, 0x66, 0x23, 0x4d, 0x10, 0x38, 0x92, 0xfb, 0x1e, 0x5e, +0x27, 0x4d, 0x10, 0x21, 0x94, 0x7e, 0x25, 0x58, 0x2f, 0x45, 0x1a, 0x0f, 0x91, 0x78, 0x2e, 0x45, +0x3e, 0x44, 0x09, 0x0b, 0x91, 0x72, 0x2b, 0x54, 0x33, 0x49, 0x09, 0x17, 0x99, 0xf4, 0x25, 0x4f, +0x2f, 0x4b, 0x36, 0x1f, 0x97, 0xf2, 0x19, 0x58, 0x34, 0x47, 0x09, 0x35, 0x96, 0xf8, 0x1e, 0x55, +0x33, 0x47, 0x09, 0x34, 0x96, 0xf1, 0x0a, 0x64, 0x2d, 0x49, 0x36, 0x34, 0x94, 0xf8, 0x0d, 0x6f, +0x22, 0x4d, 0x09, 0x42, 0x94, 0xf4, 0x0f, 0x64, 0x2d, 0x48, 0x35, 0x39, 0x90, 0x78, 0x24, 0x59, +0x33, 0x46, 0x09, 0x3a, 0x8c, 0x6e, 0x29, 0x59, 0x2c, 0x4d, 0x35, 0x36, 0x91, 0xfe, 0x1b, 0x68, +0x21, 0x4f, 0x08, 0x35, 0x92, 0xfc, 0x17, 0x62, 0x29, 0x4a, 0x09, 0x2d, 0x94, 0xf8, 0x16, 0x58, +0x35, 0x47, 0x09, 0x18, 0x99, 0xe7, 0x84, 0x69, 0x31, 0x45, 0x10, 0x13, 0x9a, 0xe8, 0x83, 0x6a, +0x29, 0x48, 0x35, 0x0c, 0x96, 0xf5, 0x18, 0x58, 0x33, 0x45, 0x0e, 0x03, 0x92, 0xfe, 0x11, 0x61, +0x2a, 0x4b, 0x09, 0x03, 0x8e, 0x6f, 0x26, 0x53, 0x29, 0x53, 0x07, 0x1a, 0x98, 0xef, 0x03, 0x6f, +0x23, 0x49, 0x07, 0x54, 0x92, 0xf4, 0x0f, 0x5b, 0x32, 0x43, 0x07, 0x5f, 0x89, 0x7d, 0x16, 0x60, +0x2e, 0x47, 0x22, 0x5c, 0x88, 0x79, 0x1a, 0x56, 0x2f, 0x48, 0x22, 0x43, 0x8f, 0xf8, 0x10, 0x57, +0x31, 0x46, 0x07, 0x3c, 0x8c, 0x7f, 0x16, 0x5e, 0x26, 0x4d, 0x07, 0x30, 0x86, 0x6a, 0x24, 0x60, +0x28, 0x4a, 0x07, 0x2d, 0x8d, 0x7e, 0x12, 0x5e, 0x31, 0x49, 0x07, 0x1b, 0x97, 0xef, 0x03, 0x67, +0x28, 0x4e, 0x22, 0x13, 0x97, 0xf6, 0x1b, 0x46, 0x4c, 0x3b, 0x59, 0x0d, 0x97, 0x7f, 0x3a, 0x37, +0x46, 0x3e, 0x23, 0x07, 0x9c, 0xe8, 0x0a, 0x4b, 0x4b, 0x3a, 0x5a, 0x04, 0x95, 0x7f, 0x1e, 0x49, +0x47, 0x40, 0x67, 0x03, 0x9a, 0xf3, 0x14, 0x5d, 0x33, 0x45, 0x63, 0x02, 0x95, 0x7c, 0x1c, 0x65, +0x22, 0x50, 0x07, 0x02, 0x94, 0xfa, 0x15, 0x5c, 0x29, 0x4b, 0x08, 0x14, 0x94, 0xee, 0x87, 0x72, +0x1f, 0x51, 0x5b, 0x1b, 0x92, 0xf2, 0x84, 0x71, 0x1e, 0x53, 0x00, 0x17, 0x94, 0xf9, 0x16, 0x57, +0x30, 0x4b, 0x23, 0x19, 0x90, 0x71, 0x28, 0x58, 0x2e, 0x48, 0x5a, 0x0f, 0x9a, 0xe7, 0x85, 0x6e, +0x28, 0x49, 0x23, 0x0c, 0x9d, 0xe3, 0x91, 0x7f, 0x1d, 0x4b, 0x23, 0x05, 0x9f, 0xde, 0x96, 0x77, +0x29, 0x48, 0x3f, 0x05, 0x9e, 0xe1, 0x8f, 0x71, 0x2a, 0x46, 0x23, 0x0c, 0x89, 0x70, 0x08, 0xfc, +0x18, 0x50, 0x23, 0x02, 0x98, 0xef, 0x0d, 0x6b, 0x24, 0x4d, 0x23, 0x01, 0x97, 0xf8, 0x1e, 0x57, +0x36, 0x45, 0x22, 0x00, 0x97, 0xef, 0x0e, 0x5e, 0x34, 0x47, 0x17, 0x00, 0x8c, 0x71, 0x38, 0x3f, +0x39, 0x4b, 0x23, 0x00, 0x84, 0x6e, 0x31, 0x44, 0x3a, 0x49, 0x22, 0x00, 0x00, 0x64, 0x34, 0x45, +0x3c, 0x48, 0x08, 0x04, 0x08, 0xf7, 0x20, 0x5d, 0x3f, 0x43, 0x15, 0x30, 0x19, 0x73, 0x29, 0x55, +0x35, 0x4b, 0x07, 0x36, 0x03, 0x6d, 0x18, 0x61, 0x25, 0x59, 0x23, 0x2b, 0x8d, 0x7e, 0x17, 0x6b, +0x1d, 0x56, 0x3e, 0x12, 0x97, 0xf1, 0x14, 0x5b, 0x2d, 0x4c, 0x3d, 0x05, 0x99, 0xef, 0x0f, 0x58, +0x3c, 0x3f, 0x00, 0x01, 0x91, 0xff, 0x13, 0x50, 0x44, 0x40, 0x3d, 0x01, 0x85, 0x76, 0x15, 0x50, +0x3b, 0x3d, 0x07, 0x24, 0x05, 0x74, 0x29, 0x4c, 0x3c, 0x48, 0x4c, 0x59, 0x01, 0x75, 0x20, 0x56, +0x37, 0x48, 0x0c, 0x4f, 0x82, 0x72, 0x20, 0x5c, 0x29, 0x51, 0x22, 0x32, 0x80, 0x73, 0x17, 0x60, +0x26, 0x56, 0x0c, 0x1a, 0x87, 0x7a, 0x15, 0x56, 0x33, 0x50, 0x0c, 0x07, 0x94, 0xf2, 0x13, 0x49, +0x47, 0x41, 0x30, 0x02, 0x89, 0x75, 0x18, 0x50, 0x34, 0x49, 0x0c, 0x04, 0x91, 0x7d, 0x1a, 0x67, +0x1e, 0x50, 0x0c, 0x34, 0x85, 0x6f, 0x2d, 0x4e, 0x35, 0x4c, 0x14, 0x76, 0x09, 0x66, 0x17, 0x5f, +0x2c, 0x4b, 0x65, 0x60, 0x8c, 0xf9, 0x02, 0x6c, 0x23, 0x4e, 0x65, 0x71, 0x88, 0x72, 0x25, 0x47, +0x3c, 0x44, 0x64, 0x85, 0x03, 0x61, 0x34, 0x54, 0x23, 0x4d, 0x65, 0x7e, 0x87, 0x77, 0x13, 0x71, +0x13, 0x53, 0x65, 0x6c, 0x88, 0x73, 0x28, 0x57, 0x2b, 0x4c, 0x28, 0x66, 0x00, 0x5b, 0x32, 0x55, +0x33, 0x49, 0x0a, 0x55, 0x06, 0x54, 0x42, 0x4c, 0x26, 0x55, 0x29, 0x58, 0x0c, 0x57, 0x35, 0x56, +0x29, 0x4b, 0x65, 0x4d, 0x15, 0x46, 0x3b, 0x59, 0x31, 0x4d, 0x28, 0x49, 0x22, 0x4b, 0x2b, 0x53, +0x39, 0x51, 0x28, 0x44, 0x1d, 0x57, 0x2e, 0x52, 0x31, 0x48, 0x10, 0x31, 0x27, 0x5c, 0x39, 0x50, +0x30, 0x3f, 0x04, 0x16, 0x13, 0x73, 0x26, 0x4f, 0x37, 0x3e, 0x04, 0x09, 0x84, 0x70, 0x2c, 0x4c, +0x37, 0x49, 0x29, 0x1e, 0x86, 0x70, 0x24, 0x50, 0x34, 0x4f, 0x0b, 0x66, 0x00, 0x71, 0x1c, 0x60, +0x2b, 0x4e, 0x0b, 0x73, 0x06, 0x66, 0x2e, 0x4b, 0x36, 0x4d, 0x0b, 0x6a, 0x09, 0x63, 0x28, 0x4d, +0x36, 0x51, 0x2b, 0x4c, 0x10, 0x5d, 0x2e, 0x4d, 0x37, 0x4e, 0x23, 0x3a, 0x0c, 0x6f, 0x25, 0x53, +0x30, 0x53, 0x1a, 0x22, 0x18, 0x65, 0x36, 0x4b, 0x37, 0x57, 0x11, 0x0f, 0x11, 0x75, 0x20, 0x60, +0x2e, 0x4b, 0x0b, 0x3b, 0x1f, 0x66, 0x2a, 0x57, 0x29, 0x49, 0x29, 0x60, 0x09, 0x6a, 0x25, 0x5b, +0x20, 0x56, 0x47, 0x77, 0x06, 0x67, 0x1e, 0x60, 0x27, 0x54, 0x0a, 0x48, 0x04, 0x6a, 0x23, 0x59, +0x25, 0x59, 0x0a, 0x07, 0x8d, 0x71, 0x27, 0x50, 0x1e, 0x5c, 0x17, 0x06, 0x12, 0x56, 0x37, 0x55, +0x20, 0x4f, 0x22, 0x40, 0x1a, 0x6b, 0x2e, 0x53, 0x3a, 0x44, 0x22, 0x7f, 0x09, 0x68, 0x28, 0x5c, +0x27, 0x50, 0x22, 0xb5, 0x04, 0x69, 0x2a, 0x58, 0x2e, 0x4b, 0x59, 0xbc, 0x04, 0x5e, 0x36, 0x57, +0x2f, 0x4a, 0x11, 0x98, 0x84, 0x60, 0x34, 0x56, 0x32, 0x44, 0x59, 0x8b, 0x8a, 0x76, 0x22, 0x56, +0x36, 0x43, 0x59, 0x55, 0x93, 0xf7, 0x1a, 0x4f, 0x41, 0x3c, 0x59, 0x33, 0x93, 0xf9, 0x15, 0x67, +0x1d, 0x51, 0x58, 0x1c, 0x92, 0x7d, 0x18, 0x69, 0x16, 0x57, 0x59, 0x14, 0x93, 0xfd, 0x16, 0x72, +0x09, 0x5e, 0x59, 0x0d, 0x92, 0x76, 0x36, 0x43, 0x2a, 0x52, 0x23, 0x0b, 0x93, 0x7f, 0x29, 0x4a, +0x33, 0x48, 0x57, 0x07, 0x8e, 0x77, 0x18, 0x5f, 0x28, 0x50, 0x58, 0x07, 0x8a, 0x68, 0x23, 0x63, +0x28, 0x4b, 0x22, 0x06, 0x8f, 0x6d, 0x36, 0x4f, 0x33, 0x47, 0x23, 0x06, 0x83, 0x64, 0x2c, 0x5c, +0x2b, 0x49, 0x01, 0x09, 0x82, 0xf5, 0x11, 0x75, 0x17, 0x5f, 0x15, 0x4c, 0x84, 0xf9, 0x07, 0x70, +0x1e, 0x58, 0x24, 0x66, 0x09, 0x6a, 0x22, 0x5d, 0x21, 0x5b, 0x3d, 0x78, 0x0d, 0x6e, 0x21, 0x60, +0x22, 0x54, 0x3d, 0x81, 0x0c, 0x68, 0x21, 0x60, 0x26, 0x56, 0x3d, 0x7d, 0x05, 0x68, 0x29, 0x5c, +0x1a, 0x5f, 0x3d, 0x9d, 0x08, 0x61, 0x2e, 0x55, 0x27, 0x57, 0x3e, 0x8b, 0x09, 0x63, 0x2f, 0x5a, +0x25, 0x57, 0x3e, 0x75, 0x06, 0x67, 0x29, 0x5f, 0x1e, 0x5c, 0x3e, 0x83, 0x0c, 0x61, 0x2a, 0x5c, +0x28, 0x53, 0x3e, 0x6c, 0x07, 0x64, 0x27, 0x5f, 0x2b, 0x4f, 0x3d, 0x69, 0x04, 0x65, 0x29, 0x5d, +0x29, 0x4f, 0x3d, 0x5c, 0x02, 0x63, 0x2b, 0x5b, 0x27, 0x51, 0x3d, 0x4a, 0x83, 0x72, 0x18, 0x66, +0x1e, 0x55, 0x3d, 0x39, 0x82, 0x73, 0x15, 0x64, 0x1f, 0x53, 0x3d, 0x3c, 0x03, 0x69, 0x1f, 0x5b, +0x20, 0x55, 0x3e, 0x3b, 0x05, 0x64, 0x24, 0x5c, 0x27, 0x4d, 0x3e, 0x2c, 0x85, 0x7a, 0x0e, 0x69, +0x25, 0x4d, 0x3e, 0x32, 0x87, 0x79, 0x14, 0x66, 0x25, 0x53, 0x3e, 0x28, 0x8d, 0xf8, 0x08, 0x6f, +0x23, 0x52, 0x3e, 0x1e, 0x8f, 0xf3, 0x04, 0x73, 0x1c, 0x55, 0x3d, 0x14, 0x95, 0xe7, 0x8f, 0xfa, +0x11, 0x5b, 0x3e, 0x12, 0x91, 0xef, 0x83, 0x78, 0x1b, 0x56, 0x3e, 0x12, 0x90, 0xf5, 0x0a, 0x65, +0x25, 0x55, 0x3e, 0x11, 0x8f, 0xf2, 0x84, 0x78, 0x1e, 0x51, 0x3e, 0x0c, 0x91, 0xee, 0x88, 0x7a, +0x14, 0x58, 0x3e, 0x0f, 0x8f, 0xf1, 0x83, 0x7a, 0x17, 0x56, 0x3e, 0x0a, 0x91, 0xee, 0x87, 0xfe, +0x10, 0x5d, 0x3d, 0x07, 0x91, 0xf4, 0x0d, 0x65, 0x1c, 0x5c, 0x3d, 0x04, 0x8f, 0xf3, 0x08, 0x6c, +0x16, 0x61, 0x3d, 0x03, 0x86, 0x7f, 0x11, 0x68, 0x0f, 0x63, 0x3d, 0x02, 0x84, 0x76, 0x1b, 0x5b, +0x14, 0x60, 0x3d, 0x01, 0x8b, 0x78, 0x22, 0x55, 0x21, 0x56, 0x28, 0x01, 0x91, 0x75, 0x13, 0x6e, +0x0b, 0x5c, 0x2a, 0x01, 0x85, 0x5b, 0x21, 0x5a, 0x2e, 0x47, 0x2e, 0x03, 0x8e, 0x7c, 0x18, 0x52, +0x2b, 0x4c, 0x31, 0x0a, 0x89, 0xfc, 0x12, 0x54, 0x35, 0x3d, 0x30, 0x1a, 0x0f, 0x6b, 0x1a, 0x4c, +0x2a, 0x47, 0x22, 0x28, 0x20, 0x55, 0x23, 0x3b, 0x2d, 0x4d, 0x22, 0x2c, 0x1a, 0x55, 0x24, 0x3a, +0x3e, 0x40, 0x23, 0x26, 0x15, 0x54, 0x22, 0x40, 0x39, 0x45, 0x22, 0x22, 0x17, 0x4d, 0x21, 0x3e, +0x3f, 0x47, 0x22, 0x1f, 0x12, 0x49, 0x27, 0x46, 0x34, 0x4b, 0x22, 0x1a, 0x0c, 0x4b, 0x2f, 0x40, +0x37, 0x4a, 0x22, 0x1e, 0x05, 0x55, 0x22, 0x51, 0x30, 0x4a, 0x22, 0x12, 0x83, 0x5c, 0x24, 0x4f, +0x30, 0x4c, 0x20, 0x11, 0x83, 0x5f, 0x1a, 0x54, 0x2a, 0x55, 0x22, 0x10, 0x06, 0x47, 0x38, 0x3a, +0x31, 0x57, 0x22, 0x0b, 0x84, 0x57, 0x32, 0x37, 0x39, 0x54, 0x22, 0x07, 0x80, 0x57, 0x28, 0x3d, +0x38, 0x53, 0x24, 0x03, 0x8c, 0x57, 0x37, 0x47, 0x3d, 0x41, 0x22, 0x03, 0x8d, 0x4e, 0x4b, 0x44, +0x26, 0x52, 0x1d, 0x07, 0x85, 0x41, 0x4b, 0x36, 0x4c, 0x3f, 0x19, 0x31, 0x2c, 0x1b, 0x3a, 0x30, +0x4b, 0x57, 0x16, 0x71, 0x2f, 0x26, 0x35, 0x25, 0x54, 0x5c, 0x13, 0xd5, 0x28, 0x2c, 0x44, 0x24, +0x4f, 0x59, 0x13, 0xd1, 0x1a, 0x3b, 0x42, 0x22, 0x52, 0x52, 0x14, 0x71, 0x00, 0x62, 0x2d, 0x3a, +0x4b, 0x40, 0x50, 0x34, 0x81, 0x5c, 0x35, 0x42, 0x3c, 0x4b, 0x3d, 0x4c, 0x23, 0x28, 0x54, 0x40, +0x30, 0x56, 0x3e, 0x3f, 0x29, 0x22, 0x5a, 0x42, 0x36, 0x4d, 0x3e, 0x2c, 0x2d, 0x1d, 0x5c, 0x47, +0x35, 0x4c, 0x3d, 0x21, 0x2b, 0x1a, 0x5d, 0x42, 0x2b, 0x5b, 0x3d, 0x1b, 0x36, 0x17, 0x50, 0x4c, +0x34, 0x51, 0x80, 0x18, 0x4c, 0x16, 0x39, 0x4f, 0x45, 0x4c, 0x80, 0x12, 0x54, 0x0f, 0x35, 0x4d, +0x40, 0x4c, 0x80, 0x0f, 0x53, 0x1a, 0x34, 0x48, 0x42, 0x4d, 0x80, 0x0b, 0x69, 0x22, 0x10, 0x3c, +0x5b, 0x4f, 0x80, 0x09, 0x6e, 0x27, 0x08, 0x31, 0x58, 0x55, 0x18, 0x05, 0x48, 0x1b, 0x10, 0x34, +0x53, 0x55, 0x18, 0x07, 0x32, 0x32, 0x05, 0x36, 0x42, 0x67, 0x17, 0x0e, 0x37, 0x30, 0x06, 0x30, +0x46, 0x67, 0x16, 0x29, 0x27, 0x3a, 0x1e, 0x2a, 0x4a, 0x59, 0x14, 0x29, 0x0f, 0x4b, 0x2a, 0x38, +0x3c, 0x51, 0x14, 0x2f, 0x04, 0x54, 0x2c, 0x43, 0x29, 0x58, 0x14, 0x3a, 0x04, 0x55, 0x2f, 0x41, +0x2e, 0x53, 0x13, 0x3b, 0x07, 0x41, 0x42, 0x3c, 0x2f, 0x59, 0x12, 0x4d, 0x14, 0x24, 0x56, 0x3c, +0x34, 0x59, 0x12, 0xa1, 0x18, 0x26, 0x53, 0x40, 0x3a, 0x4e, 0x11, 0xd8, 0x12, 0x34, 0x57, 0x3f, +0x3a, 0x45, 0x10, 0xf3, 0x18, 0x33, 0x56, 0x46, 0x33, 0x46, 0x10, 0xdd, 0x16, 0x3e, 0x3f, 0x52, +0x3c, 0x3e, 0x10, 0x7f, 0x12, 0x3c, 0x42, 0x46, 0x42, 0x44, 0x11, 0x30, 0x1b, 0x3c, 0x2c, 0x3c, +0x41, 0x4b, 0x12, 0x31, 0x20, 0x2f, 0x2e, 0x39, 0x4a, 0x4b, 0x14, 0x16, 0x1d, 0x2a, 0x36, 0x30, +0x4b, 0x51, 0x15, 0x33, 0x23, 0x2d, 0x31, 0x39, 0x45, 0x4f, 0x15, 0xc5, 0x2b, 0x32, 0x3d, 0x36, +0x3c, 0x52, 0x15, 0xdb, 0x27, 0x34, 0x45, 0x30, 0x3e, 0x5b, 0x3d, 0xf0, 0x25, 0x3c, 0x39, 0x3a, +0x42, 0x57, 0x3d, 0xfc, 0x20, 0x3f, 0x39, 0x3e, 0x40, 0x57, 0x15, 0xaa, 0x17, 0x4a, 0x2e, 0x3f, +0x43, 0x52, 0x3e, 0x77, 0x8c, 0x7c, 0x19, 0x46, 0x43, 0x47, 0x16, 0x48, 0x83, 0x69, 0x21, 0x3f, +0x4d, 0x42, 0x17, 0x4d, 0x80, 0x61, 0x24, 0x4d, 0x3a, 0x4c, 0x17, 0x7c, 0x14, 0x4e, 0x26, 0x40, +0x47, 0x4d, 0x17, 0x7e, 0x2a, 0x3b, 0x32, 0x36, 0x40, 0x4f, 0x17, 0x6e, 0x2b, 0x38, 0x29, 0x38, +0x4f, 0x49, 0x17, 0x47, 0x14, 0x53, 0x26, 0x40, 0x5b, 0x30, 0x22, 0x11, 0x86, 0x64, 0x3d, 0x46, +0x37, 0x4b, 0x22, 0x09, 0x8c, 0x75, 0x2c, 0x4f, 0x35, 0x4a, 0x22, 0x06, 0x83, 0x62, 0x30, 0x4e, +0x41, 0x3e, 0x2d, 0x05, 0x11, 0x5d, 0x4d, 0x31, 0x3f, 0x3c, 0x0b, 0x05, 0x21, 0x50, 0x52, 0x3f, +0x3e, 0x3d, 0x0d, 0x0d, 0x1d, 0x5f, 0x35, 0x3e, 0x3d, 0x39, 0x1d, 0x1e, 0x80, 0x54, 0x3c, 0x3a, +0x39, 0x4a, 0x1d, 0x5b, 0x06, 0x51, 0x37, 0x36, 0x40, 0x4f, 0x1c, 0x64, 0x0a, 0x52, 0x34, 0x3f, +0x3e, 0x4b, 0x49, 0x6d, 0x08, 0x52, 0x36, 0x35, 0x4d, 0x43, 0x1c, 0x48, 0x0e, 0x4b, 0x36, 0x33, +0x54, 0x3d, 0x1c, 0x10, 0x0d, 0x47, 0x3f, 0x31, 0x4b, 0x41, 0x1c, 0x06, 0x10, 0x3f, 0x42, 0x3d, +0x45, 0x47, 0x29, 0x03, 0x05, 0x4e, 0x35, 0x42, 0x4d, 0x3a, 0x29, 0x04, 0x07, 0x59, 0x35, 0x40, +0x44, 0x3d, 0x04, 0x03, 0x14, 0x54, 0x3d, 0x47, 0x35, 0x3b, 0x1c, 0x01, 0x21, 0x4c, 0x35, 0x47, +0x3d, 0x46, 0x2f, 0x02, 0x28, 0x41, 0x40, 0x3e, 0x3e, 0x31, 0x2e, 0x01, 0x2c, 0x38, 0x4b, 0x45, +0x36, 0x3b, 0x06, 0x01, 0x31, 0x2a, 0x48, 0x3c, 0x3b, 0x46, 0x15, 0x01, 0x3c, 0x17, 0x38, 0x4f, +0x2b, 0x4a, 0x1e, 0x01, 0x81, 0x3b, 0x39, 0x47, 0x4d, 0x3c, 0x1e, 0x04, 0x87, 0x55, 0x20, 0x54, +0x46, 0x3b, 0x1c, 0x17, 0x8b, 0x58, 0x41, 0x50, 0x1b, 0x57, 0x1c, 0x38, 0x05, 0x46, 0x49, 0x40, +0x36, 0x51, 0x1c, 0x40, 0x81, 0x51, 0x52, 0x33, 0x3f, 0x4a, 0x1c, 0x57, 0x81, 0x50, 0x4f, 0x33, +0x3c, 0x49, 0x1d, 0x27, 0x84, 0x4e, 0x49, 0x3b, 0x3a, 0x4b, 0x29, 0x0b, 0x8f, 0x6f, 0x1d, 0x5d, +0x37, 0x41, 0x2a, 0x07, 0x8d, 0x61, 0x33, 0x4b, 0x3e, 0x43, 0x0b, 0x05, 0x87, 0x55, 0x46, 0x45, +0x37, 0x49, 0x29, 0x04, 0x89, 0x57, 0x4e, 0x3d, 0x33, 0x4c, 0x29, 0x04, 0x08, 0x41, 0x4b, 0x4b, +0x32, 0x47, 0x29, 0x02, 0x12, 0x32, 0x58, 0x4d, 0x22, 0x51, 0x1d, 0x01, 0x2e, 0x1c, 0x52, 0x4f, +0x3c, 0x45, 0x04, 0x01, 0x33, 0x1e, 0x55, 0x53, 0x2a, 0x49, 0x1d, 0x00, 0x00, 0x3a, 0x54, 0x41, +0x22, 0x55, 0x22, 0x00, 0x8a, 0x47, 0x45, 0x44, 0x3d, 0x44, 0x23, 0x01, 0x85, 0x36, 0x52, 0x46, +0x33, 0x4a, 0x22, 0x01, 0x8a, 0x4c, 0x50, 0x39, 0x30, 0x4d, 0x1e, 0x0e, 0x15, 0x35, 0x45, 0x3f, +0x30, 0x4c, 0x1d, 0x27, 0x1f, 0x4c, 0x23, 0x39, 0x48, 0x3f, 0x1d, 0x1e, 0x11, 0x60, 0x12, 0x4a, +0x3c, 0x46, 0x1d, 0x1e, 0x15, 0x59, 0x0f, 0x4c, 0x3b, 0x48, 0x1d, 0x1f, 0x1c, 0x4e, 0x1b, 0x41, +0x45, 0x43, 0x1d, 0x1e, 0x1e, 0x46, 0x23, 0x36, 0x4c, 0x46, 0x1d, 0x1c, 0x17, 0x46, 0x28, 0x35, +0x55, 0x3d, 0x1c, 0x1d, 0x14, 0x51, 0x21, 0x37, 0x55, 0x3c, 0x1c, 0x18, 0x1c, 0x43, 0x28, 0x34, +0x57, 0x3d, 0x1c, 0x15, 0x19, 0x41, 0x32, 0x28, 0x54, 0x46, 0x1c, 0x0d, 0x17, 0x2e, 0x47, 0x25, +0x45, 0x56, 0x1c, 0x07, 0x02, 0x36, 0x5c, 0x25, 0x40, 0x50, 0x1d, 0x03, 0x82, 0x3e, 0x44, 0x3c, +0x4a, 0x41, 0x1d, 0x02, 0x86, 0x48, 0x3b, 0x3c, 0x54, 0x3a, 0x1d, 0x02, 0x90, 0x5c, 0x30, 0x53, +0x41, 0x3a, 0x1b, 0x06, 0x85, 0x43, 0x44, 0x44, 0x49, 0x38, 0x18, 0x37, 0x18, 0x35, 0x3a, 0x32, +0x52, 0x47, 0x3d, 0x8b, 0x24, 0x38, 0x32, 0x33, 0x51, 0x4b, 0x11, 0xbe, 0x20, 0x3f, 0x2e, 0x39, +0x55, 0x48, 0x33, 0xd8, 0x24, 0x3a, 0x3a, 0x33, 0x4f, 0x4f, 0x34, 0x8c, 0x20, 0x3b, 0x2d, 0x42, +0x5b, 0x3d, 0x11, 0x48, 0x16, 0x4a, 0x30, 0x39, 0x4b, 0x48, 0x1d, 0x33, 0x1f, 0x31, 0x3c, 0x41, +0x47, 0x46, 0x1d, 0x30, 0x3b, 0x1d, 0x40, 0x58, 0x44, 0x41, 0x35, 0x24, 0x41, 0x23, 0x41, 0x50, +0x49, 0x45, 0x80, 0x1f, 0x40, 0x26, 0x4f, 0x4b, 0x3e, 0x4d, 0x80, 0x13, 0x47, 0x15, 0x4a, 0x59, +0x44, 0x40, 0x80, 0x0f, 0x4f, 0x16, 0x33, 0x5c, 0x51, 0x41, 0x80, 0x09, 0x5a, 0x22, 0x21, 0x49, +0x54, 0x4a, 0x80, 0x0b, 0x74, 0x33, 0x24, 0x3c, 0x42, 0x49, 0x80, 0x05, 0x72, 0x3b, 0x23, 0x3d, +0x51, 0x55, 0x14, 0x07, 0x55, 0x15, 0x13, 0x2f, 0x48, 0x5b, 0x15, 0x0b, 0x3d, 0x28, 0x0c, 0x33, +0x4d, 0x5a, 0x13, 0x2e, 0x2a, 0x40, 0x16, 0x36, 0x3b, 0x5e, 0x11, 0x47, 0x16, 0x54, 0x11, 0x45, +0x3c, 0x50, 0x11, 0x3c, 0x19, 0x48, 0x18, 0x45, 0x40, 0x4e, 0x35, 0x2f, 0x14, 0x42, 0x26, 0x47, +0x3a, 0x4e, 0x35, 0x1c, 0x08, 0x45, 0x27, 0x4c, 0x44, 0x42, 0x11, 0x1b, 0x02, 0x51, 0x1d, 0x50, +0x49, 0x3e, 0x10, 0x42, 0x11, 0x39, 0x34, 0x44, 0x49, 0x42, 0x10, 0x69, 0x1c, 0x31, 0x31, 0x45, +0x54, 0x47, 0x0e, 0x89, 0x13, 0x38, 0x45, 0x43, 0x3c, 0x51, 0x0d, 0xc1, 0x15, 0x49, 0x38, 0x46, +0x44, 0x42, 0x0c, 0x96, 0x19, 0x49, 0x2c, 0x4b, 0x40, 0x52, 0x2d, 0xb3, 0x1f, 0x3f, 0x37, 0x49, +0x40, 0x4a, 0x0d, 0xa3, 0x1d, 0x3a, 0x3f, 0x48, 0x3b, 0x49, 0x0f, 0x18, 0x09, 0x48, 0x2e, 0x43, +0x4a, 0x3f, 0x35, 0x0e, 0x2a, 0x22, 0x27, 0x3c, 0x45, 0x58, 0x11, 0x16, 0x25, 0x2f, 0x20, 0x3b, +0x46, 0x58, 0x10, 0x7e, 0x36, 0x1f, 0x27, 0x43, 0x51, 0x51, 0x10, 0xff, 0x27, 0x32, 0x30, 0x4b, +0x49, 0x41, 0x35, 0xff, 0x2b, 0x38, 0x38, 0x47, 0x42, 0x41, 0x35, 0xe5, 0x26, 0x33, 0x3e, 0x47, +0x41, 0x48, 0x35, 0xd2, 0x1b, 0x48, 0x30, 0x4a, 0x44, 0x4b, 0x11, 0x9e, 0x14, 0x55, 0x2a, 0x4b, +0x38, 0x51, 0x12, 0x65, 0x81, 0x69, 0x1f, 0x49, 0x3f, 0x4c, 0x14, 0x34, 0x83, 0x5c, 0x33, 0x42, +0x3c, 0x4c, 0x14, 0x4d, 0x15, 0x51, 0x1d, 0x49, 0x3c, 0x55, 0x14, 0x82, 0x1e, 0x4b, 0x25, 0x46, +0x3d, 0x4e, 0x15, 0x7f, 0x26, 0x42, 0x31, 0x42, 0x44, 0x40, 0x15, 0x63, 0x2c, 0x3b, 0x34, 0x34, +0x4f, 0x3d, 0x1a, 0x2f, 0x1e, 0x4c, 0x2c, 0x38, 0x56, 0x31, 0x34, 0x08, 0x07, 0x59, 0x3a, 0x4a, +0x30, 0x4e, 0x16, 0x05, 0x1c, 0x48, 0x45, 0x3c, 0x37, 0x4c, 0x02, 0x06, 0x17, 0x44, 0x48, 0x49, +0x3b, 0x49, 0x17, 0x10, 0x02, 0x62, 0x40, 0x49, 0x33, 0x4f, 0x17, 0x25, 0x0e, 0x61, 0x38, 0x44, +0x37, 0x44, 0x17, 0x51, 0x81, 0x5d, 0x36, 0x46, 0x2a, 0x50, 0x17, 0x7a, 0x09, 0x4e, 0x3e, 0x47, +0x2c, 0x53, 0x16, 0xab, 0x0b, 0x5c, 0x28, 0x44, 0x3d, 0x48, 0x16, 0x96, 0x03, 0x5b, 0x29, 0x43, +0x47, 0x43, 0x17, 0x32, 0x85, 0x64, 0x26, 0x49, 0x44, 0x42, 0x23, 0x11, 0x8b, 0x78, 0x1a, 0x47, +0x47, 0x37, 0x22, 0x07, 0x83, 0x6b, 0x2d, 0x47, 0x2a, 0x4b, 0x17, 0x05, 0x82, 0x64, 0x40, 0x3a, +0x3e, 0x4a, 0x02, 0x05, 0x0e, 0x44, 0x53, 0x38, 0x35, 0x4b, 0x02, 0x04, 0x15, 0x2e, 0x61, 0x3e, +0x34, 0x4f, 0x17, 0x03, 0x18, 0x36, 0x61, 0x43, 0x37, 0x56, 0x0c, 0x02, 0x29, 0x36, 0x56, 0x44, +0x3a, 0x53, 0x02, 0x01, 0x32, 0x31, 0x4f, 0x45, 0x45, 0x4e, 0x17, 0x00, 0x14, 0x3c, 0x43, 0x47, +0x32, 0x45, 0x23, 0x02, 0x92, 0x63, 0x34, 0x4a, 0x43, 0x39, 0x59, 0x0a, 0x97, 0xf5, 0x1b, 0x47, +0x49, 0x39, 0x22, 0x15, 0x97, 0xf1, 0x11, 0x5a, 0x35, 0x43, 0x23, 0x26, 0x94, 0x7e, 0x32, 0x3b, +0x44, 0x42, 0x23, 0x33, 0x8c, 0x6b, 0x3b, 0x41, 0x32, 0x51, 0x59, 0x2a, 0x89, 0x69, 0x3f, 0x31, +0x46, 0x4c, 0x23, 0x19, 0x89, 0x6b, 0x41, 0x27, 0x55, 0x44, 0x59, 0x0c, 0x92, 0xf2, 0x10, 0x55, +0x3c, 0x48, 0x2d, 0x09, 0x8b, 0x6a, 0x3f, 0x2d, 0x53, 0x3e, 0x58, 0x05, 0x04, 0x4b, 0x5f, 0x30, +0x43, 0x4c, 0x17, 0x05, 0x11, 0x30, 0x5b, 0x48, 0x3a, 0x41, 0x22, 0x04, 0x30, 0x32, 0x50, 0x47, +0x34, 0x4e, 0x0c, 0x04, 0x3f, 0x27, 0x53, 0x40, 0x32, 0x52, 0x02, 0x02, 0x3e, 0x23, 0x44, 0x5a, +0x3a, 0x4b, 0x22, 0x01, 0x16, 0x27, 0x54, 0x4a, 0x26, 0x48, 0x29, 0x00, 0x85, 0x42, 0x47, 0x45, +0x33, 0x4a, 0x2a, 0x00, 0x83, 0x3d, 0x4b, 0x46, 0x33, 0x49, 0x29, 0x00, 0x90, 0x5a, 0x4c, 0x38, +0x32, 0x4b, 0x26, 0x02, 0x87, 0x50, 0x43, 0x44, 0x2f, 0x49, 0x23, 0x0c, 0x15, 0x3e, 0x38, 0x37, +0x3e, 0x4a, 0x22, 0x14, 0x12, 0x5a, 0x1e, 0x3c, 0x4a, 0x3a, 0x22, 0x12, 0x0c, 0x62, 0x0c, 0x52, +0x3d, 0x40, 0x21, 0x0f, 0x11, 0x59, 0x0e, 0x52, 0x3b, 0x47, 0x22, 0x0f, 0x0f, 0x5b, 0x10, 0x52, +0x3e, 0x41, 0x22, 0x10, 0x14, 0x52, 0x0f, 0x4d, 0x45, 0x43, 0x59, 0x0d, 0x18, 0x4b, 0x0e, 0x47, +0x4e, 0x45, 0x23, 0x0b, 0x1d, 0x42, 0x14, 0x3f, 0x56, 0x43, 0x22, 0x0b, 0x1a, 0x3d, 0x22, 0x37, +0x56, 0x44, 0x22, 0x08, 0x0d, 0x39, 0x41, 0x30, 0x44, 0x4e, 0x21, 0x02, 0x0b, 0x29, 0x4e, 0x34, +0x41, 0x4e, 0x22, 0x01, 0x8b, 0x4f, 0x39, 0x41, 0x4b, 0x3c, 0x23, 0x00, 0x8d, 0x52, 0x33, 0x49, +0x43, 0x42, 0x23, 0x01, 0x92, 0x64, 0x23, 0x5d, 0x3b, 0x3d, 0x22, 0x01, 0x91, 0x53, 0x48, 0x44, +0x3f, 0x3d, 0x1b, 0x07, 0x93, 0x70, 0x2b, 0x55, 0x2a, 0x46, 0x13, 0x58, 0x09, 0x40, 0x4b, 0x35, +0x3c, 0x4d, 0x0d, 0x96, 0x11, 0x38, 0x53, 0x32, 0x41, 0x4c, 0x2d, 0xb8, 0x1a, 0x34, 0x44, 0x3e, +0x4a, 0x42, 0x2d, 0xc9, 0x1e, 0x41, 0x2e, 0x3f, 0x55, 0x3b, 0x0e, 0x8b, 0x18, 0x4c, 0x29, 0x3a, +0x46, 0x47, 0x13, 0x4d, 0x19, 0x46, 0x3f, 0x3f, 0x3b, 0x3e, 0x2c, 0x41, 0x33, 0x2a, 0x50, 0x42, +0x36, 0x46, 0x18, 0x3e, 0x3d, 0x22, 0x5a, 0x51, 0x39, 0x46, 0x80, 0x23, 0x41, 0x15, 0x4f, 0x58, +0x35, 0x41, 0x80, 0x1c, 0x53, 0x24, 0x49, 0x50, 0x2e, 0x3c, 0x80, 0x0f, 0x53, 0x24, 0x44, 0x4f, +0x32, 0x3a, 0x80, 0x0d, 0x6a, 0x37, 0x39, 0x4d, 0x3e, 0x3a, 0x80, 0x0c, 0x6f, 0x38, 0x32, 0x46, +0x40, 0x40, 0x80, 0x0c, 0xfe, 0x47, 0x2f, 0x49, 0x4b, 0x46, 0x80, 0x07, 0xff, 0x47, 0x31, 0x3e, +0x4c, 0x4e, 0x80, 0x0b, 0x67, 0x29, 0x10, 0x28, 0x40, 0x53, 0x10, 0x09, 0x3a, 0x25, 0x10, 0x2e, +0x42, 0x6d, 0x0f, 0x10, 0x31, 0x36, 0x02, 0x38, 0x40, 0x6c, 0x0e, 0x15, 0x31, 0x35, 0x04, 0x37, +0x46, 0x66, 0x0d, 0x12, 0x29, 0x32, 0x0a, 0x40, 0x4b, 0x5c, 0x2d, 0x16, 0x0c, 0x3a, 0x39, 0x4b, +0x1e, 0x62, 0x0c, 0x17, 0x0b, 0x2e, 0x4e, 0x47, 0x22, 0x5a, 0x0c, 0x1a, 0x86, 0x3d, 0x64, 0x44, +0x0e, 0x5e, 0x0c, 0x18, 0x82, 0x3a, 0x51, 0x57, 0x19, 0x53, 0x0b, 0x46, 0x85, 0x49, 0x53, 0x48, +0x20, 0x58, 0x0b, 0xe0, 0x02, 0x3f, 0x60, 0x38, 0x32, 0x52, 0x29, 0xc3, 0x0a, 0x4a, 0x2f, 0x5c, +0x45, 0x39, 0x0a, 0xec, 0x13, 0x41, 0x32, 0x61, 0x41, 0x37, 0x0a, 0xf9, 0x18, 0x43, 0x2d, 0x65, +0x3f, 0x38, 0x0a, 0xeb, 0x1e, 0x32, 0x3d, 0x58, 0x41, 0x3f, 0x0b, 0x53, 0x11, 0x31, 0x4e, 0x49, +0x37, 0x4c, 0x2c, 0x15, 0x11, 0x3f, 0x22, 0x44, 0x5b, 0x3a, 0x0d, 0x32, 0x06, 0x55, 0x2c, 0x45, +0x46, 0x3b, 0x06, 0x51, 0x11, 0x42, 0x37, 0x48, 0x3d, 0x43, 0x2c, 0xff, 0x22, 0x2f, 0x4c, 0x45, +0x33, 0x56, 0x0c, 0xff, 0x23, 0x34, 0x2e, 0x55, 0x47, 0x4a, 0x2d, 0xff, 0x2c, 0x33, 0x30, 0x49, +0x46, 0x54, 0x2d, 0xff, 0x25, 0x3b, 0x31, 0x49, 0x40, 0x54, 0x2e, 0xfa, 0x0f, 0x53, 0x37, 0x47, +0x36, 0x55, 0x2f, 0x98, 0x04, 0x60, 0x2f, 0x45, 0x3f, 0x4f, 0x0e, 0x72, 0x86, 0x67, 0x30, 0x4a, +0x2e, 0x55, 0x0f, 0x52, 0x0b, 0x53, 0x25, 0x52, 0x30, 0x5b, 0x0f, 0x52, 0x1d, 0x48, 0x1c, 0x48, +0x42, 0x57, 0x10, 0x57, 0x29, 0x3d, 0x22, 0x3d, 0x43, 0x5a, 0x10, 0x3b, 0x31, 0x2f, 0x24, 0x39, +0x54, 0x4b, 0x12, 0x21, 0x2a, 0x38, 0x22, 0x33, 0x5b, 0x3e, 0x1d, 0x05, 0x24, 0x3f, 0x28, 0x40, +0x47, 0x41, 0x1d, 0x02, 0x33, 0x3c, 0x32, 0x3f, 0x49, 0x53, 0x1c, 0x09, 0x81, 0x5a, 0x42, 0x46, +0x34, 0x4e, 0x4d, 0x22, 0x8f, 0xf5, 0x0c, 0x65, 0x27, 0x4f, 0x1c, 0x2b, 0x90, 0xf5, 0x08, 0x71, +0x1a, 0x56, 0x1c, 0x39, 0x8e, 0x7e, 0x16, 0x65, 0x21, 0x50, 0x3b, 0x6d, 0x01, 0x56, 0x39, 0x4c, +0x25, 0x58, 0x3b, 0xc8, 0x0c, 0x4d, 0x36, 0x42, 0x3a, 0x50, 0x13, 0xf7, 0x13, 0x44, 0x3e, 0x3d, +0x3c, 0x52, 0x3c, 0x99, 0x07, 0x56, 0x32, 0x40, 0x3f, 0x4c, 0x1c, 0x45, 0x83, 0x5e, 0x39, 0x4a, +0x2b, 0x50, 0x1c, 0x22, 0x87, 0x6d, 0x34, 0x4e, 0x28, 0x54, 0x0b, 0x19, 0x85, 0x70, 0x35, 0x4f, +0x2b, 0x5a, 0x5c, 0x19, 0x82, 0x6d, 0x34, 0x51, 0x29, 0x59, 0x5c, 0x15, 0x82, 0x6d, 0x32, 0x51, +0x2a, 0x59, 0x0b, 0x13, 0x86, 0x72, 0x32, 0x4c, 0x33, 0x51, 0x3d, 0x11, 0x06, 0x4e, 0x65, 0x26, +0x43, 0x4f, 0x10, 0x05, 0x89, 0x75, 0x32, 0x50, 0x24, 0x5c, 0x16, 0x03, 0x93, 0x78, 0x31, 0x42, +0x35, 0x4a, 0x54, 0x09, 0x91, 0xff, 0x16, 0x57, 0x30, 0x44, 0x1d, 0x1b, 0x89, 0x61, 0x38, 0x46, +0x34, 0x49, 0x4e, 0x2a, 0x01, 0x3d, 0x52, 0x49, 0x27, 0x53, 0x1c, 0x3d, 0x85, 0x4d, 0x52, 0x3c, +0x2c, 0x57, 0x1c, 0x33, 0x00, 0x4b, 0x4c, 0x39, 0x32, 0x57, 0x1c, 0x2a, 0x09, 0x43, 0x4f, 0x33, +0x37, 0x51, 0x1e, 0x0e, 0x01, 0x44, 0x4b, 0x2f, 0x44, 0x47, 0x2c, 0x04, 0x83, 0x4a, 0x4c, 0x2a, +0x49, 0x46, 0x0d, 0x02, 0x12, 0x3c, 0x43, 0x3f, 0x31, 0x4e, 0x4d, 0x01, 0x16, 0x35, 0x56, 0x3f, +0x31, 0x48, 0x29, 0x01, 0x21, 0x30, 0x53, 0x45, 0x30, 0x4c, 0x1d, 0x01, 0x2f, 0x35, 0x48, 0x47, +0x39, 0x48, 0x1e, 0x01, 0x35, 0x31, 0x49, 0x46, 0x37, 0x4b, 0x00, 0x00, 0x3f, 0x37, 0x52, 0x4b, +0x38, 0x43, 0x16, 0x00, 0x0a, 0x3f, 0x42, 0x38, 0x40, 0x42, 0x1f, 0x04, 0x94, 0x77, 0x1d, 0x50, +0x43, 0x40, 0x24, 0x05, 0x8f, 0x66, 0x36, 0x41, 0x3f, 0x45, 0x24, 0x0c, 0x8e, 0x70, 0x2d, 0x46, +0x3a, 0x4e, 0x15, 0x12, 0x8d, 0x77, 0x26, 0x4b, 0x31, 0x54, 0x23, 0x1e, 0x8e, 0x78, 0x18, 0x62, +0x20, 0x54, 0x20, 0x0c, 0x92, 0xfd, 0x14, 0x5b, 0x20, 0x55, 0x23, 0x04, 0x91, 0x7f, 0x01, 0x69, +0x28, 0x4f, 0x23, 0x03, 0x82, 0x58, 0x1b, 0x50, 0x43, 0x43, 0x22, 0x18, 0x03, 0x5b, 0x30, 0x43, +0x2f, 0x55, 0x23, 0x2b, 0x0a, 0x62, 0x24, 0x4d, 0x2f, 0x4e, 0x23, 0x39, 0x03, 0x6b, 0x18, 0x5d, +0x28, 0x4f, 0x23, 0x43, 0x06, 0x63, 0x22, 0x54, 0x35, 0x4b, 0x29, 0x2a, 0x84, 0x6c, 0x23, 0x55, +0x2a, 0x50, 0x29, 0x12, 0x8c, 0x7d, 0x18, 0x57, 0x2f, 0x4b, 0x2a, 0x09, 0x85, 0x67, 0x2d, 0x40, +0x3c, 0x44, 0x2c, 0x05, 0x02, 0x65, 0x18, 0x4f, 0x31, 0x47, 0x26, 0x0a, 0x80, 0x5b, 0x30, 0x3b, +0x3e, 0x45, 0x29, 0x1e, 0x03, 0x56, 0x3e, 0x3c, 0x44, 0x3e, 0x20, 0x3f, 0x01, 0x65, 0x26, 0x55, +0x26, 0x54, 0x51, 0x59, 0x80, 0x6e, 0x22, 0x5d, 0x30, 0x52, 0x29, 0x48, 0x83, 0x6a, 0x21, 0x58, +0x2b, 0x55, 0x1e, 0x61, 0x85, 0x7a, 0x1b, 0x67, 0x1c, 0x5c, 0x1d, 0x56, 0x86, 0x78, 0x25, 0x57, +0x27, 0x5a, 0x1d, 0x5a, 0x87, 0x7e, 0x1e, 0x58, 0x31, 0x53, 0x1c, 0x6f, 0x03, 0x69, 0x32, 0x48, +0x36, 0x50, 0x1c, 0x83, 0x0b, 0x56, 0x3f, 0x43, 0x3e, 0x50, 0x1c, 0x49, 0x0d, 0x47, 0x55, 0x31, +0x3f, 0x54, 0x29, 0x26, 0x82, 0x5e, 0x34, 0x4f, 0x2f, 0x4f, 0x29, 0x23, 0x86, 0x74, 0x15, 0x6b, +0x1e, 0x55, 0x29, 0x26, 0x84, 0x72, 0x1a, 0x63, 0x22, 0x58, 0x29, 0x25, 0x85, 0x72, 0x22, 0x51, +0x2c, 0x53, 0x29, 0x1d, 0x06, 0x69, 0x22, 0x5d, 0x23, 0x55, 0x28, 0x08, 0x82, 0x66, 0x30, 0x51, +0x23, 0x57, 0x16, 0x0b, 0x05, 0x64, 0x23, 0x57, 0x2a, 0x4e, 0x1a, 0x46, 0x08, 0x68, 0x14, 0x59, +0x2e, 0x49, 0x11, 0x78, 0x0b, 0x59, 0x22, 0x56, 0x37, 0x43, 0x10, 0x60, 0x05, 0x66, 0x15, 0x69, +0x26, 0x4a, 0x0f, 0x8f, 0x0d, 0x65, 0x0e, 0x68, 0x28, 0x4a, 0x11, 0x65, 0x05, 0x61, 0x0b, 0x65, +0x34, 0x42, 0x10, 0x62, 0x0f, 0x54, 0x0d, 0x60, 0x39, 0x45, 0x0f, 0x4b, 0x10, 0x55, 0x0d, 0x68, +0x31, 0x44, 0x0f, 0x44, 0x0b, 0x5c, 0x0d, 0x6a, 0x33, 0x41, 0x0f, 0x54, 0x0a, 0x58, 0x15, 0x68, +0x34, 0x3f, 0x10, 0x3e, 0x0f, 0x58, 0x11, 0x65, 0x33, 0x3d, 0x10, 0x2e, 0x09, 0x5d, 0x0b, 0x6a, +0x33, 0x3c, 0x10, 0x23, 0x09, 0x55, 0x0a, 0x6c, 0x37, 0x3e, 0x10, 0x12, 0x85, 0x6a, 0x82, 0x78, +0x22, 0x4f, 0x10, 0x0a, 0x94, 0xf5, 0x8f, 0xfa, 0x11, 0x55, 0x11, 0x09, 0x86, 0x5a, 0x10, 0x6d, +0x37, 0x3f, 0x12, 0x09, 0x8a, 0x5c, 0x18, 0x65, 0x34, 0x45, 0x17, 0x12, 0x39, 0x22, 0x0e, 0x42, +0x49, 0x5a, 0x43, 0x48, 0x18, 0x47, 0x2e, 0x45, 0x3b, 0x4b, 0x23, 0x4e, 0x00, 0x5c, 0x32, 0x46, +0x3d, 0x48, 0x18, 0x4f, 0x83, 0x63, 0x34, 0x3e, 0x40, 0x44, 0x16, 0x31, 0x85, 0x62, 0x34, 0x3d, +0x3a, 0x4b, 0x17, 0x23, 0x86, 0x56, 0x46, 0x37, 0x33, 0x4f, 0x18, 0x1c, 0x8f, 0x6e, 0x2a, 0x49, +0x3f, 0x3e, 0x19, 0x13, 0x8f, 0x61, 0x3f, 0x44, 0x42, 0x35, 0x19, 0x12, 0x8e, 0x56, 0x54, 0x36, +0x40, 0x3c, 0x19, 0x10, 0x88, 0x47, 0x56, 0x41, 0x33, 0x41, 0x18, 0x0e, 0x89, 0x4f, 0x49, 0x3f, +0x3e, 0x3e, 0x17, 0x14, 0x04, 0x43, 0x3a, 0x46, 0x46, 0x3a, 0x16, 0x1f, 0x07, 0x54, 0x21, 0x45, +0x51, 0x39, 0x19, 0x1d, 0x10, 0x4e, 0x16, 0x4d, 0x56, 0x33, 0x45, 0x18, 0x17, 0x49, 0x12, 0x4b, +0x53, 0x3c, 0x46, 0x11, 0x19, 0x40, 0x12, 0x4d, 0x51, 0x41, 0x18, 0x08, 0x24, 0x3b, 0x04, 0x44, +0x4e, 0x53, 0x17, 0x0e, 0x2d, 0x38, 0x04, 0x3a, 0x52, 0x55, 0x3d, 0x39, 0x14, 0x57, 0x0e, 0x4f, +0x46, 0x45, 0x3f, 0x42, 0x0d, 0x65, 0x09, 0x5a, 0x41, 0x42, 0x3e, 0x65, 0x03, 0x71, 0x09, 0x5b, +0x3e, 0x42, 0x3d, 0x6f, 0x06, 0x6b, 0x11, 0x55, 0x40, 0x41, 0x3e, 0x86, 0x0e, 0x63, 0x1b, 0x47, +0x4a, 0x3e, 0x3e, 0x72, 0x06, 0x64, 0x23, 0x49, 0x45, 0x42, 0x16, 0x7b, 0x12, 0x56, 0x2e, 0x40, +0x45, 0x46, 0x3d, 0x6e, 0x0e, 0x59, 0x28, 0x41, 0x44, 0x45, 0x3f, 0x63, 0x16, 0x50, 0x28, 0x3e, +0x45, 0x4c, 0x3d, 0x7f, 0x25, 0x47, 0x2e, 0x34, 0x42, 0x53, 0x14, 0x90, 0x21, 0x4c, 0x2c, 0x36, +0x44, 0x4e, 0x14, 0x8c, 0x27, 0x3e, 0x31, 0x32, 0x3e, 0x59, 0x3e, 0x76, 0x1d, 0x43, 0x33, 0x36, +0x3f, 0x58, 0x3e, 0x72, 0x19, 0x4c, 0x2d, 0x38, 0x45, 0x54, 0x06, 0x3e, 0x0c, 0x57, 0x2f, 0x37, +0x46, 0x4f, 0x3e, 0x31, 0x04, 0x5c, 0x33, 0x37, 0x3f, 0x52, 0x3e, 0x21, 0x03, 0x5b, 0x32, 0x33, +0x46, 0x4e, 0x3e, 0x16, 0x06, 0x50, 0x38, 0x37, 0x3b, 0x56, 0x3e, 0x0e, 0x83, 0x5c, 0x40, 0x2a, +0x3d, 0x52, 0x15, 0x09, 0x86, 0x6a, 0x2e, 0x38, 0x39, 0x4d, 0x15, 0x07, 0x02, 0x64, 0x31, 0x44, +0x2f, 0x53, 0x15, 0x04, 0x8b, 0x7d, 0x28, 0x44, 0x36, 0x4d, 0x15, 0x06, 0x02, 0x69, 0x39, 0x41, +0x32, 0x50, 0x00, 0x04, 0x83, 0x72, 0x38, 0x3f, 0x37, 0x4f, 0x15, 0x03, 0x04, 0x74, 0x39, 0x4b, +0x33, 0x58, 0x15, 0x02, 0x81, 0xf8, 0x26, 0x5a, 0x2f, 0x58, 0x15, 0x02, 0x01, 0xf8, 0x26, 0x5d, +0x2f, 0x59, 0x15, 0x02, 0x83, 0xf8, 0x21, 0x5e, 0x2b, 0x5b, 0x00, 0x01, 0x08, 0x79, 0x33, 0x55, +0x34, 0x57, 0x00, 0x01, 0x07, 0x78, 0x2f, 0x55, 0x3c, 0x52, 0x15, 0x01, 0x8c, 0xfd, 0x19, 0x50, +0x2c, 0x4f, 0x29, 0x01, 0x89, 0x76, 0x28, 0x3c, 0x3a, 0x49, 0x29, 0x01, 0x88, 0x71, 0x2a, 0x3a, +0x3f, 0x44, 0x29, 0x00, 0x87, 0x70, 0x2a, 0x37, 0x4a, 0x3d, 0x2a, 0x02, 0x11, 0x63, 0x25, 0x37, +0x37, 0x4b, 0x2d, 0x02, 0x82, 0x67, 0x20, 0x32, 0x49, 0x48, 0x29, 0x04, 0x8a, 0x6e, 0x21, 0x36, +0x47, 0x49, 0x26, 0x0b, 0x0e, 0x3d, 0x44, 0x27, 0x42, 0x55, 0x24, 0x11, 0x82, 0x4d, 0x4c, 0x24, +0x45, 0x4c, 0x23, 0x15, 0x85, 0x4d, 0x54, 0x25, 0x39, 0x53, 0x22, 0x14, 0x03, 0x3a, 0x5c, 0x2b, +0x2e, 0x5c, 0x22, 0x11, 0x04, 0x40, 0x4c, 0x2d, 0x3c, 0x54, 0x22, 0x10, 0x09, 0x2d, 0x5f, 0x2f, +0x31, 0x59, 0x22, 0x11, 0x09, 0x37, 0x47, 0x38, 0x44, 0x4c, 0x22, 0x0e, 0x0b, 0x36, 0x4f, 0x28, +0x43, 0x55, 0x22, 0x0b, 0x0a, 0x3d, 0x49, 0x21, 0x4b, 0x50, 0x23, 0x02, 0x83, 0x3c, 0x5c, 0x2c, +0x4a, 0x3a, 0x22, 0x00, 0x8f, 0x61, 0x45, 0x38, 0x4c, 0x35, 0x59, 0x00, 0x93, 0x5a, 0x58, 0x2e, +0x45, 0x3b, 0x22, 0x00, 0x8e, 0x56, 0x5a, 0x34, 0x39, 0x45, 0x22, 0x01, 0x16, 0x40, 0x30, 0x51, +0x44, 0x3a, 0x23, 0x01, 0x2e, 0x31, 0x41, 0x25, 0x3c, 0x56, 0x01, 0x02, 0x41, 0x4c, 0x44, 0x22, +0x39, 0x3d, 0x0a, 0x02, 0x3a, 0x45, 0x32, 0x26, 0x41, 0x3d, 0x1d, 0x13, 0x01, 0x66, 0x21, 0x43, +0x43, 0x3a, 0x1b, 0x32, 0x05, 0x50, 0x47, 0x30, 0x4a, 0x3c, 0x1b, 0x43, 0x00, 0x4c, 0x51, 0x38, +0x3e, 0x43, 0x1a, 0x49, 0x8d, 0x71, 0x38, 0x48, 0x2d, 0x4c, 0x18, 0x56, 0x83, 0x61, 0x40, 0x4c, +0x2a, 0x4c, 0x18, 0x49, 0x8c, 0x6c, 0x3e, 0x4b, 0x30, 0x48, 0x17, 0x68, 0x89, 0x61, 0x47, 0x45, +0x2d, 0x4a, 0x41, 0x9f, 0x05, 0x57, 0x4d, 0x46, 0x30, 0x49, 0x16, 0x94, 0x06, 0x54, 0x52, 0x42, +0x37, 0x48, 0x16, 0xca, 0x0b, 0x54, 0x43, 0x48, 0x39, 0x41, 0x15, 0xfc, 0x0d, 0x54, 0x45, 0x44, +0x3a, 0x43, 0x15, 0xe8, 0x13, 0x4b, 0x4d, 0x3a, 0x3d, 0x4d, 0x15, 0xff, 0x17, 0x4b, 0x43, 0x37, +0x4a, 0x4a, 0x15, 0xe2, 0x1f, 0x44, 0x38, 0x33, 0x54, 0x4f, 0x15, 0xb0, 0x27, 0x3e, 0x33, 0x2b, +0x53, 0x51, 0x15, 0x6f, 0x25, 0x3d, 0x37, 0x23, 0x52, 0x54, 0x15, 0x09, 0x08, 0x42, 0x3e, 0x38, +0x5f, 0x2a, 0x17, 0x0a, 0x1d, 0x35, 0x34, 0x39, 0x4b, 0x43, 0x15, 0x31, 0x18, 0x49, 0x26, 0x37, +0x55, 0x41, 0x15, 0x46, 0x1f, 0x44, 0x26, 0x35, 0x56, 0x45, 0x15, 0x44, 0x19, 0x44, 0x23, 0x41, +0x52, 0x44, 0x3e, 0x39, 0x12, 0x3e, 0x2a, 0x4d, 0x59, 0x32, 0x3e, 0x27, 0x06, 0x48, 0x22, 0x5a, +0x56, 0x2c, 0x3e, 0x13, 0x8c, 0x65, 0x16, 0x6c, 0x39, 0x38, 0x3d, 0x10, 0x91, 0x74, 0x08, 0x78, +0x30, 0x39, 0x3d, 0x12, 0x91, 0x72, 0x0b, 0x72, 0x3a, 0x35, 0x3d, 0x0e, 0x96, 0xf4, 0x8b, 0xf9, +0x22, 0x41, 0x15, 0x0c, 0x8d, 0x6f, 0x2c, 0x41, 0x53, 0x2d, 0x00, 0x09, 0x83, 0x5a, 0x42, 0x3e, +0x4d, 0x39, 0x00, 0x0a, 0x83, 0x53, 0x46, 0x40, 0x4b, 0x39, 0x00, 0x03, 0x92, 0x64, 0x53, 0x2d, +0x4c, 0x3b, 0x29, 0x03, 0x91, 0x62, 0x49, 0x41, 0x3f, 0x3e, 0x3e, 0x01, 0x92, 0x62, 0x44, 0x45, +0x41, 0x39, 0x00, 0x02, 0x06, 0x2e, 0x60, 0x43, 0x3f, 0x3d, 0x00, 0x0a, 0x22, 0x14, 0x6c, 0x47, +0x32, 0x4e, 0x0c, 0x15, 0x23, 0x22, 0x66, 0x41, 0x2c, 0x58, 0x17, 0x1a, 0x85, 0x58, 0x34, 0x3a, +0x51, 0x3a, 0x15, 0x25, 0x07, 0x4c, 0x34, 0x35, 0x50, 0x40, 0x15, 0x2c, 0x0e, 0x42, 0x39, 0x38, +0x43, 0x47, 0x15, 0x20, 0x0e, 0x37, 0x47, 0x40, 0x3d, 0x43, 0x3e, 0x1f, 0x0c, 0x3d, 0x41, 0x40, +0x3d, 0x44, 0x3d, 0x1c, 0x01, 0x42, 0x4a, 0x3a, 0x41, 0x42, 0x3d, 0x19, 0x05, 0x3c, 0x4c, 0x3a, +0x3a, 0x49, 0x3d, 0x19, 0x83, 0x49, 0x47, 0x37, 0x42, 0x42, 0x15, 0x1e, 0x0c, 0x33, 0x4e, 0x38, +0x3b, 0x4a, 0x15, 0x27, 0x12, 0x3e, 0x3a, 0x38, 0x46, 0x47, 0x16, 0x26, 0x0a, 0x4a, 0x2d, 0x3c, +0x53, 0x3c, 0x17, 0x25, 0x12, 0x4d, 0x23, 0x3c, 0x5b, 0x36, 0x17, 0x25, 0x1c, 0x3f, 0x25, 0x3b, +0x5b, 0x39, 0x15, 0x1d, 0x19, 0x3e, 0x1e, 0x43, 0x57, 0x3c, 0x18, 0x14, 0x27, 0x3c, 0x0d, 0x36, +0x52, 0x53, 0x17, 0x1b, 0x2b, 0x35, 0x1b, 0x2d, 0x54, 0x51, 0x17, 0x27, 0x27, 0x3c, 0x1f, 0x2c, +0x4c, 0x54, 0x17, 0x20, 0x20, 0x3b, 0x26, 0x30, 0x4d, 0x4e, 0x17, 0x20, 0x15, 0x37, 0x35, 0x39, +0x4c, 0x43, 0x17, 0x1e, 0x0d, 0x41, 0x2e, 0x40, 0x53, 0x3a, 0x17, 0x18, 0x05, 0x43, 0x34, 0x44, +0x54, 0x34, 0x17, 0x1d, 0x06, 0x3a, 0x45, 0x3c, 0x4c, 0x3c, 0x16, 0x1b, 0x00, 0x3c, 0x58, 0x31, +0x40, 0x44, 0x17, 0x12, 0x83, 0x42, 0x4a, 0x3e, 0x49, 0x39, 0x17, 0x0f, 0x82, 0x45, 0x39, 0x4a, +0x4a, 0x37, 0x18, 0x0d, 0x87, 0x49, 0x3b, 0x4f, 0x3f, 0x3b, 0x18, 0x0a, 0x8a, 0x4b, 0x45, 0x49, +0x3c, 0x3c, 0x17, 0x0c, 0x91, 0x61, 0x3c, 0x3f, 0x46, 0x3a, 0x17, 0x09, 0x8c, 0x58, 0x2a, 0x58, +0x48, 0x30, 0x17, 0x05, 0x93, 0x68, 0x1f, 0x67, 0x3a, 0x36, 0x17, 0x05, 0x95, 0x68, 0x35, 0x57, +0x32, 0x3e, 0x18, 0x04, 0x90, 0x5a, 0x41, 0x42, 0x44, 0x3b, 0x18, 0x08, 0x92, 0x65, 0x3a, 0x42, +0x46, 0x38, 0x17, 0x03, 0x9b, 0xf2, 0x14, 0x5b, 0x3b, 0x39, 0x17, 0x03, 0x98, 0x7e, 0x22, 0x54, +0x43, 0x34, 0x18, 0x04, 0x99, 0xf8, 0x24, 0x47, 0x46, 0x36, 0x18, 0x03, 0x98, 0xf7, 0x29, 0x3f, +0x4d, 0x38, 0x59, 0x02, 0x98, 0xf3, 0x25, 0x43, 0x4c, 0x39, 0x59, 0x02, 0x9a, 0xec, 0x15, 0x50, +0x44, 0x3c, 0x02, 0x02, 0x96, 0xf7, 0x23, 0x4b, 0x46, 0x3d, 0x59, 0x03, 0x91, 0x74, 0x38, 0x40, +0x48, 0x3e, 0x59, 0x02, 0x95, 0xfe, 0x31, 0x38, 0x54, 0x39, 0x59, 0x02, 0x9a, 0xe9, 0x0e, 0x59, +0x3a, 0x44, 0x59, 0x02, 0x9a, 0xe9, 0x0a, 0x5c, 0x3a, 0x42, 0x2d, 0x01, 0x9a, 0xec, 0x1b, 0x42, +0x51, 0x39, 0x02, 0x01, 0x9b, 0xe8, 0x0f, 0x50, 0x48, 0x3c, 0x18, 0x02, 0x94, 0x72, 0x37, 0x42, +0x47, 0x38, 0x59, 0x04, 0x95, 0x74, 0x34, 0x43, 0x43, 0x3a, 0x20, 0x07, 0x95, 0x62, 0x4f, 0x31, +0x4d, 0x36, 0x19, 0x1a, 0x93, 0x5f, 0x59, 0x2d, 0x30, 0x51, 0x18, 0x42, 0x88, 0x5b, 0x44, 0x35, +0x3d, 0x4b, 0x18, 0x4a, 0x06, 0x51, 0x2c, 0x45, 0x4d, 0x43, 0x17, 0x3c, 0x80, 0x5e, 0x20, 0x4f, +0x46, 0x47, 0x17, 0x3b, 0x01, 0x56, 0x26, 0x51, 0x4c, 0x40, 0x43, 0x41, 0x05, 0x4d, 0x34, 0x4b, +0x49, 0x44, 0x18, 0x39, 0x87, 0x63, 0x25, 0x55, 0x40, 0x47, 0x18, 0x49, 0x04, 0x4c, 0x3a, 0x45, +0x47, 0x48, 0x18, 0x3e, 0x82, 0x5e, 0x26, 0x53, 0x3e, 0x4c, 0x18, 0x4c, 0x87, 0x75, 0x0d, 0x67, +0x2c, 0x54, 0x17, 0x61, 0x08, 0x50, 0x32, 0x47, 0x45, 0x4a, 0x17, 0x73, 0x15, 0x43, 0x34, 0x43, +0x4f, 0x43, 0x18, 0x66, 0x04, 0x5c, 0x26, 0x51, 0x36, 0x4c, 0x19, 0x1d, 0x93, 0xf7, 0x07, 0x69, +0x28, 0x4d, 0x19, 0x1a, 0x8c, 0x74, 0x20, 0x53, 0x36, 0x43, 0x19, 0x1f, 0x91, 0x7d, 0x1b, 0x4d, +0x39, 0x48, 0x18, 0x23, 0x90, 0xf3, 0x89, 0x71, 0x20, 0x53, 0x18, 0x3f, 0x81, 0x74, 0x11, 0x5e, +0x22, 0x52, 0x17, 0x84, 0x10, 0x53, 0x34, 0x44, 0x31, 0x52, 0x17, 0x8b, 0x1b, 0x3f, 0x35, 0x42, +0x47, 0x4e, 0x16, 0xae, 0x15, 0x54, 0x2b, 0x48, 0x3f, 0x51, 0x15, 0xaa, 0x21, 0x48, 0x2e, 0x47, +0x4b, 0x46, 0x14, 0xae, 0x1e, 0x48, 0x2a, 0x4d, 0x46, 0x4a, 0x14, 0xb0, 0x15, 0x4d, 0x32, 0x48, +0x3e, 0x4d, 0x13, 0xc7, 0x0e, 0x54, 0x37, 0x3f, 0x3d, 0x50, 0x14, 0x96, 0x0a, 0x57, 0x38, 0x44, +0x3c, 0x51, 0x15, 0x84, 0x07, 0x5e, 0x28, 0x57, 0x34, 0x4f, 0x3f, 0x7b, 0x02, 0x65, 0x24, 0x57, +0x35, 0x4c, 0x15, 0x51, 0x84, 0x69, 0x21, 0x5c, 0x31, 0x4d, 0x3e, 0x41, 0x86, 0x5d, 0x3e, 0x49, +0x2c, 0x53, 0x15, 0x35, 0x8b, 0x6e, 0x33, 0x4b, 0x2d, 0x4e, 0x15, 0x18, 0x8d, 0x65, 0x3a, 0x44, +0x37, 0x45, 0x15, 0x0c, 0x8a, 0x57, 0x43, 0x44, 0x43, 0x39, 0x52, 0x06, 0x8c, 0x63, 0x32, 0x4e, +0x45, 0x36, 0x28, 0x05, 0x03, 0x4e, 0x33, 0x51, 0x3d, 0x3d, 0x18, 0x05, 0x08, 0x4a, 0x39, 0x48, +0x42, 0x37, 0x1a, 0x0d, 0x04, 0x47, 0x46, 0x3e, 0x41, 0x3f, 0x18, 0x2e, 0x02, 0x52, 0x3b, 0x41, +0x46, 0x38, 0x17, 0x49, 0x81, 0x55, 0x47, 0x3e, 0x34, 0x47, 0x17, 0x50, 0x05, 0x4c, 0x47, 0x44, +0x2c, 0x4f, 0x17, 0x2b, 0x8b, 0x5b, 0x4e, 0x40, 0x22, 0x57, 0x18, 0x34, 0x87, 0x64, 0x33, 0x46, +0x33, 0x4e, 0x18, 0x2c, 0x8c, 0x6c, 0x36, 0x3c, 0x39, 0x4b, 0x18, 0x23, 0x89, 0x54, 0x50, 0x41, +0x1d, 0x5d, 0x18, 0x21, 0x8a, 0x58, 0x51, 0x32, 0x30, 0x55, 0x17, 0x32, 0x82, 0x59, 0x3f, 0x37, +0x3a, 0x4f, 0x17, 0x3c, 0x12, 0x45, 0x3f, 0x39, 0x32, 0x59, 0x18, 0x2c, 0x12, 0x41, 0x3c, 0x35, +0x43, 0x51, 0x19, 0x33, 0x10, 0x45, 0x3c, 0x3c, 0x57, 0x3f, 0x18, 0x1d, 0x25, 0x31, 0x30, 0x3f, +0x53, 0x40, 0x19, 0x0d, 0x28, 0x27, 0x32, 0x48, 0x4d, 0x3d, 0x25, 0x06, 0x31, 0x23, 0x2a, 0x43, +0x44, 0x49, 0x23, 0x09, 0x29, 0x25, 0x2e, 0x4f, 0x42, 0x45, 0x20, 0x10, 0x26, 0x34, 0x2d, 0x40, +0x4a, 0x41, 0x1e, 0x1a, 0x25, 0x3e, 0x1e, 0x32, 0x52, 0x4c, 0x1d, 0x1d, 0x14, 0x3a, 0x37, 0x38, +0x46, 0x49, 0x1c, 0x17, 0x16, 0x36, 0x3d, 0x37, 0x3d, 0x53, 0x1c, 0x10, 0x07, 0x3f, 0x43, 0x3a, +0x42, 0x45, 0x1c, 0x0b, 0x88, 0x59, 0x2f, 0x49, 0x3b, 0x46, 0x1d, 0x0a, 0x8f, 0x62, 0x30, 0x4f, +0x34, 0x47, 0x1d, 0x08, 0x93, 0x6e, 0x28, 0x58, 0x35, 0x3f, 0x1d, 0x08, 0x95, 0x75, 0x22, 0x5f, +0x2e, 0x42, 0x1d, 0x09, 0x8f, 0x69, 0x30, 0x46, 0x45, 0x39, 0x1d, 0x0a, 0x8b, 0x60, 0x34, 0x44, +0x45, 0x3c, 0x1e, 0x07, 0x94, 0x69, 0x40, 0x3b, 0x42, 0x3e, 0x1e, 0x0a, 0x8e, 0x5a, 0x40, 0x42, +0x47, 0x36, 0x1f, 0x0a, 0x87, 0x3c, 0x65, 0x3b, 0x34, 0x42, 0x24, 0x07, 0x8d, 0x40, 0x6c, 0x3d, +0x1f, 0x54, 0x24, 0x0a, 0x92, 0x56, 0x5d, 0x3e, 0x24, 0x53, 0x25, 0x0a, 0x8a, 0x49, 0x56, 0x44, +0x30, 0x46, 0x26, 0x0e, 0x8c, 0x48, 0x64, 0x45, 0x1d, 0x52, 0x25, 0x17, 0x8c, 0x5e, 0x46, 0x4a, +0x33, 0x43, 0x23, 0x2f, 0x0a, 0x3d, 0x5a, 0x50, 0x29, 0x45, 0x23, 0x30, 0x0d, 0x3a, 0x5c, 0x4d, +0x2b, 0x41, 0x23, 0x28, 0x80, 0x43, 0x62, 0x45, 0x26, 0x48, 0x23, 0x2c, 0x06, 0x43, 0x56, 0x4b, +0x31, 0x40, 0x24, 0x1b, 0x82, 0x55, 0x47, 0x48, 0x3e, 0x35, 0x24, 0x19, 0x81, 0x4a, 0x59, 0x46, +0x2a, 0x46, 0x22, 0x21, 0x03, 0x3d, 0x6a, 0x40, 0x22, 0x4c, 0x21, 0x24, 0x04, 0x3e, 0x69, 0x3f, +0x23, 0x4e, 0x21, 0x12, 0x90, 0x64, 0x56, 0x37, 0x2e, 0x4f, 0x23, 0x0c, 0x92, 0x76, 0x36, 0x39, +0x48, 0x3d, 0x24, 0x0b, 0x8a, 0x57, 0x53, 0x37, 0x36, 0x4e, 0x24, 0x08, 0x88, 0x59, 0x51, 0x33, +0x35, 0x50, 0x23, 0x08, 0x8d, 0x6b, 0x3e, 0x33, 0x45, 0x3e, 0x22, 0x06, 0x96, 0xfd, 0x33, 0x2d, +0x51, 0x3e, 0x23, 0x03, 0x9b, 0xee, 0x1f, 0x3f, 0x4e, 0x37, 0x23, 0x03, 0x99, 0xf8, 0x2e, 0x41, +0x41, 0x3d, 0x23, 0x03, 0x95, 0x70, 0x3d, 0x46, 0x3a, 0x3e, 0x23, 0x03, 0x97, 0x7e, 0x2f, 0x49, +0x3f, 0x3b, 0x23, 0x03, 0x99, 0xf8, 0x2f, 0x42, 0x42, 0x3e, 0x23, 0x04, 0x94, 0x6d, 0x45, 0x38, +0x45, 0x3e, 0x23, 0x03, 0x8a, 0x55, 0x4c, 0x4b, 0x2c, 0x4d, 0x07, 0x01, 0x0e, 0x3f, 0x46, 0x50, +0x38, 0x42, 0x08, 0x01, 0x22, 0x43, 0x4b, 0x3f, 0x39, 0x57, 0x19, 0x00, 0x27, 0x45, 0x42, 0x46, +0x38, 0x4e, 0x23, 0x00, 0x2a, 0x47, 0x4c, 0x4a, 0x38, 0x50, 0x08, 0x00, 0x29, 0x3e, 0x4d, 0x3a, +0x3e, 0x47, 0x08, 0x00, 0x25, 0x46, 0x46, 0x40, 0x40, 0x4b, 0x42, 0x00, 0x23, 0x44, 0x3e, 0x43, +0x42, 0x46, 0x08, 0x00, 0x1f, 0x41, 0x45, 0x47, 0x44, 0x39, 0x07, 0x00, 0x1a, 0x4e, 0x43, 0x47, +0x3d, 0x3f, 0x13, 0x00, 0x18, 0x4a, 0x44, 0x52, 0x33, 0x3d, 0x24, 0x00, 0x23, 0x3f, 0x4a, 0x41, +0x45, 0x41, 0x23, 0x00, 0x0e, 0x41, 0x3f, 0x3f, 0x35, 0x42, 0x28, 0x02, 0x13, 0x69, 0x1e, 0x34, +0x39, 0x3d, 0x1e, 0x05, 0x15, 0x48, 0x34, 0x1d, 0x52, 0x45, 0x18, 0x0e, 0x80, 0x66, 0x0f, 0x45, +0x44, 0x48, 0x14, 0x13, 0x87, 0x69, 0x0a, 0x55, 0x3f, 0x47, 0x12, 0x1e, 0x80, 0x50, 0x29, 0x47, +0x3d, 0x4b, 0x12, 0x2d, 0x04, 0x4b, 0x2a, 0x47, 0x41, 0x48, 0x12, 0x32, 0x11, 0x3c, 0x30, 0x3e, +0x4b, 0x46, 0x12, 0x51, 0x15, 0x36, 0x39, 0x3c, 0x46, 0x4c, 0x12, 0x4d, 0x83, 0x51, 0x3f, 0x3c, +0x36, 0x50, 0x12, 0x81, 0x18, 0x32, 0x43, 0x36, 0x45, 0x4e, 0x11, 0x83, 0x24, 0x2a, 0x41, 0x32, +0x43, 0x59, 0x11, 0x8b, 0x26, 0x33, 0x3d, 0x36, 0x41, 0x52, 0x12, 0x22, 0x19, 0x3c, 0x37, 0x45, +0x46, 0x3f, 0x23, 0x09, 0x89, 0x63, 0x2e, 0x48, 0x4b, 0x39, 0x59, 0x08, 0x8f, 0x70, 0x2d, 0x4b, +0x43, 0x3a, 0x5a, 0x0b, 0x8d, 0x6c, 0x34, 0x4b, 0x3c, 0x42, 0x07, 0x0a, 0x83, 0x5c, 0x47, 0x2e, +0x56, 0x39, 0x22, 0x0d, 0x11, 0x4b, 0x36, 0x4d, 0x3d, 0x45, 0x22, 0x09, 0x1f, 0x2b, 0x4a, 0x49, +0x52, 0x37, 0x0a, 0x0b, 0x2e, 0x53, 0x1f, 0x48, 0x3a, 0x44, 0x1c, 0x28, 0x0d, 0x55, 0x20, 0x4e, +0x3e, 0x44, 0x14, 0x53, 0x03, 0x61, 0x27, 0x4f, 0x33, 0x49, 0x10, 0xae, 0x81, 0x5d, 0x31, 0x53, +0x3a, 0x44, 0x0f, 0xfc, 0x0f, 0x4d, 0x3d, 0x52, 0x36, 0x4a, 0x30, 0xff, 0x10, 0x53, 0x36, 0x5c, +0x34, 0x48, 0x0e, 0xf5, 0x0d, 0x5a, 0x2f, 0x67, 0x2e, 0x46, 0x0d, 0xed, 0x12, 0x59, 0x30, 0x67, +0x2d, 0x46, 0x2d, 0xff, 0x0b, 0x68, 0x2a, 0x6c, 0x25, 0x4d, 0x0c, 0xff, 0x0c, 0x61, 0x35, 0x64, +0x24, 0x4e, 0x0c, 0xff, 0x06, 0x69, 0x2b, 0x6b, 0x24, 0x4b, 0x0c, 0xff, 0x0e, 0x62, 0x2b, 0x64, +0x32, 0x43, 0x0c, 0xff, 0x0e, 0x62, 0x31, 0x5c, 0x31, 0x45, 0x0c, 0xff, 0x05, 0x71, 0x2f, 0x5a, +0x28, 0x55, 0x0c, 0xeb, 0x0f, 0x62, 0x30, 0x4c, 0x40, 0x4d, 0x2d, 0xe7, 0x1d, 0x56, 0x29, 0x43, +0x43, 0x4e, 0x0d, 0xa4, 0x1b, 0x50, 0x20, 0x43, 0x47, 0x59, 0x0e, 0x92, 0x1b, 0x51, 0x1a, 0x48, +0x3d, 0x5f, 0x08, 0x2c, 0x12, 0x53, 0x2d, 0x4c, 0x49, 0x3e, 0x13, 0x27, 0x08, 0x57, 0x2c, 0x46, +0x4d, 0x42, 0x11, 0x88, 0x18, 0x50, 0x1e, 0x4b, 0x43, 0x45, 0x11, 0x70, 0x0d, 0x56, 0x1b, 0x50, +0x44, 0x43, 0x35, 0x74, 0x0a, 0x55, 0x1f, 0x51, 0x4b, 0x3f, 0x10, 0x75, 0x0d, 0x47, 0x2d, 0x53, +0x4e, 0x35, 0x11, 0x69, 0x0c, 0x50, 0x26, 0x53, 0x4f, 0x32, 0x11, 0x2f, 0x88, 0x6b, 0x1e, 0x5c, +0x3a, 0x3a, 0x5a, 0x22, 0x8f, 0xff, 0x0d, 0x61, 0x30, 0x42, 0x11, 0x1c, 0x90, 0x7e, 0x10, 0x5e, +0x32, 0x44, 0x11, 0x1b, 0x85, 0x64, 0x2a, 0x51, 0x3f, 0x3c, 0x5a, 0x22, 0x87, 0x6c, 0x3a, 0x43, +0x40, 0x46, 0x5a, 0x10, 0x8e, 0x6e, 0x40, 0x37, 0x4d, 0x3b, 0x11, 0x0b, 0x0a, 0x31, 0x72, 0x3b, +0x2b, 0x4f, 0x36, 0x07, 0x15, 0x43, 0x4b, 0x4c, 0x2a, 0x50, 0x4f, 0x04, 0x87, 0x70, 0x2a, 0x5e, +0x20, 0x4f, 0x09, 0x09, 0x91, 0xf9, 0x12, 0x6b, 0x1c, 0x58, 0x09, 0x0f, 0x91, 0xf3, 0x00, 0x70, +0x1e, 0x57, 0x26, 0x19, 0x91, 0x7b, 0x1a, 0x61, 0x2a, 0x4b, 0x17, 0x36, 0x8c, 0x5a, 0x3b, 0x5d, +0x23, 0x4c, 0x17, 0x47, 0x90, 0x60, 0x3e, 0x65, 0x11, 0x52, 0x17, 0x47, 0x8a, 0x5a, 0x3b, 0x65, +0x15, 0x4f, 0x16, 0x5e, 0x87, 0x5a, 0x3d, 0x64, 0x17, 0x52, 0x15, 0x60, 0x89, 0x5d, 0x3a, 0x64, +0x16, 0x53, 0x15, 0x66, 0x87, 0x68, 0x2e, 0x60, 0x1f, 0x53, 0x15, 0x5c, 0x88, 0x5e, 0x3b, 0x59, +0x1a, 0x59, 0x14, 0x4c, 0x8a, 0x62, 0x40, 0x4d, 0x1f, 0x57, 0x15, 0x2b, 0x8b, 0x68, 0x31, 0x52, +0x22, 0x55, 0x10, 0x15, 0x81, 0x66, 0x26, 0x5e, 0x1d, 0x55, 0x35, 0x0e, 0x02, 0x60, 0x2b, 0x57, +0x2a, 0x4f, 0x14, 0x06, 0x04, 0x64, 0x31, 0x49, 0x37, 0x44, 0x11, 0x04, 0x1b, 0x4e, 0x46, 0x3c, +0x3c, 0x3e, 0x08, 0x0c, 0x16, 0x4f, 0x4d, 0x4e, 0x22, 0x5c, 0x07, 0x12, 0x05, 0x68, 0x29, 0x60, +0x20, 0x5c, 0x10, 0x43, 0x84, 0x70, 0x1e, 0x55, 0x2d, 0x4c, 0x08, 0xb9, 0x0d, 0x5b, 0x2d, 0x47, +0x30, 0x53, 0x22, 0xf4, 0x1c, 0x4f, 0x2c, 0x46, 0x33, 0x56, 0x21, 0xff, 0x2a, 0x48, 0x25, 0x49, +0x49, 0x4e, 0x22, 0xcb, 0x24, 0x4b, 0x2d, 0x46, 0x43, 0x4a, 0x08, 0x8c, 0x22, 0x42, 0x30, 0x49, +0x48, 0x40, 0x08, 0x34, 0x06, 0x5d, 0x30, 0x54, 0x30, 0x4a, 0x5a, 0x17, 0x8a, 0x6c, 0x28, 0x5b, +0x2b, 0x49, 0x23, 0x14, 0x83, 0x61, 0x38, 0x49, 0x3b, 0x46, 0x59, 0x0e, 0x83, 0x6e, 0x23, 0x5f, +0x28, 0x54, 0x23, 0x0e, 0x02, 0x60, 0x2a, 0x61, 0x26, 0x54, 0x15, 0x0b, 0x08, 0x5d, 0x33, 0x4d, +0x2b, 0x51, 0x15, 0x0a, 0x14, 0x4d, 0x33, 0x40, 0x3c, 0x4b, 0x23, 0x05, 0x12, 0x44, 0x47, 0x33, +0x34, 0x4e, 0x23, 0x01, 0x82, 0x53, 0x3b, 0x4c, 0x2e, 0x46, 0x25, 0x03, 0x91, 0x65, 0x2e, 0x55, +0x3e, 0x38, 0x25, 0x06, 0x96, 0x74, 0x24, 0x5e, 0x38, 0x3a, 0x24, 0x08, 0x91, 0x65, 0x39, 0x4b, +0x36, 0x49, 0x23, 0x11, 0x8d, 0x69, 0x36, 0x4a, 0x30, 0x4e, 0x22, 0x17, 0x8d, 0x6c, 0x33, 0x4f, +0x2e, 0x4d, 0x23, 0x14, 0x8c, 0x71, 0x28, 0x4f, 0x2e, 0x51, 0x23, 0x0e, 0x80, 0x5d, 0x36, 0x3d, +0x36, 0x4f, 0x23, 0x10, 0x81, 0x5c, 0x34, 0x4a, 0x34, 0x4b, 0x23, 0x07, 0x82, 0x56, 0x47, 0x36, +0x42, 0x47, 0x3e, 0x03, 0x0c, 0x42, 0x5b, 0x34, 0x3c, 0x4d, 0x07, 0x02, 0x0d, 0x4d, 0x49, 0x3c, +0x40, 0x42, 0x80, 0x01, 0x28, 0x35, 0x4f, 0x3a, 0x38, 0x43, 0x06, 0x00, 0x39, 0x36, 0x3e, 0x4d, +0x42, 0x40, 0x08, 0x00, 0x35, 0x27, 0x51, 0x49, 0x37, 0x43, 0x08, 0x00, 0x31, 0x2c, 0x47, 0x47, +0x3a, 0x4a, 0x36, 0x00, 0x3c, 0x2f, 0x50, 0x42, 0x35, 0x40, 0x1f, 0x00, 0x26, 0x2d, 0x4b, 0x3d, +0x36, 0x4a, 0x20, 0x02, 0x91, 0x67, 0x3d, 0x47, 0x39, 0x3f, 0x16, 0x07, 0x92, 0x6a, 0x3b, 0x48, +0x38, 0x3f, 0x15, 0x14, 0x8b, 0x70, 0x27, 0x4d, 0x3d, 0x40, 0x28, 0x1e, 0x80, 0x5d, 0x34, 0x4a, +0x35, 0x4a, 0x27, 0x19, 0x01, 0x67, 0x27, 0x49, 0x36, 0x4c, 0x26, 0x0b, 0x88, 0x6d, 0x1c, 0x50, +0x38, 0x4a, 0x28, 0x03, 0x87, 0x5c, 0x30, 0x46, 0x3e, 0x40, 0x25, 0x02, 0x83, 0x54, 0x23, 0x4e, +0x3f, 0x46, 0x23, 0x07, 0x86, 0x57, 0x3c, 0x3f, 0x32, 0x53, 0x24, 0x14, 0x09, 0x4e, 0x34, 0x49, +0x35, 0x48, 0x3e, 0x31, 0x05, 0x60, 0x25, 0x50, 0x2f, 0x4e, 0x23, 0x3b, 0x01, 0x6c, 0x21, 0x4f, +0x33, 0x4c, 0x22, 0x41, 0x10, 0x56, 0x36, 0x47, 0x34, 0x4a, 0x28, 0x1d, 0x83, 0x70, 0x1e, 0x54, +0x2f, 0x49, 0x28, 0x0e, 0x13, 0x4a, 0x34, 0x41, 0x3b, 0x3f, 0x2f, 0x0b, 0x28, 0x44, 0x28, 0x44, +0x35, 0x3a, 0x30, 0x0b, 0x2b, 0x3c, 0x35, 0x35, 0x3e, 0x3a, 0x29, 0x21, 0x0b, 0x5a, 0x30, 0x40, +0x3a, 0x43, 0x2a, 0x2d, 0x82, 0x70, 0x19, 0x55, 0x2e, 0x4a, 0x29, 0x4a, 0x87, 0x76, 0x16, 0x63, +0x2a, 0x4f, 0x29, 0x66, 0x0d, 0x60, 0x28, 0x56, 0x29, 0x51, 0x29, 0x83, 0x13, 0x59, 0x37, 0x44, +0x2f, 0x4f, 0x1d, 0x90, 0x0a, 0x53, 0x3f, 0x50, 0x2e, 0x52, 0x1d, 0x71, 0x09, 0x65, 0x2f, 0x59, +0x2c, 0x55, 0x1d, 0x9a, 0x10, 0x5f, 0x34, 0x55, 0x2d, 0x50, 0x1c, 0x8d, 0x07, 0x6a, 0x2e, 0x58, +0x2c, 0x54, 0x1c, 0x6b, 0x12, 0x52, 0x4a, 0x4c, 0x2f, 0x5b, 0x29, 0x76, 0x04, 0x5f, 0x29, 0x5b, +0x33, 0x48, 0x0b, 0x66, 0x11, 0x49, 0x47, 0x41, 0x3a, 0x4c, 0x29, 0x30, 0x04, 0x5d, 0x34, 0x50, +0x2a, 0x57, 0x29, 0x2f, 0x08, 0x58, 0x31, 0x50, 0x2d, 0x57, 0x29, 0x28, 0x0c, 0x5a, 0x27, 0x52, +0x2a, 0x57, 0x28, 0x13, 0x80, 0x78, 0x09, 0x6e, 0x1c, 0x53, 0x10, 0x09, 0x8c, 0xff, 0x15, 0x61, +0x23, 0x51, 0x35, 0x14, 0x82, 0x69, 0x2a, 0x4f, 0x3a, 0x4b, 0x47, 0x51, 0x81, 0x64, 0x26, 0x55, +0x3c, 0x3f, 0x10, 0x7c, 0x03, 0x6a, 0x13, 0x64, 0x36, 0x43, 0x35, 0x98, 0x09, 0x58, 0x1f, 0x5d, +0x3a, 0x3d, 0x11, 0xb3, 0x0a, 0x52, 0x22, 0x5b, 0x33, 0x44, 0x34, 0x7b, 0x07, 0x5b, 0x11, 0x61, +0x36, 0x43, 0x36, 0x69, 0x0e, 0x56, 0x08, 0x65, 0x36, 0x48, 0x0c, 0x67, 0x16, 0x56, 0x02, 0x60, +0x34, 0x4f, 0x0c, 0x63, 0x17, 0x53, 0x0a, 0x61, 0x3a, 0x47, 0x10, 0x4e, 0x14, 0x4e, 0x18, 0x5c, +0x3e, 0x3d, 0x35, 0x46, 0x0d, 0x52, 0x15, 0x5e, 0x3a, 0x41, 0x10, 0x31, 0x08, 0x53, 0x14, 0x64, +0x3a, 0x40, 0x10, 0x0f, 0x91, 0x72, 0x0f, 0x6e, 0x2c, 0x42, 0x11, 0x0a, 0x97, 0xfd, 0x0b, 0x72, +0x1f, 0x4a, 0x38, 0x05, 0x93, 0x6f, 0x10, 0x72, 0x27, 0x47, 0x14, 0x05, 0x87, 0x57, 0x1d, 0x55, +0x3c, 0x48, 0x18, 0x0c, 0x8c, 0x6e, 0x26, 0x50, 0x22, 0x51, 0x18, 0x36, 0x1d, 0x46, 0x37, 0x4d, +0x21, 0x45, 0x18, 0x6d, 0x15, 0x45, 0x3a, 0x4e, 0x31, 0x46, 0x12, 0x6c, 0x12, 0x4f, 0x33, 0x47, +0x2c, 0x4d, 0x11, 0x74, 0x01, 0x61, 0x2f, 0x49, 0x38, 0x45, 0x11, 0x5e, 0x81, 0x62, 0x28, 0x53, +0x2e, 0x4b, 0x17, 0x32, 0x8b, 0x75, 0x19, 0x51, 0x35, 0x49, 0x17, 0x28, 0x05, 0x52, 0x35, 0x3d, +0x3f, 0x45, 0x17, 0x1b, 0x02, 0x52, 0x36, 0x42, 0x33, 0x4c, 0x18, 0x0f, 0x0c, 0x42, 0x30, 0x39, +0x49, 0x48, 0x17, 0x09, 0x81, 0x48, 0x3f, 0x40, 0x2f, 0x53, 0x17, 0x09, 0x16, 0x27, 0x42, 0x3c, +0x39, 0x54, 0x17, 0x0b, 0x17, 0x2a, 0x3c, 0x3f, 0x38, 0x54, 0x16, 0x11, 0x26, 0x31, 0x20, 0x31, +0x51, 0x50, 0x41, 0x0e, 0x2f, 0x37, 0x07, 0x33, 0x4f, 0x5a, 0x18, 0x0a, 0x38, 0x30, 0x81, 0x34, +0x50, 0x61, 0x45, 0x08, 0x3d, 0x2c, 0x86, 0x31, 0x51, 0x65, 0x19, 0x17, 0x14, 0x59, 0x0f, 0x55, +0x30, 0x45, 0x15, 0x34, 0x19, 0x61, 0x18, 0x4b, 0x2f, 0x3e, 0x3e, 0x60, 0x0e, 0x56, 0x23, 0x53, +0x3a, 0x40, 0x3d, 0x6c, 0x07, 0x61, 0x19, 0x5b, 0x3a, 0x41, 0x3e, 0x71, 0x06, 0x64, 0x16, 0x56, +0x43, 0x3c, 0x3e, 0x66, 0x88, 0xfe, 0x83, 0x6f, 0x2d, 0x43, 0x3e, 0x68, 0x84, 0x75, 0x0a, 0x65, +0x35, 0x40, 0x3e, 0x76, 0x82, 0x76, 0x06, 0x69, 0x2f, 0x46, 0x3d, 0x6c, 0x85, 0x79, 0x09, 0x65, +0x2c, 0x4a, 0x3e, 0x56, 0x8c, 0xfb, 0x05, 0x6a, 0x27, 0x4d, 0x3e, 0x5e, 0x87, 0x7e, 0x0a, 0x67, +0x29, 0x4c, 0x15, 0x69, 0x82, 0x78, 0x0f, 0x60, 0x29, 0x4d, 0x15, 0x6c, 0x82, 0x7b, 0x04, 0x67, +0x29, 0x4a, 0x3d, 0x65, 0x01, 0x73, 0x0e, 0x5c, 0x35, 0x41, 0x3d, 0x5e, 0x83, 0x7e, 0x00, 0x69, +0x31, 0x43, 0x3f, 0x60, 0x84, 0x7a, 0x07, 0x66, 0x32, 0x47, 0x3d, 0x5b, 0x82, 0x7c, 0x03, 0x64, +0x30, 0x47, 0x3e, 0x6e, 0x02, 0x6e, 0x0d, 0x5e, 0x31, 0x4b, 0x15, 0x57, 0x81, 0x6e, 0x13, 0x5b, +0x31, 0x49, 0x3e, 0x64, 0x06, 0x6a, 0x11, 0x57, 0x3d, 0x41, 0x3e, 0x6d, 0x04, 0x6f, 0x0a, 0x5d, +0x31, 0x4a, 0x3e, 0x56, 0x02, 0x70, 0x03, 0x62, 0x2f, 0x4d, 0x3f, 0x4e, 0x86, 0x7c, 0x80, 0x6b, +0x2e, 0x48, 0x3e, 0x5c, 0x85, 0x79, 0x07, 0x65, 0x31, 0x43, 0x3e, 0x5b, 0x83, 0x7c, 0x06, 0x62, +0x2d, 0x49, 0x3e, 0x42, 0x83, 0x73, 0x1b, 0x4a, 0x3c, 0x46, 0x3e, 0x57, 0x0c, 0x68, 0x1e, 0x47, +0x3e, 0x42, 0x15, 0x4e, 0x0b, 0x66, 0x1c, 0x48, 0x3c, 0x46, 0x3e, 0x50, 0x84, 0xfb, 0x84, 0x67, +0x2b, 0x48, 0x3e, 0x4b, 0x82, 0x7b, 0x0b, 0x58, 0x38, 0x42, 0x3e, 0x3e, 0x85, 0x7b, 0x10, 0x56, +0x34, 0x48, 0x3e, 0x4a, 0x05, 0x6b, 0x1b, 0x50, 0x31, 0x4e, 0x3e, 0x3f, 0x8a, 0xfc, 0x0c, 0x59, +0x30, 0x4c, 0x15, 0x39, 0x82, 0x73, 0x1e, 0x4b, 0x36, 0x4c, 0x3e, 0x36, 0x85, 0x7a, 0x13, 0x50, +0x36, 0x4c, 0x3e, 0x31, 0x02, 0x68, 0x2b, 0x44, 0x36, 0x4d, 0x3f, 0x43, 0x05, 0x74, 0x14, 0x53, +0x33, 0x47, 0x3e, 0x2f, 0x83, 0x71, 0x1d, 0x50, 0x34, 0x4a, 0x3e, 0x27, 0x87, 0x78, 0x0f, 0x5f, +0x2a, 0x4d, 0x3e, 0x2b, 0x82, 0x6a, 0x1c, 0x59, 0x2c, 0x4f, 0x3d, 0x24, 0x82, 0x6b, 0x23, 0x53, +0x26, 0x55, 0x3e, 0x1e, 0x81, 0x65, 0x38, 0x45, 0x2f, 0x54, 0x3e, 0x1b, 0x01, 0x68, 0x2f, 0x52, +0x1e, 0x5a, 0x3e, 0x15, 0x81, 0x6b, 0x2c, 0x5b, 0x14, 0x64, 0x3e, 0x16, 0x8a, 0xf6, 0x0a, 0x69, +0x23, 0x50, 0x3e, 0x12, 0x8d, 0xf2, 0x09, 0x6c, 0x1f, 0x55, 0x3d, 0x0f, 0x8a, 0xfa, 0x17, 0x64, +0x1f, 0x5b, 0x3d, 0x11, 0x87, 0xfb, 0x16, 0x6a, 0x1f, 0x5b, 0x3d, 0x0f, 0x83, 0x7b, 0x21, 0x60, +0x22, 0x5b, 0x3e, 0x0f, 0x8b, 0xf1, 0x03, 0x73, 0x1d, 0x56, 0x3e, 0x0b, 0x93, 0xe5, 0x91, 0xf8, +0x12, 0x59, 0x3e, 0x08, 0x91, 0xec, 0x09, 0x67, 0x27, 0x54, 0x3e, 0x06, 0x90, 0xf6, 0x1d, 0x61, +0x20, 0x5a, 0x3e, 0x06, 0x94, 0xe7, 0x8c, 0x7f, 0x1a, 0x55, 0x3d, 0x04, 0x96, 0xe5, 0x87, 0x6f, +0x25, 0x53, 0x3d, 0x05, 0x8f, 0xee, 0x0c, 0x66, 0x25, 0x57, 0x3e, 0x04, 0x8c, 0xf6, 0x20, 0x54, +0x2f, 0x55, 0x3e, 0x02, 0x95, 0xe7, 0x82, 0x6d, 0x27, 0x51, 0x3e, 0x01, 0x93, 0xe9, 0x01, 0x6f, +0x24, 0x52, 0x15, 0x01, 0x8d, 0xfb, 0x2d, 0x4a, 0x35, 0x4f, 0x15, 0x01, 0x8d, 0x7e, 0x2d, 0x4e, +0x32, 0x4e, 0x15, 0x00, 0x05, 0x65, 0x2b, 0x53, 0x39, 0x52, 0x15, 0x00, 0x01, 0x7c, 0x16, 0x59, +0x39, 0x4a, 0x2a, 0x00, 0x06, 0x61, 0x38, 0x39, 0x3b, 0x38, 0x00, 0x00, 0x83, 0x5b, 0x3d, 0x35, +0x43, 0x34, 0x15, 0x00, 0x10, 0x4e, 0x43, 0x3f, 0x37, 0x3d, 0x00, 0x00, 0x04, 0x53, 0x3f, 0x36, +0x2d, 0x47, 0x00, 0x00, 0x05, 0x57, 0x36, 0x34, 0x3b, 0x3f, 0x01, 0x00, 0x29, 0x48, 0x38, 0x34, +0x3e, 0x39, 0x15, 0x00, 0x2b, 0x5a, 0x38, 0x3f, 0x3c, 0x3c, 0x15, 0x00, 0x2b, 0x5a, 0x40, 0x47, +0x3c, 0x3a, 0x15, 0x00, 0x2b, 0x5e, 0x3f, 0x43, 0x3f, 0x3f, 0x00, 0x00, 0x2c, 0x4c, 0x41, 0x37, +0x3a, 0x42, 0x00, 0x00, 0x26, 0x4f, 0x32, 0x3d, 0x2f, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, +}; + +//File: merry.wav +//Time: 23670 ms +//Size: 8418 bytes +//Quality: 6 diff --git a/board-package-source/libraries/ArdVoice/extras/assets/merry.wav b/board-package-source/libraries/ArdVoice/extras/assets/merry.wav new file mode 100644 index 0000000000000000000000000000000000000000..0be9a38bba35cd4e1207f72152711336b5f5babe GIT binary patch literal 189205 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%0DU1}NvV5iPf}lhYC*&_&U) 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 z z-hl!c;3DsWF(;EH+8UMGFPr_9tM!+Cj0w&MUJ|<#1|d zjkl1aOB3`_Hjh!O#R?9>DO(056sdrps#npnb9yJAjyul6OMR4F4`vwQ*7kQqeQVpY z&j*YWp#XHOen5eZ6)MUEJG>IvXrFdSa|9J>rzb0ZH{h89hAdiaPMb$NdnMMH=@vPf2>!Gf=^|*bm z0B!1c^gdAwxx`t+h-1xqPD8CXiY;h|r%6|riyS10PSlF^5#~g;$I7%LbvT<>s|}V7 zuBVS;NhjfwGrh4I)eFUZ0fzb&lFAZ)iKwOyU8oC)Gk}ts$Td1?%9QK&igGJL2f@$g)PX+O*rWSWi4Z)<%N}JiWSnFGI-_`+Tq* zvtmnx=on3`=nEI{3bd>epXXYz;NV$QV6p+_qms7A?71*Sf(Dt;MvFt7Lj}_(F)gyB7TiwkFvhXi z#QX*u5!oD@Lv(%!h140ilnp#3o2rb(rQhiz){-8Zp$SlL$o7pc%QYyD2$~~x0E?v( zl%0-Gg2wAHa$c-S1Ph`B#X#mB;j>nmj&2O#sCJx^Tr(6`g1RE827JN}h2el-kyCaA zVMa5myJ}Zgy5c}(ydpxMNC;vF6(qD081(uTpABJ!F}s9EV5F%FUB&~7-xhVB^<_pt z{T{hqSMZQdfu&_s*H4it<=Z26#yMyLfZ7JI9gt|F?Nl(%#|DHRvR%vWiYCkHFa&fh z#ix2Lo$)9H6*`p||NGF=1IfnD!IK?IDSP#vEf0xBxz}+m(r-8vY~^sr3sTjrD?$&e zB?!%3(rqN7VCfMRw|gw?FFGGJK&kUBYpC|+L<%CY&qh_d;8#OzJec9(C_f_uN9r}l zl@X18FDQkFR$J~7lh%UmQl=w1a!(B56G9ePc@~pD zWUP@I2L*&7X`I#a+xXKGtDv&ALJRyG`1%C1<9B>)JNST3I2)g(U{Vq5gYpX6K47~oREQoMHoAl=)eO;RdYtRv%y!tg9du<+_EldL?WPI5 zztATpTw+UIVnX)QmyRo#cLiVUu_0-Zj%M|tSgE~r5iPefch-bT(;jrhlx)F z`Kuml!z3W#1n1E-VWEP<5zUiiV~ZrgXM~KFG{PyhOkj0`We>atx)joAHcigueSkke zPR2Fhz-0`Jy#mPvTn)6L(clDvct87PZEtt z25Hn+FhmYTga!utuhi}qVbBRnnnD%X8cEb7lEKNzcVWRBbmIxeLts(I829TTXS*F< z5}*P*g5snKku`izChc@BOf(?bMKh5EJ+!fI1RFd9x-tTlvvs0gFY^#OiI}HCc+s8N z0DVP+8N@8`gala0W7H_*o9ewHn}bpakP_M914y$$u^X+2@f4Xqj>~mza1aU8BC;BV zkh)T?LsgMSr=Y+I-TAOLMOt8Qgybp!&nSCb6f7>&w07XYIytbK1hUBJUWg#+N5lF2 zVvN7xJIgL?A2G$5W~Jm6ck<2bJyq<`Hi)lAkPT1Cd)jYa$ z(A+)H5YZDWb#NIyOdJsd8G>Ftu;vR{jQE!0RF7Tq{d?8Q0}z3*Z~~iT&>xNw{L&4F zeat_`6G@3X9kqA5@73Rbr&&0p8!WD}wrh=-!^zoI;^5Pt_JVm=Fjbmx+})~FeeYH? zUnMXE)G5J3E3sV6A0xPKFviXfqG`3oicYCQHVb!<8sBPCGE#X|l$@*idOM$Bs0gjf zME9p~aR$u;s!}~V*gay%CLQ)*$r&xCqs7&F>^c!bRl2ZY0@bd!%jIIZQh0wKojMYU z`+eSlr+B#CPDZMUd~*PQ$5yo@R_f)we7=4AJ^|B#<4w*Sb9x5F-vTT+#+j~du{$!W zr>D6Rg7q5h^4>Ah#w=&OS~$Uaj41i(YA&nO0ql=}5ftCf6;CsJ<*HD+kH*0Uh~r{m zM(Zu6>hndS!kG{JzM#}@?(FSlPEIQdpDn_aHyduQpTrtwfQS;GY(`BM^G1S)`r-8t z9%kxC*m=t>*_|$i>+6eUfHyGhdW)-R3(czz_72&8?m!M(ffOguZkOwMO721xF+sCI#~hRY`(|Mq!2G2Le4 zo$tT*-Pd0)SFJ}EpFe%<^I$5 z0r$_}EVZ_ezfL}T(i8T7_QPV1GQz>r7+-(7Fdm!U z{?1?ScABv~TmRWpWmjrK|C6M_Q~0KoD3$D-&$1m&e4(j!_2WV-Ci&& zUOc}2YKGO;n6&@y@(lSp)5%xA=y2~p+@;?Caq0N%$w%%eY%}k_{&t7GnD*vZA5YhA z*j;}44^HR)dpnivcPppk7heuyx7@mS^G5`|y_oiApN>`lY|K9WcOJR_+HQgTZnc_x z_Qg5dD>NSd{EeJ>_NYHvKZiQfvXkHZy<*(_d8S$V3ugEFvo8jmpV8jC@k-Tsei6?n zk5^N0-KT&5J5~P9y%Xl-?c&jw&px%p97(?SJ{S^T&KKkH6(Z);;PL-8GY-F>%PFsy z?z>+<+B8}Z#k=<&_oOp7+|CI|NaqG|6w+-zh5pee|!CyXx$|b_8#81XItQJ zSF=P(qRD^wnjwC0FQebfw@QD1`H9xNMQ87w+!995d?=gY)$+sS-+y9o-#;l?l}48O z{rTr%{+;Ii+lO~s^GC2d%t!uk9?k##naX_oq+-@9C&C|=zX%%lDi0p!Zg={RAmW^c z?qoH1_P@AB@z1i1RxBTkzMj9(iiPaYPxc?EfVgx)5=+*b}Dj2%Cx>(JPGS9_4WsQx9DJT`NZz3J_M#; z{~r?f{@d9)bXA87pg_gC%-r00=U8x;&lbqvn=gBd|L}!Y{mZ?545=&BruT9J7*pxN zop&3M{XU%zafC0rpZ&X@bK|{YrClZR=ic;bMDX%%_0dXg(Q>+)Xyfbc_V@F+cH^MLXG)EDY+a5uR<1YmH|{kJZ!+BU z-Np6g*_ZPenYkJ2DBA=uax(HbiKSuZXX?=*7r_OUggOqq^=V;0uV46gQ0)9 z?!oe@#glTOT01TlAMo{3nGu?v+(SR%51nDM+C=Ni(eP|+;9zK#vqx<#$oE-jk40C; zL?X0Os45_p*H^>&#emV|qf)L?qVgXSC6=I}_h8X-#@*Fws0`_&AmKwUh@nIhQYw;BP(&*kI&AQ zc%r+=xs~j~{YLF*hd3!#PCFdW$6cs~g8pQHn9&h13Ueed_tdsPW#Ep=9Pgdd)h65q z=&wP8pCj`$jK-5LoFtKn*w}_#&7M9uI%@28@W3H8-m@{tO5%Qhg2c>eG8oM~2Mhcb zzn{+@ot#v65scd5Obg0Gr#Bnm_hREQ34+lgj`|b;VYz(%?(t#cVUt9jq#=X|c8-St zd%{|dJx<)8`p($nNujo1-p@Sj007lysYpVg{b1A!<2a4NgJ=m`3g9j*uBGJ<8rg$= z;jo~Itco6_4-_L59Ahkc2R*kJhEd=L2FZJwqeAgC&mNEpM`OCw3r#=L2Z)IDr$ER4 z|0KOxUZReAE{$#Wj_HyAQbic?qz z6@4?}3vanY+vz;9xGq=PddcP-?-D8D)Oxn~vY7{*x3%}qo%qVZPQ~ayHD}#U(Ho3M z1F~W-PkNKfOKh0yUyWCz9%b{q%Qa)9dQ%ukV?ZI7ec*F#MPAz3X`5 z_T;kKNZgdR*P>FypSyT^eD=-dv=RfQn|$?e*wEGmQqHiUhn;3 z@p0Q9cz1Qjd$ejC`VJz6$>ij#Z(5moU-1|Jx_7@8ksfTXJ#6pLLPiqFZKw958Gq#T@{2Pm zrz$&{qv_z}AO5%z-ClWoPv4!DN+he1kKV3cpF~@~entoyiYuFc{!xCS^}qQ3OLDl=FORz~|6o15 zzrFLw^YC6~I`nIwjPa9ltw%F~j5)28gxbNlxBO(5`JC|e1l#yUfNqX}La;Ku9 zY`-;`_K#ox^&*;-V|VZGuOF5MRj3_Q0XlLxwEf^wra8WOb~?QN@^p57Ic&}gtFC-` zI}l&l40lsoiAo(yr&7u3q_z%`b4D%X;-%9$IdeLnT;=>h??>;)UHge<`Ejx{Y)vj| zajhDOSQBG38_!OjE_#jh{Y>pZ^)Al` zi?eB~JMTqeg-#`&`sjn5cs$Tv+O>?5P4$r%F`W8r(Yror#v{c_b8!9b0^WsoxVQ0> z4_3Dx9(3m?&$iJUQ8-Q(#54JoKe)vEy**3^?NpC=`G9_=-)O84yLc+@I@ z3Wqxs+S=XC8H?u^$HVc9y06qO+}`uwSwGzIR*h{^tyaC`G@1noDIsiA(3>miqpP#! zQ)QR3>0!-!@X^QjHvDRC_KVr<{EH)JrX{1U9jU*VE}D(W)v-SOM7~onKth@a{MDuO?d{kC zB3H%fwp&Y0KdR;{m$Biqlqn_tE5d+}RoRSwmxJqYuo;kl+-CU{d1XsM7_sfJH zvjq&biB$rz*13{)fjaA|J$KCJ*n9rMkI=|o4tUMSxGQOE=B8>TcINP(YqYiQ2SSZ5~tkBb1t& zx%P!)kl@8U_1YY1k8e)N;DRg`F?8@__o1@<}Q9#mICP z$!N*-@cmR+&NdUW|)bs>=Q9|W=7ZQz`&grH^^GNs#!oU3;xPBj&erISLtmZB-$6Dfl| z5`+v;;z_R$6#}5rPCbJcIabJ^!g27e0FKDSqS)HC`#AC;P^4!?!BgYcVt3#}x@aZ3kqx8v3VBsr5tk>?H2+yZWiJF@~q43je`d+BU6iQT(~E;|zGU`_BL5)fOo z=Sg_7dDK+UenQU@002K+5#2mYJ^QGrME6TTG-6F9Hn$_cO!rA`1x1p(*5M+6KN zk42C+gj`lZ%CpSS8s+!IMH+N2LC6WH6X-xbEqs~;d>*M@s0fftI#w}`q&}ikdE}hI z@6as=A(sXy#FtZ22kwTl66knvWmVx`%LP$OZV3`Xy#eM7Xcl)Xq>W^lrl3qA1i&aN zL4~6a1h^I`a_mZQPqerY*3!8Ab-&!Y*hq>1zER zl)}F7MXcd7j{y0xz?YWy_cLtDVr?ef-nBzdBu2_wt9IHom|Z$)sT9ibB4fkZt`&56 z_h>ow+eR@|iS2J3?(M`p2_cWwIlF4JZ(vnYhtCIhXGk$r$leo`(Lb&lFdX9d?z-Op z$;a#IB-ZDze)$dVd{~t(Sjr^>QH$~UVrY~b-JVv`dTnVV6MypKN0Ik-T&ehe(pxzD z<)_Wwv}wroyqwN-q3=4ES4XhIA%gqV$uQDBN#FY)H-GqpJKK8WWYoX;`Kv**RSg9~ zdEWKKi*{UUSOD3})h@P#D0s%sORMjMTpz5s?d4~~&dtrt9#j)q35cG1Rhf;7*0IIS z_#)2fv(tV%Dvy%~_xD#H9lRSXcRGV_pUo;}ZN-x%djE>~;+>VdnE zPuh#m`@vwkrVdUNrAI#jgve~rttidK6r_IlNPgtoUHvFv1R`tezH~l&{p|Ae>Y|z{ z*5iRVZ$b*Z!|4}a4$!m$X>5B}O4Wz|{QZL!Dc5WRjC^W1i|>EQ++i%9fGn?2ok8+! zc&Y2-sTq9xT^XXX5%5Psl}0z*etxQ!aMh}nV^LQ^PwZr8!>g~p!37~-jn#)IQhp-e zc~slJb=&VLSb;i{j$dEF!OjJOyB;6(+^|&cy?XZP#2PI-(dt%m*4T9wHj+{Ib~jJ? zsVO_naW;~uB!h>r!iSg3=_m8Ei_>l+r_QZ=epT_iWUqfCm`FtP?aNosE^3)%+>-&m z4nDS4pDnxPJ_^X_9%kz&3JZ8Y>hZaD)>G=PAHL?z#kkdjcZ(kvCWX{t&yFy+?b+-l z@dzA>SS=Fv?5*B^;(;|edv-iS7uZNEwKU{?YbH1j{ZW;DBoCYy%yN#_gfM;2C4%k> z5*~(GZ#0E?8+}>Z#BG=EV#lJ7h-YJ~&w-5-IWW;eCgw?2^QmMG<~)uUIoMrDcA)nR zb;#mF8nOYMCV3x{Zb@L`zyV0>%DD&#=|nFW4Yo

kcWj8Ss6_)7g+4{AlHHwODsmPj?d%(? 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 ITdbr1ZtNp?4T-q(!8~i-qX`grIoOhm? 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 GKm5Phpir;? literal 0 HcmV?d00001 diff --git a/board-package-source/libraries/ArdVoice/extras/assets/two.wav b/board-package-source/libraries/ArdVoice/extras/assets/two.wav new file mode 100644 index 0000000000000000000000000000000000000000..7cf9daf49c03f0ab6bec4625c60c9870992a17c2 GIT binary patch literal 3744 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 Pztj8e=>KVavF3jPof1#p literal 0 HcmV?d00001 diff --git a/board-package-source/libraries/ArdVoice/extras/vocoder/vocoder0.2.jar b/board-package-source/libraries/ArdVoice/extras/vocoder/vocoder0.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..2c5add052b62962ae639150468aa05b32a34b3e3 GIT binary patch literal 12346 zcmaKS18`>Bwr*_O>Dac_VaK+UKelb#HafPQbZpzUolaiwd+w{f?|tu_Z=vR@HO81& zHEY#3#wY&+6buar3JMAc3Xf6>=pR4>0t1o}RTiR?loex;5t5Y@6ID{Cml69M0|LSy zse|$Rh6FUDb3^z69IL5Qs9@$G@JK9lEeL;h9k}(v>%e6$jr%i}_+kPkQdMh^>B9fs z0iy9vedY65Isrn)(EAnm;x*<@I4;5Lm^8gzRnuGk2P9O#b8v$4pE0QZx#a(h3xTWf}YZvpq;7S^_gR_-=#|G^UNe_0wh7&{x+P!)uHv#4!gd70|2h39D#zuL1cKal&jzg@ZXRV{YZ)Y z&FB-5;FawYrAPWrIWB;qrMj-Q>Yyyp%fC0SpjZiu)~PfuH8*=dcC7)<&rQxft*t8- zyQ!tVw(&+GKqyUnY`d?0w^?d@KR1wpU{6KCQTmoK&S6{zHA%W=bMz^Ff5n%VT}7*;qxc+^-0lm2rDf&^IFKDa}Lo>D%2_~%CvNa^4P$N+Y0jQ%Bxf2 zH2C1Q(xO5O&m*CY#*AjaGo#6{hZ0lih(h!!#P#^?AQZ0+)V;~qD_!j0%G+B1{6S$B z9_>+YZDc~*ugEBHKilbO8y=eIVZzz(X`)1p22J6q5kcL38WZFJ{|ap(sYQwhPm#(@ z z@OYV#Al;BdTm(ZqsBUrhr*7t%#p1q9zABNisdFVAnmNMYz}_miQ!>_^`;MTz2tmC@ zzcGNb53XYR0HgWm20Dy5G~j(X$Ldle)>~K<^1Y7zh$W$7ei@l1`3g;S zqtY-CDqp@)OEjo9uZ|-F?h)-3Ohj)h1c_(H$+&w3*FCX^tZ}u4ona~4xQCoxsjvFZ z?c$gieKU*es#B)>Xzpwg-R7BkK7+rfxTHqs8mgFhlz7{nn)BRoleW0#b}ypjF8Q4L zygXHnwN>pzfsa7yta(Nl3?0wmPk>3AmW~`6KT69@d%k$2vB*Y+x^%`(x}@7h4rOIk zoimrz2*dqI2hm$5EAduwQN(4C773h^`4#MSLrb&J@_;Js^a~(#@R2}WyAA7oc^Y(# z8&M<4W+Un~df@{L?TQ_oBU*Wn0BCyx>7e#@5)aQAzZRuqZtdy(9$h({QkB`OB=ol+ zVP9u%ahfQx;*^kK13MDToCr5wjAv_T3LY6m=rWt3Dj1txizm?&vsU;PM+1{tYNOj~ zBwUY_FIM6-!HM6p{Tf2|6U%)Ln6JtklY>lHR;)YT{o%q{p7uQf@3H{W#FCIpH$NWe zABKu%`XFM~HE5@GB1Joa7lOWrrzqB#Jd9Yh*KneR9;60$zUl)cFVsYVlIt801|%(n zs6no<{VJs-A8diO3c0Tvq#r>cT_-Hi>l{JufaYy3cBi^H{oJ^nGSrBO)o?j2{?QQ8x6)C;mY$%PG+6En)SZ}(tw+9s^i1s7{9==x33m!7<4PF?Hf$1iOaP%6gSZ*FBFMA zzf27q6{w!U>o-4&7Br?w=9B{_Vr7#@J44eG;1;429~c! zMUOD%4KzSHJ8kIVK4{VOd&d(4EhCUB6Jd*tfbU81WQ`(;co1-X2FE(s@sG5IVSW7Y zL8~dcpt38w&}o4I+xze{K5`P@Z%F!aO?X~5u33Z8;_&G7BomBwR&bWzA5yDmv^E!% z)o`Jp=FV5Fu4aQ_?U}(j@z+*>30jD%Z zh-r`3)H*GmBwI$`BH%~V92ZUE92O^c0a@~GVAkwtxNnB>)wGa$yp6$|UCmK41azp6m3=4e zQxdN0A0P-f3VL(Vs(M+UpP5T?gPs&>o`vK0-z<}Sy1G^q`uiT^f|*e=Ire2~u`ZJ1 zbCEqdF6E&6645BRqMd#WK4TSTF9)^5!@z7Bge`4aa+A3xO)+W)8_mN}rQXb_oiYUz z96I4c(8UI!Ku5dG6Wl+R2yy&Y&Zy+-m!?l9Grt2Um%lxyMi%4pCiUH0nZUF_eGk-u#*lz z@9F*p-*BGwvz+h65F!ov7bJs<*YCYeQp!%iP-p7SZr6~n;U11rCBg0Lxcac>IVY$b zI$>uN+qhebI|uNp^r@AP=5WP}ZOZ;Pa#IgPVhYDIA?ebP6UxFUvQXh7^ zCL)idnQE4|zs)9bi9ZSMCyM;M3Y?HSd@?YlBOw?nPnj4Js$}nF7}XvZ0Bx0)KNr6e z8QIyk&l#@sMq8O-v@*?{v>|UuTy>jpXraom31bfy&72KAn|Nd|3he{&rW}J?r_j|> z=E$whx(GYetOmMx=Mz$n+ED;zB4U# zzMlaiz;|yLZg=+rl8fndUu$2T=1kv~2Be%GF6t+(e)Y=EJ3$7gLBPH$+#hI#JVVg! zZ4>m~rzH0n1zxoX=`mkAH<}>TU~s+Pb{#JgrxwbeisUb|U7d-%800J;?%V@^i03%?OIfF*wy^QKLWwNOK_!I=mv$z{Xa}fy{W(LD0tUl_pE=8=5p#&c#i-##M_;nwFI%H;*AV^YCH= zE)xY1KjcsgM>R969u+NhjH>jc3f*3*D0P_v3@e(NwJbxMTw-=O1#zeJi)hbqHhBRt z@doimB*MloUi0Q8##r=BQhspTC1Srqi&I9}CoAA*QhdN%`Y)ZwL(R^Cub4%D3h_P4 zqxOh3-nB7Pc#FHNbo!Ohq8f^<>EPln?T*5FV)RKcF6d zY|o@C%;wXdW?O*KBZ|Kz%E#YN?U3isJR^aVaY{>D5WXV86*fcbbjxFxgh4Decv9kE zRS=0>Dn?oszMZpdK-07@)efUJ%dRc5ysO!cy*yjknnN%U-H6FCi@YIiyNmG#)FOpr zlX$e}Vor3Gkg{h}hVm>yW7ne`dpTF^CTP)zKotd9EVDv2cpK+LMvziHOfm<*Lb4e? zTzu&!yyo9EN6$-jImB-+kduJ0Z+>dxrQ-qrUQBqqIX%Ph8w3&`+ij^1DKG{H&w+IZ zTpU){N!$OLoBJlgh$M#lYJeuD^tOCo#%ubPNH>w~Lw@QP?j7rgIzOa9GUo2_9ZDye zxZ7q>%c1UvVmC%lg6&|W&cr{_{{fS}xo2CcObYm&f+_k%0IZNOFo}WcMS@cp1#0 z{V4t{L(WEx$fPyGyuKpIL7T>`glW8UG!Su`22Vu~qamgup_<(^8)&Q4(oH{sleuKJ z=>ie*eMD$^9zM=2^8?h9V#>BC^W~Z8Rnl@9p~j!60rGNF*Bxy(|d z_%a4?>e3EMZyvf2v^lzg_T(?+I=d;q3M)I*1zBDw`bM)kZdbk!bIR8qYrlENYEHd5 zjpBA7^T2Ff3K_Rc&B|CED5htiGZkWdy9Qhu+y-jn5qHgQ@Wd3AUukqRlVqZtFF)PL zq~v|(cFhca%+nz81~!#|!_OZw3ge-+(vcZ!P!r%eEQj;ORgaFRVn$)Dd=qo7v~hz? zeoI0~FhCPULit;Xc<2MH8qTyclE5&K&nl`V$n{sRgwPg^m!b@ta;Bss#7R7k!s?O3 zYdJnc;Cu51B;7O(PyK3*UgofMPL36o6Tid9Z~iD6he_PL-|nCfGBxL-o}PYXyR~6T9yz*XpMdKwPuEmfO+E~g zAI$xJv#16%DbZk9q`CztlqeWND?&7v$&IyZ$*yYO??5FgP?p2-QA?X-C_|RY){@9W zaEJo-*Q!uCBrn;mHx}&gEzXL}GZRW==6|iM`yN#n>BNQUoUVHwPi3V$9%X%f0FG#` zy*}N6nhGX@e(Z#7t>{ncS5h$J;Fm!Ui45@7&1Ougw=Q?HV8@V3pMZRN_ks3hNHDJH zH53AJH#5=fYM{jjMx8-4HQY=6w$NZ#`OR)L8Fw&7%%R0EF9!noT)Y6a6o#+|O}{(> z|$7_-@6CQ!WVx8A|N(({#X&67L*KhV)Vh790xd;CWqgaUBmIN7jXO-^ETo?`kYq z>qwiz-5ENSf;Z^ zKO@h6zF^KUv8&9r#fTUwZ<>#X{$1Q^BxVl0fx)$yOhw(iKr_#xy6HN~;TvB3$U5ts zB_i2C-Opeg@a23rPALF{=ks+Gr03~Zrh?^O3hjkl{;_v!a`P&QLAwTnWlFnkV!JIx ziD^-($_W0VmRX!f)OThqxv`V#rdkA7JK!OP@5jlP=2kZJwoe9u+U52ZRQg?wct8T}5eA329Ee%otGUQ;jDd@b_09v{T_89WZ?;Q@! zX5{|ho(BaW)qK(OxT8<(rITuLX7C79-ORT_C<-O-(oVA-2^n*pjf~l114UICvWh0O zTQg+XbL+@gu@H#^_AraObd9E}5LV`v?d~cA+-(8S@0t@w2mYA9p)#?MD6<^7VBc?m z#k!0{EVafhD57*& zal|(i?;M%g$>JdxK(@fjh_{&=*WIz^*4C!AMI%k>{p-daHg@dBOqneE6&g0SEDSL? zu?y7Ng%{5V!3;70Il+JLqR+0L%Jlhh(&WeS*KmsLbN&yi$K#NDiXyfi%U!S>L#+2v z6{l;lRrj&}>)mJUsjWurYQFNXd5lk>{UnRSnt>mRpCqukeT4HLD|XB**6Vnmvden{ z$gT8&Es1y+ws;8QVW5co;%bc$;!?@gZ;FJn`%z$DtLd8nX{F*r)|@6g1k?of5cR~9 zp1u0$LpA79XVwwyL=5_!d+DFX6WC~!lpP*0CbW z$K8{pM}iOVQ5hTYw}$Sd9PA{YMTkI>tf6C!LjWD~0*$;=blmK~yE2&YZujhJc%`=D zp(i=RltYc)wP0^(Pv3UN3r;-8e%O+}LvR1~?l~*VN@CnXZJk%4r?(akJ1ccI6~UFE z_(ncr`r;jsIbuRVqum2gsK`^)t0&GlU_WS01G2gcG+jkkQe``lvrWaeNX28{pe@^{ z(|i}QerZb1_%1W+jse3b$Tv9?Cb+s+HG^KXYRt?kG2&pUcavK!6Ikvb8F)1W1$F*9*bWjV83g<7U@X%^PvaOI(-hN zq^^gd`)$IF7O~nAx$Cc(CkjYowQe#PFk5WZFcoHV4tTKrdRYt;+>A?@KAxZ>&paV+ z#{`=&2*}IRxsg4`66-e<4wE_FXVK)oAkyXFD(tRfS%?>J}F5=+4&F~-%DmNJ+B`E;R^=ObxK zx1VU0O8q{FYAa*Ro=2B_u3#~LxXQlzj@RO7O*yQ(%#ZU2ZTxBXvuJx|RSX=>{M!$( zrG?Y|o5c>;O;mNl83Ax#^iYsDaMshGj*w2vqYIYW`YeunAnLQzGyIrzNthvqmBxG( ziq||Z-W>g5HxD&szs1}|fv(Hwb!XjL4!U96wu!Hr(!MzKu`wKVsVq)M*6m5u)W_P! zYtvoptSLossb~D9oD>E&li=p-6e@*5TJ(cB(zcDi#JTP%Rrl=|XnLNgCgt+LtH!Q- z0xwsDrl2qN~A(wTpvVQ#SnY z795=Iq4AxO6&$^p1>C9O9WpjQ(pqJT%zCbz($tL|jxVY$4&$z^x6WlQHf;<8c~ULf zk&BS|#wK*p-z51Dh4$0nT+N;}9`J8Hon&}of3Ii1sIj~-*DCGSK`l^)?yI z5zRM(w zX?J*KKe%m+*?0YxYoi@S9%4sg!p@|eiCsXKv=t%7+Rzm3+M(Ls7ENz69Qx{$cI6wT zCpS0C9CtZEu+@Bg7y94Emq+FdU_<| z#&BOC&Q-ji!FY*=`7SUT9Y1{n(k7}lgpmrcnuWczP7{97vHE0BG#r~7M!(9Dt?+3A zlCz@gt+W29VsGSj#Cui-lODeC`17yUz|%A4^#S2uOd{U0Ul@-~1g_cgcH|nynDDa6 zG_Q8sb2}PYVyc01qhSS{>HuyZ$`%Hhl>T@V5%NR|bcW4$-1B=9Oee|h$Whq&fMAw- z=;>caRCs)4bwx&xesm$8vE)gq1T=xf0GchlK zEKdphVt(($Ch}k-`Cg0?{0bACQDXnV93k_d7eWLBtJAX+m&)D4jo;Rj@YG6wcWMHr z_M@eWYHU)H4?c04ExlUD5)FHB6LfRhy;;ptv`qq^x4l7=;m-5w@%ZPFPSfC#1ig>L z&CP6f1l5*uWnRHmH9JU1hVF^#$m7u-BbAuF#cWY>i7PCiICSxIbI@qWeK(B5_U8sY^56?(@;c3T0^L%d z=(nL;8I?@U8(VXS^ZsS@g^d?Hy07|xZ7#T7__-1Qgp!kJguaexUq_UM!bO8mcqdxbh+_ZmPm(Sc@Dp1a zYL7^{*C*ZYR?qHUrNzQEWKzF#;$f;(g`aOUpVCm;&RN}^-1mv!TvM}#UC*Oo1}F`( zAls?jUUrxYs48fjXY^*g5yXdg51~Wh5jt2xV-J2SJ?uJi>Nn8MW^~M`7Exzl{B^z#xH$=m6jP&a`P(BNyUH#Ig z$`#mPD~a@zEuyc<0yd-YhVu%s;f+4O)kyeap#+Fl4>nXb97Fj*6C_UE)7}yre4ymN ziK-Sb?4lXmqWIr33*C}D{Z7hya&(yHaSO?RS%d3GL(i^fFfwWnNHp_o`F|tD=HRERHA> z)~TcNYM8IcN`x`$#yPwW^XL`r^2vu-v%T}Adrb703HFRzNmg?o_D1)1vtAT&O-ZQ6 z`HmdC=iyx7u8cOjULU|q86gVotv$*z8#p#R2e>zx)iu8(c*0of*g;9i)i$i7Jmitf zDIY|sL({F3-XPung8Yl8LTZaEs3HIXq2vCOr~YqU0pY*lsnYTyOpO1RqFUM|9isbm zdwGtVI%?Gu8F2VTB;XGDg+PFWX#4#N`UPJCBe8N})1P3>VZ{!tEUiTnMyFY`5l<=I z*{IS6MvYO`JQZdHu<%_WY-*BqUNg7025=jd)p}38TeAz5&7bx^dtZBQt#eJgPjT5! z>3JOD`GLQ*p;O`9{f_Uh@0I{uH{UEV>#;JfV6Un!Eof@_1fr9}Yh-$fbl26=$Qvo|i-FCXGOENK#C)~D$3 zWL_fsk|ISpBnY5foZ;-qZg$J3IdTzI383BETEUBnAYWNm+&zc%=dUQ*D5@_^r8jA3 zz`zqgPSi?RmVlbqN?JC9A{06|fu@hl#jT>jK&rt%IYSgycxQJB&9d)3KQ_M?5S>y4 zrIi07O6hN6gBQJYu~9hbZKB)@4@MiwAww`8FfVTdE86ow+G8egCqrx$7yi`uR@XQc z{w{1v+VV=fsVh|O$$rhNeOJF8~e)$vn6#`?jxe(>YU`%G4iotxU8ZE{Tnz{*p zoCSyYnjQg4f=9F^bZ-*}!}r1Zf-V0;b)n~9#6x)@S^YKiyBiQ2hN6Wb=4!PA{^SZ1 zYYYWjwSL`W{ul?S$yfTcLW!z+3(Fke0$aFulKUR~^{uF*rR$=J5=J&3^a}lh77DxR z`ulJ!HrKCh!^?}`di4o^Bkz%Ce~U@py~^l!=Haf@ zJ=t~rhL1f5!_5dUYwpYw2U-eoe&f}s_aiEBiw1M?(eP%`MIM`TF2rD;G zzuCxiXfx={_>Ov=R=!74{5gZC;Pre@bRnNcfe8p^kPyT}(5wOsFG(ZV@$|zg^$Sq! zxa~izhuLISngs7siY17F;fKVBQ-xo~I~@oQ*WG<4r5ZU|q+I4m>DH%s8n3!YTxnY`HAKkiH9j%6PBn@BLT3vrDbCkmR) zUaT%m+d6St$03%M!bx3SstOs~1q#J)dArN6t`i3;_}aNk+!gAG&OQbZRTtDNV$F@n znCds1_QK#6msyqePBGlq?Ny6-6Zz-AO^jL~-2Z%&Rnn6Q`0g#~_?TV2RD7Qu>h%Pu zUG9Coqp8jDQ2jfS;7!=18|BZyFN& z5;hUhq^$(ym}QYxHB+fxdb)9(!6`)ne((#E(GnYGvmj{x>ToOI#Vf-NaI4|8VUN?T zbV6IQTcatL?^b|pCm_~Rf6Q(j=d)Zy0ifnNnom6aPL`QumkOuty0U-7Po&@dDc4><_gCJosMGnZ4X~^mbcM{wL4NI(~)r|aU&9q z2Zm-_W$+4rs_*7XX@yrZSPUJv$w>kq{wKhSmZFnJzCTR8e^zs&pL;DzwX$GbQzBFq zPLW%h(FHjs^z`Ys(}zO4W?p+d4{{Kg@{d|95twqFqBVJt#>=r=;W)--BxxOmJeV?j z`lYIb>R;>27WU;vhPeX0?7u)ihRZ#>;sC#uW15U&c)7ko41kV_wBn7GEk&8u_ zbtXeNBzv4Ed=of)^VFhuq1d2WMdyFFN;U4zbHxM#>`1jl1W>1B?=I7!(u+(VuS0c8 zqWh9|(LbjgJwZx(h17@Si=H&q`1@2AlV|U8t|ZsGN`H~w)pbGc%Hub8g($z+s!d8? zhn0-R`#Toi^7Oz>n&M!Xlw%39^^A`+93Bi;t&9b5j4W-gM0?(#9d`-Zfn}_QOhTI} z-rxICZ+c=L*DMqn2FWug%JmdmFAvM zGrAa)-jz`A>G_DvRCtE6ywc4ChKgCX*oQ96z3y;B`Z4PQE5h_tB6A4!^>a#})p4wkxP=P{OlSPVEn`SS^?l85$1dV|vh+IMG`wi0`s)^`;h7o@#aY^CGiA=kG9*q%zv} zsK?w9We?J0)B1|sSV_;M5`(7tqr@=qbht_)m1sxkQAw5PdyP{tj!0ok9BIsW`h%VzIN|tru2|W4SjT|Z z_V#dKd@jx==0c`FbectG)osHBL3xItEog%Eq6z0olS^@H5=A025i)c zd~=pha90>$cTNqntt4q$bM+eL*++20262t6_z%iDQ-gj~$jCVUPkEKdk8q1yn2KN? z4VeuM|H4}I^B^OX!1IN{XAa(HP>V;cp}uQ%F8*&KK62z_daPG>TuL#y0W ziba(AsY&qfGMtfB-#89IjwB8@QXg*Sp%Dq?pUDT0aRz>hC31Skgd(Vz7{t7^MW(8- z(b`-|>S|%b72fK}6+dw`={0ma!ErF**Q*H*{nWCoHWszy$_;=QQ$#Chr7gS_NX9rw z?<8qgl^>(qqM~0MXXt2mbFYK^l&N18InBUgKUoCh`Bq{w6Fmy zVKNzhj|ij0{Ka^!Elf@__sVqu^1OxLY|Ir>X( zV}?-G#=@A$pPR+eSJh%BHImO0;a_AXs_G2Q?~lHE?T>O={s%A!8qnYJ@qfy<|B{dY zPy9PE`Cn0Bfd0MI`|l_j|4otplgD4u@4wOcr}>vu{BI%nzwhfWDfr(w`qTWU=ikEc zzvuj46z(5I$iJlFe*+8n{~zK16^j3J9sep{{*y5NRlfWiBPjnN=0A#=|BU$8DF6A@ j{vw)x!;a|xAMqcwQ~n1y#9t1Oe~#lnlj5WQ>*@ahc)|~V literal 0 HcmV?d00001 diff --git a/board-package-source/libraries/ArdVoice/keywords.txt b/board-package-source/libraries/ArdVoice/keywords.txt new file mode 100644 index 0000000..d4460af --- /dev/null +++ b/board-package-source/libraries/ArdVoice/keywords.txt @@ -0,0 +1,23 @@ +###################################### +# Syntax Coloring Map For ArdVoice +###################################### + +###################################### +# Datatypes (KEYWORD1) +###################################### + +ArdVoice KEYWORD1 + +###################################### +# Methods and Functions (KEYWORD2) +###################################### + +isVoicePlaying KEYWORD2 +playVoice KEYWORD2 +stopVoice KEYWORD2 + +###################################### +# Constants (LITERAL1) +###################################### + +# (none defined in this library) diff --git a/board-package-source/libraries/ArdVoice/library.properties b/board-package-source/libraries/ArdVoice/library.properties new file mode 100644 index 0000000..91e6abc --- /dev/null +++ b/board-package-source/libraries/ArdVoice/library.properties @@ -0,0 +1,9 @@ +name=ArdVoice +version=0.1.0 +author=Ignacio Vina +maintainer=Ignacio Vina +sentence=A library to play audio (voices) on the Arduboy game system. +paragraph=Plays PCM speech and other audio from compressed .wav data. +category=Other +url=https://github.com/igvina/ArdVoice +architectures=avr diff --git a/board-package-source/libraries/ArdVoice/src/ArdVoice.cpp b/board-package-source/libraries/ArdVoice/src/ArdVoice.cpp new file mode 100644 index 0000000..764e269 --- /dev/null +++ b/board-package-source/libraries/ArdVoice/src/ArdVoice.cpp @@ -0,0 +1,219 @@ +/* + Copyright (C) 2016 Ignacio Vina (@igvina) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + + +// ArdVoice: version 0.1 + +#include "ArdVoice.h" + +//#define SAMPLES 180 +// 7812,5 ticks/s vs 8000 Hz -> 175,78 + +#define SAMPLES 176 + +//Could be size 10 but 16 is faster for % op +#define BUFFER_SIZE 16 +uint8_t soundBuffer[BUFFER_SIZE]; + +const uint8_t *voiceName; +//MAX coeffs 10 +uint8_t numberOfCoeffs; +int16_t coeffs[10]; + +uint8_t samplesMod; + +int16_t gain; +uint8_t pitchPeriod; + +uint8_t sample_count = 1; +uint8_t sample1 = 0xFF; + + +int16_t biasOffset; +uint16_t beat; +uint16_t beat_lenght; + + +ArdVoice::ArdVoice(){}; + +void ArdVoice::playVoice(const uint8_t *audio){ + playVoice(audio, 0, 0, 1.0); +} + +void ArdVoice::playVoice(const uint8_t *audio, uint16_t startTime, uint16_t endTime, float speed){ + + + if (!isSoundInit){ + isSoundInit = true; +/* + The Arduboy2 library, or equivalent, will control the mode of the + speaker pins itself, in order to handle muting. + If the ArdVoice library is used where another library or sketch doesn't + control the speaker pins, uncomment the following two lines. +*/ +// pinMode(PIN_SPEAKER_1, OUTPUT); +// pinMode(PIN_SPEAKER_2, OUTPUT); + + TCCR4A = 0b01000010; // Fast-PWM 8-bit + TCCR4B = 0b00000001; // 62500Hz + // It is faster, but generates an annoying noise/buzz + //TCCR4B = 0b00000010; // 62500Hz / 4 + OCR4C = 0xFF; // Resolution to 8-bit (TOP=0xFF) + OCR4A = 127; +#ifdef AB_ALTERNATE_WIRING + TCCR4C = 0b01000101; + OCR4D = 127; +#endif + } + + voiceName = audio; + + byte readedByte = pgm_read_byte(&voiceName[1]); + + uint16_t chunks = ((readedByte & 0x0F) << 8) | (pgm_read_byte(&voiceName[0]) & 0xFF); + + numberOfCoeffs = (readedByte >> 4) & 0x0F; + beat = (startTime * 2/*8*/) / /*180*/45; + sample1=0; + sample_count=1; + samplesMod = (uint8_t)(SAMPLES * speed); + beat_lenght = endTime == 0 ? chunks : (endTime * 2/*8*/) / /*180*/45; + + //Init timer + TIMSK4 = 0b00000100; +} + + +//Timer +ISR(TIMER4_OVF_vect){ + + sample_count--; + + if(sample1 != 0xFF){ + if(sample_count == 0){ + // Should be sample_count = 8, but it's slow to process + sample_count = 4; + // Read LPC coeffs on first sample + if (sample1 == 0){ + // Reset buffer + memset(soundBuffer, 127, BUFFER_SIZE); + // Get array offset + uint16_t offset = 2 + beat * (2 + numberOfCoeffs); + beat++; + + // Check if voice ended + if(beat > beat_lenght){ + // Stop timer and return + OCR4A = 127; +#ifdef AB_ALTERNATE_WIRING + OCR4D = 127; +#endif + TIMSK4 = 0; + sample1 = 0xFF; + return; + } + + byte readedByte = pgm_read_byte(&voiceName[offset]); + + pitchPeriod = readedByte & 0xb10000000; + + if (pitchPeriod == 0){ + pitchPeriod = (readedByte & 0xFF) + 20; + } else { + pitchPeriod = 0; + } + + gain = ((pgm_read_byte(&voiceName[offset+1])& 0xFF));; + biasOffset = 64; + + for (uint8_t i = 0; i < numberOfCoeffs ; i++){ + readedByte = pgm_read_byte(&voiceName[offset + 2 + i]); + + if ((readedByte & 0b10000000) == 0){ + coeffs[i] =((readedByte & 0xFF) - 64); + } else{ + coeffs[i] = (((64 * 64) / ((readedByte & 0b01111111) - 64 ))); + } + //TIP: Faster to precalculate + biasOffset += coeffs[i]; + } + biasOffset *= 127; + } + + // Get next sample + + int16_t temp = pitchPeriod == 0 ? + gain * ((fastRand8())-127): + (sample1 % pitchPeriod) == 0 ? gain * 127: 0; + + uint8_t sampleOffset = sample1 % BUFFER_SIZE; + + for (uint8_t i = 0; i < numberOfCoeffs; i++) { + temp -= coeffs[i] * ((soundBuffer[(sampleOffset- i + BUFFER_SIZE - 1)%BUFFER_SIZE] & 0xFF)); + } + + temp = (temp + biasOffset) / 64; + // Fix out of range values + temp = temp < 0 ? 0 : temp > 255 ? 255 : temp; + + OCR4A = soundBuffer[sampleOffset] = temp & 0xFF; +#ifdef AB_ALTERNATE_WIRING + OCR4D = soundBuffer[sampleOffset]; +#endif + sample1++; + + // Jump to next beat + if (sample1 == samplesMod) sample1 = 0; + } + } +} + +void ArdVoice::stopVoice(){ + OCR4A = 127; +#ifdef AB_ALTERNATE_WIRING + OCR4D = 127; +#endif + TIMSK4 = 0; + sample1 = 0xFF; +} + +boolean ArdVoice::isVoicePlaying(){ + return sample1 != 0xFF; +} + +uint8_t fastRand8() { + static uint8_t state[STATE_BYTES] = { 0x87, 0xdd, 0xdc, 0x10, 0x35, 0xbc, 0x5c }; + static uint16_t c = 0x42; + static unsigned int i = 0; + uint16_t t; + uint8_t x; + + x = state[i]; + t = (uint16_t)x * MULT_LO + c; + c = t >> 8; + +#if MULT_HI + c += x; +#endif + + x = t & 255; + state[i] = x; + if (++i >= sizeof(state)) + i = 0; + return x; +} + + diff --git a/board-package-source/libraries/ArdVoice/src/ArdVoice.h b/board-package-source/libraries/ArdVoice/src/ArdVoice.h new file mode 100644 index 0000000..d60b4cb --- /dev/null +++ b/board-package-source/libraries/ArdVoice/src/ArdVoice.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2016 Ignacio Vina (@igvina) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// ArdVoice: version 0.1 + +#ifndef ARDVOICE_H +#define ARDVOICE_H + +#include + +#define PIN_SPEAKER_1 5 /**< The pin number of the first lead of the speaker */ +#ifndef AB_ALTERNATE_WIRING + #define PIN_SPEAKER_2 13 /**< The pin number of the second lead of the speaker */ +#else + #define PIN_SPEAKER_2 6 /**< Pro Micro alternative second lead of the speaker */ +#endif + +//Fast pseudoo-random number generator, it's ok for noise +#define STATE_BYTES 7 +#define MULT 0x13B /* for STATE_BYTES==6 only */ +#define MULT_LO (MULT & 255) +#define MULT_HI (MULT & 256) + +uint8_t fastRand8(); + +class ArdVoice +{ + public: + ArdVoice(); + void playVoice(const uint8_t *audio); + void playVoice(const uint8_t *audio, uint16_t startTime, uint16_t endTime, float speed); + void stopVoice(); + boolean isVoicePlaying(); + private: + boolean isSoundInit = false; + +}; + + + +#endif diff --git a/board-package-source/libraries/Arduboy-TinyFont/LICENSE b/board-package-source/libraries/Arduboy-TinyFont/LICENSE new file mode 100644 index 0000000..9735151 --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, Botond Kis +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/board-package-source/libraries/Arduboy-TinyFont/README.md b/board-package-source/libraries/Arduboy-TinyFont/README.md new file mode 100644 index 0000000..20319ea --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/README.md @@ -0,0 +1,141 @@ +# Arduboy-TinyFont +Tiny 4x4 Font for Arduboy which contains the small ASCII Table from 32 to 127. +The sprite for the font uses 192 bytes. +The last character 127 is supposed to bel `DEL` but i used it as a placeholder (■) for not found characters. + +![Preview](https://github.com/yinkou/Arduboy-TinyFont/blob/master/bitmaps/tinyfont-preview.png?raw=true "Font Preview") + +## Usage: +Make an instance of `Tinyfont` and initialize it with a screenbuffer with corresponding sizes. +Call `print()` with you c-string and position to draw text to the screen. + +#### Sample: +```cpp +Tinyfont tinyfont = Tinyfont(arduboy.sBuffer, Arduboy2::width(), Arduboy2::height()); +tinyfont.setCursor(0, 0); +tinyfont.print("The quick brown fox jumps\nover the lazy dog."); +``` + +## Dependencies: +Subclass of Arduino `Print`. + +## Customization: +You can adjust `letterSpacing` and `lineHeight`. + +#### Custom characters: +You can add custom characters above 127 (up to index 255) by using the `4x4font.png` as base. +Edit the file (or the .psd) in an image editor of your choice. But be sure to always append 8x8 pixels at the end which you can fill as you like. +Throw the new .png through a image converter and replace the sprite in `TinyfontSprite.c` with your new data. + +## Optimization: +I'm pretty sure this can be optimized since it takes a lot of space. + +#### Arduboy2::print() +`Sketch uses 7902 bytes (27%) of program storage space` + +#### Tinyfont::print() +`Sketch uses 8834 bytes (30%) of program storage space.` + +#### Both: +`Sketch uses 8918 bytes (30%) of program storage space` + + +## Table +**dec**|**hex**|**symbol** +:-----:|:-----:|:-----: +32|20|(space) +33|21|! +34|22|" +35|23|# +36|24|$ +37|25|% +38|26|& +39|27|' +40|28|( +41|29|) +42|2A|* +43|2B|+ +44|2C|; +45|2D|- +46|2E|. +47|2F|/ +48|30|0 +49|31|1 +50|32|2 +51|33|3 +52|34|4 +53|35|5 +54|36|6 +55|37|7 +56|38|8 +57|39|9 +58|3A|: +59|3B|" +60|3C|< +61|3D|= +62|3E|> +63|3F|? +64|40|@ +65|41|A +66|42|B +67|43|C +68|44|D +69|45|E +70|46|F +71|47|G +72|48|H +73|49|I +74|4A|J +75|4B|K +76|4C|L +77|4D|M +78|4E|N +79|4F|O +80|50|P +81|51|Q +82|52|R +83|53|S +84|54|T +85|55|U +86|56|V +87|57|W +88|58|X +89|59|Y +90|5A|Z +91|5B|[ +92|5C|\ +93|5D|] +94|5E|^ +95|5F|\_ +96|60|` +97|61|a +98|62|b +99|63|c +100|64|d +101|65|e +102|66|f +103|67|g +104|68|h +105|69|i +106|6A|j +107|6B|k +108|6C|l +109|6D|m +110|6E|n +111|6F|o +112|70|p +113|71|q +114|72|r +115|73|s +116|74|t +117|75|u +118|76|v +119|77|w +120|78|x +121|79|y +122|7A|z +123|7B|{ +124|7C|\\| +125|7D|} +126|7E|~ +127|7F|■ diff --git a/board-package-source/libraries/Arduboy-TinyFont/bitmaps/4x4font.psd b/board-package-source/libraries/Arduboy-TinyFont/bitmaps/4x4font.psd new file mode 100644 index 0000000000000000000000000000000000000000..bf741a10d729f23de0a18720e787c606f3885c45 GIT binary patch literal 194420 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 D7Vnv2 literal 0 HcmV?d00001 diff --git a/board-package-source/libraries/Arduboy-TinyFont/bitmaps/tinyfont-preview.png b/board-package-source/libraries/Arduboy-TinyFont/bitmaps/tinyfont-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..5acc63f2b5fbd85fc8d517df58839259c06d794a GIT binary patch literal 3712 zcmbVN2{@GbAD`MS)Y3|qzoU7^Iy2^S&6IVFYtmqi#Huv&&Wm9#GsBEX(e9Rr$K648 zLv6+TEx2>G{v|Fz>wY_xOB1-_Q5=#(TQEsIL0Y zDi{o=N^*7dg29#@g08P9FNgle9n(WYUn*QzKRyh$T0`=;40bAe6AZRe$nf?R_>y-J z01nHHO6Sl(GZBjmMZ;j*Y(-ou5DE(5G%$$4wn0o>yo`V|=r)L57GyM;O9X=%uKRf) zWxu;Ous;;Q(-F4c!ncVCPyrSwpu$BgCYw(X*&vqc5}<3zZ4?5&6e0+ED4|ejCd8R>ctI!(9*;+%u_!DS2}L0Jk!%4~gkQ2neZ^0*k9C%jU~uf&@c}s9Y4r3@xD~41rJXT1-B@lTaRlwnSb2v=-ls)BD;6&omRN-VQz+g)%OE}4L zKu4+ov_VLwjzr^-Se!Q+O~By^So9Xj_|ei(GKbCxj8ueLL)JiIG2U1V!Q6^qZvD4V z$Z~Y5fciPXWHN!o<_oB703u*Kr{`zgbT`d)A>YR1q3H1~%Jz4?_-*%(izlZ#ZajbEJzN~7 z%h>iLRVz_**68hm+RM=1cN4ivUodIQm*1SnI=0}~G>Nr6dyrEk7tUZUFzow1$Jbm%mI`ywTTfY1fD;X7-NW$?NHS?0Py?NqwW1hh|+ub4kLXLs$biMD$SkL_JSCpftiI>ZviM z#KgnYE{vq2ett&JdT1322i?bAy0!c+jocW+8y+dJ=*n$gi|8dnP%+Dv zfj$E(PNy#Vv@fge($Z9qN*lS7V4HQ0Y&p9_7SNx+FCjS!+*xAecOj%Nfb&g_tNH7+ z?nt%h4SoUnr7cyz;iOa`OtR19wySwlu(3#`yNWi%J12hCrav0VTyxR4ShZ%Y6qjb0 zfrf7SFWZ7=UvJe|x+Pau`aRzj5*yc}>p$v(WKVb1`D_Wbsw_UM>#a1L-(x^SRkB7q z+h(pe4$hfmy}Woevvx2RvJBKeZ)%iq+N-)SV&YVYwp(wN!|nSt)_n6q70~zlwMNzo z8h*xg_y9N$4Ai$r7RK0Y?b}ob%53dNzS=n~cE52d!_>4)dH3nxu3^i?hJOEjI7*E# zWg7Xsj4>ged_H*ZP!Y$lR;2rvtT!pe1=*!f&ZO>%zuSFYtlH;oMH~3x!0L#E(H*9_ ztyFItE4qYJI?Xv0u?*Kw!H zZ$?tL8&CrBo9}FCn7rXSyiuN;76&#oRP~4kLR~0S@sK`Y!}Yqy1!tPGD%A4(F_m?dU*PGy8&gA=b&s@ex(xZ;govDY#orl4fZmZJ+bvsp z_hP4_11fc7yi_uWeZNXZedpi!C|-r}%y6y@Dib2{_JVQ=H&@=M{Z`|l6Y%4D}(ug;it3jN&=rV9p^4^_)YJZyih+2Np07LyWQ6~^@4 zKsh{@U>9f+)4G3!Y2b5w&lhuXHYu_aQ#ZrzIsa7omS$%BtF69x$akC)q>~lR&9e5~ z@w!7+(ZDxJ&j+%Cvd$K#6aCf;KN#LUIaM?&4sYcDD*i$5I6!m4(f8)cH___Y%8h#5 zgpK~1{SzeVIrsMsgTd??lArVEjui;cr+e%P{f=4tq$i@a@_@)g%-zoPxX_$)Pc5;9 z1A@8Nk(!>#J3)S~$t9x2NHKio*66 z@_#;3*&+Jlp$Db&veu|`%w>X$RLOse20QoG)*d&CYbzn$lsqFjxjU9Q?2G#!KU=|{ literal 0 HcmV?d00001 diff --git a/board-package-source/libraries/Arduboy-TinyFont/bitmaps/tinyfont_8x8.png b/board-package-source/libraries/Arduboy-TinyFont/bitmaps/tinyfont_8x8.png new file mode 100644 index 0000000000000000000000000000000000000000..a19f93a0806077e340beabcc9fc4b86c411f8b16 GIT binary patch literal 690 zcmV;j0!{siP)$8pQky-lA@@PK|)))bTus=S|YD(0G(==H@m2(R|xLcpqHi{VgS>tAE-Poo;onC zldis?+HBroQVd{P*M6frcpf*#+FnJg)!h;>>UPm=C^x%9+Aa6q8ZO}!gT&Q`fDspR zonxuQ>OmU#AaS8?>tA%ap<=4~)ie zPo7^wVsJsQ7k+e!<{05301|tQ&9ZOe3V`;W=H?2)7u^{Qb(qLGsFyf+NSwSZN(^{=yz$hC z^AxD-Ydp=5{hdP1dFrQm8V37KjJhgojMK!`pGLiC$B0^e44C>&x>2{F;;F;XI=~n| zsuA78*cRdc{F^eo!g>Ik$_`tfIZ*5p9$q3&I{(>kId4pLSc~%o?dHHS>p7^Dy|6y` Y16}Y0QcwPRZvX%Q07*qoM6N<$f`+X+{Qv*} literal 0 HcmV?d00001 diff --git a/board-package-source/libraries/Arduboy-TinyFont/examples/TinyfontSample/TinyfontSample.ino b/board-package-source/libraries/Arduboy-TinyFont/examples/TinyfontSample/TinyfontSample.ino new file mode 100644 index 0000000..fa63849 --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/examples/TinyfontSample/TinyfontSample.ino @@ -0,0 +1,47 @@ +#include +#include "Tinyfont.h" + +Arduboy2 arduboy; +Tinyfont tinyfont = Tinyfont(arduboy.sBuffer, Arduboy2::width(), Arduboy2::height()); +char allLetters[101]; + +void setup() { + arduboy.begin(); + Serial.begin(9600); + + // create all ascii letters from 32-126 + size_t newLineCounter = 0; + for (size_t i = 0; i < 100; i++) { + if ((i % 26) == 0) { + allLetters[i] = '\n'; + newLineCounter++; + } + else{ + allLetters[i] = (char) (i+32) - newLineCounter; + } + } + allLetters[100] = '\0'; +} + +void loop() { + // put your main code here, to run repeatedly: + + arduboy.clear(); + + tinyfont.setCursor(1, 0); + tinyfont.print("THE QUICK BROWN FOX JUMPS\nOVER THE LAZY DOG."); + tinyfont.setCursor(1, 11); + tinyfont.print("The quick brown fox jumps\nover the lazy dog."); + + // all letters + tinyfont.setCursor(1, 22); + tinyfont.print(allLetters); + + // for comparison + arduboy.setCursor(1, 52); + arduboy.print("THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG."); + + // screen capture + Serial.write(arduboy.getBuffer(), 128 * 64 / 8); + arduboy.display(); +} diff --git a/board-package-source/libraries/Arduboy-TinyFont/keywords.txt b/board-package-source/libraries/Arduboy-TinyFont/keywords.txt new file mode 100644 index 0000000..c7744a4 --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/keywords.txt @@ -0,0 +1,7 @@ +https://github.com/yinkou/Arduboy-TinyFont + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Tinyfont KEYWORD1 diff --git a/board-package-source/libraries/Arduboy-TinyFont/library.json b/board-package-source/libraries/Arduboy-TinyFont/library.json new file mode 100644 index 0000000..9e1e081 --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/library.json @@ -0,0 +1,21 @@ +{ + "name": "Arduboy-Tinyfont", + "description": "Tiny 4x4 Font for Arduboy which contains the small ASCII Table from 32 to 127. The sprite for the font uses 192 bytes.", + "keywords": "arduboy, font, tiny, 4x4, text, display, print", + "authors": + { + "name": "Boti Kis", + "email": "not@available.com", + "url": "https://github.com/yinkou/Arduboy-TinyFont", + "maintainer": true + }, + + "repository": + { + "type": "git", + "url": "https://github.com/yinkou/Arduboy-TinyFont" + }, + "version": "3.2", + "license": "BSD-3-Clause", + "examples": "examples/TinyfontSample/TinyfontSample.ino" +} diff --git a/board-package-source/libraries/Arduboy-TinyFont/library.properties b/board-package-source/libraries/Arduboy-TinyFont/library.properties new file mode 100644 index 0000000..e6b5542 --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/library.properties @@ -0,0 +1,10 @@ +name=Arduboy-TinyFont +version=3.2 +author=Boti Kis +maintainer=Boti Kis +sentence=Tiny 4x4 Font for Arduboy which contains the small ASCII Table from 32 to 127. The sprite for the font uses 192 bytes. +paragraph=Subclasses Arduino::Print and works with all print functions. +category=Display +url=https://github.com/yinkou/Arduboy-TinyFont +architectures=avr +includes=Tinyfont.h diff --git a/board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.cpp b/board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.cpp new file mode 100644 index 0000000..80a8e8d --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.cpp @@ -0,0 +1,123 @@ +#include "Tinyfont.h" +#include "TinyfontSprite.c" + +#define TINYFONT_WIDTH 4 +#define TINYFONT_HEIGHT 4 + +Tinyfont::Tinyfont(uint8_t *screenBuffer, int16_t width, int16_t height){ + sBuffer = screenBuffer; + sWidth = width; + sHeight = height; + + // default values + lineHeight = TINYFONT_HEIGHT + 1; + letterSpacing = 1; + + cursorX = cursorY = baseX = 0; + textColor = 1; + + maskText = false; +} + +size_t Tinyfont::write(uint8_t c) { + if(c == '\n'){ + cursorX = baseX; // cr + cursorY += lineHeight; // lf + } + // check for tab + else if(c == '\t'){ + cursorX += TINYFONT_WIDTH + 5; + } + // check \n + else if (c == '\n') { + cursorX = baseX; + cursorY += lineHeight; + } + else{ + // draw char + printChar(c, cursorX, cursorY); + cursorX += TINYFONT_WIDTH + letterSpacing; + } + return 1; +} + +void Tinyfont::printChar(char c, int16_t x, int16_t y) +{ + // no need to draw at all of we're offscreen + if (x + TINYFONT_WIDTH <= 0 || x > sWidth - 1 || y + TINYFONT_HEIGHT <= 0 || y > sHeight - 1) + return; + + // check if char is available + if (((uint8_t) c) < 32 || ((uint8_t) c) > 255) c = (char)127; + + uint8_t cval = ((uint8_t) c) - 32; + + // layout lowercase letters + if (cval >= 65 && cval <= 90) y++; + + // layout comma letters + if (cval == 12 || cval == 27) y++; + + // get sprite frames + const uint8_t *letter = TINYFONT_SPRITE + ((cval/2) * 4); + + for (uint8_t i = 0; i < 4; i++ ) { + + uint8_t colData = pgm_read_byte(letter++); + if (c % 2 == 0) { + // mask upper sprite + colData &= 0x0f; + } + else{ + // for every odd character, shift pixels to get the correct character + colData >>= 4; + } + + if (maskText) { + drawByte(x+i, y, 0x0f, (textColor == 0)?1:0); + } + + drawByte(x+i, y, colData, textColor); + } +} + +void Tinyfont::drawByte(int16_t x, int16_t y, uint8_t pixels, uint8_t color){ + + uint8_t row = (uint8_t)y / 8; + + // check if byte needs to be seperated + if (((uint8_t)y)%8 == 0) { + uint8_t col = (uint8_t)x % sWidth; + if (color == 0) + sBuffer[col + row*sWidth] &= ~pixels; + else + sBuffer[col + row*sWidth] |= pixels; + } + else{ + uint8_t d = (uint8_t)y%8; + + drawByte(x, row*8, pixels << d, color); + drawByte(x, (row+1)*8, pixels >> (8-d), color); + } +} + +void Tinyfont::setCursor(int16_t x, int16_t y){ + cursorX = baseX = x; + cursorY = y; +} + +int16_t Tinyfont::getCursorX() const { + return cursorX; +} + +int16_t Tinyfont::getCursorY() const { + return cursorY; +} + +void Tinyfont::setTextColor(uint8_t color){ + textColor = color; +} + +uint8_t Tinyfont::getTextColor() const { + return textColor; +} diff --git a/board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.h b/board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.h new file mode 100644 index 0000000..669cb96 --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/src/Tinyfont.h @@ -0,0 +1,109 @@ +#ifndef TINYFONT_H +#define TINYFONT_H + +#include +#include + +/** + * Tinyfont uses a 4x4 font to print text. + * It conforms do standard ASCII letters in range from 32 to 126. + * Even tough the lowercase letters are available, the best readability + * is given with the Uppercase letters. + * + * Usage: + * Call the print() method of a Tinyfont instance. + * + * Special letters: + * \n makes a linebreak in print(). + * \t makes a 9 px long jump in print(). + */ +class Tinyfont : public Print { + public: + Tinyfont(uint8_t *screenBuffer, int16_t width, int16_t height); //!< Needs to be initialized with a screenBuffer where the height is a multiple of 8. + virtual size_t write(uint8_t); // used by the Arduino Print class + + /** \brief + * Prints a single letter in ASCII range from 32 to 126. + * + * \details + * Every character outside the range will be 127, wich is a square fallback sprite. + */ + void printChar(char c, int16_t x, int16_t y); + + + /** \brief + * Set the location of the text cursor. + * + * \param x The X coordinate, in pixels, for the new location of the text cursor. + * \param y The Y coordinate, in pixels, for the new location of the text cursor. + * + * \details + * The location of the text cursor is set the the specified coordinates. + * The coordinates are in pixels. Since the coordinates can specify any pixel + * location, the text does not have to be placed on specific rows. + * As with all drawing functions, location 0, 0 is the top left corner of + * the display. The cursor location will be the top left corner of the next + * character written. + */ + void setCursor(int16_t x, int16_t y); + + /** \brief + * Get the X coordinate of the current text cursor position. + * + * \return The X coordinate of the current text cursor position. + * + * \details + * The X coordinate returned is a pixel location with 0 indicating the + * leftmost column. + */ + int16_t getCursorX() const; + + /** \brief + * Get the Y coordinate of the current text cursor position. + * + * \return The Y coordinate of the current text cursor position. + * + * \details + * The Y coordinate returned is a pixel location with 0 indicating the + * topmost row. + */ + int16_t getCursorY() const; + + /** \brief + * Set the text foreground color. + * + * \param color The color to be used for following text. + */ + void setTextColor(uint8_t color); + + /** \brief + * Get the text foreground color. + * + * \return The color used for text. + */ + uint8_t getTextColor() const; + + /** \brief + * If set to true the pixel behind the text will be set to the opposite of textColor. + * Default is false. + */ + bool maskText; + + private: + void drawByte(int16_t x, int16_t y, uint8_t pixels, uint8_t color); + + uint8_t *sBuffer; + int16_t sWidth; + int16_t sHeight; + + int16_t cursorX; //!< Default is 0. + int16_t baseX; //!< needed for linebreak. + int16_t cursorY; //!< Default is 0. + + uint8_t textColor; // BLACK == 0, everything else is WHITE. Default is WHITE. + + uint8_t letterSpacing; //!< letterSpacing controls the distance between letters. Default is 1. + uint8_t lineHeight; //!< lineHeight controls the height between lines breakend by \n. Default is 5. +}; + +#endif diff --git a/board-package-source/libraries/Arduboy-TinyFont/src/TinyfontSprite.c b/board-package-source/libraries/Arduboy-TinyFont/src/TinyfontSprite.c new file mode 100644 index 0000000..686da16 --- /dev/null +++ b/board-package-source/libraries/Arduboy-TinyFont/src/TinyfontSprite.c @@ -0,0 +1,36 @@ + +#ifndef TINYFONT_SPRITE_H +#define TINYFONT_SPRITE_H + +#include +#include + +const unsigned char PROGMEM TINYFONT_SPRITE[] = +{ + 0x00, 0xb0, 0x00, 0x00, 0xa1, 0x70, 0xe1, 0x50, + 0x96, 0x4f, 0x26, 0x90, 0x0f, 0x1d, 0x07, 0x0c, + 0x00, 0x96, 0x69, 0x00, 0x4a, 0xe4, 0x4a, 0x00, + 0x48, 0x44, 0x40, 0x00, 0x80, 0x68, 0x10, 0x00, + 0x0f, 0x99, 0xfb, 0x8f, 0x9d, 0xbd, 0xbb, 0xfb, + 0x77, 0xd4, 0xd4, 0xdf, 0x1f, 0x1a, 0x1a, 0xfe, + 0x7f, 0x5d, 0x5d, 0xff, 0x80, 0x5a, 0x00, 0x00, + 0xa0, 0xa4, 0xaa, 0x00, 0x10, 0xba, 0x34, 0x00, + 0xff, 0x59, 0x53, 0xf3, 0xff, 0x9b, 0x9b, 0x9e, + 0xff, 0xb9, 0xb9, 0x96, 0xff, 0x95, 0x95, 0xd1, + 0x9f, 0xf4, 0x94, 0x0f, 0xfc, 0x29, 0x5f, 0x91, + 0xff, 0x18, 0x38, 0xf8, 0xff, 0x92, 0x94, 0xff, + 0xff, 0x95, 0xd5, 0xf7, 0xbf, 0xb5, 0xdd, 0xd7, + 0xf1, 0x8f, 0x81, 0xf1, 0xf7, 0x88, 0xc8, 0xf7, + 0x79, 0xc6, 0x46, 0x79, 0x09, 0xfd, 0x9b, 0x09, + 0x01, 0x96, 0xf8, 0x00, 0x82, 0x81, 0x82, 0x80, + 0x50, 0x71, 0x62, 0x00, 0x77, 0x56, 0x56, 0x00, + 0x76, 0x76, 0x37, 0x00, 0xa2, 0xb7, 0x73, 0x01, + 0x07, 0x72, 0x06, 0x00, 0x78, 0x27, 0x50, 0x00, + 0x73, 0x34, 0x74, 0x00, 0x77, 0x51, 0x76, 0x00, + 0x7f, 0x55, 0xf7, 0x00, 0x47, 0x71, 0x10, 0x00, + 0x32, 0x47, 0x72, 0x00, 0x73, 0x64, 0x73, 0x00, + 0x15, 0xa2, 0x75, 0x00, 0x61, 0x67, 0x94, 0x00, + 0x00, 0x9f, 0x60, 0x60, 0xf4, 0xf2, 0xf6, 0xf2, +}; + +#endif diff --git a/board-package-source/libraries/ArduboyTones/LICENSE.txt b/board-package-source/libraries/ArduboyTones/LICENSE.txt new file mode 100644 index 0000000..f08ad19 --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2017 Scott Allen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/board-package-source/libraries/ArduboyTones/README.md b/board-package-source/libraries/ArduboyTones/README.md new file mode 100644 index 0000000..2485b40 --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/README.md @@ -0,0 +1,222 @@ +# The ArduboyTones Library + +The ArduboyTones library is maintained in a git repository hosted on [GitHub](https://github.com/) at: + +https://github.com/MLXXXp/ArduboyTones + +ArduboyTones is a library for playing tones and tone sequences, intended to be used with the Arduino based [Arduboy miniature game system](https://www.arduboy.com/) (but could be used with other Arduino boards). + +## Description + +**ArduboyTones** is a small, efficient library which generates tones and tone sequences on a speaker attached to digital output pins. It is intended to be used by games and other sketches written for the Arduboy, so the pins (and timer) used are *hard coded* for the Arduboy, and thus aren't specified in any functions. + +Like the [Arduino built in *tone()* function](https://www.arduino.cc/en/Reference/Tone), the tones are simple square waves generated by toggling a pin digitally high and low with a 50% duty cycle. Also like Arduino *tone()*, once started, interrupts are used so that the sound plays in the background while the *real* code continues to run. + +ArduboyTones has equivalents to Arduino [*tone()*](https://www.arduino.cc/en/Reference/Tone) and [*noTone()*](https://www.arduino.cc/en/Reference/NoTone) and additionally: + +- As well as a single tone, the *tone()* function can play two or three tones, in sequence, with a single call. +- Includes functions to play a tone sequence of any length, specified by an array located in either program memory ([PROGMEM](https://www.arduino.cc/en/Reference/PROGMEM)) or RAM. The array can be optionally terminated with a *repeat* command so the sequence will repeat continuously unless stopped by using *noTone()* or a new tone or sequence is started. +- Each tone can specify that it's to be played at either normal or a higher volume. High volume is accomplished by taking advantage of the speaker being wired across two pins and toggling each pin opposite to the other, which will generate twice the normal voltage across the speaker. For normal volume, one pin is toggled while the other is held low. +- A function is available to set flags to ignore the individual volume setting in each tone, so that all tones will play at either normal or high volume. +- Tone sequences can include intervals of silence (musical rests). +- Includes a global *mute* capability by using a callback function, specified by the sketch, which indicates sound is to be muted. When muted, the sketch can continue to call functions to produce tones in the usual way but the speaker will remain silent. It is intended that the Arduboy2 Library's *audio.enabled()* function, or something similar, be used as this function. +- A function is provided which will return `true` if tones are playing or `false` if the sequence has completed. + +Note that even with all these features, ArduboyTones will use significantly less code space than using Arduino *tone()* functions. + +### Converting MIDI files + +A separate command line utility program, [midi2tones](https://github.com/MLXXXp/midi2tones), is available. It will convert [standard MIDI files](https://www.midi.org/articles/about-midi-part-4-midi-files) to ArduboyTones format when the `-o2` option is specified. + +## Installation + +The library can be installed using the Arduino IDE library manager: + +- In the Arduino IDE select from the menus: `Sketch > Include Library > Manage Libraries...` +- In the Library Manager *Filter your search...* field enter *arduboytones*. +- Click somewhere within the ArduboyTones entry. +- Click on the *Install* button. + +For more library installation information see + +[Installing Additional Arduino Libraries - Using the Library Manager](https://www.arduino.cc/en/Guide/Libraries#toc3) + +## Using the library + +### Setting up + +Include the library using + +```cpp +#include +``` + +You must then create an *ArduboyTones* object which specifies the callback function used for muting. The function is a required parameter. It must return a *boolean* (or *bool*) value which will be `true` if sound should be played, or `false` if all sounds should be muted. In this document the *ArduboyTones* object will be named *sound*. The *audio.enabled()* function of the *Arduboy* library will be used for the mute callback. The *Arduboy* object will be named *arduboy*. + +So, to set things up we can use: + +```cpp +#include +#include + +Arduboy2 arduboy; +ArduboyTones sound(arduboy.audio.enabled); +``` + +### Specifying tones + +Each tone is specified by a frequency and duration pair, the same as with Arduino *tone()*. Like *tone()*, the frequency is specified in hertz (Hz, cycles per second). The duration is in milliseconds (actually very slightly shorter; see below). + +There are some small differences between the Arduino *tone()* and the ArduboyTones frequency and duration parameters. + +#### Frequency + +- ArduboyTones can only play frequencies between 16 Hz and 32767 Hz. Arduino *tone()* allows a greater range. +- For efficiency, ArduboyTones uses a single clock prescaler value for the timer. The result is that very high frequencies may be a bit less accurate than what Arduino *tone()* would produce. It likely won't be noticeable for the range of frequencies that will mainly be used. +- With ArduboyTones, you can use a frequency value of 0 to indicate silence (a musical rest) for the duration specified. +- You can indicate that a tone should sound at a higher volume by adding the defined value *TONE_HIGH_VOLUME* to the desired frequency. + +#### Duration + +- To make the code smaller and more efficient, durations are actually in 1024ths of a second instead of 1000ths (milliseconds). See the note near the end of this document for a detailed explanation. +- With ArduboyTones, a tone's duration is specified as an unsigned int (16 bits) instead of an unsigned long (32 bits). This means the maximum duration allowed is 65535 (65 seconds). Like Arduino *tone()* a duration of 0 indicates forever, which can be stopped by *noTone()* or replaced by a new tone or sequence call. + +#### Defines for musical notes + + ArduboyTones includes file *ArduboyTonesPitches.h* which will automatically be included by *ArduboyTones.h*. *ArduboyTonesPitches.h* provides frequency values for musical notes based on A4 = 440 Hz. + +The format is: + +`NOTE_` + +*NOTE_REST* is defined as 0 and can be used for a musical rest. + +There are no flats. You have to use the sharp note equivalent. + +Notes are define over the range of C0 (16 Hz) to B9 (15804 Hz) + +Examples: `NOTE_C3 NOTE_GS4 NOTE_B5H NOTE_DS6H` + +### Functions + +All functions are members of class *ArduboyTones*, so you must remember to reference each function with the object name. +Example: `sound.tone(1000, 500);` + +---------- + +Play a tone forever or until interrupted: + +`void tone(frequency)` + +Play a single tone for the duration. Duration can be 0 (forever): + +`void tone(frequency, duration)` + +Play two tones in sequence: + +`void tone(freq1, dur1, freq2, dur2)` + +Play three tones in sequence: + +`void tone(freq1, dur1, freq2, dur2, freq3, dur3)` + +---------- + +Play a tone sequence from frequency/duration pairs in an array in program memory: + +`void tones(arrayInProgram)` + +The array must end with a single value of either *TONES_END*, to end the sequence, or *TONES_REPEAT* to continuously repeat from beginning to end. + +Example: + +```cpp +const uint16_t song1[] PROGMEM = { + 220,1000, 0,250, 440,500, 880,2000, + TONES_END }; + +sound.tones(song1); +``` + +---------- + +The same as *tones()* above except the frequency/duration pairs are in an array in RAM instead of in program memory: + +`void tonesInRAM(arrayInRAM)` + + Generally, the only reason to use *tonesInRAM()* instead of *tones()* would be if dynamically altering the contents of the array is required. + +Example: + +```cpp +uint16_t song2[] = { + NOTE_A3,1000, NOTE_REST,250, NOTE_A4,500, NOTE_A5,2000, + TONES_REPEAT }; + +sound.tonesInRAM(song2); +``` + +---------- + +Stop playing the tone or sequence: + +`void noTone()` + +If called when nothing is playing, it will do nothing. + +---------- + +Set the volume to always be normal, always high, or tone controlled: + +`void volumeMode(mode)` + +The following values for *mode* should be used: + +- *VOLUME_IN_TONE* - Each tone will play at the volume specified in the tone itself. This is the default. +- *VOLUME_ALWAYS_NORMAL* - All tones will play at normal volume level regardless of what's specified in the tones. +- *VOLUME_ALWAYS_HIGH* - All tones will play at high volume level regardless of what's specified in the tones. + +---------- + +Check if a tone or tone sequence is playing: + +`boolean playing()` + +Returns `true` if playing (even if sound is muted). + +---------- + +### Notes and Hints + +#### Example sketch + +The ArduboyTones library contains an example sketch *ArduboyTonesTest* in the *examples* folder. It was primarily written to test the library but the code can be examined and uploaded for examples of using all the functions. It uses the [*Arduboy2*](https://github.com/MLXXXp/Arduboy2) library, which must be installed to compile the sketch. *ArduboyTonesTest* can be loaded into the Arduino IDE using the menus: + +`File > Examples > ArduboyTones > ArduboyTonesTest` + +#### Frequencies and durations work the same everywhere + +You can use rests and infinite durations in *tone()* functions the same as in sequence arrays. Most of the time this wouldn't be useful, however... + +- A rest would only be useful in the middle of a three tone *tone()* function, to play two tones with a rest between them. Or maybe on the end, if you were chaining *tone()* functions by using *playing()* to wait for each one to end, and then starting the next one immediately. +- A duration of 0 (forever) is only useful on the last tone of a sequence, even in an array. +- You can use *TONES_REPEAT* (and even *TONES_END*) in place of a frequency in a *tone()* function. In this case the mandatory duration value would be ignored. About the only place this might be useful would be using *TONES_REPEAT* at the end of a three tone *tone()* function, to play two tones repeatedly. For instance, two tones repeated could be used when a character starts walking and then *noTone()* could be called when the character stopped. + +Something to consider for all of the above points, though: + +Using a two or three tone array in program memory with *tones()* is likely more efficient than using a two or three tone *tone()* function. The two and three tone *tone()* functions were only added to make things easier and quick for sketches where code size isn't an issue. + +#### Why durations aren't exactly in milliseconds + +Ideally, to match Arduino *tone()*, durations should be given in 1000ths of a second (milliseconds). However, ArduboyTones treats durations as being in 1024ths of a second. Here's why: + +To calculate internal timing values for a duration given in milliseconds, a divide by 500 on an *unsigned long* (32 bit) number is required, which is what Arduino *tone()* does. On an 8 bit processor without any native divide instructions, this is slow and takes a fair amount of code. On the other hand, a divide by 512 is easily and quickly accomplished by simply shifting the value right 9 bits. This is what ArduboyTones does, at the expense of durations being about 2.34% shorter than the same value would be with Arduino *tone()*. + +In most circumstances, the slightly shorter durations will likely be unnoticeable. If a duration needs to be precise, the required value can be calculated by multiplying the desired duration, in milliseconds, by 1.024. + +#### Use with the Arduboy Development Kit (DevKit) version + +ArduboyTones will work with the Arduboy DevKit. The DevKit is limited to controlling only one pin for the speaker, so all tones will sound at normal volume. The high volume setting in tones will be ignored, and calls to *volumeMode()* will have no effect. + +---------- + diff --git a/board-package-source/libraries/ArduboyTones/examples/ArduboyTonesTest/ArduboyTonesTest.ino b/board-package-source/libraries/ArduboyTones/examples/ArduboyTonesTest/ArduboyTonesTest.ino new file mode 100644 index 0000000..e0208bb --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/examples/ArduboyTonesTest/ArduboyTonesTest.ino @@ -0,0 +1,228 @@ +// Sketch for testing the ArduboyTones library + +#include +#include + +Arduboy2 arduboy; +ArduboyTones sound(arduboy.audio.enabled); + +#define BUTTON_DELAY 200 + +byte circlePos = 7; + +#define NDUR 100 +const uint16_t allNotes[] PROGMEM = { + NOTE_C0H,NDUR, NOTE_CS0,NDUR, NOTE_D0,NDUR, NOTE_DS0,NDUR, NOTE_E0,NDUR, NOTE_F0,NDUR, + NOTE_FS0,NDUR, NOTE_G0,NDUR, NOTE_GS0,NDUR, NOTE_A0,NDUR, NOTE_AS0,NDUR, NOTE_B0,NDUR, + NOTE_C1H,NDUR, NOTE_CS1,NDUR, NOTE_D1,NDUR, NOTE_DS1,NDUR, NOTE_E1,NDUR, NOTE_F1,NDUR, + NOTE_FS1,NDUR, NOTE_G1,NDUR, NOTE_GS1,NDUR, NOTE_A1,NDUR, NOTE_AS1,NDUR, NOTE_B1,NDUR, + NOTE_C2H,NDUR, NOTE_CS2,NDUR, NOTE_D2,NDUR, NOTE_DS2,NDUR, NOTE_E2,NDUR, NOTE_F2,NDUR, + NOTE_FS2,NDUR, NOTE_G2,NDUR, NOTE_GS2,NDUR, NOTE_A2,NDUR, NOTE_AS2,NDUR, NOTE_B2,NDUR, + NOTE_C3H,NDUR, NOTE_CS3,NDUR, NOTE_D3,NDUR, NOTE_DS3,NDUR, NOTE_E3,NDUR, NOTE_F3,NDUR, + NOTE_FS3,NDUR, NOTE_G3,NDUR, NOTE_GS3,NDUR, NOTE_A3,NDUR, NOTE_AS3,NDUR, NOTE_B3,NDUR, + NOTE_C4H,NDUR, NOTE_CS4,NDUR, NOTE_D4,NDUR, NOTE_DS4,NDUR, NOTE_E4,NDUR, NOTE_F4,NDUR, + NOTE_FS4,NDUR, NOTE_G4,NDUR, NOTE_GS4,NDUR, NOTE_A4,NDUR, NOTE_AS4,NDUR, NOTE_B4,NDUR, + NOTE_C5H,NDUR, NOTE_CS5,NDUR, NOTE_D5,NDUR, NOTE_DS5,NDUR, NOTE_E5,NDUR, NOTE_F5,NDUR, + NOTE_FS5,NDUR, NOTE_G5,NDUR, NOTE_GS5,NDUR, NOTE_A5,NDUR, NOTE_AS5,NDUR, NOTE_B5,NDUR, + NOTE_C6H,NDUR, NOTE_CS6,NDUR, NOTE_D6,NDUR, NOTE_DS6,NDUR, NOTE_E6,NDUR, NOTE_F6,NDUR, + NOTE_FS6,NDUR, NOTE_G6,NDUR, NOTE_GS6,NDUR, NOTE_A6,NDUR, NOTE_AS6,NDUR, NOTE_B6,NDUR, + NOTE_C7H,NDUR, NOTE_CS7,NDUR, NOTE_D7,NDUR, NOTE_DS7,NDUR, NOTE_E7,NDUR, NOTE_F7,NDUR, + NOTE_FS7,NDUR, NOTE_G7,NDUR, NOTE_GS7,NDUR, NOTE_A7,NDUR, NOTE_AS7,NDUR, NOTE_B7,NDUR, + NOTE_C8H,NDUR, NOTE_CS8,NDUR, NOTE_D8,NDUR, NOTE_DS8,NDUR, NOTE_E8,NDUR, NOTE_F8,NDUR, + NOTE_FS8,NDUR, NOTE_G8,NDUR, NOTE_GS8,NDUR, NOTE_A8,NDUR, NOTE_AS8,NDUR, NOTE_B8,NDUR, + NOTE_C9H,NDUR, NOTE_CS9,NDUR, NOTE_D9,NDUR, NOTE_DS9,NDUR, NOTE_E9,NDUR, NOTE_F9,NDUR, + NOTE_FS9,NDUR, NOTE_G9,NDUR, NOTE_GS9,NDUR, NOTE_A9,NDUR, NOTE_AS9,NDUR, NOTE_B9,NDUR, + TONES_REPEAT +}; + +const uint16_t sound1[] PROGMEM = { + NOTE_C1,500, NOTE_C1H,500, NOTE_G1,500, NOTE_G1H,500, + NOTE_C2,500, NOTE_C2H,500, NOTE_G2,500, NOTE_G2H,500, + NOTE_C3,500, NOTE_C3H,500, NOTE_G3,500, NOTE_G3H,500, + NOTE_C4,500, NOTE_C4H,500, NOTE_G4,500, NOTE_G4H,500, + NOTE_C5,500, NOTE_C5H,500, NOTE_G5,500, NOTE_G5H,500, + NOTE_C6,500, NOTE_C6H,500, NOTE_G6,500, NOTE_G6H,500, + NOTE_C7,500, NOTE_C7H,500, NOTE_G7,500, NOTE_G7H,500, + NOTE_C8,500, NOTE_C8H,500, NOTE_G8,500, NOTE_G8H,500, + NOTE_C9,500, NOTE_C9H,500, NOTE_G9,500, NOTE_G9H,500, + TONES_END +}; + +uint16_t inRAM[] = { + NOTE_E4,400, NOTE_D4,200, NOTE_C4,400, NOTE_REST,200, NOTE_D4,200, + NOTE_C4,300, NOTE_REST,100, NOTE_C4,300, NOTE_REST,100, NOTE_E4,300, + NOTE_REST,100, NOTE_G4,300, NOTE_REST,100, NOTE_F4,300, NOTE_REST,100, + NOTE_A4,300, NOTE_REST,100, NOTE_D5H,200, NOTE_REST,200, NOTE_D5H,200, + NOTE_REST,1500, + TONES_REPEAT +}; + +void setup() { + arduboy.begin(); +} + +void loop() { + boolean newNotes; + + displayAudio(); + while(true) { + moveCircle(); + if (arduboy.pressed(UP_BUTTON)) { + arduboy.audio.on(); + displayAudio(); + } + if (arduboy.pressed(DOWN_BUTTON)) { + arduboy.audio.off(); + displayAudio(); + } + if (arduboy.pressed(B_BUTTON)) { + delay(BUTTON_DELAY); + break; + } + } + + sound.tone(1000); + arduboy.clear(); + arduboy.print("tone(1000)\n\nB: noTone()\n delay(1000)\n break"); + while (sound.playing()) { + moveCircle(); + if (arduboy.pressed(B_BUTTON)) { + sound.noTone(); + delay(1000); + break; + } + } + + sound.tone(500, 4000); + arduboy.clear(); + arduboy.print("tone(500, 4000)\n\nB: break"); + while (sound.playing()) { + moveCircle(); + if (arduboy.pressed(B_BUTTON)) { + delay(BUTTON_DELAY); + break; + } + } + + sound.tone(NOTE_C4,500, NOTE_C5H,5000); + arduboy.clear(); + arduboy.print("tone(C4,500,C5H,5000)\n\nB: noTone(), break"); + while (sound.playing()) { + moveCircle(); + if (arduboy.pressed(B_BUTTON)) { + sound.noTone(); + delay(BUTTON_DELAY); + break; + } + } + + sound.tone(NOTE_C7H,500, NOTE_REST,1000, NOTE_C6,5000); + arduboy.clear(); + arduboy.print("tone(C7H,500,\n REST,1000,\n C6,6000)\n\nB: noTone(), break"); + while (sound.playing()) { + moveCircle(); + if (arduboy.pressed(B_BUTTON)) { + sound.noTone(); + delay(BUTTON_DELAY); + break; + } + } + + sound.tones(allNotes); + arduboy.clear(); + arduboy.print("tones(allNotes)\n\nA: noTone(), again\nUP: again\nB: break"); + while (sound.playing()) { + moveCircle(); + if (arduboy.pressed(A_BUTTON)) { + sound.noTone(); + sound.tones(allNotes); + } + if (arduboy.pressed(UP_BUTTON)) { + sound.tones(allNotes); + } + if (arduboy.pressed(B_BUTTON)) { + delay(BUTTON_DELAY); + break; + } + } + + newNotes = false; + inRAM[34] = inRAM[38] = NOTE_D5H; + sound.tonesInRAM(inRAM); + arduboy.clear(); + arduboy.print("tonesInRAM(inRAM)\n\nA: change notes\nB: break"); + while (sound.playing()) { + moveCircle(); + if (arduboy.pressed(A_BUTTON)) { + newNotes = !newNotes; + if (newNotes) { + inRAM[34] = inRAM[38] = NOTE_C5H; + } + else { + inRAM[34] = inRAM[38] = NOTE_D5H; + } + delay(BUTTON_DELAY); + } + if (arduboy.pressed(B_BUTTON)) { + delay(BUTTON_DELAY); + break; + } + } + + sound.tones(sound1); + arduboy.clear(); + arduboy.print("volumeMode(IN_TONES)\ntones(sound1)\n\nB: break"); + while(sound.playing()) { + moveCircle(); + if (arduboy.pressed(B_BUTTON)) { + delay(BUTTON_DELAY); + break; + } + } + + sound.volumeMode(VOLUME_ALWAYS_NORMAL); + sound.tones(sound1); + arduboy.clear(); + arduboy.print("volumeMode(NORMAL)\ntones(sound1)\n\nB: noTone(), break"); + while(sound.playing()) { + moveCircle(); + if (arduboy.pressed(B_BUTTON)) { + sound.noTone(); + delay(BUTTON_DELAY); + break; + } + } + + sound.volumeMode(VOLUME_ALWAYS_HIGH); + sound.tones(sound1); + arduboy.clear(); + arduboy.print("volumeMode(HIGH)\ntones(sound1)\n\nB: break"); + while(sound.playing()) { + moveCircle(); + if (arduboy.pressed(B_BUTTON)) { + delay(BUTTON_DELAY); + break; + } + } + sound.volumeMode(VOLUME_IN_TONE); +} + +void moveCircle() { + arduboy.fillCircle(circlePos, 54, 7, BLACK); + circlePos += 8; + if (circlePos > 119) { + circlePos = 7; + } + arduboy.fillCircle(circlePos, 54, 7, WHITE); + arduboy.display(); + delay(100); +} + +void displayAudio() { + arduboy.clear(); + arduboy.print("Audio enabled: "); + arduboy.print(arduboy.audio.enabled() ? "YES" : "NO"); + arduboy.print("\n\nUP: enable\nDOWN: disable\nB: break"); + arduboy.invert(!arduboy.audio.enabled()); +} + diff --git a/board-package-source/libraries/ArduboyTones/extras/Doxyfile b/board-package-source/libraries/ArduboyTones/extras/Doxyfile new file mode 100644 index 0000000..2013056 --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/extras/Doxyfile @@ -0,0 +1,329 @@ +# Doxyfile 1.8.11 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "ArduboyTones Library" +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = ./doxygen +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 2 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = ino=C++ +MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ./src ./README.md +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ *.h *.hh *.hxx *.hpp *.h++ +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = ./README.md +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_OPTIONS = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 245 +HTML_COLORSTYLE_SAT = 90 +HTML_COLORSTYLE_GAMMA = 95 +HTML_TIMESTAMP = YES +HTML_DYNAMIC_SECTIONS = YES +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = YES +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = YES +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/board-package-source/libraries/ArduboyTones/extras/docs/FILE_DESCRIPTIONS.md b/board-package-source/libraries/ArduboyTones/extras/docs/FILE_DESCRIPTIONS.md new file mode 100644 index 0000000..554007c --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/extras/docs/FILE_DESCRIPTIONS.md @@ -0,0 +1,22 @@ +# File Descriptions + +Documentation for files contained in this repository which aren't self explanatory. + +### /library.properties + +Provides information so that this library can be installed and updated in the Arduino IDE using the [Library Manager](https://www.arduino.cc/en/Guide/Libraries#toc3). + +The value of *version* must be set to the latest stable tagged release. This should be changed and commited just before tagging the new release. + +See the [Arduino IDE 1.5: Library specification](https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification) for details. + +### /library.json + +This JSON file is a manifest used by the [PlatformIO IDE](http://platformio.org/) to make this library available in its [Library Manager](http://docs.platformio.org/en/latest/librarymanager/index.html). + +The value of *version* must be set to the latest stable tagged release. This should be changed and commited just before tagging the new release. + +See the [PlatformIO library.json](http://docs.platformio.org/en/latest/librarymanager/config.html) documentation for details. + +---------- + diff --git a/board-package-source/libraries/ArduboyTones/keywords.txt b/board-package-source/libraries/ArduboyTones/keywords.txt new file mode 100644 index 0000000..bcde966 --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/keywords.txt @@ -0,0 +1,30 @@ +###################################### +# Syntax Coloring Map For ArduboyTones +###################################### + +###################################### +# Datatypes (KEYWORD1) +###################################### + +ArduboyTones KEYWORD1 + +###################################### +# Methods and Functions (KEYWORD2) +###################################### + +playing KEYWORD2 +tone KEYWORD2 +tones KEYWORD2 +tonesInRAM KEYWORD2 +volumeMode KEYWORD2 + +###################################### +# Constants (LITERAL1) +###################################### + +TONES_END LITERAL1 +TONES_REPEAT LITERAL1 +TONE_HIGH_VOLUME LITERAL1 +VOLUME_ALWAYS_HIGH LITERAL1 +VOLUME_ALWAYS_NORMAL LITERAL1 +VOLUME_IN_TONE LITERAL1 diff --git a/board-package-source/libraries/ArduboyTones/library.json b/board-package-source/libraries/ArduboyTones/library.json new file mode 100644 index 0000000..fb6efee --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/library.json @@ -0,0 +1,14 @@ +{ + "name": "ArduboyTones", + "keywords": "arduboy, game, sound, music", + "description": "A library for playing a sequence of tones, intended for use with the Arduboy game system", + "repository": + { + "type": "git", + "url": "https://github.com/MLXXXp/ArduboyTones.git" + }, + "version": "1.0.3", + "exclude": "extras", + "frameworks": "arduino", + "platforms": "atmelavr" +} diff --git a/board-package-source/libraries/ArduboyTones/library.properties b/board-package-source/libraries/ArduboyTones/library.properties new file mode 100644 index 0000000..5cfec80 --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/library.properties @@ -0,0 +1,9 @@ +name=ArduboyTones +version=1.0.3 +author=Scott Allen +maintainer=Scott Allen +sentence=A library for playing a sequence of tones, intended for use with the Arduboy game system. +paragraph=Plays one or more tones in sequence. Driven by interrupts, so audio plays in the background while the "real" program runs in the foreground. Written to minimize code size by specifically targeting the processor and pins of the Arduboy. +category=Other +url=https://github.com/MLXXXp/ArduboyTones +architectures=avr diff --git a/board-package-source/libraries/ArduboyTones/src/ArduboyTones.cpp b/board-package-source/libraries/ArduboyTones/src/ArduboyTones.cpp new file mode 100644 index 0000000..8b56dde --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/src/ArduboyTones.cpp @@ -0,0 +1,287 @@ +/** + * @file ArduboyTones.cpp + * \brief An Arduino library for playing tones and tone sequences, + * intended for the Arduboy game system. + */ + +/***************************************************************************** + ArduboyTones + +An Arduino library to play tones and tone sequences. + +Specifically written for use by the Arduboy miniature game system +https://www.arduboy.com/ +but could work with other Arduino AVR boards that have 16 bit timer 3 +available, by changing the port and bit definintions for the pin(s) +if necessary. + +Copyright (c) 2017 Scott Allen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*****************************************************************************/ + +#include "ArduboyTones.h" + +// pointer to a function that indicates if sound is enabled +static bool (*outputEnabled)(); + +static volatile long durationToggleCount = 0; +static volatile bool tonesPlaying = false; +static volatile bool toneSilent; +#ifdef TONES_VOLUME_CONTROL +static volatile bool toneHighVol; +static volatile bool forceHighVol = false; +static volatile bool forceNormVol = false; +#endif + +static volatile uint16_t *tonesStart; +static volatile uint16_t *tonesIndex; +static volatile uint16_t toneSequence[MAX_TONES * 2 + 1]; +static volatile bool inProgmem; + + +ArduboyTones::ArduboyTones(boolean (*outEn)()) +{ + outputEnabled = outEn; + + toneSequence[MAX_TONES * 2] = TONES_END; + + bitClear(TONE_PIN_PORT, TONE_PIN); // set the pin low + bitSet(TONE_PIN_DDR, TONE_PIN); // set the pin to output mode +#ifdef TONES_2_SPEAKER_PINS + bitClear(TONE_PIN2_PORT, TONE_PIN2); // set pin 2 low + bitSet(TONE_PIN2_DDR, TONE_PIN2); // set pin 2 to output mode +#endif +} + +void ArduboyTones::tone(uint16_t freq, uint16_t dur) +{ + bitWrite(TIMSK3, OCIE3A, 0); // disable the output compare match interrupt + inProgmem = false; + tonesStart = tonesIndex = toneSequence; // set to start of sequence array + toneSequence[0] = freq; + toneSequence[1] = dur; + toneSequence[2] = TONES_END; // set end marker + nextTone(); // start playing +} + +void ArduboyTones::tone(uint16_t freq1, uint16_t dur1, + uint16_t freq2, uint16_t dur2) +{ + bitWrite(TIMSK3, OCIE3A, 0); // disable the output compare match interrupt + inProgmem = false; + tonesStart = tonesIndex = toneSequence; // set to start of sequence array + toneSequence[0] = freq1; + toneSequence[1] = dur1; + toneSequence[2] = freq2; + toneSequence[3] = dur2; + toneSequence[4] = TONES_END; // set end marker + nextTone(); // start playing +} + +void ArduboyTones::tone(uint16_t freq1, uint16_t dur1, + uint16_t freq2, uint16_t dur2, + uint16_t freq3, uint16_t dur3) +{ + bitWrite(TIMSK3, OCIE3A, 0); // disable the output compare match interrupt + inProgmem = false; + tonesStart = tonesIndex = toneSequence; // set to start of sequence array + toneSequence[0] = freq1; + toneSequence[1] = dur1; + toneSequence[2] = freq2; + toneSequence[3] = dur2; + toneSequence[4] = freq3; + toneSequence[5] = dur3; + // end marker was set in the constructor and will never change + nextTone(); // start playing +} + +void ArduboyTones::tones(const uint16_t *tones) +{ + bitWrite(TIMSK3, OCIE3A, 0); // disable the output compare match interrupt + inProgmem = true; + tonesStart = tonesIndex = (uint16_t *)tones; // set to start of sequence array + nextTone(); // start playing +} + +void ArduboyTones::tonesInRAM(uint16_t *tones) +{ + bitWrite(TIMSK3, OCIE3A, 0); // disable the output compare match interrupt + inProgmem = false; + tonesStart = tonesIndex = tones; // set to start of sequence array + nextTone(); // start playing +} + +void ArduboyTones::noTone() +{ + bitWrite(TIMSK3, OCIE3A, 0); // disable the output compare match interrupt + TCCR3B = 0; // stop the counter + bitClear(TONE_PIN_PORT, TONE_PIN); // set the pin low +#ifdef TONES_VOLUME_CONTROL + bitClear(TONE_PIN2_PORT, TONE_PIN2); // set pin 2 low +#endif + tonesPlaying = false; +} + +void ArduboyTones::volumeMode(uint8_t mode) +{ +#ifdef TONES_VOLUME_CONTROL + forceNormVol = false; // assume volume is tone controlled + forceHighVol = false; + + if (mode == VOLUME_ALWAYS_NORMAL) { + forceNormVol = true; + } + else if (mode == VOLUME_ALWAYS_HIGH) { + forceHighVol = true; + } +#endif +} + +bool ArduboyTones::playing() +{ + return tonesPlaying; +} + +void ArduboyTones::nextTone() +{ + uint16_t freq; + uint16_t dur; + long toggleCount; + uint32_t ocrValue; +#ifdef TONES_ADJUST_PRESCALER + uint8_t tccrxbValue; +#endif + + freq = getNext(); // get tone frequency + + if (freq == TONES_END) { // if freq is actually an "end of sequence" marker + noTone(); // stop playing + return; + } + + tonesPlaying = true; + + if (freq == TONES_REPEAT) { // if frequency is actually a "repeat" marker + tonesIndex = tonesStart; // reset to start of sequence + freq = getNext(); + } + +#ifdef TONES_VOLUME_CONTROL + if (((freq & TONE_HIGH_VOLUME) || forceHighVol) && !forceNormVol) { + toneHighVol = true; + } + else { + toneHighVol = false; + } +#endif + + freq &= ~TONE_HIGH_VOLUME; // strip volume indicator from frequency + +#ifdef TONES_ADJUST_PRESCALER + if (freq >= MIN_NO_PRESCALE_FREQ) { + tccrxbValue = _BV(WGM32) | _BV(CS30); // CTC mode, no prescaling + ocrValue = F_CPU / freq / 2 - 1; + toneSilent = false; + } + else { + tccrxbValue = _BV(WGM32) | _BV(CS31); // CTC mode, prescaler /8 +#endif + if (freq == 0) { // if tone is silent + ocrValue = F_CPU / 8 / SILENT_FREQ / 2 - 1; // dummy tone for silence + freq = SILENT_FREQ; + toneSilent = true; + bitClear(TONE_PIN_PORT, TONE_PIN); // set the pin low + } + else { + ocrValue = F_CPU / 8 / freq / 2 - 1; + toneSilent = false; + } +#ifdef TONES_ADJUST_PRESCALER + } +#endif + + if (!outputEnabled()) { // if sound has been muted + toneSilent = true; + } + +#ifdef TONES_VOLUME_CONTROL + if (toneHighVol && !toneSilent) { + // set pin 2 to the compliment of pin 1 + if (bitRead(TONE_PIN_PORT, TONE_PIN)) { + bitClear(TONE_PIN2_PORT, TONE_PIN2); + } + else { + bitSet(TONE_PIN2_PORT, TONE_PIN2); + } + } + else { + bitClear(TONE_PIN2_PORT, TONE_PIN2); // set pin 2 low for normal volume + } +#endif + + dur = getNext(); // get tone duration + if (dur != 0) { + // A right shift is used to divide by 512 for efficency. + // For durations in milliseconds it should actually be a divide by 500, + // so durations will by shorter by 2.34% of what is specified. + toggleCount = ((long)dur * freq) >> 9; + } + else { + toggleCount = -1; // indicate infinite duration + } + + TCCR3A = 0; +#ifdef TONES_ADJUST_PRESCALER + TCCR3B = tccrxbValue; +#else + TCCR3B = _BV(WGM32) | _BV(CS31); // CTC mode, prescaler /8 +#endif + OCR3A = ocrValue; + durationToggleCount = toggleCount; + bitWrite(TIMSK3, OCIE3A, 1); // enable the output compare match interrupt +} + +uint16_t ArduboyTones::getNext() +{ + if (inProgmem) { + return pgm_read_word(tonesIndex++); + } + return *tonesIndex++; +} + +ISR(TIMER3_COMPA_vect) +{ + if (durationToggleCount != 0) { + if (!toneSilent) { + *(&TONE_PIN_PORT) ^= TONE_PIN_MASK; // toggle the pin +#ifdef TONES_VOLUME_CONTROL + if (toneHighVol) { + *(&TONE_PIN2_PORT) ^= TONE_PIN2_MASK; // toggle pin 2 + } +#endif + } + if (durationToggleCount > 0) { + durationToggleCount--; + } + } + else { + ArduboyTones::nextTone(); + } +} diff --git a/board-package-source/libraries/ArduboyTones/src/ArduboyTones.h b/board-package-source/libraries/ArduboyTones/src/ArduboyTones.h new file mode 100644 index 0000000..ff32948 --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/src/ArduboyTones.h @@ -0,0 +1,305 @@ +/** + * @file ArduboyTones.h + * \brief An Arduino library for playing tones and tone sequences, + * intended for the Arduboy game system. + */ + +/***************************************************************************** + ArduboyTones + +An Arduino library to play tones and tone sequences. + +Specifically written for use by the Arduboy miniature game system +https://www.arduboy.com/ +but could work with other Arduino AVR boards that have 16 bit timer 3 +available, by changing the port and bit definintions for the pin(s) +if necessary. + +Copyright (c) 2017 Scott Allen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*****************************************************************************/ + +#ifndef ARDUBOY_TONES_H +#define ARDUBOY_TONES_H + +#include + +// ************************************************************ +// ***** Values to use as function parameters in sketches ***** +// ************************************************************ + +/** \brief + * Frequency value for sequence termination. (No duration follows) + */ +#define TONES_END 0x8000 + +/** \brief + * Frequency value for sequence repeat. (No duration follows) + */ +#define TONES_REPEAT 0x8001 + + +/** \brief + * Add this to the frequency to play a tone at high volume + */ +#define TONE_HIGH_VOLUME 0x8000 + + +/** \brief + * `volumeMode()` parameter. Use the volume encoded in each tone's frequency + */ +#define VOLUME_IN_TONE 0 + +/** \brief + * `volumeMode()` parameter. Play all tones at normal volume, ignoring + * what's encoded in the frequencies + */ +#define VOLUME_ALWAYS_NORMAL 1 + +/** \brief + * `volumeMode()` parameter. Play all tones at high volume, ignoring + * what's encoded in the frequencies + */ +#define VOLUME_ALWAYS_HIGH 2 + +// ************************************************************ + + +#ifndef AB_DEVKIT + // ***** SPEAKER ON TWO PINS ***** + // Indicates that each of the speaker leads is attached to a pin, the way + // the Arduboy is wired. Allows tones of a higher volume to be produced. + // If commented out only one speaker pin will be used. The other speaker + // lead should be attached to ground. + #define TONES_2_SPEAKER_PINS + // ******************************* + + // ***** VOLUME HIGH/NORMAL SUPPORT ***** + // With the speaker placed across two pins, higher volume is produced by + // toggling the second pin to the opposite state of the first pin. + // Normal volume is produced by leaving the second pin low. + // Comment this out for only normal volume support, which will slightly + // reduce the code size. + #define TONES_VOLUME_CONTROL + // ************************************** + + #ifdef TONES_VOLUME_CONTROL + // Must be defined for volume control, so force it if necessary. + #define TONES_2_SPEAKER_PINS + #endif +#endif + +// ***** CONTROL THE TIMER CLOCK PRESCALER **** +// Uncommenting this will switch the timer clock to use no prescaler, +// instead of a divide by 8 prescaler, if the frequency is high enough to +// allow it. This will result in higher frequencies being more accurate at +// the expense of requiring more code. If left commented out, a divide by 8 +// prescaler will be used for all frequencies. +//#define TONES_ADJUST_PRESCALER +// ******************************************** + +// This must match the maximum number of tones that can be specified in +// the tone() function. +#define MAX_TONES 3 + +#ifndef AB_DEVKIT + // Arduboy speaker pin 1 = Arduino pin 5 = ATmega32u4 PC6 + #define TONE_PIN_PORT PORTC + #define TONE_PIN_DDR DDRC + #define TONE_PIN PORTC6 + #define TONE_PIN_MASK _BV(TONE_PIN) +#ifndef AB_ALTERNATE_WIRING + // Arduboy speaker pin 2 = Arduino pin 13 = ATmega32u4 PC7 + #define TONE_PIN2_PORT PORTC + #define TONE_PIN2_DDR DDRC + #define TONE_PIN2 PORTC7 +#else + // Arduboy speaker pin 2 = Pro Micro pin 6 = ATmega32u4 PD7 + #define TONE_PIN2_PORT PORTD + #define TONE_PIN2_DDR DDRD + #define TONE_PIN2 PORTD7 +#endif + #define TONE_PIN2_MASK _BV(TONE_PIN2) +#else + // DevKit speaker pin 1 = Arduino pin A2 = ATmega32u4 PF5 + #define TONE_PIN_PORT PORTF + #define TONE_PIN_DDR DDRF + #define TONE_PIN PORTF5 + #define TONE_PIN_MASK _BV(TONE_PIN) +#endif + +// The minimum frequency that can be produced without a clock prescaler. +#define MIN_NO_PRESCALE_FREQ ((uint16_t)(((F_CPU / 2L) + (1L << 16) - 1L) / (1L << 16))) + +// Dummy frequency used to for silent tones (rests). +#define SILENT_FREQ 250 + + +/** \brief + * The ArduboyTones class for generating tones by specifying + * frequency/duration pairs. + */ +class ArduboyTones +{ + public: + /** \brief + * The ArduboyTones class constructor. + * + * \param outEn A function which returns a boolean value of `true` if sound + * should be played or `false` if sound should be muted. This function will + * be called from the timer interrupt service routine, at the start of each + * tone, so it should be as fast as possible. + */ + ArduboyTones(bool (*outEn)()); + + /** \brief + * Play a single tone. + * + * \param freq The frequency of the tone, in hertz. + * \param dur The duration to play the tone for, in 1024ths of a + * second (very close to milliseconds). A duration of 0, or if not provided, + * means play forever, or until `noTone()` is called or a new tone or + * sequence is started. + */ + static void tone(uint16_t freq, uint16_t dur = 0); + + /** \brief + * Play two tones in sequence. + * + * \param freq1,freq2 The frequency of the tone in hertz. + * \param dur1,dur2 The duration to play the tone for, in 1024ths of a + * second (very close to milliseconds). + */ + static void tone(uint16_t freq1, uint16_t dur1, + uint16_t freq2, uint16_t dur2); + + /** \brief + * Play three tones in sequence. + * + * \param freq1,freq2,freq3 The frequency of the tone, in hertz. + * \param dur1,dur2,dur3 The duration to play the tone for, in 1024ths of a + * second (very close to milliseconds). + */ + static void tone(uint16_t freq1, uint16_t dur1, + uint16_t freq2, uint16_t dur2, + uint16_t freq3, uint16_t dur3); + + /** \brief + * Play a tone sequence from frequency/duration pairs in a PROGMEM array. + * + * \param tones A pointer to an array of frequency/duration pairs. + * The array must be placed in code space using `PROGMEM`. + * + * \details + * \parblock + * See the `tone()` function for details on the frequency and duration values. + * A frequency of 0 for any tone means silence (a musical rest). + * + * The last element of the array must be `TONES_END` or `TONES_REPEAT`. + * + * Example: + * + * \code + * const uint16_t sound1[] PROGMEM = { + * 220,1000, 0,250, 440,500, 880,2000, + * TONES_END + * }; + * \endcode + * + * \endparblock + */ + static void tones(const uint16_t *tones); + + /** \brief + * Play a tone sequence from frequency/duration pairs in an array in RAM. + * + * \param tones A pointer to an array of frequency/duration pairs. + * The array must be located in RAM. + * + * \see tones() + * + * \details + * \parblock + * See the `tone()` function for details on the frequency and duration values. + * A frequency of 0 for any tone means silence (a musical rest). + * + * The last element of the array must be `TONES_END` or `TONES_REPEAT`. + * + * Example: + * + * \code + * uint16_t sound2[] = { + * 220,1000, 0,250, 440,500, 880,2000, + * TONES_END + * }; + * \endcode + * + * \endparblock + * + * \note Using `tones()`, with the data in PROGMEM, is normally a better + * choice. The only reason to use tonesInRAM() would be if dynamically + * altering the contents of the array is required. + */ + static void tonesInRAM(uint16_t *tones); + + /** \brief + * Stop playing the tone or sequence. + * + * \details + * If a tone or sequence is playing, it will stop. If nothing + * is playing, this function will do nothing. + */ + static void noTone(); + + /** \brief + * Set the volume to always normal, always high, or tone controlled. + * + * \param mode + * \parblock + * One of the following values should be used: + * + * - `VOLUME_IN_TONE` The volume of each tone will be specified in the tone + * itself. + * - `VOLUME_ALWAYS_NORMAL` All tones will play at the normal volume level. + * - `VOLUME_ALWAYS_HIGH` All tones will play at the high volume level. + * + * \endparblock + */ + static void volumeMode(uint8_t mode); + + /** \brief + * Check if a tone or tone sequence is playing. + * + * \return boolean `true` if playing (even if sound is muted). + */ + static bool playing(); + +private: + // Get the next value in the sequence + static uint16_t getNext(); + +public: + // Called from ISR so must be public. Should not be called by a program. + static void nextTone(); +}; + +#include "ArduboyTonesPitches.h" + +#endif diff --git a/board-package-source/libraries/ArduboyTones/src/ArduboyTonesPitches.h b/board-package-source/libraries/ArduboyTones/src/ArduboyTonesPitches.h new file mode 100644 index 0000000..3c0175c --- /dev/null +++ b/board-package-source/libraries/ArduboyTones/src/ArduboyTonesPitches.h @@ -0,0 +1,254 @@ +/** + * @file ArduboyTonesPitches.h + * \brief Frequency definitions for standard note pitches. + */ + +// Definitions ending with "H" indicate high volume + +#ifndef ARDUBOY_TONES_PITCHES_H +#define ARDUBOY_TONES_PITCHES_H + +#define NOTE_REST 0 +#define NOTE_C0 16 +#define NOTE_CS0 17 +#define NOTE_D0 18 +#define NOTE_DS0 19 +#define NOTE_E0 21 +#define NOTE_F0 22 +#define NOTE_FS0 23 +#define NOTE_G0 25 +#define NOTE_GS0 26 +#define NOTE_A0 28 +#define NOTE_AS0 29 +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2218 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 +#define NOTE_E8 5274 +#define NOTE_F8 5588 +#define NOTE_FS8 5920 +#define NOTE_G8 6272 +#define NOTE_GS8 6645 +#define NOTE_A8 7040 +#define NOTE_AS8 7459 +#define NOTE_B8 7902 +#define NOTE_C9 8372 +#define NOTE_CS9 8870 +#define NOTE_D9 9397 +#define NOTE_DS9 9956 +#define NOTE_E9 10548 +#define NOTE_F9 11175 +#define NOTE_FS9 11840 +#define NOTE_G9 12544 +#define NOTE_GS9 13290 +#define NOTE_A9 14080 +#define NOTE_AS9 14917 +#define NOTE_B9 15804 + +#define NOTE_C0H (NOTE_C0 + TONE_HIGH_VOLUME) +#define NOTE_CS0H (NOTE_CS0 + TONE_HIGH_VOLUME) +#define NOTE_D0H (NOTE_D08 + TONE_HIGH_VOLUME) +#define NOTE_DS0H (NOTE_DS0 + TONE_HIGH_VOLUME) +#define NOTE_E0H (NOTE_E0 + TONE_HIGH_VOLUME) +#define NOTE_F0H (NOTE_F0 + TONE_HIGH_VOLUME) +#define NOTE_FS0H (NOTE_FS0 + TONE_HIGH_VOLUME) +#define NOTE_G0H (NOTE_G0 + TONE_HIGH_VOLUME) +#define NOTE_GS0H (NOTE_GS0 + TONE_HIGH_VOLUME) +#define NOTE_A0H (NOTE_A0 + TONE_HIGH_VOLUME) +#define NOTE_AS0H (NOTE_AS0 + TONE_HIGH_VOLUME) +#define NOTE_B0H (NOTE_B0 + TONE_HIGH_VOLUME) +#define NOTE_C1H (NOTE_C1 + TONE_HIGH_VOLUME) +#define NOTE_CS1H (NOTE_CS1 + TONE_HIGH_VOLUME) +#define NOTE_D1H (NOTE_D1 + TONE_HIGH_VOLUME) +#define NOTE_DS1H (NOTE_DS1 + TONE_HIGH_VOLUME) +#define NOTE_E1H (NOTE_E1 + TONE_HIGH_VOLUME) +#define NOTE_F1H (NOTE_F1 + TONE_HIGH_VOLUME) +#define NOTE_FS1H (NOTE_FS1 + TONE_HIGH_VOLUME) +#define NOTE_G1H (NOTE_G1 + TONE_HIGH_VOLUME) +#define NOTE_GS1H (NOTE_GS1 + TONE_HIGH_VOLUME) +#define NOTE_A1H (NOTE_A1 + TONE_HIGH_VOLUME) +#define NOTE_AS1H (NOTE_AS1 + TONE_HIGH_VOLUME) +#define NOTE_B1H (NOTE_B1 + TONE_HIGH_VOLUME) +#define NOTE_C2H (NOTE_C2 + TONE_HIGH_VOLUME) +#define NOTE_CS2H (NOTE_CS2 + TONE_HIGH_VOLUME) +#define NOTE_D2H (NOTE_D2 + TONE_HIGH_VOLUME) +#define NOTE_DS2H (NOTE_DS2 + TONE_HIGH_VOLUME) +#define NOTE_E2H (NOTE_E2 + TONE_HIGH_VOLUME) +#define NOTE_F2H (NOTE_F2 + TONE_HIGH_VOLUME) +#define NOTE_FS2H (NOTE_FS2 + TONE_HIGH_VOLUME) +#define NOTE_G2H (NOTE_G2 + TONE_HIGH_VOLUME) +#define NOTE_GS2H (NOTE_GS2 + TONE_HIGH_VOLUME) +#define NOTE_A2H (NOTE_A2 + TONE_HIGH_VOLUME) +#define NOTE_AS2H (NOTE_AS2 + TONE_HIGH_VOLUME) +#define NOTE_B2H (NOTE_B2 + TONE_HIGH_VOLUME) +#define NOTE_C3H (NOTE_C3 + TONE_HIGH_VOLUME) +#define NOTE_CS3H (NOTE_CS3 + TONE_HIGH_VOLUME) +#define NOTE_D3H (NOTE_D3 + TONE_HIGH_VOLUME) +#define NOTE_DS3H (NOTE_DS3 + TONE_HIGH_VOLUME) +#define NOTE_E3H (NOTE_E3 + TONE_HIGH_VOLUME) +#define NOTE_F3H (NOTE_F3 + TONE_HIGH_VOLUME) +#define NOTE_FS3H (NOTE_F3 + TONE_HIGH_VOLUME) +#define NOTE_G3H (NOTE_G3 + TONE_HIGH_VOLUME) +#define NOTE_GS3H (NOTE_GS3 + TONE_HIGH_VOLUME) +#define NOTE_A3H (NOTE_A3 + TONE_HIGH_VOLUME) +#define NOTE_AS3H (NOTE_AS3 + TONE_HIGH_VOLUME) +#define NOTE_B3H (NOTE_B3 + TONE_HIGH_VOLUME) +#define NOTE_C4H (NOTE_C4 + TONE_HIGH_VOLUME) +#define NOTE_CS4H (NOTE_CS4 + TONE_HIGH_VOLUME) +#define NOTE_D4H (NOTE_D4 + TONE_HIGH_VOLUME) +#define NOTE_DS4H (NOTE_DS4 + TONE_HIGH_VOLUME) +#define NOTE_E4H (NOTE_E4 + TONE_HIGH_VOLUME) +#define NOTE_F4H (NOTE_F4 + TONE_HIGH_VOLUME) +#define NOTE_FS4H (NOTE_FS4 + TONE_HIGH_VOLUME) +#define NOTE_G4H (NOTE_G4 + TONE_HIGH_VOLUME) +#define NOTE_GS4H (NOTE_GS4 + TONE_HIGH_VOLUME) +#define NOTE_A4H (NOTE_A4 + TONE_HIGH_VOLUME) +#define NOTE_AS4H (NOTE_AS4 + TONE_HIGH_VOLUME) +#define NOTE_B4H (NOTE_B4 + TONE_HIGH_VOLUME) +#define NOTE_C5H (NOTE_C5 + TONE_HIGH_VOLUME) +#define NOTE_CS5H (NOTE_CS5 + TONE_HIGH_VOLUME) +#define NOTE_D5H (NOTE_D5 + TONE_HIGH_VOLUME) +#define NOTE_DS5H (NOTE_DS5 + TONE_HIGH_VOLUME) +#define NOTE_E5H (NOTE_E5 + TONE_HIGH_VOLUME) +#define NOTE_F5H (NOTE_F5 + TONE_HIGH_VOLUME) +#define NOTE_FS5H (NOTE_FS5 + TONE_HIGH_VOLUME) +#define NOTE_G5H (NOTE_G5 + TONE_HIGH_VOLUME) +#define NOTE_GS5H (NOTE_GS5 + TONE_HIGH_VOLUME) +#define NOTE_A5H (NOTE_A5 + TONE_HIGH_VOLUME) +#define NOTE_AS5H (NOTE_AS5 + TONE_HIGH_VOLUME) +#define NOTE_B5H (NOTE_B5 + TONE_HIGH_VOLUME) +#define NOTE_C6H (NOTE_C6 + TONE_HIGH_VOLUME) +#define NOTE_CS6H (NOTE_CS6 + TONE_HIGH_VOLUME) +#define NOTE_D6H (NOTE_D6 + TONE_HIGH_VOLUME) +#define NOTE_DS6H (NOTE_DS6 + TONE_HIGH_VOLUME) +#define NOTE_E6H (NOTE_E6 + TONE_HIGH_VOLUME) +#define NOTE_F6H (NOTE_F6 + TONE_HIGH_VOLUME) +#define NOTE_FS6H (NOTE_FS6 + TONE_HIGH_VOLUME) +#define NOTE_G6H (NOTE_G6 + TONE_HIGH_VOLUME) +#define NOTE_GS6H (NOTE_GS6 + TONE_HIGH_VOLUME) +#define NOTE_A6H (NOTE_A6 + TONE_HIGH_VOLUME) +#define NOTE_AS6H (NOTE_AS6 + TONE_HIGH_VOLUME) +#define NOTE_B6H (NOTE_B6 + TONE_HIGH_VOLUME) +#define NOTE_C7H (NOTE_C7 + TONE_HIGH_VOLUME) +#define NOTE_CS7H (NOTE_CS7 + TONE_HIGH_VOLUME) +#define NOTE_D7H (NOTE_D7 + TONE_HIGH_VOLUME) +#define NOTE_DS7H (NOTE_DS7 + TONE_HIGH_VOLUME) +#define NOTE_E7H (NOTE_E7 + TONE_HIGH_VOLUME) +#define NOTE_F7H (NOTE_F7 + TONE_HIGH_VOLUME) +#define NOTE_FS7H (NOTE_FS7 + TONE_HIGH_VOLUME) +#define NOTE_G7H (NOTE_G7 + TONE_HIGH_VOLUME) +#define NOTE_GS7H (NOTE_GS7 + TONE_HIGH_VOLUME) +#define NOTE_A7H (NOTE_A7 + TONE_HIGH_VOLUME) +#define NOTE_AS7H (NOTE_AS7 + TONE_HIGH_VOLUME) +#define NOTE_B7H (NOTE_B7 + TONE_HIGH_VOLUME) +#define NOTE_C8H (NOTE_C8 + TONE_HIGH_VOLUME) +#define NOTE_CS8H (NOTE_CS8 + TONE_HIGH_VOLUME) +#define NOTE_D8H (NOTE_D8 + TONE_HIGH_VOLUME) +#define NOTE_DS8H (NOTE_DS8 + TONE_HIGH_VOLUME) +#define NOTE_E8H (NOTE_E8 + TONE_HIGH_VOLUME) +#define NOTE_F8H (NOTE_F8 + TONE_HIGH_VOLUME) +#define NOTE_FS8H (NOTE_FS8 + TONE_HIGH_VOLUME) +#define NOTE_G8H (NOTE_G8 + TONE_HIGH_VOLUME) +#define NOTE_GS8H (NOTE_GS8 + TONE_HIGH_VOLUME) +#define NOTE_A8H (NOTE_A8 + TONE_HIGH_VOLUME) +#define NOTE_AS8H (NOTE_AS8 + TONE_HIGH_VOLUME) +#define NOTE_B8H (NOTE_B8 + TONE_HIGH_VOLUME) +#define NOTE_C9H (NOTE_C9 + TONE_HIGH_VOLUME) +#define NOTE_CS9H (NOTE_CS9 + TONE_HIGH_VOLUME) +#define NOTE_D9H (NOTE_D9 + TONE_HIGH_VOLUME) +#define NOTE_DS9H (NOTE_DS9 + TONE_HIGH_VOLUME) +#define NOTE_E9H (NOTE_E9 + TONE_HIGH_VOLUME) +#define NOTE_F9H (NOTE_F9 + TONE_HIGH_VOLUME) +#define NOTE_FS9H (NOTE_FS9 + TONE_HIGH_VOLUME) +#define NOTE_G9H (NOTE_G9 + TONE_HIGH_VOLUME) +#define NOTE_GS9H (NOTE_GS9 + TONE_HIGH_VOLUME) +#define NOTE_A9H (NOTE_A9 + TONE_HIGH_VOLUME) +#define NOTE_AS9H (NOTE_AS9 + TONE_HIGH_VOLUME) +#define NOTE_B9H (NOTE_B9 + TONE_HIGH_VOLUME) + +#endif diff --git a/board-package-source/libraries/EEPROM/README.md b/board-package-source/libraries/EEPROM/README.md new file mode 100644 index 0000000..a624136 --- /dev/null +++ b/board-package-source/libraries/EEPROM/README.md @@ -0,0 +1,139 @@ +## **EEPROM Library V2.0** for Arduino + +**Written by:** _Christopher Andrews_. + +### **What is the EEPROM library.** + +Th EEPROM library provides an easy to use interface to interact with the internal non-volatile storage found in AVR based Arduino boards. This library will work on many AVR devices like ATtiny and ATmega chips. + +### **How to use it** +The EEPROM library is included in your IDE download. To add its functionality to your sketch you'll need to reference the library header file. You do this by adding an include directive to the top of your sketch. + +```Arduino +#include + +void setup(){ + +} + +void loop(){ + +} + +``` + +The library provides a global variable named `EEPROM`, you use this variable to access the library functions. The methods provided in the EEPROM class are listed below. + +You can view all the examples [here](examples/). + +### **Library functions** + +#### **`EEPROM.read( address )`** [[_example_]](examples/eeprom_read/eeprom_read.ino) + +This function allows you to read a single byte of data from the eeprom. +Its only parameter is an `int` which should be set to the address you wish to read. + +The function returns an `unsigned char` containing the value read. + +#### **`EEPROM.write( address, value )`** [[_example_]](examples/eeprom_write/eeprom_write.ino) + +The `write()` method allows you to write a single byte of data to the EEPROM. +Two parameters are needed. The first is an `int` containing the address that is to be written, and the second is a the data to be written (`unsigned char`). + +This function does not return any value. + +#### **`EEPROM.update( address, value )`** [[_example_]](examples/eeprom_update/eeprom_update.ino) + +This function is similar to `EEPROM.write()` however this method will only write data if the cell contents pointed to by `address` is different to `value`. This method can help prevent unnecessary wear on the EEPROM cells. + +This function does not return any value. + +#### **`EEPROM.get( address, object )`** [[_example_]](examples/eeprom_get/eeprom_get.ino) + +This function will retrieve any object from the EEPROM. +Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to read. + +This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience. + +#### **`EEPROM.put( address, object )`** [[_example_]](examples/eeprom_put/eeprom_put.ino) + +This function will write any object to the EEPROM. +Two parameters are needed to call this function. The first is an `int` containing the address that is to be written, and the second is the object you would like to write. + +This function uses the _update_ method to write its data, and therefore only rewrites changed cells. + +This function returns a reference to the `object` passed in. It does not need to be used and is only returned for conveience. + +#### **Subscript operator: `EEPROM[address]`** [[_example_]](examples/eeprom_crc/eeprom_crc.ino) + +This operator allows using the identifier `EEPROM` like an array. +EEPROM cells can be read _and_ **_written_** directly using this method. + +This operator returns a reference to the EEPROM cell. + +```c++ +unsigned char val; + +//Read first EEPROM cell. +val = EEPROM[ 0 ]; + +//Write first EEPROM cell. +EEPROM[ 0 ] = val; + +//Compare contents +if( val == EEPROM[ 0 ] ){ + //Do something... +} +``` + +#### **`EEPROM.length()`** + +This function returns an `unsigned int` containing the number of cells in the EEPROM. + +--- + +### **Advanced features** + +This library uses a component based approach to provide its functionality. This means you can also use these components to design a customized approach. Two background classes are available for use: `EERef` & `EEPtr`. + +#### **`EERef` class** + +This object references an EEPROM cell. +Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. +This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. + +```C++ +EERef ref = EEPROM[ 10 ]; //Create a reference to 11th cell. + +ref = 4; //write to EEPROM cell. + +unsigned char val = ref; //Read referenced cell. +``` + +#### **`EEPtr` class** + +This object is a bidirectional pointer to EEPROM cells represented by `EERef` objects. +Just like a normal pointer type, this type can be dereferenced and repositioned using +increment/decrement operators. + +```C++ +EEPtr ptr = 10; //Create a pointer to 11th cell. + +*ptr = 4; //dereference and write to EEPROM cell. + +unsigned char val = *ptr; //dereference and read. + +ptr++; //Move to next EEPROM cell. +``` + +#### **`EEPROM.begin()`** + +This function returns an `EEPtr` pointing to the first cell in the EEPROM. +This is useful for STL objects, custom iteration and C++11 style ranged for loops. + +#### **`EEPROM.end()`** + +This function returns an `EEPtr` pointing at the location after the last EEPROM cell. +Used with `begin()` to provide custom iteration. + +**Note:** The `EEPtr` returned is invalid as it is out of range. Infact the hardware causes wrapping of the address (overflow) and `EEPROM.end()` actually references the first EEPROM cell. diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino b/board-package-source/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino new file mode 100644 index 0000000..8b5121c --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino @@ -0,0 +1,39 @@ +/* + * EEPROM Clear + * + * Sets all of the bytes of the EEPROM to 0. + * Please see eeprom_iteration for a more in depth + * look at how to traverse the EEPROM. + * + * This example code is in the public domain. + */ + +#include + +void setup() { + // initialize the LED pin as an output. + pinMode(13, OUTPUT); + + /*** + Iterate through each byte of the EEPROM storage. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + + for (int i = 0 ; i < EEPROM.length() ; i++) { + EEPROM.write(i, 0); + } + + // turn the LED on when we're done + digitalWrite(13, HIGH); +} + +void loop() { + /** Empty loop. **/ +} diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino b/board-package-source/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino new file mode 100644 index 0000000..c6db85c --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_crc/eeprom_crc.ino @@ -0,0 +1,52 @@ +/*** + Written by Christopher Andrews. + CRC algorithm generated by pycrc, MIT licence ( https://github.com/tpircher/pycrc ). + + A CRC is a simple way of checking whether data has changed or become corrupted. + This example calculates a CRC value directly on the EEPROM values. + The purpose of this example is to highlight how the EEPROM object can be used just like an array. +***/ + +#include +#include + +void setup() { + + //Start serial + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + //Print length of data to run CRC on. + Serial.print("EEPROM length: "); + Serial.println(EEPROM.length()); + + //Print the result of calling eeprom_crc() + Serial.print("CRC32 of EEPROM data: 0x"); + Serial.println(eeprom_crc(), HEX); + Serial.print("\n\nDone!"); +} + +void loop() { + /* Empty loop */ +} + +unsigned long eeprom_crc(void) { + + const unsigned long crc_table[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, + 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c + }; + + unsigned long crc = ~0L; + + for (int index = 0 ; index < EEPROM.length() ; ++index) { + crc = crc_table[(crc ^ EEPROM[index]) & 0x0f] ^ (crc >> 4); + crc = crc_table[(crc ^ (EEPROM[index] >> 4)) & 0x0f] ^ (crc >> 4); + crc = ~crc; + } + return crc; +} diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino b/board-package-source/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino new file mode 100644 index 0000000..a07cee7 --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_get/eeprom_get.ino @@ -0,0 +1,68 @@ +/*** + eeprom_get example. + + This shows how to use the EEPROM.get() method. + + To pre-set the EEPROM data, run the example sketch eeprom_put. + This sketch will run without it, however, the values shown + will be shown from what ever is already on the EEPROM. + + This may cause the serial object to print out a large string + of garbage if there is no null character inside one of the strings + loaded. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +void setup() { + + float f = 0.00f; //Variable to store data read from EEPROM. + int eeAddress = 0; //EEPROM address to start reading from + + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + Serial.print("Read float from EEPROM: "); + + //Get the float data from the EEPROM at position 'eeAddress' + EEPROM.get(eeAddress, f); + Serial.println(f, 3); //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float. + + /*** + As get also returns a reference to 'f', you can use it inline. + E.g: Serial.print( EEPROM.get( eeAddress, f ) ); + ***/ + + /*** + Get can be used with custom structures too. + I have separated this into an extra function. + ***/ + + secondTest(); //Run the next test. +} + +struct MyObject { + float field1; + byte field2; + char name[10]; +}; + +void secondTest() { + int eeAddress = sizeof(float); //Move address to the next byte after float 'f'. + + MyObject customVar; //Variable to store custom object read from EEPROM. + EEPROM.get(eeAddress, customVar); + + Serial.println("Read custom object from EEPROM: "); + Serial.println(customVar.field1); + Serial.println(customVar.field2); + Serial.println(customVar.name); +} + +void loop() { + /* Empty loop */ +} diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino b/board-package-source/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino new file mode 100644 index 0000000..3673b47 --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_iteration/eeprom_iteration.ino @@ -0,0 +1,57 @@ +/*** + eeprom_iteration example. + + A set of example snippets highlighting the + simplest methods for traversing the EEPROM. + + Running this sketch is not necessary, this is + simply highlighting certain programming methods. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +void setup() { + + /*** + Iterate the EEPROM using a for loop. + ***/ + + for (int index = 0 ; index < EEPROM.length() ; index++) { + + //Add one to each cell in the EEPROM + EEPROM[ index ] += 1; + } + + /*** + Iterate the EEPROM using a while loop. + ***/ + + int index = 0; + + while (index < EEPROM.length()) { + + //Add one to each cell in the EEPROM + EEPROM[ index ] += 1; + index++; + } + + /*** + Iterate the EEPROM using a do-while loop. + ***/ + + int idx = 0; //Used 'idx' to avoid name conflict with 'index' above. + + do { + + //Add one to each cell in the EEPROM + EEPROM[ idx ] += 1; + idx++; + } while (idx < EEPROM.length()); + + +} //End of setup function. + +void loop() {} \ No newline at end of file diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino b/board-package-source/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino new file mode 100644 index 0000000..c1ba0a5 --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_put/eeprom_put.ino @@ -0,0 +1,58 @@ +/*** + eeprom_put example. + + This shows how to use the EEPROM.put() method. + Also, this sketch will pre-set the EEPROM data for the + example sketch eeprom_get. + + Note, unlike the single byte version EEPROM.write(), + the put method will use update semantics. As in a byte + will only be written to the EEPROM if the data is actually + different. + + Written by Christopher Andrews 2015 + Released under MIT licence. +***/ + +#include + +struct MyObject { + float field1; + byte field2; + char name[10]; +}; + +void setup() { + + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + float f = 123.456f; //Variable to store in EEPROM. + int eeAddress = 0; //Location we want the data to be put. + + + //One simple call, with the address first and the object second. + EEPROM.put(eeAddress, f); + + Serial.println("Written float data type!"); + + /** Put is designed for use with custom structures also. **/ + + //Data to store. + MyObject customVar = { + 3.14f, + 65, + "Working!" + }; + + eeAddress += sizeof(float); //Move address to the next byte after float 'f'. + + EEPROM.put(eeAddress, customVar); + Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!"); +} + +void loop() { + /* Empty loop */ +} diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino b/board-package-source/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino new file mode 100644 index 0000000..a8a3510 --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino @@ -0,0 +1,56 @@ +/* + * EEPROM Read + * + * Reads the value of each byte of the EEPROM and prints it + * to the computer. + * This example code is in the public domain. + */ + +#include + +// start reading from the first byte (address 0) of the EEPROM +int address = 0; +byte value; + +void setup() { + // initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } +} + +void loop() { + // read a byte from the current address of the EEPROM + value = EEPROM.read(address); + + Serial.print(address); + Serial.print("\t"); + Serial.print(value, DEC); + Serial.println(); + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + address = address + 1; + if (address == EEPROM.length()) { + address = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++address &= EEPROM.length() - 1; + ***/ + + delay(500); +} diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino b/board-package-source/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino new file mode 100644 index 0000000..5e3db5b --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_update/eeprom_update.ino @@ -0,0 +1,71 @@ +/*** + EEPROM Update method + + Stores values read from analog input 0 into the EEPROM. + These values will stay in the EEPROM when the board is + turned off and may be retrieved later by another sketch. + + If a value has not changed in the EEPROM, it is not overwritten + which would reduce the life span of the EEPROM unnecessarily. + + Released using MIT licence. + ***/ + +#include + +/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ +int address = 0; + +void setup() { + /** EMpty setup **/ +} + +void loop() { + /*** + need to divide by 4 because analog inputs range from + 0 to 1023 and each byte of the EEPROM can only hold a + value from 0 to 255. + ***/ + int val = analogRead(0) / 4; + + /*** + Update the particular EEPROM cell. + these values will remain there when the board is + turned off. + ***/ + EEPROM.update(address, val); + + /*** + The function EEPROM.update(address, val) is equivalent to the following: + + if( EEPROM.read(address) != val ){ + EEPROM.write(address, val); + } + ***/ + + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + address = address + 1; + if (address == EEPROM.length()) { + address = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++address &= EEPROM.length() - 1; + ***/ + + delay(100); +} diff --git a/board-package-source/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino b/board-package-source/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino new file mode 100644 index 0000000..f9bea64 --- /dev/null +++ b/board-package-source/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino @@ -0,0 +1,60 @@ +/* + * EEPROM Write + * + * Stores values read from analog input 0 into the EEPROM. + * These values will stay in the EEPROM when the board is + * turned off and may be retrieved later by another sketch. + */ + +#include + +/** the current address in the EEPROM (i.e. which byte we're going to write to next) **/ +int addr = 0; + +void setup() { + /** Empty setup. **/ +} + +void loop() { + /*** + Need to divide by 4 because analog inputs range from + 0 to 1023 and each byte of the EEPROM can only hold a + value from 0 to 255. + ***/ + + int val = analogRead(0) / 4; + + /*** + Write the value to the appropriate byte of the EEPROM. + these values will remain there when the board is + turned off. + ***/ + + EEPROM.write(addr, val); + + /*** + Advance to the next address, when at the end restart at the beginning. + + Larger AVR processors have larger EEPROM sizes, E.g: + - Arduno Duemilanove: 512b EEPROM storage. + - Arduino Uno: 1kb EEPROM storage. + - Arduino Mega: 4kb EEPROM storage. + + Rather than hard-coding the length, you should use the pre-provided length function. + This will make your code portable to all AVR processors. + ***/ + addr = addr + 1; + if (addr == EEPROM.length()) { + addr = 0; + } + + /*** + As the EEPROM sizes are powers of two, wrapping (preventing overflow) of an + EEPROM address is also doable by a bitwise and of the length - 1. + + ++addr &= EEPROM.length() - 1; + ***/ + + + delay(100); +} diff --git a/board-package-source/libraries/EEPROM/keywords.txt b/board-package-source/libraries/EEPROM/keywords.txt new file mode 100644 index 0000000..2cabc0b --- /dev/null +++ b/board-package-source/libraries/EEPROM/keywords.txt @@ -0,0 +1,22 @@ +####################################### +# Syntax Coloring Map For EEPROM +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +EEPROM KEYWORD1 +EERef KEYWORD1 +EEPtr KEYWORD2 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +update KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/board-package-source/libraries/EEPROM/library.properties b/board-package-source/libraries/EEPROM/library.properties new file mode 100644 index 0000000..3b20032 --- /dev/null +++ b/board-package-source/libraries/EEPROM/library.properties @@ -0,0 +1,10 @@ +name=EEPROM +version=2.0 +author=Arduino, Christopher Andrews +maintainer=Arduino +sentence=Enables reading and writing to the permanent board storage. +paragraph=This library allows to read and write data in a memory type, the EEPROM, that keeps its content also when the board is powered off. The amount of EEPROM available depends on the microcontroller type. +category=Data Storage +url=http://www.arduino.cc/en/Reference/EEPROM +architectures=avr + diff --git a/board-package-source/libraries/EEPROM/src/EEPROM.h b/board-package-source/libraries/EEPROM/src/EEPROM.h new file mode 100644 index 0000000..cde75db --- /dev/null +++ b/board-package-source/libraries/EEPROM/src/EEPROM.h @@ -0,0 +1,146 @@ +/* + EEPROM.h - EEPROM library + Original Copyright (c) 2006 David A. Mellis. All right reserved. + New version by Christopher Andrews 2015. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EEPROM_h +#define EEPROM_h + +#include +#include +#include + +/*** + EERef class. + + This object references an EEPROM cell. + Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. + This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. +***/ + +struct EERef{ + + EERef( const int index ) + : index( index ) {} + + //Access/read members. + uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); } + operator const uint8_t() const { return **this; } + + //Assignment/write members. + EERef &operator=( const EERef &ref ) { return *this = *ref; } + EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; } + EERef &operator +=( uint8_t in ) { return *this = **this + in; } + EERef &operator -=( uint8_t in ) { return *this = **this - in; } + EERef &operator *=( uint8_t in ) { return *this = **this * in; } + EERef &operator /=( uint8_t in ) { return *this = **this / in; } + EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; } + EERef &operator %=( uint8_t in ) { return *this = **this % in; } + EERef &operator &=( uint8_t in ) { return *this = **this & in; } + EERef &operator |=( uint8_t in ) { return *this = **this | in; } + EERef &operator <<=( uint8_t in ) { return *this = **this << in; } + EERef &operator >>=( uint8_t in ) { return *this = **this >> in; } + + EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; } + + /** Prefix increment/decrement **/ + EERef& operator++() { return *this += 1; } + EERef& operator--() { return *this -= 1; } + + /** Postfix increment/decrement **/ + uint8_t operator++ (int){ + uint8_t ret = **this; + return ++(*this), ret; + } + + uint8_t operator-- (int){ + uint8_t ret = **this; + return --(*this), ret; + } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPtr class. + + This object is a bidirectional pointer to EEPROM cells represented by EERef objects. + Just like a normal pointer type, this can be dereferenced and repositioned using + increment/decrement operators. +***/ + +struct EEPtr{ + + EEPtr( const int index ) + : index( index ) {} + + operator const int() const { return index; } + EEPtr &operator=( int in ) { return index = in, *this; } + + //Iterator functionality. + bool operator!=( const EEPtr &ptr ) { return index != ptr.index; } + EERef operator*() { return index; } + + /** Prefix & Postfix increment/decrement **/ + EEPtr& operator++() { return ++index, *this; } + EEPtr& operator--() { return --index, *this; } + EEPtr operator++ (int) { return index++; } + EEPtr operator-- (int) { return index--; } + + int index; //Index of current EEPROM cell. +}; + +/*** + EEPROMClass class. + + This object represents the entire EEPROM space. + It wraps the functionality of EEPtr and EERef into a basic interface. + This class is also 100% backwards compatible with earlier Arduino core releases. +***/ + +struct EEPROMClass{ + + //Basic user access methods. + EERef operator[]( const int idx ) { return idx; } + uint8_t read( int idx ) { return EERef( idx ); } + void write( int idx, uint8_t val ) { (EERef( idx )) = val; } + void update( int idx, uint8_t val ) { EERef( idx ).update( val ); } + + //STL and C++11 iteration capability. + EEPtr begin() { return 0x00; } + EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. + uint16_t length() { return E2END + 1; } + + //Functionality to 'get' and 'put' objects to and from EEPROM. + template< typename T > T &get( int idx, T &t ){ + EEPtr e = idx; + uint8_t *ptr = (uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e; + return t; + } + + template< typename T > const T &put( int idx, const T &t ){ + EEPtr e = idx; + const uint8_t *ptr = (const uint8_t*) &t; + for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ ); + return t; + } +}; + +static EEPROMClass EEPROM; +#endif \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/LICENCE b/board-package-source/libraries/FixedPointsArduino/LICENCE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/LICENCE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/board-package-source/libraries/FixedPointsArduino/README.md b/board-package-source/libraries/FixedPointsArduino/README.md new file mode 100644 index 0000000..8f2908c --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/README.md @@ -0,0 +1,176 @@ +# FixedPoints +A portable fixed point arithmetic library. + +Some knowledge of how fixed point types are formatted is required to used this library to full effect. +No knowledge of how these operations are implemented is required to use them. + +This library was written with Arduino in mind, as well as CPUs with limited floating point support. +However, given the templated nature of the library, it should still function on a wide variety of CPUs. + +## Project Showcase + +Here's a list of projects that use `FixedPoints`: + +* [1943](https://github.com/filmote/Nineteen43) for the [Arduboy](https://arduboy.com/) by [@filmote](https://github.com/filmote) +* [XOD Powered Rechargeable Solar Lamp](http://www.instructables.com/id/XOD-powered-Rechargeable-Solar-Lamp/) by [Victorian DeLorean](http://www.instructables.com/member/Victorian%20DeLorean/) + +If you have a project that uses `FixedPoints` and would like your work to be showcased here, +please [raise an issue](https://github.com/Pharap/FixedPointsArduino/issues/new). + +## Requirements: + +- The Compiler must be C++11 compliant. +- The user should ideally be familar with the [Q number format](https://en.wikipedia.org/wiki/Q_(number_format)) for fixed points. + +## Licence + +This code uses the Apache 2.0 Licence. +This means: + +- This code comes with no warranty. +- The licensor and any contributors cannot be held liable for damages. +- If you use this code, edited or unedited, you must: + - Package a copy of LICENCE with your code. + - Package a copy of NOTICE with your code. +- You may modify the source code. + - If you modify a file, you must state this prominently in the file (i.e. in a comment at the top). + - Any modified code may use a different licence. + - Any unmodified code must carry the same Apache 2.0 licence. +- You may not use any trademarks owned by the licensor. + +## Conditional Compilation + +These are symbols you can define prior to library inclusion to alter the behaviour of the library. + +- `FIXED_POINTS_USE_NAMESPACE`: Define this to wrap all classes and functions in the namespace `FixedPoints`. Useful for preventing naming conflicts. +- `FIXED_POINTS_NO_RANDOM`: Define this to disable the random utility functions. Useful for systems that don't have access to `long random(void)` from avr-libc. + +## FAQ + +* Why can't I multiply `UQ32x32` or `SQ31x32` by another type? + * Because it would require a 128-bit integer type to provide enough precision for accurate multiplication. + +## Contents +This library supplies two core types and sixteen type aliases. + +### Defines + +- `FIXED_POINTS_NAMESPACE`: The namespace used by FixedPoints. This is empty unless `FIXED_POINTS_USE_NAMESPACE` is defined prior to inclusion. +- `FIXED_POINTS_DETAILS`: An infrastructure macro that should not be used in user code. It is safe to undefine this if it is causing problems. +- `FIXED_POINTS_BEGIN_NAMESPACE`: An infrastructure macro that should not be used in user code. It is safe to undefine this if it is causing problems. +- `FIXED_POINTS_END_NAMESPACE`: An infrastructure macro that should not be used in user code. It is safe to undefine this if it is causing problems. + +### Core Types: +The core types are provided by `FixedPoints.h`. + +- `UFixed`: An unsigned fixed point type where I is the number of bits used for the integer part of the number and F is the number of bits used for the fractional part of the number. +- `SFixed`: An signed fixed point type where I is the number of bits used for the integer part of the number (excluding the implicit sign bit) and F is the number of bits used for the fractional part of the number. + +### Aliases: +The common aliases are provided by `FixedPointsCommon.h`. + +- `UQ4x4`: An alias for `UFixed<4, 4>`, an 8-bit unsigned fixed point in the Q4.4 format. +- `UQ8x8`: An alias for `UFixed<8, 8>`, a 16-bit unsigned fixed point in the Q8.8 format. +- `UQ16x16`: An alias for `UFixed<16, 16>`, a 32-bit unsigned fixed point in the Q16.16 format. +- `UQ32x32`: An alias for `UFixed<32, 32>`, a 64-bit unsigned fixed point in the Q32.32 format. +- `UQ1x7`: An alias for `UFixed<1, 7>`, an 8-bit unsigned fixed point in the Q1.7 format. +- `UQ1x15`: An alias for `UFixed<1, 15>`, a 16-bit unsigned fixed point in the Q1.15 format. +- `UQ1x31`: An alias for `UFixed<1, 31>`, a 32-bit unsigned fixed point in the Q1.31 format. +- `UQ1x63`: An alias for `UFixed<1, 63>`, a 64-bit unsigned fixed point in the Q1.63 format. +- `SQ3x4`: An alias for `SFixed<3, 4>`, an 8-bit signed fixed point in the Q3.4 format with implicit sign bit. +- `SQ7x8`: An alias for `SFixed<7, 8>`, a 16-bit signed fixed point in the Q7.8 format with implicit sign bit. +- `SQ15x16`: An alias for `SFixed<15, 16>`, a 32-bit signed fixed point in the Q15.16 format with implicit sign bit. +- `SQ31x32`: An alias for `SFixed<31, 32>`, a 64-bit signed fixed point in the Q31.32 format with implicit sign bit. +- `SQ1x6`: An alias for `SFixed<1, 6>`, an 8-bit signed fixed point in the Q1.6 format with implicit sign bit. +- `SQ1x14`: An alias for `SFixed<1, 14>`, a 16-bit signed fixed point in the Q1.14 format with implicit sign bit. +- `SQ1x30`: An alias for `SFixed<1, 30>`, a 32-bit signed fixed point in the Q1.30 format with implicit sign bit. +- `SQ1x62`: An alias for `SFixed<1, 62>`, a 64-bit signed fixed point in the Q1.62 format with implicit sign bit. + +([About Q Format](https://en.wikipedia.org/wiki/Q_(number_format)).) + +### Operators: + +- `+`: Adds two `UFixed`s or two `SFixed`s +- `-`: Subtracts two `UFixed`s or two `SFixed`s +- `*`: Multiplies two `UFixed`s or two `SFixed`s +- `/`: Divides two `UFixed`s or two `SFixed`s +- `==`: Compares two `UFixed`s or two `SFixed`s +- `!=`: Compares two `UFixed`s or two `SFixed`s +- `<`: Compares two `UFixed`s or two `SFixed`s +- `<=`: Compares two `UFixed`s or two `SFixed`s +- `>`: Compares two `UFixed`s or two `SFixed`s +- `>=`: Compares two `UFixed`s or two `SFixed`s + +### Free Functions: + +- `floorFixed`: The floor operation. +- `ceilFixed`: The Ceiling operation +- `roundFixed`: Rounding operation. +- `truncFixed`: Truncation operation. +- `signbitFixed`: Returns `true` for signed numbers and `false` for unsigned numbers. +- `copysignFixed`: Returns a value with the magnitude of the first argument and the sign of the second argument. +- `multiply`: Multiplies two `UFixed`s or two `SFixed`s, returns a result that is twice the resolution of the input. + +### Member Functions: + +- `UFixed::getInteger`: Gets the integer part of an unsigned fixed point. +- `UFixed::getFraction`: Gets the fractional part of an unsigned fixed point. +- `UFixed::getInternal`: Gets the internal representation of an unsigned fixed point. + +- `SFixed::getInteger`: Gets the integer part of a signed fixed point. +- `SFixed::getFraction`: Gets the fractional part of a signed fixed point. +- `SFixed::getInternal`: Gets the internal representation of a signed fixed point. + +### Static Functions: + +- `UFixed::fromInternal`: Produces an unsigned fixed point number from its internal representation. +- `SFixed::fromInternal`: Produces a signed fixed point number from its internal representation. + +## Construction: + +Note that both `UFixed` and `SFixed` are implicitly compile-time constructable from all integer and decimal literals. +This means that you may write code such as `UFixed<8, 8> value = 0.5;` without incurring a runtime cost for converting from `double` to `UFixed<8, 8>` because the constructor is `constexpr`. + +`UFixed` is constructable from: +- Any integer literal type, regardless of sign. +-- This constructs the fixed point as an integer with no fractional part. +-- A value that does not fit shall be truncated without warning. +-- If a constant value is used, the fixed point shall be constructed at compile time. +- An unsigned integer part and an unsigned fractional part. +-- The integer part is of the smallest type capable of representing `I` bits. +-- The fractional part is of the smallest type capable of representing `F` bits. +-- If constant values are used, the fixed point shall be constructed at compile time. +- Any decimal literal type, regardless of sign. +-- This constructs the fixed point as a best approximation of the provided value. +-- A value that does not fit shall be truncated without warning. +-- If a constant value is used, the fixed point shall be constructed at compile time. + +`SFixed` is constructable from: +- Any integer literal type, regardless of sign. +-- This constructs the fixed point as an integer with no fractional part. +-- A value that does not fit shall be truncated without warning. +-- If a constant value is used, the fixed point shall be constructed at compile time. +- A signed integer part and an unsigned fractional part. +-- The integer part is of the smallest type capable of representing `I + 1` bits. +-- The fractional part is of the smallest type capable of representing `F` bits. +-- If constant values are used, the fixed point shall be constructed at compile time. +- Any decimal literal type, regardless of sign. +-- This constructs the fixed point as a best approximation of the provided value. +-- A value that does not fit shall be truncated without warning. +-- If a constant value is used, the fixed point shall be constructed at compile time. + +### Casts: + +`UFixed` is explicitly convertible to: +- `float`. +- `double`. +- The smallest unsigned type capable of holding its integer part. I.e. a type of at least `I` bits. +- Another `UFixed` type of a different scale. E.g. `UFixed<4, 4>` may be converted to `UFixed<8, 8>` and vice versa. + +`SFixed` is explicitly convertible to: +- `float`. +- `double`. +- The smallest signed type capable of holding its integer part. I.e. a type of at least `I + 1` bits. +- Another `SFixed` type of a different scale. E.g. `SFixed<3, 4>` may be converted to `SFixed<7, 8>` and vice versa. + + diff --git a/board-package-source/libraries/FixedPointsArduino/examples/FixedPointCalculations/FixedPointCalculations.ino b/board-package-source/libraries/FixedPointsArduino/examples/FixedPointCalculations/FixedPointCalculations.ino new file mode 100644 index 0000000..70f1e01 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/examples/FixedPointCalculations/FixedPointCalculations.ino @@ -0,0 +1,171 @@ +#include +#include + +void TestUQ8x8(void) +{ + Serial.println(F("The size of UQ8x8 on your system is:")); + Serial.println(sizeof(UQ8x8)); + Serial.println(); + + UQ8x8 a = 1.5; + Serial.println(F("Displaying a as float:")); + Serial.println(static_cast(a)); + Serial.println(); + + Serial.println(F("Displaying the integer part of a")); + Serial.println(a.getInteger()); + Serial.println(); + + Serial.println(F("Displaying floorFixed(a):")); + Serial.println(static_cast(floorFixed(a))); + Serial.println(); + + Serial.println(F("Displaying ceilFixed(a):")); + Serial.println(static_cast(ceilFixed(a))); + Serial.println(); + + Serial.println(F("Displaying roundFixed(a):")); + Serial.println(static_cast(roundFixed(a))); + Serial.println(); + + Serial.println(F("Displaying truncFixed(a):")); + Serial.println(static_cast(truncFixed(a))); + Serial.println(); + + UQ8x8 b = 5.25; + Serial.println(F("Displaying b as float:")); + Serial.println(static_cast(b)); + Serial.println(); + + Serial.println(F("Displaying the integer part of b")); + Serial.println(b.getInteger()); + Serial.println(); + + Serial.println(F("Displaying floorFixed(b):")); + Serial.println(static_cast(floorFixed(b))); + Serial.println(); + + Serial.println(F("Displaying ceilFixed(b):")); + Serial.println(static_cast(ceilFixed(b))); + Serial.println(); + + Serial.println(F("Displaying roundFixed(b):")); + Serial.println(static_cast(roundFixed(b))); + Serial.println(); + + Serial.println(F("Displaying truncFixed(b):")); + Serial.println(static_cast(truncFixed(b))); + Serial.println(); + + Serial.println(F("Displaying a + b as float:")); + Serial.println(static_cast(a + b)); + Serial.println(); + + Serial.println(F("Displaying a - b as float:")); + Serial.println(F("(Note the underflow due lack of sign bit)")); + Serial.println(static_cast(a - b)); + Serial.println(); + + Serial.println(F("Displaying b - a as float:")); + Serial.println(static_cast(b - a)); + Serial.println(); + + Serial.println(F("Displaying a * b as float:")); + Serial.println(static_cast(a * b)); + Serial.println(); + + Serial.println(F("Displaying a / b as float:")); + Serial.println(static_cast(a / b)); + Serial.println(); +} + +void TestSQ7x8(void) +{ + Serial.println(F("The size of SQ7x8 on your system is:")); + Serial.println(sizeof(SQ7x8)); + Serial.println(); + + SQ7x8 a = 1.5; + Serial.println(F("Displaying a as float:")); + Serial.println(static_cast(a)); + Serial.println(); + + Serial.println(F("Displaying the integer part of a")); + Serial.println(a.getInteger()); + Serial.println(); + + Serial.println(F("Displaying floorFixed(a):")); + Serial.println(static_cast(floorFixed(a))); + Serial.println(); + + Serial.println(F("Displaying ceilFixed(a):")); + Serial.println(static_cast(ceilFixed(a))); + Serial.println(); + + Serial.println(F("Displaying roundFixed(a):")); + Serial.println(static_cast(roundFixed(a))); + Serial.println(); + + Serial.println(F("Displaying truncFixed(a):")); + Serial.println(static_cast(truncFixed(a))); + Serial.println(); + + SQ7x8 b = 5.25; + Serial.println(F("Displaying b as float:")); + Serial.println(static_cast(b)); + Serial.println(); + + Serial.println(F("Displaying the integer part of b")); + Serial.println(b.getInteger()); + Serial.println(); + + Serial.println(F("Displaying floorFixed(b):")); + Serial.println(static_cast(floorFixed(b))); + Serial.println(); + + Serial.println(F("Displaying ceilFixed(b):")); + Serial.println(static_cast(ceilFixed(b))); + Serial.println(); + + Serial.println(F("Displaying roundFixed(b):")); + Serial.println(static_cast(roundFixed(b))); + Serial.println(); + + Serial.println(F("Displaying truncFixed(b):")); + Serial.println(static_cast(truncFixed(b))); + Serial.println(); + + Serial.println(F("Displaying a + b as float:")); + Serial.println(static_cast(a + b)); + Serial.println(); + + Serial.println(F("Displaying a - b as float:")); + Serial.println(F("(Note this is correct due to sign bit)")); + Serial.println(static_cast(a - b)); + Serial.println(); + + Serial.println(F("Displaying b - a as float:")); + Serial.println(static_cast(b - a)); + Serial.println(); + + Serial.println(F("Displaying a * b as float:")); + Serial.println(static_cast(a * b)); + Serial.println(); + + Serial.println(F("Displaying a / b as float:")); + Serial.println(static_cast(a / b)); + Serial.println(); +} + +void setup() +{ + Serial.begin(9600); + while(!Serial); + + TestUQ8x8(); + TestSQ7x8(); +} + +void loop() +{ +} diff --git a/board-package-source/libraries/FixedPointsArduino/extras/AFixedPointPrimer.md b/board-package-source/libraries/FixedPointsArduino/extras/AFixedPointPrimer.md new file mode 100644 index 0000000..3413465 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/extras/AFixedPointPrimer.md @@ -0,0 +1,69 @@ +# A Fixed Point Primer + +## What Are Fixed Point Numbers? + +Normally computers operate on what are called 'integers'. +Integers are numbers that do not have a fractional component in them. +For example 0, 1, 42, 128, 10000 are all integers + +Numbers that do have a fractional component are called 'rational' numbers. +They are often represented either as fractions or as numbers with a 'radix point'in them (often called a 'decimal point' in day-to-day maths) +For example 0.5, 1.75, 42.42, 128.367 and 10000.00001 are all rational numbers. + +Normally computers represent these in what is called a 'floating point' format. +The name 'floating point' refers to the fact that the radix point can change position within the number, i.e. the radix point can 'float' around. + +Another way to represent real numbers is what is called a 'fixed point' format. +The name 'fixed point' refers to the fact that the radix point does not change position within the number, i.e. it is 'fixed' in place. +This means that the range of numbers that can be represented by a fixed point is much more limited in terms of scale (how large or small the numbers can be). + +## Why Use Fixed Point Numbers? + +To allow the ability to move the radix point, the most common floating point formats are quite complicated and typically need special hardware or lots of complicated functions to implement them. + +Almost all modern CPUs have floating point capabilities built into them. +However many CPUs intended for use in embedded systems do not have this capability built in because it is not always needed and it is often cheaper to leave it out. + +This is where fixed points come in. + +By limiting the format so that the radix point is fixed in place, the implementation of fixed point numbers becomes a lot simpler. + +In fact for the most basic operations, addition and subtraction, the operations are exactly the same as they are for integers. Some of the more complicated operations like multiplication and division are very similar and merely involve a bit of bit shifting to adjust the results. + +This means that even the simplest of CPUs can use fixed point numbers without any special hardware support. As long as they support integer and bit shifting operations, they can support fixed point numbers. + +## Why Aren't Fixed Point Numbers Used More Often? + +Fixed point numbers have fallen out of favour because modern CPUs tend to come with floating point support as standard. The wide range of support for floating points and the sheer dominance of the IEEE 754 floating point format means that for most cases using floating points to perform operations on real numbers is preferred. + +Even if a particular application could be sped up by switching to fixed points, there are many reasons why people tend not to choose this option, not least because of the lack of awareness of fixed point numbers and because of the lack of available fixed point libraries. + +Indeed, finding information about fixed point numbers can be quite a struggle. + +## How Do Fixed Points Work? + +Fixed point numbers are comprised of two parts, the integer part and the fractional part. +Each part takes up a set number of bits. For example, a common format (often called `Q8.8`) has `8` bits for the integer part and 8 bits for the fractional part. + +The integer part stores the digits to the left of the radix point. +This part behaves exactly like a regular integer and for all intents and purposes can be imagined as one. If you understand how computers represent integers, you already understand the integer part. + +For example, in the `Q8.8` format, there are `8` bits in the integer part, thus it is capable of holding `256` values. The values are `0` to `255` when unsigned or `-128` to `127` when signed and in two's complement format. + +The fractional part stores the digits to the right of the radix point. +This part has special behaviour that can be a bit tricky to comprehend at first. +The simplest way to think of it is as a fraction. + +For example in the `Q8.8` format, there are `8` bits for the fractional part, which means it is capable of holding `256` values. +When thought of as a fraction, the fractional part is treated as an unsigned integer, meaning it can hold values of `0` to `255`. This integer is then imagined as the numerator of a fraction in which the denominator is the number of possible values that can be held, i.e. `256`. + +If the fractional part had the integer value of `64`, then its effective value can be represented as `64/256`, which would be equivalent to the decimal value of `0.25`. + +As a more in depth example, consider a Q8.8 value where the integer part is `5` and the fractional part has an integer value of `37`. This can be thought of as a mixed fraction `5 37/256`. +Using a calculator to divide `37` by `256` you will find that `37/256 = 0.14453125`, which means that the number being represented is `5.14453125`. + +## Further Reading + +- Wikipedia's article about [Radix Points](https://en.wikipedia.org/wiki/Radix_point) +- Wikipedia's article about [Integers](https://en.wikipedia.org/wiki/Integer) +- Wikipedia's article about [Rational Numbers](https://en.wikipedia.org/wiki/Rational_number) diff --git a/board-package-source/libraries/FixedPointsArduino/extras/Credits.md b/board-package-source/libraries/FixedPointsArduino/extras/Credits.md new file mode 100644 index 0000000..5bf721f --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/extras/Credits.md @@ -0,0 +1,14 @@ +## Main Credits: + +- [Pharap](https://github.com/Pharap) - main programmer + +## Extra special thanks to: + +- [bakagamedev](https://github.com/bakagamedev) - extra-handy duck +- [filmote](https://github.com/filmote) - testing and debugging +- [eried](https://github.com/eried) - testing and debugging + +## Special mentions: + +- crait +- Bergasms diff --git a/board-package-source/libraries/FixedPointsArduino/extras/Hello.txt b/board-package-source/libraries/FixedPointsArduino/extras/Hello.txt new file mode 100644 index 0000000..189a7ee --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/extras/Hello.txt @@ -0,0 +1,8 @@ + + /\___/\ ~ + ( O . O ) \\ + > ^ < // + ( \ / )// + u U U u + + ヘロー エブリニャン! diff --git a/board-package-source/libraries/FixedPointsArduino/extras/Important.txt b/board-package-source/libraries/FixedPointsArduino/extras/Important.txt new file mode 100644 index 0000000..702d4cd --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/extras/Important.txt @@ -0,0 +1,6 @@ +Do not attempt to use anything from the Details namespace. +Everything in the Details namespace is merely an implementation detail which may be changed without notice, +thus any attempt to use anything from the Details namespace may result in your own code breaking in future updates. + +To wrap the fixed point types in the FixedPoints namespace (e.g. in case of name conflicts): +#define FIXED_POINTS_USE_NAMESPACE \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/keywords.txt b/board-package-source/libraries/FixedPointsArduino/keywords.txt new file mode 100644 index 0000000..e713eaa --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/keywords.txt @@ -0,0 +1,47 @@ + +#################################### +# Syntax Colouring For FixedPoints # +#################################### + +#################################### +# Datatypes (KEYWORD1) # +#################################### + +SFixed KEYWORD1 +UFixed KEYWORD1 +UQ4x4 KEYWORD1 +UQ8x8 KEYWORD1 +UQ16x16 KEYWORD1 +UQ32x32 KEYWORD1 +UQ1x7 KEYWORD1 +UQ1x15 KEYWORD1 +UQ1x31 KEYWORD1 +UQ1x63 KEYWORD1 +SQ3x4 KEYWORD1 +SQ7x8 KEYWORD1 +SQ15x16 KEYWORD1 +SQ31x32 KEYWORD1 +SQ1x6 KEYWORD1 +SQ1x14 KEYWORD1 +SQ1x30 KEYWORD1 +SQ1x62 KEYWORD1 + +#################################### +# Methods and Functions (KEYWORD2) # +#################################### + +getInternal KEYWORD2 +getInteger KEYWORD2 +getFraction KEYWORD2 +fromInternal KEYWORD2 +multiply KEYWORD2 +floorFixed KEYWORD2 +ceilFixed KEYWORD2 +roundFixed KEYWORD2 +truncFixed KEYWORD2 +signbitFixed KEYWORD2 +absFixed KEYWORD2 +copysignFixed KEYWORD2 +nextafterFixed KEYWORD2 +randomUFixed KEYWORD2 +randomSFixed KEYWORD2 diff --git a/board-package-source/libraries/FixedPointsArduino/library.json b/board-package-source/libraries/FixedPointsArduino/library.json new file mode 100644 index 0000000..f99202f --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/library.json @@ -0,0 +1,18 @@ +{ + "name": "FixedPoints", + "description": "A templated header-only fixed point arithmetic library aimed at Arduino", + "keywords": "maths, fixed, point, fixed point, arithmetic", + "authors": + { + "name": "Pharap", + "url": "https://github.com/Pharap" + }, + "repository": + { + "type": "git", + "url": "https://github.com/Pharap/FixedPointsArduino.git" + }, + "license": "Apache-2.0", + "version": "1.0.7", + "frameworks": "arduino" +} \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/library.properties b/board-package-source/libraries/FixedPointsArduino/library.properties new file mode 100644 index 0000000..4d3ac0e --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/library.properties @@ -0,0 +1,10 @@ +name=FixedPoints +version=1.0.7 +author=Pharap +maintainer=Pharap +sentence=A template library for defining fixed point types of varying sizes. +paragraph=The library is designed to be generic so it should be applicable to almost all size requirements and processor architectures. +category=Data Processing +url=https://github.com/Pharap/FixedPointsArduino +architectures=* +includes=FixedPoints.h, FixedPointsCommon.h diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints.h new file mode 100644 index 0000000..435b540 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints.h @@ -0,0 +1,15 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "FixedPoints/FixedPoints.h" \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Details.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Details.h new file mode 100644 index 0000000..6abedd0 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Details.h @@ -0,0 +1,205 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#if defined(FIXED_POINTS_USE_NAMESPACE) +#define FIXED_POINTS_NAMESPACE FixedPoints +#define FIXED_POINTS_BEGIN_NAMESPACE namespace FIXED_POINTS_NAMESPACE\ +{ +#define FIXED_POINTS_END_NAMESPACE } +#define FIXED_POINTS_DETAILS Details +#else +#define FIXED_POINTS_NAMESPACE +#define FIXED_POINTS_BEGIN_NAMESPACE +#define FIXED_POINTS_END_NAMESPACE +#define FIXED_POINTS_DETAILS FixedPointsDetails +#endif + +#if defined(ESP8266) || defined(ARDUINO_SAM_DUE) +#define FIXED_POINTS_NO_RANDOM +#endif + +// Pay no attention to the man behind the curtains + +FIXED_POINTS_BEGIN_NAMESPACE +namespace FIXED_POINTS_DETAILS +{ + template< typename T > + struct BitSize + { + BitSize(void) = delete; + constexpr static const auto Value = sizeof(T) * CHAR_BIT; + }; + + template< bool Condition, typename TTrue, typename TFalse > + struct Conditional; + + template< typename TTrue, typename TFalse > + struct Conditional< true, TTrue, TFalse > { using Type = TTrue; }; + + template< typename TTrue, typename TFalse > + struct Conditional< false, TTrue, TFalse > { using Type = TFalse; }; + + template< bool Condition, typename TTrue, typename TFalse > + using ConditionalT = typename Conditional::Type; + + template< typename T, typename U > + using LargerType = ConditionalT<(BitSize::Value > BitSize::Value), T, U>; + + template< typename T, typename U > + using StrictLargerType = ConditionalT< (BitSize::Value > BitSize::Value), T, ConditionalT< (BitSize::Value > BitSize::Value), U, void > >; + + template< typename T, typename U > + using SmallerType = ConditionalT<(BitSize::Value < BitSize::Value), T, U>; + + template< typename T, typename U > + using StrictSmallerType = ConditionalT< (BitSize::Value < BitSize::Value), T, ConditionalT< (BitSize::Value < BitSize::Value), U, void > >; + + template< unsigned Bits, typename... Ts > + struct LeastTypeHelper; + + template< unsigned Bits, typename T, typename... Ts > + struct LeastTypeHelper + { + LeastTypeHelper(void) = delete; + using Type = ConditionalT<(Bits <= BitSize::Value), T, typename LeastTypeHelper::Type>; + }; + + template< unsigned Bits > + struct LeastTypeHelper + { + LeastTypeHelper(void) = delete; + using Type = void; + }; + + + template< unsigned Bits, typename... Ts > + using LeastType = typename LeastTypeHelper::Type; + + template< unsigned Bits > + struct LeastUIntDef + { + static_assert(Bits <= BitSize::Value, "No type large enough"); + LeastUIntDef(void) = delete; + using Type = LeastType; + }; + + + template< unsigned Bits > + using LeastUInt = typename LeastUIntDef::Type; + + template< unsigned Bits > + struct LeastIntDef + { + static_assert(Bits <= BitSize::Value, "No type large enough"); + LeastIntDef(void) = delete; + using Type = LeastType; + }; + + template< unsigned Bits > + using LeastInt = typename LeastIntDef::Type; + + template< unsigned Bits > + struct MsbMask + { + MsbMask(void) = delete; + constexpr const static LeastUInt Value = (1ull << (Bits - 1)); + }; + + template< unsigned Bits > + struct IdentityMask + { + IdentityMask(void) = delete; + constexpr const static LeastUInt Value = 1 | (IdentityMask::Value << 1); + }; + + template<> + struct IdentityMask<0> + { + IdentityMask(void) = delete; + constexpr const static LeastUInt<0> Value = 0; + }; + +#if !defined(FIXED_POINTS_NO_RANDOM) + template< typename T > + struct RandomHelper; + + template<> + struct RandomHelper + { + static inline uint8_t Random() { return static_cast(random()); } + }; + + template<> + struct RandomHelper + { + static inline uint16_t Random() { return static_cast(random()); } + }; + + template<> + struct RandomHelper + { + static inline uint32_t Random() { return static_cast(random()); } + }; + + template<> + struct RandomHelper + { + static inline uint64_t Random() { return (static_cast(random()) << 32) | static_cast(random()); } + }; + + template<> + struct RandomHelper + { + static inline int8_t Random() { return static_cast(random()); } + }; + + template<> + struct RandomHelper + { + static inline int16_t Random() { return static_cast(random()); } + }; + + template<> + struct RandomHelper + { + static inline int32_t Random() { return static_cast(random()); } + }; + + template<> + struct RandomHelper + { + static inline int64_t Random() { return (static_cast(random()) << 32) | static_cast(random()); } + }; +#endif + + /////////////////////// + // Here be dragons!! // + // // + // /\___/\ _ // + // ( O . O ) \\ // + // > ^ < // // + // ( \ / )// // + // u U U u // + // // + // Or cats?... // + // ~Mwrow~ // + /////////////////////// +} +FIXED_POINTS_END_NAMESPACE diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/FixedPoints.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/FixedPoints.h new file mode 100644 index 0000000..8325e36 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/FixedPoints.h @@ -0,0 +1,20 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Details.h" + +#include "UFixed.h" +#include "SFixed.h" + +#include "Utils.h" \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixed.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixed.h new file mode 100644 index 0000000..da7ad3a --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixed.h @@ -0,0 +1,219 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Details.h" + +FIXED_POINTS_BEGIN_NAMESPACE + +// +// Declaration +// + +template< unsigned Integer, unsigned Fraction > +class SFixed +{ +public: + constexpr const static uintmax_t IntegerSize = Integer + 1; + constexpr const static uintmax_t FractionSize = Fraction; + constexpr const static uintmax_t LogicalSize = IntegerSize + FractionSize; + constexpr const static uintmax_t Scale = UINTMAX_C(1) << FractionSize; + +public: + static_assert(LogicalSize <= FIXED_POINTS_DETAILS::BitSize::Value, "Platform does not have a native type large enough for SFixed."); + +public: + using IntegerType = FIXED_POINTS_DETAILS::LeastInt; + using FractionType = FIXED_POINTS_DETAILS::LeastUInt; + using InternalType = FIXED_POINTS_DETAILS::LeastInt; + + constexpr const static uintmax_t InternalSize = FIXED_POINTS_DETAILS::BitSize::Value; + + using ShiftType = FIXED_POINTS_DETAILS::LeastUInt; + using MaskType = FIXED_POINTS_DETAILS::LeastUInt; + +public: + constexpr const static ShiftType IntegerShift = FractionSize; + constexpr const static ShiftType FractionShift = 0; + + constexpr const static MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + constexpr const static MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + + constexpr const static MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift); + + constexpr const static MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask::Value; + constexpr const static MaskType LesserMidpointMask = MidpointMask - 1; + +protected: + class RawType + { + private: + const InternalType value; + + public: + constexpr inline explicit RawType(const InternalType & value) : value(value) {} + constexpr inline explicit operator InternalType(void) const { return this->value; } + }; + +protected: + InternalType value; + +protected: + constexpr SFixed(const RawType & value); + +public: + constexpr SFixed(void); + constexpr SFixed(const IntegerType & integer, const FractionType & fraction); + constexpr SFixed(const char & value); + constexpr SFixed(const unsigned char & value); + constexpr SFixed(const signed char & value); + constexpr SFixed(const unsigned short int & value); + constexpr SFixed(const signed short int & value); + constexpr SFixed(const unsigned int & value); + constexpr SFixed(const signed int & value); + constexpr SFixed(const unsigned long int & value); + constexpr SFixed(const signed long int & value); + constexpr SFixed(const unsigned long long int & value); + constexpr SFixed(const signed long long int & value); + constexpr SFixed(const double & value); + constexpr SFixed(const float & value); + constexpr SFixed(const long double & value); + + constexpr InternalType getInternal(void) const; + constexpr IntegerType getInteger(void) const; + constexpr FractionType getFraction(void) const; + + constexpr explicit operator IntegerType(void) const; + constexpr explicit operator float(void) const; + constexpr explicit operator double(void) const; + constexpr explicit operator long double(void) const; + + template< unsigned IntegerOut, unsigned FractionOut > + constexpr explicit operator SFixed(void) const; + + constexpr static SFixed fromInternal(const InternalType & value); + + constexpr SFixed operator -(void) const; + SFixed & operator ++(void); + SFixed & operator --(void); + SFixed & operator +=(const SFixed & other); + SFixed & operator -=(const SFixed & other); + SFixed & operator *=(const SFixed & other); + SFixed & operator /=(const SFixed & other); + +public: + constexpr const static SFixed Epsilon = SFixed::fromInternal(1); + constexpr const static SFixed MinValue = SFixed::fromInternal(FIXED_POINTS_DETAILS::MsbMask::Value); + constexpr const static SFixed MaxValue = SFixed::fromInternal(~FIXED_POINTS_DETAILS::MsbMask::Value); + + // 40 digits is probably enough for these + constexpr const static SFixed Pi = 3.1415926535897932384626433832795028841971; + constexpr const static SFixed E = 2.718281828459045235360287471352662497757; + constexpr const static SFixed Phi = 1.6180339887498948482045868343656381177203; + constexpr const static SFixed Tau = 6.2831853071795864769252867665590057683943; +}; + + +// +// Free functions +// + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed multiply(const SFixed & left, const SFixed & right); + +// +// Basic Logic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator ==(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator !=(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <=(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >=(const SFixed & left, const SFixed & right); + +// +// Inter-size Logic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator ==(const SFixed & left, const SFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator !=(const SFixed & left, const SFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <(const SFixed & left, const SFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >(const SFixed & left, const SFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <=(const SFixed & left, const SFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >=(const SFixed & left, const SFixed & right); + +// +// Basic Arithmetic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator +(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator -(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator *(const SFixed & left, const SFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator /(const SFixed & left, const SFixed & right); + +// +// Inter-size Arithmetic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator +(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator -(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator *(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +inline constexpr auto operator /(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed >; + +FIXED_POINTS_END_NAMESPACE + +#include "SFixedMemberFunctions.h" +#include "SFixedFreeFunctions.h" \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedFreeFunctions.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedFreeFunctions.h new file mode 100644 index 0000000..1fe5047 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedFreeFunctions.h @@ -0,0 +1,323 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +FIXED_POINTS_BEGIN_NAMESPACE + +// +// multiply +// + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed multiply(const SFixed & left, const SFixed & right) +{ + static_assert(((Integer + 1) * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the result type would be too large"); + + using ResultType = SFixed; + using InternalType = typename ResultType::InternalType; + return ResultType::fromInternal(static_cast(static_cast(left.getInternal()) * static_cast(right.getInternal()))); +} + +// +// Basic Logic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator ==(const SFixed & left, const SFixed & right) +{ + return (left.getInternal() == right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator !=(const SFixed & left, const SFixed & right) +{ + return (left.getInternal() != right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <(const SFixed & left, const SFixed & right) +{ + return (left.getInternal() < right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >(const SFixed & left, const SFixed & right) +{ + return (left.getInternal() > right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <=(const SFixed & left, const SFixed & right) +{ + return (left.getInternal() <= right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >=(const SFixed & left, const SFixed & right) +{ + return (left.getInternal() >= right.getInternal()); +} + +// +// Inter-size Logic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator ==(const SFixed & left, const SFixed & right) +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) == static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator !=(const SFixed & left, const SFixed & right) +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) != static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <(const SFixed & left, const SFixed & right) +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) < static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >(const SFixed & left, const SFixed & right) +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) > static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <=(const SFixed & left, const SFixed & right) +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) <= static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >=(const SFixed & left, const SFixed & right) +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) >= static_cast(right)); +} + +// +// Basic Arithmetic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator +(const SFixed & left, const SFixed & right) +{ + using InternalType = typename SFixed::InternalType; + return SFixed::fromInternal(static_cast(left.getInternal() + right.getInternal())); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator -(const SFixed & left, const SFixed & right) +{ + using InternalType = typename SFixed::InternalType; + return SFixed::fromInternal(static_cast(left.getInternal() - right.getInternal())); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator *(const SFixed & left, const SFixed & right) +{ + static_assert(((Integer + 1) * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the intermediary type would be too large"); + + using InternalType = typename SFixed::InternalType; + using PrecisionType = typename SFixed::InternalType; + return SFixed::fromInternal(static_cast((static_cast(left.getInternal()) * static_cast(right.getInternal())) >> Fraction)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed operator /(const SFixed & left, const SFixed & right) +{ + using InternalType = typename SFixed::InternalType; + using PrecisionType = typename SFixed::InternalType; + return SFixed::fromInternal(static_cast((static_cast(left.getInternal()) << Fraction) / right.getInternal())); +} + +// +// Inter-size Arithmetic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator +(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) + static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator -(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) - static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator *(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) * static_cast(right)); +} + + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator /(const SFixed & left, const SFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< SFixed, SFixed > +{ + using LeftType = SFixed; + using RightType = SFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) / static_cast(right)); +} + +// +// Literal-type Operators +// Generated by macro to make maintenance easier +// + +#define LOGIC_OPERATOR( type, op )\ + template< unsigned Integer, unsigned Fraction >\ + constexpr bool operator op (const SFixed & left, const type & right)\ + {\ + return (left op SFixed(right));\ + }\ + \ + template< unsigned Integer, unsigned Fraction >\ + constexpr bool operator op (const type & left, const SFixed & right)\ + {\ + return (SFixed(left) op right);\ + } + +#define ARITHMETIC_OPERATOR( type, op )\ + template< unsigned Integer, unsigned Fraction >\ + constexpr SFixed operator op (const SFixed & left, const type & right)\ + {\ + return (left op SFixed(right));\ + }\ + \ + template< unsigned Integer, unsigned Fraction >\ + constexpr SFixed operator op (const type & left, const SFixed & right)\ + {\ + return (SFixed(left) op right);\ + } + +#define LOGIC_OPERATORS( type )\ + LOGIC_OPERATOR( type, == )\ + LOGIC_OPERATOR( type, != )\ + LOGIC_OPERATOR( type, < )\ + LOGIC_OPERATOR( type, <= )\ + LOGIC_OPERATOR( type, > )\ + LOGIC_OPERATOR( type, >= ) + +#define ARITHMETIC_OPERATORS( type ) \ + ARITHMETIC_OPERATOR( type, + )\ + ARITHMETIC_OPERATOR( type, - )\ + ARITHMETIC_OPERATOR( type, * )\ + ARITHMETIC_OPERATOR( type, / ) + +#define OPERATORS( type ) \ + LOGIC_OPERATORS( type )\ + ARITHMETIC_OPERATORS( type ) + +OPERATORS( float ) +OPERATORS( double ) +OPERATORS( long double ) + +OPERATORS( char ) +OPERATORS( unsigned char ) +OPERATORS( signed char ) +OPERATORS( unsigned short int ) +OPERATORS( signed short int ) +OPERATORS( unsigned int ) +OPERATORS( signed int ) +OPERATORS( unsigned long int ) +OPERATORS( signed long int ) +OPERATORS( unsigned long long int ) +OPERATORS( signed long long int ) + +// Prevent Macro-bleed: + +#undef OPERATORS +#undef ARITHMETIC_OPERATORS +#undef LOGIC_OPERATORS +#undef ARITHMETIC_OPERATOR +#undef LOGIC_OPERATOR + +FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedMemberFunctions.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedMemberFunctions.h new file mode 100644 index 0000000..e11b8ef --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/SFixedMemberFunctions.h @@ -0,0 +1,273 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +FIXED_POINTS_BEGIN_NAMESPACE + +// +// Constructors +// + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const RawType & value) + : value(static_cast(value)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(void) + : value(0) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const IntegerType & integer, const FractionType & fraction) + : value((static_cast(integer) << FractionSize) | fraction) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const char & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const unsigned char & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const signed char & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const unsigned short int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const signed short int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const unsigned int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const signed int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const unsigned long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const signed long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const unsigned long long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const signed long long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const float & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::SFixed(const long double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + +// +// Getters +// + +template< unsigned Integer, unsigned Fraction > +constexpr typename SFixed::InternalType SFixed::getInternal(void) const +{ + return this->value; +} + +template< unsigned Integer, unsigned Fraction > +constexpr typename SFixed::IntegerType SFixed::getInteger(void) const +{ + return (static_cast(this->value >> IntegerShift) & IntegerMask) | ((this->value < 0) ? ~IntegerMask : 0); +} + +template< unsigned Integer, unsigned Fraction > +constexpr typename SFixed::FractionType SFixed::getFraction(void) const +{ + return static_cast(this->value >> FractionShift) & FractionMask; +} + +// +// Cast Operators +// + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::operator IntegerType(void) const +{ + return this->getInteger(); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::operator float(void) const +{ + return (1.0F / Scale) * + static_cast + ((this->value & IdentityMask) | + ((this->value < 0) ? ~IdentityMask : 0)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::operator double(void) const +{ + return (1.0 / Scale) * + static_cast + ((this->value & IdentityMask) | + ((this->value < 0) ? ~IdentityMask : 0)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed::operator long double(void) const +{ + return (1.0L / Scale) * + static_cast + ((this->value & IdentityMask) | + ((this->value < 0) ? ~IdentityMask : 0)); +} + +template< unsigned Integer, unsigned Fraction > +template< unsigned IntegerOut, unsigned FractionOut > +constexpr SFixed::operator SFixed(void) const +{ + using OutputType = SFixed; + using OutputInternalType = typename OutputType::InternalType; + using OutputShiftType = typename OutputType::ShiftType; + + using InputType = SFixed; + using InputShiftType = typename InputType::ShiftType; + + return + (FractionOut > FractionSize) ? + OutputType::fromInternal(static_cast(static_cast(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) : + (FractionSize > FractionOut) ? + OutputType::fromInternal(static_cast(static_cast(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) : + OutputType::fromInternal(this->value); +} + +// +// Static Functions +// + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed SFixed::fromInternal(const typename SFixed::InternalType & value) +{ + return SFixed(RawType(value)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed SFixed::operator -(void) const +{ + return SFixed::fromInternal(-this->value); +} + +// +// Member Operators +// + +template< unsigned Integer, unsigned Fraction > +SFixed & SFixed::operator ++(void) +{ + this->value += (1 << FractionSize); + return *this; +} + +template< unsigned Integer, unsigned Fraction > +SFixed & SFixed::operator --(void) +{ + this->value -= (1 << FractionSize); + return *this; +} + +// +// Compound Assignment Operators +// + +template< unsigned Integer, unsigned Fraction > +SFixed & SFixed::operator +=(const SFixed & other) +{ + this->value += other.value; + return *this; +} + +template< unsigned Integer, unsigned Fraction > +SFixed & SFixed::operator -=(const SFixed & other) +{ + this->value -= other.value; + return *this; +} + +template< unsigned Integer, unsigned Fraction > +SFixed & SFixed::operator *=(const SFixed & other) +{ + using InternalType = typename SFixed::InternalType; + using PrecisionType = typename SFixed::InternalType; + const PrecisionType temp = (static_cast(this->value) * static_cast(other.value)) >> Fraction; + this->value = static_cast(temp); + return *this; +} + +template< unsigned Integer, unsigned Fraction > +SFixed & SFixed::operator /=(const SFixed & other) +{ + using InternalType = typename SFixed::InternalType; + using PrecisionType = typename SFixed::InternalType; + const PrecisionType temp = (static_cast(this->value) << Fraction) / static_cast(other.value); + this->value = static_cast(temp); + return *this; +} + +FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixed.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixed.h new file mode 100644 index 0000000..34344eb --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixed.h @@ -0,0 +1,220 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Details.h" + +FIXED_POINTS_BEGIN_NAMESPACE + +// +// Declaration +// + +template< unsigned Integer, unsigned Fraction > +class UFixed +{ +public: + constexpr const static uintmax_t IntegerSize = Integer; + constexpr const static uintmax_t FractionSize = Fraction; + constexpr const static uintmax_t LogicalSize = IntegerSize + FractionSize; + constexpr const static uintmax_t Scale = UINTMAX_C(1) << FractionSize; + +public: + static_assert(LogicalSize <= FIXED_POINTS_DETAILS::BitSize::Value, "Platform does not have a native type large enough for UFixed."); + +public: + using IntegerType = FIXED_POINTS_DETAILS::LeastUInt; + using FractionType = FIXED_POINTS_DETAILS::LeastUInt; + using InternalType = FIXED_POINTS_DETAILS::LeastUInt; + + constexpr const static uintmax_t InternalSize = FIXED_POINTS_DETAILS::BitSize::Value; + + using ShiftType = FIXED_POINTS_DETAILS::LeastUInt; + using MaskType = FIXED_POINTS_DETAILS::LeastUInt; + +public: + constexpr const static ShiftType IntegerShift = FractionSize; + constexpr const static ShiftType FractionShift = 0; + + constexpr const static MaskType IntegerMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + constexpr const static MaskType FractionMask = FIXED_POINTS_DETAILS::IdentityMask::Value; + + constexpr const static MaskType IdentityMask = (IntegerMask << IntegerShift) | (FractionMask << FractionShift); + + constexpr const static MaskType MidpointMask = FIXED_POINTS_DETAILS::MsbMask::Value; + constexpr const static MaskType LesserMidpointMask = MidpointMask - 1; + +protected: + class RawType + { + private: + const InternalType value; + + public: + constexpr inline explicit RawType(const InternalType & value) : value(value) {} + constexpr inline explicit operator InternalType(void) const { return this->value; } + }; + +protected: + InternalType value; + +protected: + constexpr UFixed(const RawType & value); + +public: + constexpr UFixed(void); + constexpr UFixed(const IntegerType & integer, const FractionType & fraction); + constexpr UFixed(const char & value); + constexpr UFixed(const unsigned char & value); + constexpr UFixed(const signed char & value); + constexpr UFixed(const unsigned short int & value); + constexpr UFixed(const signed short int & value); + constexpr UFixed(const unsigned int & value); + constexpr UFixed(const signed int & value); + constexpr UFixed(const unsigned long int & value); + constexpr UFixed(const signed long int & value); + constexpr UFixed(const unsigned long long int & value); + constexpr UFixed(const signed long long int & value); + constexpr UFixed(const double & value); + constexpr UFixed(const float & value); + constexpr UFixed(const long double & value); + +public: + constexpr InternalType getInternal(void) const; + constexpr IntegerType getInteger(void) const; + constexpr FractionType getFraction(void) const; + + constexpr explicit operator IntegerType(void) const; + constexpr explicit operator float(void) const; + constexpr explicit operator double(void) const; + constexpr explicit operator long double(void) const; + + template< unsigned IntegerOut, unsigned FractionOut > + constexpr explicit operator UFixed(void) const; + + constexpr static UFixed fromInternal(const InternalType & value); + + UFixed & operator ++(void); + UFixed & operator --(void); + UFixed & operator +=(const UFixed & other); + UFixed & operator -=(const UFixed & other); + UFixed & operator *=(const UFixed & other); + UFixed & operator /=(const UFixed & other); + +public: + constexpr const static UFixed Epsilon = UFixed::fromInternal(1); + constexpr const static UFixed MinValue = UFixed::fromInternal(0); + constexpr const static UFixed MaxValue = UFixed::fromInternal(~0); + + // 40 digits is probably enough for these + constexpr const static UFixed Pi = 3.1415926535897932384626433832795028841971; + constexpr const static UFixed E = 2.718281828459045235360287471352662497757; + constexpr const static UFixed Phi = 1.6180339887498948482045868343656381177203; + constexpr const static UFixed Tau = 6.2831853071795864769252867665590057683943; +}; + + +// +// Free functions +// + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed multiply(const UFixed & left, const UFixed & right); + + +// +// Basic Logic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator ==(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator !=(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <=(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >=(const UFixed & left, const UFixed & right); + +// +// Inter-size Logic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator ==(const UFixed & left, const UFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator !=(const UFixed & left, const UFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <(const UFixed & left, const UFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >(const UFixed & left, const UFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <=(const UFixed & left, const UFixed & right); + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >=(const UFixed & left, const UFixed & right); + +// +// Basic Arithmetic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator +(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator -(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator *(const UFixed & left, const UFixed & right); + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator /(const UFixed & left, const UFixed & right); + +// +// Inter-size Arithmetic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator +(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator -(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator *(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +inline constexpr auto operator /(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed >; + +FIXED_POINTS_END_NAMESPACE + +#include "UFixedMemberFunctions.h" +#include "UFixedFreeFunctions.h" \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedFreeFunctions.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedFreeFunctions.h new file mode 100644 index 0000000..55b042e --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedFreeFunctions.h @@ -0,0 +1,323 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +FIXED_POINTS_BEGIN_NAMESPACE + +// +// multiply +// + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed multiply(const UFixed & left, const UFixed & right) +{ + static_assert((Integer * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the result type would be too large"); + + using ResultType = UFixed; + using InternalType = typename ResultType::InternalType; + return ResultType::fromInternal(static_cast(static_cast(left.getInternal()) * static_cast(right.getInternal()))); +} + +// +// Basic Logic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator ==(const UFixed & left, const UFixed & right) +{ + return (left.getInternal() == right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator !=(const UFixed & left, const UFixed & right) +{ + return (left.getInternal() != right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <(const UFixed & left, const UFixed & right) +{ + return (left.getInternal() < right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >(const UFixed & left, const UFixed & right) +{ + return (left.getInternal() > right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator <=(const UFixed & left, const UFixed & right) +{ + return (left.getInternal() <= right.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool operator >=(const UFixed & left, const UFixed & right) +{ + return (left.getInternal() >= right.getInternal()); +} + +// +// Inter-size Logic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator ==(const UFixed & left, const UFixed & right) +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator == has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) == static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator !=(const UFixed & left, const UFixed & right) +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator != has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) != static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <(const UFixed & left, const UFixed & right) +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator < has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) < static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >(const UFixed & left, const UFixed & right) +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator > has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) > static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator <=(const UFixed & left, const UFixed & right) +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator <= has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) <= static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr bool operator >=(const UFixed & left, const UFixed & right) +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator >= has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) >= static_cast(right)); +} + +// +// Basic Arithmetic Operations +// + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator +(const UFixed & left, const UFixed & right) +{ + using InternalType = typename UFixed::InternalType; + return UFixed::fromInternal(static_cast(left.getInternal() + right.getInternal())); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator -(const UFixed & left, const UFixed & right) +{ + using InternalType = typename UFixed::InternalType; + return UFixed::fromInternal(static_cast(left.getInternal() - right.getInternal())); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator *(const UFixed & left, const UFixed & right) +{ + static_assert((Integer * 2 + Fraction * 2) <= FIXED_POINTS_DETAILS::BitSize::Value, "Multiplication cannot be performed, the intermediary type would be too large"); + + using InternalType = typename UFixed::InternalType; + using PrecisionType = typename UFixed::InternalType; + return UFixed::fromInternal(static_cast((static_cast(left.getInternal()) * static_cast(right.getInternal())) >> Fraction)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed operator /(const UFixed & left, const UFixed & right) +{ + using InternalType = typename UFixed::InternalType; + using PrecisionType = typename UFixed::InternalType; + return UFixed::fromInternal(static_cast((static_cast(left.getInternal()) << Fraction) / static_cast(right.getInternal()))); +} + +// +// Inter-size Arithmetic Operations +// + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator +(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator + has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) + static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator -(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator - has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) - static_cast(right)); +} + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator *(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator * has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) * static_cast(right)); +} + + +template< unsigned IntegerLeft, unsigned FractionLeft, unsigned IntegerRight, unsigned FractionRight > +constexpr auto operator /(const UFixed & left, const UFixed & right) + -> FIXED_POINTS_DETAILS::LargerType< UFixed, UFixed > +{ + using LeftType = UFixed; + using RightType = UFixed; + + static_assert(LeftType::InternalSize != RightType::InternalSize, "operator / has ambiguous result"); + + using CompareType = FIXED_POINTS_DETAILS::LargerType; + + return (static_cast(left) / static_cast(right)); +} + +// +// Literal-type Operators +// Generated by macro to make maintenance easier +// + +#define LOGIC_OPERATOR( type, op )\ + template< unsigned Integer, unsigned Fraction >\ + constexpr bool operator op (const UFixed & left, const type & right)\ + {\ + return (left op UFixed(right));\ + }\ + \ + template< unsigned Integer, unsigned Fraction >\ + constexpr bool operator op (const type & left, const UFixed & right)\ + {\ + return (UFixed(left) op right);\ + } + +#define ARITHMETIC_OPERATOR( type, op )\ + template< unsigned Integer, unsigned Fraction >\ + constexpr UFixed operator op (const UFixed & left, const type & right)\ + {\ + return (left op UFixed(right));\ + }\ + \ + template< unsigned Integer, unsigned Fraction >\ + constexpr UFixed operator op (const type & left, const UFixed & right)\ + {\ + return (UFixed(left) op right);\ + } + +#define LOGIC_OPERATORS( type )\ + LOGIC_OPERATOR( type, == )\ + LOGIC_OPERATOR( type, != )\ + LOGIC_OPERATOR( type, < )\ + LOGIC_OPERATOR( type, <= )\ + LOGIC_OPERATOR( type, > )\ + LOGIC_OPERATOR( type, >= ) + +#define ARITHMETIC_OPERATORS( type ) \ + ARITHMETIC_OPERATOR( type, + )\ + ARITHMETIC_OPERATOR( type, - )\ + ARITHMETIC_OPERATOR( type, * )\ + ARITHMETIC_OPERATOR( type, / ) + +#define OPERATORS( type ) \ + LOGIC_OPERATORS( type )\ + ARITHMETIC_OPERATORS( type ) + +OPERATORS( float ) +OPERATORS( double ) +OPERATORS( long double ) + +OPERATORS( char ) +OPERATORS( unsigned char ) +OPERATORS( signed char ) +OPERATORS( unsigned short int ) +OPERATORS( signed short int ) +OPERATORS( unsigned int ) +OPERATORS( signed int ) +OPERATORS( unsigned long int ) +OPERATORS( signed long int ) +OPERATORS( unsigned long long int ) +OPERATORS( signed long long int ) + +// Prevent Macro-bleed: + +#undef OPERATORS +#undef ARITHMETIC_OPERATORS +#undef LOGIC_OPERATORS +#undef ARITHMETIC_OPERATOR +#undef LOGIC_OPERATOR + +FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedMemberFunctions.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedMemberFunctions.h new file mode 100644 index 0000000..69f99e0 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/UFixedMemberFunctions.h @@ -0,0 +1,258 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +FIXED_POINTS_BEGIN_NAMESPACE + +// +// Constructors +// + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const RawType & value) + : value(static_cast(value)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(void) + : value(0) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const IntegerType & integer, const FractionType & fraction) + : value((static_cast(integer) << FractionSize) | fraction) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const char & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const unsigned char & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const signed char & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const unsigned short int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const signed short int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const unsigned int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const signed int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const unsigned long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const signed long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const unsigned long long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const signed long long int & value) + : value(static_cast(static_cast< FIXED_POINTS_DETAILS::LargerType >(value) << FractionSize)) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const float & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::UFixed(const long double & value) + : value(static_cast(value * static_cast(Scale))) +{ +} + +// +// Getters +// + +template< unsigned Integer, unsigned Fraction > +constexpr typename UFixed::InternalType UFixed::getInternal(void) const +{ + return this->value; +} + +template< unsigned Integer, unsigned Fraction > +constexpr typename UFixed::IntegerType UFixed::getInteger(void) const +{ + return static_cast(this->value >> IntegerShift) & IntegerMask; +} + +template< unsigned Integer, unsigned Fraction > +constexpr typename UFixed::FractionType UFixed::getFraction(void) const +{ + return static_cast(this->value >> FractionShift) & FractionMask; +} + +// +// Cast Operators +// + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::operator IntegerType(void) const +{ + return this->getInteger(); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::operator float(void) const +{ + return ((this->value & IdentityMask) * (1.0F / Scale)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::operator double(void) const +{ + return ((this->value & IdentityMask) * (1.0 / Scale)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed::operator long double(void) const +{ + return ((this->value & IdentityMask) * (1.0L / Scale)); +} + +template< unsigned Integer, unsigned Fraction > +template< unsigned IntegerOut, unsigned FractionOut > +constexpr UFixed::operator UFixed(void) const +{ + using OutputType = UFixed; + using OutputInternalType = typename OutputType::InternalType; + using OutputShiftType = typename OutputType::ShiftType; + + using InputType = UFixed; + using InputShiftType = typename InputType::ShiftType; + + return + (FractionOut > FractionSize) ? + OutputType::fromInternal(static_cast(static_cast(this->value) << ((FractionOut > FractionSize) ? (FractionOut - FractionSize) : 0))) : + (FractionSize > FractionOut) ? + OutputType::fromInternal(static_cast(static_cast(this->value) >> ((FractionSize > FractionOut) ? (FractionSize - FractionOut) : 0))) : + OutputType::fromInternal(this->value); +} + +// +// Static Functions +// + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed UFixed::fromInternal(const typename UFixed::InternalType & value) +{ + return UFixed(RawType(value)); +} + +// +// Member Operators +// + +template< unsigned Integer, unsigned Fraction > +UFixed & UFixed::operator ++(void) +{ + this->value += (1 << FractionSize); + return *this; +} + +template< unsigned Integer, unsigned Fraction > +UFixed & UFixed::operator --(void) +{ + this->value -= (1 << FractionSize); + return *this; +} + +// +// Compound Assignment Operators +// + +template< unsigned Integer, unsigned Fraction > +UFixed & UFixed::operator +=(const UFixed & other) +{ + this->value += other.value; + return *this; +} + +template< unsigned Integer, unsigned Fraction > +UFixed & UFixed::operator -=(const UFixed & other) +{ + this->value -= other.value; + return *this; +} + +template< unsigned Integer, unsigned Fraction > +UFixed & UFixed::operator *=(const UFixed & other) +{ + using InternalType = typename UFixed::InternalType; + using PrecisionType = typename UFixed::InternalType; + const PrecisionType temp = (static_cast(this->value) * static_cast(other.value)) >> FractionSize; + this->value = static_cast(temp); + return *this; +} + +template< unsigned Integer, unsigned Fraction > +UFixed & UFixed::operator /=(const UFixed & other) +{ + using InternalType = typename UFixed::InternalType; + using PrecisionType = typename UFixed::InternalType; + const PrecisionType temp = (static_cast(this->value) << FractionSize) / static_cast(other.value); + this->value = static_cast(temp); + return *this; +} + +FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Utils.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Utils.h new file mode 100644 index 0000000..0d1cf6b --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPoints/Utils.h @@ -0,0 +1,256 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Details.h" +#include "UFixed.h" +#include "SFixed.h" + +// +// Declaration +// + +FIXED_POINTS_BEGIN_NAMESPACE + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed floorFixed(const UFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed floorFixed(const SFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed ceilFixed(const UFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed ceilFixed(const SFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed roundFixed(const UFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed roundFixed(const SFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr bool signbitFixed(const SFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed absFixed(const SFixed & value); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed copysignFixed(const SFixed & x, const SFixed & y); + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed nextafterFixed(const SFixed & from, const SFixed & to); + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed nextafterFixed(const UFixed & from, const UFixed & to); + +// +// Unsigned Random +// + +#if !defined(FIXED_POINTS_NO_RANDOM) +template< unsigned Integer, unsigned Fraction > +UFixed randomUFixed(void); + +template< unsigned Integer, unsigned Fraction > +UFixed randomUFixed(const UFixed & exclusiveUpperBound); + +template< unsigned Integer, unsigned Fraction > +UFixed randomUFixed(const UFixed & inclusiveLowerBound, const UFixed & exclusiveUpperBound); +#endif + +// +// Signed Random +// + +#if !defined(FIXED_POINTS_NO_RANDOM) +template< unsigned Integer, unsigned Fraction > +SFixed randomSFixed(void); + +template< unsigned Integer, unsigned Fraction > +SFixed randomSFixed(const SFixed & exclusiveUpperBound); + +template< unsigned Integer, unsigned Fraction > +SFixed randomSFixed(const SFixed & inclusiveLowerBound, const SFixed & exclusiveUpperBound); +#endif + +FIXED_POINTS_END_NAMESPACE + +// +// Definition +// + +FIXED_POINTS_BEGIN_NAMESPACE + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed floorFixed(const UFixed & value) +{ + using OutputType = UFixed; + using InternalType = typename OutputType::InternalType; + return OutputType::fromInternal(static_cast(value.getInternal() & ~OutputType::FractionMask)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed floorFixed(const SFixed & value) +{ + using OutputType = SFixed; + using InternalType = typename OutputType::InternalType; + return OutputType::fromInternal(static_cast(value.getInternal() & ~OutputType::FractionMask)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed ceilFixed(const UFixed & value) +{ + return UFixed((value.getFraction() == 0) ? value.getInteger() : (value.getInteger() + 1), 0); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed ceilFixed(const SFixed & value) +{ + return SFixed((value.getFraction() == 0) ? value.getInteger() : (value.getInteger() + 1), 0); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed roundFixed(const UFixed & value) +{ + using OutputType = UFixed; + return (value.getFraction() >= OutputType(0.5).getFraction()) ? ceilFixed(value) : floorFixed(value); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed roundFixed(const SFixed & value) +{ + using OutputType = SFixed; + return + signbitFixed(value) ? + ((value.getFraction() <= OutputType(0.5).getFraction()) ? floorFixed(value) : ceilFixed(value)) : + ((value.getFraction() >= OutputType(0.5).getFraction()) ? ceilFixed(value) : floorFixed(value)); +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed truncFixed(const UFixed & value) +{ + return UFixed(value.getInteger(), 0); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed truncFixed(const SFixed & value) +{ + using OutputType = SFixed; + return + (value.getInternal() < 0) ? + OutputType::fromInternal(value.getInternal() & ~OutputType::FractionMask) + OutputType(1, 0) : + OutputType::fromInternal(value.getInternal() & ~OutputType::FractionMask); +} + +template< unsigned Integer, unsigned Fraction > +constexpr bool signbitFixed(const SFixed & value) +{ + return (value.getInternal() < 0); +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed absFixed(const SFixed & value) +{ + return (signbitFixed(value)) ? -value : value; +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed copysignFixed(const SFixed & x, const SFixed & y) +{ + return (signbitFixed(x) != signbitFixed(y)) ? -x : x; +} + +template< unsigned Integer, unsigned Fraction > +constexpr SFixed nextafterFixed(const SFixed & from, const SFixed & to) +{ + using ResultType = SFixed; + return + (from < to) ? + ResultType::fromInternal(from.getInternal() + 1) : + (from > to) ? + ResultType::fromInternal(from.getInternal() - 1) : + to; +} + +template< unsigned Integer, unsigned Fraction > +constexpr UFixed nextafterFixed(const UFixed & from, const UFixed & to) +{ + using ResultType = UFixed; + return + (from < to) ? + ResultType::fromInternal(from.getInternal() + 1) : + (from > to) ? + ResultType::fromInternal(from.getInternal() - 1) : + to; +} + +// +// Unsigned Random +// + +#if !defined(FIXED_POINTS_NO_RANDOM) +template< unsigned Integer, unsigned Fraction > +UFixed randomUFixed(void) +{ + using InternalType = typename UFixed::InternalType; + return UFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random()); +} + +template< unsigned Integer, unsigned Fraction > +UFixed randomUFixed(const UFixed & exclusiveUpperBound) +{ + using InternalType = typename UFixed::InternalType; + return UFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random() % exclusiveUpperBound.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +UFixed randomUFixed(const UFixed & inclusiveLowerBound, const UFixed & exclusiveUpperBound) +{ + using InternalType = typename UFixed::InternalType; + return UFixed::fromInternal(inclusiveLowerBound.getInternal() + (FIXED_POINTS_DETAILS::RandomHelper::Random() % (exclusiveUpperBound.getInternal() - inclusiveLowerBound.getInternal()))); +} +#endif + +// +// Signed Random +// + +#if !defined(FIXED_POINTS_NO_RANDOM) +template< unsigned Integer, unsigned Fraction > +SFixed randomSFixed(void) +{ + using InternalType = typename SFixed::InternalType; + return SFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random()); +} + +template< unsigned Integer, unsigned Fraction > +SFixed randomSFixed(const SFixed & exclusiveUpperBound) +{ + using InternalType = typename SFixed::InternalType; + return SFixed::fromInternal(FIXED_POINTS_DETAILS::RandomHelper::Random() % exclusiveUpperBound.getInternal()); +} + +template< unsigned Integer, unsigned Fraction > +SFixed randomSFixed(const SFixed & inclusiveLowerBound, const SFixed & exclusiveUpperBound) +{ + using InternalType = typename SFixed::InternalType; + auto value = FIXED_POINTS_DETAILS::RandomHelper::Random(); + return SFixed::fromInternal(inclusiveLowerBound.getInternal() + (abs(value) % (exclusiveUpperBound.getInternal() - inclusiveLowerBound.getInternal()))); +} +#endif + +FIXED_POINTS_END_NAMESPACE diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon.h new file mode 100644 index 0000000..d0c908a --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon.h @@ -0,0 +1,15 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "FixedPointsCommon/FixedPointsCommon.h" \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/FixedPointsCommon.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/FixedPointsCommon.h new file mode 100644 index 0000000..dd067a6 --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/FixedPointsCommon.h @@ -0,0 +1,18 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "../FixedPoints.h" + +#include "SFixedCommon.h" +#include "UFixedCommon.h" \ No newline at end of file diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/SFixedCommon.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/SFixedCommon.h new file mode 100644 index 0000000..ddf9c9b --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/SFixedCommon.h @@ -0,0 +1,29 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "../FixedPoints.h" + +FIXED_POINTS_BEGIN_NAMESPACE +using SQ3x4 = SFixed<3, 4>; +using SQ7x8 = SFixed<7, 8>; +using SQ15x16 = SFixed<15, 16>; +using SQ31x32 = SFixed<31, 32>; + +using SQ1x6 = SFixed<1, 6>; +using SQ1x14 = SFixed<1, 14>; +using SQ1x30 = SFixed<1, 30>; +using SQ1x62 = SFixed<1, 62>; +FIXED_POINTS_END_NAMESPACE diff --git a/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/UFixedCommon.h b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/UFixedCommon.h new file mode 100644 index 0000000..3687bfb --- /dev/null +++ b/board-package-source/libraries/FixedPointsArduino/src/FixedPointsCommon/UFixedCommon.h @@ -0,0 +1,29 @@ +// Copyright 2017-2018 Pharap +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "../FixedPoints.h" + +FIXED_POINTS_BEGIN_NAMESPACE +using UQ4x4 = UFixed<4, 4>; +using UQ8x8 = UFixed<8, 8>; +using UQ16x16 = UFixed<16, 16>; +using UQ32x32 = UFixed<32, 32>; + +using UQ1x7 = UFixed<1, 7>; +using UQ1x15 = UFixed<1, 15>; +using UQ1x31 = UFixed<1, 31>; +using UQ1x63 = UFixed<1, 63>; +FIXED_POINTS_END_NAMESPACE \ No newline at end of file diff --git a/board-package-source/libraries/HID/keywords.txt b/board-package-source/libraries/HID/keywords.txt new file mode 100644 index 0000000..32a9ba5 --- /dev/null +++ b/board-package-source/libraries/HID/keywords.txt @@ -0,0 +1,21 @@ +####################################### +# Syntax Coloring Map HID +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +HID KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +SendReport KEYWORD2 +AppendDescriptor KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +HID_TX LITERAL1 \ No newline at end of file diff --git a/board-package-source/libraries/HID/library.properties b/board-package-source/libraries/HID/library.properties new file mode 100644 index 0000000..9075bd8 --- /dev/null +++ b/board-package-source/libraries/HID/library.properties @@ -0,0 +1,9 @@ +name=HID +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Module for PluggableUSB infrastructure. Exposes an API for devices like Keyboards, Mice and Gamepads. +paragraph= +category=Communication +url=http://www.arduino.cc/en/Reference/HID +architectures=avr diff --git a/board-package-source/libraries/HID/src/HID.cpp b/board-package-source/libraries/HID/src/HID.cpp new file mode 100644 index 0000000..21ede26 --- /dev/null +++ b/board-package-source/libraries/HID/src/HID.cpp @@ -0,0 +1,162 @@ +/* + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#include "HID.h" + +#if defined(USBCON) + +HID_& HID() +{ + static HID_ obj; + return obj; +} + +int HID_::getInterface(uint8_t* interfaceCount) +{ + *interfaceCount += 1; // uses 1 + HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), + D_HIDREPORT(descriptorSize), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) + }; + return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); +} + +int HID_::getDescriptor(USBSetup& setup) +{ + // Check if this is a HID Class Descriptor request + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } + if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } + + // In a HID Class Descriptor wIndex cointains the interface number + if (setup.wIndex != pluggedInterface) { return 0; } + + int total = 0; + HIDSubDescriptor* node; + for (node = rootNode; node; node = node->next) { + int res = USB_SendControl(TRANSFER_PGM, node->data, node->length); + if (res == -1) + return -1; + total += res; + } + + // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol + // due to the USB specs, but Windows and Linux just assumes its in report mode. + protocol = HID_REPORT_PROTOCOL; + + return total; +} + +uint8_t HID_::getShortName(char *name) +{ + name[0] = 'H'; + name[1] = 'I'; + name[2] = 'D'; + name[3] = 'A' + (descriptorSize & 0x0F); + name[4] = 'A' + ((descriptorSize >> 4) & 0x0F); + return 5; +} + +void HID_::AppendDescriptor(HIDSubDescriptor *node) +{ + if (!rootNode) { + rootNode = node; + } else { + HIDSubDescriptor *current = rootNode; + while (current->next) { + current = current->next; + } + current->next = node; + } + descriptorSize += node->length; +} + +int HID_::SendReport(uint8_t id, const void* data, int len) +{ + auto ret = USB_Send(pluggedEndpoint, &id, 1); + if (ret < 0) return ret; + auto ret2 = USB_Send(pluggedEndpoint | TRANSFER_RELEASE, data, len); + if (ret2 < 0) return ret2; + return ret + ret2; +} + +bool HID_::setup(USBSetup& setup) +{ + if (pluggedInterface != setup.wIndex) { + return false; + } + + uint8_t request = setup.bRequest; + uint8_t requestType = setup.bmRequestType; + + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) + { + if (request == HID_GET_REPORT) { + // TODO: HID_GetReport(); + return true; + } + if (request == HID_GET_PROTOCOL) { + // TODO: Send8(protocol); + return true; + } + if (request == HID_GET_IDLE) { + // TODO: Send8(idle); + } + } + + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) + { + if (request == HID_SET_PROTOCOL) { + // The USB Host tells us if we are in boot or report mode. + // This only works with a real boot compatible device. + protocol = setup.wValueL; + return true; + } + if (request == HID_SET_IDLE) { + idle = setup.wValueL; + return true; + } + if (request == HID_SET_REPORT) + { + //uint8_t reportID = setup.wValueL; + //uint16_t length = setup.wLength; + //uint8_t data[length]; + // Make sure to not read more data than USB_EP_SIZE. + // You can read multiple times through a loop. + // The first byte (may!) contain the reportID on a multreport. + //USB_RecvControl(data, length); + } + } + + return false; +} + +HID_::HID_(void) : PluggableUSBModule(1, 1, epType), + rootNode(NULL), descriptorSize(0), + protocol(HID_REPORT_PROTOCOL), idle(1) +{ + epType[0] = EP_TYPE_INTERRUPT_IN; + PluggableUSB().plug(this); +} + +int HID_::begin(void) +{ + return 0; +} + +#endif /* if defined(USBCON) */ diff --git a/board-package-source/libraries/HID/src/HID.h b/board-package-source/libraries/HID/src/HID.h new file mode 100644 index 0000000..93c4bd5 --- /dev/null +++ b/board-package-source/libraries/HID/src/HID.h @@ -0,0 +1,125 @@ +/* + Copyright (c) 2015, Arduino LLC + Original code (pre-library): Copyright (c) 2011, Peter Barrett + + Permission to use, copy, modify, and/or distribute this software for + any purpose with or without fee is hereby granted, provided that the + above copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR + BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + */ + +#ifndef HID_h +#define HID_h + +#include +#include +#include "PluggableUSB.h" + +#if defined(USBCON) + +#define _USING_HID + +// HID 'Driver' +// ------------ +#define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 +#define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0A +#define HID_SET_PROTOCOL 0x0B + +#define HID_HID_DESCRIPTOR_TYPE 0x21 +#define HID_REPORT_DESCRIPTOR_TYPE 0x22 +#define HID_PHYSICAL_DESCRIPTOR_TYPE 0x23 + +// HID subclass HID1.11 Page 8 4.2 Subclass +#define HID_SUBCLASS_NONE 0 +#define HID_SUBCLASS_BOOT_INTERFACE 1 + +// HID Keyboard/Mouse bios compatible protocols HID1.11 Page 9 4.3 Protocols +#define HID_PROTOCOL_NONE 0 +#define HID_PROTOCOL_KEYBOARD 1 +#define HID_PROTOCOL_MOUSE 2 + +// Normal or bios protocol (Keyboard/Mouse) HID1.11 Page 54 7.2.5 Get_Protocol Request +// "protocol" variable is used for this purpose. +#define HID_BOOT_PROTOCOL 0 +#define HID_REPORT_PROTOCOL 1 + +// HID Request Type HID1.11 Page 51 7.2.1 Get_Report Request +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + +typedef struct +{ + uint8_t len; // 9 + uint8_t dtype; // 0x21 + uint8_t addr; + uint8_t versionL; // 0x101 + uint8_t versionH; // 0x101 + uint8_t country; + uint8_t desctype; // 0x22 report + uint8_t descLenL; + uint8_t descLenH; +} HIDDescDescriptor; + +typedef struct +{ + InterfaceDescriptor hid; + HIDDescDescriptor desc; + EndpointDescriptor in; +} HIDDescriptor; + +class HIDSubDescriptor { +public: + HIDSubDescriptor *next = NULL; + HIDSubDescriptor(const void *d, const uint16_t l) : data(d), length(l) { } + + const void* data; + const uint16_t length; +}; + +class HID_ : public PluggableUSBModule +{ +public: + HID_(void); + int begin(void); + int SendReport(uint8_t id, const void* data, int len); + void AppendDescriptor(HIDSubDescriptor* node); + +protected: + // Implementation of the PluggableUSBModule + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + uint8_t getShortName(char* name); + +private: + uint8_t epType[1]; + + HIDSubDescriptor* rootNode; + uint16_t descriptorSize; + + uint8_t protocol; + uint8_t idle; +}; + +// Replacement for global singleton. +// This function prevents static-initialization-order-fiasco +// https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use +HID_& HID(); + +#define D_HIDREPORT(length) { 9, 0x21, 0x01, 0x01, 0, 1, 0x22, lowByte(length), highByte(length) } + +#endif // USBCON + +#endif // HID_h diff --git a/board-package-source/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/board-package-source/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100644 index 0000000..df73ade --- /dev/null +++ b/board-package-source/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,143 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + */ + +// the sensor communicates using SPI, so include the library: +#include + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading +const byte READ = 0b11111100; // SCP1000's read command +const byte WRITE = 0b00000010; // SCP1000's write command + +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +void setup() { + Serial.begin(9600); + + // start the SPI library: + SPI.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + // give the sensor time to set up: + delay(100); +} + +void loop() { + //Select High Resolution Mode + writeRegister(0x03, 0x0A); + + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + float realTemp = (float)tempData / 20.0; + Serial.print("Temp[C]="); + Serial.print(realTemp); + + + //Read the pressure data highest 3 bits: + byte pressure_data_high = readRegister(0x1F, 1); + pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressure_data_low = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4; + + // display the temperature: + Serial.println("\tPressure [Pa]=" + String(pressure)); + } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead) { + byte inByte = 0; // incoming byte from the SPI + unsigned int result = 0; // result to return + Serial.print(thisRegister, BIN); + Serial.print("\t"); + // SCP1000 expects the register name in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the address and the command into one byte + byte dataToSend = thisRegister & READ; + Serial.println(thisRegister, BIN); + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + SPI.transfer(dataToSend); + // send a value of 0 to read the first byte returned: + result = SPI.transfer(0x00); + // decrement the number of bytes left to read: + bytesToRead--; + // if you still have another byte to read: + if (bytesToRead > 0) { + // shift the first byte left, then get the second byte: + result = result << 8; + inByte = SPI.transfer(0x00); + // combine the byte you just got with the previous one: + result = result | inByte; + // decrement the number of bytes left to read: + bytesToRead--; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return (result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + + // SCP1000 expects the register address in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the register address and the command into one byte: + byte dataToSend = thisRegister | WRITE; + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(dataToSend); //Send register location + SPI.transfer(thisValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + diff --git a/board-package-source/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/board-package-source/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino new file mode 100644 index 0000000..c7afcc0 --- /dev/null +++ b/board-package-source/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -0,0 +1,71 @@ +/* + Digital Pot Control + + This example controls an Analog Devices AD5206 digital potentiometer. + The AD5206 has 6 potentiometer channels. Each channel's pins are labeled + A - connect this to voltage + W - this is the pot's wiper, which changes when you set it + B - connect this to ground. + + The AD5206 is SPI-compatible,and to command it, you send two bytes, + one with the channel number (0 - 5) and one with the resistance value for the + channel (0 - 255). + + The circuit: + * All A pins of AD5206 connected to +5V + * All B pins of AD5206 connected to ground + * An LED and a 220-ohm resisor in series connected from each W pin to ground + * CS - to digital pin 10 (SS pin) + * SDI - to digital pin 11 (MOSI pin) + * CLK - to digital pin 13 (SCK pin) + + created 10 Aug 2010 + by Tom Igoe + + Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 + +*/ + + +// inslude the SPI library: +#include + + +// set pin 10 as the slave select for the digital pot: +const int slaveSelectPin = 10; + +void setup() { + // set the slaveSelectPin as an output: + pinMode(slaveSelectPin, OUTPUT); + // initialize SPI: + SPI.begin(); +} + +void loop() { + // go through the six channels of the digital pot: + for (int channel = 0; channel < 6; channel++) { + // change the resistance on this channel from min to max: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, level); + delay(10); + } + // wait a second at the top: + delay(100); + // change the resistance on this channel from max to min: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, 255 - level); + delay(10); + } + } + +} + +void digitalPotWrite(int address, int value) { + // take the SS pin low to select the chip: + digitalWrite(slaveSelectPin, LOW); + // send in the address and value via SPI: + SPI.transfer(address); + SPI.transfer(value); + // take the SS pin high to de-select the chip: + digitalWrite(slaveSelectPin, HIGH); +} diff --git a/board-package-source/libraries/SPI/keywords.txt b/board-package-source/libraries/SPI/keywords.txt new file mode 100644 index 0000000..fa76165 --- /dev/null +++ b/board-package-source/libraries/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4 LITERAL1 +SPI_CLOCK_DIV16 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_CLOCK_DIV128 LITERAL1 +SPI_CLOCK_DIV2 LITERAL1 +SPI_CLOCK_DIV8 LITERAL1 +SPI_CLOCK_DIV32 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 \ No newline at end of file diff --git a/board-package-source/libraries/SPI/library.properties b/board-package-source/libraries/SPI/library.properties new file mode 100644 index 0000000..4ed8db9 --- /dev/null +++ b/board-package-source/libraries/SPI/library.properties @@ -0,0 +1,10 @@ +name=SPI +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. +paragraph=SPI is a synchronous serial data protocol used by microcontrollers for communicating with one or more peripheral devices quickly over short distances. It uses three lines common to all devices (MISO, MOSI and SCK) and one specific for each device. +category=Communication +url=http://www.arduino.cc/en/Reference/SPI +architectures=avr + diff --git a/board-package-source/libraries/SPI/src/SPI.cpp b/board-package-source/libraries/SPI/src/SPI.cpp new file mode 100644 index 0000000..af14e07 --- /dev/null +++ b/board-package-source/libraries/SPI/src/SPI.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) + * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "SPI.h" + +SPIClass SPI; + +uint8_t SPIClass::initialized = 0; +uint8_t SPIClass::interruptMode = 0; +uint8_t SPIClass::interruptMask = 0; +uint8_t SPIClass::interruptSave = 0; +#ifdef SPI_TRANSACTION_MISMATCH_LED +uint8_t SPIClass::inTransactionFlag = 0; +#endif + +void SPIClass::begin() +{ + uint8_t sreg = SREG; + noInterrupts(); // Protect from a scheduler and prevent transactionBegin + if (!initialized) { + // Set SS to high so a connected chip will be "deselected" by default + uint8_t port = digitalPinToPort(SS); + uint8_t bit = digitalPinToBitMask(SS); + volatile uint8_t *reg = portModeRegister(port); + + // if the SS pin is not already configured as an output + // then set it high (to enable the internal pull-up resistor) + if(!(*reg & bit)){ + digitalWrite(SS, HIGH); + } + + // When the SS pin is set as OUTPUT, it can be used as + // a general purpose output port (it doesn't influence + // SPI operations). + pinMode(SS, OUTPUT); + + // Warning: if the SS pin ever becomes a LOW INPUT then SPI + // automatically switches to Slave, so the data direction of + // the SS pin MUST be kept as OUTPUT. + SPCR |= _BV(MSTR); + SPCR |= _BV(SPE); + + // Set direction register for SCK and MOSI pin. + // MISO pin automatically overrides to INPUT. + // By doing this AFTER enabling SPI, we avoid accidentally + // clocking in a single bit since the lines go directly + // from "input" to SPI control. + // http://code.google.com/p/arduino/issues/detail?id=888 + pinMode(SCK, OUTPUT); + pinMode(MOSI, OUTPUT); + } + initialized++; // reference count + SREG = sreg; +} + +void SPIClass::end() { + uint8_t sreg = SREG; + noInterrupts(); // Protect from a scheduler and prevent transactionBegin + // Decrease the reference counter + if (initialized) + initialized--; + // If there are no more references disable SPI + if (!initialized) { + SPCR &= ~_BV(SPE); + interruptMode = 0; + #ifdef SPI_TRANSACTION_MISMATCH_LED + inTransactionFlag = 0; + #endif + } + SREG = sreg; +} + +// mapping of interrupt numbers to bits within SPI_AVR_EIMSK +#if defined(__AVR_ATmega32U4__) + #define SPI_INT0_MASK (1< + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) + * Copyright (c) 2014 by Andrew J. Kroll (atomicity fixes) + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include + +// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), +// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method +#define SPI_HAS_NOTUSINGINTERRUPT 1 + +// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. +// This way when there is a bug fix you can check this define to alert users +// of your code if it uses better version of this library. +// This also implies everything that SPI_HAS_TRANSACTION as documented above is +// available too. +#define SPI_ATOMIC_VERSION 1 + +// Uncomment this line to add detection of mismatched begin/end transactions. +// A mismatch occurs if other libraries fail to use SPI.endTransaction() for +// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn +// on if any mismatch is ever detected. +//#define SPI_TRANSACTION_MISMATCH_LED 5 + +#ifndef LSBFIRST +#define LSBFIRST 0 +#endif +#ifndef MSBFIRST +#define MSBFIRST 1 +#endif + +#define SPI_CLOCK_DIV4 0x00 +#define SPI_CLOCK_DIV16 0x01 +#define SPI_CLOCK_DIV64 0x02 +#define SPI_CLOCK_DIV128 0x03 +#define SPI_CLOCK_DIV2 0x04 +#define SPI_CLOCK_DIV8 0x05 +#define SPI_CLOCK_DIV32 0x06 + +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x04 +#define SPI_MODE2 0x08 +#define SPI_MODE3 0x0C + +#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR +#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR +#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR + +// define SPI_AVR_EIMSK for AVR boards with external interrupt pins +#if defined(EIMSK) + #define SPI_AVR_EIMSK EIMSK +#elif defined(GICR) + #define SPI_AVR_EIMSK GICR +#elif defined(GIMSK) + #define SPI_AVR_EIMSK GIMSK +#endif + +class SPISettings { +public: + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode); + } else { + init_MightInline(clock, bitOrder, dataMode); + } + } + SPISettings() { + init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); + } +private: + void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + __attribute__((__always_inline__)) { + // Clock settings are defined as follows. Note that this shows SPI2X + // inverted, so the bits form increasing numbers. Also note that + // fosc/64 appears twice + // SPR1 SPR0 ~SPI2X Freq + // 0 0 0 fosc/2 + // 0 0 1 fosc/4 + // 0 1 0 fosc/8 + // 0 1 1 fosc/16 + // 1 0 0 fosc/32 + // 1 0 1 fosc/64 + // 1 1 0 fosc/64 + // 1 1 1 fosc/128 + + // We find the fastest clock that is less than or equal to the + // given clock rate. The clock divider that results in clock_setting + // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the + // slowest (128 == 2 ^^ 7, so clock_div = 6). + uint8_t clockDiv; + + // When the clock is known at compiletime, use this if-then-else + // cascade, which the compiler knows how to completely optimize + // away. When clock is not known, use a loop instead, which generates + // shorter code. + if (__builtin_constant_p(clock)) { + if (clock >= F_CPU / 2) { + clockDiv = 0; + } else if (clock >= F_CPU / 4) { + clockDiv = 1; + } else if (clock >= F_CPU / 8) { + clockDiv = 2; + } else if (clock >= F_CPU / 16) { + clockDiv = 3; + } else if (clock >= F_CPU / 32) { + clockDiv = 4; + } else if (clock >= F_CPU / 64) { + clockDiv = 5; + } else { + clockDiv = 6; + } + } else { + uint32_t clockSetting = F_CPU / 2; + clockDiv = 0; + while (clockDiv < 6 && clock < clockSetting) { + clockSetting /= 2; + clockDiv++; + } + } + + // Compensate for the duplicate fosc/64 + if (clockDiv == 6) + clockDiv = 7; + + // Invert the SPI2X bit + clockDiv ^= 0x1; + + // Pack into the SPISettings class + spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) | + (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK); + spsr = clockDiv & SPI_2XCLOCK_MASK; + } + uint8_t spcr; + uint8_t spsr; + friend class SPIClass; +}; + + +class SPIClass { +public: + // Initialize the SPI library + static void begin(); + + // If SPI is used from within an interrupt, this function registers + // that interrupt with the SPI library, so beginTransaction() can + // prevent conflicts. The input interruptNumber is the number used + // with attachInterrupt. If SPI is used from a different interrupt + // (eg, a timer), interruptNumber should be 255. + static void usingInterrupt(uint8_t interruptNumber); + // And this does the opposite. + static void notUsingInterrupt(uint8_t interruptNumber); + // Note: the usingInterrupt and notUsingInterrupt functions should + // not to be called from ISR context or inside a transaction. + // For details see: + // https://github.com/arduino/Arduino/pull/2381 + // https://github.com/arduino/Arduino/pull/2449 + + // Before using SPI.transfer() or asserting chip select pins, + // this function is used to gain exclusive access to the SPI bus + // and configure the correct settings. + inline static void beginTransaction(SPISettings settings) { + if (interruptMode > 0) { + uint8_t sreg = SREG; + noInterrupts(); + + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + interruptSave = SPI_AVR_EIMSK; + SPI_AVR_EIMSK &= ~interruptMask; + SREG = sreg; + } else + #endif + { + interruptSave = sreg; + } + } + + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 1; + #endif + + SPCR = settings.spcr; + SPSR = settings.spsr; + } + + // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + inline static uint8_t transfer(uint8_t data) { + SPDR = data; + /* + * The following NOP introduces a small delay that can prevent the wait + * loop form iterating when running at the maximum speed. This gives + * about 10% more speed, even if it seems counter-intuitive. At lower + * speeds it is unnoticed. + */ + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; // wait + return SPDR; + } + inline static uint16_t transfer16(uint16_t data) { + union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out; + in.val = data; + if (!(SPCR & _BV(DORD))) { + SPDR = in.msb; + asm volatile("nop"); // See transfer(uint8_t) function + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + } else { + SPDR = in.lsb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + SPDR = in.msb; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + } + return out.val; + } + inline static void transfer(void *buf, size_t count) { + if (count == 0) return; + uint8_t *p = (uint8_t *)buf; + SPDR = *p; + while (--count > 0) { + uint8_t out = *(p + 1); + while (!(SPSR & _BV(SPIF))) ; + uint8_t in = SPDR; + SPDR = out; + *p++ = in; + } + while (!(SPSR & _BV(SPIF))) ; + *p = SPDR; + } + // After performing a group of transfers and releasing the chip select + // signal, this function allows others to access the SPI bus + inline static void endTransaction(void) { + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (!inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 0; + #endif + + if (interruptMode > 0) { + #ifdef SPI_AVR_EIMSK + uint8_t sreg = SREG; + #endif + noInterrupts(); + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + SPI_AVR_EIMSK = interruptSave; + SREG = sreg; + } else + #endif + { + SREG = interruptSave; + } + } + } + + // Disable the SPI bus + static void end(); + + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setBitOrder(uint8_t bitOrder) { + if (bitOrder == LSBFIRST) SPCR |= _BV(DORD); + else SPCR &= ~(_BV(DORD)); + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setDataMode(uint8_t dataMode) { + SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode; + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setClockDivider(uint8_t clockDiv) { + SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK); + SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK); + } + // These undocumented functions should not be used. SPI.transfer() + // polls the hardware flag which is automatically cleared as the + // AVR responds to SPI's interrupt + inline static void attachInterrupt() { SPCR |= _BV(SPIE); } + inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); } + +private: + static uint8_t initialized; + static uint8_t interruptMode; // 0=none, 1=mask, 2=global + static uint8_t interruptMask; // which interrupts to mask + static uint8_t interruptSave; // temp storage, to restore state + #ifdef SPI_TRANSACTION_MISMATCH_LED + static uint8_t inTransactionFlag; + #endif +}; + +extern SPIClass SPI; + +#endif diff --git a/board-package-source/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino b/board-package-source/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino new file mode 100644 index 0000000..61ce88c --- /dev/null +++ b/board-package-source/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino @@ -0,0 +1,55 @@ +/* + Software serial multple serial test + + Receives from the hardware serial, sends to software serial. + Receives from software serial, sends to hardware serial. + + The circuit: + * RX is digital pin 10 (connect to TX of other device) + * TX is digital pin 11 (connect to RX of other device) + + Note: + Not all pins on the Mega and Mega 2560 support change interrupts, + so only the following can be used for RX: + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + + Not all pins on the Leonardo and Micro support change interrupts, + so only the following can be used for RX: + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). + + created back in the mists of time + modified 25 May 2012 + by Tom Igoe + based on Mikal Hart's example + + This example code is in the public domain. + + */ +#include + +SoftwareSerial mySerial(10, 11); // RX, TX + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(57600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + + Serial.println("Goodnight moon!"); + + // set the data rate for the SoftwareSerial port + mySerial.begin(4800); + mySerial.println("Hello, world?"); +} + +void loop() { // run over and over + if (mySerial.available()) { + Serial.write(mySerial.read()); + } + if (Serial.available()) { + mySerial.write(Serial.read()); + } +} + diff --git a/board-package-source/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino b/board-package-source/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino new file mode 100644 index 0000000..8d7f93e --- /dev/null +++ b/board-package-source/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino @@ -0,0 +1,91 @@ +/* + Software serial multple serial test + + Receives from the two software serial ports, + sends to the hardware serial port. + + In order to listen on a software port, you call port.listen(). + When using two software serial ports, you have to switch ports + by listen()ing on each one in turn. Pick a logical time to switch + ports, like the end of an expected transmission, or when the + buffer is empty. This example switches ports when there is nothing + more to read from a port + + The circuit: + Two devices which communicate serially are needed. + * First serial device's TX attached to digital pin 10(RX), RX to pin 11(TX) + * Second serial device's TX attached to digital pin 8(RX), RX to pin 9(TX) + + Note: + Not all pins on the Mega and Mega 2560 support change interrupts, + so only the following can be used for RX: + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + + Not all pins on the Leonardo support change interrupts, + so only the following can be used for RX: + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). + + created 18 Apr. 2011 + modified 19 March 2016 + by Tom Igoe + based on Mikal Hart's twoPortRXExample + + This example code is in the public domain. + + */ + +#include +// software serial #1: RX = digital pin 10, TX = digital pin 11 +SoftwareSerial portOne(10, 11); + +// software serial #2: RX = digital pin 8, TX = digital pin 9 +// on the Mega, use other pins instead, since 8 and 9 don't work on the Mega +SoftwareSerial portTwo(8, 9); + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + + // Start each software serial port + portOne.begin(9600); + portTwo.begin(9600); +} + +void loop() { + // By default, the last intialized port is listening. + // when you want to listen on a port, explicitly select it: + portOne.listen(); + Serial.println("Data from port one:"); + // while there is data coming in, read it + // and send to the hardware serial port: + while (portOne.available() > 0) { + char inByte = portOne.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); + + // Now listen on the second port + portTwo.listen(); + // while there is data coming in, read it + // and send to the hardware serial port: + Serial.println("Data from port two:"); + while (portTwo.available() > 0) { + char inByte = portTwo.read(); + Serial.write(inByte); + } + + // blank line to separate data from the two ports: + Serial.println(); +} + + + + + + diff --git a/board-package-source/libraries/SoftwareSerial/keywords.txt b/board-package-source/libraries/SoftwareSerial/keywords.txt new file mode 100644 index 0000000..aaea17c --- /dev/null +++ b/board-package-source/libraries/SoftwareSerial/keywords.txt @@ -0,0 +1,30 @@ +####################################### +# Syntax Coloring Map for SoftwareSerial +# (formerly NewSoftSerial) +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SoftwareSerial KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +read KEYWORD2 +write KEYWORD2 +available KEYWORD2 +isListening KEYWORD2 +overflow KEYWORD2 +flush KEYWORD2 +listen KEYWORD2 +peek KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/board-package-source/libraries/SoftwareSerial/library.properties b/board-package-source/libraries/SoftwareSerial/library.properties new file mode 100644 index 0000000..6d20a49 --- /dev/null +++ b/board-package-source/libraries/SoftwareSerial/library.properties @@ -0,0 +1,10 @@ +name=SoftwareSerial +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Enables serial communication on any digital pin. +paragraph=The SoftwareSerial library has been developed to allow serial communication on any digital pin of the board, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. +category=Communication +url=http://www.arduino.cc/en/Reference/SoftwareSerial +architectures=avr + diff --git a/board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.cpp new file mode 100644 index 0000000..474fe4a --- /dev/null +++ b/board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -0,0 +1,486 @@ +/* +SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + +// When set, _DEBUG co-opts pins 11 and 13 for debugging with an +// oscilloscope or logic analyzer. Beware: it also slightly modifies +// the bit times, so don't rely on it too much at high baud rates +#define _DEBUG 0 +#define _DEBUG_PIN1 11 +#define _DEBUG_PIN2 13 +// +// Includes +// +#include +#include +#include +#include +#include + +// +// Statics +// +SoftwareSerial *SoftwareSerial::active_object = 0; +uint8_t SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; +volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; +volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; + +// +// Debugging +// +// This function generates a brief pulse +// for debugging or measuring on an oscilloscope. +#if _DEBUG +inline void DebugPulse(uint8_t pin, uint8_t count) +{ + volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); + + uint8_t val = *pport; + while (count--) + { + *pport = val | digitalPinToBitMask(pin); + *pport = val; + } +} +#else +inline void DebugPulse(uint8_t, uint8_t) {} +#endif + +// +// Private methods +// + +/* static */ +inline void SoftwareSerial::tunedDelay(uint16_t delay) { + _delay_loop_2(delay); +} + +// This function sets the current object as the "listening" +// one and returns true if it replaces another +bool SoftwareSerial::listen() +{ + if (!_rx_delay_stopbit) + return false; + + if (active_object != this) + { + if (active_object) + active_object->stopListening(); + + _buffer_overflow = false; + _receive_buffer_head = _receive_buffer_tail = 0; + active_object = this; + + setRxIntMsk(true); + return true; + } + + return false; +} + +// Stop listening. Returns true if we were actually listening. +bool SoftwareSerial::stopListening() +{ + if (active_object == this) + { + setRxIntMsk(false); + active_object = NULL; + return true; + } + return false; +} + +// +// The receive routine called by the interrupt handler +// +void SoftwareSerial::recv() +{ + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Preserve the registers that the compiler misses +// (courtesy of Arduino forum user *etracer*) + asm volatile( + "push r18 \n\t" + "push r19 \n\t" + "push r20 \n\t" + "push r21 \n\t" + "push r22 \n\t" + "push r23 \n\t" + "push r26 \n\t" + "push r27 \n\t" + ::); +#endif + + uint8_t d = 0; + + // If RX line is high, then we don't see any start bit + // so interrupt is probably not for us + if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) + { + // Disable further interrupts during reception, this prevents + // triggering another interrupt directly after we return, which can + // cause problems at higher baudrates. + setRxIntMsk(false); + + // Wait approximately 1/2 of a bit width to "center" the sample + tunedDelay(_rx_delay_centering); + DebugPulse(_DEBUG_PIN2, 1); + + // Read each of the 8 bits + for (uint8_t i=8; i > 0; --i) + { + tunedDelay(_rx_delay_intrabit); + d >>= 1; + DebugPulse(_DEBUG_PIN2, 1); + if (rx_pin_read()) + d |= 0x80; + } + + if (_inverse_logic) + d = ~d; + + // if buffer full, set the overflow flag and return + uint8_t next = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; + if (next != _receive_buffer_head) + { + // save new data in buffer: tail points to where byte goes + _receive_buffer[_receive_buffer_tail] = d; // save new byte + _receive_buffer_tail = next; + } + else + { + DebugPulse(_DEBUG_PIN1, 1); + _buffer_overflow = true; + } + + // skip the stop bit + tunedDelay(_rx_delay_stopbit); + DebugPulse(_DEBUG_PIN1, 1); + + // Re-enable interrupts when we're sure to be inside the stop bit + setRxIntMsk(true); + + } + +#if GCC_VERSION < 40302 +// Work-around for avr-gcc 4.3.0 OSX version bug +// Restore the registers that the compiler misses + asm volatile( + "pop r27 \n\t" + "pop r26 \n\t" + "pop r23 \n\t" + "pop r22 \n\t" + "pop r21 \n\t" + "pop r20 \n\t" + "pop r19 \n\t" + "pop r18 \n\t" + ::); +#endif +} + +uint8_t SoftwareSerial::rx_pin_read() +{ + return *_receivePortRegister & _receiveBitMask; +} + +// +// Interrupt handling +// + +/* static */ +inline void SoftwareSerial::handle_interrupt() +{ + if (active_object) + { + active_object->recv(); + } +} + +#if defined(PCINT0_vect) +ISR(PCINT0_vect) +{ + SoftwareSerial::handle_interrupt(); +} +#endif + +#if defined(PCINT1_vect) +ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT2_vect) +ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT3_vect) +ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +// +// Constructor +// +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : + _rx_delay_centering(0), + _rx_delay_intrabit(0), + _rx_delay_stopbit(0), + _tx_delay(0), + _buffer_overflow(false), + _inverse_logic(inverse_logic) +{ + setTX(transmitPin); + setRX(receivePin); +} + +// +// Destructor +// +SoftwareSerial::~SoftwareSerial() +{ + end(); +} + +void SoftwareSerial::setTX(uint8_t tx) +{ + // First write, then set output. If we do this the other way around, + // the pin would be output low for a short while before switching to + // output high. Now, it is input with pullup for a short while, which + // is fine. With inverse logic, either order is fine. + digitalWrite(tx, _inverse_logic ? LOW : HIGH); + pinMode(tx, OUTPUT); + _transmitBitMask = digitalPinToBitMask(tx); + uint8_t port = digitalPinToPort(tx); + _transmitPortRegister = portOutputRegister(port); +} + +void SoftwareSerial::setRX(uint8_t rx) +{ + pinMode(rx, INPUT); + if (!_inverse_logic) + digitalWrite(rx, HIGH); // pullup for normal logic! + _receivePin = rx; + _receiveBitMask = digitalPinToBitMask(rx); + uint8_t port = digitalPinToPort(rx); + _receivePortRegister = portInputRegister(port); +} + +uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) { + if (num > sub) + return num - sub; + else + return 1; +} + +// +// Public methods +// + +void SoftwareSerial::begin(long speed) +{ + _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; + + // Precalculate the various delays, in number of 4-cycle delays + uint16_t bit_delay = (F_CPU / speed) / 4; + + // 12 (gcc 4.8.2) or 13 (gcc 4.3.2) cycles from start bit to first bit, + // 15 (gcc 4.8.2) or 16 (gcc 4.3.2) cycles between bits, + // 12 (gcc 4.8.2) or 14 (gcc 4.3.2) cycles from last bit to stop bit + // These are all close enough to just use 15 cycles, since the inter-bit + // timings are the most critical (deviations stack 8 times) + _tx_delay = subtract_cap(bit_delay, 15 / 4); + + // Only setup rx when we have a valid PCINT for this pin + if (digitalPinToPCICR(_receivePin)) { + #if GCC_VERSION > 40800 + // Timings counted from gcc 4.8.2 output. This works up to 115200 on + // 16Mhz and 57600 on 8Mhz. + // + // When the start bit occurs, there are 3 or 4 cycles before the + // interrupt flag is set, 4 cycles before the PC is set to the right + // interrupt vector address and the old PC is pushed on the stack, + // and then 75 cycles of instructions (including the RJMP in the + // ISR vector table) until the first delay. After the delay, there + // are 17 more cycles until the pin value is read (excluding the + // delay in the loop). + // We want to have a total delay of 1.5 bit time. Inside the loop, + // we already wait for 1 bit time - 23 cycles, so here we wait for + // 0.5 bit time - (71 + 18 - 22) cycles. + _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4); + + // There are 23 cycles in each loop iteration (excluding the delay) + _rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4); + + // There are 37 cycles from the last bit read to the start of + // stopbit delay and 11 cycles from the delay until the interrupt + // mask is enabled again (which _must_ happen during the stopbit). + // This delay aims at 3/4 of a bit time, meaning the end of the + // delay will be at 1/4th of the stopbit. This allows some extra + // time for ISR cleanup, which makes 115200 baud at 16Mhz work more + // reliably + _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4); + #else // Timings counted from gcc 4.3.2 output + // Note that this code is a _lot_ slower, mostly due to bad register + // allocation choices of gcc. This works up to 57600 on 16Mhz and + // 38400 on 8Mhz. + _rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 97 + 29 - 11) / 4); + _rx_delay_intrabit = subtract_cap(bit_delay, 11 / 4); + _rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (44 + 17) / 4); + #endif + + + // Enable the PCINT for the entire port here, but never disable it + // (others might also need it, so we disable the interrupt by using + // the per-pin PCMSK register). + *digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin)); + // Precalculate the pcint mask register and value, so setRxIntMask + // can be used inside the ISR without costing too much time. + _pcint_maskreg = digitalPinToPCMSK(_receivePin); + _pcint_maskvalue = _BV(digitalPinToPCMSKbit(_receivePin)); + + tunedDelay(_tx_delay); // if we were low this establishes the end + } + +#if _DEBUG + pinMode(_DEBUG_PIN1, OUTPUT); + pinMode(_DEBUG_PIN2, OUTPUT); +#endif + + listen(); +} + +void SoftwareSerial::setRxIntMsk(bool enable) +{ + if (enable) + *_pcint_maskreg |= _pcint_maskvalue; + else + *_pcint_maskreg &= ~_pcint_maskvalue; +} + +void SoftwareSerial::end() +{ + stopListening(); +} + + +// Read data from buffer +int SoftwareSerial::read() +{ + if (!isListening()) + return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + return -1; + + // Read from "head" + uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte + _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF; + return d; +} + +int SoftwareSerial::available() +{ + if (!isListening()) + return 0; + + return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; +} + +size_t SoftwareSerial::write(uint8_t b) +{ + if (_tx_delay == 0) { + setWriteError(); + return 0; + } + + // By declaring these as local variables, the compiler will put them + // in registers _before_ disabling interrupts and entering the + // critical timing sections below, which makes it a lot easier to + // verify the cycle timings + volatile uint8_t *reg = _transmitPortRegister; + uint8_t reg_mask = _transmitBitMask; + uint8_t inv_mask = ~_transmitBitMask; + uint8_t oldSREG = SREG; + bool inv = _inverse_logic; + uint16_t delay = _tx_delay; + + if (inv) + b = ~b; + + cli(); // turn off interrupts for a clean txmit + + // Write the start bit + if (inv) + *reg |= reg_mask; + else + *reg &= inv_mask; + + tunedDelay(delay); + + // Write each of the 8 bits + for (uint8_t i = 8; i > 0; --i) + { + if (b & 1) // choose bit + *reg |= reg_mask; // send 1 + else + *reg &= inv_mask; // send 0 + + tunedDelay(delay); + b >>= 1; + } + + // restore pin to natural state + if (inv) + *reg &= inv_mask; + else + *reg |= reg_mask; + + SREG = oldSREG; // turn interrupts back on + tunedDelay(_tx_delay); + + return 1; +} + +void SoftwareSerial::flush() +{ + // There is no tx buffering, simply return +} + +int SoftwareSerial::peek() +{ + if (!isListening()) + return -1; + + // Empty buffer? + if (_receive_buffer_head == _receive_buffer_tail) + return -1; + + // Read from "head" + return _receive_buffer[_receive_buffer_head]; +} diff --git a/board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.h b/board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.h new file mode 100644 index 0000000..b1a37c4 --- /dev/null +++ b/board-package-source/libraries/SoftwareSerial/src/SoftwareSerial.h @@ -0,0 +1,123 @@ +/* +SoftwareSerial.h (formerly NewSoftSerial.h) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + +#ifndef SoftwareSerial_h +#define SoftwareSerial_h + +#include +#include + +/****************************************************************************** +* Definitions +******************************************************************************/ + +#ifndef _SS_MAX_RX_BUFF +#define _SS_MAX_RX_BUFF 64 // RX buffer size +#endif + +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +class SoftwareSerial : public Stream +{ +private: + // per object data + uint8_t _receivePin; + uint8_t _receiveBitMask; + volatile uint8_t *_receivePortRegister; + uint8_t _transmitBitMask; + volatile uint8_t *_transmitPortRegister; + volatile uint8_t *_pcint_maskreg; + uint8_t _pcint_maskvalue; + + // Expressed as 4-cycle delays (must never be 0!) + uint16_t _rx_delay_centering; + uint16_t _rx_delay_intrabit; + uint16_t _rx_delay_stopbit; + uint16_t _tx_delay; + + uint16_t _buffer_overflow:1; + uint16_t _inverse_logic:1; + + // static data + static uint8_t _receive_buffer[_SS_MAX_RX_BUFF]; + static volatile uint8_t _receive_buffer_tail; + static volatile uint8_t _receive_buffer_head; + static SoftwareSerial *active_object; + + // private methods + inline void recv() __attribute__((__always_inline__)); + uint8_t rx_pin_read(); + void setTX(uint8_t transmitPin); + void setRX(uint8_t receivePin); + inline void setRxIntMsk(bool enable) __attribute__((__always_inline__)); + + // Return num - sub, or 1 if the result would be < 1 + static uint16_t subtract_cap(uint16_t num, uint16_t sub); + + // private static method for timing + static inline void tunedDelay(uint16_t delay); + +public: + // public methods + SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); + ~SoftwareSerial(); + void begin(long speed); + bool listen(); + void end(); + bool isListening() { return this == active_object; } + bool stopListening(); + bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; } + int peek(); + + virtual size_t write(uint8_t byte); + virtual int read(); + virtual int available(); + virtual void flush(); + operator bool() { return true; } + + using Print::write; + + // public only for easy access by interrupt handlers + static inline void handle_interrupt() __attribute__((__always_inline__)); +}; + +// Arduino 0012 workaround +#undef int +#undef char +#undef long +#undef byte +#undef float +#undef abs +#undef round + +#endif