Added board package source (part 2 libraries)
|
@ -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.
|
|
@ -0,0 +1,125 @@
|
|||
# ArdBitmap: Compress and draw bitmaps on the Arduboy
|
||||
By @igvina
|
||||
## Features:
|
||||
### Bitmap library:
|
||||
* Works with compressed & uncompressed bitmaps.
|
||||
* Real-time image resize (downscale).
|
||||
* Horizontal/Vertical mirroring (fast).
|
||||
* Bitmap alignment.
|
||||
|
||||
### Bitmap compressor:
|
||||
* Compatible with PC/MAC/Linux (made with Java).
|
||||
* Good compression (better than Cabi).
|
||||
* Supports PNG, GIF (also animated gifs) & JPG.
|
||||
* Autogenerate sketches from images or animated gifs (great for no-developers).
|
||||
|
||||
## Video:
|
||||
|
||||
<a href="http://www.youtube.com/watch?feature=player_embedded&v=vtDYwqJ68gU
|
||||
" target="_blank"><img src="http://img.youtube.com/vi/vtDYwqJ68gU/0.jpg"
|
||||
alt="DEMO" width="240" height="180" border="10" /></a>
|
||||
|
||||
## Usage:
|
||||
### Compressor (v2.0):
|
||||
* Syntax: java -jar compressor2.0.jar image [-options]
|
||||
* options:
|
||||
* -gs SKETCH_FOLDER Generate sketch code
|
||||
* -fr VALUE Change frame rate (only animated gifs)
|
||||
* -v View compressed image
|
||||
* -anp PREFIX Array name prefix
|
||||
* -ver Show encoder version
|
||||
|
||||
* examples:
|
||||
|
||||
"java -jar compressor2.0.jar dog.gif -gs DOG -fr 15"
|
||||
"java -jar compressor2.0.jar dance.png -v"
|
||||
|
||||
* Notes:
|
||||
* Supports PNG, GIF (also animated gifs) & JPG
|
||||
* Max image size = 128 x 64 pixels (resized if bigger)
|
||||
* Encoding ratio could be bigger than 1 (worse than original image)
|
||||
|
||||
### Bitmap library (v2.0.x):
|
||||
* Install the ArdBitmap library in the Arduino IDE. 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 *ardbitmap*
|
||||
- Click somewhere within the ArdBitmap 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)
|
||||
|
||||
* In .ino file, add ArdBitmap library instance after main library instance:
|
||||
|
||||
```cpp
|
||||
// make an instance of the Arduboy2 class used for many functions
|
||||
Arduboy2 arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
```
|
||||
|
||||
* See the _Library instance details_ section below for more information on creating an ArdBitmap class instance.
|
||||
|
||||
* To draw, call function: ardbitmap.drawCompressed(...) , ardbitmap.drawCompressedResized(...) , ardbitmap.drawBitmap(...) , ardbitmap.drawBitmapResized(...)
|
||||
|
||||
#### Methods:
|
||||
|
||||
##### Compressed images:
|
||||
* `void drawCompressed(int16_t sx, int16_t sy, const uint8_t *compBitmap, uint8_t color, uint8_t align, uint8_t mirror);`
|
||||
* `void drawCompressedResized(int16_t sx, int16_t sy, const uint8_t *compBitmap, uint8_t color,uint8_t align, uint8_t mirror, float resize);`
|
||||
|
||||
##### Uncompressed images:
|
||||
* `void drawBitmap(int16_t sx, int16_t sy, const uint8_t *bitmap,uint8_t w, uint8_t h, uint8_t color, uint8_t align, uint8_t mirror);`
|
||||
* `void drawBitmapResized(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t w,uint8_t h, uint8_t color,uint8_t align, uint8_t mirror, float resize);`
|
||||
|
||||
#### Defines:
|
||||
* `#define ALIGN_H_LEFT`
|
||||
* `#define ALIGN_H_RIGHT`
|
||||
* `#define ALIGN_H_CENTER`
|
||||
* `#define ALIGN_V_TOP`
|
||||
* `#define ALIGN_V_BOTTOM`
|
||||
* `#define ALIGN_V_CENTER`
|
||||
* `#define ALIGN_CENTER`
|
||||
* `#define ALIGN_NONE`
|
||||
* `#define MIRROR_NONE`
|
||||
* `#define MIRROR_HORIZONTAL`
|
||||
* `#define MIRROR_VERTICAL`
|
||||
* `#define MIRROR_HOR_VER`
|
||||
|
||||
#### Library instance details:
|
||||
* The library is implemented as a class template named ArdBitmap. It requires 3 pieces of information in order to create an instance of the ArdBitmap class:
|
||||
|
||||
- An _expression_ that will evaluate to a pointer to the first location in the screen buffer array, such that it can be used to index a screen buffer location like `expression[i] = 5`. The expression is provided by defining the macro `ARDBITMAP_SBUF`. It must be defined **before** including _ArdBitmap.h_
|
||||
- The width of the screen, in pixels. This is provided as the first of the two template arguments.
|
||||
- the height of the screen in pixels. This is provided as the second of the two template arguments.
|
||||
|
||||
* It's probably best to group the `#define ARDBITMAP_SBUF`, the `#include ArdBitmap.h` and the instantiation of an ArdBitmap class object as one block of code. For an Arduboy sketch this might be:
|
||||
|
||||
```cpp
|
||||
// make an instance of the Arduboy2 class used for many functions
|
||||
// (this has to be done before creating an ArdBitmap object so we can define
|
||||
// the ARDBITMAP_SBUF macro and use the defined WIDTH and HEIGHT)
|
||||
Arduboy2 arduboy;
|
||||
// use the following instead, for the older Arduboy library:
|
||||
//Arduboy arduboy;
|
||||
|
||||
// define the screen buffer pointer expression
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
// Arduboy2 library verson 3.1.0 and higher exposes the screen buffer as public,
|
||||
// so the following could be used instead and may reduce code size:
|
||||
//#define ARDBITMAP_SBUF arduboy.sBuffer
|
||||
|
||||
// we can now include the ArdBitmap header file, which will use the
|
||||
// ARDBITMAP_SBUF macro when creating the template
|
||||
#include <ArdBitmap.h>
|
||||
|
||||
// make an ArdBitmap instance, providing screen width and height arguments that
|
||||
// were defined by the Arduboy2 (or Arduboy) library
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
```
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
|
||||
#include <Arduboy.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define SHOW_FPS
|
||||
|
||||
#ifdef SHOW_FPS
|
||||
|
||||
unsigned long previousTime = 0;
|
||||
uint8_t fps = 0, fpsCounter = 0;
|
||||
|
||||
#endif
|
||||
|
||||
unsigned char* bitmap = BITMAP_TEST;
|
||||
unsigned char* bitmap_c = BITMAP_COMP_TEST;
|
||||
float resize = 0.6;
|
||||
|
||||
uint16_t counter = 0;
|
||||
uint8_t test_number = 0;
|
||||
int16_t offset = -WIDTH/2;
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.beginNoLogo();
|
||||
//arduboy.boot();
|
||||
arduboy.setFrameRate(60);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
counter++;
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
long time1 = millis();
|
||||
|
||||
switch (test_number){
|
||||
case 0:
|
||||
arduboy.setCursor(6, 28);
|
||||
arduboy.print(F("UNCOMPRESSED BITMAP"));
|
||||
break;
|
||||
case 1:
|
||||
ardbitmap.drawBitmap(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_NONE);
|
||||
break;
|
||||
case 2:
|
||||
ardbitmap.drawBitmap(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_NONE);
|
||||
break;
|
||||
case 3:
|
||||
ardbitmap.drawBitmap(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL);
|
||||
break;
|
||||
case 4:
|
||||
ardbitmap.drawBitmap(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL);
|
||||
break;
|
||||
case 5:
|
||||
ardbitmap.drawBitmap(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_VERTICAL);
|
||||
break;
|
||||
case 6:
|
||||
ardbitmap.drawBitmap(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_VERTICAL);
|
||||
break;
|
||||
case 7:
|
||||
ardbitmap.drawBitmap(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HOR_VER);
|
||||
break;
|
||||
case 8:
|
||||
ardbitmap.drawBitmap(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HOR_VER);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
arduboy.setCursor(12, 28);
|
||||
arduboy.print(F("COMPRESSED BITMAP"));
|
||||
break;
|
||||
case 10:
|
||||
ardbitmap.drawCompressed(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_NONE);
|
||||
break;
|
||||
case 11:
|
||||
ardbitmap.drawCompressed(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_NONE);
|
||||
break;
|
||||
case 12:
|
||||
ardbitmap.drawCompressed(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL);
|
||||
break;
|
||||
case 13:
|
||||
ardbitmap.drawCompressed(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL);
|
||||
break;
|
||||
case 14:
|
||||
ardbitmap.drawCompressed(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_VERTICAL);
|
||||
break;
|
||||
case 15:
|
||||
ardbitmap.drawCompressed(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_VERTICAL);
|
||||
break;
|
||||
case 16:
|
||||
ardbitmap.drawCompressed(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HOR_VER);
|
||||
break;
|
||||
case 17:
|
||||
ardbitmap.drawCompressed(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HOR_VER);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
arduboy.setCursor(6, 24);
|
||||
arduboy.print(F("UNCOMPRESSED BITMAP"));
|
||||
arduboy.setCursor(50, 38);
|
||||
arduboy.print(F("RESIZE"));
|
||||
break;
|
||||
case 19:
|
||||
ardbitmap.drawBitmapResized(WIDTH/2, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_NONE, abs(cos(counter/80.0)));
|
||||
break;
|
||||
case 20:
|
||||
ardbitmap.drawBitmapResized(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_NONE, resize);
|
||||
break;
|
||||
case 21:
|
||||
ardbitmap.drawBitmapResized(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_NONE, resize);
|
||||
break;
|
||||
case 22:
|
||||
ardbitmap.drawBitmapResized(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL, resize);
|
||||
break;
|
||||
case 23:
|
||||
ardbitmap.drawBitmapResized(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL, resize);
|
||||
break;
|
||||
case 24:
|
||||
ardbitmap.drawBitmapResized(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_VERTICAL, resize);
|
||||
break;
|
||||
case 25:
|
||||
ardbitmap.drawBitmapResized(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_VERTICAL, resize);
|
||||
break;
|
||||
case 26:
|
||||
ardbitmap.drawBitmapResized(offset, HEIGHT/2, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HOR_VER, resize);
|
||||
break;
|
||||
case 27:
|
||||
ardbitmap.drawBitmapResized(WIDTH/2, offset, bitmap, 128, 64, WHITE, ALIGN_CENTER, MIRROR_HOR_VER, resize);
|
||||
break;
|
||||
|
||||
case 28:
|
||||
arduboy.setCursor(12, 24);
|
||||
arduboy.print(F("COMPRESSED BITMAP"));
|
||||
arduboy.setCursor(50, 38);
|
||||
arduboy.print(F("RESIZE"));
|
||||
break;
|
||||
case 29:
|
||||
ardbitmap.drawCompressedResized(WIDTH/2, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_NONE, abs(cos(counter/50.0)));
|
||||
break;
|
||||
case 30:
|
||||
ardbitmap.drawCompressedResized(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_NONE, resize);
|
||||
break;
|
||||
case 31:
|
||||
ardbitmap.drawCompressedResized(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_NONE, resize);
|
||||
break;
|
||||
case 32:
|
||||
ardbitmap.drawCompressedResized(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL, resize);
|
||||
break;
|
||||
case 33:
|
||||
ardbitmap.drawCompressedResized(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL, resize);
|
||||
break;
|
||||
case 34:
|
||||
ardbitmap.drawCompressedResized(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_VERTICAL, resize);
|
||||
break;
|
||||
case 35:
|
||||
ardbitmap.drawCompressedResized(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_VERTICAL, resize);
|
||||
break;
|
||||
case 36:
|
||||
ardbitmap.drawCompressedResized(offset, HEIGHT/2, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HOR_VER, resize);
|
||||
break;
|
||||
case 37:
|
||||
ardbitmap.drawCompressedResized(WIDTH/2, offset, bitmap_c, WHITE, ALIGN_CENTER, MIRROR_HOR_VER, resize);
|
||||
break;
|
||||
|
||||
case 38:
|
||||
arduboy.setCursor(12, 24);
|
||||
arduboy.print(F("COMPRESSED BITMAP"));
|
||||
arduboy.setCursor(36, 38);
|
||||
arduboy.print(F("ANIMATION"));
|
||||
break;
|
||||
case 39:
|
||||
ardbitmap.drawCompressed(WIDTH/2, HEIGHT, DOG[(time1/80)%ARRAY_LEN(DOG)], WHITE, ALIGN_H_CENTER | ALIGN_V_BOTTOM, MIRROR_NONE);
|
||||
break;
|
||||
|
||||
case 40:
|
||||
arduboy.setCursor(12, 24);
|
||||
arduboy.print(F("COMPRESSED BITMAP"));
|
||||
arduboy.setCursor(15, 38);
|
||||
arduboy.print(F("RESIZE ANIMATION"));
|
||||
break;
|
||||
case 41:
|
||||
ardbitmap.drawCompressedResized(WIDTH/2, HEIGHT, DOG[(time1/80)%ARRAY_LEN(DOG)], WHITE, ALIGN_H_CENTER | ALIGN_V_BOTTOM, MIRROR_HORIZONTAL, abs(cos(counter/50.0)));
|
||||
break;
|
||||
|
||||
default:
|
||||
arduboy.setCursor(44, 28);
|
||||
arduboy.print(F("TEST OK"));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
offset++;
|
||||
if (offset > (WIDTH * 3) /2){
|
||||
offset = -WIDTH/2;
|
||||
test_number++;
|
||||
}
|
||||
|
||||
time1 = millis() - time1;
|
||||
#ifdef SHOW_FPS
|
||||
fpsCounter++;
|
||||
unsigned long actualTime = millis();
|
||||
if ((fpsCounter % 30) == 0) {
|
||||
if (previousTime != 0) {
|
||||
fps = (30 * 1000 / (actualTime - previousTime));
|
||||
}
|
||||
previousTime = actualTime;
|
||||
fpsCounter = 0;
|
||||
}
|
||||
|
||||
arduboy.setCursor(96, 4);
|
||||
arduboy.print(fps);
|
||||
arduboy.print(F("fps"));
|
||||
|
||||
arduboy.setCursor(96, 56);
|
||||
arduboy.print(time1);
|
||||
arduboy.print(F(" ms"));
|
||||
|
||||
#endif
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
|
||||
const unsigned char PROGMEM BITMAP_TEST[] ={
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0,
|
||||
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
|
||||
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0x00,
|
||||
0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
|
||||
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
|
||||
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0xc0,
|
||||
0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x80, 0xc0, 0xc0, 0xc0, 0x40, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfc,
|
||||
0xff, 0xff, 0x1f, 0x7f, 0xff, 0xfe, 0xf0, 0x80,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
|
||||
0xff, 0x81, 0x81, 0x81, 0x81, 0xc3, 0xe7, 0xff,
|
||||
0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03,
|
||||
0x1f, 0xff, 0xfe, 0xfc, 0xe0, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc1,
|
||||
0xc1, 0xc1, 0xc1, 0xc3, 0xff, 0xff, 0x7f, 0x3e,
|
||||
0x00, 0x00, 0x00, 0xf0, 0xfc, 0xff, 0xff, 0x0f,
|
||||
0x03, 0x01, 0x01, 0x01, 0x01, 0x03, 0x07, 0xff,
|
||||
0xff, 0xfe, 0xfc, 0x00, 0x00, 0x00, 0x01, 0x07,
|
||||
0x1f, 0x7f, 0xfe, 0xf8, 0xe0, 0x80, 0xe0, 0xf8,
|
||||
0xfe, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xc0, 0xf8, 0xff, 0xff, 0x3f,
|
||||
0x3f, 0x38, 0x38, 0x38, 0x3b, 0x3f, 0xff, 0xff,
|
||||
0xfc, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
|
||||
0xff, 0x03, 0x03, 0x03, 0x03, 0x07, 0x0f, 0xff,
|
||||
0xfe, 0xfc, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0,
|
||||
0xf8, 0xff, 0x7f, 0x3f, 0x07, 0x00, 0x00, 0x00,
|
||||
0x7f, 0xff, 0xff, 0xf0, 0xc0, 0x80, 0x80, 0x80,
|
||||
0x80, 0xc0, 0xe0, 0xff, 0xff, 0x7f, 0x3f, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x81,
|
||||
0x81, 0x81, 0x81, 0x83, 0xc3, 0xff, 0xff, 0xff,
|
||||
0x7c, 0x00, 0x00, 0x0f, 0x3f, 0xff, 0xff, 0xf0,
|
||||
0xc0, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xe0, 0xff,
|
||||
0xff, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x07, 0xff, 0xff, 0xff, 0x07,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x03, 0x03, 0x03, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x03, 0x03, 0x03, 0x00, 0x00, 0x03, 0x03, 0x03,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BITMAP_COMP_TEST[] ={
|
||||
0x7f, 0xbf, 0xff, 0x67, 0x84, 0xdc, 0x7a, 0xf3, 0xfb, 0xde, 0x7a, 0xeb, 0xad, 0xb7, 0xde, 0xf2,
|
||||
0xf1, 0xde, 0x7a, 0xeb, 0xad, 0xb7, 0x5c, 0xf9, 0x7a, 0x6f, 0x7e, 0xdf, 0x5b, 0x6f, 0xbe, 0xf7,
|
||||
0xd6, 0x5b, 0x6f, 0xbd, 0xf5, 0x96, 0x2b, 0x9f, 0xf7, 0xd8, 0x5b, 0x6f, 0x3d, 0xfa, 0x3d, 0x6e,
|
||||
0xbd, 0xf5, 0xeb, 0x1c, 0x7b, 0x13, 0x7e, 0xca, 0xc1, 0x47, 0x7d, 0x35, 0xc6, 0xe7, 0x3e, 0xb0,
|
||||
0x5c, 0x2e, 0x57, 0x3a, 0x7c, 0xc2, 0xfa, 0xc0, 0x07, 0xae, 0x5e, 0x73, 0x9b, 0xd9, 0x1c, 0x67,
|
||||
0xde, 0xbd, 0xfb, 0xfe, 0xfb, 0xf7, 0x5f, 0x18, 0x8e, 0x0e, 0x47, 0xfb, 0x30, 0xe3, 0x61, 0xd7,
|
||||
0xab, 0xae, 0xa3, 0x57, 0x8f, 0x63, 0x3c, 0xcb, 0x7a, 0xc7, 0x6d, 0x77, 0x72, 0xdb, 0xbd, 0xed,
|
||||
0x4e, 0x6e, 0xbb, 0x9f, 0xf5, 0xf0, 0xc8, 0x5b, 0xb3, 0xd2, 0x44, 0xd2, 0x57, 0x1e, 0x1e, 0xbf,
|
||||
0x5f, 0xbd, 0xf5, 0x34, 0xbb, 0x39, 0xce, 0xbc, 0x7b, 0x3f, 0xbd, 0x7a, 0xec, 0xe1, 0x4d, 0x0e,
|
||||
0x8f, 0x27, 0x6f, 0x2e, 0xb9, 0x7a, 0xcd, 0xe9, 0x09, 0xc7, 0x2f, 0x7c, 0x60, 0xb9, 0x5c, 0x2e,
|
||||
0x47, 0xfb, 0xd2, 0xf1, 0xe8, 0xe2, 0x9b, 0x4b, 0xae, 0x5e, 0x73, 0x7a, 0xc2, 0xf1, 0xcb, 0xdc,
|
||||
0x9e, 0x8e, 0xfe, 0x1e, 0x6e, 0xbd, 0xe5, 0xc7, 0xf4, 0xd6, 0xb7, 0xbd, 0xf5, 0xdb, 0xbd, 0xf5,
|
||||
0xb5, 0xb7, 0xde, 0x7a, 0xeb, 0xad, 0x47, 0x7f, 0x0e, 0xd7, 0xdc, 0x7a, 0xeb, 0x2d, 0x57, 0xbe,
|
||||
0xde, 0x5b, 0x6f, 0xbd, 0xf5, 0xd6, 0x5b, 0x3e, 0xcf, 0x35, 0xb7, 0xde, 0x7a, 0xcb, 0x95, 0xdf,
|
||||
0xe7, 0xad, 0xff, 0xd7, 0x04,
|
||||
};
|
||||
|
||||
// File: test.png
|
||||
// Size: 128x64px (1024 bytes)
|
||||
// Compressed: 229 bytes
|
||||
// Ratio: 0.22363281
|
||||
|
||||
const unsigned char PROGMEM DOG_0[] ={
|
||||
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 unsigned char PROGMEM DOG_1[] ={
|
||||
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 unsigned char PROGMEM DOG_2[] ={
|
||||
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 unsigned char PROGMEM DOG_3[] ={
|
||||
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 unsigned char PROGMEM DOG_4[] ={
|
||||
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 unsigned char PROGMEM DOG_5[] ={
|
||||
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 unsigned char PROGMEM DOG_6[] ={
|
||||
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 unsigned char *DOG[] = {
|
||||
DOG_0,
|
||||
DOG_1,
|
||||
DOG_2,
|
||||
DOG_3,
|
||||
DOG_4,
|
||||
DOG_5,
|
||||
DOG_6,
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
#include <Arduboy.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(60);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
ardbitmap.drawCompressed(WIDTH / 2 ,HEIGHT / 2, BOY, WHITE, ALIGN_CENTER, MIRROR_NONE);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
const unsigned char PROGMEM BOY[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x59, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xfb, 0x70, 0xf4, 0xdf, 0x81,
|
||||
0xf9, 0x36, 0xb7, 0xde, 0x7a, 0xeb, 0x6d, 0x5c, 0xe6, 0xde, 0x7b, 0xc7, 0xcc, 0x34, 0x23, 0x2b,
|
||||
0xc9, 0x9e, 0x27, 0xff, 0xfe, 0x7f, 0x0b, 0x5b, 0x57, 0xfe, 0xb1, 0xad, 0xf5, 0x47, 0xc8, 0x22,
|
||||
0xff, 0xfc, 0x7e, 0x6c, 0xc7, 0x3f, 0xc0, 0x8c, 0xc1, 0xf7, 0xba, 0xf9, 0x54, 0xc6, 0x3f, 0x42,
|
||||
0x6d, 0x60, 0x78, 0xcd, 0xad, 0xfb, 0xb4, 0x0e, 0x7b, 0xdd, 0xb2, 0x32, 0xec, 0xe6, 0x2f, 0x0d,
|
||||
};
|
||||
|
||||
// File: d:\arduboy\boy.gif
|
||||
// Size: 64x64px (512 bytes)
|
||||
// Encoded: 80 bytes
|
||||
// Ratio: 0.15625
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
#include <Arduboy.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(60);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
ardbitmap.drawCompressed(WIDTH / 2 ,HEIGHT / 2, BOY, WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL | MIRROR_VERTICAL);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
const unsigned char PROGMEM BOY[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x59, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xfb, 0x70, 0xf4, 0xdf, 0x81,
|
||||
0xf9, 0x36, 0xb7, 0xde, 0x7a, 0xeb, 0x6d, 0x5c, 0xe6, 0xde, 0x7b, 0xc7, 0xcc, 0x34, 0x23, 0x2b,
|
||||
0xc9, 0x9e, 0x27, 0xff, 0xfe, 0x7f, 0x0b, 0x5b, 0x57, 0xfe, 0xb1, 0xad, 0xf5, 0x47, 0xc8, 0x22,
|
||||
0xff, 0xfc, 0x7e, 0x6c, 0xc7, 0x3f, 0xc0, 0x8c, 0xc1, 0xf7, 0xba, 0xf9, 0x54, 0xc6, 0x3f, 0x42,
|
||||
0x6d, 0x60, 0x78, 0xcd, 0xad, 0xfb, 0xb4, 0x0e, 0x7b, 0xdd, 0xb2, 0x32, 0xec, 0xe6, 0x2f, 0x0d,
|
||||
};
|
||||
|
||||
// File: d:\arduboy\boy.gif
|
||||
// Size: 64x64px (512 bytes)
|
||||
// Encoded: 80 bytes
|
||||
// Ratio: 0.15625
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
#include <Arduboy.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(60);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
ardbitmap.drawCompressedResized(WIDTH / 2 ,HEIGHT, BOY, WHITE, ALIGN_H_CENTER | ALIGN_V_BOTTOM, MIRROR_NONE, 0.5);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
const unsigned char PROGMEM BOY[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x59, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xfb, 0x70, 0xf4, 0xdf, 0x81,
|
||||
0xf9, 0x36, 0xb7, 0xde, 0x7a, 0xeb, 0x6d, 0x5c, 0xe6, 0xde, 0x7b, 0xc7, 0xcc, 0x34, 0x23, 0x2b,
|
||||
0xc9, 0x9e, 0x27, 0xff, 0xfe, 0x7f, 0x0b, 0x5b, 0x57, 0xfe, 0xb1, 0xad, 0xf5, 0x47, 0xc8, 0x22,
|
||||
0xff, 0xfc, 0x7e, 0x6c, 0xc7, 0x3f, 0xc0, 0x8c, 0xc1, 0xf7, 0xba, 0xf9, 0x54, 0xc6, 0x3f, 0x42,
|
||||
0x6d, 0x60, 0x78, 0xcd, 0xad, 0xfb, 0xb4, 0x0e, 0x7b, 0xdd, 0xb2, 0x32, 0xec, 0xe6, 0x2f, 0x0d,
|
||||
};
|
||||
|
||||
// File: d:\arduboy\boy.gif
|
||||
// Size: 64x64px (512 bytes)
|
||||
// Encoded: 80 bytes
|
||||
// Ratio: 0.15625
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
#include <Arduboy.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define FRAME_RATE 60
|
||||
#define SHOW_FPS
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
|
||||
#ifdef SHOW_FPS
|
||||
|
||||
long previousTime = 0;
|
||||
uint8_t fps = 0, fpsCounter = 0;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
//arduboy.begin();
|
||||
arduboy.beginNoLogo();
|
||||
arduboy.setFrameRate(FRAME_RATE);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
//ardbitmap.drawCompressedResized(WIDTH / 2, HEIGHT / 2, BOY[arduboy.frameCount % ARRAY_LEN(BOY)], WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL| MIRROR_VERTICAL, (arduboy.frameCount % 100)/50.0);
|
||||
ardbitmap.drawCompressed(WIDTH / 2, HEIGHT / 2, BOY[arduboy.frameCount % ARRAY_LEN(BOY)], WHITE, ALIGN_CENTER, MIRROR_HORIZONTAL| MIRROR_VERTICAL);
|
||||
|
||||
#ifdef SHOW_FPS
|
||||
fpsCounter++;
|
||||
long actualTime = millis();
|
||||
if ((fpsCounter % 30) == 0) {
|
||||
if (previousTime != 0) {
|
||||
fps = (30 * 1000 / (actualTime - previousTime));
|
||||
}
|
||||
previousTime = actualTime;
|
||||
fpsCounter = 0;
|
||||
}
|
||||
|
||||
arduboy.setCursor(116, 4);
|
||||
arduboy.print(fps);
|
||||
|
||||
#endif
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
// java -jar compressor.jar boy.gif -anp BOY
|
||||
|
||||
const unsigned char PROGMEM BOY_0[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x59, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xfb, 0x70, 0xf4, 0xdf, 0x81,
|
||||
0xf9, 0x36, 0xb7, 0xde, 0x7a, 0xeb, 0x6d, 0x5c, 0xe6, 0xde, 0x7b, 0xc7, 0xcc, 0x34, 0x23, 0x2b,
|
||||
0xc9, 0x9e, 0x27, 0xff, 0xfe, 0x7f, 0x0b, 0x5b, 0x57, 0xfe, 0xb1, 0xad, 0xf5, 0x47, 0xc8, 0x22,
|
||||
0xff, 0xfc, 0x7e, 0x6c, 0xc7, 0x3f, 0xc0, 0x8c, 0xc1, 0xf7, 0xba, 0xf9, 0x54, 0xc6, 0x3f, 0x42,
|
||||
0x6d, 0x60, 0x78, 0xcd, 0xad, 0xfb, 0xb4, 0x0e, 0x7b, 0xdd, 0xb2, 0x32, 0xec, 0xe6, 0x2f, 0x0d,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_1[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd1, 0x99, 0x7b, 0xcf, 0xc3, 0x9e, 0x27, 0xff, 0xb5, 0xae, 0xfe, 0x9a, 0xde,
|
||||
0xc6, 0x65, 0x1d, 0x0e, 0xe3, 0x96, 0xab, 0x57, 0xaf, 0x5e, 0x73, 0x9a, 0x17, 0xfe, 0xf0, 0x7f,
|
||||
0x13, 0xed, 0x3e, 0x8c, 0x5b, 0x6f, 0xbd, 0xe5, 0xea, 0x95, 0xbf, 0x3f, 0xc7, 0xb5, 0x0f, 0xfe,
|
||||
0xee, 0x8c, 0xf8, 0x6f, 0xce, 0xf9, 0xf1, 0x1e, 0xf9, 0xce, 0xca, 0x3f, 0x39, 0x3a, 0xf2, 0xd9,
|
||||
0x47, 0x9f, 0x5c, 0xfe, 0xa3, 0xd3, 0x06, 0x86, 0xd7, 0xdc, 0xba, 0x5e, 0x8f, 0xcb, 0x21, 0x57,
|
||||
0x57, 0xf3, 0x97, 0x06,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_2[] ={
|
||||
0x3f, 0xff, 0xff, 0x39, 0xca, 0xe5, 0x30, 0x6e, 0xbd, 0xf5, 0x34, 0xf3, 0xcf, 0x6f, 0xcd, 0x9b,
|
||||
0x3f, 0x8f, 0x63, 0x4f, 0x73, 0xde, 0xf8, 0x97, 0xe3, 0xbc, 0xac, 0xcb, 0xf8, 0xf9, 0xd9, 0xf3,
|
||||
0xd4, 0xe1, 0x68, 0xa6, 0xff, 0x92, 0x34, 0xfc, 0x15, 0x0e, 0xfc, 0x93, 0xfb, 0x76, 0x0f, 0xfb,
|
||||
0xb0, 0x4e, 0x7e, 0x65, 0x8e, 0x7f, 0x57, 0x19, 0x83, 0xc9, 0x77, 0xbe, 0xfb, 0xbd, 0xe5, 0x3f,
|
||||
0x2c, 0x0f, 0xf1, 0xea, 0xb1, 0xab, 0x7c, 0x39, 0xa7, 0x3d, 0x8e, 0xae, 0x36, 0xfe, 0x2d, 0x01,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_3[] ={
|
||||
0x3f, 0xbf, 0x7f, 0x46, 0xaf, 0x5e, 0xf9, 0xf7, 0xc8, 0x71, 0x5c, 0xe6, 0x3e, 0xf4, 0xf3, 0x54,
|
||||
0xfe, 0x45, 0x65, 0xd4, 0x95, 0xbf, 0x8e, 0xc7, 0x35, 0xfe, 0x19, 0x39, 0xff, 0x10, 0x2c, 0x6e,
|
||||
0x3d, 0xad, 0x41, 0xff, 0x55, 0xfd, 0x11, 0x38, 0x9d, 0xf8, 0x77, 0xf6, 0x5d, 0x2f, 0x87, 0x75,
|
||||
0xd8, 0xf3, 0xe4, 0x57, 0xe6, 0xf8, 0x27, 0x25, 0x23, 0xdf, 0xfb, 0x19, 0x59, 0x9f, 0xfa, 0x17,
|
||||
0xa5, 0xcd, 0xf4, 0x9a, 0x5b, 0xfd, 0x41, 0x73, 0x1d, 0x9d, 0x2c, 0xf3, 0x37, 0x04,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_4[] ={
|
||||
0x3f, 0xff, 0x7f, 0xdc, 0xb9, 0xf7, 0xde, 0x7b, 0xde, 0xf8, 0xf7, 0xe3, 0x6d, 0x5c, 0xe6, 0xbc,
|
||||
0xac, 0x53, 0x8f, 0xfe, 0x34, 0xb3, 0xf8, 0xf7, 0xc2, 0x71, 0x66, 0xf6, 0x90, 0xe1, 0x1f, 0xe8,
|
||||
0x5f, 0x07, 0x76, 0xef, 0x8b, 0x6b, 0xe6, 0x6f, 0x40, 0x73, 0x58, 0x97, 0x75, 0xf8, 0xb7, 0xf4,
|
||||
0xf7, 0xc8, 0xfc, 0x57, 0xc6, 0xfc, 0xf6, 0xa5, 0xa7, 0x39, 0x2f, 0xe3, 0x2b, 0x1e, 0x4e, 0xf9,
|
||||
0x47, 0xb5, 0xfd, 0xce, 0xaf, 0x99, 0xf9, 0x0e, 0xb7, 0x7f, 0x3b, 0x59, 0xc3, 0x6b, 0x6e, 0x63,
|
||||
0xfc, 0xb8, 0xdd, 0xab, 0x57, 0x2d, 0x7f, 0x37,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_5[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xe6, 0x1e, 0x0e, 0xeb, 0xb2, 0x2e, 0x73, 0xfe, 0x5b, 0x1a, 0x7b, 0xcf, 0x53,
|
||||
0x6f, 0xb9, 0xfa, 0x13, 0xc3, 0xe4, 0xdf, 0x81, 0xb7, 0x71, 0x09, 0x1d, 0x99, 0x21, 0x97, 0x31,
|
||||
0x46, 0xe4, 0xaf, 0xc3, 0xf8, 0x87, 0xe0, 0x95, 0x97, 0xec, 0xe4, 0x4f, 0x41, 0x7a, 0x58, 0x97,
|
||||
0xd9, 0x7f, 0x4f, 0x7f, 0x8e, 0xcd, 0xbf, 0xb3, 0xef, 0x2e, 0xef, 0x5e, 0x0e, 0xe3, 0xc8, 0x57,
|
||||
0xe6, 0xf8, 0x57, 0xe5, 0xfe, 0xd4, 0xf6, 0xfb, 0x3d, 0x7c, 0xb2, 0xe3, 0x5f, 0xce, 0xf0, 0xea,
|
||||
0x71, 0x8c, 0xdf, 0x97, 0x79, 0xf4, 0xea, 0x1c, 0xfe, 0xe1, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_6[] ={
|
||||
0x3f, 0xbf, 0xff, 0x0a, 0xc6, 0x61, 0xef, 0xbd, 0xe7, 0xc9, 0x7f, 0x3e, 0xbd, 0xcc, 0x7d, 0x58,
|
||||
0x97, 0x71, 0xcb, 0xd5, 0xab, 0x57, 0xbe, 0x6d, 0xfe, 0xf0, 0xce, 0x34, 0xcb, 0x95, 0x7a, 0x50,
|
||||
0x4f, 0xbd, 0x65, 0xb5, 0xe6, 0x20, 0x1e, 0xf9, 0xfd, 0x8c, 0x7f, 0x33, 0x19, 0xc3, 0xbf, 0xc5,
|
||||
0xba, 0xac, 0xcb, 0x85, 0x7f, 0x46, 0x9b, 0xdf, 0xcf, 0xfc, 0x77, 0xf6, 0xdd, 0x95, 0xb3, 0x97,
|
||||
0xc3, 0xf8, 0xe6, 0xcc, 0xbf, 0xa7, 0xc9, 0x77, 0xb2, 0x7f, 0xca, 0x98, 0x5f, 0xe1, 0xf6, 0xaf,
|
||||
0xe7, 0x94, 0x6b, 0x36, 0xf9, 0xa5, 0x5d, 0x47, 0xaf, 0xce, 0xe1, 0x1f, 0x0e,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_7[] ={
|
||||
0x3f, 0xbf, 0xff, 0x2c, 0x72, 0x5a, 0x97, 0x75, 0x19, 0x47, 0xfe, 0xf9, 0xe4, 0xd6, 0xd3, 0x3a,
|
||||
0xec, 0x79, 0x19, 0xb7, 0xde, 0x7a, 0xf3, 0xcb, 0x19, 0x7f, 0x68, 0x97, 0x2b, 0xcd, 0x4a, 0x33,
|
||||
0xad, 0x07, 0xf5, 0x32, 0x6e, 0x1d, 0x4d, 0x33, 0xfd, 0x8b, 0xd8, 0x7f, 0x2e, 0xa4, 0xe3, 0xc8,
|
||||
0xef, 0xf6, 0xd6, 0x5b, 0xf7, 0xbf, 0xa2, 0x91, 0x3f, 0xc7, 0x3f, 0x2c, 0xe7, 0x67, 0xc7, 0x38,
|
||||
0xe6, 0x72, 0x18, 0x5f, 0xed, 0xfa, 0xd7, 0xf4, 0xb9, 0xee, 0x8f, 0x73, 0x5c, 0xeb, 0x2b, 0x9e,
|
||||
0xfe, 0xcd, 0xb8, 0x4f, 0xb9, 0x66, 0xd5, 0x5f, 0x3a, 0xc6, 0xd1, 0xab, 0x73, 0xf8, 0x87, 0x03,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_8[] ={
|
||||
0x3f, 0xff, 0xff, 0x5e, 0x38, 0xf6, 0xd6, 0x5b, 0xfe, 0x75, 0x79, 0xf5, 0x38, 0x2e, 0x73, 0xef,
|
||||
0xbd, 0xf7, 0x1e, 0x9f, 0xcd, 0xe1, 0xcf, 0xca, 0xb6, 0x59, 0x69, 0x56, 0x9a, 0xe5, 0x4a, 0x33,
|
||||
0x4d, 0x76, 0xe8, 0xde, 0xc5, 0x0b, 0x7f, 0x96, 0x7f, 0x3a, 0xd9, 0xa7, 0xfc, 0x4c, 0xae, 0x5e,
|
||||
0x3d, 0xae, 0x75, 0xe4, 0xdf, 0x49, 0xfb, 0xc7, 0xf8, 0x97, 0x95, 0xcb, 0xf7, 0x0e, 0xeb, 0xd4,
|
||||
0xcb, 0xc5, 0xef, 0x66, 0xfc, 0x3b, 0xfa, 0xe8, 0xc1, 0xaf, 0x8f, 0xc3, 0xc5, 0xaf, 0x6c, 0xff,
|
||||
0xdd, 0x8c, 0x71, 0xf4, 0x58, 0xc3, 0x0f, 0xcc, 0x3c, 0xe5, 0xea, 0x4e, 0xf4, 0x8f, 0x07,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_9[] ={
|
||||
0x3f, 0xff, 0xff, 0xb9, 0xcb, 0xad, 0xb7, 0xde, 0xc6, 0x65, 0xae, 0xa3, 0x57, 0x8f, 0x5d, 0xf4,
|
||||
0x8f, 0xeb, 0xb6, 0x6e, 0xeb, 0xb6, 0x4e, 0x97, 0xcb, 0x95, 0x74, 0xd5, 0x8e, 0xe1, 0xe8, 0x5f,
|
||||
0x05, 0xcd, 0xbf, 0x9e, 0x71, 0x38, 0xf4, 0x67, 0xf1, 0xf5, 0x1e, 0xfe, 0xcd, 0x2c, 0x7f, 0xfe,
|
||||
0xca, 0xe6, 0xea, 0x95, 0x7f, 0x37, 0x9e, 0x3e, 0xc1, 0x71, 0xcd, 0xc3, 0xc5, 0x5f, 0xf1, 0x6f,
|
||||
0xea, 0x2b, 0x1c, 0xbe, 0x3d, 0x0e, 0x17, 0xbf, 0xb3, 0xfc, 0x37, 0x14, 0x3a, 0x2f, 0xb3, 0x3f,
|
||||
0xb0, 0xe3, 0x96, 0xab, 0xdb, 0xea, 0x1f, 0x0f,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_10[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd9, 0xec, 0x61, 0xef, 0xbd, 0xf7, 0x21, 0x7f, 0xed, 0xde, 0x7a, 0x1b, 0x17,
|
||||
0xcd, 0xb6, 0x19, 0x6d, 0xb3, 0x5c, 0x2e, 0xa6, 0x7f, 0x10, 0xf9, 0x53, 0x73, 0xf5, 0xca, 0x67,
|
||||
0x73, 0xda, 0xe3, 0x6f, 0xf4, 0x8f, 0x26, 0xfe, 0x78, 0xbd, 0xe6, 0x36, 0x2e, 0xeb, 0x1f, 0xd3,
|
||||
0x67, 0xfd, 0x19, 0xae, 0x7f, 0x5f, 0x5c, 0x6e, 0xbc, 0x1a, 0xf3, 0xc8, 0x9d, 0xdb, 0xee, 0xe7,
|
||||
0xfe, 0x91, 0xad, 0xcb, 0xba, 0xf1, 0x53, 0xca, 0xea, 0xd1, 0xab, 0x39, 0xf8, 0x87, 0x03,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_11[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd9, 0xec, 0x61, 0xef, 0xbd, 0xe7, 0xc9, 0x7f, 0x3d, 0xe3, 0x32, 0xf7, 0x9e,
|
||||
0x97, 0x71, 0xcb, 0xd5, 0xab, 0x57, 0xbe, 0x3b, 0xc6, 0x3f, 0x04, 0x47, 0x56, 0x9a, 0x95, 0xe4,
|
||||
0x30, 0x6e, 0x1d, 0x4d, 0xfd, 0xd3, 0xac, 0xfc, 0x03, 0x5a, 0xfc, 0xe4, 0x38, 0xe6, 0xbc, 0xac,
|
||||
0xcb, 0x21, 0xff, 0x9c, 0x32, 0x7f, 0xed, 0x3f, 0xc6, 0x9d, 0x6f, 0x1c, 0xe6, 0xfa, 0xda, 0xc8,
|
||||
0x3f, 0xbd, 0xb2, 0x7a, 0xeb, 0xfa, 0x54, 0x5c, 0x3d, 0x7a, 0x35, 0x07, 0xff, 0x70,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_12[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd5, 0x1c, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xe7, 0x94, 0xdb, 0xb8, 0xcc,
|
||||
0x79, 0x19, 0xb7, 0xde, 0xfa, 0x1b, 0x76, 0xfe, 0x59, 0xe4, 0xb2, 0x0e, 0x49, 0xda, 0x39, 0x2f,
|
||||
0x2b, 0x7f, 0x98, 0xcd, 0xbf, 0x9f, 0xd1, 0x9f, 0x3d, 0xe6, 0x3e, 0xac, 0xc3, 0x25, 0xff, 0x9c,
|
||||
0xb2, 0x7f, 0xec, 0xbf, 0xcf, 0xcf, 0xf1, 0xbd, 0x8c, 0x7f, 0x81, 0x6d, 0x5d, 0xbd, 0xf5, 0x70,
|
||||
0xe3, 0x52, 0x66, 0x8f, 0x5e, 0xcd, 0xc1, 0x3f, 0x1c,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_13[] ={
|
||||
0x3f, 0xff, 0xff, 0xb1, 0x5c, 0x87, 0xbd, 0xf7, 0x9e, 0xff, 0xb8, 0xbc, 0x8d, 0xcb, 0xdc, 0x87,
|
||||
0x75, 0xea, 0xad, 0x3f, 0x24, 0xfe, 0x33, 0xda, 0x3c, 0x0a, 0xf9, 0xf3, 0xfc, 0xa3, 0xf1, 0xd6,
|
||||
0xfe, 0xfe, 0xb9, 0x0e, 0x7b, 0xaf, 0x23, 0xff, 0x7e, 0x38, 0x1e, 0xf8, 0x9d, 0xcc, 0x7f, 0x94,
|
||||
0xbf, 0xf3, 0x1f, 0x61, 0x46, 0x3b, 0x58, 0xbd, 0x15, 0xe6, 0x69, 0xf7, 0x96, 0xab, 0xb3, 0xd1,
|
||||
0x3f, 0x1e,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_14[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x9c, 0xf3, 0xb2, 0x2e, 0x73, 0xff, 0x53, 0xcb, 0x6d, 0x1c, 0x0e, 0xe3,
|
||||
0xd6, 0x5b, 0xae, 0x7c, 0x1c, 0x47, 0xff, 0x1d, 0xa5, 0x93, 0xbf, 0x97, 0xeb, 0x9f, 0xd0, 0xdf,
|
||||
0xe1, 0x34, 0xd7, 0x65, 0x8e, 0x7f, 0x4e, 0x4c, 0xf3, 0x93, 0xff, 0x1d, 0xc6, 0xef, 0xe6, 0x7b,
|
||||
0x2e, 0xf2, 0xcf, 0x8e, 0xae, 0xde, 0x7a, 0x2b, 0x8e, 0x87, 0x71, 0xf5, 0xe8, 0xd5, 0x1c, 0xfc,
|
||||
0xc3, 0x01,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_15[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd9, 0xcb, 0x6d, 0xe7, 0xea, 0xd5, 0x6b, 0x4e, 0xff, 0xf4, 0x3c, 0xdc, 0xf8,
|
||||
0xf9, 0xb9, 0x1c, 0xfa, 0x0f, 0x29, 0xf9, 0x73, 0xac, 0xb5, 0x4f, 0x79, 0x72, 0xc9, 0x3f, 0x93,
|
||||
0x3f, 0xc3, 0xe6, 0xf3, 0x39, 0xad, 0xc3, 0xfc, 0xa3, 0x7b, 0x9a, 0xfd, 0x0e, 0xa7, 0xc3, 0xec,
|
||||
0x77, 0xff, 0xb9, 0x7d, 0xf7, 0x0b, 0x9f, 0xfd, 0xa7, 0x66, 0x56, 0x6f, 0xbd, 0x1d, 0xf8, 0x52,
|
||||
0x5d, 0x3d, 0x7a, 0x35, 0x61, 0xf8, 0x87, 0x03,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_16[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xf6, 0xdc, 0xc6, 0x65, 0x5d, 0xc6, 0x91, 0x7f, 0x9d, 0xe3, 0x32, 0xfb, 0x63,
|
||||
0xe6, 0x3e, 0x8c, 0x23, 0xff, 0xbe, 0x46, 0xfe, 0x0e, 0xde, 0x32, 0xbd, 0x8d, 0x79, 0xe4, 0x9f,
|
||||
0x4b, 0xfd, 0x2b, 0x7c, 0xcb, 0xe3, 0xb8, 0x84, 0xec, 0xd8, 0x95, 0xe6, 0x0f, 0xbe, 0xfd, 0x2b,
|
||||
0xfc, 0xfb, 0x5a, 0xfd, 0x8e, 0xa7, 0xdd, 0xe3, 0xea, 0x77, 0xff, 0x7d, 0x39, 0x3e, 0xf4, 0xe9,
|
||||
0xcf, 0xd9, 0x7f, 0x52, 0x8e, 0xba, 0x7a, 0x5a, 0xf3, 0xc8, 0xa7, 0xe3, 0xea, 0xd1, 0xab, 0x09,
|
||||
0xc3, 0x3f, 0x1c,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_17[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xd3, 0xc3, 0xb8, 0xf5, 0xd6, 0xd3, 0x1c, 0xff, 0x3c, 0xb9, 0xed, 0xf1, 0xeb,
|
||||
0xb8, 0xe6, 0x36, 0x0e, 0x7b, 0x9e, 0xfa, 0x8f, 0x68, 0xe5, 0x4f, 0x50, 0xaf, 0xb9, 0xf5, 0xb4,
|
||||
0x2e, 0x9a, 0x6d, 0xdd, 0xd6, 0x6d, 0xf9, 0x27, 0xb0, 0xfc, 0x0b, 0xb8, 0xfe, 0x69, 0x9d, 0xfc,
|
||||
0x3b, 0xac, 0xfe, 0x2b, 0xca, 0x3e, 0xf9, 0x8e, 0xdb, 0x5c, 0x47, 0xae, 0xab, 0x5f, 0x1e, 0xfc,
|
||||
0x3b, 0xfa, 0x4e, 0xc7, 0xaf, 0xf9, 0xe6, 0x3f, 0xa3, 0xc1, 0xf4, 0x38, 0x0e, 0xbf, 0x6d, 0x8c,
|
||||
0xa3, 0x57, 0xe7, 0xf0, 0x0f, 0x07,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_18[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xb8, 0xac, 0x5b, 0xae, 0x5e, 0x73, 0xda, 0xbd, 0xf2, 0xaf, 0x73, 0x8c, 0xdf,
|
||||
0xcb, 0x35, 0xb7, 0x9e, 0xd6, 0x61, 0xcf, 0x53, 0xae, 0x5e, 0xbd, 0xf2, 0x77, 0xef, 0xfa, 0x7b,
|
||||
0x7c, 0x85, 0xab, 0x57, 0xaf, 0x5e, 0xfd, 0xe7, 0xa0, 0x7f, 0x0b, 0x0e, 0xff, 0xb0, 0x4e, 0xfe,
|
||||
0x1d, 0xa6, 0xff, 0x8c, 0xbc, 0x9c, 0x78, 0xe7, 0x69, 0xce, 0x93, 0xe7, 0x8e, 0xef, 0xff, 0xfb,
|
||||
0x61, 0x7e, 0x67, 0xf4, 0xd7, 0x7c, 0xf8, 0x9f, 0x8e, 0xe3, 0xe8, 0x71, 0x8d, 0x9f, 0x97, 0x79,
|
||||
0xf4, 0xea, 0xae, 0x7f, 0x38,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_19[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xa2, 0x32, 0xc6, 0xad, 0xb7, 0xde, 0xd6, 0xfa, 0xc7, 0xfb, 0x43, 0xb9, 0x7a,
|
||||
0xec, 0xad, 0xb7, 0x9e, 0xd6, 0x65, 0xaf, 0xcb, 0xba, 0x04, 0x2f, 0x86, 0x3f, 0xfa, 0xc8, 0x1f,
|
||||
0x65, 0xe7, 0x5f, 0xd9, 0xda, 0x7f, 0x93, 0xcc, 0x7f, 0x5a, 0x3b, 0x7f, 0x87, 0xe9, 0x3f, 0x23,
|
||||
0x6e, 0x07, 0x3f, 0x93, 0xcb, 0x61, 0x1c, 0x73, 0xf8, 0x01, 0xff, 0x7a, 0x32, 0xbe, 0x92, 0x79,
|
||||
0xe4, 0xfb, 0x93, 0xef, 0xfe, 0xcb, 0xa9, 0xd3, 0x63, 0x2f, 0xbf, 0x8e, 0x7d, 0xf3, 0xea, 0x21,
|
||||
0xfe, 0xe1, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_20[] ={
|
||||
0x3f, 0xbf, 0x7f, 0x15, 0xc8, 0xe1, 0xb0, 0x2e, 0xeb, 0x32, 0xc7, 0x3f, 0xdf, 0xdf, 0xe1, 0xad,
|
||||
0xb7, 0x9e, 0xd6, 0x65, 0x5d, 0xd6, 0x61, 0xef, 0xbd, 0x2f, 0xbd, 0xf5, 0x36, 0x2e, 0xc1, 0x83,
|
||||
0x7f, 0xe9, 0xe5, 0x5f, 0x05, 0xdd, 0xf5, 0xea, 0xd5, 0x7f, 0x3e, 0x5e, 0xf6, 0xfe, 0x8b, 0xcc,
|
||||
0xfc, 0xeb, 0x5a, 0xfd, 0x03, 0xb0, 0x26, 0xff, 0xaa, 0x66, 0xbe, 0xc3, 0x6d, 0xae, 0x63, 0x4e,
|
||||
0x9f, 0xff, 0x67, 0xf4, 0xc1, 0x43, 0x3f, 0x3f, 0xf9, 0xee, 0xbf, 0x1c, 0x3b, 0x3d, 0xf6, 0x74,
|
||||
0xf0, 0x07, 0xb9, 0x6f, 0x5e, 0x3d, 0xc4, 0x3f, 0x1c,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_21[] ={
|
||||
0x3f, 0xff, 0x7f, 0x1e, 0x8f, 0x3d, 0xfa, 0xcf, 0x97, 0xdb, 0xef, 0x98, 0x7b, 0xcf, 0xcb, 0x3a,
|
||||
0xf5, 0xd6, 0x5b, 0xae, 0xbe, 0xf6, 0xea, 0xb1, 0xa7, 0xfc, 0xa5, 0xeb, 0x9f, 0x84, 0x1d, 0xba,
|
||||
0xf7, 0x3e, 0x8c, 0x5b, 0x6f, 0xb9, 0x7a, 0xe5, 0xcf, 0x9f, 0xc3, 0xa9, 0x37, 0x7f, 0xf5, 0x38,
|
||||
0x5c, 0xf2, 0xcf, 0xed, 0x4f, 0x61, 0x96, 0xf0, 0x6f, 0xec, 0xfb, 0x63, 0x9e, 0x66, 0x3f, 0x55,
|
||||
0xfe, 0x79, 0x75, 0x7c, 0x26, 0x87, 0x1b, 0xdf, 0x69, 0xbe, 0xf5, 0x2f, 0x89, 0x34, 0x33, 0xb7,
|
||||
0xde, 0x56, 0x7f, 0xcd, 0xce, 0xd5, 0xab, 0xfe, 0xf1, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_22[] ={
|
||||
0x3f, 0xbf, 0xff, 0xdd, 0xc9, 0x3e, 0xf5, 0xd6, 0xdb, 0x38, 0x9c, 0xbc, 0x7a, 0xf5, 0xc7, 0xf7,
|
||||
0x34, 0xfe, 0xf6, 0xdb, 0xdf, 0xcf, 0x64, 0xb9, 0x5c, 0x8e, 0x15, 0x73, 0x50, 0x2f, 0xe3, 0xd6,
|
||||
0xa3, 0x7f, 0xfe, 0xae, 0x23, 0x7f, 0x84, 0x3d, 0xfe, 0xcd, 0xf5, 0xd6, 0xf5, 0xe3, 0x67, 0xe2,
|
||||
0xbf, 0xb9, 0xdf, 0xcd, 0x34, 0xff, 0xf4, 0xbe, 0xe7, 0xe1, 0x94, 0xe3, 0x97, 0x18, 0xff, 0xb6,
|
||||
0xd8, 0x75, 0xb1, 0x7a, 0xeb, 0xe1, 0xe4, 0xf7, 0x56, 0x8f, 0xde, 0xfe, 0xb4,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_23[] ={
|
||||
0x3f, 0xbf, 0xff, 0xdd, 0xc9, 0x3e, 0xf5, 0xd6, 0xdb, 0x38, 0x9c, 0xbc, 0x7a, 0xf5, 0xc7, 0xf7,
|
||||
0x34, 0xfe, 0xf6, 0xdb, 0xdf, 0xcf, 0x64, 0xb9, 0x5c, 0x8e, 0x15, 0x73, 0x50, 0x2f, 0xe3, 0xd6,
|
||||
0xa3, 0x7f, 0xfe, 0xae, 0x23, 0x7f, 0x84, 0x3d, 0xfe, 0xcd, 0xf5, 0xd6, 0x55, 0x7f, 0xf6, 0x6a,
|
||||
0xfc, 0x37, 0xf7, 0xbb, 0x99, 0xe6, 0x9f, 0xde, 0xf7, 0x3c, 0x9c, 0x72, 0xfc, 0x12, 0xe3, 0xdf,
|
||||
0x16, 0xbb, 0x2e, 0x56, 0x6f, 0x3d, 0x1d, 0xfc, 0xde, 0xea, 0xd1, 0xdb, 0x9f, 0x16,
|
||||
};
|
||||
|
||||
|
||||
const unsigned char *BOY[] = {
|
||||
BOY_0,
|
||||
BOY_1,
|
||||
BOY_2,
|
||||
BOY_3,
|
||||
BOY_4,
|
||||
BOY_5,
|
||||
BOY_6,
|
||||
BOY_7,
|
||||
BOY_8,
|
||||
BOY_9,
|
||||
BOY_10,
|
||||
BOY_11,
|
||||
BOY_12,
|
||||
BOY_13,
|
||||
BOY_14,
|
||||
BOY_15,
|
||||
BOY_16,
|
||||
BOY_17,
|
||||
BOY_18,
|
||||
BOY_19,
|
||||
BOY_20,
|
||||
BOY_21,
|
||||
BOY_22,
|
||||
BOY_23,
|
||||
};
|
||||
|
||||
// File: d:\arduboy\boy.gif (24 frames)
|
||||
// Size: 24x64x64px (12288 bytes)
|
||||
// Encoded: 1978 bytes
|
||||
// Ratio: 0.16097005
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
#include <Arduboy2.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy2 arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(60);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
ardbitmap.drawCompressed(WIDTH / 2 ,HEIGHT / 2, BOY, WHITE, ALIGN_CENTER, MIRROR_NONE);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
const unsigned char PROGMEM BOY[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x59, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xfb, 0x70, 0xf4, 0xdf, 0x81,
|
||||
0xf9, 0x36, 0xb7, 0xde, 0x7a, 0xeb, 0x6d, 0x5c, 0xe6, 0xde, 0x7b, 0xc7, 0xcc, 0x34, 0x23, 0x2b,
|
||||
0xc9, 0x9e, 0x27, 0xff, 0xfe, 0x7f, 0x0b, 0x5b, 0x57, 0xfe, 0xb1, 0xad, 0xf5, 0x47, 0xc8, 0x22,
|
||||
0xff, 0xfc, 0x7e, 0x6c, 0xc7, 0x3f, 0xc0, 0x8c, 0xc1, 0xf7, 0xba, 0xf9, 0x54, 0xc6, 0x3f, 0x42,
|
||||
0x6d, 0x60, 0x78, 0xcd, 0xad, 0xfb, 0xb4, 0x0e, 0x7b, 0xdd, 0xb2, 0x32, 0xec, 0xe6, 0x2f, 0x0d,
|
||||
};
|
||||
|
||||
// File: d:\arduboy\boy.gif
|
||||
// Size: 64x64px (512 bytes)
|
||||
// Encoded: 80 bytes
|
||||
// Ratio: 0.15625
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
#include <Arduboy.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define FRAME_RATE 24
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// make an ArdBitmap instance that will use the given the screen buffer and dimensions
|
||||
#define ARDBITMAP_SBUF arduboy.getBuffer()
|
||||
#include <ArdBitmap.h>
|
||||
ArdBitmap<WIDTH, HEIGHT> ardbitmap;
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(FRAME_RATE);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
float resize1 = abs(cos(millis()/ 1000.0));
|
||||
float resize2 = abs(sin(millis()/ 1000.0));
|
||||
|
||||
ardbitmap.drawCompressedResized(WIDTH/ 4, HEIGHT, BOY[arduboy.frameCount % ARRAY_LEN(BOY)], WHITE, ALIGN_H_CENTER | ALIGN_V_BOTTOM, MIRROR_NONE, resize1);
|
||||
|
||||
ardbitmap.drawCompressedResized((WIDTH * 3) / 4, HEIGHT, BOY[(arduboy.frameCount + 10) % ARRAY_LEN(BOY)], WHITE, ALIGN_H_CENTER | ALIGN_V_BOTTOM, MIRROR_NONE, resize2);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
|
||||
const unsigned char PROGMEM BOY_0[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x59, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xfb, 0x70, 0xf4, 0xdf, 0x81,
|
||||
0xf9, 0x36, 0xb7, 0xde, 0x7a, 0xeb, 0x6d, 0x5c, 0xe6, 0xde, 0x7b, 0xc7, 0xcc, 0x34, 0x23, 0x2b,
|
||||
0xc9, 0x9e, 0x27, 0xff, 0xfe, 0x7f, 0x0b, 0x5b, 0x57, 0xfe, 0xb1, 0xad, 0xf5, 0x47, 0xc8, 0x22,
|
||||
0xff, 0xfc, 0x7e, 0x6c, 0xc7, 0x3f, 0xc0, 0x8c, 0xc1, 0xf7, 0xba, 0xf9, 0x54, 0xc6, 0x3f, 0x42,
|
||||
0x6d, 0x60, 0x78, 0xcd, 0xad, 0xfb, 0xb4, 0x0e, 0x7b, 0xdd, 0xb2, 0x32, 0xec, 0xe6, 0x2f, 0x0d,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_1[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd1, 0x99, 0x7b, 0xcf, 0xc3, 0x9e, 0x27, 0xff, 0xb5, 0xae, 0xfe, 0x9a, 0xde,
|
||||
0xc6, 0x65, 0x1d, 0x0e, 0xe3, 0x96, 0xab, 0x57, 0xaf, 0x5e, 0x73, 0x9a, 0x17, 0xfe, 0xf0, 0x7f,
|
||||
0x13, 0xed, 0x3e, 0x8c, 0x5b, 0x6f, 0xbd, 0xe5, 0xea, 0x95, 0xbf, 0x3f, 0xc7, 0xb5, 0x0f, 0xfe,
|
||||
0xee, 0x8c, 0xf8, 0x6f, 0xce, 0xf9, 0xf1, 0x1e, 0xf9, 0xce, 0xca, 0x3f, 0x39, 0x3a, 0xf2, 0xd9,
|
||||
0x47, 0x9f, 0x5c, 0xfe, 0xa3, 0xd3, 0x06, 0x86, 0xd7, 0xdc, 0xba, 0x5e, 0x8f, 0xcb, 0x21, 0x57,
|
||||
0x57, 0xf3, 0x97, 0x06,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_2[] ={
|
||||
0x3f, 0xff, 0xff, 0x39, 0xca, 0xe5, 0x30, 0x6e, 0xbd, 0xf5, 0x34, 0xf3, 0xcf, 0x6f, 0xcd, 0x9b,
|
||||
0x3f, 0x8f, 0x63, 0x4f, 0x73, 0xde, 0xf8, 0x97, 0xe3, 0xbc, 0xac, 0xcb, 0xf8, 0xf9, 0xd9, 0xf3,
|
||||
0xd4, 0xe1, 0x68, 0xa6, 0xff, 0x92, 0x34, 0xfc, 0x15, 0x0e, 0xfc, 0x93, 0xfb, 0x76, 0x0f, 0xfb,
|
||||
0xb0, 0x4e, 0x7e, 0x65, 0x8e, 0x7f, 0x57, 0x19, 0x83, 0xc9, 0x77, 0xbe, 0xfb, 0xbd, 0xe5, 0x3f,
|
||||
0x2c, 0x0f, 0xf1, 0xea, 0xb1, 0xab, 0x7c, 0x39, 0xa7, 0x3d, 0x8e, 0xae, 0x36, 0xfe, 0x2d, 0x01,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_3[] ={
|
||||
0x3f, 0xbf, 0x7f, 0x46, 0xaf, 0x5e, 0xf9, 0xf7, 0xc8, 0x71, 0x5c, 0xe6, 0x3e, 0xf4, 0xf3, 0x54,
|
||||
0xfe, 0x45, 0x65, 0xd4, 0x95, 0xbf, 0x8e, 0xc7, 0x35, 0xfe, 0x19, 0x39, 0xff, 0x10, 0x2c, 0x6e,
|
||||
0x3d, 0xad, 0x41, 0xff, 0x55, 0xfd, 0x11, 0x38, 0x9d, 0xf8, 0x77, 0xf6, 0x5d, 0x2f, 0x87, 0x75,
|
||||
0xd8, 0xf3, 0xe4, 0x57, 0xe6, 0xf8, 0x27, 0x25, 0x23, 0xdf, 0xfb, 0x19, 0x59, 0x9f, 0xfa, 0x17,
|
||||
0xa5, 0xcd, 0xf4, 0x9a, 0x5b, 0xfd, 0x41, 0x73, 0x1d, 0x9d, 0x2c, 0xf3, 0x37, 0x04,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_4[] ={
|
||||
0x3f, 0xff, 0x7f, 0xdc, 0xb9, 0xf7, 0xde, 0x7b, 0xde, 0xf8, 0xf7, 0xe3, 0x6d, 0x5c, 0xe6, 0xbc,
|
||||
0xac, 0x53, 0x8f, 0xfe, 0x34, 0xb3, 0xf8, 0xf7, 0xc2, 0x71, 0x66, 0xf6, 0x90, 0xe1, 0x1f, 0xe8,
|
||||
0x5f, 0x07, 0x76, 0xef, 0x8b, 0x6b, 0xe6, 0x6f, 0x40, 0x73, 0x58, 0x97, 0x75, 0xf8, 0xb7, 0xf4,
|
||||
0xf7, 0xc8, 0xfc, 0x57, 0xc6, 0xfc, 0xf6, 0xa5, 0xa7, 0x39, 0x2f, 0xe3, 0x2b, 0x1e, 0x4e, 0xf9,
|
||||
0x47, 0xb5, 0xfd, 0xce, 0xaf, 0x99, 0xf9, 0x0e, 0xb7, 0x7f, 0x3b, 0x59, 0xc3, 0x6b, 0x6e, 0x63,
|
||||
0xfc, 0xb8, 0xdd, 0xab, 0x57, 0x2d, 0x7f, 0x37,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_5[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xe6, 0x1e, 0x0e, 0xeb, 0xb2, 0x2e, 0x73, 0xfe, 0x5b, 0x1a, 0x7b, 0xcf, 0x53,
|
||||
0x6f, 0xb9, 0xfa, 0x13, 0xc3, 0xe4, 0xdf, 0x81, 0xb7, 0x71, 0x09, 0x1d, 0x99, 0x21, 0x97, 0x31,
|
||||
0x46, 0xe4, 0xaf, 0xc3, 0xf8, 0x87, 0xe0, 0x95, 0x97, 0xec, 0xe4, 0x4f, 0x41, 0x7a, 0x58, 0x97,
|
||||
0xd9, 0x7f, 0x4f, 0x7f, 0x8e, 0xcd, 0xbf, 0xb3, 0xef, 0x2e, 0xef, 0x5e, 0x0e, 0xe3, 0xc8, 0x57,
|
||||
0xe6, 0xf8, 0x57, 0xe5, 0xfe, 0xd4, 0xf6, 0xfb, 0x3d, 0x7c, 0xb2, 0xe3, 0x5f, 0xce, 0xf0, 0xea,
|
||||
0x71, 0x8c, 0xdf, 0x97, 0x79, 0xf4, 0xea, 0x1c, 0xfe, 0xe1, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_6[] ={
|
||||
0x3f, 0xbf, 0xff, 0x0a, 0xc6, 0x61, 0xef, 0xbd, 0xe7, 0xc9, 0x7f, 0x3e, 0xbd, 0xcc, 0x7d, 0x58,
|
||||
0x97, 0x71, 0xcb, 0xd5, 0xab, 0x57, 0xbe, 0x6d, 0xfe, 0xf0, 0xce, 0x34, 0xcb, 0x95, 0x7a, 0x50,
|
||||
0x4f, 0xbd, 0x65, 0xb5, 0xe6, 0x20, 0x1e, 0xf9, 0xfd, 0x8c, 0x7f, 0x33, 0x19, 0xc3, 0xbf, 0xc5,
|
||||
0xba, 0xac, 0xcb, 0x85, 0x7f, 0x46, 0x9b, 0xdf, 0xcf, 0xfc, 0x77, 0xf6, 0xdd, 0x95, 0xb3, 0x97,
|
||||
0xc3, 0xf8, 0xe6, 0xcc, 0xbf, 0xa7, 0xc9, 0x77, 0xb2, 0x7f, 0xca, 0x98, 0x5f, 0xe1, 0xf6, 0xaf,
|
||||
0xe7, 0x94, 0x6b, 0x36, 0xf9, 0xa5, 0x5d, 0x47, 0xaf, 0xce, 0xe1, 0x1f, 0x0e,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_7[] ={
|
||||
0x3f, 0xbf, 0xff, 0x2c, 0x72, 0x5a, 0x97, 0x75, 0x19, 0x47, 0xfe, 0xf9, 0xe4, 0xd6, 0xd3, 0x3a,
|
||||
0xec, 0x79, 0x19, 0xb7, 0xde, 0x7a, 0xf3, 0xcb, 0x19, 0x7f, 0x68, 0x97, 0x2b, 0xcd, 0x4a, 0x33,
|
||||
0xad, 0x07, 0xf5, 0x32, 0x6e, 0x1d, 0x4d, 0x33, 0xfd, 0x8b, 0xd8, 0x7f, 0x2e, 0xa4, 0xe3, 0xc8,
|
||||
0xef, 0xf6, 0xd6, 0x5b, 0xf7, 0xbf, 0xa2, 0x91, 0x3f, 0xc7, 0x3f, 0x2c, 0xe7, 0x67, 0xc7, 0x38,
|
||||
0xe6, 0x72, 0x18, 0x5f, 0xed, 0xfa, 0xd7, 0xf4, 0xb9, 0xee, 0x8f, 0x73, 0x5c, 0xeb, 0x2b, 0x9e,
|
||||
0xfe, 0xcd, 0xb8, 0x4f, 0xb9, 0x66, 0xd5, 0x5f, 0x3a, 0xc6, 0xd1, 0xab, 0x73, 0xf8, 0x87, 0x03,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_8[] ={
|
||||
0x3f, 0xff, 0xff, 0x5e, 0x38, 0xf6, 0xd6, 0x5b, 0xfe, 0x75, 0x79, 0xf5, 0x38, 0x2e, 0x73, 0xef,
|
||||
0xbd, 0xf7, 0x1e, 0x9f, 0xcd, 0xe1, 0xcf, 0xca, 0xb6, 0x59, 0x69, 0x56, 0x9a, 0xe5, 0x4a, 0x33,
|
||||
0x4d, 0x76, 0xe8, 0xde, 0xc5, 0x0b, 0x7f, 0x96, 0x7f, 0x3a, 0xd9, 0xa7, 0xfc, 0x4c, 0xae, 0x5e,
|
||||
0x3d, 0xae, 0x75, 0xe4, 0xdf, 0x49, 0xfb, 0xc7, 0xf8, 0x97, 0x95, 0xcb, 0xf7, 0x0e, 0xeb, 0xd4,
|
||||
0xcb, 0xc5, 0xef, 0x66, 0xfc, 0x3b, 0xfa, 0xe8, 0xc1, 0xaf, 0x8f, 0xc3, 0xc5, 0xaf, 0x6c, 0xff,
|
||||
0xdd, 0x8c, 0x71, 0xf4, 0x58, 0xc3, 0x0f, 0xcc, 0x3c, 0xe5, 0xea, 0x4e, 0xf4, 0x8f, 0x07,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_9[] ={
|
||||
0x3f, 0xff, 0xff, 0xb9, 0xcb, 0xad, 0xb7, 0xde, 0xc6, 0x65, 0xae, 0xa3, 0x57, 0x8f, 0x5d, 0xf4,
|
||||
0x8f, 0xeb, 0xb6, 0x6e, 0xeb, 0xb6, 0x4e, 0x97, 0xcb, 0x95, 0x74, 0xd5, 0x8e, 0xe1, 0xe8, 0x5f,
|
||||
0x05, 0xcd, 0xbf, 0x9e, 0x71, 0x38, 0xf4, 0x67, 0xf1, 0xf5, 0x1e, 0xfe, 0xcd, 0x2c, 0x7f, 0xfe,
|
||||
0xca, 0xe6, 0xea, 0x95, 0x7f, 0x37, 0x9e, 0x3e, 0xc1, 0x71, 0xcd, 0xc3, 0xc5, 0x5f, 0xf1, 0x6f,
|
||||
0xea, 0x2b, 0x1c, 0xbe, 0x3d, 0x0e, 0x17, 0xbf, 0xb3, 0xfc, 0x37, 0x14, 0x3a, 0x2f, 0xb3, 0x3f,
|
||||
0xb0, 0xe3, 0x96, 0xab, 0xdb, 0xea, 0x1f, 0x0f,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_10[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd9, 0xec, 0x61, 0xef, 0xbd, 0xf7, 0x21, 0x7f, 0xed, 0xde, 0x7a, 0x1b, 0x17,
|
||||
0xcd, 0xb6, 0x19, 0x6d, 0xb3, 0x5c, 0x2e, 0xa6, 0x7f, 0x10, 0xf9, 0x53, 0x73, 0xf5, 0xca, 0x67,
|
||||
0x73, 0xda, 0xe3, 0x6f, 0xf4, 0x8f, 0x26, 0xfe, 0x78, 0xbd, 0xe6, 0x36, 0x2e, 0xeb, 0x1f, 0xd3,
|
||||
0x67, 0xfd, 0x19, 0xae, 0x7f, 0x5f, 0x5c, 0x6e, 0xbc, 0x1a, 0xf3, 0xc8, 0x9d, 0xdb, 0xee, 0xe7,
|
||||
0xfe, 0x91, 0xad, 0xcb, 0xba, 0xf1, 0x53, 0xca, 0xea, 0xd1, 0xab, 0x39, 0xf8, 0x87, 0x03,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_11[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd9, 0xec, 0x61, 0xef, 0xbd, 0xe7, 0xc9, 0x7f, 0x3d, 0xe3, 0x32, 0xf7, 0x9e,
|
||||
0x97, 0x71, 0xcb, 0xd5, 0xab, 0x57, 0xbe, 0x3b, 0xc6, 0x3f, 0x04, 0x47, 0x56, 0x9a, 0x95, 0xe4,
|
||||
0x30, 0x6e, 0x1d, 0x4d, 0xfd, 0xd3, 0xac, 0xfc, 0x03, 0x5a, 0xfc, 0xe4, 0x38, 0xe6, 0xbc, 0xac,
|
||||
0xcb, 0x21, 0xff, 0x9c, 0x32, 0x7f, 0xed, 0x3f, 0xc6, 0x9d, 0x6f, 0x1c, 0xe6, 0xfa, 0xda, 0xc8,
|
||||
0x3f, 0xbd, 0xb2, 0x7a, 0xeb, 0xfa, 0x54, 0x5c, 0x3d, 0x7a, 0x35, 0x07, 0xff, 0x70,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_12[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd5, 0x1c, 0x87, 0xbd, 0xf7, 0x61, 0xdd, 0xf8, 0xe7, 0x94, 0xdb, 0xb8, 0xcc,
|
||||
0x79, 0x19, 0xb7, 0xde, 0xfa, 0x1b, 0x76, 0xfe, 0x59, 0xe4, 0xb2, 0x0e, 0x49, 0xda, 0x39, 0x2f,
|
||||
0x2b, 0x7f, 0x98, 0xcd, 0xbf, 0x9f, 0xd1, 0x9f, 0x3d, 0xe6, 0x3e, 0xac, 0xc3, 0x25, 0xff, 0x9c,
|
||||
0xb2, 0x7f, 0xec, 0xbf, 0xcf, 0xcf, 0xf1, 0xbd, 0x8c, 0x7f, 0x81, 0x6d, 0x5d, 0xbd, 0xf5, 0x70,
|
||||
0xe3, 0x52, 0x66, 0x8f, 0x5e, 0xcd, 0xc1, 0x3f, 0x1c,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_13[] ={
|
||||
0x3f, 0xff, 0xff, 0xb1, 0x5c, 0x87, 0xbd, 0xf7, 0x9e, 0xff, 0xb8, 0xbc, 0x8d, 0xcb, 0xdc, 0x87,
|
||||
0x75, 0xea, 0xad, 0x3f, 0x24, 0xfe, 0x33, 0xda, 0x3c, 0x0a, 0xf9, 0xf3, 0xfc, 0xa3, 0xf1, 0xd6,
|
||||
0xfe, 0xfe, 0xb9, 0x0e, 0x7b, 0xaf, 0x23, 0xff, 0x7e, 0x38, 0x1e, 0xf8, 0x9d, 0xcc, 0x7f, 0x94,
|
||||
0xbf, 0xf3, 0x1f, 0x61, 0x46, 0x3b, 0x58, 0xbd, 0x15, 0xe6, 0x69, 0xf7, 0x96, 0xab, 0xb3, 0xd1,
|
||||
0x3f, 0x1e,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_14[] ={
|
||||
0x3f, 0xbf, 0xff, 0x91, 0x9c, 0xf3, 0xb2, 0x2e, 0x73, 0xff, 0x53, 0xcb, 0x6d, 0x1c, 0x0e, 0xe3,
|
||||
0xd6, 0x5b, 0xae, 0x7c, 0x1c, 0x47, 0xff, 0x1d, 0xa5, 0x93, 0xbf, 0x97, 0xeb, 0x9f, 0xd0, 0xdf,
|
||||
0xe1, 0x34, 0xd7, 0x65, 0x8e, 0x7f, 0x4e, 0x4c, 0xf3, 0x93, 0xff, 0x1d, 0xc6, 0xef, 0xe6, 0x7b,
|
||||
0x2e, 0xf2, 0xcf, 0x8e, 0xae, 0xde, 0x7a, 0x2b, 0x8e, 0x87, 0x71, 0xf5, 0xe8, 0xd5, 0x1c, 0xfc,
|
||||
0xc3, 0x01,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_15[] ={
|
||||
0x3f, 0xbf, 0xff, 0xd9, 0xcb, 0x6d, 0xe7, 0xea, 0xd5, 0x6b, 0x4e, 0xff, 0xf4, 0x3c, 0xdc, 0xf8,
|
||||
0xf9, 0xb9, 0x1c, 0xfa, 0x0f, 0x29, 0xf9, 0x73, 0xac, 0xb5, 0x4f, 0x79, 0x72, 0xc9, 0x3f, 0x93,
|
||||
0x3f, 0xc3, 0xe6, 0xf3, 0x39, 0xad, 0xc3, 0xfc, 0xa3, 0x7b, 0x9a, 0xfd, 0x0e, 0xa7, 0xc3, 0xec,
|
||||
0x77, 0xff, 0xb9, 0x7d, 0xf7, 0x0b, 0x9f, 0xfd, 0xa7, 0x66, 0x56, 0x6f, 0xbd, 0x1d, 0xf8, 0x52,
|
||||
0x5d, 0x3d, 0x7a, 0x35, 0x61, 0xf8, 0x87, 0x03,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_16[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xf6, 0xdc, 0xc6, 0x65, 0x5d, 0xc6, 0x91, 0x7f, 0x9d, 0xe3, 0x32, 0xfb, 0x63,
|
||||
0xe6, 0x3e, 0x8c, 0x23, 0xff, 0xbe, 0x46, 0xfe, 0x0e, 0xde, 0x32, 0xbd, 0x8d, 0x79, 0xe4, 0x9f,
|
||||
0x4b, 0xfd, 0x2b, 0x7c, 0xcb, 0xe3, 0xb8, 0x84, 0xec, 0xd8, 0x95, 0xe6, 0x0f, 0xbe, 0xfd, 0x2b,
|
||||
0xfc, 0xfb, 0x5a, 0xfd, 0x8e, 0xa7, 0xdd, 0xe3, 0xea, 0x77, 0xff, 0x7d, 0x39, 0x3e, 0xf4, 0xe9,
|
||||
0xcf, 0xd9, 0x7f, 0x52, 0x8e, 0xba, 0x7a, 0x5a, 0xf3, 0xc8, 0xa7, 0xe3, 0xea, 0xd1, 0xab, 0x09,
|
||||
0xc3, 0x3f, 0x1c,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_17[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xd3, 0xc3, 0xb8, 0xf5, 0xd6, 0xd3, 0x1c, 0xff, 0x3c, 0xb9, 0xed, 0xf1, 0xeb,
|
||||
0xb8, 0xe6, 0x36, 0x0e, 0x7b, 0x9e, 0xfa, 0x8f, 0x68, 0xe5, 0x4f, 0x50, 0xaf, 0xb9, 0xf5, 0xb4,
|
||||
0x2e, 0x9a, 0x6d, 0xdd, 0xd6, 0x6d, 0xf9, 0x27, 0xb0, 0xfc, 0x0b, 0xb8, 0xfe, 0x69, 0x9d, 0xfc,
|
||||
0x3b, 0xac, 0xfe, 0x2b, 0xca, 0x3e, 0xf9, 0x8e, 0xdb, 0x5c, 0x47, 0xae, 0xab, 0x5f, 0x1e, 0xfc,
|
||||
0x3b, 0xfa, 0x4e, 0xc7, 0xaf, 0xf9, 0xe6, 0x3f, 0xa3, 0xc1, 0xf4, 0x38, 0x0e, 0xbf, 0x6d, 0x8c,
|
||||
0xa3, 0x57, 0xe7, 0xf0, 0x0f, 0x07,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_18[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xb8, 0xac, 0x5b, 0xae, 0x5e, 0x73, 0xda, 0xbd, 0xf2, 0xaf, 0x73, 0x8c, 0xdf,
|
||||
0xcb, 0x35, 0xb7, 0x9e, 0xd6, 0x61, 0xcf, 0x53, 0xae, 0x5e, 0xbd, 0xf2, 0x77, 0xef, 0xfa, 0x7b,
|
||||
0x7c, 0x85, 0xab, 0x57, 0xaf, 0x5e, 0xfd, 0xe7, 0xa0, 0x7f, 0x0b, 0x0e, 0xff, 0xb0, 0x4e, 0xfe,
|
||||
0x1d, 0xa6, 0xff, 0x8c, 0xbc, 0x9c, 0x78, 0xe7, 0x69, 0xce, 0x93, 0xe7, 0x8e, 0xef, 0xff, 0xfb,
|
||||
0x61, 0x7e, 0x67, 0xf4, 0xd7, 0x7c, 0xf8, 0x9f, 0x8e, 0xe3, 0xe8, 0x71, 0x8d, 0x9f, 0x97, 0x79,
|
||||
0xf4, 0xea, 0xae, 0x7f, 0x38,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_19[] ={
|
||||
0x3f, 0xbf, 0x7f, 0xa2, 0x32, 0xc6, 0xad, 0xb7, 0xde, 0xd6, 0xfa, 0xc7, 0xfb, 0x43, 0xb9, 0x7a,
|
||||
0xec, 0xad, 0xb7, 0x9e, 0xd6, 0x65, 0xaf, 0xcb, 0xba, 0x04, 0x2f, 0x86, 0x3f, 0xfa, 0xc8, 0x1f,
|
||||
0x65, 0xe7, 0x5f, 0xd9, 0xda, 0x7f, 0x93, 0xcc, 0x7f, 0x5a, 0x3b, 0x7f, 0x87, 0xe9, 0x3f, 0x23,
|
||||
0x6e, 0x07, 0x3f, 0x93, 0xcb, 0x61, 0x1c, 0x73, 0xf8, 0x01, 0xff, 0x7a, 0x32, 0xbe, 0x92, 0x79,
|
||||
0xe4, 0xfb, 0x93, 0xef, 0xfe, 0xcb, 0xa9, 0xd3, 0x63, 0x2f, 0xbf, 0x8e, 0x7d, 0xf3, 0xea, 0x21,
|
||||
0xfe, 0xe1, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_20[] ={
|
||||
0x3f, 0xbf, 0x7f, 0x15, 0xc8, 0xe1, 0xb0, 0x2e, 0xeb, 0x32, 0xc7, 0x3f, 0xdf, 0xdf, 0xe1, 0xad,
|
||||
0xb7, 0x9e, 0xd6, 0x65, 0x5d, 0xd6, 0x61, 0xef, 0xbd, 0x2f, 0xbd, 0xf5, 0x36, 0x2e, 0xc1, 0x83,
|
||||
0x7f, 0xe9, 0xe5, 0x5f, 0x05, 0xdd, 0xf5, 0xea, 0xd5, 0x7f, 0x3e, 0x5e, 0xf6, 0xfe, 0x8b, 0xcc,
|
||||
0xfc, 0xeb, 0x5a, 0xfd, 0x03, 0xb0, 0x26, 0xff, 0xaa, 0x66, 0xbe, 0xc3, 0x6d, 0xae, 0x63, 0x4e,
|
||||
0x9f, 0xff, 0x67, 0xf4, 0xc1, 0x43, 0x3f, 0x3f, 0xf9, 0xee, 0xbf, 0x1c, 0x3b, 0x3d, 0xf6, 0x74,
|
||||
0xf0, 0x07, 0xb9, 0x6f, 0x5e, 0x3d, 0xc4, 0x3f, 0x1c,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_21[] ={
|
||||
0x3f, 0xff, 0x7f, 0x1e, 0x8f, 0x3d, 0xfa, 0xcf, 0x97, 0xdb, 0xef, 0x98, 0x7b, 0xcf, 0xcb, 0x3a,
|
||||
0xf5, 0xd6, 0x5b, 0xae, 0xbe, 0xf6, 0xea, 0xb1, 0xa7, 0xfc, 0xa5, 0xeb, 0x9f, 0x84, 0x1d, 0xba,
|
||||
0xf7, 0x3e, 0x8c, 0x5b, 0x6f, 0xb9, 0x7a, 0xe5, 0xcf, 0x9f, 0xc3, 0xa9, 0x37, 0x7f, 0xf5, 0x38,
|
||||
0x5c, 0xf2, 0xcf, 0xed, 0x4f, 0x61, 0x96, 0xf0, 0x6f, 0xec, 0xfb, 0x63, 0x9e, 0x66, 0x3f, 0x55,
|
||||
0xfe, 0x79, 0x75, 0x7c, 0x26, 0x87, 0x1b, 0xdf, 0x69, 0xbe, 0xf5, 0x2f, 0x89, 0x34, 0x33, 0xb7,
|
||||
0xde, 0x56, 0x7f, 0xcd, 0xce, 0xd5, 0xab, 0xfe, 0xf1, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_22[] ={
|
||||
0x3f, 0xbf, 0xff, 0xdd, 0xc9, 0x3e, 0xf5, 0xd6, 0xdb, 0x38, 0x9c, 0xbc, 0x7a, 0xf5, 0xc7, 0xf7,
|
||||
0x34, 0xfe, 0xf6, 0xdb, 0xdf, 0xcf, 0x64, 0xb9, 0x5c, 0x8e, 0x15, 0x73, 0x50, 0x2f, 0xe3, 0xd6,
|
||||
0xa3, 0x7f, 0xfe, 0xae, 0x23, 0x7f, 0x84, 0x3d, 0xfe, 0xcd, 0xf5, 0xd6, 0xf5, 0xe3, 0x67, 0xe2,
|
||||
0xbf, 0xb9, 0xdf, 0xcd, 0x34, 0xff, 0xf4, 0xbe, 0xe7, 0xe1, 0x94, 0xe3, 0x97, 0x18, 0xff, 0xb6,
|
||||
0xd8, 0x75, 0xb1, 0x7a, 0xeb, 0xe1, 0xe4, 0xf7, 0x56, 0x8f, 0xde, 0xfe, 0xb4,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM BOY_23[] ={
|
||||
0x3f, 0xbf, 0xff, 0xdd, 0xc9, 0x3e, 0xf5, 0xd6, 0xdb, 0x38, 0x9c, 0xbc, 0x7a, 0xf5, 0xc7, 0xf7,
|
||||
0x34, 0xfe, 0xf6, 0xdb, 0xdf, 0xcf, 0x64, 0xb9, 0x5c, 0x8e, 0x15, 0x73, 0x50, 0x2f, 0xe3, 0xd6,
|
||||
0xa3, 0x7f, 0xfe, 0xae, 0x23, 0x7f, 0x84, 0x3d, 0xfe, 0xcd, 0xf5, 0xd6, 0x55, 0x7f, 0xf6, 0x6a,
|
||||
0xfc, 0x37, 0xf7, 0xbb, 0x99, 0xe6, 0x9f, 0xde, 0xf7, 0x3c, 0x9c, 0x72, 0xfc, 0x12, 0xe3, 0xdf,
|
||||
0x16, 0xbb, 0x2e, 0x56, 0x6f, 0x3d, 0x1d, 0xfc, 0xde, 0xea, 0xd1, 0xdb, 0x9f, 0x16,
|
||||
};
|
||||
|
||||
|
||||
const unsigned char *BOY[] = {
|
||||
BOY_0,
|
||||
BOY_1,
|
||||
BOY_2,
|
||||
BOY_3,
|
||||
BOY_4,
|
||||
BOY_5,
|
||||
BOY_6,
|
||||
BOY_7,
|
||||
BOY_8,
|
||||
BOY_9,
|
||||
BOY_10,
|
||||
BOY_11,
|
||||
BOY_12,
|
||||
BOY_13,
|
||||
BOY_14,
|
||||
BOY_15,
|
||||
BOY_16,
|
||||
BOY_17,
|
||||
BOY_18,
|
||||
BOY_19,
|
||||
BOY_20,
|
||||
BOY_21,
|
||||
BOY_22,
|
||||
BOY_23,
|
||||
};
|
||||
|
||||
// File: d:\arduboy\boy.gif (24 frames)
|
||||
// Size: 24x64x64px (12288 bytes)
|
||||
// Encoded: 1978 bytes
|
||||
// Ratio: 0.16097005
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 477 B |
|
@ -0,0 +1,37 @@
|
|||
######################################
|
||||
# Syntax Coloring Map For ArdBitmap
|
||||
######################################
|
||||
|
||||
######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
######################################
|
||||
|
||||
ArdBitmap KEYWORD1
|
||||
|
||||
######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
######################################
|
||||
|
||||
drawBitmap KEYWORD2
|
||||
drawBitmapResized KEYWORD2
|
||||
drawCompressed KEYWORD2
|
||||
drawCompressedResized KEYWORD2
|
||||
|
||||
######################################
|
||||
# Constants (LITERAL1)
|
||||
######################################
|
||||
|
||||
ALIGN_H_LEFT LITERAL1
|
||||
ALIGN_H_RIGHT LITERAL1
|
||||
ALIGN_H_CENTER LITERAL1
|
||||
ALIGN_V_TOP LITERAL1
|
||||
ALIGN_V_BOTTOM LITERAL1
|
||||
ALIGN_V_CENTER LITERAL1
|
||||
ALIGN_CENTER LITERAL1
|
||||
ALIGN_NONE LITERAL1
|
||||
|
||||
MIRROR_NONE LITERAL1
|
||||
MIRROR_HORIZONTAL LITERAL1
|
||||
MIRROR_VERTICAL LITERAL1
|
||||
MIRROR_HOR_VER LITERAL1
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
name=ArdBitmap
|
||||
version=2.0.3
|
||||
author=Ignacio Vina
|
||||
maintainer=Ignacio Vina <moblynx.us@gmail.com>
|
||||
sentence=A library to compress and draw bitmaps on the Arduboy game system.
|
||||
paragraph=It supports real-time resizing and mirroring. This library is implemented as a class template.
|
||||
category=Other
|
||||
url=https://github.com/igvina/ArdBitmap
|
||||
architectures=*
|
|
@ -0,0 +1,806 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// ArdBitmap: version 2.0.3
|
||||
|
||||
#ifndef ARDBITMAP_H
|
||||
#define ARDBITMAP_H
|
||||
|
||||
//Uncomment NO_SPEED_HACK if speed is not important (reduce ~100 bytes)
|
||||
//#define NO_SPEED_HACK
|
||||
|
||||
//Uncomment RESIZE_HACK for fast drawResized with resize >= 1.0
|
||||
//#define RESIZE_HACK
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define ALIGN_H_LEFT 0b00000000
|
||||
#define ALIGN_H_RIGHT 0b00000001
|
||||
#define ALIGN_H_CENTER 0b00000010
|
||||
#define ALIGN_V_TOP 0b00000000
|
||||
#define ALIGN_V_BOTTOM 0b00000100
|
||||
#define ALIGN_V_CENTER 0b00001000
|
||||
#define ALIGN_CENTER 0b00001010
|
||||
#define ALIGN_NONE 0b00000000
|
||||
|
||||
#define MIRROR_NONE 0b00000000
|
||||
#define MIRROR_HORIZONTAL 0b00000001
|
||||
#define MIRROR_VERTICAL 0b00000010
|
||||
#define MIRROR_HOR_VER 0b00000011
|
||||
|
||||
static const uint8_t BIT_SHIFT[8] = {
|
||||
0b00000001,
|
||||
0b00000010,
|
||||
0b00000100,
|
||||
0b00001000,
|
||||
0b00010000,
|
||||
0b00100000,
|
||||
0b01000000,
|
||||
0b10000000,
|
||||
};
|
||||
|
||||
/*
|
||||
static const uint8_t REVERSE_16[16] = { 0, 8, 4, 12,
|
||||
2, 10, 6, 14 ,
|
||||
1, 9, 5, 13,
|
||||
3, 11, 7, 15 };
|
||||
|
||||
static const uint8_t REVERSE_256[256] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
|
||||
};
|
||||
*/
|
||||
|
||||
template<int16_t SB_WIDTH, int16_t SB_HEIGHT> class ArdBitmap
|
||||
{
|
||||
public:
|
||||
|
||||
void drawCompressed(int16_t sx, int16_t sy, const uint8_t *compBitmap, uint8_t color, uint8_t align, uint8_t mirror);
|
||||
void drawCompressedResized(int16_t sx, int16_t sy, const uint8_t *compBitmap, uint8_t color,uint8_t align, uint8_t mirror, float resize);
|
||||
|
||||
void drawBitmap(int16_t sx, int16_t sy, const uint8_t *bitmap,uint8_t w, uint8_t h, uint8_t color, uint8_t align, uint8_t mirror);
|
||||
void drawBitmapResized(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t w,uint8_t h, uint8_t color,uint8_t align, uint8_t mirror, float resize);
|
||||
};
|
||||
|
||||
////////////////////////
|
||||
// COMPRESSED BITMAPS //
|
||||
////////////////////////
|
||||
|
||||
template<int16_t SB_WIDTH, int16_t SB_HEIGHT>
|
||||
void ArdBitmap<SB_WIDTH, SB_HEIGHT>::drawCompressed(int16_t sx, int16_t sy, const uint8_t *compBitmap, uint8_t color, uint8_t align, uint8_t mirror)
|
||||
{
|
||||
//TODO: check why int16_t sizeCounter is a bit faster than uint16_t sizeCounter
|
||||
int16_t sizeCounter;
|
||||
uint16_t len;
|
||||
int a, iCol;
|
||||
uint8_t decByte;
|
||||
uint8_t w, h;
|
||||
uint8_t col;
|
||||
boolean scanMode, scanZigZag;
|
||||
uint16_t encoderPos;
|
||||
uint8_t characterPos;
|
||||
|
||||
|
||||
// Read size from header (Max image size = 128 x 64)
|
||||
|
||||
uint8_t byte0 = pgm_read_byte(&compBitmap[0]);
|
||||
uint8_t byte1 = pgm_read_byte(&compBitmap[1]);
|
||||
|
||||
w = (byte0 & 0b01111111) + 1;
|
||||
h = (byte1 & 0b00111111) + 1;
|
||||
|
||||
// Move positions to match alignment
|
||||
|
||||
if (align & ALIGN_H_CENTER) {
|
||||
sx -= (w / 2);
|
||||
} else if (align & ALIGN_H_RIGHT) {
|
||||
sx -= w;
|
||||
}
|
||||
|
||||
if (align & ALIGN_V_CENTER) {
|
||||
sy -= (h / 2);
|
||||
} else if (align & ALIGN_V_BOTTOM) {
|
||||
sy -= h;
|
||||
}
|
||||
|
||||
// No need to draw at all if we're offscreen
|
||||
if (sx + w < 0 || sx > SB_WIDTH - 1 || sy + h < 0 || sy > SB_HEIGHT - 1)
|
||||
return;
|
||||
|
||||
col = (byte0 >> 7) & 0x01;
|
||||
scanMode = ((byte1 >> 6) & 0x01) > 0;
|
||||
scanZigZag = ((byte1 >> 7) & 0x01) > 0;
|
||||
|
||||
int yOffset = abs(sy) % 8;
|
||||
int sRow = sy / 8;
|
||||
if (sy < 0 && yOffset > 0) {
|
||||
sRow--;
|
||||
yOffset = 8 - yOffset;
|
||||
}
|
||||
|
||||
uint8_t data;
|
||||
uint16_t bitmap_data;
|
||||
uint8_t mul_amt = 1 << yOffset;
|
||||
|
||||
//uint16_t boffs;
|
||||
|
||||
int8_t rows = h / 8;
|
||||
if (h % 8 != 0) rows++;
|
||||
|
||||
// Init values
|
||||
iCol = 0;
|
||||
decByte = 0;
|
||||
encoderPos = 16;
|
||||
characterPos = 7;
|
||||
a = 0;
|
||||
|
||||
if (mirror & MIRROR_VERTICAL) {
|
||||
a = rows - 1;
|
||||
scanMode = !scanMode;
|
||||
}
|
||||
|
||||
int iColMod = (mirror & MIRROR_HORIZONTAL) ? w - 1 : 0;
|
||||
while (a < rows && a > -1) {
|
||||
|
||||
sizeCounter = 1;
|
||||
while (((pgm_read_byte(&compBitmap[encoderPos / 8]) >> (encoderPos % 8)) & 0x01) == 1) {
|
||||
sizeCounter ++;
|
||||
encoderPos++;
|
||||
}
|
||||
encoderPos ++;
|
||||
|
||||
if (sizeCounter == 1) {
|
||||
len = 1 + ((pgm_read_byte(&compBitmap[encoderPos / 8]) >> (encoderPos % 8)) & 0x01);
|
||||
encoderPos++;
|
||||
} else {
|
||||
len = (1 << (sizeCounter - 1)) + 1 ;
|
||||
|
||||
//TODO: check why int j is faster than uint16_t j
|
||||
for (int j = 0; j < sizeCounter - 1; j++) {
|
||||
if (((pgm_read_byte(&compBitmap[encoderPos / 8]) >> (encoderPos % 8)) & 0x01) == 1) {
|
||||
len += (1 << j);
|
||||
}
|
||||
encoderPos++;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
|
||||
#ifndef NO_SPEED_HACK
|
||||
if (col == 0) {
|
||||
if (len - i > characterPos) {
|
||||
i += characterPos;
|
||||
characterPos = 0;
|
||||
} else {
|
||||
characterPos -= (len - i - 1);
|
||||
i = len;
|
||||
}
|
||||
} else if (len - i > characterPos) {
|
||||
if (characterPos == 7) {
|
||||
decByte = 0xFF;
|
||||
} else {
|
||||
decByte |= scanMode ? 0xFF >> (7 - characterPos) : (0xFF80 >> characterPos);
|
||||
}
|
||||
i += characterPos;
|
||||
characterPos = 0;
|
||||
} else {
|
||||
decByte |= scanMode ? BIT_SHIFT[characterPos] : BIT_SHIFT[7 - characterPos];
|
||||
}
|
||||
#else
|
||||
if (col) {
|
||||
decByte |= scanMode ? BIT_SHIFT[characterPos] : BIT_SHIFT[7 - characterPos];
|
||||
}
|
||||
#endif
|
||||
|
||||
characterPos--;
|
||||
|
||||
if (characterPos == 0xFF){
|
||||
|
||||
//Paint decoded byte
|
||||
int8_t bRow = sRow + a;
|
||||
|
||||
if (decByte && bRow < (SB_HEIGHT / 8) && iColMod + sx < SB_WIDTH && iColMod + sx >= 0){
|
||||
|
||||
bitmap_data = decByte * mul_amt;
|
||||
|
||||
if (bRow >= 0) {
|
||||
|
||||
data = ARDBITMAP_SBUF[(bRow * SB_WIDTH) + sx + iColMod];
|
||||
if (color) {
|
||||
data |= bitmap_data & 0xFF;
|
||||
}else {
|
||||
data &= ~(bitmap_data & 0xFF);
|
||||
}
|
||||
ARDBITMAP_SBUF[(bRow * SB_WIDTH) + sx + iColMod] = data;
|
||||
}
|
||||
|
||||
if (yOffset && bRow < (SB_HEIGHT / 8) - 1 && bRow > -2) {
|
||||
|
||||
data = ARDBITMAP_SBUF[((bRow + 1) * SB_WIDTH) + sx + iColMod];
|
||||
if (color) {
|
||||
data |= ((bitmap_data >> 8) & 0xFF);
|
||||
} else {
|
||||
data &= ~(((bitmap_data >> 8) & 0xFF));
|
||||
}
|
||||
ARDBITMAP_SBUF[((bRow + 1)*SB_WIDTH) + sx + iColMod] = data;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate next column-byte
|
||||
|
||||
if (scanZigZag) {
|
||||
scanMode = !scanMode;
|
||||
}
|
||||
|
||||
iCol++;
|
||||
|
||||
if(mirror & MIRROR_HORIZONTAL){
|
||||
iColMod--;
|
||||
}else{
|
||||
iColMod++;
|
||||
}
|
||||
if (iCol >= w){
|
||||
|
||||
iCol = 0;
|
||||
if (mirror & MIRROR_VERTICAL) {
|
||||
a--;
|
||||
} else {
|
||||
a++;
|
||||
}
|
||||
|
||||
iColMod = (mirror & MIRROR_HORIZONTAL) ? w - 1 : 0;
|
||||
}
|
||||
|
||||
// Reset decoded byte
|
||||
decByte = 0;
|
||||
characterPos = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle color for next span
|
||||
col = 1 - col;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<int16_t SB_WIDTH, int16_t SB_HEIGHT>
|
||||
void ArdBitmap<SB_WIDTH, SB_HEIGHT>::drawCompressedResized(int16_t sx, int16_t sy, const uint8_t *compBitmap, uint8_t color,uint8_t align, uint8_t mirror, float resize)
|
||||
{
|
||||
|
||||
//TODO: check if this can be done in a better way
|
||||
#ifdef RESIZE_HACK
|
||||
if (resize >= 1.0){
|
||||
return drawCompressed(sx, sy, compBitmap, color, align, mirror);
|
||||
}
|
||||
#else
|
||||
if (resize > 1.0){
|
||||
resize = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//TODO: check why int16_t sizeCounter is a bit faster than uint16_t sizeCounter
|
||||
int16_t sizeCounter;
|
||||
uint16_t len;
|
||||
uint8_t a, iCol;
|
||||
uint8_t decByte;
|
||||
uint8_t w, wRes, h, hRes;
|
||||
uint8_t col;
|
||||
boolean scanMode, scanZigZag;
|
||||
uint16_t encoderPos;
|
||||
uint8_t characterPos;
|
||||
|
||||
// Read size from header (Max image size = 128 x 64)
|
||||
|
||||
uint8_t byte0 = pgm_read_byte(&compBitmap[0]);
|
||||
uint8_t byte1 = pgm_read_byte(&compBitmap[1]);
|
||||
|
||||
w = (byte0 & 0b01111111) + 1;
|
||||
h = (byte1 & 0b00111111) + 1;
|
||||
|
||||
wRes = (uint8_t)(w * resize);
|
||||
hRes = (uint8_t)(h * resize);
|
||||
|
||||
if (align & ALIGN_H_CENTER) {
|
||||
sx -= (wRes / 2);
|
||||
} else if (align & ALIGN_H_RIGHT) {
|
||||
sx -= wRes;
|
||||
}
|
||||
|
||||
if (align & ALIGN_V_CENTER) {
|
||||
sy -= (hRes / 2);
|
||||
} else if (align & ALIGN_V_BOTTOM) {
|
||||
sy -= hRes;
|
||||
}
|
||||
|
||||
// No need to draw at all if we're offscreen
|
||||
if (sx + wRes < 0 || sx > SB_WIDTH - 1 || sy + hRes < 0 || sy > SB_HEIGHT - 1)
|
||||
return;
|
||||
|
||||
col = (byte0 >> 7) & 0x01;
|
||||
scanMode = ((byte1 >> 6) & 0x01) > 0;
|
||||
scanZigZag = ((byte1 >> 7) & 0x01) > 0;
|
||||
|
||||
int yOffset = abs(sy) % 8;
|
||||
int sRow = sy / 8;
|
||||
if (sy < 0) {
|
||||
sRow--;
|
||||
yOffset = 8 - yOffset;
|
||||
}
|
||||
|
||||
uint8_t data;
|
||||
uint16_t bitmap_data;
|
||||
uint8_t mul_amt = 1 << yOffset;
|
||||
|
||||
int rows = h / 8;
|
||||
if (h % 8 != 0) rows++;
|
||||
|
||||
uint8_t rowsRes = hRes / 8;
|
||||
if (hRes % 8 != 0) rowsRes++;
|
||||
|
||||
// Init values
|
||||
iCol = 0;
|
||||
decByte = 0;
|
||||
encoderPos = 16;
|
||||
characterPos = 7;
|
||||
a = 0;
|
||||
|
||||
// Create Lookup tables to speed up drawing
|
||||
|
||||
uint8_t x_LUT[w];
|
||||
|
||||
for (uint8_t i=0 ; i < w; i++){
|
||||
x_LUT[i] = 0xFF;
|
||||
}
|
||||
// Precalculate column translation (0xFF if skipped)
|
||||
for (uint8_t i=0 ; i < wRes; i++){
|
||||
x_LUT[((uint16_t)i * w) / wRes] = (mirror & MIRROR_HORIZONTAL) ? wRes - 1 - i : i;
|
||||
}
|
||||
|
||||
uint8_t y_LUT[h];
|
||||
|
||||
for (uint8_t i=0 ; i < h; i++){
|
||||
y_LUT[i] = 0xFF;
|
||||
}
|
||||
|
||||
for (uint8_t i=0 ; i < hRes; i++){
|
||||
y_LUT[((uint16_t)i * h) / hRes] = (mirror & MIRROR_VERTICAL) ? hRes - 1 - i : i;
|
||||
}
|
||||
|
||||
while (a < rows && /*a > -1*/ a != 0xFF) {
|
||||
|
||||
sizeCounter = 1;
|
||||
while (((pgm_read_byte(&compBitmap[encoderPos / 8]) >> (encoderPos % 8)) & 0x01) == 1) {
|
||||
sizeCounter ++;
|
||||
encoderPos++;
|
||||
}
|
||||
encoderPos ++;
|
||||
|
||||
if (sizeCounter == 1) {
|
||||
len = 1 + ((pgm_read_byte(&compBitmap[encoderPos / 8]) >> (encoderPos % 8)) & 0x01);
|
||||
encoderPos++;
|
||||
} else {
|
||||
len = (1 << (sizeCounter - 1)) + 1 ;
|
||||
|
||||
//TODO: check why int j is faster than uint16_t j
|
||||
for (int j = 0; j < sizeCounter - 1; j++) {
|
||||
if (((pgm_read_byte(&compBitmap[encoderPos / 8]) >> (encoderPos % 8)) & 0x01) == 1) {
|
||||
len += (1 << j);
|
||||
}
|
||||
encoderPos++;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < len; i++)
|
||||
{
|
||||
|
||||
#ifndef NO_SPEED_HACK
|
||||
if (col == 0) {
|
||||
if (len - i > characterPos) {
|
||||
i += characterPos;
|
||||
characterPos = 0;
|
||||
} else {
|
||||
characterPos -= (len - i - 1);
|
||||
i = len;
|
||||
}
|
||||
} else if (len - i > characterPos) {
|
||||
if (characterPos == 7) {
|
||||
decByte = 0xFF;
|
||||
} else {
|
||||
decByte |= scanMode ? 0xFF >> (7 - characterPos) : (0xFF80 >> characterPos);
|
||||
}
|
||||
i += characterPos;
|
||||
characterPos = 0;
|
||||
} else {
|
||||
decByte |= scanMode ? BIT_SHIFT[characterPos] : BIT_SHIFT[7 - characterPos];
|
||||
}
|
||||
#else
|
||||
if (col) {
|
||||
decByte |= scanMode ? BIT_SHIFT[characterPos] : BIT_SHIFT[7 - characterPos];
|
||||
}
|
||||
#endif
|
||||
|
||||
characterPos--;
|
||||
|
||||
if (characterPos == 0xFF){
|
||||
|
||||
//Paint decoded byte
|
||||
int aRow8 = a * 8;
|
||||
int16_t iColMod = x_LUT[iCol] + sx;
|
||||
|
||||
// Skip if column not needed
|
||||
if (x_LUT[iCol] != 0xFF && iColMod < SB_WIDTH && iColMod >= 0){
|
||||
|
||||
for (uint8_t s = 0; s < 8 ;s++){
|
||||
|
||||
if (y_LUT[aRow8+s] != 0xFF && decByte & BIT_SHIFT[s]){
|
||||
|
||||
//TODO: CHECK LIMITS ON LUT?
|
||||
uint8_t row = (uint8_t)(y_LUT[aRow8+s]+sy) / 8;
|
||||
|
||||
if (row < (SB_HEIGHT / 8)) {
|
||||
|
||||
if (color) {
|
||||
ARDBITMAP_SBUF[(row*SB_WIDTH) + (uint8_t)iColMod] |= BIT_SHIFT[((uint8_t)(y_LUT[aRow8+s]+sy) % 8)];
|
||||
} else {
|
||||
ARDBITMAP_SBUF[(row*SB_WIDTH) + (uint8_t)iColMod] &= ~ BIT_SHIFT[((uint8_t)(y_LUT[aRow8+s]+sy) % 8)];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate next column-byte
|
||||
|
||||
if (scanZigZag) {
|
||||
scanMode = !scanMode;
|
||||
}
|
||||
|
||||
iCol++;
|
||||
if (iCol >= w){
|
||||
|
||||
iCol = 0;
|
||||
a++;
|
||||
}
|
||||
|
||||
// Reset decoded byte
|
||||
decByte = 0;
|
||||
characterPos = 7;
|
||||
}
|
||||
}
|
||||
|
||||
col = 1 - col; // toggle colour for next span
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// UNCOMPRESSED BITMAPS //
|
||||
//////////////////////////
|
||||
|
||||
|
||||
template<int16_t SB_WIDTH, int16_t SB_HEIGHT>
|
||||
void ArdBitmap<SB_WIDTH, SB_HEIGHT>::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color, uint8_t align, uint8_t mirror)
|
||||
{
|
||||
|
||||
// Move positions to match alignment
|
||||
|
||||
if (align & ALIGN_H_CENTER) {
|
||||
x -= (w / 2);
|
||||
} else if (align & ALIGN_H_RIGHT) {
|
||||
x -= w;
|
||||
}
|
||||
|
||||
if (align & ALIGN_V_CENTER) {
|
||||
y -= (h / 2);
|
||||
} else if (align & ALIGN_V_BOTTOM) {
|
||||
y -= h;
|
||||
}
|
||||
|
||||
// no need to draw at all of we're offscreen
|
||||
if (x + w <= 0 || x > SB_WIDTH - 1 || y + h <= 0 || y > SB_HEIGHT - 1)
|
||||
return;
|
||||
|
||||
if (bitmap == NULL)
|
||||
return;
|
||||
|
||||
// xOffset technically doesn't need to be 16 bit but the math operations
|
||||
// are measurably faster if it is
|
||||
uint16_t xOffset, ofs;
|
||||
int8_t yOffset = abs(y) % 8;
|
||||
int8_t sRow = y / 8;
|
||||
uint8_t loop_h, start_h, rendered_width;
|
||||
|
||||
if (y < 0 && yOffset > 0) {
|
||||
sRow--;
|
||||
yOffset = 8 - yOffset;
|
||||
}
|
||||
|
||||
// if the left side of the render is offscreen skip those loops
|
||||
if (x < 0) {
|
||||
xOffset = abs(x);
|
||||
} else {
|
||||
xOffset = 0;
|
||||
}
|
||||
|
||||
// if the right side of the render is offscreen skip those loops
|
||||
if (x + w > SB_WIDTH - 1) {
|
||||
rendered_width = ((SB_WIDTH - x) - xOffset);
|
||||
} else {
|
||||
rendered_width = (w - xOffset);
|
||||
}
|
||||
|
||||
// if the top side of the render is offscreen skip those loops
|
||||
if (sRow < -1) {
|
||||
start_h = abs(sRow) - 1;
|
||||
} else {
|
||||
start_h = 0;
|
||||
}
|
||||
|
||||
loop_h = h / 8 + (h % 8 > 0 ? 1 : 0); // divide, then round up
|
||||
|
||||
// if (sRow + loop_h - 1 > (SB_HEIGHT/8)-1)
|
||||
if (sRow + loop_h > (SB_HEIGHT / 8)) {
|
||||
loop_h = (SB_HEIGHT / 8) - sRow;
|
||||
}
|
||||
|
||||
// prepare variables for loops later so we can compare with 0
|
||||
// instead of comparing two variables
|
||||
loop_h -= start_h;
|
||||
|
||||
sRow += start_h;
|
||||
ofs = (sRow * SB_WIDTH) + x + xOffset;
|
||||
|
||||
uint8_t *bofs = (uint8_t *)bitmap + (start_h * w) + xOffset;
|
||||
|
||||
if (mirror & MIRROR_HORIZONTAL) {
|
||||
bofs += rendered_width - 1;
|
||||
if (x < 0){
|
||||
bofs -= w - rendered_width;
|
||||
} else{
|
||||
bofs += w - rendered_width;
|
||||
}
|
||||
}
|
||||
|
||||
if (mirror & MIRROR_VERTICAL) {
|
||||
bofs += (loop_h - 1) * w;
|
||||
if (y < 0){
|
||||
bofs -= (start_h * w);
|
||||
} else {
|
||||
bofs += (sRow * w);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t data;
|
||||
uint8_t mul_amt = 1 << yOffset;
|
||||
uint16_t bitmap_data;
|
||||
|
||||
// really if yOffset = 0 you have a faster case here that could be
|
||||
// optimized
|
||||
for (uint8_t a = 0; a < loop_h; a++) {
|
||||
for (uint8_t iCol = 0; iCol < rendered_width; iCol++) {
|
||||
data = pgm_read_byte(bofs);
|
||||
if(data) {
|
||||
if (mirror & MIRROR_VERTICAL){
|
||||
//reverse bits
|
||||
data = (data & 0xF0) >> 4 | (data & 0x0F) << 4;
|
||||
data = (data & 0xCC) >> 2 | (data & 0x33) << 2;
|
||||
data = (data & 0xAA) >> 1 | (data & 0x55) << 1;
|
||||
|
||||
//LUT - No speed improvement and more mem
|
||||
//data = (((REVERSE_16[(data & 0x0F)]) << 4) + REVERSE_16[((data & 0xF0) >> 4)]);
|
||||
|
||||
//Fast but too much mem
|
||||
//data = REVERSE_256[data];
|
||||
}
|
||||
|
||||
bitmap_data = data * mul_amt;
|
||||
if (sRow >= 0) {
|
||||
data = ARDBITMAP_SBUF[ofs];
|
||||
if (color){
|
||||
data |= bitmap_data & 0xFF;
|
||||
} else {
|
||||
data &= ~(bitmap_data & 0xFF);
|
||||
}
|
||||
ARDBITMAP_SBUF[ofs] = data;
|
||||
}
|
||||
|
||||
if (yOffset != 0 && sRow < 7) {
|
||||
data = ARDBITMAP_SBUF[ofs + SB_WIDTH];
|
||||
if (color){
|
||||
data |= (bitmap_data >> 8) & 0xFF;
|
||||
} else{
|
||||
data &= ~((bitmap_data >> 8) & 0xFF);
|
||||
}
|
||||
ARDBITMAP_SBUF[ofs + SB_WIDTH] = data;
|
||||
}
|
||||
}
|
||||
ofs++;
|
||||
|
||||
if (mirror & MIRROR_HORIZONTAL){
|
||||
bofs--;
|
||||
} else{
|
||||
bofs++;
|
||||
}
|
||||
}
|
||||
sRow++;
|
||||
|
||||
if (mirror & MIRROR_HORIZONTAL){
|
||||
bofs += w + rendered_width;
|
||||
} else{
|
||||
bofs += w - rendered_width;
|
||||
}
|
||||
|
||||
if (mirror & MIRROR_VERTICAL){
|
||||
bofs -= 2 * w;
|
||||
}
|
||||
ofs += SB_WIDTH - rendered_width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<int16_t SB_WIDTH, int16_t SB_HEIGHT>
|
||||
void ArdBitmap<SB_WIDTH, SB_HEIGHT>::drawBitmapResized(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t w,uint8_t h, uint8_t color,uint8_t align, uint8_t mirror, float resize)
|
||||
{
|
||||
|
||||
//TODO: check if this can be done in a better way
|
||||
#ifdef RESIZE_HACK
|
||||
if (resize >= 1.0){
|
||||
return drawBitmap(sx, sy, bitmap,w, h, color, align, mirror);
|
||||
}
|
||||
#else
|
||||
if (resize > 1.0){
|
||||
resize = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
//TODO: check why int16_t sizeCounter is a bit faster than uint16_t sizeCounter
|
||||
int16_t sizeCounter;
|
||||
uint16_t len;
|
||||
uint8_t a, iCol;
|
||||
uint8_t data;
|
||||
uint8_t wRes, hRes;
|
||||
uint8_t col;
|
||||
|
||||
wRes = (uint8_t)(w * resize);
|
||||
hRes = (uint8_t)(h * resize);
|
||||
|
||||
|
||||
// Move positions to match alignment
|
||||
if (align & ALIGN_H_CENTER) {
|
||||
sx -= (wRes / 2);
|
||||
} else if (align & ALIGN_H_RIGHT) {
|
||||
sx -= wRes;
|
||||
}
|
||||
|
||||
if (align & ALIGN_V_CENTER) {
|
||||
sy -= (hRes / 2);
|
||||
} else if (align & ALIGN_V_BOTTOM) {
|
||||
sy -= hRes;
|
||||
}
|
||||
|
||||
// No need to draw at all if we're offscreen
|
||||
if (sx + wRes < 0 || sx > SB_WIDTH - 1 || sy + hRes < 0 || sy > SB_HEIGHT - 1)
|
||||
return;
|
||||
|
||||
int yOffset = abs(sy) % 8;
|
||||
int sRow = sy / 8;
|
||||
if (sy < 0) {
|
||||
sRow--;
|
||||
yOffset = 8 - yOffset;
|
||||
}
|
||||
|
||||
int rows = h / 8;
|
||||
if (h % 8 != 0) rows++;
|
||||
|
||||
uint8_t rowsRes = hRes / 8;
|
||||
if (hRes % 8 != 0) rowsRes++;
|
||||
|
||||
// Init values
|
||||
iCol = 0;
|
||||
a = 0;
|
||||
|
||||
// Create Lookup tables to speed up drawing
|
||||
|
||||
uint8_t x_LUT[w];
|
||||
|
||||
for (uint8_t i=0 ; i < w; i++){
|
||||
x_LUT[i] = 0xFF;
|
||||
}
|
||||
// Precalculate column translation (0xFF if skipped)
|
||||
for (uint8_t i=0 ; i < wRes; i++){
|
||||
x_LUT[((uint16_t)i * w) / wRes] = (mirror & MIRROR_HORIZONTAL) ? wRes - 1 - i : i;
|
||||
}
|
||||
|
||||
uint8_t y_LUT[h];
|
||||
|
||||
for (uint8_t i=0 ; i < h; i++){
|
||||
y_LUT[i] = 0xFF;
|
||||
}
|
||||
|
||||
for (uint8_t i=0 ; i < hRes; i++){
|
||||
y_LUT[((uint16_t)i * h) / hRes] = (mirror & MIRROR_VERTICAL) ? hRes - 1 - i : i;
|
||||
}
|
||||
|
||||
len = w * rows;
|
||||
|
||||
for (uint16_t i = 0; i < len ; i++){
|
||||
|
||||
data = pgm_read_byte(&bitmap[i]);
|
||||
int aRow8 = a * 8;
|
||||
int16_t iColMod = x_LUT[iCol] + sx;
|
||||
|
||||
// Skip if column not needed
|
||||
if (x_LUT[iCol] != 0xFF && iColMod < SB_WIDTH && iColMod >= 0){
|
||||
for (uint8_t s = 0; s < 8 ;s++){
|
||||
if (y_LUT[aRow8+s] != 0xFF && data & BIT_SHIFT[s]){
|
||||
//TODO: CHECK LIMITS ON LUT?
|
||||
uint8_t row = (uint8_t)(y_LUT[aRow8+s]+sy) / 8;
|
||||
|
||||
if (row < (SB_HEIGHT / 8)) {
|
||||
if (color) {
|
||||
ARDBITMAP_SBUF[(row*SB_WIDTH) + (uint8_t)iColMod] |= BIT_SHIFT[((uint8_t)(y_LUT[aRow8+s]+sy) % 8)];
|
||||
} else {
|
||||
ARDBITMAP_SBUF[(row*SB_WIDTH) + (uint8_t)iColMod] &= ~ BIT_SHIFT[((uint8_t)(y_LUT[aRow8+s]+sy) % 8)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iCol++;
|
||||
if (iCol >= w){
|
||||
iCol = 0;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# Individual Contributors
|
||||
|
||||
- Kevin "Arduboy" Bates (@Arduboy)
|
||||
- arduboychris (@arduboychris)
|
||||
- Josh Goebel (@yyyc514)
|
||||
- Scott Allen (@MLXXXp)
|
||||
- Ross Shoger (@rogosher)
|
||||
- Andrew (@ace-dent)
|
||||
|
||||
|
||||
# Included code from other open source projects
|
||||
|
||||
- Original SSD1306 library
|
||||
https://github.com/adafruit/Adafruit_SSD1306
|
||||
BSD License
|
||||
Copyright (c) 2012, Adafruit Industries
|
||||
|
||||
- arduino-playtune
|
||||
https://github.com/LenShustek/arduino-playtune
|
||||
GNU General Public License v3
|
||||
(C) Copyright 2011, 2015, Len Shustek
|
|
@ -0,0 +1,32 @@
|
|||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2015, Kevin "Arduboy" Bates
|
||||
Copyright (c) 2015, Chris Martinez
|
||||
Copyright (c) 2015, Josh Goebel
|
||||
All rights reserved.
|
||||
|
||||
Please see CONTRIBUTORS.md for license information and copyright
|
||||
notices for any libraries we built on or redistribute.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. 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.
|
||||
3. Neither the name of the copyright holders 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 ''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 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.
|
|
@ -0,0 +1,143 @@
|
|||
Arduboy Library · `1.1.1`
|
||||
===============
|
||||
|
||||
Welcome to Arduboy! This is release `1.1.1` of the Arduboy Library.
|
||||
|
||||
## About
|
||||
|
||||
Arduboy is an open-source hardware platform allowing gamers to easily make and share games using C/C++. The **Arduboy Library** is an open-source library that provides a programming interface for making games and applications that run on an Arduboy. The Arduboy Library supports both the **production** and **development** Arduboy units.
|
||||
|
||||
### Contributing to the Arduboy Library
|
||||
|
||||
The Github url for this project is https://github.com/Arduboy/Arduboy.
|
||||
|
||||
Using `git` and Github, anyone can contribute to the Arduboy library. The source found using the Arduino _Library Manager_ can be found on the [`stable`](https://github.com/Arduboy/Arduboy/tree/stable) branch. For "bleeding-edge" work on the library, see the [`develop`](https://github.com/Arduboy/Arduboy/tree/develop) branch of the Arduboy repository.
|
||||
|
||||
## Using the Arduboy Library
|
||||
|
||||
To start using the Arduboy Library in your applications, the library must be
|
||||
available to your own project's source. The most reliable method for including
|
||||
the latest stable release of the Aruboy Library in your project is to use the
|
||||
Arduino IDE and its _Library Manager_.
|
||||
|
||||
After the Arduboy Library is installed, it must be included for use in your project's source.
|
||||
|
||||
### Install
|
||||
|
||||
The Arduboy Library can be installed on your system in manys: through the Arduino IDE, using `git` to clone the library, or manually download and install the library. This section outlines the most common methods, and the Arduboy Library must only be installed once. Please use the first method _Install Using the Arduino IDE_ if you are unsure.
|
||||
|
||||
#### Install Using the Arduino IDE
|
||||
|
||||
Using the Arudino IDE, under the menu item, `Sketch > Include Library`, can be
|
||||
found `Manage Libraries`. This will open the Arudino IDE's _Library Manager_.
|
||||
Using this dialog the Arduboy Library can be search for and installed to be
|
||||
made available to your projects. See the following **Include** section, or add
|
||||
`#include <Arduboy.h>` to beginning of your project's source to start using the library.
|
||||
|
||||
#### Manually Installing
|
||||
|
||||
Install the library by cloning the `stable` branch of the Arduboy repository.
|
||||
|
||||
$ git clone -b stable https://github.com/Arduboy/Arduboy.git
|
||||
|
||||
The Arduboy Library can also be installed by downloading and unpacking a
|
||||
[release package](https://github.com/Arduboy/Arduboy/releases) into your
|
||||
system's Arduino `libraries` folder.
|
||||
|
||||
#### Locating The Arduino `libraries/` Folder
|
||||
|
||||
The library should be installed into your user's home Arduino `libraries`
|
||||
directory. Refer to the following list for the location of the Arduino
|
||||
`libraries` folder.
|
||||
|
||||
##### Arduino Library Locations by OS
|
||||
|
||||
Arduino library locations listed by operating system (OS).
|
||||
|
||||
**Linux**
|
||||
|
||||
/home/username/Documents/Arduino/libraries
|
||||
|
||||
**Mac**
|
||||
|
||||
/Users/username/Documents/Arduino/libraries
|
||||
|
||||
**Windows**
|
||||
|
||||
C:\Users\username\My Documents\Arduino\libraries
|
||||
|
||||
##### Use the Arduino IDE to Find or Change the Location of `libraries/`
|
||||
|
||||
If you don't find the `libraries` folder in one of the above locations, you can
|
||||
determine its location using the navigation menu `File > Preferences`. In the
|
||||
`Settings` tab will be a `Sketchbook location:` field. The `libraries` folder
|
||||
will be in the folder set in this field.
|
||||
|
||||
## Include
|
||||
|
||||
To start using the Arduboy library in your own sketches, the `Arduboy.h` header
|
||||
must be included in your project. To do so, add the following line to the top of your `.ino` file.
|
||||
|
||||
~~~~~~~~~~~~~~~{.cpp}
|
||||
#include "Arduboy.h"
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
You can have the Arduino IDE add `#include "Arduboy.h"` to your sketch
|
||||
automatically by using the navigation menu `Sketch > Include Library > Arduboy`.
|
||||
|
||||
## Board Selection
|
||||
|
||||
Select the **Leonardo** board as the target platform, or use the following
|
||||
instructions to add the Arduboy and Arduboy Devkit to the Arduino IDE.
|
||||
|
||||
### Add Arduboy Hardware to Arduino IDE
|
||||
|
||||
In the Arudino IDE select, `File > Preferences`. In the *Settings* tab there
|
||||
will be a field titled *Additional Boards Manager URLs:*, put the following in
|
||||
this field:
|
||||
|
||||
https://arduboy.github.io/board-support/package_arduboy_index.json
|
||||
|
||||
See this [guide](http://community.arduboy.com/t/quickly-add-the-arduboy-arduboy-devkit-to-the-arduino-ide/1069) for more detailed instructions.
|
||||
|
||||
## Arduboy Examples
|
||||
|
||||
Example games and source can be found in the `examples` directory.
|
||||
|
||||
### Playing Examples
|
||||
|
||||
Find and play an example by opening it through the Arduino IDE, compiling,
|
||||
and uploading the example to the Arduboy.
|
||||
|
||||
Examples can be found in the Arduino IDE in the navigation menu under,
|
||||
`File > Examples > Arduboy > Example_Name`.
|
||||
|
||||
## Running on a Development Board
|
||||
|
||||
To run this library on a development Arduboy board, edit `src/core/core.h` so
|
||||
that `#define AB_DEVKIT` is uncommented and `#define ARDUBOY_10` is comment out.
|
||||
|
||||
~~~~~~~~~~~~~~~{.cpp}
|
||||
//#define ARDUBOY_10 //< compile for the production Arduboy v1.0
|
||||
#define AB_DEVKIT //< compile for the official dev kit
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
## Custom Arduboy Library Source
|
||||
|
||||
If you find that a modified version of the Arduboy Library has been used to
|
||||
build a game, and you have already installed a release version of the Aruboy
|
||||
Library, then several options are available to allow you to compile and run the
|
||||
application without altering the Arduino IDE's libraries.
|
||||
|
||||
Use one of the following options to compile sketches that have included copies
|
||||
of the Aruboy Library,
|
||||
|
||||
**Option 1.**
|
||||
|
||||
Remove the local `Arduboy.cpp` and `Arduboy.h` files and try recompiling.
|
||||
This will only work in some cases.
|
||||
|
||||
**Option 2.**
|
||||
|
||||
Rename `Arduboy.h` to `CustomArduboy.h` (or a similar name) and add
|
||||
`#include "CustomArduboy.h"` to the `.ino` sketch file.
|
|
@ -0,0 +1,739 @@
|
|||
/*
|
||||
Breakout
|
||||
Copyright (C) 2011 Sebastian Goscik
|
||||
All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "Arduboy.h"
|
||||
#include "breakout_bitmaps.h"
|
||||
|
||||
Arduboy arduboy;
|
||||
|
||||
const unsigned int COLUMNS = 13; //Columns of bricks
|
||||
const unsigned int ROWS = 4; //Rows of bricks
|
||||
int dx = -1; //Initial movement of ball
|
||||
int dy = -1; //Initial movement of ball
|
||||
int xb; //Balls starting possition
|
||||
int yb; //Balls starting possition
|
||||
boolean released; //If the ball has been released by the player
|
||||
boolean paused = false; //If the game has been paused
|
||||
byte xPaddle; //X position of paddle
|
||||
boolean isHit[ROWS][COLUMNS]; //Array of if bricks are hit or not
|
||||
boolean bounced=false; //Used to fix double bounce glitch
|
||||
byte lives = 3; //Amount of lives
|
||||
byte level = 1; //Current level
|
||||
unsigned int score=0; //Score for the game
|
||||
unsigned int brickCount; //Amount of bricks hit
|
||||
byte pad,pad2,pad3; //Button press buffer used to stop pause repeating
|
||||
byte oldpad,oldpad2,oldpad3;
|
||||
char text[16]; //General string buffer
|
||||
boolean start=false; //If in menu or in game
|
||||
boolean initialDraw=false;//If the inital draw has happened
|
||||
char initials[3]; //Initials used in high score
|
||||
|
||||
//Ball Bounds used in collision detection
|
||||
byte leftBall;
|
||||
byte rightBall;
|
||||
byte topBall;
|
||||
byte bottomBall;
|
||||
|
||||
//Brick Bounds used in collision detection
|
||||
byte leftBrick;
|
||||
byte rightBrick;
|
||||
byte topBrick;
|
||||
byte bottomBrick;
|
||||
|
||||
byte tick;
|
||||
|
||||
#include "pins_arduino.h" // Arduino pre-1.0 needs this
|
||||
|
||||
void intro()
|
||||
{
|
||||
for(int i = -8; i < 28; i = i + 2)
|
||||
{
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(46, i);
|
||||
arduboy.print("ARDUBOY");
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
arduboy.tunes.tone(987, 160);
|
||||
delay(160);
|
||||
arduboy.tunes.tone(1318, 400);
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
void movePaddle()
|
||||
{
|
||||
//Move right
|
||||
if(xPaddle < WIDTH - 12)
|
||||
{
|
||||
if (arduboy.pressed(RIGHT_BUTTON))
|
||||
{
|
||||
xPaddle+=2;
|
||||
}
|
||||
}
|
||||
|
||||
//Move left
|
||||
if(xPaddle > 0)
|
||||
{
|
||||
if (arduboy.pressed(LEFT_BUTTON))
|
||||
{
|
||||
xPaddle-=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void moveBall()
|
||||
{
|
||||
tick++;
|
||||
if(released)
|
||||
{
|
||||
//Move ball
|
||||
if (abs(dx)==2) {
|
||||
xb += dx/2;
|
||||
// 2x speed is really 1.5 speed
|
||||
if (tick%2==0)
|
||||
xb += dx/2;
|
||||
} else {
|
||||
xb += dx;
|
||||
}
|
||||
yb=yb + dy;
|
||||
|
||||
//Set bounds
|
||||
leftBall = xb;
|
||||
rightBall = xb + 2;
|
||||
topBall = yb;
|
||||
bottomBall = yb + 2;
|
||||
|
||||
//Bounce off top edge
|
||||
if (yb <= 0)
|
||||
{
|
||||
yb = 2;
|
||||
dy = -dy;
|
||||
arduboy.tunes.tone(523, 250);
|
||||
}
|
||||
|
||||
//Lose a life if bottom edge hit
|
||||
if (yb >= 64)
|
||||
{
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
xPaddle = 54;
|
||||
yb=60;
|
||||
released = false;
|
||||
lives--;
|
||||
drawLives();
|
||||
arduboy.tunes.tone(175, 250);
|
||||
if (random(0, 2) == 0)
|
||||
{
|
||||
dx = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Bounce off left side
|
||||
if (xb <= 0)
|
||||
{
|
||||
xb = 2;
|
||||
dx = -dx;
|
||||
arduboy.tunes.tone(523, 250);
|
||||
}
|
||||
|
||||
//Bounce off right side
|
||||
if (xb >= WIDTH - 2)
|
||||
{
|
||||
xb = WIDTH - 4;
|
||||
dx = -dx;
|
||||
arduboy.tunes.tone(523, 250);
|
||||
}
|
||||
|
||||
//Bounce off paddle
|
||||
if (xb+1>=xPaddle && xb<=xPaddle+12 && yb+2>=63 && yb<=64)
|
||||
{
|
||||
dy = -dy;
|
||||
dx = ((xb-(xPaddle+6))/3); //Applies spin on the ball
|
||||
// prevent straight bounce
|
||||
if (dx == 0) {
|
||||
dx = (random(0,2) == 1) ? 1 : -1;
|
||||
}
|
||||
arduboy.tunes.tone(200, 250);
|
||||
}
|
||||
|
||||
//Bounce off Bricks
|
||||
for (byte row = 0; row < ROWS; row++)
|
||||
{
|
||||
for (byte column = 0; column < COLUMNS; column++)
|
||||
{
|
||||
if (!isHit[row][column])
|
||||
{
|
||||
//Sets Brick bounds
|
||||
leftBrick = 10 * column;
|
||||
rightBrick = 10 * column + 10;
|
||||
topBrick = 6 * row + 1;
|
||||
bottomBrick = 6 * row + 7;
|
||||
|
||||
//If A collison has occured
|
||||
if (topBall <= bottomBrick && bottomBall >= topBrick &&
|
||||
leftBall <= rightBrick && rightBall >= leftBrick)
|
||||
{
|
||||
Score();
|
||||
brickCount++;
|
||||
isHit[row][column] = true;
|
||||
arduboy.drawRect(10*column, 2+6*row, 8, 4, 0);
|
||||
|
||||
//Vertical collision
|
||||
if (bottomBall > bottomBrick || topBall < topBrick)
|
||||
{
|
||||
//Only bounce once each ball move
|
||||
if(!bounced)
|
||||
{
|
||||
dy =- dy;
|
||||
yb += dy;
|
||||
bounced = true;
|
||||
arduboy.tunes.tone(261, 250);
|
||||
}
|
||||
}
|
||||
|
||||
//Hoizontal collision
|
||||
if (leftBall < leftBrick || rightBall > rightBrick)
|
||||
{
|
||||
//Only bounce once brick each ball move
|
||||
if(!bounced)
|
||||
{
|
||||
dx =- dx;
|
||||
xb += dx;
|
||||
bounced = true;
|
||||
arduboy.tunes.tone(261, 250);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Reset Bounce
|
||||
bounced = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Ball follows paddle
|
||||
xb=xPaddle + 5;
|
||||
|
||||
//Release ball if FIRE pressed
|
||||
pad3 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if (pad3 == 1 && oldpad3 == 0)
|
||||
{
|
||||
released=true;
|
||||
|
||||
//Apply random direction to ball on release
|
||||
if (random(0, 2) == 0)
|
||||
{
|
||||
dx = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = -1;
|
||||
}
|
||||
//Makes sure the ball heads upwards
|
||||
dy = -1;
|
||||
}
|
||||
oldpad3 = pad3;
|
||||
}
|
||||
}
|
||||
|
||||
void drawBall()
|
||||
{
|
||||
// arduboy.setCursor(0,0);
|
||||
// arduboy.print(arduboy.cpuLoad());
|
||||
// arduboy.print(" ");
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
|
||||
moveBall();
|
||||
|
||||
arduboy.drawPixel(xb, yb, 1);
|
||||
arduboy.drawPixel(xb+1, yb, 1);
|
||||
arduboy.drawPixel(xb, yb+1, 1);
|
||||
arduboy.drawPixel(xb+1, yb+1, 1);
|
||||
}
|
||||
|
||||
void drawPaddle()
|
||||
{
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
movePaddle();
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 1);
|
||||
}
|
||||
|
||||
void drawLives()
|
||||
{
|
||||
sprintf(text, "LIVES:%u", lives);
|
||||
arduboy.setCursor(0, 90);
|
||||
arduboy.print(text);
|
||||
}
|
||||
|
||||
void drawGameOver()
|
||||
{
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
arduboy.setCursor(52, 42);
|
||||
arduboy.print( "Game");
|
||||
arduboy.setCursor(52, 54);
|
||||
arduboy.print("Over");
|
||||
arduboy.display();
|
||||
delay(4000);
|
||||
}
|
||||
|
||||
void pause()
|
||||
{
|
||||
paused = true;
|
||||
//Draw pause to the screen
|
||||
arduboy.setCursor(52, 45);
|
||||
arduboy.print("PAUSE");
|
||||
arduboy.display();
|
||||
while (paused)
|
||||
{
|
||||
delay(150);
|
||||
//Unpause if FIRE is pressed
|
||||
pad2 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if (pad2 > 1 && oldpad2 == 0 && released)
|
||||
{
|
||||
arduboy.fillRect(52, 45, 30, 11, 0);
|
||||
|
||||
paused=false;
|
||||
}
|
||||
oldpad2=pad2;
|
||||
}
|
||||
}
|
||||
|
||||
void Score()
|
||||
{
|
||||
score += (level*10);
|
||||
sprintf(text, "SCORE:%u", score);
|
||||
arduboy.setCursor(80, 90);
|
||||
arduboy.print(text);
|
||||
}
|
||||
|
||||
void newLevel(){
|
||||
//Undraw paddle
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
|
||||
//Undraw ball
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
|
||||
//Alter various variables to reset the game
|
||||
xPaddle = 54;
|
||||
yb = 60;
|
||||
brickCount = 0;
|
||||
released = false;
|
||||
|
||||
//Draws new bricks and resets their values
|
||||
for (byte row = 0; row < 4; row++) {
|
||||
for (byte column = 0; column < 13; column++)
|
||||
{
|
||||
isHit[row][column] = false;
|
||||
arduboy.drawRect(10*column, 2+6*row, 8, 4, 1);
|
||||
}
|
||||
}
|
||||
|
||||
//Draws the initial lives
|
||||
drawLives();
|
||||
|
||||
//Draws the initial score
|
||||
sprintf(text, "SCORE:%u", score);
|
||||
arduboy.setCursor(80, 90);
|
||||
arduboy.print(text);
|
||||
}
|
||||
|
||||
//Used to delay images while reading button input
|
||||
boolean pollFireButton(int n)
|
||||
{
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
delay(15);
|
||||
pad = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if(pad == 1 && oldpad == 0)
|
||||
{
|
||||
oldpad3 = 1; //Forces pad loop 3 to run once
|
||||
return true;
|
||||
}
|
||||
oldpad = pad;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//Function by nootropic design to display highscores
|
||||
boolean displayHighScores(byte file)
|
||||
{
|
||||
byte y = 10;
|
||||
byte x = 24;
|
||||
// Each block of EEPROM has 10 high scores, and each high score entry
|
||||
// is 5 bytes long: 3 bytes for initials and two bytes for score.
|
||||
int address = file*10*5;
|
||||
byte hi, lo;
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(32, 0);
|
||||
arduboy.print("HIGH SCORES");
|
||||
arduboy.display();
|
||||
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
sprintf(text, "%2d", i+1);
|
||||
arduboy.setCursor(x,y+(i*8));
|
||||
arduboy.print( text);
|
||||
arduboy.display();
|
||||
hi = EEPROM.read(address + (5*i));
|
||||
lo = EEPROM.read(address + (5*i) + 1);
|
||||
|
||||
if ((hi == 0xFF) && (lo == 0xFF))
|
||||
{
|
||||
score = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
score = (hi << 8) | lo;
|
||||
}
|
||||
|
||||
initials[0] = (char)EEPROM.read(address + (5*i) + 2);
|
||||
initials[1] = (char)EEPROM.read(address + (5*i) + 3);
|
||||
initials[2] = (char)EEPROM.read(address + (5*i) + 4);
|
||||
|
||||
if (score > 0)
|
||||
{
|
||||
sprintf(text, "%c%c%c %u", initials[0], initials[1], initials[2], score);
|
||||
arduboy.setCursor(x + 24, y + (i*8));
|
||||
arduboy.print(text);
|
||||
arduboy.display();
|
||||
}
|
||||
}
|
||||
if (pollFireButton(300))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
boolean titleScreen()
|
||||
{
|
||||
//Clears the screen
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(16,22);
|
||||
arduboy.setTextSize(2);
|
||||
arduboy.print("ARAKNOID");
|
||||
arduboy.setTextSize(1);
|
||||
arduboy.display();
|
||||
if (pollFireButton(25))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//Flash "Press FIRE" 5 times
|
||||
for(byte i = 0; i < 5; i++)
|
||||
{
|
||||
//Draws "Press FIRE"
|
||||
//arduboy.bitmap(31, 53, fire); arduboy.display();
|
||||
arduboy.setCursor(31, 53);
|
||||
arduboy.print("PRESS FIRE!");
|
||||
arduboy.display();
|
||||
|
||||
if (pollFireButton(50))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//Removes "Press FIRE"
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(16,22);
|
||||
arduboy.setTextSize(2);
|
||||
arduboy.print("ARAKNOID");
|
||||
arduboy.setTextSize(1);
|
||||
arduboy.display();
|
||||
|
||||
arduboy.display();
|
||||
if (pollFireButton(25))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Function by nootropic design to add high scores
|
||||
void enterInitials()
|
||||
{
|
||||
char index = 0;
|
||||
|
||||
arduboy.clear();
|
||||
|
||||
initials[0] = ' ';
|
||||
initials[1] = ' ';
|
||||
initials[2] = ' ';
|
||||
|
||||
while (true)
|
||||
{
|
||||
arduboy.display();
|
||||
arduboy.clear();
|
||||
|
||||
arduboy.setCursor(16,0);
|
||||
arduboy.print("HIGH SCORE");
|
||||
sprintf(text, "%u", score);
|
||||
arduboy.setCursor(88, 0);
|
||||
arduboy.print(text);
|
||||
arduboy.setCursor(56, 20);
|
||||
arduboy.print(initials[0]);
|
||||
arduboy.setCursor(64, 20);
|
||||
arduboy.print(initials[1]);
|
||||
arduboy.setCursor(72, 20);
|
||||
arduboy.print(initials[2]);
|
||||
for(byte i = 0; i < 3; i++)
|
||||
{
|
||||
arduboy.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1);
|
||||
}
|
||||
arduboy.drawLine(56, 28, 88, 28, 0);
|
||||
arduboy.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, 1);
|
||||
delay(150);
|
||||
|
||||
if (arduboy.pressed(LEFT_BUTTON) || arduboy.pressed(B_BUTTON))
|
||||
{
|
||||
index--;
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
} else
|
||||
{
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(RIGHT_BUTTON))
|
||||
{
|
||||
index++;
|
||||
if (index > 2)
|
||||
{
|
||||
index = 2;
|
||||
} else {
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(DOWN_BUTTON))
|
||||
{
|
||||
initials[index]++;
|
||||
arduboy.tunes.tone(523, 250);
|
||||
// A-Z 0-9 :-? !-/ ' '
|
||||
if (initials[index] == '0')
|
||||
{
|
||||
initials[index] = ' ';
|
||||
}
|
||||
if (initials[index] == '!')
|
||||
{
|
||||
initials[index] = 'A';
|
||||
}
|
||||
if (initials[index] == '[')
|
||||
{
|
||||
initials[index] = '0';
|
||||
}
|
||||
if (initials[index] == '@')
|
||||
{
|
||||
initials[index] = '!';
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(UP_BUTTON))
|
||||
{
|
||||
initials[index]--;
|
||||
arduboy.tunes.tone(523, 250);
|
||||
if (initials[index] == ' ') {
|
||||
initials[index] = '?';
|
||||
}
|
||||
if (initials[index] == '/') {
|
||||
initials[index] = 'Z';
|
||||
}
|
||||
if (initials[index] == 31) {
|
||||
initials[index] = '/';
|
||||
}
|
||||
if (initials[index] == '@') {
|
||||
initials[index] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(A_BUTTON))
|
||||
{
|
||||
if (index < 2)
|
||||
{
|
||||
index++;
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
} else {
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void enterHighScore(byte file)
|
||||
{
|
||||
// Each block of EEPROM has 10 high scores, and each high score entry
|
||||
// is 5 bytes long: 3 bytes for initials and two bytes for score.
|
||||
int address = file * 10 * 5;
|
||||
byte hi, lo;
|
||||
char tmpInitials[3];
|
||||
unsigned int tmpScore = 0;
|
||||
|
||||
// High score processing
|
||||
for(byte i = 0; i < 10; i++)
|
||||
{
|
||||
hi = EEPROM.read(address + (5*i));
|
||||
lo = EEPROM.read(address + (5*i) + 1);
|
||||
if ((hi == 0xFF) && (lo == 0xFF))
|
||||
{
|
||||
// The values are uninitialized, so treat this entry
|
||||
// as a score of 0.
|
||||
tmpScore = 0;
|
||||
} else
|
||||
{
|
||||
tmpScore = (hi << 8) | lo;
|
||||
}
|
||||
if (score > tmpScore)
|
||||
{
|
||||
enterInitials();
|
||||
for(byte j=i;j<10;j++)
|
||||
{
|
||||
hi = EEPROM.read(address + (5*j));
|
||||
lo = EEPROM.read(address + (5*j) + 1);
|
||||
|
||||
if ((hi == 0xFF) && (lo == 0xFF))
|
||||
{
|
||||
tmpScore = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpScore = (hi << 8) | lo;
|
||||
}
|
||||
|
||||
tmpInitials[0] = (char)EEPROM.read(address + (5*j) + 2);
|
||||
tmpInitials[1] = (char)EEPROM.read(address + (5*j) + 3);
|
||||
tmpInitials[2] = (char)EEPROM.read(address + (5*j) + 4);
|
||||
|
||||
// write score and initials to current slot
|
||||
EEPROM.write(address + (5*j), ((score >> 8) & 0xFF));
|
||||
EEPROM.write(address + (5*j) + 1, (score & 0xFF));
|
||||
EEPROM.write(address + (5*j) + 2, initials[0]);
|
||||
EEPROM.write(address + (5*j) + 3, initials[1]);
|
||||
EEPROM.write(address + (5*j) + 4, initials[2]);
|
||||
|
||||
// tmpScore and tmpInitials now hold what we want to
|
||||
//write in the next slot.
|
||||
score = tmpScore;
|
||||
initials[0] = tmpInitials[0];
|
||||
initials[1] = tmpInitials[1];
|
||||
initials[2] = tmpInitials[2];
|
||||
}
|
||||
|
||||
score = 0;
|
||||
initials[0] = ' ';
|
||||
initials[1] = ' ';
|
||||
initials[2] = ' ';
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(60);
|
||||
arduboy.print("Hello World!");
|
||||
arduboy.display();
|
||||
intro();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
//Title screen loop switches from title screen
|
||||
//and high scores until FIRE is pressed
|
||||
while (!start)
|
||||
{
|
||||
start = titleScreen();
|
||||
if (!start)
|
||||
{
|
||||
start = displayHighScores(2);
|
||||
}
|
||||
}
|
||||
|
||||
//Initial level draw
|
||||
if (!initialDraw)
|
||||
{
|
||||
//Clears the screen
|
||||
arduboy.display();
|
||||
arduboy.clear();
|
||||
//Selects Font
|
||||
//Draws the new level
|
||||
newLevel();
|
||||
initialDraw=true;
|
||||
}
|
||||
|
||||
if (lives>0)
|
||||
{
|
||||
drawPaddle();
|
||||
|
||||
//Pause game if FIRE pressed
|
||||
pad = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
|
||||
if(pad >1 && oldpad==0 && released)
|
||||
{
|
||||
oldpad2=0; //Forces pad loop 2 to run once
|
||||
pause();
|
||||
}
|
||||
|
||||
oldpad=pad;
|
||||
drawBall();
|
||||
|
||||
if(brickCount == ROWS * COLUMNS)
|
||||
{
|
||||
level++;
|
||||
newLevel();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drawGameOver();
|
||||
if (score > 0)
|
||||
{
|
||||
enterHighScore(2);
|
||||
}
|
||||
|
||||
arduboy.clear();
|
||||
initialDraw=false;
|
||||
start=false;
|
||||
lives=3;
|
||||
score=0;
|
||||
newLevel();
|
||||
}
|
||||
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# ArduBreakout
|
||||
|
||||
Brick breaking game in the vein of Atari's *Breakout*.
|
||||
|
||||
Control the paddle with the directional keys to keep a ball bouncing against a brick wall until all of the bricks are broken.
|
||||
|
||||
High scores are saved to EEPROM and can be saved through Arduboy restarts.
|
|
@ -0,0 +1,124 @@
|
|||
#include "breakout_bitmaps.h"
|
||||
|
||||
PROGMEM const unsigned char title[] =
|
||||
{
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x07,0xFF,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xE0,0x00,
|
||||
0x00,0x08,0x00,0x60,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x03,0xF4,0x10,0x00,
|
||||
0x00,0x0B,0xFF,0x10,0x00,0x00,0x00,0x20,0x80,0x00,0x00,0x04,0x09,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xD0,0x00,0x00,0x00,0x2E,0xB8,0x00,0x00,0x05,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xD0,0x00,0x00,0x00,0x2E,0x44,0x00,0x00,0x05,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xD0,0x00,0x00,0x00,0x2E,0x34,0x00,0x00,0x05,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xCF,0xFF,0xF9,0xFF,0xAE,0x35,0xFF,0x7C,0xF9,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xC0,0x00,0x06,0x00,0x4E,0x66,0x00,0x83,0x01,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0xFF,0x13,0xE7,0xF0,0xFF,0x0F,0xE0,0x7E,0x38,0x73,0xF9,0xD0,0x00,
|
||||
0x00,0x0B,0xFF,0x13,0xE7,0xF0,0xFF,0x0F,0xC0,0x7E,0x38,0x73,0xF9,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xDC,0x0E,0x0C,0x01,0xCF,0x80,0xE1,0x38,0x71,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xDC,0xCE,0x0C,0x01,0xCF,0xC0,0xE1,0x38,0x71,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0x83,0xDD,0x2F,0xF0,0x7F,0xCE,0xE0,0xE1,0x38,0x71,0xE0,0x10,0x00,
|
||||
0x00,0x0B,0x83,0xDD,0x2F,0xF0,0xFF,0xCE,0x70,0xE1,0x38,0x71,0xE0,0x10,0x00,
|
||||
0x00,0x0B,0x83,0xDD,0x2E,0x00,0x81,0xCE,0x38,0xE1,0x38,0x71,0xE1,0xD0,0x00,
|
||||
0x00,0x0B,0xFF,0x1D,0x27,0xFC,0xFE,0xCE,0x1C,0x7E,0x1F,0xC4,0x79,0xD0,0x00,
|
||||
0x00,0x0B,0xFF,0x1D,0x17,0xFC,0x7E,0xCE,0x0C,0x7E,0x1F,0xCA,0x79,0xD0,0x00,
|
||||
0x00,0x08,0x00,0x41,0x10,0x01,0x00,0x00,0xE1,0x00,0xC0,0x11,0x00,0x10,0x00,
|
||||
0x00,0x07,0xFF,0xBE,0x0F,0xFE,0xFF,0xFF,0x1E,0xFF,0x3F,0xE0,0xFF,0xE0,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x04,0x04,0x10,0x03,0x8A,0x10,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x04,0x00,0x00,0x02,0x08,0x80,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0xF3,0x35,0x54,0xD7,0x63,0x1A,0xD7,0x60,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x46,0x54,0x95,0x52,0x2A,0x95,0x50,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x35,0x25,0x97,0x53,0x9A,0x57,0x50,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0xF0,0x06,0x04,0x00,0x04,0x00,0x38,0x00,0x0A,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x88,0x09,0x04,0x00,0x20,0x00,0x44,0x00,0x02,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0xF2,0x84,0x27,0x31,0xB5,0x98,0x40,0xC6,0x6A,0x80,0x00,0x00,
|
||||
0x00,0x00,0x00,0x8A,0x82,0x54,0x8A,0x24,0x54,0x4D,0x28,0x8B,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x8A,0x89,0x44,0xA8,0xA5,0x54,0x45,0x22,0x8A,0x80,0x00,0x00,
|
||||
0x00,0x00,0x00,0xF1,0x06,0x37,0x1B,0x14,0xD4,0x3C,0xCC,0x6A,0x80,0x00,0x00,
|
||||
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
PROGMEM const unsigned char fire[] =
|
||||
{
|
||||
57,8,
|
||||
0xF8,0x00,0x00,0x00,0x3D,0xEF,0x8F,0x80,
|
||||
0xCC,0x00,0x00,0x00,0x60,0xCC,0xD8,0x00,
|
||||
0xCC,0x00,0x00,0x00,0x60,0xCC,0xD8,0x00,
|
||||
0xF9,0x67,0x1E,0x78,0x78,0xCF,0x9F,0x00,
|
||||
0xC1,0x8C,0xA0,0x80,0x60,0xCC,0xD8,0x00,
|
||||
0xC1,0x8F,0x1C,0x70,0x60,0xCC,0xD8,0x00,
|
||||
0xC1,0x8C,0x02,0x08,0x60,0xCC,0xDF,0x80,
|
||||
0xC1,0x87,0xBC,0xF0,0x61,0xEC,0xCF,0x80,
|
||||
};
|
||||
|
||||
PROGMEM const unsigned char arrow[] =
|
||||
{
|
||||
5,5,
|
||||
0x20,
|
||||
0x10,
|
||||
0xF8,
|
||||
0x10,
|
||||
0x20,
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef BREAKOUT_BITMAPS_H
|
||||
#define BREAKOUT_BITMAPS_H
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
extern const unsigned char fire[];
|
||||
extern const unsigned char title[];
|
||||
extern const unsigned char arrow[];
|
||||
|
||||
#endif
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Buttons example
|
||||
June 11, 2015
|
||||
Copyright (C) 2015 David Martinez
|
||||
All rights reserved.
|
||||
This code is the most basic barebones code for showing how to use buttons in
|
||||
Arduboy.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "Arduboy.h"
|
||||
|
||||
// Make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// Variables for your game go here.
|
||||
char text[] = "Press Buttons!";
|
||||
byte x;
|
||||
byte y;
|
||||
|
||||
// Width of each charcter including inter-character space
|
||||
#define CHAR_WIDTH 6
|
||||
|
||||
// Height of each charater
|
||||
#define CHAR_HEIGHT 8
|
||||
|
||||
// To get the number of characters, we subtract 1 from the length of
|
||||
// the array because there will be a NULL terminator at the end.
|
||||
#define NUM_CHARS (sizeof(text) - 1)
|
||||
|
||||
// This is the highest value that x can be without the end of the text
|
||||
// going farther than the right side of the screen. We add one because
|
||||
// there will be a 1 pixel space at the end of the last character.
|
||||
// WIDTH and HEIGHT are defined in the Arduboy library.
|
||||
#define X_MAX (WIDTH - (NUM_CHARS * CHAR_WIDTH) + 1)
|
||||
|
||||
// This is the highest value that y can be without the text going below
|
||||
// the bottom of the screen.
|
||||
#define Y_MAX (HEIGHT - CHAR_HEIGHT)
|
||||
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
//initiate arduboy instance
|
||||
arduboy.begin();
|
||||
|
||||
// here we set the framerate to 30, we do not need to run at default 60 and
|
||||
// it saves us battery life.
|
||||
arduboy.setFrameRate(30);
|
||||
|
||||
// set x and y to the middle of the screen
|
||||
x = (WIDTH / 2) - (NUM_CHARS * CHAR_WIDTH / 2);
|
||||
y = (HEIGHT / 2) - (CHAR_HEIGHT / 2);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// the next couple of lines will deal with checking if the D-pad buttons
|
||||
// are pressed and move our text accordingly.
|
||||
// We check to make sure that x and y stay within a range that keeps the
|
||||
// text on the screen.
|
||||
|
||||
// if the right button is pressed move 1 pixel to the right every frame
|
||||
if(arduboy.pressed(RIGHT_BUTTON) && (x < X_MAX)) {
|
||||
x++;
|
||||
}
|
||||
|
||||
// if the left button is pressed move 1 pixel to the left every frame
|
||||
if(arduboy.pressed(LEFT_BUTTON) && (x > 0)) {
|
||||
x--;
|
||||
}
|
||||
|
||||
// if the up button or B button is pressed move 1 pixel up every frame
|
||||
if((arduboy.pressed(UP_BUTTON) || arduboy.pressed(B_BUTTON)) && (y > 0)) {
|
||||
y--;
|
||||
}
|
||||
|
||||
// if the down button or A button is pressed move 1 pixel down every frame
|
||||
if((arduboy.pressed(DOWN_BUTTON) || arduboy.pressed(A_BUTTON)) && (y < Y_MAX)) {
|
||||
y++;
|
||||
}
|
||||
|
||||
|
||||
// we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
// we set our cursor x pixels to the right and y down from the top
|
||||
arduboy.setCursor(x, y);
|
||||
|
||||
// then we print to screen what is stored in our text variable we declared earlier
|
||||
arduboy.print(text);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display.
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Hello, World! example
|
||||
June 11, 2015
|
||||
Copyright (C) 2015 David Martinez
|
||||
All rights reserved.
|
||||
This code is the most basic barebones code for writing a program for Arduboy.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "Arduboy.h"
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
|
||||
// here we set the framerate to 15, we do not need to run at
|
||||
// default 60 and it saves us battery life
|
||||
arduboy.setFrameRate(15);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
// we set our cursor 5 pixels to the right and 10 down from the top
|
||||
// (positions start at 0, 0)
|
||||
arduboy.setCursor(4, 9);
|
||||
|
||||
// then we print to screen what is in the Quotation marks ""
|
||||
arduboy.print(F("Hello, world!"));
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
### Benchmark run as of June 2015
|
||||
|
||||
- drawPixel
|
||||
- drawTriangle
|
||||
- fillTriangle
|
||||
- drawRect
|
||||
- fillRect
|
||||
- drawCircle
|
||||
- fillCircle
|
||||
- drawRoundRect
|
||||
- fillRoundRect
|
||||
- drawLine
|
||||
- drawFastHLine
|
||||
- drawFastVLine
|
||||
- drawBitmap
|
||||
- drawSlowBitmap
|
||||
- paint
|
|
@ -0,0 +1,4 @@
|
|||
# Tunes
|
||||
Play a musical composition using the Arduboy.
|
||||
|
||||
A small composition is stored by `byte PROGMEM score`. The score is played in the sketch loop using `playScore(score)`.
|
|
@ -0,0 +1,201 @@
|
|||
#include "Arduboy.h"
|
||||
|
||||
const byte PROGMEM score [] = {
|
||||
// Sinfonia No.12 in A major BWV.798 J.S.Bach
|
||||
// Conductor Track
|
||||
7,208, 0x90,0x45, 0x91,0x39, 1,77, 0x80, 0x81, 0x90,0x44, 0,166, 0x80, 0x90,0x45, 0,166, 0x80, 0x90,0x47,
|
||||
0x91,0x38, 1,77, 0x80, 0x81, 0x90,0x45, 0,166, 0x80, 0x90,0x44, 0,166, 0x80, 0x90,0x45, 0x91,0x36, 1,77,
|
||||
0x81, 1,77, 0x91,0x31, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x44, 0,166, 0x80, 0x90,0x45,
|
||||
0,166, 0x80, 0x90,0x47, 0x91,0x32, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x49, 0,166, 0x80,
|
||||
0x90,0x40, 0,166, 0x80, 0x90,0x4A, 0x91,0x34, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x4C, 1,77,
|
||||
0x80, 0x90,0x49, 0x91,0x2D, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x39, 0,166, 0x80,
|
||||
0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x38, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x81, 0x90,0x4C,
|
||||
0x91,0x36, 0,166, 0x80, 0x90,0x4E, 0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x34, 0x92,0x40, 0,166, 0x80, 0x90,0x51,
|
||||
0,166, 0x80, 0x81, 0x82, 0x90,0x53, 0x91,0x3F, 0,166, 0x81, 0x91,0x40, 0,166, 0x81, 0x91,0x3F, 0x92,0x42,
|
||||
0,166, 0x80, 0x90,0x51, 0,166, 0x80, 0x81, 0x82, 0x90,0x50, 0x91,0x40, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x3F,
|
||||
0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x3D, 0x92,0x40, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x90,0x4C, 0x91,0x38, 0,166, 0x82, 0x92,0x42, 0,166, 0x81, 0x82,
|
||||
0x91,0x3F, 0,166, 0x81, 0x91,0x40, 0,166, 0x81, 0x91,0x42, 0x92,0x39, 0,166, 0x81, 0x91,0x3B, 0,166,
|
||||
0x81, 0x82, 0x91,0x44, 0,166, 0x81, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x4B, 0x92,0x3B, 0,166,
|
||||
0x80, 0x82, 0x90,0x3B, 0,166, 0x80, 0x90,0x47, 1,77, 0x80, 0x81, 0x90,0x4C, 0x91,0x44, 0x92,0x40, 0,166,
|
||||
0x81, 0x91,0x45, 0,166, 0x80, 0x81, 0x82, 0x90,0x4A, 0x91,0x47, 0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x45, 0,166,
|
||||
0x80, 0x81, 0x90,0x4A, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x40,
|
||||
0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x3E, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x3D, 0x92,0x39, 0,166, 0x81,
|
||||
0x91,0x49, 0,166, 0x81, 0x82, 0x91,0x4E, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x39, 0,166, 0x80,
|
||||
0x82, 0x90,0x50, 0x92,0x3B, 0,166, 0x81, 0x91,0x4B, 0,166, 0x81, 0x82, 0x91,0x4C, 0x92,0x39, 0,166, 0x80,
|
||||
0x82, 0x90,0x50, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x4E, 0x92,0x39, 0,166, 0x81, 0x91,0x49, 0,166, 0x81,
|
||||
0x91,0x4A, 0,166, 0x80, 0x90,0x4E, 0,166, 0x80, 0x90,0x4C, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x3B, 0,166,
|
||||
0x81, 0x82, 0x91,0x49, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x4C, 0x92,0x39, 0,166, 0x80, 0x81, 0x82, 0x90,0x3B,
|
||||
0x91,0x4A, 0x92,0x44, 0,166, 0x80, 0x90,0x34, 0,166, 0x80, 0x81, 0x82, 0x90,0x3D, 0x91,0x49, 0x92,0x45, 0,166,
|
||||
0x80, 0x90,0x34, 0,166, 0x80, 0x81, 0x90,0x3E, 0x91,0x47, 0,166, 0x80, 0x90,0x34, 0,166, 0x80, 0x82, 0x90,0x44,
|
||||
0x92,0x40, 1,77, 0x80, 0x81, 0x82, 0x90,0x3D, 0x91,0x45, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x90,0x39,
|
||||
0x92,0x49, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x82, 0x90,0x3D, 0x92,0x4E, 0,166, 0x80, 0x90,0x3F, 0,166,
|
||||
0x80, 0x81, 0x90,0x45, 0x91,0x40, 0,166, 0x81, 0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x44, 0x91,0x3B, 0,166,
|
||||
0x81, 0x91,0x39, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x38, 0,166, 0x82, 0x92,0x39, 0,166, 0x81, 0x82, 0x91,0x4C,
|
||||
0x92,0x3B, 0,166, 0x82, 0x92,0x3D, 0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x3F, 0,166, 0x82, 0x92,0x40, 0,166,
|
||||
0x80, 0x82, 0x90,0x42, 0x92,0x39, 0,166, 0x82, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x4B, 0x92,0x36, 0,166,
|
||||
0x81, 0x82, 0x91,0x4C, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x4E, 0x92,0x39, 0,166, 0x82, 0x92,0x38, 0,166,
|
||||
0x81, 0x82, 0x91,0x4C, 0x92,0x39, 0,166, 0x81, 0x82, 0x91,0x4B, 0x92,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x4C,
|
||||
0x91,0x38, 0,166, 0x92,0x4B, 0,166, 0x81, 0x82, 0x91,0x49, 0x92,0x39, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x3B,
|
||||
0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x3D, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x4B,
|
||||
0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x40, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x3F, 0,166, 0x80,
|
||||
0x82, 0x90,0x47, 0x92,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x50, 0x91,0x39, 0x92,0x40, 0,166, 0x80, 0x81, 0x90,0x47,
|
||||
0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x36, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x82, 0x90,0x53,
|
||||
0x91,0x3F, 0x92,0x3B, 1,77, 0x80, 0x81, 0x82, 0x90,0x50, 0x91,0x34, 0x92,0x40, 0,166, 0x80, 0x90,0x51, 0,166,
|
||||
0x80, 0x90,0x53, 0,166, 0x80, 0x90,0x51, 0,166, 0x80, 0x81, 0x82, 0x90,0x50, 0,166, 0x80, 0x90,0x4E, 0x91,0x39,
|
||||
0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0x91,0x35, 0,166, 0x81, 0x91,0x31, 0,166, 0x81, 0x91,0x44, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x31,
|
||||
0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x38, 0,166, 0x82, 0x92,0x31, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x35,
|
||||
0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x31, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x36, 0,166, 0x82, 0x92,0x31,
|
||||
0,166, 0x80, 0x82, 0x90,0x38, 0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x31, 0x92,0x4A, 0,166, 0x80, 0x82, 0x90,0x36,
|
||||
0x92,0x4C, 0,166, 0x80, 0x90,0x31, 0,166, 0x80, 0x82, 0x90,0x34, 0x92,0x4A, 0,166, 0x80, 0x82, 0x90,0x31,
|
||||
0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x33, 0x92,0x47, 0,166, 0x80, 0x90,0x2F, 0,166, 0x80, 0x81, 0x90,0x34,
|
||||
0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x2F, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x36, 0x91,0x45, 0,166, 0x80,
|
||||
0x90,0x2F, 0,166, 0x80, 0x81, 0x90,0x33, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x2F, 0x91,0x42, 0,166, 0x80,
|
||||
0x81, 0x90,0x44, 0x91,0x34, 0,166, 0x81, 0x91,0x2F, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x36, 0,166, 0x81,
|
||||
0x82, 0x91,0x49, 0x92,0x2F, 0,166, 0x81, 0x82, 0x91,0x4A, 0x92,0x34, 0,166, 0x82, 0x92,0x2F, 0,166, 0x81,
|
||||
0x82, 0x91,0x49, 0x92,0x32, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x2F, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x31,
|
||||
0,166, 0x82, 0x92,0x2D, 0,166, 0x80, 0x82, 0x90,0x32, 0x92,0x41, 0,166, 0x80, 0x82, 0x90,0x42, 0x92,0x2D,
|
||||
0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x34, 0,166, 0x82, 0x92,0x2D, 0,166, 0x80, 0x82, 0x90,0x42, 0x92,0x31,
|
||||
0,166, 0x80, 0x82, 0x90,0x2D, 0x92,0x41, 0,166, 0x80, 0x82, 0x90,0x42, 0x92,0x32, 0,166, 0x82, 0x92,0x2D,
|
||||
0,166, 0x81, 0x82, 0x91,0x34, 0x92,0x45, 0,166, 0x81, 0x82, 0x91,0x2D, 0x92,0x47, 0,166, 0x81, 0x82, 0x91,0x32,
|
||||
0x92,0x49, 0,166, 0x81, 0x91,0x2D, 0,166, 0x81, 0x82, 0x91,0x31, 0x92,0x47, 0,166, 0x81, 0x82, 0x91,0x2D,
|
||||
0x92,0x45, 0,166, 0x81, 0x82, 0x91,0x30, 0x92,0x44, 0,166, 0x81, 0x91,0x2C, 0,166, 0x80, 0x81, 0x90,0x31,
|
||||
0x91,0x3F, 0,166, 0x80, 0x81, 0x90,0x2C, 0x91,0x41, 0,166, 0x80, 0x81, 0x90,0x33, 0x91,0x42, 0,166, 0x80,
|
||||
0x90,0x2C, 0,166, 0x80, 0x81, 0x90,0x30, 0x91,0x41, 0,166, 0x80, 0x81, 0x90,0x2C, 0x91,0x3F, 0,166, 0x80,
|
||||
0x81, 0x90,0x31, 0x91,0x41, 1,77, 0x81, 0x82, 0x91,0x44, 0x92,0x41, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x42,
|
||||
0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x44, 1,77, 0x81, 0x82, 0x91,0x45, 0x92,0x42, 0,166, 0x81, 0x82, 0x91,0x44,
|
||||
0x92,0x41, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x42, 1,77, 0x81, 0x91,0x46, 0,166, 0x81, 0x91,0x48, 0,166,
|
||||
0x81, 0x82, 0x91,0x49, 0x92,0x40, 1,77, 0x81, 0x91,0x48, 0,166, 0x81, 0x91,0x46, 0,166, 0x81, 0x82, 0x91,0x3F,
|
||||
0x92,0x48, 1,77, 0x82, 0x92,0x48, 0,166, 0x82, 0x92,0x49, 0,166, 0x81, 0x82, 0x91,0x4B, 0x92,0x42, 1,77,
|
||||
0x81, 0x91,0x49, 0,166, 0x81, 0x91,0x48, 0,166, 0x80, 0x81, 0x90,0x49, 0,166, 0x91,0x3E, 0,166, 0x80,
|
||||
0x81, 0x90,0x44, 0x91,0x3D, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x47, 0x91,0x3D,
|
||||
0x92,0x41, 0,166, 0x81, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x44,
|
||||
0x91,0x3D, 0,166, 0x80, 0x81, 0x82, 0x90,0x45, 0x91,0x42, 0x92,0x36, 0,166, 0x80, 0x81, 0x90,0x42, 0,166,
|
||||
0x80, 0x82, 0x90,0x44, 0x91,0x35, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x38,
|
||||
0,166, 0x80, 0x90,0x49, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x35,
|
||||
0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x36, 0,166, 0x92,0x49, 0,166, 0x82, 0x92,0x47, 0,166, 0x80, 0x90,0x4A,
|
||||
0,166, 0x80, 0x90,0x49, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x35,
|
||||
0,166, 0x80, 0x82, 0x90,0x49, 0x92,0x36, 0,166, 0x80, 0x81, 0x82, 0x90,0x38, 0x91,0x47, 0x92,0x41, 0,166,
|
||||
0x80, 0x90,0x31, 0,166, 0x80, 0x81, 0x82, 0x90,0x39, 0x91,0x42, 0x92,0x45, 0,166, 0x80, 0x90,0x31, 0,166,
|
||||
0x80, 0x82, 0x90,0x3B, 0x92,0x44, 0,166, 0x80, 0x90,0x31, 0,166, 0x80, 0x81, 0x90,0x3D, 0x91,0x41, 0,166,
|
||||
0x80, 0x90,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x39, 0x91,0x42, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x90,0x3D,
|
||||
0x92,0x49, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x82, 0x90,0x39, 0x92,0x4E, 0,166, 0x80, 0x90,0x38, 0,166,
|
||||
0x80, 0x81, 0x90,0x36, 0x91,0x45, 0,166, 0x80, 0x90,0x34, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x3B, 0,166,
|
||||
0x81, 0x91,0x3D, 0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x3E, 0,166, 0x82, 0x92,0x3D, 0,166, 0x81, 0x82, 0x91,0x50,
|
||||
0x92,0x3B, 0,166, 0x82, 0x92,0x39, 0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x38, 0,166, 0x82, 0x92,0x36, 0,166,
|
||||
0x80, 0x82, 0x90,0x4C, 0x92,0x3D, 0,166, 0x82, 0x92,0x3E, 0,166, 0x81, 0x82, 0x91,0x49, 0x92,0x40, 0,166,
|
||||
0x82, 0x92,0x3E, 0,166, 0x81, 0x82, 0x91,0x51, 0x92,0x3D, 0,166, 0x82, 0x92,0x3B, 0,166, 0x80, 0x82, 0x90,0x49,
|
||||
0x92,0x39, 0,166, 0x82, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x3F, 0x92,0x4E, 0,166, 0x80, 0x90,0x40, 0,166,
|
||||
0x80, 0x81, 0x90,0x42, 0x91,0x4B, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x3F, 0x91,0x53, 0,166,
|
||||
0x80, 0x90,0x3D, 0,166, 0x80, 0x81, 0x90,0x3B, 0x91,0x51, 0,166, 0x80, 0x90,0x39, 0,166, 0x80, 0x81, 0x90,0x50,
|
||||
0x91,0x40, 1,77, 0x80, 0x82, 0x90,0x50, 0x92,0x47, 0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x49, 0,166, 0x80,
|
||||
0x82, 0x90,0x53, 0x92,0x4A, 1,77, 0x80, 0x82, 0x90,0x51, 0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x50, 0x92,0x47,
|
||||
0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x49, 1,77, 0x82, 0x92,0x49, 0,166, 0x82, 0x92,0x4B, 0,166, 0x80,
|
||||
0x82, 0x90,0x50, 0x92,0x4C, 1,77, 0x82, 0x92,0x4B, 0,166, 0x82, 0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x4E,
|
||||
0x92,0x4B, 1,77, 0x82, 0x92,0x4B, 0,166, 0x82, 0x92,0x4C, 0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x4E, 1,77,
|
||||
0x82, 0x92,0x4C, 0,166, 0x82, 0x92,0x4B, 0,166, 0x82, 0x92,0x4C, 0,166, 0x81, 0x91,0x3D, 0,166, 0x80,
|
||||
0x81, 0x90,0x50, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x53, 0x91,0x38,
|
||||
0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x4E,
|
||||
0x91,0x32, 0,166, 0x80, 0x81, 0x82, 0x90,0x4C, 0x91,0x31, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x39, 0,166,
|
||||
0x80, 0x81, 0x90,0x49, 0x91,0x32, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x34,
|
||||
0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x31, 0,166, 0x80, 0x81, 0x90,0x4F,
|
||||
0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x32, 0x91,0x4E, 0,166, 0x80, 0x90,0x39, 0,166, 0x80, 0x90,0x34, 0x92,0x45,
|
||||
0,166, 0x80, 0x82, 0x90,0x39, 0x92,0x47, 0,166, 0x80, 0x82, 0x90,0x32, 0x92,0x49, 0,166, 0x80, 0x90,0x39,
|
||||
0,166, 0x80, 0x82, 0x90,0x31, 0x92,0x47, 0,166, 0x80, 0x82, 0x90,0x39, 0x92,0x45, 0,166, 0x80, 0x82, 0x90,0x2F,
|
||||
0x92,0x44, 0,166, 0x80, 0x90,0x38, 0,166, 0x80, 0x81, 0x90,0x31, 0x91,0x4A, 0,166, 0x80, 0x81, 0x90,0x38,
|
||||
0x91,0x4C, 0,166, 0x80, 0x81, 0x90,0x32, 0x91,0x4E, 0,166, 0x80, 0x90,0x38, 0,166, 0x80, 0x81, 0x90,0x2F,
|
||||
0x91,0x4C, 0,166, 0x80, 0x81, 0x90,0x38, 0x91,0x4A, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x31, 0,166, 0x81,
|
||||
0x91,0x38, 0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x32, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x38, 0,166, 0x81,
|
||||
0x82, 0x91,0x47, 0x92,0x31, 0,166, 0x82, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x2F, 0,166, 0x81,
|
||||
0x82, 0x91,0x44, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x2E, 0,166, 0x82, 0x92,0x36, 0,166, 0x80,
|
||||
0x82, 0x90,0x49, 0x92,0x2F, 0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x36, 0,166, 0x80, 0x82, 0x90,0x4C, 0x92,0x31,
|
||||
0,166, 0x82, 0x92,0x36, 0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x2E, 0,166, 0x80, 0x82, 0x90,0x49, 0x92,0x36,
|
||||
0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x2F, 0,166, 0x82, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x31,
|
||||
0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x2F, 0,166, 0x82, 0x92,0x36,
|
||||
0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x2D, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x2C,
|
||||
0x92,0x40, 0,166, 0x81, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x28, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x2A, 0,166, 0x81, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0x91,0x2C, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x2D, 0,166, 0x80,
|
||||
0x90,0x45, 0,166, 0x80, 0x81, 0x82, 0x90,0x4E, 0x91,0x2C, 0,166, 0x81, 0x91,0x45, 0x92,0x2D, 0,166, 0x81,
|
||||
0x82, 0x91,0x44, 0x92,0x2F, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x82, 0x90,0x4C, 0x92,0x2D, 0,166, 0x81,
|
||||
0x82, 0x91,0x44, 0x92,0x2C, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x2D, 0,166, 0x80, 0x90,0x49, 0,166, 0x80,
|
||||
0x90,0x4A, 0,166, 0x81, 0x91,0x42, 0,166, 0x81, 0x91,0x40, 0,166, 0x80, 0x82, 0x90,0x47, 0x92,0x2F, 0,166,
|
||||
0x80, 0x82, 0x90,0x49, 0x92,0x2C, 0,166, 0x81, 0x82, 0x91,0x2D, 0x92,0x40, 0,166, 0x80, 0x81, 0x82, 0x90,0x2F,
|
||||
0x91,0x44, 0x92,0x3E, 0,166, 0x80, 0x90,0x28, 0,166, 0x80, 0x81, 0x82, 0x90,0x31, 0x91,0x3D, 0x92,0x45, 0,166,
|
||||
0x80, 0x90,0x28, 0,166, 0x80, 0x81, 0x90,0x32, 0x91,0x3B, 0,166, 0x80, 0x90,0x28, 0,166, 0x80, 0x82, 0x90,0x34,
|
||||
0x92,0x44, 1,77, 0x80, 0x81, 0x82, 0x90,0x31, 0x91,0x45, 0x92,0x40, 0,166, 0x82, 0x92,0x3D, 0,166, 0x80,
|
||||
0x81, 0x82, 0x90,0x36, 0x91,0x44, 0x92,0x3E, 0,166, 0x81, 0x91,0x45, 0,166, 0x81, 0x91,0x47, 0,166, 0x82,
|
||||
0x92,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x35, 0x91,0x45, 0x92,0x3D, 0,166, 0x81, 0x91,0x44, 0,166, 0x80,
|
||||
0x81, 0x90,0x45, 0x91,0x36, 0,166, 0x82, 0x92,0x39, 0,166, 0x82, 0x92,0x3B, 0,166, 0x82, 0x92,0x38, 0,166,
|
||||
0x82, 0x92,0x39, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x44, 0x91,0x34, 0,166, 0x80, 0x90,0x45,
|
||||
0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x32, 0,166, 0x80, 0x82, 0x90,0x38, 0x92,0x40, 0,166, 0x80, 0x81, 0x82,
|
||||
0x90,0x49, 0x91,0x31, 0x92,0x39, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x2F, 0,166,
|
||||
0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x82, 0x90,0x4C, 0x91,0x34, 0x92,0x38, 1,77, 0x80, 0x81, 0x82, 0x90,0x49,
|
||||
0x91,0x39, 0x92,0x2D, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3D, 0,166, 0x80, 0x90,0x47,
|
||||
0,166, 0x80, 0x81, 0x82, 0x90,0x49, 0x91,0x42, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x90,0x4C, 0x92,0x39,
|
||||
0,166, 0x80, 0x90,0x4E, 0,166, 0x80, 0x82, 0x90,0x47, 0x92,0x38, 0,166, 0x80, 0x90,0x45, 0,166, 0x80,
|
||||
0x81, 0x90,0x44, 0x91,0x3B, 0,166, 0x80, 0x90,0x45, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x40, 0,166, 0x80,
|
||||
0x90,0x49, 0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x38, 0,166, 0x80, 0x90,0x4C, 0,166, 0x80, 0x82, 0x90,0x45,
|
||||
0x92,0x36, 0,166, 0x80, 0x90,0x44, 0,166, 0x80, 0x81, 0x90,0x42, 0x91,0x39, 0,166, 0x80, 0x90,0x44, 0,166,
|
||||
0x80, 0x81, 0x90,0x45, 0x91,0x3E, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x82, 0x90,0x49, 0x92,0x36, 0,166,
|
||||
0x80, 0x90,0x4A, 0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x34, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x44,
|
||||
0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x3D, 0x91,0x40, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x3E, 1,77, 0x81,
|
||||
0x91,0x3D, 0,166, 0x81, 0x91,0x3B, 0,166, 0x81, 0x91,0x3D, 0,166, 0x80, 0x90,0x4C, 0,166, 0x80, 0x81,
|
||||
0x90,0x49, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x3D, 1,77,
|
||||
0x81, 0x91,0x3B, 0,166, 0x81, 0x91,0x39, 0,166, 0x81, 0x91,0x3B, 0,166, 0x80, 0x90,0x47, 0,166, 0x80,
|
||||
0x81, 0x90,0x4A, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x3B,
|
||||
1,77, 0x81, 0x91,0x39, 0,166, 0x81, 0x91,0x38, 0,166, 0x81, 0x91,0x39, 0,166, 0x80, 0x90,0x45, 0,166,
|
||||
0x80, 0x81, 0x90,0x49, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x39,
|
||||
1,77, 0x81, 0x91,0x38, 0,166, 0x81, 0x91,0x36, 0,166, 0x81, 0x91,0x38, 0,166, 0x80, 0x82, 0x90,0x4C,
|
||||
0x92,0x34, 0,166, 0x80, 0x81, 0x82, 0x90,0x4B, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x3B, 0,166,
|
||||
0x80, 0x81, 0x90,0x4E, 0x91,0x45, 0x92,0x3C, 0,166, 0x82, 0x92,0x38, 0,166, 0x80, 0x81, 0x82, 0x90,0x39, 0,166,
|
||||
0x80, 0x90,0x33, 0,166, 0x80, 0x90,0x49, 0x91,0x45, 0x92,0x34, 0,13, 1,29, 0,246, 0x80, 0x81, 0x90,0x4A,
|
||||
0x91,0x47, 0,53, 0,141, 0x80, 0x81, 0x82, 0x90,0x47, 0x91,0x44, 0x92,0x28, 0,95, 1,77, 0,202,
|
||||
0x80, 0x81, 0x90,0x45, 0,91, 0,136, 0x80, 0x82, 0x90,0x45, 0x91,0x2D, 7,83, 0x80, 0x81, 0xf0};
|
||||
|
||||
Arduboy arduboy;
|
||||
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
arduboy.setTextSize(4);
|
||||
arduboy.setCursor(0,0);
|
||||
arduboy.print("Music\nDemo");
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
void loop ()
|
||||
{
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
if (arduboy.pressed(UP_BUTTON)) {
|
||||
y-=1;
|
||||
} else if (arduboy.pressed(DOWN_BUTTON)) {
|
||||
y+=1;
|
||||
} else if (arduboy.pressed(LEFT_BUTTON)) {
|
||||
x-=1;
|
||||
} else if (arduboy.pressed(RIGHT_BUTTON)) {
|
||||
x+=1;
|
||||
}
|
||||
|
||||
if (arduboy.pressed(A_BUTTON)) {
|
||||
arduboy.invert(true);
|
||||
} else if (arduboy.pressed(B_BUTTON)) {
|
||||
arduboy.invert(false);
|
||||
}
|
||||
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(x,y);
|
||||
arduboy.print("Music\nDemo");
|
||||
arduboy.display();
|
||||
|
||||
// play the tune if we aren't already
|
||||
if (!arduboy.tunes.playing())
|
||||
arduboy.tunes.playScore(score);
|
||||
}
|
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 434 B |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "Arduboy",
|
||||
"keywords": "arduboy, game",
|
||||
"description": "This library is for content creation on the Arduboy, a portable gaming platform",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/Arduboy/Arduboy.git"
|
||||
},
|
||||
"version": "1.1.1",
|
||||
"exclude": "extras",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "atmelavr"
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Arduboy
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Arduboy KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
allPixelsOn KEYWORD2
|
||||
blank KEYWORD2
|
||||
clear KEYWORD2
|
||||
cpuLoad KEYWORD2
|
||||
display KEYWORD2
|
||||
drawBitmap KEYWORD2
|
||||
drawChar KEYWORD2
|
||||
drawCircle KEYWORD2
|
||||
drawFastHLine KEYWORD2
|
||||
drawFastVLine KEYWORD2
|
||||
drawLine KEYWORD2
|
||||
drawPixel KEYWORD2
|
||||
drawRect KEYWORD2
|
||||
drawRoundRect KEYWORD2
|
||||
drawSlowXYBitmap KEYWORD2
|
||||
drawTriangle KEYWORD2
|
||||
everyXFrames KEYWORD2
|
||||
fillCircle KEYWORD2
|
||||
fillRect KEYWORD2
|
||||
fillRoundRect KEYWORD2
|
||||
fillScreen KEYWORD2
|
||||
fillTriangle KEYWORD2
|
||||
flipVertical KEYWORD2
|
||||
flipHorizontal KEYWORD2
|
||||
getBuffer KEYWORD2
|
||||
getInput KEYWORD2
|
||||
idle KEYWORD2
|
||||
initRandomSeed KEYWORD2
|
||||
invert KEYWORD2
|
||||
nextFrame KEYWORD2
|
||||
notPressed KEYWORD2
|
||||
paint8Pixels KEYWORD2
|
||||
paintScreen KEYWORD2
|
||||
pressed KEYWORD2
|
||||
setCursor KEYWORD2
|
||||
setFrameRate KEYWORD2
|
||||
setRGBled KEYWORD2
|
||||
setTextSize KEYWORD2
|
||||
setTextWrap KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
BLACK LITERAL1
|
||||
WHITE LITERAL1
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
name=Arduboy
|
||||
version=1.1.1
|
||||
author=Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen, Ross O. Shoger
|
||||
maintainer=Ross O. Shoger ross@arduboy.com
|
||||
sentence=The Arduboy core library.
|
||||
paragraph=This library is for content creation on the Arduboy, a portable gaming platform. The library provides access to the sound, display, and input of the Arduboy.
|
||||
category=Other
|
||||
url=https://github.com/arduboy/arduboy
|
||||
architectures=avr
|
||||
includes=Arduboy.h
|
|
@ -0,0 +1,774 @@
|
|||
#include "Arduboy.h"
|
||||
#include "glcdfont.c"
|
||||
#include "ab_logo.c"
|
||||
|
||||
Arduboy::Arduboy()
|
||||
{
|
||||
// frame management
|
||||
setFrameRate(60);
|
||||
frameCount = 0;
|
||||
nextFrameStart = 0;
|
||||
post_render = false;
|
||||
// init not necessary, will be reset after first use
|
||||
// lastFrameStart
|
||||
// lastFrameDurationMs
|
||||
|
||||
// font rendering
|
||||
cursor_x = 0;
|
||||
cursor_y = 0;
|
||||
textsize = 1;
|
||||
}
|
||||
|
||||
void Arduboy::start() // deprecated
|
||||
{
|
||||
begin();
|
||||
}
|
||||
|
||||
void Arduboy::begin()
|
||||
{
|
||||
boot(); // required
|
||||
bootUtils();
|
||||
|
||||
bootLogo();
|
||||
|
||||
// Audio
|
||||
tunes.initChannel(PIN_SPEAKER_1);
|
||||
tunes.initChannel(PIN_SPEAKER_2);
|
||||
audio.begin();
|
||||
}
|
||||
|
||||
// this is pusposely duplicated (without logo) so that
|
||||
// whichever is actually used is linked and the one
|
||||
// that is not is gone without wasting any space in flash
|
||||
void Arduboy::beginNoLogo()
|
||||
{
|
||||
boot(); // required
|
||||
bootUtils();
|
||||
|
||||
// Audio
|
||||
tunes.initChannel(PIN_SPEAKER_1);
|
||||
tunes.initChannel(PIN_SPEAKER_2);
|
||||
audio.begin();
|
||||
}
|
||||
|
||||
void Arduboy::bootUtils()
|
||||
{
|
||||
// flashlight
|
||||
if(pressed(UP_BUTTON)) {
|
||||
// sendLCDCommand(OLED_ALL_PIXELS_ON); // smaller than allPixelsOn()
|
||||
blank();
|
||||
setRGBled(255,255,255);
|
||||
while(true) {}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::bootLogo()
|
||||
{
|
||||
// setRGBled(10,0,0);
|
||||
for(int8_t y = -18; y<=24; y++) {
|
||||
setRGBled(24-y, 0, 0);
|
||||
|
||||
clear();
|
||||
drawBitmap(20,y, arduboy_logo, 88, 16, WHITE);
|
||||
display();
|
||||
delay(27);
|
||||
// longer delay post boot, we put it inside the loop to
|
||||
// save the flash calling clear/delay again outside the loop
|
||||
if (y==-16) {
|
||||
delay(250);
|
||||
}
|
||||
}
|
||||
|
||||
delay(750);
|
||||
setRGBled(0,0,0);
|
||||
}
|
||||
|
||||
/* Frame management */
|
||||
|
||||
void Arduboy::setFrameRate(uint8_t rate)
|
||||
{
|
||||
frameRate = rate;
|
||||
eachFrameMillis = 1000/rate;
|
||||
}
|
||||
|
||||
bool Arduboy::everyXFrames(uint8_t frames)
|
||||
{
|
||||
return frameCount % frames == 0;
|
||||
}
|
||||
|
||||
bool Arduboy::nextFrame()
|
||||
{
|
||||
long now = millis();
|
||||
uint8_t remaining;
|
||||
|
||||
// post render
|
||||
if (post_render) {
|
||||
lastFrameDurationMs = now - lastFrameStart;
|
||||
frameCount++;
|
||||
post_render = false;
|
||||
}
|
||||
|
||||
// if it's not time for the next frame yet
|
||||
if (now < nextFrameStart) {
|
||||
remaining = nextFrameStart - now;
|
||||
// if we have more than 1ms to spare, lets sleep
|
||||
// we should be woken up by timer0 every 1ms, so this should be ok
|
||||
if (remaining > 1)
|
||||
idle();
|
||||
return false;
|
||||
}
|
||||
|
||||
// pre-render
|
||||
|
||||
// technically next frame should be last frame + each frame but if we're
|
||||
// running a slow render we would constnatly be behind the clock
|
||||
// keep an eye on this and see how it works. If it works well the
|
||||
// lastFrameStart variable could be eliminated completely
|
||||
nextFrameStart = now + eachFrameMillis;
|
||||
lastFrameStart = now;
|
||||
post_render = true;
|
||||
return post_render;
|
||||
}
|
||||
|
||||
int Arduboy::cpuLoad()
|
||||
{
|
||||
return lastFrameDurationMs*100 / eachFrameMillis;
|
||||
}
|
||||
|
||||
void Arduboy::initRandomSeed()
|
||||
{
|
||||
power_adc_enable(); // ADC on
|
||||
randomSeed(~rawADC(ADC_TEMP) * ~rawADC(ADC_VOLTAGE) * ~micros() + micros());
|
||||
power_adc_disable(); // ADC off
|
||||
}
|
||||
|
||||
uint16_t Arduboy::rawADC(byte adc_bits)
|
||||
{
|
||||
ADMUX = adc_bits;
|
||||
// we also need MUX5 for temperature check
|
||||
if (adc_bits == ADC_TEMP) {
|
||||
ADCSRB = _BV(MUX5);
|
||||
}
|
||||
|
||||
delay(2); // Wait for ADMUX setting to settle
|
||||
ADCSRA |= _BV(ADSC); // Start conversion
|
||||
while (bit_is_set(ADCSRA,ADSC)); // measuring
|
||||
|
||||
return ADC;
|
||||
}
|
||||
|
||||
/* Graphics */
|
||||
|
||||
void Arduboy::clearDisplay() // deprecated
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void Arduboy::clear()
|
||||
{
|
||||
fillScreen(BLACK);
|
||||
}
|
||||
|
||||
void Arduboy::drawPixel(int x, int y, uint8_t color)
|
||||
{
|
||||
#ifdef PIXEL_SAFE_MODE
|
||||
if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t row = (uint8_t)y / 8;
|
||||
if (color)
|
||||
{
|
||||
sBuffer[(row*WIDTH) + (uint8_t)x] |= _BV((uint8_t)y % 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sBuffer[(row*WIDTH) + (uint8_t)x] &= ~ _BV((uint8_t)y % 8);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Arduboy::getPixel(uint8_t x, uint8_t y)
|
||||
{
|
||||
uint8_t row = y / 8;
|
||||
uint8_t bit_position = y % 8;
|
||||
return (sBuffer[(row*WIDTH) + x] & _BV(bit_position)) >> bit_position;
|
||||
}
|
||||
|
||||
void Arduboy::drawCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color)
|
||||
{
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
drawPixel(x0, y0+r, color);
|
||||
drawPixel(x0, y0-r, color);
|
||||
drawPixel(x0+r, y0, color);
|
||||
drawPixel(x0-r, y0, color);
|
||||
|
||||
while (x<y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawCircleHelper
|
||||
(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, uint8_t color)
|
||||
{
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x<y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
if (cornername & 0x4)
|
||||
{
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
}
|
||||
if (cornername & 0x2)
|
||||
{
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
}
|
||||
if (cornername & 0x8)
|
||||
{
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
}
|
||||
if (cornername & 0x1)
|
||||
{
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color)
|
||||
{
|
||||
drawFastVLine(x0, y0-r, 2*r+1, color);
|
||||
fillCircleHelper(x0, y0, r, 3, 0, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillCircleHelper
|
||||
(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, int16_t delta,
|
||||
uint8_t color)
|
||||
{
|
||||
// used to do circles and roundrects!
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x < y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
if (cornername & 0x1)
|
||||
{
|
||||
drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
|
||||
if (cornername & 0x2)
|
||||
{
|
||||
drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawLine
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color)
|
||||
{
|
||||
// bresenham's algorithm - thx wikpedia
|
||||
boolean steep = abs(y1 - y0) > abs(x1 - x0);
|
||||
if (steep) {
|
||||
swap(x0, y0);
|
||||
swap(x1, y1);
|
||||
}
|
||||
|
||||
if (x0 > x1) {
|
||||
swap(x0, x1);
|
||||
swap(y0, y1);
|
||||
}
|
||||
|
||||
int16_t dx, dy;
|
||||
dx = x1 - x0;
|
||||
dy = abs(y1 - y0);
|
||||
|
||||
int16_t err = dx / 2;
|
||||
int8_t ystep;
|
||||
|
||||
if (y0 < y1)
|
||||
{
|
||||
ystep = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ystep = -1;
|
||||
}
|
||||
|
||||
for (; x0 <= x1; x0++)
|
||||
{
|
||||
if (steep)
|
||||
{
|
||||
drawPixel(y0, x0, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawPixel(x0, y0, color);
|
||||
}
|
||||
|
||||
err -= dy;
|
||||
if (err < 0)
|
||||
{
|
||||
y0 += ystep;
|
||||
err += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color)
|
||||
{
|
||||
drawFastHLine(x, y, w, color);
|
||||
drawFastHLine(x, y+h-1, w, color);
|
||||
drawFastVLine(x, y, h, color);
|
||||
drawFastVLine(x+w-1, y, h, color);
|
||||
}
|
||||
|
||||
void Arduboy::drawFastVLine
|
||||
(int16_t x, int16_t y, uint8_t h, uint8_t color)
|
||||
{
|
||||
int end = y+h;
|
||||
for (int a = max(0,y); a < min(end,HEIGHT); a++)
|
||||
{
|
||||
drawPixel(x,a,color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawFastHLine
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t color)
|
||||
{
|
||||
int end = x+w;
|
||||
for (int a = max(0,x); a < min(end,WIDTH); a++)
|
||||
{
|
||||
drawPixel(a,y,color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color)
|
||||
{
|
||||
// stupidest version - update in subclasses if desired!
|
||||
for (int16_t i=x; i<x+w; i++)
|
||||
{
|
||||
drawFastVLine(i, y, h, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillScreen(uint8_t color)
|
||||
{
|
||||
// C version:
|
||||
//
|
||||
// if (color != BLACK)
|
||||
// {
|
||||
// color = 0xFF; // all pixels on
|
||||
// }
|
||||
// for (int16_t i = 0; i < WIDTH * HEIGTH / 8; i++)
|
||||
// {
|
||||
// sBuffer[i] = color;
|
||||
// }
|
||||
|
||||
// This asm version is semi hard coded for 128x64, 96x96 and 128x96 resolutions
|
||||
|
||||
// local variable for screen buffer pointer,
|
||||
// which can be declared a read-write operand
|
||||
uint8_t* bPtr = sBuffer;
|
||||
|
||||
asm volatile
|
||||
(
|
||||
// if value is zero, skip assigning to 0xff
|
||||
"cpse %[color], __zero_reg__\n"
|
||||
"ldi %[color], 0xFF\n"
|
||||
// counter = WIDTH * HEIGHT / 8 / 8
|
||||
"ldi r24, %[cnt]\n"
|
||||
"loopto:\n"
|
||||
// (4x/8x) store color into screen buffer,
|
||||
// then increment buffer position
|
||||
"st Z+, %[color]\n"
|
||||
"st Z+, %[color]\n"
|
||||
"st Z+, %[color]\n"
|
||||
"st Z+, %[color]\n"
|
||||
#if defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128) || defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128)
|
||||
"st Z+, %[color]\n"
|
||||
"st Z+, %[color]\n"
|
||||
"st Z+, %[color]\n"
|
||||
"st Z+, %[color]\n"
|
||||
#endif
|
||||
// decrease counter
|
||||
"subi r24, 1\n"
|
||||
// repeat for 256, 144 or 192 loops depending on screen resolution
|
||||
"brcc loopto\n"
|
||||
: [color] "+d" (color),
|
||||
"+z" (bPtr)
|
||||
#if defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128) || defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128)
|
||||
: [cnt] "M" (WIDTH * HEIGHT / 8 / 8 - 1)
|
||||
#else
|
||||
: [cnt] "M" (WIDTH * HEIGHT / 8 / 4 - 1)
|
||||
#endif
|
||||
: "r24"
|
||||
);
|
||||
}
|
||||
|
||||
void Arduboy::drawRoundRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color)
|
||||
{
|
||||
// smarter version
|
||||
drawFastHLine(x+r, y, w-2*r, color); // Top
|
||||
drawFastHLine(x+r, y+h-1, w-2*r, color); // Bottom
|
||||
drawFastVLine(x, y+r, h-2*r, color); // Left
|
||||
drawFastVLine(x+w-1, y+r, h-2*r, color); // Right
|
||||
// draw four corners
|
||||
drawCircleHelper(x+r, y+r, r, 1, color);
|
||||
drawCircleHelper(x+w-r-1, y+r, r, 2, color);
|
||||
drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
|
||||
drawCircleHelper(x+r, y+h-r-1, r, 8, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillRoundRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color)
|
||||
{
|
||||
// smarter version
|
||||
fillRect(x+r, y, w-2*r, h, color);
|
||||
|
||||
// draw four corners
|
||||
fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
|
||||
fillCircleHelper(x+r, y+r, r, 2, h-2*r-1, color);
|
||||
}
|
||||
|
||||
void Arduboy::drawTriangle
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
|
||||
{
|
||||
drawLine(x0, y0, x1, y1, color);
|
||||
drawLine(x1, y1, x2, y2, color);
|
||||
drawLine(x2, y2, x0, y0, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillTriangle
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
|
||||
{
|
||||
|
||||
int16_t a, b, y, last;
|
||||
// Sort coordinates by Y order (y2 >= y1 >= y0)
|
||||
if (y0 > y1)
|
||||
{
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
if (y1 > y2)
|
||||
{
|
||||
swap(y2, y1); swap(x2, x1);
|
||||
}
|
||||
if (y0 > y1)
|
||||
{
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
|
||||
if(y0 == y2)
|
||||
{ // Handle awkward all-on-same-line case as its own thing
|
||||
a = b = x0;
|
||||
if(x1 < a)
|
||||
{
|
||||
a = x1;
|
||||
}
|
||||
else if(x1 > b)
|
||||
{
|
||||
b = x1;
|
||||
}
|
||||
if(x2 < a)
|
||||
{
|
||||
a = x2;
|
||||
}
|
||||
else if(x2 > b)
|
||||
{
|
||||
b = x2;
|
||||
}
|
||||
drawFastHLine(a, y0, b-a+1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t dx01 = x1 - x0,
|
||||
dy01 = y1 - y0,
|
||||
dx02 = x2 - x0,
|
||||
dy02 = y2 - y0,
|
||||
dx12 = x2 - x1,
|
||||
dy12 = y2 - y1,
|
||||
sa = 0,
|
||||
sb = 0;
|
||||
|
||||
// For upper part of triangle, find scanline crossings for segments
|
||||
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
|
||||
// is included here (and second loop will be skipped, avoiding a /0
|
||||
// error there), otherwise scanline y1 is skipped here and handled
|
||||
// in the second loop...which also avoids a /0 error here if y0=y1
|
||||
// (flat-topped triangle).
|
||||
if (y1 == y2)
|
||||
{
|
||||
last = y1; // Include y1 scanline
|
||||
}
|
||||
else
|
||||
{
|
||||
last = y1-1; // Skip it
|
||||
}
|
||||
|
||||
|
||||
for(y = y0; y <= last; y++)
|
||||
{
|
||||
a = x0 + sa / dy01;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx01;
|
||||
sb += dx02;
|
||||
|
||||
if(a > b)
|
||||
{
|
||||
swap(a,b);
|
||||
}
|
||||
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
|
||||
// For lower part of triangle, find scanline crossings for segments
|
||||
// 0-2 and 1-2. This loop is skipped if y1=y2.
|
||||
sa = dx12 * (y - y1);
|
||||
sb = dx02 * (y - y0);
|
||||
|
||||
for(; y <= y2; y++)
|
||||
{
|
||||
a = x1 + sa / dy12;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx12;
|
||||
sb += dx02;
|
||||
|
||||
if(a > b)
|
||||
{
|
||||
swap(a,b);
|
||||
}
|
||||
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawBitmap
|
||||
(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h,
|
||||
uint8_t color)
|
||||
{
|
||||
// no need to dar at all of we're offscreen
|
||||
if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
|
||||
return;
|
||||
|
||||
int yOffset = abs(y) % 8;
|
||||
int sRow = y / 8;
|
||||
if (y < 0) {
|
||||
sRow--;
|
||||
yOffset = 8 - yOffset;
|
||||
}
|
||||
int rows = h/8;
|
||||
if (h%8!=0) rows++;
|
||||
for (int a = 0; a < rows; a++) {
|
||||
int bRow = sRow + a;
|
||||
if (bRow > (HEIGHT/8)-1) break;
|
||||
if (bRow > -2) {
|
||||
for (int iCol = 0; iCol<w; iCol++) {
|
||||
if (iCol + x > (WIDTH-1)) break;
|
||||
if (iCol + x >= 0) {
|
||||
if (bRow >= 0) {
|
||||
if (color == WHITE) this->sBuffer[ (bRow*WIDTH) + x + iCol ] |= pgm_read_byte(bitmap+(a*w)+iCol) << yOffset;
|
||||
else if (color == BLACK) this->sBuffer[ (bRow*WIDTH) + x + iCol ] &= ~(pgm_read_byte(bitmap+(a*w)+iCol) << yOffset);
|
||||
else this->sBuffer[ (bRow*WIDTH) + x + iCol ] ^= pgm_read_byte(bitmap+(a*w)+iCol) << yOffset;
|
||||
}
|
||||
if (yOffset && bRow<(HEIGHT/8)-1 && bRow > -2) {
|
||||
if (color == WHITE) this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] |= pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset);
|
||||
else if (color == BLACK) this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] &= ~(pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset));
|
||||
else this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] ^= pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Arduboy::drawSlowXYBitmap
|
||||
(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color)
|
||||
{
|
||||
// no need to dar at all of we're offscreen
|
||||
if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
|
||||
return;
|
||||
|
||||
int16_t xi, yi, byteWidth = (w + 7) / 8;
|
||||
for(yi = 0; yi < h; yi++) {
|
||||
for(xi = 0; xi < w; xi++ ) {
|
||||
if(pgm_read_byte(bitmap + yi * byteWidth + xi / 8) & (128 >> (xi & 7))) {
|
||||
drawPixel(x + xi, y + yi, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Arduboy::drawChar
|
||||
(int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size)
|
||||
{
|
||||
boolean draw_background = bg != color;
|
||||
|
||||
if ((x >= WIDTH) || // Clip right
|
||||
(y >= HEIGHT) || // Clip bottom
|
||||
((x + 5 * size - 1) < 0) || // Clip left
|
||||
((y + 8 * size - 1) < 0) // Clip top
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int8_t i=0; i<6; i++ )
|
||||
{
|
||||
uint8_t line;
|
||||
if (i == 5)
|
||||
{
|
||||
line = 0x0;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = pgm_read_byte(font+(c*5)+i);
|
||||
}
|
||||
|
||||
for (int8_t j = 0; j<8; j++)
|
||||
{
|
||||
uint8_t draw_color = (line & 0x1) ? color : bg;
|
||||
|
||||
if (draw_color || draw_background) {
|
||||
for (uint8_t a = 0; a < size; a++ ) {
|
||||
for (uint8_t b = 0; b < size; b++ ) {
|
||||
drawPixel(x + (i * size) + a, y + (j * size) + b, draw_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
line >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::setCursor(int16_t x, int16_t y)
|
||||
{
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
void Arduboy::setTextSize(uint8_t s)
|
||||
{
|
||||
// textsize must always be 1 or higher
|
||||
textsize = max(1,s);
|
||||
}
|
||||
|
||||
void Arduboy::setTextWrap(boolean w)
|
||||
{
|
||||
wrap = w;
|
||||
}
|
||||
|
||||
size_t Arduboy::write(uint8_t c)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
cursor_y += textsize*8;
|
||||
cursor_x = 0;
|
||||
}
|
||||
else if (c == '\r')
|
||||
{
|
||||
// skip em
|
||||
}
|
||||
else
|
||||
{
|
||||
drawChar(cursor_x, cursor_y, c, 1, 0, textsize);
|
||||
cursor_x += textsize*6;
|
||||
if (wrap && (cursor_x > (WIDTH - textsize*6)))
|
||||
{
|
||||
// calling ourselves recursively for 'newline' is
|
||||
// 12 bytes smaller than doing the same math here
|
||||
write('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::display()
|
||||
{
|
||||
this->paintScreen(sBuffer);
|
||||
}
|
||||
|
||||
unsigned char* Arduboy::getBuffer()
|
||||
{
|
||||
return sBuffer;
|
||||
}
|
||||
|
||||
|
||||
boolean Arduboy::pressed(uint8_t buttons)
|
||||
{
|
||||
return (buttonsState() & buttons) == buttons;
|
||||
}
|
||||
|
||||
boolean Arduboy::notPressed(uint8_t buttons)
|
||||
{
|
||||
return (buttonsState() & buttons) == 0;
|
||||
}
|
||||
|
||||
void Arduboy::swap(int16_t& a, int16_t& b)
|
||||
{
|
||||
int temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
#ifndef Arduboy_h
|
||||
#define Arduboy_h
|
||||
|
||||
#include "core/core.h"
|
||||
#include <SPI.h>
|
||||
#include <Print.h>
|
||||
#include <limits.h>
|
||||
|
||||
/// Library version.
|
||||
/**
|
||||
* A version number, 'x.y.z', is stored in the form xxyyzz,
|
||||
* where ((x * 10000) + (y * 100) + (z)),
|
||||
* resulting in 'xxxyyzz', with no leading zeros.
|
||||
*/
|
||||
#define ARDUBOY_LIB_VER 10101 // 1.1.1
|
||||
|
||||
// EEPROM settings
|
||||
#define EEPROM_VERSION 0
|
||||
#define EEPROM_BRIGHTNESS 1
|
||||
#define EEPROM_AUDIO_ON_OFF 2
|
||||
|
||||
// we reserve the first 16 byte of EEPROM for system use
|
||||
#define EEPROM_STORAGE_SPACE_START 16 // and onward
|
||||
|
||||
// eeprom settings above are neded for audio
|
||||
#include "audio/audio.h"
|
||||
|
||||
#define PIXEL_SAFE_MODE
|
||||
|
||||
// compare Vcc to 1.1 bandgap
|
||||
#define ADC_VOLTAGE (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1))
|
||||
// compare temperature to 2.5 internal reference and _BV(MUX5)
|
||||
#define ADC_TEMP (_BV(REFS0) | _BV(REFS1) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0))
|
||||
|
||||
class Arduboy : public Print, public ArduboyCore
|
||||
{
|
||||
public:
|
||||
Arduboy();
|
||||
|
||||
/// Returns true if the button mask passed in is pressed.
|
||||
/**
|
||||
* if (pressed(LEFT_BUTTON + A_BUTTON))
|
||||
*/
|
||||
boolean pressed(uint8_t buttons);
|
||||
|
||||
/// Returns true if the button mask passed in not pressed.
|
||||
/**
|
||||
* if (notPressed(LEFT_BUTTON))
|
||||
*/
|
||||
boolean notPressed(uint8_t buttons);
|
||||
|
||||
/// Initializes the hardware
|
||||
void begin();
|
||||
/// Initializes the hardware (but with no boot logo)
|
||||
void beginNoLogo();
|
||||
void start() __attribute__ ((deprecated("use begin() instead")));
|
||||
|
||||
/// Scrolls in the Arduboy logo
|
||||
void bootLogo();
|
||||
|
||||
/// Boot utils such as flashlight, etc
|
||||
void inline bootUtils() __attribute__((always_inline));
|
||||
|
||||
/// Clears display.
|
||||
void clear();
|
||||
void clearDisplay() __attribute__ ((deprecated("use clear() instead")));
|
||||
|
||||
/// Copies the contents of the screen buffer to the screen.
|
||||
/**
|
||||
* X and Y positions on the display are from the top left corner, thus a Y of 64
|
||||
* is the bottom of the screen and an X of 128 is the right side of the screen.
|
||||
* "Color" or "value" means choosing whether a pixel is lit or not - if color is
|
||||
* 0, the pixel is off (black), if color is 1, the pixel is on (white).
|
||||
*/
|
||||
void display();
|
||||
|
||||
/// Sets a single pixel on the screen buffer to white or black.
|
||||
void drawPixel(int x, int y, uint8_t color);
|
||||
|
||||
uint8_t getPixel(uint8_t x, uint8_t y);
|
||||
|
||||
/// Draw a circle of a defined radius.
|
||||
/**
|
||||
* Draws a circle in white or black. X and Y are the center point of the circle.
|
||||
*/
|
||||
void drawCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws one or more "corners" of a circle.
|
||||
void drawCircleHelper(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, uint8_t color);
|
||||
|
||||
/// Draws a filled-in circle.
|
||||
void fillCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws one or both vertical halves of a filled-in circle.
|
||||
void fillCircleHelper(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, int16_t delta, uint8_t color);
|
||||
|
||||
/// Draws a line between two points.
|
||||
/**
|
||||
* Uses Bresenham's algorithm.
|
||||
*/
|
||||
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color);
|
||||
|
||||
/// Draws a rectangle of a width and height.
|
||||
void drawRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws vertical line.
|
||||
void drawFastVLine(int16_t x, int16_t y, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws a horizontal line.
|
||||
void drawFastHLine(int16_t x, int16_t y, uint8_t w, uint8_t color);
|
||||
|
||||
/// Draws a filled-in rectangle.
|
||||
void fillRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Fills the screen buffer with white or black.
|
||||
void fillScreen(uint8_t color);
|
||||
|
||||
/// Draws a rectangle with rounded edges.
|
||||
void drawRoundRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws a filled-in rectangle with rounded edges.
|
||||
void fillRoundRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws the outline of a triangle.
|
||||
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color);
|
||||
|
||||
/// Draws a filled-in triangle.
|
||||
void fillTriangle (int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color);
|
||||
|
||||
/// Draws a bitmap from program memory to a specific X/Y
|
||||
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws images that are bit-oriented horizontally.
|
||||
/**
|
||||
* This requires a lot of additional CPU power and will draw images slower
|
||||
* than drawBitmap, where the images are stored in a format that
|
||||
* allows them to be directly written to the screen. It is
|
||||
* recommended you use drawBitmap when possible.
|
||||
*/
|
||||
void drawSlowXYBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws an ASCII character at a point.
|
||||
void drawChar(int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size);
|
||||
|
||||
/// Sets the location of the screen cursor.
|
||||
void setCursor(int16_t x, int16_t y);
|
||||
|
||||
/// Set text size
|
||||
/**
|
||||
* As mentioned in drawChar(), individual ASCII characters are 6x8 pixels
|
||||
* (5x7 with spacing on two edges). The size is a pixel multiplier,
|
||||
* so a size of 2 means each character will be 12x16, etc.
|
||||
*/
|
||||
void setTextSize(uint8_t s);
|
||||
|
||||
/// Sets whether text will wrap at screen edges.
|
||||
void setTextWrap(boolean w);
|
||||
|
||||
unsigned char* getBuffer();
|
||||
|
||||
/// Writes a single ASCII character to the screen.
|
||||
virtual size_t write(uint8_t);
|
||||
|
||||
/// Seeds the random number generator with entropy from the temperature, voltage reading, and microseconds since boot.
|
||||
/**
|
||||
* This method is still most effective when called semi-randomly such
|
||||
* as after a user hits a button to start a game or other semi-random
|
||||
* events
|
||||
*/
|
||||
void initRandomSeed();
|
||||
|
||||
/// Swap the references of two pointers.
|
||||
void swap(int16_t& a, int16_t& b);
|
||||
|
||||
ArduboyTunes tunes;
|
||||
ArduboyAudio audio;
|
||||
|
||||
void setFrameRate(uint8_t rate);
|
||||
bool nextFrame();
|
||||
bool everyXFrames(uint8_t frames);
|
||||
|
||||
/// Returns the load on the CPU as a percentage.
|
||||
/**
|
||||
* This is based on how much of the time your app is spends rendering
|
||||
* frames. This number can be higher than 100 if your app is rendering
|
||||
* really slowly.
|
||||
*/
|
||||
int cpuLoad();
|
||||
|
||||
uint8_t frameRate;
|
||||
uint16_t frameCount;
|
||||
uint8_t eachFrameMillis;
|
||||
long lastFrameStart;
|
||||
long nextFrameStart;
|
||||
bool post_render;
|
||||
uint8_t lastFrameDurationMs;
|
||||
|
||||
/// useful for getting raw approximate voltage values
|
||||
uint16_t rawADC(byte adc_bits);
|
||||
|
||||
protected:
|
||||
unsigned char sBuffer[(HEIGHT*WIDTH)/8];
|
||||
|
||||
|
||||
// Adafruit stuff
|
||||
protected:
|
||||
int16_t cursor_x;
|
||||
int16_t cursor_y;
|
||||
uint8_t textsize;
|
||||
boolean wrap; // If set, 'wrap' text at right edge of display
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
#include <avr/pgmspace.h>
|
||||
|
||||
#ifndef ARDUBOY_LOGO_CREATED
|
||||
#define ARDUBOY_LOGO_CREATED
|
||||
|
||||
// arduboy_logo.png
|
||||
// 88x16
|
||||
PROGMEM const unsigned char arduboy_logo[] = {
|
||||
0xF0, 0xF8, 0x9C, 0x8E, 0x87, 0x83, 0x87, 0x8E, 0x9C, 0xF8,
|
||||
0xF0, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFE, 0xFF, 0x83, 0x83, 0x83, 0x83, 0x83, 0xC7,
|
||||
0xEE, 0x7C, 0x38, 0x00, 0x00, 0xF8, 0xFC, 0x0E, 0x07, 0x03,
|
||||
0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0x3F, 0x7F,
|
||||
0xE0, 0xC0, 0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x3F, 0xFF, 0xFF,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x3E, 0x77,
|
||||
0xE3, 0xC1, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x3F, 0x70,
|
||||
0xE0, 0xC0, 0xC0, 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00,
|
||||
0x7F, 0xFF, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xE3, 0x77, 0x3E,
|
||||
0x1C, 0x00, 0x00, 0x1F, 0x3F, 0x70, 0xE0, 0xC0, 0xC0, 0xC0,
|
||||
0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,319 @@
|
|||
#include "Arduboy.h"
|
||||
#include "audio.h"
|
||||
|
||||
const byte PROGMEM tune_pin_to_timer_PGM[] = { 3, 1 };
|
||||
volatile byte *_tunes_timer1_pin_port;
|
||||
volatile byte _tunes_timer1_pin_mask;
|
||||
volatile int32_t timer1_toggle_count;
|
||||
volatile byte *_tunes_timer3_pin_port;
|
||||
volatile byte _tunes_timer3_pin_mask;
|
||||
byte _tune_pins[AVAILABLE_TIMERS];
|
||||
byte _tune_num_chans = 0;
|
||||
volatile boolean tune_playing; // is the score still playing?
|
||||
volatile unsigned wait_timer_frequency2; /* its current frequency */
|
||||
volatile boolean wait_timer_playing = false; /* is it currently playing a note? */
|
||||
volatile boolean tonePlaying = false;
|
||||
volatile unsigned long wait_toggle_count; /* countdown score waits */
|
||||
|
||||
// pointers to your musical score and your position in said score
|
||||
volatile const byte *score_start = 0;
|
||||
volatile const byte *score_cursor = 0;
|
||||
|
||||
// Table of midi note frequencies * 2
|
||||
// They are times 2 for greater accuracy, yet still fits in a word.
|
||||
// Generated from Excel by =ROUND(2*440/32*(2^((x-9)/12)),0) for 0<x<128
|
||||
// The lowest notes might not work, depending on the Arduino clock frequency
|
||||
// Ref: http://www.phy.mtu.edu/~suits/notefreqs.html
|
||||
const uint8_t PROGMEM _midi_byte_note_frequencies[48] = {
|
||||
16,17,18,19,21,22,23,24,26,28,29,31,33,35,37,39,41,44,46,49,52,55,58,62,65,
|
||||
69,73,78,82,87,92,98,104,110,117,123,131,139,147,156,165,175,185,196,208,220,
|
||||
233,247
|
||||
};
|
||||
const unsigned int PROGMEM _midi_word_note_frequencies[80] = {
|
||||
262,277,294,311,330,349,370,392,415,440,466,494,523,554,587,622,659,
|
||||
698,740,784,831,880,932,988,1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,
|
||||
1865,1976,2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,3951,4186,
|
||||
4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902,8372,8870,9397,9956,
|
||||
10548,11175,11840,12544,13290,14080,14917,15804,16744,17740,18795,19912,21096,
|
||||
22351,23680,25088 };
|
||||
|
||||
/* AUDIO */
|
||||
|
||||
bool ArduboyAudio::audio_enabled = false;
|
||||
|
||||
void ArduboyAudio::on()
|
||||
{
|
||||
power_timer1_enable();
|
||||
power_timer3_enable();
|
||||
audio_enabled = true;
|
||||
}
|
||||
|
||||
bool ArduboyAudio::enabled()
|
||||
{
|
||||
return audio_enabled;
|
||||
}
|
||||
|
||||
void ArduboyAudio::off()
|
||||
{
|
||||
audio_enabled = false;
|
||||
power_timer1_disable();
|
||||
power_timer3_disable();
|
||||
}
|
||||
|
||||
void ArduboyAudio::saveOnOff()
|
||||
{
|
||||
EEPROM.write(EEPROM_AUDIO_ON_OFF, audio_enabled);
|
||||
}
|
||||
|
||||
void ArduboyAudio::begin()
|
||||
{
|
||||
tune_playing = false;
|
||||
if (EEPROM.read(EEPROM_AUDIO_ON_OFF))
|
||||
on();
|
||||
}
|
||||
|
||||
/* TUNES */
|
||||
|
||||
void ArduboyTunes::initChannel(byte pin)
|
||||
{
|
||||
byte timer_num;
|
||||
|
||||
// we are all out of timers
|
||||
if (_tune_num_chans == AVAILABLE_TIMERS)
|
||||
return;
|
||||
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + _tune_num_chans);
|
||||
_tune_pins[_tune_num_chans] = pin;
|
||||
_tune_num_chans++;
|
||||
pinMode(pin, OUTPUT);
|
||||
switch (timer_num) {
|
||||
case 1: // 16 bit timer
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0;
|
||||
bitWrite(TCCR1B, WGM12, 1);
|
||||
bitWrite(TCCR1B, CS10, 1);
|
||||
_tunes_timer1_pin_port = portOutputRegister(digitalPinToPort(pin));
|
||||
_tunes_timer1_pin_mask = digitalPinToBitMask(pin);
|
||||
break;
|
||||
case 3: // 16 bit timer
|
||||
TCCR3A = 0;
|
||||
TCCR3B = 0;
|
||||
bitWrite(TCCR3B, WGM32, 1);
|
||||
bitWrite(TCCR3B, CS30, 1);
|
||||
_tunes_timer3_pin_port = portOutputRegister(digitalPinToPort(pin));
|
||||
_tunes_timer3_pin_mask = digitalPinToBitMask(pin);
|
||||
playNote(0, 60); /* start and stop channel 0 (timer 3) on middle C so wait/delay works */
|
||||
stopNote(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::playNote(byte chan, byte note)
|
||||
{
|
||||
byte timer_num;
|
||||
byte prescalar_bits;
|
||||
unsigned int frequency2; /* frequency times 2 */
|
||||
unsigned long ocr;
|
||||
|
||||
// we can't plan on a channel that does not exist
|
||||
if (chan >= _tune_num_chans)
|
||||
return;
|
||||
|
||||
// we only have frequencies for 128 notes
|
||||
if (note > 127) {
|
||||
return;
|
||||
}
|
||||
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
|
||||
if (note < 48) {
|
||||
frequency2 = pgm_read_byte(_midi_byte_note_frequencies + note);
|
||||
} else {
|
||||
frequency2 = pgm_read_word(_midi_word_note_frequencies + note - 48);
|
||||
}
|
||||
|
||||
//****** 16-bit timer *********
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency2 - 1;
|
||||
prescalar_bits = 0b001;
|
||||
if (ocr > 0xffff) {
|
||||
ocr = F_CPU / frequency2 / 64 - 1;
|
||||
prescalar_bits = 0b011;
|
||||
}
|
||||
// Set the OCR for the given timer, then turn on the interrupts
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalar_bits;
|
||||
OCR1A = ocr;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
break;
|
||||
case 3:
|
||||
TCCR3B = (TCCR3B & 0b11111000) | prescalar_bits;
|
||||
OCR3A = ocr;
|
||||
wait_timer_frequency2 = frequency2; // for "tune_delay" function
|
||||
wait_timer_playing = true;
|
||||
bitWrite(TIMSK3, OCIE3A, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::stopNote(byte chan)
|
||||
{
|
||||
byte timer_num;
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
TIMSK1 &= ~(1 << OCIE1A); // disable the interrupt
|
||||
*_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask); // keep pin low after stop
|
||||
break;
|
||||
case 3:
|
||||
wait_timer_playing = false;
|
||||
*_tunes_timer3_pin_port &= ~(_tunes_timer3_pin_mask); // keep pin low after stop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::playScore(const byte *score)
|
||||
{
|
||||
score_start = score;
|
||||
score_cursor = score_start;
|
||||
step(); /* execute initial commands */
|
||||
tune_playing = true; /* release the interrupt routine */
|
||||
}
|
||||
|
||||
void ArduboyTunes::stopScore (void)
|
||||
{
|
||||
for (uint8_t i = 0; i < _tune_num_chans; i++)
|
||||
stopNote(i);
|
||||
tune_playing = false;
|
||||
}
|
||||
|
||||
bool ArduboyTunes::playing()
|
||||
{
|
||||
return tune_playing;
|
||||
}
|
||||
|
||||
/* Do score commands until a "wait" is found, or the score is stopped.
|
||||
This is called initially from tune_playcore, but then is called
|
||||
from the interrupt routine when waits expire.
|
||||
*/
|
||||
/* if CMD < 0x80, then the other 7 bits and the next byte are a 15-bit big-endian number of msec to wait */
|
||||
void ArduboyTunes::step()
|
||||
{
|
||||
byte command, opcode, chan;
|
||||
unsigned duration;
|
||||
|
||||
while (1) {
|
||||
command = pgm_read_byte(score_cursor++);
|
||||
opcode = command & 0xf0;
|
||||
chan = command & 0x0f;
|
||||
if (opcode == TUNE_OP_STOPNOTE) { /* stop note */
|
||||
stopNote(chan);
|
||||
}
|
||||
else if (opcode == TUNE_OP_PLAYNOTE) { /* play note */
|
||||
playNote(chan, pgm_read_byte(score_cursor++));
|
||||
}
|
||||
else if (opcode == TUNE_OP_RESTART) { /* restart score */
|
||||
score_cursor = score_start;
|
||||
}
|
||||
else if (opcode == TUNE_OP_STOP) { /* stop score */
|
||||
tune_playing = false;
|
||||
break;
|
||||
}
|
||||
else if (opcode < 0x80) { /* wait count in msec. */
|
||||
duration = ((unsigned)command << 8) | (pgm_read_byte(score_cursor++));
|
||||
wait_toggle_count = ((unsigned long) wait_timer_frequency2 * duration + 500) / 1000;
|
||||
if (wait_toggle_count == 0) wait_toggle_count = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::closeChannels(void)
|
||||
{
|
||||
byte timer_num;
|
||||
for (uint8_t chan=0; chan < _tune_num_chans; chan++) {
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
TIMSK1 &= ~(1 << OCIE1A);
|
||||
break;
|
||||
case 3:
|
||||
TIMSK3 &= ~(1 << OCIE3A);
|
||||
break;
|
||||
}
|
||||
digitalWrite(_tune_pins[chan], 0);
|
||||
}
|
||||
_tune_num_chans = 0;
|
||||
tune_playing = false;
|
||||
}
|
||||
|
||||
void ArduboyTunes::soundOutput()
|
||||
{
|
||||
if (wait_timer_playing) { // toggle the pin if we're sounding a note
|
||||
*_tunes_timer3_pin_port ^= _tunes_timer3_pin_mask;
|
||||
}
|
||||
if (tune_playing && wait_toggle_count && --wait_toggle_count == 0) {
|
||||
// end of a score wait, so execute more score commands
|
||||
ArduboyTunes::step(); // execute commands
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::tone(unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
tonePlaying = true;
|
||||
uint8_t prescalarbits = 0b001;
|
||||
int32_t toggle_count = 0;
|
||||
uint32_t ocr = 0;
|
||||
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency / 2 - 1;
|
||||
prescalarbits = 0b001;
|
||||
if (ocr > 0xffff) {
|
||||
ocr = F_CPU / frequency / 2 / 64 - 1;
|
||||
prescalarbits = 0b011;
|
||||
}
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
|
||||
|
||||
// Calculate the toggle count
|
||||
if (duration > 0) {
|
||||
toggle_count = 2 * frequency * duration / 1000;
|
||||
}
|
||||
else {
|
||||
toggle_count = -1;
|
||||
}
|
||||
// Set the OCR for the given timer,
|
||||
// set the toggle count,
|
||||
// then turn on the interrupts
|
||||
OCR1A = ocr;
|
||||
timer1_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
}
|
||||
|
||||
// TIMER 1
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
if (tonePlaying) {
|
||||
if (timer1_toggle_count != 0) {
|
||||
// toggle the pin
|
||||
*_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask;
|
||||
if (timer1_toggle_count > 0) timer1_toggle_count--;
|
||||
}
|
||||
else {
|
||||
tonePlaying = false;
|
||||
TIMSK1 &= ~(1 << OCIE1A); // disable the interrupt
|
||||
*_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
else {
|
||||
*_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask; // toggle the pin
|
||||
}
|
||||
}
|
||||
|
||||
// TIMER 3
|
||||
ISR(TIMER3_COMPA_vect)
|
||||
{
|
||||
// Timer 3 is the one assigned first, so we keep it running always
|
||||
// and use it to time score waits, whether or not it is playing a note.
|
||||
ArduboyTunes::soundOutput();
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef ArduboyAudio_h
|
||||
#define ArduboyAudio_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/power.h>
|
||||
|
||||
#define AVAILABLE_TIMERS 2
|
||||
#define TUNE_OP_PLAYNOTE 0x90 /* play a note: low nibble is generator #, note is next byte */
|
||||
#define TUNE_OP_STOPNOTE 0x80 /* stop a note: low nibble is generator # */
|
||||
#define TUNE_OP_RESTART 0xe0 /* restart the score from the beginning */
|
||||
#define TUNE_OP_STOP 0xf0 /* stop playing */
|
||||
|
||||
|
||||
class ArduboyAudio
|
||||
{
|
||||
public:
|
||||
void static begin();
|
||||
void static on();
|
||||
void static off();
|
||||
void static saveOnOff();
|
||||
bool static enabled();
|
||||
|
||||
protected:
|
||||
bool static audio_enabled;
|
||||
};
|
||||
|
||||
|
||||
class ArduboyTunes
|
||||
{
|
||||
public:
|
||||
// Playtune Functions
|
||||
|
||||
/// Assign a timer to an output pin.
|
||||
void initChannel(byte pin);
|
||||
|
||||
/// Start playing a polyphonic score.
|
||||
void playScore(const byte *score);
|
||||
|
||||
/// Stop playing the score.
|
||||
void stopScore();
|
||||
|
||||
/// Delay in milliseconds.
|
||||
void delay(unsigned msec);
|
||||
|
||||
/// Stop all timers.
|
||||
void closeChannels();
|
||||
|
||||
bool playing();
|
||||
void tone(unsigned int frequency, unsigned long duration);
|
||||
|
||||
// called via interrupt
|
||||
void static step();
|
||||
void static soundOutput();
|
||||
|
||||
private:
|
||||
void static playNote (byte chan, byte note);
|
||||
void static stopNote (byte chan);
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,590 @@
|
|||
#include "core.h"
|
||||
|
||||
// need to redeclare these here since we declare them static in .h
|
||||
volatile uint8_t *ArduboyCore::mosiport,
|
||||
/* *ArduboyCore::csport, */ *ArduboyCore::dcport;
|
||||
uint8_t ArduboyCore::mosipinmask,
|
||||
ArduboyCore::cspinmask, ArduboyCore::dcpinmask;
|
||||
|
||||
const uint8_t PROGMEM pinBootProgram[] = {
|
||||
// buttons
|
||||
PIN_LEFT_BUTTON, INPUT_PULLUP,
|
||||
PIN_RIGHT_BUTTON, INPUT_PULLUP,
|
||||
PIN_UP_BUTTON, INPUT_PULLUP,
|
||||
PIN_DOWN_BUTTON, INPUT_PULLUP,
|
||||
PIN_A_BUTTON, INPUT_PULLUP,
|
||||
PIN_B_BUTTON, INPUT_PULLUP,
|
||||
|
||||
// OLED SPI
|
||||
DC, OUTPUT,
|
||||
CS, OUTPUT,
|
||||
RST, OUTPUT,
|
||||
0
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM lcdBootProgram[] = {
|
||||
|
||||
// boot defaults are commented out but left here incase they
|
||||
// might prove useful for reference
|
||||
//
|
||||
// Further reading: https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
|
||||
#ifdef OLED_SH1106
|
||||
0x8D, 0x14, // Charge Pump Setting v = enable (0x14)
|
||||
0xA1, // Set Segment Re-map
|
||||
0xC8, // Set COM Output Scan Direction
|
||||
0x81, 0xCF, // Set Contrast v = 0xCF
|
||||
0xD9, 0xF1, // Set Precharge = 0xF1
|
||||
OLED_SET_COLUMN_ADDRESS_LO, //Set column address for left most pixel
|
||||
0xAF // Display On
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128) || defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128)
|
||||
#if defined(OLED_96X96) || defined(OLED_128X64_ON_96X96)
|
||||
0x15, 0x10, 0x3f, //left most 32 pixels are invisible
|
||||
#elif defined(OLED_96X96_ON_128X128)
|
||||
0x15, 0x08, 0x37, //center 96 pixels horizontally
|
||||
#elif defined(OLED_64X128_ON_128X128)
|
||||
0x15, 0x10, 0x2f, //center 64 pixels horizontally
|
||||
#else
|
||||
0x15, 0x00, 0x3f, //Set column start and end address
|
||||
#endif
|
||||
#if defined (OLED_96X96)
|
||||
0x75, 0x20, 0x7f, //Set row start and end address
|
||||
#elif defined (OLED_128X64_ON_96X96)
|
||||
0x75, 0x30, 0x6f, //Set row start and end address
|
||||
#elif defined (OLED_128X96)
|
||||
0x75, 0x00, 0x5f, //Set row start and end address
|
||||
#elif defined(OLED_128X64_ON_128X96)
|
||||
0x75, 0x10, 0x4f, //Set row start and end address
|
||||
#elif defined(OLED_96X96_ON_128X128) || defined(OLED_128X96_ON_128X128)
|
||||
0x75, 0x10, 0x6f, //Set row start and end address to centered 96 lines
|
||||
#elif defined(OLED_128X64_ON_128X128)
|
||||
0x75, 0x20, 0x5f, //Set row start and end address to centered 64 lines
|
||||
#else
|
||||
0x75, 0x00, 0x7F, //Set row start and end address to use all 128 lines
|
||||
#endif
|
||||
#if defined(OLED_64X128_ON_128X128)
|
||||
0xA0, 0x51, //set re-map: split odd-even COM signals|COM remap|column address remap
|
||||
#else
|
||||
0xA0, 0x55, //set re-map: split odd-even COM signals|COM remap|vertical address increment|column address remap
|
||||
#endif
|
||||
0xA1, 0x00, //set display start line
|
||||
0xA2, 0x00, //set display offset
|
||||
//0xA4, //Normal display
|
||||
0xA8, 0x7F, //Set MUX ratio 128MUX
|
||||
//0xB2, 0x23,
|
||||
//0xB3, 0xF0, //set devider clock | oscillator frequency
|
||||
0x81, 0xCF, //Set contrast
|
||||
//0xBC, 0x1F, //set precharge voltage
|
||||
//0x82, 0xFE, //set second Precharge speed
|
||||
0xB1, 0x21, //reset and 1st precharge phase length phase 2:2 DCLKs, Phase 1: 1 DCLKs
|
||||
//0xBB, 0x0F, //set 2nd precharge period: 15 DCLKs
|
||||
//0xbe, 0x1F, //output level high voltage com signal
|
||||
//0xB8, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, //set gray scale table
|
||||
0xAF //Display on
|
||||
#else
|
||||
// for SSD1306 and SSD1309 displays
|
||||
//
|
||||
// Display Off
|
||||
// 0xAE,
|
||||
|
||||
// Set Display Clock Divisor v = 0xF0
|
||||
// default is 0x80
|
||||
0xD5, 0xF0,
|
||||
|
||||
// Set Multiplex Ratio v = 0x3F
|
||||
// 0xA8, 0x3F,
|
||||
|
||||
// Set Display Offset v = 0
|
||||
// 0xD3, 0x00,
|
||||
|
||||
// Set Start Line (0)
|
||||
// 0x40,
|
||||
#if defined OLED_SSD1309
|
||||
//Charge Pump command not supported, use two NOPs instead to keep same size and easy patchability
|
||||
0xE3, 0xE3,
|
||||
#else
|
||||
// Charge Pump Setting v = enable (0x14)
|
||||
// default is disabled
|
||||
0x8D, 0x14,
|
||||
#endif
|
||||
|
||||
// Set Segment Re-map (A0) | (b0001)
|
||||
// default is (b0000)
|
||||
0xA1,
|
||||
|
||||
// Set COM Output Scan Direction
|
||||
0xC8,
|
||||
|
||||
// Set COM Pins v
|
||||
// 0xDA, 0x12,
|
||||
|
||||
// Set Contrast v = 0xCF
|
||||
0x81, 0xCF,
|
||||
|
||||
// Set Precharge = 0xF1
|
||||
0xD9, 0xF1,
|
||||
|
||||
// Set VCom Detect
|
||||
// 0xDB, 0x40,
|
||||
|
||||
// Entire Display ON
|
||||
// 0xA4,
|
||||
|
||||
// Set normal/inverse display
|
||||
// 0xA6,
|
||||
|
||||
// Display On
|
||||
0xAF,
|
||||
|
||||
// set display mode = horizontal addressing mode (0x00)
|
||||
0x20, 0x00,
|
||||
|
||||
// set col address range
|
||||
// 0x21, 0x00, COLUMN_ADDRESS_END,
|
||||
|
||||
// set page address range
|
||||
// 0x22, 0x00, PAGE_ADDRESS_END
|
||||
#endif
|
||||
};
|
||||
|
||||
ArduboyCore::ArduboyCore() {}
|
||||
|
||||
void ArduboyCore::boot()
|
||||
{
|
||||
#if F_CPU == 8000000L
|
||||
slowCPU();
|
||||
#endif
|
||||
|
||||
SPI.begin();
|
||||
bootPins();
|
||||
bootLCD();
|
||||
|
||||
#ifdef SAFE_MODE
|
||||
if (buttonsState() == (LEFT_BUTTON | UP_BUTTON))
|
||||
safeMode();
|
||||
#endif
|
||||
|
||||
saveMuchPower();
|
||||
}
|
||||
|
||||
#if F_CPU == 8000000L
|
||||
// if we're compiling for 8Mhz we need to slow the CPU down because the
|
||||
// hardware clock on the Arduboy is 16MHz
|
||||
void ArduboyCore::slowCPU()
|
||||
{
|
||||
uint8_t oldSREG = SREG;
|
||||
cli(); // suspend interrupts
|
||||
CLKPR = _BV(CLKPCE); // allow reprogramming clock
|
||||
CLKPR = 1; // set clock divisor to 2 (0b0001)
|
||||
SREG = oldSREG; // restore interrupts
|
||||
}
|
||||
#endif
|
||||
|
||||
void ArduboyCore::bootPins()
|
||||
{
|
||||
uint8_t pin, mode;
|
||||
const uint8_t *i = pinBootProgram;
|
||||
|
||||
while(true) {
|
||||
pin = pgm_read_byte(i++);
|
||||
mode = pgm_read_byte(i++);
|
||||
if (pin==0) break;
|
||||
pinMode(pin, mode);
|
||||
}
|
||||
|
||||
digitalWrite(RST, HIGH);
|
||||
delay(1); // VDD (3.3V) goes high at start, lets just chill for a ms
|
||||
digitalWrite(RST, LOW); // bring reset low
|
||||
delay(10); // wait 10ms
|
||||
digitalWrite(RST, HIGH); // bring out of reset
|
||||
}
|
||||
|
||||
void ArduboyCore::bootLCD()
|
||||
{
|
||||
// setup the ports we need to talk to the OLED
|
||||
//csport = portOutputRegister(digitalPinToPort(CS));
|
||||
*portOutputRegister(digitalPinToPort(CS)) &= ~cspinmask;
|
||||
cspinmask = digitalPinToBitMask(CS);
|
||||
dcport = portOutputRegister(digitalPinToPort(DC));
|
||||
dcpinmask = digitalPinToBitMask(DC);
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
#if defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128)
|
||||
LCDDataMode();
|
||||
for (uint16_t i = 0; i < 8192; i++) SPI.transfer(0); //Clear all display ram
|
||||
#endif
|
||||
|
||||
LCDCommandMode();
|
||||
// run our customized boot-up command sequence against the
|
||||
// OLED to initialize it properly for Arduboy
|
||||
for (int8_t i=0; i < sizeof(lcdBootProgram); i++) {
|
||||
SPI.transfer(pgm_read_byte(lcdBootProgram + i));
|
||||
}
|
||||
LCDDataMode();
|
||||
}
|
||||
|
||||
void ArduboyCore::LCDDataMode()
|
||||
{
|
||||
*dcport |= dcpinmask;
|
||||
// *csport &= ~cspinmask;
|
||||
}
|
||||
|
||||
void ArduboyCore::LCDCommandMode()
|
||||
{
|
||||
// *csport |= cspinmask;
|
||||
*dcport &= ~dcpinmask;
|
||||
// *csport &= ~cspinmask; CS set once at bootLCD
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ArduboyCore::safeMode()
|
||||
{
|
||||
blank(); // too avoid random gibberish
|
||||
while (true) {
|
||||
asm volatile("nop \n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Power Management */
|
||||
|
||||
void ArduboyCore::idle()
|
||||
{
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sleep_mode();
|
||||
}
|
||||
|
||||
void ArduboyCore::saveMuchPower()
|
||||
{
|
||||
power_adc_disable();
|
||||
power_usart0_disable();
|
||||
power_twi_disable();
|
||||
// timer 0 is for millis()
|
||||
// timers 1 and 3 are for music and sounds
|
||||
power_timer2_disable();
|
||||
power_usart1_disable();
|
||||
// we need USB, for now (to allow triggered reboots to reprogram)
|
||||
// power_usb_disable()
|
||||
}
|
||||
|
||||
uint8_t ArduboyCore::width() { return WIDTH; }
|
||||
|
||||
uint8_t ArduboyCore::height() { return HEIGHT; }
|
||||
|
||||
|
||||
/* Drawing */
|
||||
|
||||
void ArduboyCore::paint8Pixels(uint8_t pixels)
|
||||
{
|
||||
SPI.transfer(pixels);
|
||||
}
|
||||
|
||||
void ArduboyCore::paintScreen(const unsigned char *image)
|
||||
{
|
||||
#if defined OLED_SH1106
|
||||
for (uint8_t i = 0; i < HEIGHT / 8; i++)
|
||||
{
|
||||
LCDCommandMode();
|
||||
SPDR = (OLED_SET_PAGE_ADDRESS + i);
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
SPDR = (OLED_SET_COLUMN_ADDRESS_HI); // we only need to reset hi nibble to 0
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
LCDDataMode();
|
||||
for (uint8_t j = WIDTH; j > 0; j--)
|
||||
{
|
||||
SPDR = pgm_read_byte(*(image++));
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
}
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128) || defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128) || defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128)
|
||||
#if defined(OLED_128X64_ON_96X96)
|
||||
uint16_t i = 16;
|
||||
for (uint8_t col = 0; col < 96 / 2; col++)
|
||||
#else
|
||||
uint16_t i = 0;
|
||||
for (uint8_t col = 0; col < WIDTH / 2; col++)
|
||||
#endif
|
||||
{
|
||||
for (uint8_t row = 0; row < HEIGHT / 8; row++)
|
||||
{
|
||||
uint8_t b1 = pgm_read_byte(image + i);
|
||||
uint8_t b2 = pgm_read_byte(image + i + 1);
|
||||
for (uint8_t shift = 0; shift < 8; shift++)
|
||||
{
|
||||
uint8_t c = 0xFF;
|
||||
if ((b1 & 1) == 0) c &= 0x0F;
|
||||
if ((b2 & 1) == 0) c &= 0xF0;
|
||||
SPDR = c;
|
||||
b1 = b1 >> 1;
|
||||
b2 = b2 >> 1;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
i += WIDTH;
|
||||
}
|
||||
i -= HEIGHT / 8 * WIDTH - 2;
|
||||
}
|
||||
#elif defined(OLED_64X128_ON_128X128)
|
||||
uint16_t i = WIDTH-1;
|
||||
for (uint8_t col = 0; col < WIDTH ; col++)
|
||||
{
|
||||
for (uint8_t row = 0; row < HEIGHT / 8; row++)
|
||||
{
|
||||
uint8_t b = pgm_read_byte(image + i);
|
||||
if (clear) *(image + i) = 0;
|
||||
for (uint8_t shift = 0; shift < 4; shift++)
|
||||
{
|
||||
uint8_t c = 0xFF;
|
||||
if ((b & _BV(0)) == 0) c &= 0x0F;
|
||||
if ((b & _BV(1)) == 0) c &= 0xF0;
|
||||
SPDR = c;
|
||||
b = b >> 2;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
i += WIDTH;
|
||||
}
|
||||
i -= HEIGHT / 8 * WIDTH + 1;
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
|
||||
{
|
||||
SPI.transfer(pgm_read_byte(image + i));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// paint from a memory buffer, this should be FAST as it's likely what
|
||||
// will be used by any buffer based subclass
|
||||
void ArduboyCore::paintScreen(unsigned char image[])
|
||||
{
|
||||
#if defined OLED_SH1106
|
||||
for (uint8_t i = 0; i < HEIGHT / 8; i++)
|
||||
{
|
||||
LCDCommandMode();
|
||||
SPDR = (OLED_SET_PAGE_ADDRESS + i);
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
SPDR = (OLED_SET_COLUMN_ADDRESS_HI); // we only need to reset hi nibble to 0
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
LCDDataMode();
|
||||
for (uint8_t j = WIDTH; j > 0; j--)
|
||||
{
|
||||
SPDR = *(image++);
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
}
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128)|| defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128)
|
||||
// 1 bit to 4-bit expander display code with clear support.
|
||||
// Each transfer takes 18 cycles with additional 4 cycles for a column change.
|
||||
asm volatile(
|
||||
#if defined(OLED_128X64_ON_96X96)
|
||||
" adiw r30, 16 \n\t"
|
||||
#endif
|
||||
" ldi r25, %[col] \n\t"
|
||||
".lcolumn: \n\t"
|
||||
" ldi r24, %[row] ;1 \n\t"
|
||||
".lrow: \n\t"
|
||||
" ldi r21, 7 ;1 \n\t"
|
||||
" ld r22, z ;2 \n\t"
|
||||
" ldd r23, z+1 ;2 \n\t"
|
||||
".lshiftstart: \n\t"
|
||||
" ldi r20, 0xFF ;1 \n\t"
|
||||
" sbrs r22, 0 ;1 \n\t"
|
||||
" andi r20, 0x0f ;1 \n\t"
|
||||
" sbrs r23, 0 ;1 \n\t"
|
||||
" andi r20,0xf0 ;1 \n\t"
|
||||
" out %[spdr], r20 ;1 \n\t"
|
||||
" \n\t"
|
||||
" cp %[clear], __zero_reg__ ;1 \n\t"
|
||||
" brne .lclear1 ;1/2 \n\t"
|
||||
".lshiftothers: \n\t"
|
||||
" movw r18, %A[ptr] ;1 \n\t"
|
||||
" rjmp .+0 ;2 \n\t"
|
||||
" rjmp .lshiftnext ;2 \n\t"
|
||||
".lclear1: \n\t"
|
||||
" st z, __zero_reg__ ;2 \n\t"
|
||||
" std z+1, __zero_reg__ ;2 \n\t"
|
||||
".lshiftnext: \n\t"
|
||||
" \n\t"
|
||||
" lsr r22 ;1 \n\t"
|
||||
" lsr r23 ;1 \n\t"
|
||||
" \n\t"
|
||||
" ldi r20, 0xFF ;1 \n\t"
|
||||
" sbrs r22, 0 ;1/2 \n\t"
|
||||
" andi r20, 0x0f ;1 \n\t"
|
||||
" sbrs r23, 0 ;1/2 \n\t"
|
||||
" andi r20,0xf0 ;1 \n\t"
|
||||
" \n\t"
|
||||
" subi r18, %[top_lsb] ;1 \n\t" //image - (WIDTH * ((HEIGHT / 8) - 1) - 2)
|
||||
" sbci r19, %[top_msb] ;1 \n\t"
|
||||
" subi r21, 1 ;1 \n\t"
|
||||
" out %[spdr], r20 ;1 \n\t"
|
||||
" brne .lshiftothers ;1/2 \n\t"
|
||||
" \n\t"
|
||||
" nop ;1 \n\t"
|
||||
" subi %A[ptr], %[width] ;1 \n\t" //image + width (negated addition)
|
||||
" sbci %B[ptr], -1 ;1 \n\t"
|
||||
" subi r24, 1 ;1 \n\t"
|
||||
" brne .lrow ;1/2 \n\t"
|
||||
" \n\t"
|
||||
" movw %A[ptr], r18 ;1 \n\t"
|
||||
" subi r25, 1 ;1 \n\t"
|
||||
" brne .lcolumn ;1/2 \n\t"
|
||||
" in __tmp_reg__, %[spsr] \n\t" //read SPSR to clear SPIF
|
||||
: [ptr] "+&z" (image)
|
||||
: [spdr] "I" (_SFR_IO_ADDR(SPDR)),
|
||||
[spsr] "I" (_SFR_IO_ADDR(SPSR)),
|
||||
[row] "M" (HEIGHT / 8),
|
||||
#if defined(OLED_128X64_ON_96X96)
|
||||
[col] "M" (96 / 2),
|
||||
#else
|
||||
[col] "M" (WIDTH / 2),
|
||||
#endif
|
||||
[width] "M" (256 - WIDTH),
|
||||
[top_lsb] "M" ((WIDTH * ((HEIGHT / 8) - 1) - 2) & 0xFF),
|
||||
[top_msb] "M" ((WIDTH * ((HEIGHT / 8) - 1) - 2) >> 8),
|
||||
[clear] "r" (0)
|
||||
: "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25"
|
||||
);
|
||||
#elif defined(OLED_64X128_ON_128X128)
|
||||
uint16_t i = WIDTH-1;
|
||||
for (uint8_t col = 0; col < WIDTH ; col++)
|
||||
{
|
||||
for (uint8_t row = 0; row < HEIGHT / 8; row++)
|
||||
{
|
||||
uint8_t b = *(image + i);
|
||||
if (clear) *(image + i) = 0;
|
||||
for (uint8_t shift = 0; shift < 4; shift++)
|
||||
{
|
||||
uint8_t c = 0xFF;
|
||||
if ((b & _BV(0)) == 0) c &= 0x0F;
|
||||
if ((b & _BV(1)) == 0) c &= 0xF0;
|
||||
SPDR = c;
|
||||
b = b >> 2;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
i += WIDTH;
|
||||
}
|
||||
i -= HEIGHT / 8 * WIDTH + 1;
|
||||
}
|
||||
#else
|
||||
uint8_t c;
|
||||
int i = 0;
|
||||
|
||||
SPDR = image[i++]; // set the first SPI data byte to get things started
|
||||
|
||||
// the code to iterate the loop and get the next byte from the buffer is
|
||||
// executed while the previous byte is being sent out by the SPI controller
|
||||
while (i < (HEIGHT * WIDTH) / 8)
|
||||
{
|
||||
// get the next byte. It's put in a local variable so it can be sent as
|
||||
// as soon as possible after the sending of the previous byte has completed
|
||||
c = image[i++];
|
||||
|
||||
while (!(SPSR & _BV(SPIF))) { } // wait for the previous byte to be sent
|
||||
|
||||
// put the next byte in the SPI data register. The SPI controller will
|
||||
// clock it out while the loop continues and gets the next byte ready
|
||||
SPDR = c;
|
||||
}
|
||||
while (!(SPSR & _BV(SPIF))) { } // wait for the last byte to be sent
|
||||
#endif
|
||||
}
|
||||
|
||||
void ArduboyCore::blank()
|
||||
{
|
||||
#ifdef OLED_SH1106
|
||||
for (int i = 0; i < (HEIGHT * 132) / 8; i++)
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128)
|
||||
for (int i = 0; i < (HEIGHT * WIDTH) / 2; i++)
|
||||
#else //OLED SSD1306 and compatibles
|
||||
for (int i = 0; i < (HEIGHT * WIDTH) / 8; i++)
|
||||
#endif
|
||||
SPI.transfer(0x00);
|
||||
}
|
||||
|
||||
void ArduboyCore::sendLCDCommand(uint8_t command)
|
||||
{
|
||||
LCDCommandMode();
|
||||
SPI.transfer(command);
|
||||
LCDDataMode();
|
||||
}
|
||||
|
||||
// invert the display or set to normal
|
||||
// when inverted, a pixel set to 0 will be on
|
||||
void ArduboyCore::invert(boolean inverse)
|
||||
{
|
||||
sendLCDCommand(inverse ? OLED_PIXELS_INVERTED : OLED_PIXELS_NORMAL);
|
||||
}
|
||||
|
||||
// turn all display pixels on, ignoring buffer contents
|
||||
// or set to normal buffer display
|
||||
void ArduboyCore::allPixelsOn(boolean on)
|
||||
{
|
||||
sendLCDCommand(on ? OLED_ALL_PIXELS_ON : OLED_PIXELS_FROM_RAM);
|
||||
}
|
||||
|
||||
// flip the display vertically or set to normal
|
||||
void ArduboyCore::flipVertical(boolean flipped)
|
||||
{
|
||||
sendLCDCommand(flipped ? OLED_VERTICAL_FLIPPED : OLED_VERTICAL_NORMAL);
|
||||
}
|
||||
|
||||
#define OLED_HORIZ_FLIPPED 0xA0 // reversed segment re-map
|
||||
#define OLED_HORIZ_NORMAL 0xA1 // normal segment re-map
|
||||
|
||||
// flip the display horizontally or set to normal
|
||||
void ArduboyCore::flipHorizontal(boolean flipped)
|
||||
{
|
||||
sendLCDCommand(flipped ? OLED_HORIZ_FLIPPED : OLED_HORIZ_NORMAL);
|
||||
}
|
||||
|
||||
/* RGB LED */
|
||||
|
||||
void ArduboyCore::setRGBled(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
#ifdef ARDUBOY_10 // RGB, all the pretty colors
|
||||
// inversion is necessary because these are common annode LEDs
|
||||
analogWrite(RED_LED, 255 - red);
|
||||
analogWrite(GREEN_LED, 255 - green);
|
||||
analogWrite(BLUE_LED, 255 - blue);
|
||||
#elif defined(AB_DEVKIT)
|
||||
// only blue on devkit
|
||||
digitalWrite(BLUE_LED, ~blue);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
uint8_t ArduboyCore::getInput()
|
||||
{
|
||||
return buttonsState();
|
||||
}
|
||||
|
||||
|
||||
uint8_t ArduboyCore::buttonsState()
|
||||
{
|
||||
uint8_t buttons;
|
||||
|
||||
// using ports here is ~100 bytes smaller than digitalRead()
|
||||
#ifdef AB_DEVKIT
|
||||
// down, left, up
|
||||
buttons = ((~PINB) & B01110000);
|
||||
// right button
|
||||
//buttons = buttons | (((~PINC) & B01000000) >> 4);
|
||||
if ((PINC & B01000000) == 0) buttons |= 0x04; //compiles to shorter and faster code
|
||||
// A and B
|
||||
//buttons = buttons | (((~PINF) & B11000000) >> 6);
|
||||
if ((PINF & B10000000) == 0) buttons |= 0x02; //compiles to shorter and faster code
|
||||
if ((PINF & B01000000) == 0) buttons |= 0x01;
|
||||
#elif defined(ARDUBOY_10)
|
||||
// down, up, left right
|
||||
buttons = ((~PINF) & B11110000);
|
||||
// A (left)
|
||||
//buttons = buttons | (((~PINE) & B01000000) >> 3);
|
||||
if ((PINE & B01000000) == 0) {buttons |= 0x08;} //compiles to shorter and faster code
|
||||
// B (right)
|
||||
//buttons = buttons | (((~PINB) & B00010000) >> 2);
|
||||
if ((PINB & B00010000) == 0) {buttons |= 0x04;} //compiles to shorter and faster code
|
||||
#endif
|
||||
|
||||
return buttons;
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
#ifndef ArduboyCore_h
|
||||
#define ArduboyCore_h
|
||||
|
||||
#include <avr/power.h>
|
||||
#include <SPI.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// main hardware compile flags
|
||||
|
||||
#if !defined(ARDUBOY_10) && !defined(AB_DEVKIT)
|
||||
/// defaults to Arduboy Release 1.0 if not using a boards.txt file
|
||||
/**
|
||||
* we default to Arduboy Release 1.0 if a compile flag has not been
|
||||
* passed to us from a boards.txt file
|
||||
*
|
||||
* if you wish to compile for the devkit without using a boards.txt
|
||||
* file simply comment out the ARDUBOY_10 define and uncomment
|
||||
* the AB_DEVKIT define like this:
|
||||
*
|
||||
* // #define ARDUBOY_10
|
||||
* #define AB_DEVKIT
|
||||
*/
|
||||
#define ARDUBOY_10 //< compile for the production Arduboy v1.0
|
||||
// #define AB_DEVKIT //< compile for the official dev kit
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AB_DEVKIT
|
||||
#define DEVKIT //< for compatibilty with older sketches
|
||||
#define SAFE_MODE //< include safe mode (44 bytes)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ARDUBOY_10
|
||||
|
||||
#if defined AB_ALTERNATE_WIRING //Pro Micro Alternative OLED CS & RST pins
|
||||
#define CS 1
|
||||
#define RST 2
|
||||
#else
|
||||
#define CS 12
|
||||
#define RST 6
|
||||
#endif
|
||||
#define DC 4
|
||||
|
||||
#define RED_LED 10
|
||||
#if defined AB_ALTERNATE_WIRING //Pro Micro Alternative GREEN LED pin
|
||||
#define GREEN_LED 3
|
||||
#else
|
||||
#define GREEN_LED 11
|
||||
#endif
|
||||
#define BLUE_LED 9
|
||||
#define TX_LED 30
|
||||
#define RX_LED 17
|
||||
|
||||
// pin values for buttons, probably shouldn't use these
|
||||
#define PIN_LEFT_BUTTON A2
|
||||
#define PIN_RIGHT_BUTTON A1
|
||||
#define PIN_UP_BUTTON A0
|
||||
#define PIN_DOWN_BUTTON A3
|
||||
#define PIN_A_BUTTON 7
|
||||
#define PIN_B_BUTTON 8
|
||||
|
||||
// bit values for button states
|
||||
#define LEFT_BUTTON _BV(5)
|
||||
#define RIGHT_BUTTON _BV(6)
|
||||
#define UP_BUTTON _BV(7)
|
||||
#define DOWN_BUTTON _BV(4)
|
||||
#define A_BUTTON _BV(3)
|
||||
#define B_BUTTON _BV(2)
|
||||
|
||||
#define PIN_SPEAKER_1 5
|
||||
#define PIN_SPEAKER_1_PORT &PORTC
|
||||
#define PIN_SPEAKER_1_BITMASK _BV(6)
|
||||
|
||||
#if defined AB_ALTERNATE_WIRING //Pro Micro alternative for 2nd speaker pin
|
||||
#define PIN_SPEAKER_2 6
|
||||
#define PIN_SPEAKER_2_PORT &PORTD
|
||||
#define PIN_SPEAKER_2_BITMASK _BV(7)
|
||||
#else
|
||||
#define PIN_SPEAKER_2 13
|
||||
#define PIN_SPEAKER_2_PORT &PORTC
|
||||
#define PIN_SPEAKER_2_BITMASK _BV(7)
|
||||
#endif
|
||||
|
||||
#elif defined(AB_DEVKIT)
|
||||
|
||||
#define CS 6
|
||||
#define DC 4
|
||||
#define RST 12
|
||||
|
||||
// map all LEDs to the single TX LED on DEVKIT
|
||||
#define RED_LED 17
|
||||
#define GREEN_LED 17
|
||||
#define BLUE_LED 17
|
||||
#define TX_LED 17
|
||||
#define RX_LED 17
|
||||
|
||||
// pin values for buttons, probably shouldn't use these
|
||||
#define PIN_LEFT_BUTTON 9
|
||||
#define PIN_RIGHT_BUTTON 5
|
||||
#define PIN_UP_BUTTON 8
|
||||
#define PIN_DOWN_BUTTON 10
|
||||
#define PIN_A_BUTTON A0
|
||||
#define PIN_B_BUTTON A1
|
||||
|
||||
// bit values for button states
|
||||
#define LEFT_BUTTON _BV(5)
|
||||
#define RIGHT_BUTTON _BV(2)
|
||||
#define UP_BUTTON _BV(4)
|
||||
#define DOWN_BUTTON _BV(6)
|
||||
#define A_BUTTON _BV(1)
|
||||
#define B_BUTTON _BV(0)
|
||||
|
||||
#define PIN_SPEAKER_1 A2
|
||||
#define PIN_SPEAKER_2 A3
|
||||
|
||||
#define PIN_SPEAKER_1_PORT &PORTF
|
||||
#define PIN_SPEAKER_2_PORT &PORTF
|
||||
|
||||
#define PIN_SPEAKER_1_BITMASK _BV(5)
|
||||
#define PIN_SPEAKER_2_BITMASK _BV(4)
|
||||
|
||||
#endif
|
||||
|
||||
#define OLED_PIXELS_INVERTED 0xA7 // All pixels inverted (Same for SH1106)
|
||||
#define OLED_PIXELS_NORMAL 0xA6 // All pixels normal (Same for SH1106)
|
||||
|
||||
#define OLED_ALL_PIXELS_ON 0xA5 // all pixels on (Same for SH1106)
|
||||
#define OLED_PIXELS_FROM_RAM 0xA4 // pixels mapped to display RAM contents (Same for SH1106)
|
||||
|
||||
#define OLED_VERTICAL_FLIPPED 0xC0 // reversed COM scan direction (Same for SH1106)
|
||||
#define OLED_VERTICAL_NORMAL 0xC8 // normal COM scan direction (Same for SH1106)
|
||||
|
||||
#define OLED_SET_PAGE_ADDRESS 0xB0 // (Same for SH1106)
|
||||
#if defined OLED_SH1106
|
||||
#define OLED_SET_COLUMN_ADDRESS_LO 0x02 //SH1106: 1st pixel starts on column 2
|
||||
#else
|
||||
#define OLED_SET_COLUMN_ADDRESS_LO 0x00
|
||||
#endif
|
||||
#define OLED_SET_COLUMN_ADDRESS_HI 0x10 //(Same for SH1106)
|
||||
|
||||
// -----
|
||||
|
||||
#define COLUMN_ADDRESS_END (WIDTH - 1) & 0x7F // 128 pixels wide
|
||||
#define PAGE_ADDRESS_END ((HEIGHT/8)-1) & 0x07 // 8 pages high
|
||||
|
||||
#if defined (OLED_96X96) || (OLED_96X96_ON_128X128)
|
||||
#define WIDTH 96
|
||||
#else
|
||||
#define WIDTH 128 //The standard width of the display in pixels
|
||||
#endif
|
||||
#if defined(OLED_128X128)
|
||||
#define HEIGHT 128
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_96X96_ON_128X128) || defined(OLED_128X96_ON_128X128)
|
||||
#define HEIGHT 96
|
||||
#else
|
||||
#define HEIGHT 64 //The standard height of the display in pixels
|
||||
#endif
|
||||
|
||||
#define INVERT 2 //< lit/unlit pixel
|
||||
#define WHITE 1 //< lit pixel
|
||||
#define BLACK 0 //< unlit pixel
|
||||
|
||||
class ArduboyCore
|
||||
{
|
||||
public:
|
||||
ArduboyCore();
|
||||
|
||||
/// allows the CPU to idle between frames
|
||||
/**
|
||||
* This puts the CPU in "Idle" sleep mode. You should call this as often
|
||||
* as you can for the best power savings. The timer 0 overflow interrupt
|
||||
* will wake up the chip every 1ms - so even at 60 FPS a well written
|
||||
* app should be able to sleep maybe half the time in between rendering
|
||||
* it's own frames.
|
||||
*
|
||||
* See the Arduboy class nextFrame() for an example of how to use idle()
|
||||
* in a frame loop.
|
||||
*/
|
||||
void static idle();
|
||||
|
||||
void static LCDDataMode(); //< put the display in data mode
|
||||
|
||||
/// put the display in command mode
|
||||
/**
|
||||
* See SSD1306 documents for available commands and command sequences.
|
||||
*
|
||||
* Links:
|
||||
* - https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
* - http://www.eimodule.com/download/SSD1306-OLED-Controller.pdf
|
||||
*/
|
||||
void static LCDCommandMode();
|
||||
|
||||
uint8_t static width(); //< return display width
|
||||
uint8_t static height(); // < return display height
|
||||
|
||||
/// get current state of all buttons (bitmask)
|
||||
/**
|
||||
* Bit mask that is returned:
|
||||
*
|
||||
* Hi Low
|
||||
* DevKit 00000000 - reserved
|
||||
* -DLU-RAB D down
|
||||
* U up
|
||||
* 1.0 00000000 L left
|
||||
* URLDAB-- R right
|
||||
*
|
||||
* Of course you shouldn't worry about bits (they may change with future
|
||||
* hardware revisions) and should instead use the button defines:
|
||||
* LEFT_BUTTON, A_BUTTON, UP_BUTTON, etc.
|
||||
*/
|
||||
|
||||
uint8_t static getInput(); __attribute__ ((deprecated("use buttonsState() instead")));
|
||||
uint8_t static buttonsState();
|
||||
|
||||
// paints 8 pixels (vertically) from a single byte
|
||||
// - 1 is lit, 0 is unlit
|
||||
//
|
||||
// NOTE: You probably wouldn't actually use this, you'd build something
|
||||
// higher level that does it's own calls to SPI.transfer(). It's
|
||||
// included for completeness since it seems there should be some very
|
||||
// rudimentary low-level draw function in the core that supports the
|
||||
// minimum unit that the hardware allows (which is a strip of 8 pixels)
|
||||
//
|
||||
// This routine starts in the top left and then across the screen.
|
||||
// After each "page" (row) of 8 pixels is drawn it will shift down
|
||||
// to start drawing the next page. To paint the full screen you call
|
||||
// this function 1,024 times.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// X = painted pixels, . = unpainted
|
||||
//
|
||||
// blank() paint8Pixels() 0xFF, 0, 0x0F, 0, 0xF0
|
||||
// v TOP LEFT corner (8x9) v TOP LEFT corner
|
||||
// ........ (page 1) X...X... (page 1)
|
||||
// ........ X...X...
|
||||
// ........ X...X...
|
||||
// ........ X...X...
|
||||
// ........ X.X.....
|
||||
// ........ X.X.....
|
||||
// ........ X.X.....
|
||||
// ........ (end of page 1) X.X..... (end of page 1)
|
||||
// ........ (page 2) ........ (page 2)
|
||||
void static paint8Pixels(uint8_t pixels);
|
||||
|
||||
/// paints an entire image directly to hardware (from PROGMEM)
|
||||
/*
|
||||
* Each byte will be 8 vertical pixels, painted in the same order as
|
||||
* explained above in paint8Pixels.
|
||||
*/
|
||||
void static paintScreen(const unsigned char *image);
|
||||
|
||||
/// paints an entire image directly to hardware (from RAM)
|
||||
/*
|
||||
* Each byte will be 8 vertical pixels, painted in the same order as
|
||||
* explained above in paint8Pixels.
|
||||
*/
|
||||
void static paintScreen(unsigned char image[]);
|
||||
|
||||
/// paints a blank (black) screen to hardware
|
||||
void static blank();
|
||||
|
||||
/// invert the display or set to normal
|
||||
/**
|
||||
* when inverted, a pixel set to 0 will be on
|
||||
*/
|
||||
void static invert(boolean inverse);
|
||||
|
||||
/// turn all display pixels on, or display the buffer contents
|
||||
/**
|
||||
* when set to all pixels on, the display buffer will be
|
||||
* ignored but not altered
|
||||
*/
|
||||
void static allPixelsOn(boolean on);
|
||||
|
||||
/// flip the display vertically or set to normal
|
||||
void static flipVertical(boolean flipped);
|
||||
|
||||
/// flip the display horizontally or set to normal
|
||||
void static flipHorizontal(boolean flipped);
|
||||
|
||||
/// send a single byte command to the OLED
|
||||
void static sendLCDCommand(uint8_t command);
|
||||
|
||||
/// set the light output of the RGB LEB
|
||||
void setRGBled(uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
protected:
|
||||
/// boots the hardware
|
||||
/**
|
||||
* - sets input/output/pullup mode for pins
|
||||
* - powers up the OLED screen and initializes it properly
|
||||
* - sets up power saving
|
||||
* - kicks CPU down to 8Mhz if needed
|
||||
* - allows Safe mode to be entered
|
||||
*/
|
||||
void static boot();
|
||||
|
||||
/// Safe mode
|
||||
/**
|
||||
* Safe Mode is engaged by holding down both the LEFT button and UP button
|
||||
* when plugging the device into USB. It puts your device into a tight
|
||||
* loop and allows it to be reprogrammed even if you have uploaded a very
|
||||
* broken sketch that interferes with the normal USB triggered auto-reboot
|
||||
* functionality of the device.
|
||||
*
|
||||
* This is most useful on Devkits because they lack a built-in reset
|
||||
* button.
|
||||
*/
|
||||
void static inline safeMode() __attribute__((always_inline));
|
||||
|
||||
// internals
|
||||
void static inline bootLCD() __attribute__((always_inline));
|
||||
void static inline bootPins() __attribute__((always_inline));
|
||||
void static inline slowCPU() __attribute__((always_inline));
|
||||
void static inline saveMuchPower(); __attribute__((always_inline));
|
||||
|
||||
|
||||
private:
|
||||
volatile static uint8_t *mosiport, /* *csport, */ *dcport;
|
||||
uint8_t static mosipinmask, cspinmask, dcpinmask;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,268 @@
|
|||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#ifndef FONT5X7_H
|
||||
#define FONT5X7_H
|
||||
|
||||
// standard ascii 5x7 font
|
||||
const static unsigned char font[] PROGMEM =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
|
||||
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
|
||||
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
|
||||
0x18, 0x3C, 0x7E, 0x3C, 0x18,
|
||||
0x1C, 0x57, 0x7D, 0x57, 0x1C,
|
||||
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
|
||||
0x00, 0x18, 0x3C, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
|
||||
0x00, 0x18, 0x24, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
|
||||
0x30, 0x48, 0x3A, 0x06, 0x0E,
|
||||
0x26, 0x29, 0x79, 0x29, 0x26,
|
||||
0x40, 0x7F, 0x05, 0x05, 0x07,
|
||||
0x40, 0x7F, 0x05, 0x25, 0x3F,
|
||||
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
|
||||
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
|
||||
0x14, 0x22, 0x7F, 0x22, 0x14,
|
||||
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
|
||||
0x06, 0x09, 0x7F, 0x01, 0x7F,
|
||||
0x00, 0x66, 0x89, 0x95, 0x6A,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x94, 0xA2, 0xFF, 0xA2, 0x94,
|
||||
0x08, 0x04, 0x7E, 0x04, 0x08,
|
||||
0x10, 0x20, 0x7E, 0x20, 0x10,
|
||||
0x08, 0x08, 0x2A, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x2A, 0x08, 0x08,
|
||||
0x1E, 0x10, 0x10, 0x10, 0x10,
|
||||
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
|
||||
0x30, 0x38, 0x3E, 0x38, 0x30,
|
||||
0x06, 0x0E, 0x3E, 0x0E, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x5F, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x07, 0x00,
|
||||
0x14, 0x7F, 0x14, 0x7F, 0x14,
|
||||
0x24, 0x2A, 0x7F, 0x2A, 0x12,
|
||||
0x23, 0x13, 0x08, 0x64, 0x62,
|
||||
0x36, 0x49, 0x56, 0x20, 0x50,
|
||||
0x00, 0x08, 0x07, 0x03, 0x00,
|
||||
0x00, 0x1C, 0x22, 0x41, 0x00,
|
||||
0x00, 0x41, 0x22, 0x1C, 0x00,
|
||||
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
|
||||
0x08, 0x08, 0x3E, 0x08, 0x08,
|
||||
0x00, 0x80, 0x70, 0x30, 0x00,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x60, 0x60, 0x00,
|
||||
0x20, 0x10, 0x08, 0x04, 0x02,
|
||||
0x3E, 0x51, 0x49, 0x45, 0x3E,
|
||||
0x00, 0x42, 0x7F, 0x40, 0x00,
|
||||
0x72, 0x49, 0x49, 0x49, 0x46,
|
||||
0x21, 0x41, 0x49, 0x4D, 0x33,
|
||||
0x18, 0x14, 0x12, 0x7F, 0x10,
|
||||
0x27, 0x45, 0x45, 0x45, 0x39,
|
||||
0x3C, 0x4A, 0x49, 0x49, 0x31,
|
||||
0x41, 0x21, 0x11, 0x09, 0x07,
|
||||
0x36, 0x49, 0x49, 0x49, 0x36,
|
||||
0x46, 0x49, 0x49, 0x29, 0x1E,
|
||||
0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x00, 0x40, 0x34, 0x00, 0x00,
|
||||
0x00, 0x08, 0x14, 0x22, 0x41,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x00, 0x41, 0x22, 0x14, 0x08,
|
||||
0x02, 0x01, 0x59, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x5D, 0x59, 0x4E,
|
||||
0x7C, 0x12, 0x11, 0x12, 0x7C,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x36,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x22,
|
||||
0x7F, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x41,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x01,
|
||||
0x3E, 0x41, 0x41, 0x51, 0x73,
|
||||
0x7F, 0x08, 0x08, 0x08, 0x7F,
|
||||
0x00, 0x41, 0x7F, 0x41, 0x00,
|
||||
0x20, 0x40, 0x41, 0x3F, 0x01,
|
||||
0x7F, 0x08, 0x14, 0x22, 0x41,
|
||||
0x7F, 0x40, 0x40, 0x40, 0x40,
|
||||
0x7F, 0x02, 0x1C, 0x02, 0x7F,
|
||||
0x7F, 0x04, 0x08, 0x10, 0x7F,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x51, 0x21, 0x5E,
|
||||
0x7F, 0x09, 0x19, 0x29, 0x46,
|
||||
0x26, 0x49, 0x49, 0x49, 0x32,
|
||||
0x03, 0x01, 0x7F, 0x01, 0x03,
|
||||
0x3F, 0x40, 0x40, 0x40, 0x3F,
|
||||
0x1F, 0x20, 0x40, 0x20, 0x1F,
|
||||
0x3F, 0x40, 0x38, 0x40, 0x3F,
|
||||
0x63, 0x14, 0x08, 0x14, 0x63,
|
||||
0x03, 0x04, 0x78, 0x04, 0x03,
|
||||
0x61, 0x59, 0x49, 0x4D, 0x43,
|
||||
0x00, 0x7F, 0x41, 0x41, 0x41,
|
||||
0x02, 0x04, 0x08, 0x10, 0x20,
|
||||
0x00, 0x41, 0x41, 0x41, 0x7F,
|
||||
0x04, 0x02, 0x01, 0x02, 0x04,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x03, 0x07, 0x08, 0x00,
|
||||
0x20, 0x54, 0x54, 0x78, 0x40,
|
||||
0x7F, 0x28, 0x44, 0x44, 0x38,
|
||||
0x38, 0x44, 0x44, 0x44, 0x28,
|
||||
0x38, 0x44, 0x44, 0x28, 0x7F,
|
||||
0x38, 0x54, 0x54, 0x54, 0x18,
|
||||
0x00, 0x08, 0x7E, 0x09, 0x02,
|
||||
0x18, 0xA4, 0xA4, 0x9C, 0x78,
|
||||
0x7F, 0x08, 0x04, 0x04, 0x78,
|
||||
0x00, 0x44, 0x7D, 0x40, 0x00,
|
||||
0x20, 0x40, 0x40, 0x3D, 0x00,
|
||||
0x7F, 0x10, 0x28, 0x44, 0x00,
|
||||
0x00, 0x41, 0x7F, 0x40, 0x00,
|
||||
0x7C, 0x04, 0x78, 0x04, 0x78,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x78,
|
||||
0x38, 0x44, 0x44, 0x44, 0x38,
|
||||
0xFC, 0x18, 0x24, 0x24, 0x18,
|
||||
0x18, 0x24, 0x24, 0x18, 0xFC,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x08,
|
||||
0x48, 0x54, 0x54, 0x54, 0x24,
|
||||
0x04, 0x04, 0x3F, 0x44, 0x24,
|
||||
0x3C, 0x40, 0x40, 0x20, 0x7C,
|
||||
0x1C, 0x20, 0x40, 0x20, 0x1C,
|
||||
0x3C, 0x40, 0x30, 0x40, 0x3C,
|
||||
0x44, 0x28, 0x10, 0x28, 0x44,
|
||||
0x4C, 0x90, 0x90, 0x90, 0x7C,
|
||||
0x44, 0x64, 0x54, 0x4C, 0x44,
|
||||
0x00, 0x08, 0x36, 0x41, 0x00,
|
||||
0x00, 0x00, 0x77, 0x00, 0x00,
|
||||
0x00, 0x41, 0x36, 0x08, 0x00,
|
||||
0x02, 0x01, 0x02, 0x04, 0x02,
|
||||
0x3C, 0x26, 0x23, 0x26, 0x3C,
|
||||
0x1E, 0xA1, 0xA1, 0x61, 0x12,
|
||||
0x3A, 0x40, 0x40, 0x20, 0x7A,
|
||||
0x38, 0x54, 0x54, 0x55, 0x59,
|
||||
0x21, 0x55, 0x55, 0x79, 0x41,
|
||||
0x21, 0x54, 0x54, 0x78, 0x41,
|
||||
0x21, 0x55, 0x54, 0x78, 0x40,
|
||||
0x20, 0x54, 0x55, 0x79, 0x40,
|
||||
0x0C, 0x1E, 0x52, 0x72, 0x12,
|
||||
0x39, 0x55, 0x55, 0x55, 0x59,
|
||||
0x39, 0x54, 0x54, 0x54, 0x59,
|
||||
0x39, 0x55, 0x54, 0x54, 0x58,
|
||||
0x00, 0x00, 0x45, 0x7C, 0x41,
|
||||
0x00, 0x02, 0x45, 0x7D, 0x42,
|
||||
0x00, 0x01, 0x45, 0x7C, 0x40,
|
||||
0xF0, 0x29, 0x24, 0x29, 0xF0,
|
||||
0xF0, 0x28, 0x25, 0x28, 0xF0,
|
||||
0x7C, 0x54, 0x55, 0x45, 0x00,
|
||||
0x20, 0x54, 0x54, 0x7C, 0x54,
|
||||
0x7C, 0x0A, 0x09, 0x7F, 0x49,
|
||||
0x32, 0x49, 0x49, 0x49, 0x32,
|
||||
0x32, 0x48, 0x48, 0x48, 0x32,
|
||||
0x32, 0x4A, 0x48, 0x48, 0x30,
|
||||
0x3A, 0x41, 0x41, 0x21, 0x7A,
|
||||
0x3A, 0x42, 0x40, 0x20, 0x78,
|
||||
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
|
||||
0x39, 0x44, 0x44, 0x44, 0x39,
|
||||
0x3D, 0x40, 0x40, 0x40, 0x3D,
|
||||
0x3C, 0x24, 0xFF, 0x24, 0x24,
|
||||
0x48, 0x7E, 0x49, 0x43, 0x66,
|
||||
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
|
||||
0xFF, 0x09, 0x29, 0xF6, 0x20,
|
||||
0xC0, 0x88, 0x7E, 0x09, 0x03,
|
||||
0x20, 0x54, 0x54, 0x79, 0x41,
|
||||
0x00, 0x00, 0x44, 0x7D, 0x41,
|
||||
0x30, 0x48, 0x48, 0x4A, 0x32,
|
||||
0x38, 0x40, 0x40, 0x22, 0x7A,
|
||||
0x00, 0x7A, 0x0A, 0x0A, 0x72,
|
||||
0x7D, 0x0D, 0x19, 0x31, 0x7D,
|
||||
0x26, 0x29, 0x29, 0x2F, 0x28,
|
||||
0x26, 0x29, 0x29, 0x29, 0x26,
|
||||
0x30, 0x48, 0x4D, 0x40, 0x20,
|
||||
0x38, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x38,
|
||||
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
|
||||
0x2F, 0x10, 0x28, 0x34, 0xFA,
|
||||
0x00, 0x00, 0x7B, 0x00, 0x00,
|
||||
0x08, 0x14, 0x2A, 0x14, 0x22,
|
||||
0x22, 0x14, 0x2A, 0x14, 0x08,
|
||||
0x95, 0x00, 0x22, 0x00, 0x95,
|
||||
0xAA, 0x00, 0x55, 0x00, 0xAA,
|
||||
0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x00,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x00,
|
||||
0x10, 0x10, 0xFF, 0x00, 0xFF,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x14, 0x14, 0x14, 0xFC, 0x00,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xFC,
|
||||
0x14, 0x14, 0x17, 0x10, 0x1F,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0x1F, 0x00,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x14,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x17,
|
||||
0x00, 0x00, 0xFC, 0x04, 0xF4,
|
||||
0x14, 0x14, 0x17, 0x10, 0x17,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xF4,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x17, 0x14,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0xF4, 0x14,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x14,
|
||||
0x00, 0x00, 0x00, 0xFC, 0x14,
|
||||
0x00, 0x00, 0xF0, 0x10, 0xF0,
|
||||
0x10, 0x10, 0xFF, 0x10, 0xFF,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x14,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF0, 0x10,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x38, 0x44, 0x44, 0x38, 0x44,
|
||||
0x7C, 0x2A, 0x2A, 0x3E, 0x14,
|
||||
0x7E, 0x02, 0x02, 0x06, 0x06,
|
||||
0x02, 0x7E, 0x02, 0x7E, 0x02,
|
||||
0x63, 0x55, 0x49, 0x41, 0x63,
|
||||
0x38, 0x44, 0x44, 0x3C, 0x04,
|
||||
0x40, 0x7E, 0x20, 0x1E, 0x20,
|
||||
0x06, 0x02, 0x7E, 0x02, 0x02,
|
||||
0x99, 0xA5, 0xE7, 0xA5, 0x99,
|
||||
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
|
||||
0x4C, 0x72, 0x01, 0x72, 0x4C,
|
||||
0x30, 0x4A, 0x4D, 0x4D, 0x30,
|
||||
0x30, 0x48, 0x78, 0x48, 0x30,
|
||||
0xBC, 0x62, 0x5A, 0x46, 0x3D,
|
||||
0x3E, 0x49, 0x49, 0x49, 0x00,
|
||||
0x7E, 0x01, 0x01, 0x01, 0x7E,
|
||||
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
|
||||
0x44, 0x44, 0x5F, 0x44, 0x44,
|
||||
0x40, 0x51, 0x4A, 0x44, 0x40,
|
||||
0x40, 0x44, 0x4A, 0x51, 0x40,
|
||||
0x00, 0x00, 0xFF, 0x01, 0x03,
|
||||
0xE0, 0x80, 0xFF, 0x00, 0x00,
|
||||
0x08, 0x08, 0x6B, 0x6B, 0x08,
|
||||
0x36, 0x12, 0x36, 0x24, 0x36,
|
||||
0x06, 0x0F, 0x09, 0x0F, 0x06,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x30, 0x40, 0xFF, 0x01, 0x01,
|
||||
0x00, 0x1F, 0x01, 0x01, 0x1E,
|
||||
0x00, 0x19, 0x1D, 0x17, 0x12,
|
||||
0x00, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,148 @@
|
|||
/**
|
||||
\page licenses Software License Agreements
|
||||
\verbatim
|
||||
|
||||
Software License Agreements
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Licensed under the BSD 3-clause license:
|
||||
|
||||
Arduboy2 library:
|
||||
Copyright (c) 2016-2018, Scott Allen
|
||||
All rights reserved.
|
||||
|
||||
The Arduboy2 library was forked from the Arduboy library:
|
||||
https://github.com/Arduboy/Arduboy
|
||||
Copyright (c) 2016, Kevin "Arduboy" Bates
|
||||
Copyright (c) 2016, Chris Martinez
|
||||
Copyright (c) 2016, Josh Goebel
|
||||
Copyright (c) 2016, Scott Allen
|
||||
All rights reserved.
|
||||
which is in turn partially based on the Adafruit_SSD1306 library
|
||||
https://github.com/adafruit/Adafruit_SSD1306
|
||||
Copyright (c) 2012, Adafruit Industries
|
||||
All rights reserved.
|
||||
|
||||
SetSystemEEPROM example sketch:
|
||||
Copyright (c) 2018, Scott Allen
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. 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.
|
||||
3. Neither the name of the copyright holders 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 ''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 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.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Licensed under the BSD 2-clause license:
|
||||
|
||||
Portions of the Arduboy library, and thus portions of the Arduboy2 library,
|
||||
based on the Adafruit-GFX library:
|
||||
https://github.com/adafruit/Adafruit-GFX-Library
|
||||
Copyright (c) 2012 Adafruit Industries
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Licensed under the MIT license:
|
||||
|
||||
Code from ArduboyExtra:
|
||||
https://github.com/yyyc514/ArduboyExtra
|
||||
Copyright (c) 2015 Josh Goebel
|
||||
|
||||
Code for drawing compressed bitmaps:
|
||||
https://github.com/TEAMarg/drawCompressed
|
||||
Copyright (c) 2016 TEAM a.r.g.
|
||||
|
||||
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.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Licensed under the GNU LGPL license:
|
||||
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
|
||||
|
||||
ArduBreakout example sketch:
|
||||
Original work:
|
||||
Copyright (c) 2011 Sebastian Goscik
|
||||
All rights reserved.
|
||||
Modified work:
|
||||
Copyright (c) 2016 Scott Allen
|
||||
All rights reserved.
|
||||
|
||||
Buttons and HelloWorld example sketches:
|
||||
Copyright (c) 2015 David Martinez
|
||||
All rights reserved.
|
||||
|
||||
This work 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.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Placed in the public domain:
|
||||
|
||||
BeepDemo example sketch:
|
||||
By Scott Allen
|
||||
|
||||
RGBled example sketch:
|
||||
By Scott Allen
|
||||
|
||||
===============================================================================
|
||||
\endverbatim
|
||||
*/
|
|
@ -0,0 +1,439 @@
|
|||
# Arduboy2 (Homemade) Library
|
||||
|
||||
This is a fork of the Arduboy2 Library with support for alternate displays: SH1106, SSD1309, displays with 4-bit pixel depth and alternate resolution: SSD1327 (128x96) and SSD1329 (96x96) as wel as alternate pin wiring for a (SparkFun) Pro Micro.
|
||||
|
||||
The original Arduboy2 library is maintained in a git repository hosted on [GitHub](https://github.com/) at:
|
||||
|
||||
https://github.com/MLXXXp/Arduboy2
|
||||
|
||||
The **Arduboy2** library is a fork of the [Arduboy library](https://github.com/Arduboy/Arduboy), which provides a standard *application programming interface* (API) to the display, buttons and other hardware of the Arduino based [Arduboy miniature game system](https://www.arduboy.com/).
|
||||
|
||||
The name *Arduboy2* doesn't indicate that it's for a new "next generation" of the Arduboy hardware. The name was changed so it can coexist in the Arduino IDE with the current *Arduboy* library, without conflict. This way, existing sketches can continue to use the *Arduboy* library and class, without changes, while new sketches can be written (or old ones modified) to use and take advantage of the capabilities of the *Arduboy2* class and library.
|
||||
|
||||
For notes on the differences between the *Arduboy2* library and the original *Arduboy* library, and for information on migrating a sketch currently using the *Arduboy* library, see the sections at the end of this document.
|
||||
|
||||
## Library documentation
|
||||
|
||||
Comments in the library header files are formatted for the [Doxygen](http://www.doxygen.org) document generation system. The HTML files generated using the configuration file _extras/Doxyfile_ can be found at:
|
||||
|
||||
https://MLXXXp.github.io/documents/Arduino/libraries/Arduboy2/Doxygen/html/index.html
|
||||
|
||||
A generated PDF file can be found at:
|
||||
|
||||
https://MLXXXp.github.io/documents/Arduino/libraries/Arduboy2/Doxygen/pdf/Arduboy2.pdf
|
||||
|
||||
## Installation
|
||||
|
||||
The Arduboy2 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 *arduboy2*.
|
||||
- Click somewhere within the Arduboy2 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)
|
||||
|
||||
## Start up features
|
||||
|
||||
The *begin()* function, used to initialize the library, includes features that are intended to be available to all sketches using the library (unless the sketch developer has chosen to disable one or more of them to free up some code space):
|
||||
|
||||
### The boot logo
|
||||
|
||||
At the start of the sketch, the **ARDUBOY** logo scrolls down from the top of the screen to the center.
|
||||
|
||||
The RGB LED lights red then green then blue while the logo is scrolling. (If your Arduboy is one of those that has the RGB LED installed incorrectly, then it will light blue then off then red). For users who do not wish to have the RGB LED flash during the boot logo sequence, a flag can be set in system EEPROM to have it remain off. The included *SetSystemEEPROM* example sketch can be used to set this flag.
|
||||
|
||||
A user settable *unit name* of up to 6 characters can be saved in system EEPROM memory. If set, this name will be briefly displayed at the bottom of the boot logo screen, after the logo stops scrolling down. This feature is only available if the *Arduboy2* class is used, not the *Arduboy2Base* class. This is because it requires the text display functions, which are only available in the *Arduboy2* class. A flag in system EEPROM controls whether or not the *unit name* is displayed on the boot logo screen, regardless of whether the *unit name* itself has been set. The included *SetSystemEEPROM* example sketch can be used to set both the *unit name* and this flag.
|
||||
|
||||
Once the logo display sequence completes, the sketch continues.
|
||||
|
||||
For developers who wish to quickly begin testing, or impatient users who want to go strait to playing their game, the boot logo sequence can be bypassed by holding the *RIGHT* button while powering up, and then releasing it. Alternatively, the *RIGHT* button can be pressed while the logo is scrolling down.
|
||||
|
||||
For users who wish to always disable the displaying of the boot logo sequence on boot up, a flag in system EEPROM is available for this. The included *SetSystemEEPROM* example sketch can be used to set this flag.
|
||||
|
||||
### "Flashlight" mode
|
||||
|
||||
If the *UP* button is pressed and held when the Arduboy is powered on, it enters *flashlight* mode. This turns the RGB LED fully on, and all the pixels of the screen are lit, resulting in a bright white light suitable as a small flashlight. (For an incorrect RGB LED, only the screen will light). To exit *flashlight* mode the Arduboy must be restarted.
|
||||
|
||||
*Flashlight* mode is also sometimes useful to allow uploading of new sketches, in case the sketch currently loaded uses a large amount of RAM which creates a bootloader problem.
|
||||
|
||||
### Audio mute control
|
||||
|
||||
Pressing and holding the *B* button when powering on will enter *System Control* mode. The RGB LED will light blue (red for an incorrect LED) to indicate that you are in *system control* mode. You must continue to hold the *B* button to remain in this mode. The only *system control* function currently implemented is *audio mute control*.
|
||||
|
||||
Pressing the *UP* button (while still holding *B*) will set a flag in system EEPROM indicating *audio enabled*. The RGB LED will flash green once (off for an incorrect LED) to indicate this action.
|
||||
|
||||
Pressing the *DOWN* button (while still holding *B*) will set the flag to *audio disabled* (muted). The RGB LED will flash red once (blue for an incorrect LED) to indicate this action.
|
||||
|
||||
Releasing the *B* button will exit *system control* mode and the sketch will continue.
|
||||
|
||||
Note that the audio control feature only sets a flag in EEPROM. Whatever code actually produces the sound must use the *audio.enabled()* function to check and honor the mute state. Audio libraries written with the Arduboy system in mind, such as the available *ArduboyPlaytune* and *ArduboyTones*, should do this. However, be aware that for some sketches, which don't use the Arduboy2 or other compliant library and generate sounds in their own way, this method of muting sound may not work.
|
||||
|
||||
## Using the library in a sketch
|
||||
|
||||
As with most libraries, to use Arduboy2 in your sketch you must include its header file at the start:
|
||||
|
||||
```cpp
|
||||
#include <Arduboy2.h>
|
||||
```
|
||||
|
||||
You must then create an Arduboy2 class object:
|
||||
|
||||
```cpp
|
||||
Arduboy2 arduboy;
|
||||
```
|
||||
|
||||
Naming the object *arduboy* has become somewhat of a standard, but you can use a different name if you wish.
|
||||
|
||||
To initialize the library, you must call its *begin()* function. This is usually done at the start of the sketch's *setup()* function:
|
||||
|
||||
```cpp
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
// more setup code follows, if required
|
||||
}
|
||||
```
|
||||
|
||||
The rest of the Arduboy2 functions will now be available for use.
|
||||
|
||||
If you wish to use the Sprites class functions you must create a Sprites object:
|
||||
|
||||
```cpp
|
||||
Sprites sprites;
|
||||
```
|
||||
|
||||
Sample sketches have been included with the library as examples of how to use it. To load an example, for examination and uploading to the Arduboy, using the Arduino IDE menus select:
|
||||
|
||||
`File > Examples > Arduboy2`
|
||||
|
||||
More information on writing sketches for the Arduboy can be found in the [Arduboy Community Forum](http://community.arduboy.com/).
|
||||
|
||||
### Using EEPROM in a sketch
|
||||
|
||||
The Arduboy2 library reserves an area at the start of EEPROM for storing system information, such as the current audio mute state and the Unit Name and Unit ID. A sketch **must not** use this reserved area for its own purposes. A sketch may use any EEPROM past this reserved area. The first EEPROM address available for sketch use is given as the defined value *EEPROM_STORAGE_SPACE_START*
|
||||
|
||||
### Audio control functions
|
||||
|
||||
The library includes an Arduboy2Audio class. This class provides functions to enable and disable (mute) sound and also save the current mute state so that it remains in effect over power cycles and after loading a different sketch. It doesn't contain anything to actually produce sound.
|
||||
|
||||
The Arduboy2Base class, and thus the Arduboy2 class, creates an Arduboy2Audio class object named *audio*, so a sketch doesn't need to create its own Arduboy2Audio object.
|
||||
|
||||
Example:
|
||||
|
||||
```cpp
|
||||
#include <Arduboy2.h>
|
||||
|
||||
Arduboy2 arduboy;
|
||||
|
||||
// Arduboy2Audio functions can be called as follows:
|
||||
arduboy.audio.on();
|
||||
arduboy.audio.off();
|
||||
```
|
||||
|
||||
### Simple tone generation
|
||||
|
||||
The *BeepPin1* and *BeepPin2* classes are available to generate simple square wave tones using speaker pin 1 and speaker pin 2 respectively. These classes are documented in file *Arduboy2Beep.h*. Also, *BeepDemo* is included as one of the example sketches, which demonstrates basic use.
|
||||
|
||||
NOTE: These functions will not work with a DevKit Arduboy because the speaker pins used cannot be directly controlled by a timer/counter. "Dummy" functions are provided so a sketch will compile and work properly but no sound will be produced.
|
||||
|
||||
### Ways to make more code space available to sketches
|
||||
|
||||
#### Sound effects and music
|
||||
|
||||
If all you want is to play single tones, using the built in *BeepPin1* or *BeepPin2* classes will be very efficient.
|
||||
|
||||
If you want to be able to play sequences of tones or background music, using the [*ArduboyTones*](https://github.com/MLXXXp/ArduboyTones) library will be more code efficient than using [*ArduboyPlaytune*](https://github.com/Arduboy/ArduboyPlayTune) or most other sound libraries compatible with the Arduboy. *ArduboyTones* even produces less code than the [Arduino built in *tone()* function](https://www.arduino.cc/en/Reference/Tone). You'll have to decide on the appropriate library or functions you use to generate sound, based on the features required and how much memory you want it to use.
|
||||
|
||||
#### Remove the text functions
|
||||
|
||||
If your sketch doesn't use any of the functions for displaying text, such as *setCursor()* and *print()*, you can remove them. You could do this if your sketch generates whatever text it requires by some other means. Removing the text functions frees up code by not including the font table and some code that is always pulled in by inheriting the [Arduino *Print* class](http://playground.arduino.cc/Code/Printclass).
|
||||
|
||||
To eliminate text capability in your sketch, when creating the library object simply use the *Arduboy2Base* class instead of *Arduboy2*:
|
||||
|
||||
For example, if the object will be named *arduboy*:
|
||||
|
||||
Replace
|
||||
|
||||
```cpp
|
||||
Arduboy2 arduboy;
|
||||
```
|
||||
|
||||
with
|
||||
|
||||
```cpp
|
||||
Arduboy2Base arduboy;
|
||||
```
|
||||
|
||||
#### Remove boot up features
|
||||
|
||||
As previously described, the *begin()* function includes features that are intended to be available to all sketches during boot up. However, if you're looking to gain some code space, you can call *boot()* instead of *begin()*. This will initialize the system but not include any of the extra boot up features. If desired, you can then add back in any of these features by calling the functions that perform them. You will have to trade off between the desirability of having a feature and how much memory you can recover by not including it.
|
||||
|
||||
A good way to use *boot()* instead of *begin()* is to copy the code from the body of the *begin()* function, in file *Arduboy2.cpp*, into your sketch and then edit it to retain the *boot()* call and any feature calls desired.
|
||||
|
||||
As of this writing, the begin function is:
|
||||
|
||||
```cpp
|
||||
void Arduboy2Base::begin()
|
||||
{
|
||||
boot(); // raw hardware
|
||||
|
||||
display(); // blank the display (sBuffer is global, so cleared automatically)
|
||||
|
||||
flashlight(); // light the RGB LED and screen if UP button is being held.
|
||||
|
||||
// check for and handle buttons held during start up for system control
|
||||
systemButtons();
|
||||
|
||||
audio.begin();
|
||||
|
||||
bootLogo();
|
||||
|
||||
waitNoButtons(); // wait for all buttons to be released
|
||||
}
|
||||
```
|
||||
|
||||
To incorporate it into your sketch just keep *boot()* and whatever feature calls are desired, if any. Comment out or delete the rest. Remember to add the class object name in front of each function call, since they're now being called from outside the class itself. If your sketch uses sound, it's a good idea to keep the call to *audio.begin()*.
|
||||
|
||||
For example: Let's say a sketch has its own code to enable, disable and save the *audio on/off* setting, and wants to keep the *flashlight* function. In *setup()* it could replace *begin()* with:
|
||||
|
||||
```cpp
|
||||
arduboy.boot(); // raw hardware
|
||||
|
||||
// *** This particular sketch clears the display soon, so it doesn't need this:
|
||||
// display(); // blank the display (sBuffer is global, so cleared automatically)
|
||||
|
||||
arduboy.flashlight(); // light the RGB LED and screen if UP button is being held.
|
||||
|
||||
// check for and handle buttons held during start up for system control
|
||||
// systemButtons();
|
||||
|
||||
arduboy.audio.begin();
|
||||
|
||||
// bootLogo();
|
||||
|
||||
// waitNoButtons(); // wait for all buttons to be released
|
||||
```
|
||||
|
||||
This saves whatever code *display()*, *systemButtons()*, *bootLogo()* and *waitNoButtons()* would use.
|
||||
|
||||
There are a few functions provided that are roughly equivalent to the standard functions used by *begin()* but which use less code space.
|
||||
|
||||
- *bootLogoCompressed()*, *bootLogoSpritesSelfMasked()*, *bootLogoSpritesOverwrite()*, *bootLogoSpritesBSelfMasked()* and *bootLogoSpritesBOverwrite()* will do the same as *bootLogo()* but will use *drawCompressed()*, or *Sprites* / *SpritesB* class *drawSelfMasked()* or *drawOverwrite()* functions respectively, instead of *drawBitmask()*, to render the logo. If the sketch uses one of these functions, then using the boot logo function that also uses it may reduce code size. It's best to try each of them to see which one produces the smallest size.
|
||||
- *bootLogoText()* can be used in place *bootLogo()* in the case where the sketch uses text functions. It renders the logo as text instead of as a bitmap (so doesn't look as good).
|
||||
- *safeMode()* can be used in place of *flashlight()* for cases where it's needed to allow uploading a new sketch when the bootloader "magic key" problem is an issue. It only lights the red RGB LED, so you don't get the bright light that is the primary purpose of *flashlight()*.
|
||||
|
||||
#### Use the SpritesB class instead of Sprites
|
||||
|
||||
The *SpritesB* class has functions identical to the *Sprites* class. The difference is that *SpritesB* is optimized for small code size rather than execution speed. If you want to use the sprites functions, and the slower speed of *SpritesB* doesn't affect your sketch, you may be able to use it to gain some code space.
|
||||
|
||||
Even if the speed is acceptable when using *SpritesB*, you should still try using *Sprites*. In some cases *Sprites* will produce less code than *SpritesB*, notably when only one of the functions is used.
|
||||
|
||||
You can easily switch between using *Sprites* or *SpritesB* by using one or the other to create an object instance:
|
||||
|
||||
```cpp
|
||||
Sprites sprites; // Use this to optimize for execution speed
|
||||
SpritesB sprites; // Use this to (likely) optimize for code size
|
||||
```
|
||||
|
||||
#### Eliminate the USB stack code
|
||||
|
||||
**Warning:** Although this will free up a fair amount of code and some RAM space, without an active USB interface uploader programs will be unable to automatically force a reset to invoke the bootloader. This means the user will have to manually initiate a reset in order to upload a new sketch. This can be an inconvenience or even frustrating for a user, due to the fact that timing the sequence can sometimes be tricky. Therefore, using this technique should be considered as a last resort. If it is used, the sketch documentation should state clearly what will be involved to upload a new sketch.
|
||||
|
||||
The *ARDUBOY_NO_USB* macro is used to eliminate the USB code. The *exitToBootloader()* function is available to make it easier for a user to invoke the bootloader. For more details, see the documentation provided for these.
|
||||
|
||||
----------
|
||||
|
||||
## What's different from Arduboy library V1.1
|
||||
|
||||
A main goal of Arduboy2 is to provide ways in which more code space can be freed for use by large sketches. Another goal is to allow methods other than the *tunes* functions to be used to produce sounds. Arduboy2 remains substantially compatible with [Arduboy library V1.1](https://github.com/Arduboy/Arduboy/releases/tag/v1.1), which was the latest stable release at the time of the fork. Arduboy2 is based on the code targeted for Arduboy library V1.2, which was still in development and unreleased at the time it was forked.
|
||||
|
||||
Main differences between Arduboy2 and Arduboy V1.1 are:
|
||||
|
||||
- The *ArduboyTunes* subclass, which provided the *tunes.xxx()* functions, has been removed. It's functionality is available in a separate [*ArduboyPlaytune* library](https://github.com/Arduboy/ArduboyPlayTune). By removing these functions, more code space may become available because interrupt routines and other support code was being compiled in even if a sketch didn't make use them. Another benefit is that without the automatic installation of timer interrupt service routines, other audio generating functions and libraries, that need access to the same interrupts, can now be used. Removal of the *tunes* functions is the main API incompatibility with Arduboy V1.1. Sketches written to use *tunes* functions will need some minor modifications in order to make them work with Arduboy2 plus ArduboyPlaytune, [ArduboyTones](https://github.com/MLXXXp/ArduboyTones), or some other audio library.
|
||||
- Arduboy library V1.1 uses timer 1 for the *tunes* functions. This causes problems when attempting to control the Arduboy's RGB LED using PWM, such as with *setRGBled()*, because it also requires timer 1. Since the *tunes* functionality has been removed from Arduboy2, there are no problems with using the RGB LED (except those caused by the RGB LED being incorrectly installed). Of course, using an external library that uses timer 1, such as *ArduboyPlaytune*, may reintroduce the problems. However, using a library that doesn't use timer 1, such as *ArduboyTones*, is now an option.
|
||||
- The code to generate text output, using *setCursor()*, *print()*, etc., can be removed to free up code space, if a sketch doesn't use any text functions. The *Arduboy2* class includes the text functions but using the *Arduboy2Base* class instead will eliminate them. With text functions included, the font table and some support functions are always compiled in even if not used. The API for using text functions is the same as Arduboy V1.1 with some additional functions added:
|
||||
- *setTextColor()* and *setTextBackground()* allow for printing black text on a white background.
|
||||
- *getCursorX()* and *getCursorY()* allow for determining the current text cursor position.
|
||||
- The *clear()* function will now reset the text cursor to home position 0, 0.
|
||||
- A new feature has been added which allows the *audio on/off* flag in system EEPROM to be configured by the user when the sketch starts. The flag is used by the Arduboy and Arduboy2 *audio* subclass, along with external sound functions and libraries, to provide a standardized sound mute capability. See the information above, under the heading *Audio mute control*, for more details.
|
||||
- The *color* parameter, which is the last parameter for most of the drawing functions, has been made optional and will default to WHITE if not included in the call. This doesn't save any code but has been added as a convenience, since most drawing functions are called with WHITE specified.
|
||||
- A new function *digitalWriteRGB()* has been added to control the RGB LED digitally instead of using PWM. This uses less code if just turning the RGB LEDs fully on or off is all that's required.
|
||||
- The *beginNoLogo()* function is not included. This function could be used in Arduboy V1.1 in place of *begin()* to suppress the displaying of the ARDUBOY logo and thus free up the code that it required. Instead, Arduboy2 allows a sketch to call *boot()* and then add in any extra features that *begin()* provides by calling their functions directly after *boot()*, if desired.
|
||||
- The *ArduboyCore* and *ArduboyAudio* base classes, previously only available to, and used to derive, the *Arduboy* class, have been made publicly available for the benefit of developers who may wish to use them as the base of an entirely new library. This change doesn't affect the existing API.
|
||||
|
||||
As of version 2.1.0 functionality from the [Team A.R.G.](http://www.team-arg.org/) *Arglib* library has been added:
|
||||
|
||||
- The sprite drawing functions, collision detection functions, and button handling functions that Team A.R.G. incorporated from the [ArduboyExtra](https://github.com/yyyc514/ArduboyExtra) project. The *poll()* function was renamed *pollButtons()* for clarity. The *Sprites* class doesn't require a parameter for the constructor, whereas in *Arglib* a pointer to an Arduboy class object is required.
|
||||
- The *drawCompressed()* function, which allows compressed bitmaps to be drawn. Saving bitmaps in compressed form may reduce overall sketch size.
|
||||
|
||||
Team A.R.G. has now migrated all of their games and demos to use the Arduboy2 library.
|
||||
|
||||
## Migrating a sketch from Arduboy library V1.1 to Arduboy2
|
||||
|
||||
Since the Arduboy2 library can coexist in the Arduino IDE alongside the Arduboy library V1.1, a currently working sketch that uses Arduboy V1.1 doesn't have to be migrated to Arduboy2. However, if you want to switch a sketch to Arduboy2 for further development, in order to take advantage of any of the changes and enhancements, it's generally relatively easy.
|
||||
|
||||
The Arduboy2 library, for the most part, is compatible with Arduboy library V1.1 but migrating a sketch to Arduboy2 will require some small changes, and more so if it uses the *tunes* functions, such as *tunes.tone()* or *tunes.playScore()*.
|
||||
|
||||
### Required changes
|
||||
|
||||
The first thing to do is change the `include` for the library header file:
|
||||
|
||||
```cpp
|
||||
#include <Arduboy.h>
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```cpp
|
||||
#include <Arduboy2.h>
|
||||
```
|
||||
|
||||
If it was "Arduboy.h" (in quotes), it's still better to change it to <Arduboy2.h> (in angle brackets).
|
||||
|
||||
The same thing has to be done with creating the library object. (If the object name isn't *arduboy*, keep whatever name is used.):
|
||||
|
||||
```cpp
|
||||
Arduboy arduboy;
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```cpp
|
||||
Arduboy2 arduboy;
|
||||
```
|
||||
|
||||
If the sketch doesn't use any *tunes* functions, there's a good chance this is all that has to be done to make it compile.
|
||||
|
||||
### Sketch uses only *tunes.tone()* for sound
|
||||
|
||||
If the sketch has sound but only uses *tunes.tone()*, solutions are:
|
||||
|
||||
#### Solution 1: Switch to using Arduino *tone()*
|
||||
|
||||
An easy change is to use the Arduino built in *tone()* function. You can add a function to the sketch that wraps *tone()* so that it works like *tunes.tone()*, like so:
|
||||
|
||||
```cpp
|
||||
// Wrap the Arduino tone() function so that the pin doesn't have to be
|
||||
// specified each time. Also, don't play if audio is set to off.
|
||||
void playTone(unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
if (arduboy.audio.enabled() == true)
|
||||
{
|
||||
tone(PIN_SPEAKER_1, frequency, duration);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You then change all *tunes.tone()* calls to *playTone()* calls using the same parameter values. For example:
|
||||
|
||||
```cpp
|
||||
arduboy.tunes.tone(1000, 250);
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```cpp
|
||||
playTone(1000, 250);
|
||||
```
|
||||
|
||||
#### Solution 2: Switch to using the ArduboyTones library
|
||||
|
||||
Changing to the *ArduboyTones* library is slightly more complicated. The advantage is that it will generate less code than using *tone()* and will also allow you to easily enhance the sketch to play tone sequences instead of just single tones. ArduboyTones can also play each tone at either normal or a higher volume.
|
||||
|
||||
You have to add an include for the ArduboyTones header file:
|
||||
|
||||
```cpp
|
||||
#include <ArduboyTones.h>
|
||||
```
|
||||
|
||||
You then have to create an object for the *ArduboyTones* class and pass it a pointer to the Arduboy2 *audio.enabled()* function. This must go after the creation of the Arduboy2 object, like so:
|
||||
|
||||
```cpp
|
||||
Arduboy2 arduboy;
|
||||
ArduboyTones sound(arduboy.audio.enabled);
|
||||
```
|
||||
|
||||
You then change all Arduboy *tunes.tone()* calls to ArduboyTones *tone()* calls using the same parameter values. For example:
|
||||
|
||||
```cpp
|
||||
arduboy.tunes.tone(1000, 250);
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```cpp
|
||||
sound.tone(1000, 250);
|
||||
```
|
||||
|
||||
See the [ArduboyTones](https://github.com/MLXXXp/ArduboyTones) README file for more information on installing and using it.
|
||||
|
||||
#### Solution 3: Switch to using the ArduboyPlaytune library.
|
||||
|
||||
See the following for how to do this:
|
||||
|
||||
### Sketch uses *tunes.playScore()*
|
||||
|
||||
If the sketch uses *tunes.playScore()*, probably the easiest solution is to use the *ArduboyPlaytune* library. *ArduboyPlaytune* is essentially the code that was in the Arduboy V1.1 *tunes* subclass, which has been removed from Arduboy2. It's been cleaned up and a few enhancements have been added, but all the Arduboy V1.1 *tunes* functions are available.
|
||||
|
||||
You have to add an include for the ArduboyPlaytune header file:
|
||||
|
||||
```cpp
|
||||
#include <ArduboyPlaytune.h>
|
||||
```
|
||||
|
||||
You then have to create an object for the *ArduboyPlaytune* class and pass it a pointer to the Arduboy2 *audio.enabled()* function. This must go after the creation of the Arduboy2 object, like so:
|
||||
|
||||
```cpp
|
||||
Arduboy2 arduboy;
|
||||
ArduboyPlaytune tunes(arduboy.audio.enabled);
|
||||
```
|
||||
|
||||
The sound channels must then be initialzed and assigned to the speaker pins. This code would go in the *setup()* function:
|
||||
|
||||
```cpp
|
||||
// audio setup
|
||||
tunes.initChannel(PIN_SPEAKER_1);
|
||||
#ifndef AB_DEVKIT
|
||||
// if not a DevKit
|
||||
tunes.initChannel(PIN_SPEAKER_2);
|
||||
#else
|
||||
// if it's a DevKit
|
||||
tunes.initChannel(PIN_SPEAKER_1); // use the same pin for both channels
|
||||
tunes.toneMutesScore(true); // mute the score when a tone is sounding
|
||||
#endif
|
||||
```
|
||||
|
||||
If you name the ArduboyPlaytune object *tunes* as shown above, then you just have to remove the Arduboy object name from any *tunes* calls. For example:
|
||||
|
||||
```cpp
|
||||
arduboy.tunes.playScore(mySong);
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```cpp
|
||||
tunes.playScore(mySong);
|
||||
```
|
||||
|
||||
See the [*ArduboyPlaytune* library](https://github.com/Arduboy/ArduboyPlayTune) documentation for more information.
|
||||
|
||||
If you don't need to play scores containing two parts, and don't require tones to be played in parallel with a score that's playing, then as an alternative to using *ArduboyPlaytune* you may wish to consider switching to *ArduboyTones*. This may require a bit of work because any *ArduboyPlaytune* scores would have to be converted to *ArduboyTones* format. It would involve changing note numbers to frequencies. This could be simplified by using the provided *NOTE_* defines. Also, durations would have to be converted, including adding silent "rest" tones as necessary.
|
||||
|
||||
The benefit of using *ArduboyTones* would be reduced code size and possibly easier addition of new sequences without the need of a MIDI to Playtune format converter.
|
||||
|
||||
### Sketch uses the *beginNoLogo()* function instead of *begin()*
|
||||
|
||||
The *beginNoLogo()* function has been removed. Instead, *boot()* can be used with additional functions following it to add back in desired boot functionality. See the information above, under the heading *Remove boot up features*, for more details. Assuming the object is named *arduboy*, a direct replacement for *beginNoLogo()* would be:
|
||||
|
||||
```cpp
|
||||
arduboy.boot();
|
||||
arduboy.display();
|
||||
arduboy.flashlight();
|
||||
arduboy.audio.begin();
|
||||
```
|
||||
|
||||
----------
|
||||
|
|
@ -0,0 +1,716 @@
|
|||
/*
|
||||
Breakout
|
||||
Copyright (C) 2011 Sebastian Goscik
|
||||
All rights reserved.
|
||||
|
||||
Modifications by Scott Allen 2016 (after previous changes by ???)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <Arduboy2.h>
|
||||
|
||||
// block in EEPROM to save high scores
|
||||
#define EE_FILE 2
|
||||
|
||||
Arduboy2 arduboy;
|
||||
BeepPin1 beep;
|
||||
|
||||
const unsigned int FRAME_RATE = 40; // Frame rate in frames per second
|
||||
const unsigned int COLUMNS = 13; //Columns of bricks
|
||||
const unsigned int ROWS = 4; //Rows of bricks
|
||||
int dx = -1; //Initial movement of ball
|
||||
int dy = -1; //Initial movement of ball
|
||||
int xb; //Balls starting possition
|
||||
int yb; //Balls starting possition
|
||||
boolean released; //If the ball has been released by the player
|
||||
boolean paused = false; //If the game has been paused
|
||||
byte xPaddle; //X position of paddle
|
||||
boolean isHit[ROWS][COLUMNS]; //Array of if bricks are hit or not
|
||||
boolean bounced=false; //Used to fix double bounce glitch
|
||||
byte lives = 3; //Amount of lives
|
||||
byte level = 1; //Current level
|
||||
unsigned int score=0; //Score for the game
|
||||
unsigned int brickCount; //Amount of bricks hit
|
||||
boolean pad, pad2, pad3; //Button press buffer used to stop pause repeating
|
||||
boolean oldpad, oldpad2, oldpad3;
|
||||
char text_buffer[16]; //General string buffer
|
||||
boolean start=false; //If in menu or in game
|
||||
boolean initialDraw=false;//If the inital draw has happened
|
||||
char initials[3]; //Initials used in high score
|
||||
|
||||
//Ball Bounds used in collision detection
|
||||
byte leftBall;
|
||||
byte rightBall;
|
||||
byte topBall;
|
||||
byte bottomBall;
|
||||
|
||||
//Brick Bounds used in collision detection
|
||||
byte leftBrick;
|
||||
byte rightBrick;
|
||||
byte topBrick;
|
||||
byte bottomBrick;
|
||||
|
||||
byte tick;
|
||||
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
beep.begin();
|
||||
arduboy.setFrameRate(FRAME_RATE);
|
||||
arduboy.initRandomSeed();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// Handle the timing and stopping of tones
|
||||
beep.timer();
|
||||
|
||||
//Title screen loop switches from title screen
|
||||
//and high scores until FIRE is pressed
|
||||
while (!start)
|
||||
{
|
||||
start = titleScreen();
|
||||
if (!start)
|
||||
{
|
||||
start = displayHighScores(EE_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
//Initial level draw
|
||||
if (!initialDraw)
|
||||
{
|
||||
//Clears the screen
|
||||
arduboy.clear();
|
||||
//Selects Font
|
||||
//Draws the new level
|
||||
level = 1;
|
||||
newLevel();
|
||||
score = 0;
|
||||
initialDraw=true;
|
||||
}
|
||||
|
||||
if (lives>0)
|
||||
{
|
||||
drawPaddle();
|
||||
|
||||
//Pause game if FIRE pressed
|
||||
pad = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
|
||||
if(pad == true && oldpad == false && released)
|
||||
{
|
||||
oldpad2 = false; //Forces pad loop 2 to run once
|
||||
pause();
|
||||
}
|
||||
|
||||
oldpad = pad;
|
||||
drawBall();
|
||||
|
||||
if(brickCount == ROWS * COLUMNS)
|
||||
{
|
||||
level++;
|
||||
newLevel();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drawGameOver();
|
||||
if (score > 0)
|
||||
{
|
||||
enterHighScore(EE_FILE);
|
||||
}
|
||||
|
||||
arduboy.clear();
|
||||
initialDraw=false;
|
||||
start=false;
|
||||
lives=3;
|
||||
newLevel();
|
||||
}
|
||||
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
void movePaddle()
|
||||
{
|
||||
//Move right
|
||||
if(xPaddle < WIDTH - 12)
|
||||
{
|
||||
if (arduboy.pressed(RIGHT_BUTTON))
|
||||
{
|
||||
xPaddle+=2;
|
||||
}
|
||||
}
|
||||
|
||||
//Move left
|
||||
if(xPaddle > 0)
|
||||
{
|
||||
if (arduboy.pressed(LEFT_BUTTON))
|
||||
{
|
||||
xPaddle-=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void moveBall()
|
||||
{
|
||||
tick++;
|
||||
if(released)
|
||||
{
|
||||
//Move ball
|
||||
if (abs(dx)==2) {
|
||||
xb += dx/2;
|
||||
// 2x speed is really 1.5 speed
|
||||
if (tick%2==0)
|
||||
xb += dx/2;
|
||||
} else {
|
||||
xb += dx;
|
||||
}
|
||||
yb=yb + dy;
|
||||
|
||||
//Set bounds
|
||||
leftBall = xb;
|
||||
rightBall = xb + 2;
|
||||
topBall = yb;
|
||||
bottomBall = yb + 2;
|
||||
|
||||
//Bounce off top edge
|
||||
if (yb <= 0)
|
||||
{
|
||||
yb = 2;
|
||||
dy = -dy;
|
||||
playTone(523, 250);
|
||||
}
|
||||
|
||||
//Lose a life if bottom edge hit
|
||||
if (yb >= 64)
|
||||
{
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
xPaddle = 54;
|
||||
yb=60;
|
||||
released = false;
|
||||
lives--;
|
||||
playToneTimed(175, 500);
|
||||
if (random(0, 2) == 0)
|
||||
{
|
||||
dx = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//Bounce off left side
|
||||
if (xb <= 0)
|
||||
{
|
||||
xb = 2;
|
||||
dx = -dx;
|
||||
playTone(523, 250);
|
||||
}
|
||||
|
||||
//Bounce off right side
|
||||
if (xb >= WIDTH - 2)
|
||||
{
|
||||
xb = WIDTH - 4;
|
||||
dx = -dx;
|
||||
playTone(523, 250);
|
||||
}
|
||||
|
||||
//Bounce off paddle
|
||||
if (xb+1>=xPaddle && xb<=xPaddle+12 && yb+2>=63 && yb<=64)
|
||||
{
|
||||
dy = -dy;
|
||||
dx = ((xb-(xPaddle+6))/3); //Applies spin on the ball
|
||||
// prevent straight bounce
|
||||
if (dx == 0) {
|
||||
dx = (random(0,2) == 1) ? 1 : -1;
|
||||
}
|
||||
playTone(200, 250);
|
||||
}
|
||||
|
||||
//Bounce off Bricks
|
||||
for (byte row = 0; row < ROWS; row++)
|
||||
{
|
||||
for (byte column = 0; column < COLUMNS; column++)
|
||||
{
|
||||
if (!isHit[row][column])
|
||||
{
|
||||
//Sets Brick bounds
|
||||
leftBrick = 10 * column;
|
||||
rightBrick = 10 * column + 10;
|
||||
topBrick = 6 * row + 1;
|
||||
bottomBrick = 6 * row + 7;
|
||||
|
||||
//If A collison has occured
|
||||
if (topBall <= bottomBrick && bottomBall >= topBrick &&
|
||||
leftBall <= rightBrick && rightBall >= leftBrick)
|
||||
{
|
||||
Score();
|
||||
brickCount++;
|
||||
isHit[row][column] = true;
|
||||
arduboy.drawRect(10*column, 2+6*row, 8, 4, 0);
|
||||
|
||||
//Vertical collision
|
||||
if (bottomBall > bottomBrick || topBall < topBrick)
|
||||
{
|
||||
//Only bounce once each ball move
|
||||
if(!bounced)
|
||||
{
|
||||
dy =- dy;
|
||||
yb += dy;
|
||||
bounced = true;
|
||||
playTone(261, 250);
|
||||
}
|
||||
}
|
||||
|
||||
//Hoizontal collision
|
||||
if (leftBall < leftBrick || rightBall > rightBrick)
|
||||
{
|
||||
//Only bounce once brick each ball move
|
||||
if(!bounced)
|
||||
{
|
||||
dx =- dx;
|
||||
xb += dx;
|
||||
bounced = true;
|
||||
playTone(261, 250);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Reset Bounce
|
||||
bounced = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Ball follows paddle
|
||||
xb=xPaddle + 5;
|
||||
|
||||
//Release ball if FIRE pressed
|
||||
pad3 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if (pad3 == true && oldpad3 == false)
|
||||
{
|
||||
released = true;
|
||||
|
||||
//Apply random direction to ball on release
|
||||
if (random(0, 2) == 0)
|
||||
{
|
||||
dx = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = -1;
|
||||
}
|
||||
//Makes sure the ball heads upwards
|
||||
dy = -1;
|
||||
}
|
||||
oldpad3 = pad3;
|
||||
}
|
||||
}
|
||||
|
||||
void drawBall()
|
||||
{
|
||||
// arduboy.setCursor(0,0);
|
||||
// arduboy.print(arduboy.cpuLoad());
|
||||
// arduboy.print(" ");
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
|
||||
moveBall();
|
||||
|
||||
arduboy.drawPixel(xb, yb, 1);
|
||||
arduboy.drawPixel(xb+1, yb, 1);
|
||||
arduboy.drawPixel(xb, yb+1, 1);
|
||||
arduboy.drawPixel(xb+1, yb+1, 1);
|
||||
}
|
||||
|
||||
void drawPaddle()
|
||||
{
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
movePaddle();
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 1);
|
||||
}
|
||||
|
||||
void drawGameOver()
|
||||
{
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
arduboy.setCursor(37, 42);
|
||||
arduboy.print("Game Over");
|
||||
arduboy.setCursor(31, 56);
|
||||
arduboy.print("Score: ");
|
||||
arduboy.print(score);
|
||||
arduboy.display();
|
||||
arduboy.delayShort(4000);
|
||||
}
|
||||
|
||||
void pause()
|
||||
{
|
||||
paused = true;
|
||||
//Draw pause to the screen
|
||||
arduboy.setCursor(52, 45);
|
||||
arduboy.print("PAUSE");
|
||||
arduboy.display();
|
||||
while (paused)
|
||||
{
|
||||
arduboy.delayShort(150);
|
||||
//Unpause if FIRE is pressed
|
||||
pad2 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if (pad2 == true && oldpad2 == false && released)
|
||||
{
|
||||
arduboy.fillRect(52, 45, 30, 11, 0);
|
||||
|
||||
paused=false;
|
||||
}
|
||||
oldpad2 = pad2;
|
||||
}
|
||||
}
|
||||
|
||||
void Score()
|
||||
{
|
||||
score += (level*10);
|
||||
}
|
||||
|
||||
void newLevel(){
|
||||
//Undraw paddle
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
|
||||
//Undraw ball
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
|
||||
//Alter various variables to reset the game
|
||||
xPaddle = 54;
|
||||
yb = 60;
|
||||
brickCount = 0;
|
||||
released = false;
|
||||
|
||||
//Draws new bricks and resets their values
|
||||
for (byte row = 0; row < 4; row++) {
|
||||
for (byte column = 0; column < 13; column++)
|
||||
{
|
||||
isHit[row][column] = false;
|
||||
arduboy.drawRect(10*column, 2+6*row, 8, 4, 1);
|
||||
}
|
||||
}
|
||||
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
//Used to delay images while reading button input
|
||||
boolean pollFireButton(int n)
|
||||
{
|
||||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
arduboy.delayShort(15);
|
||||
pad = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if(pad == true && oldpad == false)
|
||||
{
|
||||
oldpad3 = true; //Forces pad loop 3 to run once
|
||||
return true;
|
||||
}
|
||||
oldpad = pad;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//Function by nootropic design to display highscores
|
||||
boolean displayHighScores(byte file)
|
||||
{
|
||||
byte y = 8;
|
||||
byte x = 24;
|
||||
// Each block of EEPROM has 7 high scores, and each high score entry
|
||||
// is 5 bytes long: 3 bytes for initials and two bytes for score.
|
||||
int address = file * 7 * 5 + EEPROM_STORAGE_SPACE_START;
|
||||
byte hi, lo;
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(32, 0);
|
||||
arduboy.print("HIGH SCORES");
|
||||
arduboy.display();
|
||||
|
||||
for(int i = 0; i < 7; i++)
|
||||
{
|
||||
sprintf(text_buffer, "%2d", i+1);
|
||||
arduboy.setCursor(x,y+(i*8));
|
||||
arduboy.print(text_buffer);
|
||||
arduboy.display();
|
||||
hi = EEPROM.read(address + (5*i));
|
||||
lo = EEPROM.read(address + (5*i) + 1);
|
||||
|
||||
if ((hi == 0xFF) && (lo == 0xFF))
|
||||
{
|
||||
score = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
score = (hi << 8) | lo;
|
||||
}
|
||||
|
||||
initials[0] = (char)EEPROM.read(address + (5*i) + 2);
|
||||
initials[1] = (char)EEPROM.read(address + (5*i) + 3);
|
||||
initials[2] = (char)EEPROM.read(address + (5*i) + 4);
|
||||
|
||||
if (score > 0)
|
||||
{
|
||||
sprintf(text_buffer, "%c%c%c %u", initials[0], initials[1], initials[2], score);
|
||||
arduboy.setCursor(x + 24, y + (i*8));
|
||||
arduboy.print(text_buffer);
|
||||
arduboy.display();
|
||||
}
|
||||
}
|
||||
if (pollFireButton(300))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
boolean titleScreen()
|
||||
{
|
||||
//Clears the screen
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(16,22);
|
||||
arduboy.setTextSize(2);
|
||||
arduboy.print("BREAKOUT");
|
||||
arduboy.setTextSize(1);
|
||||
arduboy.display();
|
||||
if (pollFireButton(25))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//Flash "Press FIRE" 5 times
|
||||
for(byte i = 0; i < 5; i++)
|
||||
{
|
||||
//Draws "Press FIRE"
|
||||
arduboy.setCursor(31, 53);
|
||||
arduboy.print("PRESS FIRE!");
|
||||
arduboy.display();
|
||||
|
||||
if (pollFireButton(50))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//Removes "Press FIRE"
|
||||
arduboy.setCursor(31, 53);
|
||||
arduboy.print(" ");
|
||||
arduboy.display();
|
||||
|
||||
if (pollFireButton(25))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//Function by nootropic design to add high scores
|
||||
void enterInitials()
|
||||
{
|
||||
byte index = 0;
|
||||
|
||||
arduboy.clear();
|
||||
|
||||
initials[0] = ' ';
|
||||
initials[1] = ' ';
|
||||
initials[2] = ' ';
|
||||
|
||||
while (true)
|
||||
{
|
||||
arduboy.display();
|
||||
arduboy.clear();
|
||||
|
||||
arduboy.setCursor(16,0);
|
||||
arduboy.print("HIGH SCORE");
|
||||
sprintf(text_buffer, "%u", score);
|
||||
arduboy.setCursor(88, 0);
|
||||
arduboy.print(text_buffer);
|
||||
arduboy.setCursor(56, 20);
|
||||
arduboy.print(initials[0]);
|
||||
arduboy.setCursor(64, 20);
|
||||
arduboy.print(initials[1]);
|
||||
arduboy.setCursor(72, 20);
|
||||
arduboy.print(initials[2]);
|
||||
for(byte i = 0; i < 3; i++)
|
||||
{
|
||||
arduboy.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1);
|
||||
}
|
||||
arduboy.drawLine(56, 28, 88, 28, 0);
|
||||
arduboy.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, 1);
|
||||
arduboy.delayShort(70);
|
||||
|
||||
if (arduboy.pressed(LEFT_BUTTON) || arduboy.pressed(B_BUTTON))
|
||||
{
|
||||
if (index > 0)
|
||||
{
|
||||
index--;
|
||||
playToneTimed(1046, 80);
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(RIGHT_BUTTON))
|
||||
{
|
||||
if (index < 2)
|
||||
{
|
||||
index++;
|
||||
playToneTimed(1046, 80);
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(UP_BUTTON))
|
||||
{
|
||||
initials[index]++;
|
||||
playToneTimed(523, 80);
|
||||
// A-Z 0-9 :-? !-/ ' '
|
||||
if (initials[index] == '0')
|
||||
{
|
||||
initials[index] = ' ';
|
||||
}
|
||||
if (initials[index] == '!')
|
||||
{
|
||||
initials[index] = 'A';
|
||||
}
|
||||
if (initials[index] == '[')
|
||||
{
|
||||
initials[index] = '0';
|
||||
}
|
||||
if (initials[index] == '@')
|
||||
{
|
||||
initials[index] = '!';
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(DOWN_BUTTON))
|
||||
{
|
||||
initials[index]--;
|
||||
playToneTimed(523, 80);
|
||||
if (initials[index] == ' ') {
|
||||
initials[index] = '?';
|
||||
}
|
||||
if (initials[index] == '/') {
|
||||
initials[index] = 'Z';
|
||||
}
|
||||
if (initials[index] == 31) {
|
||||
initials[index] = '/';
|
||||
}
|
||||
if (initials[index] == '@') {
|
||||
initials[index] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (arduboy.pressed(A_BUTTON))
|
||||
{
|
||||
playToneTimed(1046, 80);
|
||||
if (index < 2)
|
||||
{
|
||||
index++;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void enterHighScore(byte file)
|
||||
{
|
||||
// Each block of EEPROM has 7 high scores, and each high score entry
|
||||
// is 5 bytes long: 3 bytes for initials and two bytes for score.
|
||||
int address = file * 7 * 5 + EEPROM_STORAGE_SPACE_START;
|
||||
byte hi, lo;
|
||||
char tmpInitials[3];
|
||||
unsigned int tmpScore = 0;
|
||||
|
||||
// High score processing
|
||||
for(byte i = 0; i < 7; i++)
|
||||
{
|
||||
hi = EEPROM.read(address + (5*i));
|
||||
lo = EEPROM.read(address + (5*i) + 1);
|
||||
if ((hi == 0xFF) && (lo == 0xFF))
|
||||
{
|
||||
// The values are uninitialized, so treat this entry
|
||||
// as a score of 0.
|
||||
tmpScore = 0;
|
||||
} else
|
||||
{
|
||||
tmpScore = (hi << 8) | lo;
|
||||
}
|
||||
if (score > tmpScore)
|
||||
{
|
||||
enterInitials();
|
||||
for(byte j = i; j < 7; j++)
|
||||
{
|
||||
hi = EEPROM.read(address + (5*j));
|
||||
lo = EEPROM.read(address + (5*j) + 1);
|
||||
|
||||
if ((hi == 0xFF) && (lo == 0xFF))
|
||||
{
|
||||
tmpScore = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpScore = (hi << 8) | lo;
|
||||
}
|
||||
|
||||
tmpInitials[0] = (char)EEPROM.read(address + (5*j) + 2);
|
||||
tmpInitials[1] = (char)EEPROM.read(address + (5*j) + 3);
|
||||
tmpInitials[2] = (char)EEPROM.read(address + (5*j) + 4);
|
||||
|
||||
// write score and initials to current slot
|
||||
EEPROM.update(address + (5*j), ((score >> 8) & 0xFF));
|
||||
EEPROM.update(address + (5*j) + 1, (score & 0xFF));
|
||||
EEPROM.update(address + (5*j) + 2, initials[0]);
|
||||
EEPROM.update(address + (5*j) + 3, initials[1]);
|
||||
EEPROM.update(address + (5*j) + 4, initials[2]);
|
||||
|
||||
// tmpScore and tmpInitials now hold what we want to
|
||||
//write in the next slot.
|
||||
score = tmpScore;
|
||||
initials[0] = tmpInitials[0];
|
||||
initials[1] = tmpInitials[1];
|
||||
initials[2] = tmpInitials[2];
|
||||
}
|
||||
|
||||
score = 0;
|
||||
initials[0] = ' ';
|
||||
initials[1] = ' ';
|
||||
initials[2] = ' ';
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Play a tone at the specified frequency for the specified duration.
|
||||
void playTone(unsigned int frequency, unsigned int duration)
|
||||
{
|
||||
beep.tone(beep.freq(frequency), duration / (1000 / FRAME_RATE));
|
||||
}
|
||||
|
||||
// Play a tone at the specified frequency for the specified duration using
|
||||
// a delay to time the tone.
|
||||
// Used when beep.timer() isn't being called.
|
||||
void playToneTimed(unsigned int frequency, unsigned int duration)
|
||||
{
|
||||
beep.tone(beep.freq(frequency));
|
||||
arduboy.delayShort(duration);
|
||||
beep.noTone();
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# ArduBreakout
|
||||
|
||||
Brick breaking game in the vein of Atari's *Breakout*.
|
||||
|
||||
Control the paddle with the directional keys to keep a ball bouncing against a brick wall until all of the bricks are broken.
|
||||
|
||||
High scores are saved to EEPROM and can be saved through Arduboy restarts.
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
This sketch provides an example of using the Arduboy2 library's BeepPin1 class
|
||||
to play simple tones.
|
||||
*/
|
||||
|
||||
/*
|
||||
To the extent possible under law, Scott Allen has waived all copyright and
|
||||
related or neighboring rights to this BeepDemo program.
|
||||
*/
|
||||
|
||||
// Comments are only provided for code dealing with tone generation or control.
|
||||
|
||||
#include <Arduboy2.h>
|
||||
// There's no need to #include <Arduboy2Beep.h>
|
||||
// It will be included in Arduboy2.h
|
||||
|
||||
Arduboy2 arduboy;
|
||||
|
||||
BeepPin1 beep; // Create a class instance for speaker pin 1
|
||||
//BeepPin2 beep; // For speaker pin 2, use this line instead of the line above
|
||||
|
||||
int objectX = 0;
|
||||
|
||||
char displayText[60];
|
||||
|
||||
void setup() {
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(25);
|
||||
|
||||
beep.begin(); // Set up the hardware for playing tones
|
||||
|
||||
commandText("none - Press buttons");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (!arduboy.nextFrame()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The timer() function is called once per frame, so duration values will be
|
||||
// the number of frames that the tone plays for.
|
||||
// At 25 frames per second each frame will be 40ms.
|
||||
beep.timer(); // handle tone duration
|
||||
|
||||
arduboy.pollButtons();
|
||||
|
||||
if (arduboy.justPressed(LEFT_BUTTON)) {
|
||||
// Play a 523.251Hz tone (piano note C5) for 5 frames (200ms at 25 FPS)
|
||||
// beep.freq(523.251) is used to convert 523.251Hz to the required count
|
||||
beep.tone(beep.freq(523.251), 5);
|
||||
|
||||
commandText("beep.tone(\n beep.freq(523.251),\n 5)");
|
||||
}
|
||||
|
||||
if (arduboy.justPressed(UP_BUTTON)) {
|
||||
// Play a 587.330Hz tone (piano note D5) for 15 frames (600ms at 25 FPS)
|
||||
beep.tone(beep.freq(587.330), 15);
|
||||
|
||||
commandText("beep.tone(\n beep.freq(587.330),\n 15)");
|
||||
}
|
||||
|
||||
if (arduboy.justPressed(RIGHT_BUTTON)) {
|
||||
// Play a 659.255Hz tone (piano note E5) for 50 frames (2s at 25 FPS)
|
||||
beep.tone(beep.freq(659.255), 50);
|
||||
|
||||
commandText("beep.tone(\n beep.freq(659.255),\n 50)");
|
||||
}
|
||||
|
||||
if (arduboy.justPressed(DOWN_BUTTON)) {
|
||||
// Play a 698.456Hz tone (piano note F5) until stopped
|
||||
// or replaced by another tone
|
||||
beep.tone(beep.freq(698.456));
|
||||
|
||||
commandText("beep.tone(\n beep.freq(698.456))");
|
||||
}
|
||||
|
||||
if (arduboy.justPressed(A_BUTTON)) {
|
||||
// For short tones with a duration less than a frame time,
|
||||
// or when timer() isn't being used, such as in a menu,
|
||||
// a continuous tone can be played and then stopped after a delay
|
||||
// but note that no other work will be done during the delay.
|
||||
beep.tone(beep.freq(1000)); // Play a 1000Hz tone until stopped
|
||||
arduboy.delayShort(30); // Delay for 30ms
|
||||
beep.noTone(); // Stop the tone
|
||||
|
||||
commandText("beep.tone(\n beep.freq(1000))\n(delay 30ms)\nbeep.noTone()");
|
||||
}
|
||||
|
||||
if (arduboy.justPressed(B_BUTTON)) {
|
||||
beep.noTone(); // Stop the tone if one is playing
|
||||
|
||||
commandText("beep.noTone()");
|
||||
}
|
||||
|
||||
arduboy.println(F("Last command:"));
|
||||
arduboy.print(displayText);
|
||||
|
||||
// The Arduboy2 class's audio subclass controls sound muting.
|
||||
// For this sketch, mute or unmute can be set using the "System Control"
|
||||
// start up feature. (Hold B while powering up then, while still holding B,
|
||||
// press UP to enable sound or DOWN for mute.)
|
||||
if (!arduboy.audio.enabled()) {
|
||||
arduboy.setCursor(22, 40);
|
||||
arduboy.print(F("Sound is MUTED"));
|
||||
}
|
||||
|
||||
arduboy.setCursor(0, 48);
|
||||
// The "duration" variable can be tested for non-zero to determine if a
|
||||
// timed tone is currently playing.
|
||||
if (beep.duration != 0) {
|
||||
arduboy.print(F("A tone is playing"));
|
||||
}
|
||||
else {
|
||||
arduboy.print(F("Continuous tone or\nno tone playing"));
|
||||
}
|
||||
|
||||
arduboy.drawRect(objectX, 40, 6, 6);
|
||||
if (++objectX == WIDTH - 6) {
|
||||
objectX = 0;
|
||||
}
|
||||
|
||||
arduboy.display(CLEAR_BUFFER);
|
||||
}
|
||||
|
||||
void commandText(const char* text) {
|
||||
strncpy(displayText, text, sizeof displayText);
|
||||
displayText[sizeof displayText - 1] = '\0';
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Buttons example
|
||||
June 11, 2015
|
||||
Copyright (C) 2015 David Martinez
|
||||
All rights reserved.
|
||||
This code is the most basic barebones code for showing how to use buttons in
|
||||
Arduboy.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <Arduboy2.h>
|
||||
|
||||
// Make an instance of arduboy used for many functions
|
||||
Arduboy2 arduboy;
|
||||
|
||||
// Variables for your game go here.
|
||||
char title[] = "Press Buttons!";
|
||||
byte x;
|
||||
byte y;
|
||||
|
||||
// Width of each charcter including inter-character space
|
||||
#define CHAR_WIDTH 6
|
||||
|
||||
// Height of each charater
|
||||
#define CHAR_HEIGHT 8
|
||||
|
||||
// To get the number of characters, we subtract 1 from the length of
|
||||
// the array because there will be a NULL terminator at the end.
|
||||
#define NUM_CHARS (sizeof(title) - 1)
|
||||
|
||||
// This is the highest value that x can be without the end of the text
|
||||
// going farther than the right side of the screen. We add one because
|
||||
// there will be a 1 pixel space at the end of the last character.
|
||||
// WIDTH and HEIGHT are defined in the Arduboy library.
|
||||
#define X_MAX (WIDTH - (NUM_CHARS * CHAR_WIDTH) + 1)
|
||||
|
||||
// This is the highest value that y can be without the text going below
|
||||
// the bottom of the screen.
|
||||
#define Y_MAX (HEIGHT - CHAR_HEIGHT)
|
||||
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
//initiate arduboy instance
|
||||
arduboy.begin();
|
||||
|
||||
// here we set the framerate to 30, we do not need to run at default 60 and
|
||||
// it saves us battery life.
|
||||
arduboy.setFrameRate(30);
|
||||
|
||||
// set x and y to the middle of the screen
|
||||
x = (WIDTH / 2) - (NUM_CHARS * CHAR_WIDTH / 2);
|
||||
y = (HEIGHT / 2) - (CHAR_HEIGHT / 2);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// the next couple of lines will deal with checking if the D-pad buttons
|
||||
// are pressed and move our text accordingly.
|
||||
// We check to make sure that x and y stay within a range that keeps the
|
||||
// text on the screen.
|
||||
|
||||
// if the right button is pressed move 1 pixel to the right every frame
|
||||
if(arduboy.pressed(RIGHT_BUTTON) && (x < X_MAX)) {
|
||||
x++;
|
||||
}
|
||||
|
||||
// if the left button is pressed move 1 pixel to the left every frame
|
||||
if(arduboy.pressed(LEFT_BUTTON) && (x > 0)) {
|
||||
x--;
|
||||
}
|
||||
|
||||
// if the up button or B button is pressed move 1 pixel up every frame
|
||||
if((arduboy.pressed(UP_BUTTON) || arduboy.pressed(B_BUTTON)) && (y > 0)) {
|
||||
y--;
|
||||
}
|
||||
|
||||
// if the down button or A button is pressed move 1 pixel down every frame
|
||||
if((arduboy.pressed(DOWN_BUTTON) || arduboy.pressed(A_BUTTON)) && (y < Y_MAX)) {
|
||||
y++;
|
||||
}
|
||||
|
||||
|
||||
// we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
// we set our cursor x pixels to the right and y down from the top
|
||||
arduboy.setCursor(x, y);
|
||||
|
||||
// then we print to screen what is stored in our title variable we declared earlier
|
||||
arduboy.print(title);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display.
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Buttons
|
||||
=======
|
||||
|
||||
A an example that demonstrates how to capture input from the buttons.
|
|
@ -0,0 +1,169 @@
|
|||
/*******************************************************************************
|
||||
Arduboy hardware test toy v1.0 September 2017 by Mr.Blinky
|
||||
*******************************************************************************/
|
||||
|
||||
#include <Arduboy2.h>
|
||||
#include "globals.h"
|
||||
#include "bitmaps.h"
|
||||
|
||||
Arduboy2 arduboy;
|
||||
Sprites sprites;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(FRAMERATE);
|
||||
arduboy.audio.on;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
sprites.drawOverwrite(BACKGROUND_X,BACKGROUND_Y,background_gfx,0);
|
||||
#ifdef AB_DEVKIT
|
||||
sprites.drawOverwrite(NOSPEAKER_X,NOSPEAKER_Y,nospeaker_gfx,0);
|
||||
#endif
|
||||
|
||||
//button input control
|
||||
if (arduboy.pressed(LEFT_BUTTON))
|
||||
{
|
||||
sprites.drawSelfMasked(BUTTON_LEFT_X,BUTTON_LEFT_Y,buttonleft_gfx,0);
|
||||
if (selectedOption > 4) selectedOption--;
|
||||
else if (selectedOption < 3) decreaseOptionValue();
|
||||
hardwareChange = true;
|
||||
}
|
||||
if (arduboy.pressed(RIGHT_BUTTON))
|
||||
{
|
||||
sprites.drawSelfMasked(BUTTON_RIGHT_X,BUTTON_RIGHT_Y,buttonright_gfx,0);
|
||||
if (selectedOption > 2)
|
||||
{
|
||||
if (selectedOption == 3) selectedOption += 2;
|
||||
else if (selectedOption < MAX_OPTIONS-1) selectedOption++;
|
||||
}
|
||||
else increaseOptionValue();
|
||||
hardwareChange = true;
|
||||
}
|
||||
if (arduboy.pressed(UP_BUTTON))
|
||||
{
|
||||
sprites.drawSelfMasked(BUTTON_UP_X,BUTTON_UP_Y,buttonup_gfx,0);
|
||||
if (selectedOption > 0) selectedOption--;
|
||||
hardwareChange = true;
|
||||
}
|
||||
if (arduboy.pressed(DOWN_BUTTON))
|
||||
{
|
||||
sprites.drawSelfMasked(BUTTON_DOWN_X,BUTTON_DOWN_Y,buttondown_gfx,0);
|
||||
if (selectedOption < MAX_OPTIONS-1) selectedOption++;
|
||||
hardwareChange = true;
|
||||
}
|
||||
if (arduboy.pressed(A_BUTTON))
|
||||
{
|
||||
sprites.drawSelfMasked(BUTTON_A_X,BUTTON_A_Y,button_gfx,0);
|
||||
decreaseOptionValue();
|
||||
hardwareChange = true;
|
||||
}
|
||||
if (arduboy.pressed(B_BUTTON))
|
||||
{
|
||||
sprites.drawSelfMasked(BUTTON_B_X,BUTTON_B_Y,button_gfx,0);
|
||||
increaseOptionValue();
|
||||
hardwareChange = true;
|
||||
}
|
||||
|
||||
// draw focused option
|
||||
switch (selectedOption)
|
||||
{
|
||||
case 0: sprites.drawOverwrite(RED_X,RED_Y,red_focus_gfx,0);
|
||||
break;
|
||||
case 1: sprites.drawOverwrite(GREEN_X,GREEN_Y,green_focus_gfx,0);
|
||||
break;
|
||||
case 2: sprites.drawOverwrite(BLUE_X,BLUE_Y,blue_focus_gfx,0);
|
||||
break;
|
||||
case 3: sprites.drawOverwrite(RXLED_X,RXLED_Y,rxled_on_focus_gfx,0);
|
||||
break;
|
||||
case 4: sprites.drawOverwrite(TXLED_X,TXLED_Y,txled_on_focus_gfx,0);
|
||||
break;
|
||||
case 5: sprites.drawOverwrite(SPEAKER1_X,SPEAKER1_Y,speaker1_on_focus_gfx,0);
|
||||
break;
|
||||
case 6: sprites.drawOverwrite(SPEAKER2_X,SPEAKER2_Y,speaker2_on_focus_gfx,0);
|
||||
break;
|
||||
}
|
||||
|
||||
//Draw option values
|
||||
sprites.drawOverwrite(SLIDER_X + SLIDER_X_STEP * rgbLed.red,SLIDER_Y,slider_gfx,0);
|
||||
sprites.drawOverwrite(SLIDER_X + SLIDER_X_STEP * rgbLed.green,SLIDER_Y + 1 * SLIDER_HEIGHT,slider_gfx,0);
|
||||
sprites.drawOverwrite(SLIDER_X + SLIDER_X_STEP * rgbLed.blue,SLIDER_Y + 2 * SLIDER_HEIGHT,slider_gfx,0);
|
||||
sprites.drawOverwrite(ON_GFX_X,ON_GFX_Y,rxled_on ? on_gfx : off_gfx,0);
|
||||
sprites.drawOverwrite(OFF_GFX_X,OFF_GFX_Y,txled_on ? on_gfx : off_gfx,0);
|
||||
if (speaker1_on) sprites.drawOverwrite(SOUND1_X,SOUND1_Y,sound_gfx,0);
|
||||
if (speaker2_on) sprites.drawOverwrite(SOUND2_X,SOUND2_Y,sound_gfx,0);
|
||||
//update complete display
|
||||
arduboy.display();
|
||||
|
||||
//apply hardware changes
|
||||
if (hardwareChange)
|
||||
{
|
||||
arduboy.setRGBled(pgm_read_byte(rgbValues + rgbLed.red), pgm_read_byte(rgbValues + rgbLed.green), pgm_read_byte(rgbValues + rgbLed.blue));
|
||||
rxled_on ? RXLED1 : RXLED0;
|
||||
txled_on ? TXLED1 : TXLED0;
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
speaker1_on ? SPEAKER_1_PORT ^= _BV(SPEAKER_1_BIT) : SPEAKER_1_PORT &= ~_BV(SPEAKER_1_BIT);
|
||||
#ifndef AB_DEVKIT
|
||||
speaker2_on ? SPEAKER_2_PORT ^= _BV(SPEAKER_2_BIT) : SPEAKER_2_PORT |= _BV(SPEAKER_2_BIT);
|
||||
#endif
|
||||
delayMicroseconds(300);
|
||||
}
|
||||
hardwareChange = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void decreaseOptionValue(void)
|
||||
{
|
||||
switch (selectedOption)
|
||||
{
|
||||
case 0: if (rgbLed.red > 0) rgbLed.red --;
|
||||
break;
|
||||
case 1: if (rgbLed.green > 0) rgbLed.green --;
|
||||
break;
|
||||
case 2: if (rgbLed.blue > 0) rgbLed.blue --;
|
||||
break;
|
||||
case 3: rxled_on = !rxled_on;
|
||||
break;
|
||||
case 4: txled_on = !txled_on;
|
||||
break;
|
||||
case 5: speaker1_on = !speaker1_on;
|
||||
break;
|
||||
case 6: speaker2_on = !speaker2_on;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void increaseOptionValue(void)
|
||||
{
|
||||
switch (selectedOption)
|
||||
{
|
||||
case 0: if (rgbLed.red < RGB_MAX_STEPS-1) rgbLed.red ++;
|
||||
break;
|
||||
case 1: if (rgbLed.green < RGB_MAX_STEPS-1) rgbLed.green ++;
|
||||
break;
|
||||
case 2: if (rgbLed.blue < RGB_MAX_STEPS-1) rgbLed.blue ++;
|
||||
break;
|
||||
case 3: rxled_on = !rxled_on;
|
||||
break;
|
||||
case 4: txled_on = !txled_on;
|
||||
break;
|
||||
case 5: speaker1_on = !speaker1_on;
|
||||
break;
|
||||
case 6: speaker2_on = !speaker2_on;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,168 @@
|
|||
#ifndef BITMAPS_H
|
||||
#define BITMAPS_H
|
||||
|
||||
/*******************
|
||||
* Background image
|
||||
*******************/
|
||||
|
||||
const unsigned char PROGMEM background_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
128, 64,
|
||||
0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x66, 0x66, 0xe6, 0xe6, 0xfe, 0xbe, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0xa8, 0x48, 0x10, 0xe0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0x07, 0x87, 0x80, 0x80, 0x80, 0x81, 0x87, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7e, 0xff, 0xff, 0xc3, 0x81, 0x81, 0xd3, 0xf7, 0xf7, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0xaa, 0x92, 0x44, 0x38, 0x00, 0x00,
|
||||
0x00, 0x00, 0xe0, 0xe0, 0xe1, 0x61, 0x61, 0x61, 0xe0, 0xe1, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x66, 0x66, 0x66, 0x67, 0x7f, 0x7d, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x2a, 0x24, 0x11, 0x0e, 0x00, 0x00,
|
||||
0x00, 0x00, 0xe0, 0xe0, 0x20, 0xe0, 0xc0, 0x00, 0x40, 0xc0, 0x80, 0xc0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x20, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x20, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xaa, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xaa, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x2a, 0x14, 0x40, 0x20, 0x00, 0x10, 0x00, 0x10, 0x00, 0x20, 0x40, 0x00, 0x00,
|
||||
0x00, 0x80, 0x87, 0x87, 0x81, 0x87, 0x86, 0x00, 0x04, 0x06, 0x03, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xfe, 0x03, 0x01, 0x0c, 0xfe, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xfe, 0x03, 0x01, 0xcc, 0x66, 0x3c, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x38, 0x16, 0x38, 0x80, 0x40, 0x00, 0x20, 0x00, 0x20, 0x00, 0x40, 0x80, 0x05, 0x10, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x20, 0x10, 0x05, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x11, 0x1b, 0x0e, 0x1b, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x03, 0x06, 0x0c, 0x19, 0x31, 0x21, 0x30, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x00, 0x03, 0x06, 0x0c, 0x19, 0x31, 0x21, 0x30, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xaa, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0xaa, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x20, 0x40, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x20, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/**************************
|
||||
* self masked images
|
||||
**************************/
|
||||
|
||||
const unsigned char PROGMEM button_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
8, 8,
|
||||
0x1c, 0x3e, 0x7f, 0x5f, 0x4f, 0x26, 0x1c, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM buttonleft_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
8, 8,
|
||||
0x7f, 0x5f, 0x5f, 0x4f, 0x6f, 0x36, 0x1c, 0x08,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM buttonright_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
8, 8,
|
||||
0x08, 0x1c, 0x3e, 0x7f, 0x5f, 0x5f, 0x43, 0x7f,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM buttonup_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
8, 8,
|
||||
0x1f, 0x3f, 0x7f, 0xdf, 0x67, 0x31, 0x1f, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM buttondown_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
8, 8,
|
||||
0xf8, 0xfc, 0xbe, 0xbf, 0xbe, 0x8c, 0xf8, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM off_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
18, 8,
|
||||
0x38, 0x7c, 0x44, 0x7c, 0x38, 0x00, 0x7c, 0x7c, 0x14, 0x14, 0x04, 0x00, 0x7c, 0x7c, 0x14, 0x14, 0x04, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM txt_on_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
18, 8,
|
||||
0x38, 0x7c, 0x44, 0x7c, 0x38, 0x00, 0x7c, 0x7c, 0x18, 0x30, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM on_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
18, 8,
|
||||
0x38, 0x7c, 0x44, 0x7c, 0x38, 0x00, 0x7c, 0x7c, 0x18, 0x30, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM sound_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
6, 16,
|
||||
0x00, 0x08, 0x0c, 0x46, 0x62, 0x20,
|
||||
0x00, 0x10, 0x30, 0x62, 0x46, 0x04,
|
||||
};
|
||||
|
||||
/**************************
|
||||
* non masked images
|
||||
**************************/
|
||||
|
||||
const unsigned char PROGMEM red_focus_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
14, 16,
|
||||
0xfe, 0xff, 0x03, 0x03, 0x03, 0x33, 0x33, 0x33, 0x33, 0x03, 0x83, 0x87, 0xfe, 0x7c,
|
||||
0x1f, 0x3f, 0x30, 0x30, 0x30, 0x3f, 0x1f, 0x1e, 0x3c, 0x30, 0x30, 0x31, 0x3f, 0x1f,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM green_focus_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
14, 16,
|
||||
0xf8, 0xfc, 0x0e, 0x07, 0x03, 0xe3, 0xf3, 0xf3, 0x63, 0x43, 0x47, 0x4e, 0xfc, 0xf8,
|
||||
0x07, 0x0f, 0x1c, 0x38, 0x30, 0x31, 0x33, 0x33, 0x19, 0x30, 0x30, 0x30, 0x3f, 0x3f,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM blue_focus_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
14, 16,
|
||||
0xfe, 0xff, 0x03, 0x03, 0x03, 0x33, 0x33, 0x33, 0x03, 0x03, 0x47, 0xfe, 0xfc, 0x80,
|
||||
0x1f, 0x3f, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x38, 0x1f, 0x0f,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM rxled_on_focus_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
14, 8,
|
||||
0x00, 0xff, 0x81, 0x81, 0xed, 0x81, 0x93, 0xfe, 0xba, 0x92, 0xc6, 0x92, 0xba, 0xee,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM txled_on_focus_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
14, 8,
|
||||
0x07, 0x05, 0xfd, 0x81, 0x81, 0xfd, 0x05, 0xef, 0xba, 0x92, 0xc6, 0x92, 0xba, 0xee,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM speaker1_on_focus_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
14, 24,
|
||||
0xe0, 0x10, 0x10, 0x10, 0xe0, 0x30, 0x98, 0xcc, 0x66, 0x32, 0xfa, 0xf2, 0x06, 0xfc,
|
||||
0xff, 0x00, 0x00, 0x00, 0xff, 0x80, 0x3f, 0x7f, 0xde, 0xc0, 0xdf, 0xff, 0x00, 0xff,
|
||||
0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x03, 0x06, 0x0c, 0x09, 0x0b, 0x09, 0x0c, 0x07,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM speaker2_on_focus_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
14, 24,
|
||||
0xe0, 0x10, 0x10, 0x10, 0xe0, 0x30, 0x98, 0xcc, 0x66, 0x32, 0x7a, 0xf2, 0x06, 0xfc,
|
||||
0xff, 0x00, 0x00, 0x00, 0xff, 0x80, 0x3f, 0x7f, 0xc6, 0xd3, 0xd8, 0xff, 0x00, 0xff,
|
||||
0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x03, 0x06, 0x0c, 0x09, 0x0b, 0x09, 0x0c, 0x07,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM slider_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
7, 16,
|
||||
0x00, 0xfc, 0xfe, 0xfa, 0x06, 0xfc, 0x00,
|
||||
0x00, 0x0f, 0x1f, 0x17, 0x18, 0x0f, 0x00,
|
||||
};
|
||||
|
||||
const unsigned char PROGMEM nospeaker_gfx[] =
|
||||
{
|
||||
// width, height,
|
||||
12, 24,
|
||||
0xe0, 0xe3, 0x1f, 0xfc, 0xe0, 0x00, 0xe0, 0xfc, 0x1f, 0x83, 0x08, 0xf8,
|
||||
0xff, 0xff, 0x1f, 0xe0, 0xff, 0x1f, 0xff, 0xe0, 0x0c, 0x27, 0x00, 0xff,
|
||||
0x00, 0x18, 0x1f, 0x07, 0x00, 0x00, 0x00, 0x07, 0x1f, 0x18, 0x02, 0x03,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#ifndef GLOBALS_H
|
||||
#define GLOBALS_H
|
||||
|
||||
#define FRAMERATE 10
|
||||
#define BACKGROUND_X 0
|
||||
#define BACKGROUND_Y 0
|
||||
|
||||
#define SLIDER_X 20
|
||||
#define SLIDER_Y -1
|
||||
#define SLIDER_HEIGHT 14
|
||||
#define SLIDER_X_STEP 6
|
||||
#define RGB_MAX_STEPS 17
|
||||
|
||||
|
||||
#define RED_X 0
|
||||
#define RED_Y 0
|
||||
|
||||
#define GREEN_X 0
|
||||
#define GREEN_Y 14
|
||||
|
||||
#define BLUE_X 0
|
||||
#define BLUE_Y 28
|
||||
|
||||
#define RXLED_X 0
|
||||
#define RXLED_Y 44
|
||||
|
||||
#define TXLED_X 0
|
||||
#define TXLED_Y 54
|
||||
|
||||
#define ON_GFX_X 16
|
||||
#define ON_GFX_Y 44
|
||||
|
||||
#define OFF_GFX_X 16
|
||||
#define OFF_GFX_Y 54
|
||||
|
||||
#define SPEAKER1_X 34
|
||||
#define SPEAKER1_Y 44
|
||||
|
||||
#define SOUND1_X 48
|
||||
#define SOUND1_Y 46
|
||||
|
||||
#define SPEAKER2_X 56
|
||||
#define SPEAKER2_Y 44
|
||||
|
||||
#define SOUND2_X 70
|
||||
#define SOUND2_Y 46
|
||||
|
||||
#define NOSPEAKER_X 57
|
||||
#define NOSPEAKER_Y 43
|
||||
|
||||
#define BUTTON_LEFT_X 80
|
||||
#define BUTTON_LEFT_Y 49
|
||||
|
||||
#define BUTTON_RIGHT_X 91
|
||||
#define BUTTON_RIGHT_Y 49
|
||||
|
||||
#define BUTTON_UP_X 86
|
||||
#define BUTTON_UP_Y 43
|
||||
|
||||
#define BUTTON_DOWN_X 86
|
||||
#define BUTTON_DOWN_Y 54
|
||||
|
||||
#define BUTTON_A_X 108
|
||||
#define BUTTON_A_Y 55
|
||||
|
||||
#define BUTTON_B_X 118
|
||||
#define BUTTON_B_Y 46
|
||||
|
||||
#ifdef AB_DEVKIT
|
||||
#define MAX_OPTIONS 6 //No 2nd speaker pin
|
||||
#else
|
||||
#define MAX_OPTIONS 7
|
||||
#endif
|
||||
|
||||
boolean rxled_on;
|
||||
boolean txled_on;
|
||||
boolean speaker1_on;
|
||||
boolean speaker2_on;
|
||||
byte selectedOption;
|
||||
boolean hardwareChange;
|
||||
|
||||
typedef struct rgbled_t
|
||||
{
|
||||
byte red;
|
||||
byte green;
|
||||
byte blue;
|
||||
} rgbled_t;
|
||||
|
||||
rgbled_t rgbLed;
|
||||
|
||||
const unsigned char PROGMEM rgbValues[RGB_MAX_STEPS] = {
|
||||
0,1,4,9,16,25,36,49,64,81,100,111,144,169,196,225,255
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Hello, World! example
|
||||
June 11, 2015
|
||||
Copyright (C) 2015 David Martinez
|
||||
All rights reserved.
|
||||
This code is the most basic barebones code for writing a program for Arduboy.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <Arduboy2.h>
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy2 arduboy;
|
||||
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
|
||||
// here we set the framerate to 15, we do not need to run at
|
||||
// default 60 and it saves us battery life
|
||||
arduboy.setFrameRate(15);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
// we set our cursor 5 pixels to the right and 10 down from the top
|
||||
// (positions start at 0, 0)
|
||||
arduboy.setCursor(4, 9);
|
||||
|
||||
// then we print to screen what is in the Quotation marks ""
|
||||
arduboy.print(F("Hello, world!"));
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
/***************************************************************
|
||||
Play a musical composition in the background while
|
||||
the main sketch code runs in the foreground.
|
||||
|
||||
The ArduboyPlaytune library must be installed to use this sketch
|
||||
https://github.com/Arduboy/ArduboyPlayTune
|
||||
|
||||
The D-Pad buttons will move the text and play a tone.
|
||||
|
||||
The A button mutes the sound.
|
||||
The screen is inverted when sound is muted.
|
||||
|
||||
The B button will turn sound back on if it's muted.
|
||||
|
||||
The score that is played contains two parts.
|
||||
With the DevKit only one part is played.
|
||||
***************************************************************/
|
||||
|
||||
#include <Arduboy2.h>
|
||||
#include <ArduboyPlaytune.h>
|
||||
|
||||
// 2 Part Inventions No. 3 - J.S. Bach
|
||||
const byte score[] PROGMEM = {
|
||||
2,154, 0x90,62, 0,166, 0x90,64, 0,166, 0x90,66, 0,166, 0x90,64, 0,166,
|
||||
0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 0x90,62, 0,166, 0x90,69,
|
||||
0,166, 0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 0x91,50, 0x90,66,
|
||||
0,166, 0x91,52, 0x90,62, 0,166, 0x91,54, 0x90,69, 0,166, 0x91,52, 0,166,
|
||||
0x90,71, 0x91,55, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,52, 0,55, 0x90,71,
|
||||
0,55, 0x90,73, 0,55, 0x91,50, 0x90,74, 0,166, 0x91,57, 0x90,73, 0,83,
|
||||
0x90,74, 0,83, 0x91,55, 0x90,73, 0,166, 0x91,54, 0x90,71, 0,83, 0x90,69,
|
||||
0,83, 0x91,52, 0,125, 0x80, 0,41, 0x90,73, 0x91,54, 0,166, 0x90,74, 0x91,50,
|
||||
0,166, 0x90,76, 0x91,57, 0,166, 0x90,73, 0,166, 0x91,45, 0x90,78, 0,166,
|
||||
0x90,74, 0,166, 0x91,57, 0x90,73, 0,166, 0x90,71, 0,138, 0x81, 0,27, 0x91,57,
|
||||
0x90,76, 0,166, 0x90,73, 0,166, 0x91,45, 0x90,74, 0,166, 0x90,71, 0,166,
|
||||
0x91,57, 0x90,69, 0,166, 0x90,68, 0,138, 0x81, 0,27, 0x91,57, 0x90,76, 0,166,
|
||||
0x90,73, 0,166, 0x91,45, 0x90,78, 0,166, 0x90,74, 0,166, 0x91,57, 0x90,73,
|
||||
0,166, 0x90,71, 0,138, 0x81, 0,27, 0x91,57, 0x90,76, 0,166, 0x90,73, 0,166,
|
||||
0x91,45, 0x90,74, 0,166, 0x90,71, 0,166, 0x91,57, 0x90,69, 0,166, 0x90,68,
|
||||
0,138, 0x81, 0,27, 0x91,57, 0x90,73, 0,166, 0x90,71, 0,166, 0x91,59, 0x90,74,
|
||||
0,166, 0x90,73, 0,166, 0x91,61, 0x90,71, 0,166, 0x90,69, 0,166, 0x91,62,
|
||||
0x90,78, 0,166, 0x91,61, 0,166, 0x90,68, 0x91,64, 0,166, 0x91,62, 0,166,
|
||||
0x90,69, 0x91,61, 0,166, 0x91,59, 0,166, 0x91,61, 0,27, 0x80, 0,27, 0x90,71,
|
||||
0,55, 0x90,69, 0,55, 0x91,62, 0x90,68, 0,55, 0x90,69, 0,55, 0x90,71,
|
||||
0,27, 0x80, 0,27, 0x90,71, 0x91,64, 1,77, 0x91,52, 0,166, 0x90,69, 0,166,
|
||||
0x91,57, 0x90,69, 0,166, 0x91,52, 0,166, 0x91,54, 0,166, 0x91,56, 0,166,
|
||||
0x91,57, 0x80, 0,166, 0x91,59, 0,166, 0x91,61, 0,166, 0x91,59, 0,166, 0x90,76,
|
||||
0x91,62, 0,166, 0x91,61, 0,166, 0x90,81, 0x91,59, 0,166, 0x91,57, 0,166,
|
||||
0x91,64, 0,166, 0x90,71, 0,166, 0x91,52, 0x90,73, 0,166, 0x90,75, 0,166,
|
||||
0x90,76, 0x81, 0,166, 0x90,78, 0,166, 0x90,79, 0,166, 0x90,78, 0,166, 0x91,59,
|
||||
0x90,81, 0,166, 0x90,79, 0,166, 0x91,64, 0x90,78, 0,166, 0x90,76, 0,166,
|
||||
0x90,83, 0,166, 0x91,54, 0,166, 0x90,71, 0x91,56, 0,166, 0x91,58, 0,166,
|
||||
0x91,59, 0x80, 0,166, 0x91,61, 0,166, 0x91,62, 0,166, 0x91,61, 0,166, 0x90,66,
|
||||
0x91,64, 0,166, 0x91,62, 0,166, 0x90,71, 0x91,61, 0,166, 0x91,59, 0,166,
|
||||
0x91,66, 0,166, 0x90,70, 0,166, 0x91,54, 0x90,71, 0,166, 0x90,73, 0,166,
|
||||
0x91,64, 0x90,74, 0,166, 0x90,76, 0,166, 0x91,62, 0x90,78, 0,166, 0x90,76,
|
||||
0,166, 0x91,71, 0x90,79, 0,166, 0x91,70, 0x90,78, 0,166, 0x91,71, 0x90,76,
|
||||
0,166, 0x90,74, 0,166, 0x91,61, 0x90,76, 0,166, 0x90,74, 0,166, 0x91,70,
|
||||
0x90,78, 0,166, 0x91,68, 0x90,76, 0,166, 0x91,70, 0x90,74, 0,166, 0x90,73,
|
||||
0,166, 0x91,71, 0x90,74, 0,166, 0x91,69, 0x90,73, 0,166, 0x91,67, 0x90,76,
|
||||
0,166, 0x91,66, 0x90,74, 0,166, 0x91,64, 0x90,73, 0,166, 0x91,62, 0x90,71,
|
||||
0,166, 0x91,64, 0x90,73, 0,166, 0x91,62, 0,166, 0x90,70, 0x91,66, 0,83,
|
||||
0x90,68, 0,83, 0x91,64, 0x90,70, 0,166, 0x91,62, 0x90,71, 0,166, 0x91,61,
|
||||
0,166, 0x91,62, 0,166, 0x90,73, 0x91,64, 0,138, 0x80, 0,27, 0x90,73, 0x91,66,
|
||||
0,83, 0x90,74, 0,83, 0x90,73, 0,166, 0x91,54, 0,166, 0x90,71, 0,166,
|
||||
0x91,59, 0,166, 0x90,66, 0,166, 0x91,54, 0x90,68, 0,166, 0x90,70, 0,166,
|
||||
0x91,50, 0x90,71, 0,166, 0x90,73, 0,166, 0x91,47, 0x90,74, 0,166, 0x90,73,
|
||||
0,166, 0x90,76, 0,166, 0x90,74, 0,166, 0x90,73, 0x81, 0,166, 0x90,71, 0,166,
|
||||
0x90,79, 0,166, 0x91,47, 0,166, 0x91,49, 0,166, 0x91,51, 0,166, 0x91,52,
|
||||
0,166, 0x91,54, 0,166, 0x91,55, 0,166, 0x91,54, 0,166, 0x91,57, 0,166,
|
||||
0x91,55, 0,166, 0x91,54, 0,166, 0x91,52, 0,166, 0x91,57, 0,138, 0x80, 0,27,
|
||||
0x90,64, 0,166, 0x90,66, 0,166, 0x90,68, 0,166, 0x90,69, 0,166, 0x90,71,
|
||||
0,166, 0x90,73, 0,166, 0x90,71, 0,166, 0x90,74, 0,166, 0x90,73, 0,166,
|
||||
0x90,71, 0,166, 0x90,69, 0,166, 0x90,78, 0,138, 0x81, 0,27, 0x91,45, 0,166,
|
||||
0x91,47, 0,166, 0x91,49, 0,166, 0x91,50, 0,166, 0x91,52, 0,166, 0x91,54,
|
||||
0,166, 0x91,52, 0,166, 0x91,55, 0,166, 0x91,54, 0,166, 0x91,52, 0,166,
|
||||
0x91,50, 0,166, 0x91,56, 0,138, 0x80, 0,27, 0x90,71, 0,166, 0x90,76, 0,166,
|
||||
0x91,52, 0x90,74, 0,166, 0x91,54, 0x90,73, 0,166, 0x91,56, 0x90,71, 0,166,
|
||||
0x91,57, 0x90,73, 0,166, 0x91,56, 0x90,71, 0,166, 0x91,54, 0x90,74, 0,166,
|
||||
0x91,52, 0x90,73, 0,166, 0x91,50, 0x90,71, 0,166, 0x91,54, 0x90,69, 0,166,
|
||||
0x91,52, 0x90,68, 0,83, 0x90,69, 0,83, 0x91,50, 0x90,68, 0,166, 0x91,49,
|
||||
0x90,64, 0,166, 0x91,47, 0,166, 0x90,69, 0x91,49, 0,166, 0x90,71, 0x91,45,
|
||||
0,166, 0x90,73, 0x91,57, 0,166, 0x90,71, 0,166, 0x91,54, 0x90,74, 0,166,
|
||||
0x90,73, 0,166, 0x91,49, 0x90,71, 0,166, 0x90,69, 0,166, 0x91,50, 0x90,78,
|
||||
0,166, 0x91,49, 0,166, 0x91,52, 0,166, 0x90,68, 0x91,50, 0,166, 0x90,69,
|
||||
0x91,49, 0,166, 0x90,68, 0x91,47, 0,166, 0x90,69, 0x91,49, 0,166, 0x90,74,
|
||||
0x91,50, 0,166, 0x90,71, 0x91,52, 1,77, 0x91,40, 0,166, 0x90,69, 0,138,
|
||||
0x80, 0,27, 0x90,69, 0x91,45, 0,166, 0x91,49, 0,166, 0x91,50, 0,166, 0x90,73,
|
||||
0x91,52, 0,166, 0x90,74, 0x91,54, 0,166, 0x90,76, 0x91,55, 0,166, 0x90,66,
|
||||
0x91,57, 0,166, 0x91,55, 0,166, 0x90,67, 0x91,59, 0,166, 0x91,57, 0,166,
|
||||
0x90,71, 0x91,55, 0,83, 0x90,69, 0,83, 0x91,54, 0x90,67, 0,83, 0x90,69,
|
||||
0,83, 0x91,55, 0x90,71, 0,166, 0x91,54, 0,166, 0x90,74, 0x91,57, 0,83,
|
||||
0x90,73, 0,83, 0x91,55, 0x90,71, 0,83, 0x90,73, 0,83, 0x91,54, 0x90,74,
|
||||
0,166, 0x91,52, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,52, 0,166, 0x90,76,
|
||||
0x91,55, 0,166, 0x90,74, 0x91,54, 0,166, 0x90,73, 0x91,52, 0,166, 0x90,74,
|
||||
0x91,50, 0,166, 0x90,76, 0x91,57, 0,166, 0x90,74, 0,166, 0x91,45, 0x90,73,
|
||||
0,166, 0x90,71, 0,166, 0x90,69, 0x81, 0,166, 0x90,67, 0,166, 0x90,66, 0,166,
|
||||
0x90,64, 0,166, 0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166, 0x90,62,
|
||||
0,166, 0x90,69, 0,166, 0x90,67, 0,166, 0x90,66, 0,166, 0x90,64, 0,166,
|
||||
0x91,50, 0x90,66, 0,166, 0x91,52, 0x90,62, 0,166, 0x91,54, 0x90,69, 0,166,
|
||||
0x91,52, 0,166, 0x90,71, 0x91,55, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,52,
|
||||
0,55, 0x90,71, 0,55, 0x90,73, 0,55, 0x91,50, 0x90,74, 0,166, 0x91,57,
|
||||
0x90,73, 0,83, 0x90,74, 0,83, 0x91,55, 0x90,73, 0,166, 0x91,54, 0x90,71,
|
||||
0,83, 0x90,69, 0,83, 0x91,52, 0,125, 0x80, 0,41, 0x90,74, 0x91,54, 0,166,
|
||||
0x91,50, 0,138, 0x80, 0,27, 0x90,74, 0x91,57, 0,166, 0x91,54, 0,166, 0x90,62,
|
||||
0x91,59, 0,166, 0x91,55, 0,166, 0x90,74, 0x91,54, 0,166, 0x91,52, 0,138,
|
||||
0x80, 0,27, 0x90,74, 0x91,57, 0,166, 0x91,54, 0,166, 0x90,62, 0x91,55, 0,166,
|
||||
0x91,52, 0,166, 0x90,74, 0x91,50, 0,166, 0x91,49, 0,138, 0x80, 0,27, 0x90,74,
|
||||
0x91,57, 0,166, 0x91,54, 0,166, 0x90,62, 0x91,59, 0,166, 0x91,55, 0,166,
|
||||
0x90,74, 0x91,54, 0,166, 0x91,52, 0,138, 0x80, 0,27, 0x90,74, 0x91,57, 0,166,
|
||||
0x91,54, 0,166, 0x90,62, 0x91,55, 0,166, 0x91,52, 0,166, 0x90,74, 0x91,50,
|
||||
0,166, 0x90,76, 0x91,49, 0,166, 0x90,78, 0x91,50, 0,166, 0x90,76, 0,166,
|
||||
0x91,52, 0x90,79, 0,166, 0x90,78, 0,166, 0x91,54, 0x90,76, 0,166, 0x90,74,
|
||||
0,166, 0x91,55, 0x90,83, 0,166, 0x91,54, 0,166, 0x90,73, 0x91,57, 0,166,
|
||||
0x91,55, 0,166, 0x90,74, 0x91,54, 0,166, 0x91,52, 0,166, 0x91,54, 0,27,
|
||||
0x80, 0,27, 0x90,76, 0,55, 0x90,74, 0,55, 0x91,55, 0x90,73, 0,55, 0x90,74,
|
||||
0,55, 0x90,76, 0,41, 0x80, 0,13, 0x90,76, 0x91,57, 1,77, 0x91,45, 0,166,
|
||||
0x90,74, 0,138, 0x80, 0,27, 0x90,74, 0x91,47, 0,166, 0x91,45, 0,166, 0x90,62,
|
||||
0x91,48, 0,166, 0x91,47, 0,166, 0x90,67, 0x91,45, 0,166, 0x91,43, 0,166,
|
||||
0x91,50, 0,166, 0x90,57, 0,166, 0x90,59, 0,166, 0x90,61, 0,166, 0x90,62,
|
||||
0,166, 0x90,64, 0,166, 0x90,66, 0,138, 0x81, 0,27, 0x91,49, 0x90,64, 0,166,
|
||||
0x91,47, 0x90,67, 0,166, 0x91,45, 0x90,66, 0,166, 0x91,43, 0x90,64, 0,166,
|
||||
0x91,42, 0x90,62, 0,166, 0x91,43, 0x90,71, 0,166, 0x91,42, 0,166, 0x91,45,
|
||||
0,166, 0x90,61, 0x91,43, 0,166, 0x90,62, 0x91,42, 0,166, 0x90,61, 0x91,40,
|
||||
0,166, 0x90,62, 0x91,42, 0,166, 0x90,67, 0x91,43, 0,166, 0x90,64, 0x91,45,
|
||||
1,244, 0x90,62, 0,138, 0x80, 0,27, 0x90,62, 0x91,38, 7,208, 0x80, 0x81,
|
||||
0xf0
|
||||
};
|
||||
|
||||
Arduboy2 arduboy;
|
||||
ArduboyPlaytune tunes(arduboy.audio.enabled);
|
||||
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
|
||||
arduboy.setFrameRate(25);
|
||||
arduboy.setTextSize(3);
|
||||
|
||||
// audio setup
|
||||
tunes.initChannel(PIN_SPEAKER_1);
|
||||
#ifndef AB_DEVKIT
|
||||
// if not a DevKit
|
||||
tunes.initChannel(PIN_SPEAKER_2);
|
||||
#else
|
||||
// if it's a DevKit
|
||||
tunes.initChannel(PIN_SPEAKER_1); // use the same pin for both channels
|
||||
tunes.toneMutesScore(true); // mute the score when a tone is sounding
|
||||
#endif
|
||||
|
||||
arduboy.invert(!arduboy.audio.enabled()); // invert display if sound muted
|
||||
}
|
||||
|
||||
|
||||
int x = 20, y = 10; // initial text position
|
||||
|
||||
void loop()
|
||||
{
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
if (arduboy.pressed(UP_BUTTON)) {
|
||||
y-=1;
|
||||
tunes.tone(1175,300);
|
||||
} else if (arduboy.pressed(DOWN_BUTTON)) {
|
||||
y+=1;
|
||||
tunes.tone(1397,300);
|
||||
} else if (arduboy.pressed(LEFT_BUTTON)) {
|
||||
x-=1;
|
||||
tunes.tone(1047,300);
|
||||
} else if (arduboy.pressed(RIGHT_BUTTON)) {
|
||||
x+=1;
|
||||
tunes.tone(1319,300);
|
||||
}
|
||||
|
||||
if (arduboy.pressed(A_BUTTON)) {
|
||||
arduboy.invert(true);
|
||||
arduboy.audio.off();
|
||||
} else if (arduboy.pressed(B_BUTTON)) {
|
||||
arduboy.invert(false);
|
||||
arduboy.audio.on();
|
||||
}
|
||||
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(x,y);
|
||||
arduboy.print("Music");
|
||||
arduboy.setCursor(x+8,y+24);
|
||||
arduboy.print("Demo");
|
||||
arduboy.display();
|
||||
|
||||
// play the tune if we aren't already
|
||||
if (!tunes.playing())
|
||||
tunes.playScore(score);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
# PlayTune
|
||||
|
||||
Play a musical composition using the Arduboy.
|
||||
|
||||
Demonstrates playing music in the background while the "real" sketch code runs in the foreground.
|
||||
|
||||
The ArduboyPlaytune library must be installed to use this sketch
|
||||
|
||||
https://github.com/Arduboy/ArduboyPlayTune
|
||||
|
||||
A small composition is stored by `byte PROGMEM score`. The score is started in the sketch loop using `playScore(score)`.
|
||||
|
||||
D-Pad buttons will move the text and play a tone.
|
||||
|
||||
The A button mutes the sound. The screen is inverted when sound is muted.
|
||||
|
||||
The B button will turn sound back on if it's muted.
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
This sketch demonstrates controlling the Arduboy's RGB LED,
|
||||
in both analog and digital modes.
|
||||
*/
|
||||
|
||||
/*
|
||||
To the extent possible under law, Scott Allen has waived all copyright and
|
||||
related or neighboring rights to this BeepDemo program.
|
||||
*/
|
||||
|
||||
#include <Arduboy2.h>
|
||||
|
||||
// The frame rate determines the button auto-repeat rate
|
||||
#define FRAME_RATE 25
|
||||
|
||||
// The increment/decrement amount when auto-repeating
|
||||
#define REPEAT_AMOUNT 3
|
||||
|
||||
// Delay time before button auto-repeat starts, in milliseconds
|
||||
#define REPEAT_DELAY 700
|
||||
|
||||
// Calculation of the number of frames to wait before button auto-repeat starts
|
||||
#define DELAY_FRAMES (REPEAT_DELAY / (1000 / FRAME_RATE))
|
||||
|
||||
#define ANALOG false
|
||||
#define DIGITAL true
|
||||
|
||||
#define ANALOG_MAX 255
|
||||
|
||||
// Color array index
|
||||
enum class Color {
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
COUNT
|
||||
};
|
||||
|
||||
// Map LED color index to LED name
|
||||
const byte LEDpin[(byte)(Color::COUNT)] = {
|
||||
RED_LED,
|
||||
GREEN_LED,
|
||||
BLUE_LED
|
||||
};
|
||||
|
||||
Arduboy2 arduboy;
|
||||
|
||||
// Analog LED values
|
||||
byte analogValue[3] = { 0, 0, 0};
|
||||
// Digital LED states
|
||||
byte digitalState[3] = { RGB_OFF, RGB_OFF, RGB_OFF };
|
||||
|
||||
byte analogSelected = (byte)(Color::RED);
|
||||
byte digitalSelected = (byte)(Color::RED);
|
||||
|
||||
boolean controlMode = ANALOG;
|
||||
|
||||
// Button repeat handling
|
||||
unsigned int delayCount = 0;
|
||||
boolean repeating = false;
|
||||
|
||||
// ============================= SETUP ===================================
|
||||
void setup() {
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(FRAME_RATE);
|
||||
analogSet();
|
||||
}
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// =========================== MAIN LOOP =================================
|
||||
void loop() {
|
||||
if (!arduboy.nextFrame()) {
|
||||
return;
|
||||
}
|
||||
|
||||
arduboy.pollButtons();
|
||||
|
||||
// Toggle analog/digital control mode
|
||||
if (arduboy.justPressed(A_BUTTON)) {
|
||||
if ((controlMode = !controlMode) == DIGITAL) {
|
||||
arduboy.freeRGBled();
|
||||
digitalSet();
|
||||
}
|
||||
else {
|
||||
analogSet();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset to Analog mode and all LEDs off
|
||||
if (arduboy.justPressed(B_BUTTON)) {
|
||||
reset();
|
||||
}
|
||||
|
||||
// Handle D-pad buttons for current mode
|
||||
if (controlMode == ANALOG) {
|
||||
modeAnalog();
|
||||
}
|
||||
else {
|
||||
modeDigital();
|
||||
}
|
||||
|
||||
// Handle delay before button auto-repeat starts
|
||||
if ((delayCount != 0) && (--delayCount == 0)) {
|
||||
repeating = true;
|
||||
}
|
||||
|
||||
renderScreen(); // Render and display the entire screen
|
||||
}
|
||||
// =======================================================================
|
||||
|
||||
|
||||
// Analog control
|
||||
void modeAnalog() {
|
||||
if (arduboy.justPressed(RIGHT_BUTTON)) {
|
||||
valueInc(1);
|
||||
startButtonDelay();
|
||||
}
|
||||
else if (arduboy.justPressed(LEFT_BUTTON)) {
|
||||
valueDec(1);
|
||||
startButtonDelay();
|
||||
}
|
||||
else if (repeating && arduboy.pressed(RIGHT_BUTTON)) {
|
||||
valueInc(REPEAT_AMOUNT);
|
||||
}
|
||||
else if (repeating && arduboy.pressed(LEFT_BUTTON)) {
|
||||
valueDec(REPEAT_AMOUNT);
|
||||
}
|
||||
else if (arduboy.justPressed(DOWN_BUTTON)) {
|
||||
analogSelectInc();
|
||||
}
|
||||
else if (arduboy.justPressed(UP_BUTTON)) {
|
||||
analogSelectDec();
|
||||
}
|
||||
else if (repeating) {
|
||||
stopButtonRepeat();
|
||||
}
|
||||
}
|
||||
|
||||
// Digital control
|
||||
void modeDigital() {
|
||||
if (arduboy.justPressed(RIGHT_BUTTON) || arduboy.justPressed(LEFT_BUTTON)) {
|
||||
digitalState[digitalSelected] = (digitalState[digitalSelected] == RGB_ON) ?
|
||||
RGB_OFF : RGB_ON;
|
||||
arduboy.digitalWriteRGB(LEDpin[digitalSelected],
|
||||
digitalState[digitalSelected]);
|
||||
}
|
||||
else if (arduboy.justPressed(DOWN_BUTTON)) {
|
||||
digitalSelectInc();
|
||||
}
|
||||
else if (arduboy.justPressed(UP_BUTTON)) {
|
||||
digitalSelectDec();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset to analog mode and turn all LEDs off
|
||||
void reset() {
|
||||
digitalState[(byte)(Color::RED)] = RGB_OFF;
|
||||
digitalState[(byte)(Color::GREEN)] = RGB_OFF;
|
||||
digitalState[(byte)(Color::BLUE)] = RGB_OFF;
|
||||
digitalSet();
|
||||
|
||||
analogValue[(byte)(Color::RED)] = 0;
|
||||
analogValue[(byte)(Color::GREEN)] = 0;
|
||||
analogValue[(byte)(Color::BLUE)] = 0;
|
||||
analogSet();
|
||||
|
||||
digitalSelected = (byte)(Color::RED);
|
||||
analogSelected = (byte)(Color::RED);
|
||||
|
||||
controlMode = ANALOG;
|
||||
}
|
||||
|
||||
// Increment the selected analog LED value by the specified amount
|
||||
// and update the LED
|
||||
void valueInc(byte amount) {
|
||||
if ((ANALOG_MAX - analogValue[analogSelected]) <= amount) {
|
||||
analogValue[analogSelected] = ANALOG_MAX;
|
||||
}
|
||||
else {
|
||||
analogValue[analogSelected] += amount;
|
||||
}
|
||||
|
||||
arduboy.setRGBled(LEDpin[analogSelected], analogValue[analogSelected]);
|
||||
}
|
||||
|
||||
// Decrement the selected analog LED value by the specified amount
|
||||
// and update the LED
|
||||
void valueDec(byte amount) {
|
||||
if (analogValue[analogSelected] <= amount) {
|
||||
analogValue[analogSelected] = 0;
|
||||
}
|
||||
else {
|
||||
analogValue[analogSelected] -= amount;
|
||||
}
|
||||
|
||||
arduboy.setRGBled(LEDpin[analogSelected], analogValue[analogSelected]);
|
||||
}
|
||||
|
||||
// Select the next analog color index with wrap
|
||||
void analogSelectInc() {
|
||||
selectInc(analogSelected);
|
||||
}
|
||||
|
||||
// Select the previous analog color index with wrap
|
||||
void analogSelectDec() {
|
||||
selectDec(analogSelected);
|
||||
}
|
||||
|
||||
// Select the next digital color index with wrap
|
||||
void digitalSelectInc() {
|
||||
selectInc(digitalSelected);
|
||||
}
|
||||
|
||||
// Select the previous digital color index with wrap
|
||||
void digitalSelectDec() {
|
||||
selectDec(digitalSelected);
|
||||
}
|
||||
|
||||
// Select the next color index with wrap
|
||||
void selectInc(byte &index) {
|
||||
if (++index == (byte)(Color::COUNT)) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Select the previous color index with wrap
|
||||
void selectDec(byte &index) {
|
||||
if (index == 0) {
|
||||
index = ((byte)(Color::COUNT) - 1);
|
||||
}
|
||||
else {
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
// Update all LEDs in analog mode
|
||||
void analogSet() {
|
||||
arduboy.setRGBled(analogValue[(byte)(Color::RED)],
|
||||
analogValue[(byte)(Color::GREEN)],
|
||||
analogValue[(byte)(Color::BLUE)]);
|
||||
}
|
||||
|
||||
// Update all LEDs in digital mode
|
||||
void digitalSet() {
|
||||
arduboy.digitalWriteRGB(digitalState[(byte)(Color::RED)],
|
||||
digitalState[(byte)(Color::GREEN)],
|
||||
digitalState[(byte)(Color::BLUE)]);
|
||||
}
|
||||
|
||||
// Start the button auto-repeat delay
|
||||
void startButtonDelay() {
|
||||
delayCount = DELAY_FRAMES;
|
||||
repeating = false;
|
||||
}
|
||||
|
||||
// Stop the button auto-repeat or delay
|
||||
void stopButtonRepeat() {
|
||||
delayCount = 0;
|
||||
repeating = false;
|
||||
}
|
||||
|
||||
// Render and display the screen
|
||||
void renderScreen() {
|
||||
arduboy.setCursor(12, 0);
|
||||
arduboy.print(F("RGB LED"));
|
||||
arduboy.setCursor(15, 56);
|
||||
arduboy.print(F("A:Mode B:Reset"));
|
||||
arduboy.setCursor(74, 0);
|
||||
|
||||
if (controlMode == ANALOG) {
|
||||
arduboy.print(F(" Analog"));
|
||||
drawAnalog(9, Color::RED, "Red:");
|
||||
drawAnalog(25, Color::GREEN, "Green:");
|
||||
drawAnalog(41, Color::BLUE, "Blue:");
|
||||
}
|
||||
else { // Digital
|
||||
arduboy.print(F("Digital"));
|
||||
drawDigital(9, Color::RED, "Red:");
|
||||
drawDigital(25, Color::GREEN, "Green:");
|
||||
drawDigital(41, Color::BLUE, "Blue:");
|
||||
}
|
||||
|
||||
arduboy.display(CLEAR_BUFFER);
|
||||
}
|
||||
|
||||
// Draw the information for one analog color
|
||||
void drawAnalog(int y, Color color, const char* name) {
|
||||
byte value = analogValue[(byte)color];
|
||||
|
||||
arduboy.setCursor(0, y);
|
||||
arduboy.print(name);
|
||||
arduboy.setCursor(42, y);
|
||||
printValue(value);
|
||||
if (analogSelected == (byte)color) {
|
||||
arduboy.print(F(" <--"));
|
||||
}
|
||||
drawBar(y + 8, color, value);
|
||||
}
|
||||
|
||||
// Draw the value bar for an analog color
|
||||
void drawBar(int y, Color color, byte value) {
|
||||
byte barLength = value / 2;
|
||||
|
||||
if (barLength == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (analogSelected == (byte)color) {
|
||||
arduboy.fillRect(0, y, barLength, 5);
|
||||
}
|
||||
else {
|
||||
arduboy.drawRect(0, y, barLength, 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the informaton for one digital color
|
||||
void drawDigital(int y, Color color, const char* name) {
|
||||
byte state = digitalState[(byte)color];
|
||||
|
||||
arduboy.setCursor(34, y + 3);
|
||||
arduboy.print(name);
|
||||
arduboy.setCursor(76, y + 3);
|
||||
if (state == RGB_ON) {
|
||||
arduboy.print(F("ON "));
|
||||
arduboy.fillCircle(22, y + 6, 4);
|
||||
}
|
||||
else {
|
||||
arduboy.print(F("OFF"));
|
||||
arduboy.drawCircle(22, y + 6, 4);
|
||||
}
|
||||
|
||||
if (digitalSelected == (byte)color) {
|
||||
arduboy.print(F(" <--"));
|
||||
arduboy.drawRect(16, y, 13, 13);
|
||||
}
|
||||
}
|
||||
|
||||
// Print a byte in decimal and hex
|
||||
void printValue(byte val) {
|
||||
if (val < 100) {
|
||||
arduboy.print(' ');
|
||||
}
|
||||
if (val < 10) {
|
||||
arduboy.print(' ');
|
||||
}
|
||||
arduboy.print(val);
|
||||
|
||||
arduboy.print(F(" 0x"));
|
||||
if (val < 0x10) {
|
||||
arduboy.print('0');
|
||||
}
|
||||
arduboy.print(val, HEX);
|
||||
}
|
||||
|
|
@ -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 = "Arduboy2 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 ./LICENSE.txt
|
||||
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
|
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 434 B |
|
@ -0,0 +1,26 @@
|
|||
# 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.
|
||||
|
||||
### /extras/assets/arduboy_logo.png<br>/extras/assets/arduboy_screen.png
|
||||
|
||||
Templates used to create the ARDUBOY logo used in the *bootLogo()* function.
|
||||
|
||||
----------
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Arduboy2
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Arduboy2 KEYWORD1
|
||||
Arduboy2Base KEYWORD1
|
||||
BeepPin1 KEYWORD1
|
||||
BeepPin2 KEYWORD1
|
||||
Point KEYWORD1
|
||||
Rect KEYWORD1
|
||||
Sprites KEYWORD1
|
||||
SpritesB KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
allPixelsOn KEYWORD2
|
||||
begin KEYWORD2
|
||||
blank KEYWORD2
|
||||
boot KEYWORD2
|
||||
bootLogo KEYWORD2
|
||||
bootLogoCompressed KEYWORD2
|
||||
bootLogoShell KEYWORD2
|
||||
bootLogoSpritesBOverwrite KEYWORD2
|
||||
bootLogoSpritesBSelfMasked KEYWORD2
|
||||
bootLogoSpritesOverwrite KEYWORD2
|
||||
bootLogoSpritesSelfMasked KEYWORD2
|
||||
bootLogoText KEYWORD2
|
||||
buttonsState KEYWORD2
|
||||
clear KEYWORD2
|
||||
collide KEYWORD2
|
||||
cpuLoad KEYWORD2
|
||||
delayShort KEYWORD2
|
||||
digitalWriteRGB KEYWORD2
|
||||
display KEYWORD2
|
||||
displayOff KEYWORD2
|
||||
displayOn KEYWORD2
|
||||
drawBitmap KEYWORD2
|
||||
drawChar KEYWORD2
|
||||
drawCircle KEYWORD2
|
||||
drawCompressed KEYWORD2
|
||||
drawFastHLine KEYWORD2
|
||||
drawFastVLine KEYWORD2
|
||||
drawLine KEYWORD2
|
||||
drawPixel KEYWORD2
|
||||
drawRect KEYWORD2
|
||||
drawRoundRect KEYWORD2
|
||||
drawSlowXYBitmap KEYWORD2
|
||||
drawTriangle KEYWORD2
|
||||
enabled KEYWORD2
|
||||
everyXFrames KEYWORD2
|
||||
exitToBootloader KEYWORD2
|
||||
fillCircle KEYWORD2
|
||||
fillRect KEYWORD2
|
||||
fillRoundRect KEYWORD2
|
||||
fillScreen KEYWORD2
|
||||
fillTriangle KEYWORD2
|
||||
flashlight KEYWORD2
|
||||
flipVertical KEYWORD2
|
||||
flipHorizontal KEYWORD2
|
||||
freeRGBled KEYWORD2
|
||||
generateRandomSeed KEYWORD2
|
||||
getBuffer KEYWORD2
|
||||
getCursorX KEYWORD2
|
||||
getCursorY KEYWORD2
|
||||
getPixel KEYWORD2
|
||||
getTextBackground KEYWORD2
|
||||
getTextColor KEYWORD2
|
||||
getTextSize KEYWORD2
|
||||
getTextWrap KEYWORD2
|
||||
height KEYWORD2
|
||||
idle KEYWORD2
|
||||
initRandomSeed KEYWORD2
|
||||
invert KEYWORD2
|
||||
justPressed KEYWORD2
|
||||
justReleased KEYWORD2
|
||||
nextFrame KEYWORD2
|
||||
nextFrameDEV KEYWORD2
|
||||
notPressed KEYWORD2
|
||||
off KEYWORD2
|
||||
on KEYWORD2
|
||||
paint8Pixels KEYWORD2
|
||||
paintScreen KEYWORD2
|
||||
pollButtons KEYWORD2
|
||||
pressed KEYWORD2
|
||||
readShowBootLogoFlag KEYWORD2
|
||||
readShowBootLogoLEDsFlag KEYWORD2
|
||||
readShowUnitNameFlag KEYWORD2
|
||||
readUnitID KEYWORD2
|
||||
readUnitName KEYWORD2
|
||||
safeMode KEYWORD2
|
||||
saveOnOff KEYWORD2
|
||||
setCursor KEYWORD2
|
||||
setFrameDuration KEYWORD2
|
||||
setFrameRate KEYWORD2
|
||||
setRGBled KEYWORD2
|
||||
setTextBackground KEYWORD2
|
||||
setTextColor KEYWORD2
|
||||
setTextSize KEYWORD2
|
||||
setTextWrap KEYWORD2
|
||||
SPItransfer KEYWORD2
|
||||
systemButtons KEYWORD2
|
||||
toggle KEYWORD2
|
||||
waitNoButtons KEYWORD2
|
||||
width KEYWORD2
|
||||
writeShowBootLogoFlag KEYWORD2
|
||||
writeShowBootLogoLEDsFlag KEYWORD2
|
||||
writeShowUnitNameFlag KEYWORD2
|
||||
writeUnitID KEYWORD2
|
||||
writeUnitName KEYWORD2
|
||||
|
||||
# Arduboy2Beep classes
|
||||
freq KEYWORD2
|
||||
noTone KEYWORD2
|
||||
timer KEYWORD2
|
||||
tone KEYWORD2
|
||||
|
||||
# Sprites class
|
||||
drawErase KEYWORD2
|
||||
drawExternalMask KEYWORD2
|
||||
drawOverwrite KEYWORD2
|
||||
drawPlusMask KEYWORD2
|
||||
drawSelfMasked KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
ARDUBOY_LIB_VER LITERAL1
|
||||
|
||||
ARDUBOY_UNIT_NAME_LEN LITERAL1
|
||||
|
||||
EEPROM_STORAGE_SPACE_START LITERAL1
|
||||
|
||||
HEIGHT LITERAL1
|
||||
WIDTH LITERAL1
|
||||
|
||||
BLACK LITERAL1
|
||||
WHITE LITERAL1
|
||||
INVERT LITERAL1
|
||||
|
||||
CLEAR_BUFFER LITERAL1
|
||||
|
||||
A_BUTTON LITERAL1
|
||||
B_BUTTON LITERAL1
|
||||
DOWN_BUTTON LITERAL1
|
||||
LEFT_BUTTON LITERAL1
|
||||
RIGHT_BUTTON LITERAL1
|
||||
UP_BUTTON LITERAL1
|
||||
|
||||
PIN_SPEAKER_1 LITERAL1
|
||||
PIN_SPEAKER_2 LITERAL1
|
||||
|
||||
BLUE_LED LITERAL1
|
||||
GREEN_LED LITERAL1
|
||||
RED_LED LITERAL1
|
||||
|
||||
RGB_OFF LITERAL1
|
||||
RGB_ON LITERAL1
|
||||
|
||||
ARDUBOY_NO_USB LITERAL1
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "Arduboy2",
|
||||
"keywords": "arduboy, game",
|
||||
"description": "An alternative library for content creation on the Arduboy miniature gaming platform",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/MLXXXp/Arduboy2.git"
|
||||
},
|
||||
"version": "5.1.0",
|
||||
"export":
|
||||
{
|
||||
"exclude": "extras"
|
||||
},
|
||||
"frameworks": "arduino",
|
||||
"platforms": "atmelavr"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
name=Arduboy2
|
||||
version=5.1.0
|
||||
author=Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen, Ross O. Shoger
|
||||
maintainer=Scott Allen <saydisp-git@yahoo.ca>
|
||||
sentence=An alternative library for use with the Arduboy game system.
|
||||
paragraph=This is a fork of the Arduboy library, with a main goal of providing ways in which more code space can be freed for use by large sketches. It remains substantially compatible with Arduboy library V1.1, with the main API difference being that the "tones" subclass has been removed and its functionality made available in a separate ArduboyPlaytune library. Removal of "tones" also allows other audio functions and libraries to be used, such as ArduboyTones.
|
||||
category=Other
|
||||
url=https://github.com/MLXXXp/Arduboy2
|
||||
architectures=avr
|
||||
includes=Arduboy2.h
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* @file Arduboy2Audio.cpp
|
||||
* \brief
|
||||
* The Arduboy2Audio class for speaker and sound control.
|
||||
*/
|
||||
|
||||
#include "Arduboy2.h"
|
||||
#include "Arduboy2Audio.h"
|
||||
|
||||
bool Arduboy2Audio::audio_enabled = false;
|
||||
|
||||
void Arduboy2Audio::on()
|
||||
{
|
||||
// fire up audio pins by seting them as outputs
|
||||
#ifdef ARDUBOY_10
|
||||
bitSet(SPEAKER_1_DDR, SPEAKER_1_BIT);
|
||||
bitSet(SPEAKER_2_DDR, SPEAKER_2_BIT);
|
||||
#else
|
||||
bitSet(SPEAKER_1_DDR, SPEAKER_1_BIT);
|
||||
#endif
|
||||
audio_enabled = true;
|
||||
}
|
||||
|
||||
void Arduboy2Audio::off()
|
||||
{
|
||||
audio_enabled = false;
|
||||
// shut off audio pins by setting them as inputs
|
||||
#ifdef ARDUBOY_10
|
||||
bitClear(SPEAKER_1_DDR, SPEAKER_1_BIT);
|
||||
bitClear(SPEAKER_2_DDR, SPEAKER_2_BIT);
|
||||
#else
|
||||
bitClear(SPEAKER_1_DDR, SPEAKER_1_BIT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Audio::toggle()
|
||||
{
|
||||
if (audio_enabled)
|
||||
off();
|
||||
else
|
||||
on();
|
||||
}
|
||||
|
||||
void Arduboy2Audio::saveOnOff()
|
||||
{
|
||||
EEPROM.update(EEPROM_AUDIO_ON_OFF, audio_enabled);
|
||||
}
|
||||
|
||||
void Arduboy2Audio::begin()
|
||||
{
|
||||
if (EEPROM.read(EEPROM_AUDIO_ON_OFF))
|
||||
on();
|
||||
else
|
||||
off();
|
||||
}
|
||||
|
||||
bool Arduboy2Audio::enabled()
|
||||
{
|
||||
return audio_enabled;
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* @file Arduboy2Audio.h
|
||||
* \brief
|
||||
* The Arduboy2Audio class for speaker and sound control.
|
||||
*/
|
||||
|
||||
#ifndef ARDUBOY2_AUDIO_H
|
||||
#define ARDUBOY2_AUDIO_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
/** \brief
|
||||
* Provide speaker and sound control.
|
||||
*
|
||||
* \details
|
||||
* This class provides functions to initialize the speaker and control the
|
||||
* enabling and disabling (muting) of sound. It doesn't provide any functions
|
||||
* to actually produce sound.
|
||||
*
|
||||
* The state of sound muting is stored in system EEPROM and so is retained
|
||||
* over power cycles.
|
||||
*
|
||||
* An Arduboy2Audio class object named `audio` will be created by the
|
||||
* Arduboy2Base class, so there is no need for a sketch itself to create an
|
||||
* Arduboy2Audio object. Arduboy2Audio functions can be called using the
|
||||
* Arduboy2 or Arduboy2Base `audio` object.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* #include <Arduboy2.h>
|
||||
*
|
||||
* Arduboy2 arduboy;
|
||||
*
|
||||
* // Arduboy2Audio functions can be called as follows:
|
||||
* arduboy.audio.on();
|
||||
* arduboy.audio.off();
|
||||
* \endcode
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* In order for this class to be fully functional, the external library or
|
||||
* functions used by a sketch to actually to produce sounds should be compliant
|
||||
* with this class. This means they should only produce sound if it is enabled,
|
||||
* or mute the sound if it's disabled. The `enabled()` function can be used
|
||||
* to determine if sound is enabled or muted. Generally a compliant library
|
||||
* would accept the `enabled()` function as an initialization parameter and
|
||||
* then call it as necessary to determine the current state.
|
||||
*
|
||||
* For example, the ArduboyTones and ArduboyPlaytune libraries require an
|
||||
* `enabled()` type function to be passed as a parameter in the constructor,
|
||||
* like so:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* #include <Arduboy2.h>
|
||||
* #include <ArduboyTones.h>
|
||||
*
|
||||
* Arduboy2 arduboy;
|
||||
* ArduboyTones sound(arduboy.audio.enabled);
|
||||
* \endcode
|
||||
* \endparblock
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* A friend class named _Arduboy2Ex_ is declared by this class. The intention
|
||||
* is to allow a sketch to create an _Arduboy2Ex_ class which would have access
|
||||
* to the private and protected members of the Arduboy2Audio class. It is hoped
|
||||
* that this may eliminate the need to create an entire local copy of the
|
||||
* library, in order to extend the functionality, in most circumstances.
|
||||
* \endparblock
|
||||
*/
|
||||
class Arduboy2Audio
|
||||
{
|
||||
friend class Arduboy2Ex;
|
||||
|
||||
public:
|
||||
/** \brief
|
||||
* Initialize the speaker based on the current mute setting.
|
||||
*
|
||||
* \details
|
||||
* The speaker is initialized based on the current mute setting saved in
|
||||
* system EEPROM. This function is called by `Arduboy2Base::begin()` so it
|
||||
* isn't normally required to call it within a sketch. However, if
|
||||
* `Arduboy2Core::boot()` is used instead of `Arduboy2Base::begin()` and the
|
||||
* sketch includes sound, then this function should be called after `boot()`.
|
||||
*/
|
||||
void static begin();
|
||||
|
||||
/** \brief
|
||||
* Turn sound on.
|
||||
*
|
||||
* \details
|
||||
* The system is configured to generate sound. This function sets the sound
|
||||
* mode only until the unit is powered off. To save the current mode use
|
||||
* `saveOnOff()`.
|
||||
*
|
||||
* \see off() toggle() saveOnOff()
|
||||
*/
|
||||
void static on();
|
||||
|
||||
/** \brief
|
||||
* Turn sound off (mute).
|
||||
*
|
||||
* \details
|
||||
* The system is configured to not produce sound (mute). This function sets
|
||||
* the sound mode only until the unit is powered off. To save the current
|
||||
* mode use `saveOnOff()`.
|
||||
*
|
||||
* \see on() toggle() saveOnOff()
|
||||
*/
|
||||
void static off();
|
||||
|
||||
/** \brief
|
||||
* Toggle the sound on/off state.
|
||||
*
|
||||
* \details
|
||||
* If the system is configured for sound on, it will be changed to sound off
|
||||
* (mute). If sound is off, it will be changed to on. This function sets
|
||||
* the sound mode only until the unit is powered off. To save the current
|
||||
* mode use `saveOnOff()`.
|
||||
*
|
||||
* \see on() off() saveOnOff()
|
||||
*/
|
||||
void static toggle();
|
||||
|
||||
/** \brief
|
||||
* Save the current sound state in EEPROM.
|
||||
*
|
||||
* \details
|
||||
* The current sound state, set by `on()` or `off()`, is saved to the
|
||||
* reserved system area in EEPROM. This allows the state to carry over between
|
||||
* power cycles and after uploading a different sketch.
|
||||
*
|
||||
* \note
|
||||
* EEPROM is limited in the number of times it can be written to. Sketches
|
||||
* should not continuously change and then save the state rapidly.
|
||||
*
|
||||
* \see on() off() toggle()
|
||||
*/
|
||||
void static saveOnOff();
|
||||
|
||||
/** \brief
|
||||
* Get the current sound state.
|
||||
*
|
||||
* \return `true` if sound is currently enabled (not muted).
|
||||
*
|
||||
* \details
|
||||
* This function should be used by code that actually generates sound.
|
||||
* If `true` is returned, sound can be produced. If `false` is returned,
|
||||
* sound should be muted.
|
||||
*
|
||||
* \see on() off() toggle()
|
||||
*/
|
||||
bool static enabled();
|
||||
|
||||
protected:
|
||||
bool static audio_enabled;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
* @file Arduboy2Beep.cpp
|
||||
* \brief
|
||||
* Classes to generate simple square wave tones on the Arduboy speaker pins.
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Arduboy2Beep.h"
|
||||
|
||||
#ifndef AB_DEVKIT
|
||||
|
||||
// Speaker pin 1, Timer 3A, Port C bit 6, Arduino pin 5
|
||||
|
||||
uint8_t BeepPin1::duration = 0;
|
||||
|
||||
void BeepPin1::begin()
|
||||
{
|
||||
TCCR3A = 0;
|
||||
TCCR3B = (bit(WGM32) | bit(CS31)); // CTC mode. Divide by 8 clock prescale
|
||||
}
|
||||
|
||||
void BeepPin1::tone(uint16_t count)
|
||||
{
|
||||
tone(count, 0);
|
||||
}
|
||||
|
||||
void BeepPin1::tone(uint16_t count, uint8_t dur)
|
||||
{
|
||||
duration = dur;
|
||||
TCCR3A = bit(COM3A0); // set toggle on compare mode (which connects the pin)
|
||||
OCR3A = count; // load the count (16 bits), which determines the frequency
|
||||
}
|
||||
|
||||
void BeepPin1::timer()
|
||||
{
|
||||
if (duration && (--duration == 0)) {
|
||||
TCCR3A = 0; // set normal mode (which disconnects the pin)
|
||||
}
|
||||
}
|
||||
|
||||
void BeepPin1::noTone()
|
||||
{
|
||||
duration = 0;
|
||||
TCCR3A = 0; // set normal mode (which disconnects the pin)
|
||||
}
|
||||
|
||||
|
||||
// Speaker pin 2, Timer 4A, Port C bit 7, Arduino pin 13
|
||||
|
||||
uint8_t BeepPin2::duration = 0;
|
||||
|
||||
void BeepPin2::begin()
|
||||
{
|
||||
TCCR4A = 0; // normal mode. Disable PWM
|
||||
TCCR4B = bit(CS43); // divide by 128 clock prescale
|
||||
TCCR4D = 0; // normal mode
|
||||
TC4H = 0; // toggle pin at count = 0
|
||||
OCR4A = 0; // "
|
||||
}
|
||||
|
||||
void BeepPin2::tone(uint16_t count)
|
||||
{
|
||||
tone(count, 0);
|
||||
}
|
||||
|
||||
void BeepPin2::tone(uint16_t count, uint8_t dur)
|
||||
{
|
||||
duration = dur;
|
||||
TCCR4A = bit(COM4A0); // set toggle on compare mode (which connects the pin)
|
||||
TC4H = highByte(count); // load the count (10 bits),
|
||||
OCR4C = lowByte(count); // which determines the frequency
|
||||
}
|
||||
|
||||
void BeepPin2::timer()
|
||||
{
|
||||
if (duration && (--duration == 0)) {
|
||||
TCCR4A = 0; // set normal mode (which disconnects the pin)
|
||||
}
|
||||
}
|
||||
|
||||
void BeepPin2::noTone()
|
||||
{
|
||||
duration = 0;
|
||||
TCCR4A = 0; // set normal mode (which disconnects the pin)
|
||||
}
|
||||
|
||||
|
||||
#else /* AB_DEVKIT */
|
||||
|
||||
// *** The pins used for the speaker on the DevKit cannot be directly
|
||||
// controlled by a timer/counter. The following "dummy" functions will
|
||||
// compile and operate properly but no sound will be produced
|
||||
|
||||
uint8_t BeepPin1::duration = 0;
|
||||
|
||||
void BeepPin1::begin()
|
||||
{
|
||||
}
|
||||
|
||||
void BeepPin1::tone(uint16_t count)
|
||||
{
|
||||
tone(count, 0);
|
||||
}
|
||||
|
||||
void BeepPin1::tone(uint16_t count, uint8_t dur)
|
||||
{
|
||||
(void) count; // parameter not used
|
||||
|
||||
duration = dur;
|
||||
}
|
||||
|
||||
void BeepPin1::timer()
|
||||
{
|
||||
if (duration) {
|
||||
--duration;
|
||||
}
|
||||
}
|
||||
|
||||
void BeepPin1::noTone()
|
||||
{
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
|
||||
uint8_t BeepPin2::duration = 0;
|
||||
|
||||
void BeepPin2::begin()
|
||||
{
|
||||
}
|
||||
|
||||
void BeepPin2::tone(uint16_t count)
|
||||
{
|
||||
tone(count, 0);
|
||||
}
|
||||
|
||||
void BeepPin2::tone(uint16_t count, uint8_t dur)
|
||||
{
|
||||
(void) count; // parameter not used
|
||||
|
||||
duration = dur;
|
||||
}
|
||||
|
||||
void BeepPin2::timer()
|
||||
{
|
||||
if (duration) {
|
||||
--duration;
|
||||
}
|
||||
}
|
||||
|
||||
void BeepPin2::noTone()
|
||||
{
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,362 @@
|
|||
/**
|
||||
* @file Arduboy2Beep.h
|
||||
* \brief
|
||||
* Classes to generate simple square wave tones on the Arduboy speaker pins.
|
||||
*/
|
||||
|
||||
#ifndef ARDUBOY2_BEEP_H
|
||||
#define ARDUBOY2_BEEP_H
|
||||
|
||||
/** \brief
|
||||
* Play simple square wave tones using speaker pin 1.
|
||||
*
|
||||
* \note
|
||||
* Class `BeepPin2` provides identical functions for playing tones on speaker
|
||||
* pin 2. Both classes can be used in the same sketch to allow playing
|
||||
* two tones at the same time. To do this, the `begin()` and `timer()`
|
||||
* functions of both classes must be used.
|
||||
*
|
||||
* \details
|
||||
* This class can be used to play square wave tones on speaker pin 1.
|
||||
* The functions are designed to produce very small and efficient code.
|
||||
*
|
||||
* A tone can be set to play for a given duration, or continuously until
|
||||
* stopped or replaced by a new tone. No interrupts are used. A tone is
|
||||
* generated by a hardware timer/counter directly toggling the pin,
|
||||
* so once started, no CPU cycles are used to actually play the tone.
|
||||
* The program continues to run while a tone is playing. However, a small
|
||||
* amount of code is required to time and stop a tone after a given duration.
|
||||
*
|
||||
* Tone frequencies can range from 15.26Hz to 1000000Hz.
|
||||
*
|
||||
* Although there's no specific code to handle mute control, the
|
||||
* `Arduboy2Audio` class will work since it has code to mute sound by setting
|
||||
* the speaker pins to input mode and unmute by setting the pins as outputs.
|
||||
* The `BeepPin1` class doesn't interfere with this operation.
|
||||
*
|
||||
* In order to avoid needing to use interrupts, the duration of tones is timed
|
||||
* by calling the `timer()` function continuously at a fixed interval.
|
||||
* The duration of a tone is given by specifying the number of times `timer()`
|
||||
* will be called before stopping the tone.
|
||||
*
|
||||
* For sketches that use `Arduboy2::nextFrame()`, or some other method to
|
||||
* generate frames at a fixed rate, `timer()` can be called once per frame.
|
||||
* Tone durations will then be given as the number of frames to play the tone
|
||||
* for. For example, with a rate of 60 frames per second a duration of 30
|
||||
* would be used to play a tone for half a second.
|
||||
*
|
||||
* The variable named `#duration` is the counter that times the duration of a
|
||||
* tone. A sketch can determine if a tone is currently playing by testing if
|
||||
* the `#duration` variable is non-zero (assuming it's a timed tone, not a
|
||||
* continuous tone).
|
||||
*
|
||||
* To keep the code small and efficient, the frequency of a tone is specified
|
||||
* by the actual count value to be loaded into to timer/counter peripheral.
|
||||
* The frequency will be determined by the count provided and the clock rate
|
||||
* of the timer/counter. In order to allow a tone's frequency to be specified
|
||||
* in hertz (cycles per second) the `freq()` helper function is provided,
|
||||
* which converts a given frequency to the required count value.
|
||||
*
|
||||
* NOTE that it is intended that `freq()` only be called with constant values.
|
||||
* If `freq()` is called with a variable, code to perform floating point math
|
||||
* will be included in the sketch, which will likely greatly increase the
|
||||
* sketch's code size unless the sketch also uses floating point math for
|
||||
* other purposes.
|
||||
*
|
||||
* The formulas for frequency/count conversion are:
|
||||
*
|
||||
* count=(1000000/frequency)-1
|
||||
* frequency=1000000/(count+1)
|
||||
*
|
||||
* Counts must be between 0 and 65535.
|
||||
*
|
||||
* All members of the class are static, so it's not necessary to create an
|
||||
* instance of the class in order to use it. However, creating an instance
|
||||
* doesn't produce any more code and it may make the source code smaller and
|
||||
* make it easier to switch to the `BeepPin2` class if it becomes necessary.
|
||||
*
|
||||
* The following is a basic example sketch, which will generate a tone when
|
||||
* a button is pressed.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* #include <Arduboy2.h>
|
||||
* // There's no need to #include <Arduboy2Beep.h>
|
||||
* // It will be included in Arduboy2.h
|
||||
*
|
||||
* Arduboy2 arduboy;
|
||||
* BeepPin1 beep; // class instance for speaker pin 1
|
||||
*
|
||||
* void setup() {
|
||||
* arduboy.begin();
|
||||
* arduboy.setFrameRate(50);
|
||||
* beep.begin(); // set up the hardware for playing tones
|
||||
* }
|
||||
*
|
||||
* void loop() {
|
||||
* if (!arduboy.nextFrame()) {
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* beep.timer(); // handle tone duration
|
||||
*
|
||||
* arduboy.pollButtons();
|
||||
*
|
||||
* if (arduboy.justPressed(A_BUTTON)) {
|
||||
* // play a 1000Hz tone for 100 frames (2 seconds at 50 FPS)
|
||||
* // beep.freq(1000) is used to convert 1000Hz to the required count
|
||||
* beep.tone(beep.freq(1000), 100);
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \note
|
||||
* These functions, and the equivalents in class `BeepPin2`, will not work with
|
||||
* a DevKit Arduboy because the speaker pins used cannot be directly controlled
|
||||
* by a timer/counter. "Dummy" functions are provided so a sketch will compile
|
||||
* and work properly but no sound will be produced.
|
||||
*
|
||||
* \see BeepPin2
|
||||
*/
|
||||
class BeepPin1
|
||||
{
|
||||
public:
|
||||
|
||||
/** \brief
|
||||
* The counter used by the `timer()` function to time the duration of a tone.
|
||||
*
|
||||
* \details
|
||||
* This variable is set by the `dur` parameter of the `tone()` function.
|
||||
* It is then decremented each time the `timer()` function is called, if its
|
||||
* value isn't 0. When `timer()` decrements it to 0, a tone that is playing
|
||||
* will be stopped.
|
||||
*
|
||||
* A sketch can determine if a tone is currently playing by testing if
|
||||
* this variable is non-zero (assuming it's a timed tone, not a continuous
|
||||
* tone).
|
||||
*
|
||||
* Example:
|
||||
* \code{.cpp}
|
||||
* beep.tone(beep.freq(1000), 15);
|
||||
* while (beep.duration != 0) { } // wait for the tone to stop playing
|
||||
* \endcode
|
||||
*
|
||||
* It can also be manipulated directly by the sketch, although this should
|
||||
* seldom be necessary.
|
||||
*/
|
||||
static uint8_t duration;
|
||||
|
||||
/** \brief
|
||||
* Set up the hardware.
|
||||
*
|
||||
* \details
|
||||
* Prepare the hardware for playing tones.
|
||||
* This function must be called (usually in `setup()`) before using any of
|
||||
* the other functions in this class.
|
||||
*/
|
||||
static void begin();
|
||||
|
||||
/** \brief
|
||||
* Play a tone continually, until replaced by a new tone or stopped.
|
||||
*
|
||||
* \param count The count to be loaded into the timer/counter to play
|
||||
* the desired frequency.
|
||||
*
|
||||
* \details
|
||||
* A tone is played indefinitely, until replaced by another tone or stopped
|
||||
* using `noTone()`.
|
||||
*
|
||||
* The tone's frequency is determined by the specified count, which is loaded
|
||||
* into the timer/counter that generates the tone. A desired frequency can be
|
||||
* converted into the required count value using the `freq()` function.
|
||||
*
|
||||
* \see freq() timer() noTone()
|
||||
*/
|
||||
static void tone(uint16_t count);
|
||||
|
||||
/** \brief
|
||||
* Play a tone for a given duration.
|
||||
*
|
||||
* \param count The count to be loaded into the timer/counter to play
|
||||
* the desired frequency.
|
||||
* \param dur The duration of the tone, used by `timer()`.
|
||||
*
|
||||
* \details
|
||||
* A tone is played for the specified duration, or until replaced by another
|
||||
* tone or stopped using `noTone()`.
|
||||
*
|
||||
* The tone's frequency is determined by the specified count, which is loaded
|
||||
* into the timer/counter that generates the tone. A desired frequency can be
|
||||
* converted into the required count value using the `freq()` function.
|
||||
*
|
||||
* The duration value is the number of times the `timer()` function must be
|
||||
* called before the tone is stopped.
|
||||
*
|
||||
* \see freq() timer() noTone()
|
||||
*/
|
||||
static void tone(uint16_t count, uint8_t dur);
|
||||
|
||||
/** \brief
|
||||
* Handle the duration that a tone plays for.
|
||||
*
|
||||
* \details
|
||||
* This function must be called at a constant interval, which would normally
|
||||
* be once per frame, in order to stop a tone after the desired tone duration
|
||||
* has elapsed.
|
||||
*
|
||||
* If the value of the `duration` variable is not 0, it will be decremented.
|
||||
* When the `duration` variable is decremented to 0, a playing tone will be
|
||||
* stopped.
|
||||
*/
|
||||
static void timer();
|
||||
|
||||
/** \brief
|
||||
* Stop a tone that is playing.
|
||||
*
|
||||
* \details
|
||||
* If a tone is playing it will be stopped. It's safe to call this function
|
||||
* even if a tone isn't currently playing.
|
||||
*
|
||||
* \see tone()
|
||||
*/
|
||||
static void noTone();
|
||||
|
||||
/** \brief
|
||||
* Convert a frequency to the required count.
|
||||
*
|
||||
* \param hz The frequency, in hertz (cycles per second), to be converted
|
||||
* to a count.
|
||||
*
|
||||
* \return The required count to be loaded into the timer/counter for the
|
||||
* given frequency.
|
||||
*
|
||||
* \details
|
||||
* This helper function will convert a desired tone frequency to the closest
|
||||
* value required by the `tone()` function's `count` parameter.
|
||||
* The calculated count is rounded up or down to the nearest integer,
|
||||
* if necessary.
|
||||
*
|
||||
* Example:
|
||||
* \code{.cpp}
|
||||
* beep.tone(beep.freq(440)); // play a 440Hz tone until stopped or replaced
|
||||
* \endcode
|
||||
*
|
||||
* \note
|
||||
* It is intended that `freq()` only be called with constant values.
|
||||
* If `freq()` is called with a variable, code to perform floating point math
|
||||
* will be included in the sketch, which will likely greatly increase the
|
||||
* sketch's code size unless the sketch also uses floating point math for
|
||||
* other purposes.
|
||||
*/
|
||||
static constexpr uint16_t freq(const float hz)
|
||||
{
|
||||
return (uint16_t) (((F_CPU / 8 / 2) + (hz / 2)) / hz) - 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** \brief
|
||||
* Play simple square wave tones using speaker pin 2.
|
||||
*
|
||||
* \details
|
||||
* This class contains the same functions as class `BeepPin1` except they use
|
||||
* speaker pin 2 instead of speaker pin 1.
|
||||
*
|
||||
* Using `BeepPin1` is more desirable, as it uses a 16 bit Timer, which can
|
||||
* produce a greater frequency range and resolution than the 10 bit Timer
|
||||
* used by `BeepPin2`. However, if the sketch also includes other sound
|
||||
* generating code that uses speaker pin 1, `BeepPin2` can be used to avoid
|
||||
* conflict.
|
||||
*
|
||||
* Tone frequencies on speaker pin 2 can range from 61.04Hz to 15625Hz using
|
||||
* allowed counts from 3 to 1023.
|
||||
*
|
||||
* The formulas for frequency/count conversion are:
|
||||
*
|
||||
* count=(62500/frequency)-1
|
||||
* frequency=62500/(count+1)
|
||||
*
|
||||
* See the documentation for `BeepPin1` for more details.
|
||||
*
|
||||
* \see BeepPin1
|
||||
*/
|
||||
class BeepPin2
|
||||
{
|
||||
public:
|
||||
|
||||
/** \brief
|
||||
* The counter used by the `timer()` function to time the duration of a tone
|
||||
* played on speaker pin 2.
|
||||
*
|
||||
* \details
|
||||
* For details see `BeepPin1::duration`.
|
||||
*/
|
||||
static uint8_t duration;
|
||||
|
||||
/** \brief
|
||||
* Set up the hardware for playing tones using speaker pin 2.
|
||||
*
|
||||
* \details
|
||||
* For details see `BeepPin1::begin()`.
|
||||
*/
|
||||
static void begin();
|
||||
|
||||
/** \brief
|
||||
* Play a tone on speaker pin 2 continually, until replaced by a new tone
|
||||
* or stopped.
|
||||
*
|
||||
* \param count The count to be loaded into the timer/counter to play
|
||||
* the desired frequency.
|
||||
*
|
||||
* \details
|
||||
* For details see `BeepPin1::tone(uint16_t)`.
|
||||
*/
|
||||
static void tone(uint16_t count);
|
||||
|
||||
/** \brief
|
||||
* Play a tone on speaker pin 2 for a given duration.
|
||||
*
|
||||
* \param count The count to be loaded into the timer/counter to play
|
||||
* the desired frequency.
|
||||
* \param dur The duration of the tone, used by `timer()`.
|
||||
*
|
||||
* \details
|
||||
* For details see `BeepPin1::tone(uint16_t, uint8_t)`.
|
||||
*/
|
||||
static void tone(uint16_t count, uint8_t dur);
|
||||
|
||||
/** \brief
|
||||
* Handle the duration that a tone on speaker pin 2 plays for.
|
||||
*
|
||||
* \details
|
||||
* For details see `BeepPin1::timer()`.
|
||||
*/
|
||||
static void timer();
|
||||
|
||||
/** \brief
|
||||
* Stop a tone that is playing on speaker pin 2.
|
||||
*
|
||||
* \details
|
||||
* For details see `BeepPin1::noTone()`.
|
||||
*/
|
||||
static void noTone();
|
||||
|
||||
/** \brief
|
||||
* Convert a frequency to the required count for speaker pin 2.
|
||||
*
|
||||
* \param hz The frequency, in hertz (cycles per second), to be converted
|
||||
* to a count.
|
||||
*
|
||||
* \return The required count to be loaded into the timer/counter for the
|
||||
* given frequency.
|
||||
*
|
||||
* \details
|
||||
* For details see `BeepPin1::freq()`.
|
||||
*/
|
||||
static constexpr uint16_t freq(const float hz)
|
||||
{
|
||||
return (uint16_t) (((F_CPU / 128 / 2) + (hz / 2)) / hz) - 1;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,962 @@
|
|||
/**
|
||||
* @file Arduboy2Core.cpp
|
||||
* \brief
|
||||
* The Arduboy2Core class for Arduboy hardware initilization and control.
|
||||
*/
|
||||
|
||||
#include "Arduboy2Core.h"
|
||||
|
||||
const uint8_t PROGMEM lcdBootProgram[] = {
|
||||
// boot defaults are commented out but left here in case they
|
||||
// might prove useful for reference
|
||||
//
|
||||
// Further reading: https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
|
||||
#ifdef OLED_SH1106
|
||||
0x8D, 0x14, // Charge Pump Setting v = enable (0x14)
|
||||
0xA1, // Set Segment Re-map
|
||||
0xC8, // Set COM Output Scan Direction
|
||||
0x81, 0xCF, // Set Contrast v = 0xCF
|
||||
0xD9, 0xF1, // Set Precharge = 0xF1
|
||||
OLED_SET_COLUMN_ADDRESS_LO, //Set column address for left most pixel
|
||||
0xAF // Display On
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128) || defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128)
|
||||
#if defined(OLED_96X96) || defined(OLED_128X64_ON_96X96)
|
||||
0x15, 0x10, 0x3f, //left most 32 pixels are invisible
|
||||
#elif defined(OLED_96X96_ON_128X128)
|
||||
0x15, 0x08, 0x37, //center 96 pixels horizontally
|
||||
#elif defined(OLED_64X128_ON_128X128)
|
||||
0x15, 0x10, 0x2f, //center 64 pixels horizontally
|
||||
#else
|
||||
0x15, 0x00, 0x3f, //Set column start and end address
|
||||
#endif
|
||||
#if defined (OLED_96X96)
|
||||
0x75, 0x20, 0x7f, //Set row start and end address
|
||||
#elif defined (OLED_128X64_ON_96X96)
|
||||
0x75, 0x30, 0x6f, //Set row start and end address
|
||||
#elif defined (OLED_128X96)
|
||||
0x75, 0x00, 0x5f, //Set row start and end address
|
||||
#elif defined(OLED_128X64_ON_128X96)
|
||||
0x75, 0x10, 0x4f, //Set row start and end address
|
||||
#elif defined(OLED_96X96_ON_128X128) || defined(OLED_128X96_ON_128X128)
|
||||
0x75, 0x10, 0x6f, //Set row start and end address to centered 96 lines
|
||||
#elif defined(OLED_128X64_ON_128X128)
|
||||
0x75, 0x20, 0x5f, //Set row start and end address to centered 64 lines
|
||||
#else
|
||||
0x75, 0x00, 0x7F, //Set row start and end address to use all 128 lines
|
||||
#endif
|
||||
#if defined(OLED_64X128_ON_128X128)
|
||||
0xA0, 0x51, //set re-map: split odd-even COM signals|COM remap|column address remap
|
||||
#else
|
||||
0xA0, 0x55, //set re-map: split odd-even COM signals|COM remap|vertical address increment|column address remap
|
||||
#endif
|
||||
0xA1, 0x00, //set display start line
|
||||
0xA2, 0x00, //set display offset
|
||||
//0xA4, //Normal display
|
||||
0xA8, 0x7F, //Set MUX ratio 128MUX
|
||||
//0xB2, 0x23,
|
||||
//0xB3, 0xF0, //set devider clock | oscillator frequency
|
||||
0x81, 0xCF, //Set contrast
|
||||
//0xBC, 0x1F, //set precharge voltage
|
||||
//0x82, 0xFE, //set second Precharge speed
|
||||
0xB1, 0x21, //reset and 1st precharge phase length phase 2:2 DCLKs, Phase 1: 1 DCLKs
|
||||
//0xBB, 0x0F, //set 2nd precharge period: 15 DCLKs
|
||||
//0xbe, 0x1F, //output level high voltage com signal
|
||||
//0xB8, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, //set gray scale table
|
||||
0xAF //Display on
|
||||
#else
|
||||
// for SSD1306 and SSD1309 displays
|
||||
//
|
||||
// Display Off
|
||||
// 0xAE,
|
||||
|
||||
// Set Display Clock Divisor v = 0xF0
|
||||
// default is 0x80
|
||||
0xD5, 0xF0,
|
||||
|
||||
// Set Multiplex Ratio v = 0x3F
|
||||
// 0xA8, 0x3F,
|
||||
|
||||
// Set Display Offset v = 0
|
||||
// 0xD3, 0x00,
|
||||
|
||||
// Set Start Line (0)
|
||||
// 0x40,
|
||||
#if defined OLED_SSD1309
|
||||
//Charge Pump command not supported, use two NOPs instead to keep same size and easy patchability
|
||||
0xE3, 0xE3,
|
||||
#else
|
||||
// Charge Pump Setting v = enable (0x14)
|
||||
// default is disabled
|
||||
0x8D, 0x14,
|
||||
#endif
|
||||
|
||||
// Set Segment Re-map (A0) | (b0001)
|
||||
// default is (b0000)
|
||||
0xA1,
|
||||
|
||||
// Set COM Output Scan Direction
|
||||
0xC8,
|
||||
|
||||
// Set COM Pins v
|
||||
// 0xDA, 0x12,
|
||||
|
||||
// Set Contrast v = 0xCF
|
||||
0x81, 0xCF,
|
||||
|
||||
// Set Precharge = 0xF1
|
||||
0xD9, 0xF1,
|
||||
|
||||
// Set VCom Detect
|
||||
// 0xDB, 0x40,
|
||||
|
||||
// Entire Display ON
|
||||
// 0xA4,
|
||||
|
||||
// Set normal/inverse display
|
||||
// 0xA6,
|
||||
|
||||
// Display On
|
||||
0xAF,
|
||||
|
||||
// set display mode = horizontal addressing mode (0x00)
|
||||
0x20, 0x00,
|
||||
|
||||
// set col address range
|
||||
// 0x21, 0x00, COLUMN_ADDRESS_END,
|
||||
|
||||
// set page address range
|
||||
// 0x22, 0x00, PAGE_ADDRESS_END
|
||||
#endif
|
||||
};
|
||||
|
||||
Arduboy2Core::Arduboy2Core() { }
|
||||
|
||||
void Arduboy2Core::boot()
|
||||
{
|
||||
#ifdef ARDUBOY_SET_CPU_8MHZ
|
||||
// ARDUBOY_SET_CPU_8MHZ will be set by the IDE using boards.txt
|
||||
setCPUSpeed8MHz();
|
||||
#endif
|
||||
|
||||
// Select the ADC input here so a delay isn't required in initRandomSeed()
|
||||
ADMUX = RAND_SEED_IN_ADMUX;
|
||||
|
||||
bootPins();
|
||||
bootSPI();
|
||||
bootOLED();
|
||||
bootPowerSaving();
|
||||
}
|
||||
|
||||
#ifdef ARDUBOY_SET_CPU_8MHZ
|
||||
// If we're compiling for 8MHz we need to slow the CPU down because the
|
||||
// hardware clock on the Arduboy is 16MHz.
|
||||
// We also need to readjust the PLL prescaler because the Arduino USB code
|
||||
// likely will have incorrectly set it for an 8MHz hardware clock.
|
||||
void Arduboy2Core::setCPUSpeed8MHz()
|
||||
{
|
||||
uint8_t oldSREG = SREG;
|
||||
cli(); // suspend interrupts
|
||||
PLLCSR = _BV(PINDIV); // dissable the PLL and set prescale for 16MHz)
|
||||
CLKPR = _BV(CLKPCE); // allow reprogramming clock
|
||||
CLKPR = 1; // set clock divisor to 2 (0b0001)
|
||||
PLLCSR = _BV(PLLE) | _BV(PINDIV); // enable the PLL (with 16MHz prescale)
|
||||
SREG = oldSREG; // restore interrupts
|
||||
}
|
||||
#endif
|
||||
|
||||
// Pins are set to the proper modes and levels for the specific hardware.
|
||||
// This routine must be modified if any pins are moved to a different port
|
||||
void Arduboy2Core::bootPins()
|
||||
{
|
||||
#ifdef ARDUBOY_10
|
||||
// Port B INPUT_PULLUP or HIGH
|
||||
PORTB = (_BV(RED_LED_BIT) | _BV(BLUE_LED_BIT) | //RGB LED off
|
||||
#ifndef AB_ALTERNATE_WIRING
|
||||
_BV(GREEN_LED_BIT) |
|
||||
#endif
|
||||
#ifndef ARDUINO_AVR_MICRO
|
||||
_BV(RX_LED_BIT) | //RX LED off for Arduboy and non Micro based Arduino
|
||||
#endif
|
||||
_BV(B_BUTTON_BIT)) &
|
||||
// Port B INPUT or LOW
|
||||
~(_BV(SPI_MISO_BIT) | _BV(SPI_MOSI_BIT) | _BV(SPI_SCK_BIT));
|
||||
|
||||
// Port B outputs
|
||||
DDRB = (_BV(RED_LED_BIT) | _BV(BLUE_LED_BIT) |
|
||||
#ifndef AB_ALTERNATE_WIRING
|
||||
_BV(GREEN_LED_BIT) |
|
||||
#endif
|
||||
_BV(SPI_MOSI_BIT) | _BV(SPI_SCK_BIT) | _BV(RX_LED_BIT)) &
|
||||
// Port B inputs
|
||||
~(_BV(B_BUTTON_BIT) | _BV(SPI_MISO_BIT));
|
||||
|
||||
// Port C
|
||||
// Speaker: Not set here. Controlled by audio class
|
||||
|
||||
// Port D INPUT_PULLUP or HIGH
|
||||
PORTD = (
|
||||
#ifdef AB_ALTERNATE_WIRING
|
||||
_BV(GREEN_LED_BIT) |
|
||||
#endif
|
||||
#ifndef ARDUINO_AVR_MICRO
|
||||
_BV(TX_LED_BIT) | //TX LED off for Arduboy and non Micro based Arduino
|
||||
#endif
|
||||
_BV(CART_BIT) | _BV(DC_BIT)) & //flash cart inactive, LCD data mode
|
||||
// Port D INPUT or LOW
|
||||
~(_BV(CS_BIT) | _BV(RST_BIT) //oled chip enabled, reset active
|
||||
#ifdef AB_ALTERNATE_WIRING
|
||||
| _BV(SPEAKER_2_BIT)
|
||||
#endif
|
||||
);
|
||||
|
||||
// Port D outputs
|
||||
DDRD = _BV(RST_BIT) | _BV(CS_BIT) | _BV(DC_BIT) |
|
||||
#ifdef AB_ALTERNATE_WIRING
|
||||
_BV(GREEN_LED_BIT) |
|
||||
#endif
|
||||
_BV(CART_BIT) | _BV(TX_LED_BIT);
|
||||
// Port D inputs (none)
|
||||
|
||||
// Port E INPUT_PULLUP or HIGH
|
||||
PORTE |= _BV(A_BUTTON_BIT);
|
||||
// Port E INPUT or LOW (none)
|
||||
// Port E inputs
|
||||
DDRE &= ~(_BV(A_BUTTON_BIT));
|
||||
// Port E outputs (none)
|
||||
|
||||
// Port F INPUT_PULLUP or HIGH
|
||||
PORTF = (_BV(LEFT_BUTTON_BIT) | _BV(RIGHT_BUTTON_BIT) |
|
||||
_BV(UP_BUTTON_BIT) | _BV(DOWN_BUTTON_BIT)) &
|
||||
// Port F INPUT or LOW
|
||||
~(_BV(RAND_SEED_IN_BIT));
|
||||
|
||||
// Port F outputs (none)
|
||||
DDRF = 0 &
|
||||
// Port F inputs
|
||||
~(_BV(LEFT_BUTTON_BIT) | _BV(RIGHT_BUTTON_BIT) |
|
||||
_BV(UP_BUTTON_BIT) | _BV(DOWN_BUTTON_BIT) |
|
||||
_BV(RAND_SEED_IN_BIT));
|
||||
|
||||
#elif defined(AB_DEVKIT)
|
||||
|
||||
// Port B INPUT_PULLUP or HIGH
|
||||
PORTB |= _BV(LEFT_BUTTON_BIT) | _BV(UP_BUTTON_BIT) | _BV(DOWN_BUTTON_BIT) |
|
||||
_BV(BLUE_LED_BIT);
|
||||
// Port B INPUT or LOW (none)
|
||||
// Port B inputs
|
||||
DDRB &= ~(_BV(LEFT_BUTTON_BIT) | _BV(UP_BUTTON_BIT) | _BV(DOWN_BUTTON_BIT) |
|
||||
_BV(SPI_MISO_BIT));
|
||||
// Port B outputs
|
||||
DDRB |= _BV(SPI_MOSI_BIT) | _BV(SPI_SCK_BIT) | _BV(BLUE_LED_BIT);
|
||||
|
||||
// Port C INPUT_PULLUP or HIGH
|
||||
PORTC |= _BV(RIGHT_BUTTON_BIT);
|
||||
// Port C INPUT or LOW (none)
|
||||
// Port C inputs
|
||||
DDRC &= ~(_BV(RIGHT_BUTTON_BIT));
|
||||
// Port C outputs (none)
|
||||
|
||||
// Port D INPUT_PULLUP or HIGH
|
||||
PORTD |= _BV(CS_BIT);
|
||||
// Port D INPUT or LOW
|
||||
PORTD &= ~(_BV(RST_BIT));
|
||||
// Port D inputs (none)
|
||||
// Port D outputs
|
||||
DDRD |= _BV(RST_BIT) | _BV(CS_BIT) | _BV(DC_BIT);
|
||||
|
||||
// Port E (none)
|
||||
|
||||
// Port F INPUT_PULLUP or HIGH
|
||||
PORTF |= _BV(A_BUTTON_BIT) | _BV(B_BUTTON_BIT);
|
||||
// Port F INPUT or LOW
|
||||
PORTF &= ~(_BV(RAND_SEED_IN_BIT));
|
||||
// Port F inputs
|
||||
DDRF &= ~(_BV(A_BUTTON_BIT) | _BV(B_BUTTON_BIT) | _BV(RAND_SEED_IN_BIT));
|
||||
// Port F outputs (none)
|
||||
// Speaker: Not set here. Controlled by audio class
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Core::bootOLED()
|
||||
{
|
||||
// reset the display
|
||||
uint8_t cmd;
|
||||
const void* ptr = lcdBootProgram;
|
||||
asm volatile(
|
||||
"1: \n\t" //assembly loop for 2nd delayShort(5)
|
||||
);
|
||||
delayShort(5); //for a short active low reset pulse
|
||||
asm volatile(
|
||||
" sbic %[rst_port], %[rst_bit] \n\t" //continue if reset is active
|
||||
" rjmp 2f \n\t" //else break
|
||||
" sbi %[rst_port], %[rst_bit] \n\t" //deactivate reset
|
||||
" rjmp 1b \n\t" //loop for a recover from reset delay
|
||||
"2: \n\t"
|
||||
:
|
||||
: [rst_port] "I" (_SFR_IO_ADDR(RST_PORT)),
|
||||
[rst_bit] "I" (RST_BIT)
|
||||
:
|
||||
);
|
||||
#if defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128)
|
||||
for (uint16_t i = 0; i < 8192; i++) SPItransfer(0); //make sure all display ram is cleared
|
||||
#endif
|
||||
//bitClear(CS_PORT, CS_BIT); // select the display as default SPI device, already cleared by boot pins)
|
||||
LCDCommandMode();
|
||||
asm volatile(
|
||||
" ldi r25, %[size] \n\t" // for (uint8_t i = 0; i < sizeof(lcdBootProgram); i++)
|
||||
"3: \n\t" // {
|
||||
" lpm %[cmd], Z+ \n\t" // cmd = pgm_read_byte(lcdBootProgram + i));
|
||||
: [ptr] "+z" (ptr),
|
||||
[cmd] "=r" (cmd)
|
||||
: [size] "I" (sizeof(lcdBootProgram))
|
||||
: "r25"
|
||||
);
|
||||
SPItransfer(cmd); // transfer display command
|
||||
asm volatile(
|
||||
" dec r25 \n\t" // }
|
||||
" brne 3b \n\t"
|
||||
:
|
||||
:
|
||||
: "r25"
|
||||
);
|
||||
LCDDataMode();
|
||||
}
|
||||
|
||||
void Arduboy2Core::LCDDataMode()
|
||||
{
|
||||
bitSet(DC_PORT, DC_BIT);
|
||||
}
|
||||
|
||||
void Arduboy2Core::LCDCommandMode()
|
||||
{
|
||||
bitClear(DC_PORT, DC_BIT);
|
||||
}
|
||||
|
||||
// Initialize the SPI interface for the display
|
||||
void Arduboy2Core::bootSPI()
|
||||
{
|
||||
// master, mode 0, MSB first, CPU clock / 2 (8MHz)
|
||||
SPCR = _BV(SPE) | _BV(MSTR);
|
||||
SPSR = _BV(SPI2X);
|
||||
}
|
||||
|
||||
// Write to the SPI bus (MOSI pin)
|
||||
uint8_t Arduboy2Core::SPItransfer(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;
|
||||
}
|
||||
|
||||
void Arduboy2Core::safeMode()
|
||||
{
|
||||
if (buttonsState() == UP_BUTTON)
|
||||
{
|
||||
digitalWriteRGB(RED_LED, RGB_ON);
|
||||
|
||||
#ifndef ARDUBOY_CORE // for Arduboy core timer 0 should remain enabled
|
||||
// prevent the bootloader magic number from being overwritten by timer 0
|
||||
// when a timer variable overlaps the magic number location
|
||||
power_timer0_disable();
|
||||
#endif
|
||||
|
||||
while (true) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Power Management */
|
||||
|
||||
void Arduboy2Core::idle()
|
||||
{
|
||||
SMCR = _BV(SE); // select idle mode and enable sleeping
|
||||
sleep_cpu();
|
||||
SMCR = 0; // disable sleeping
|
||||
}
|
||||
|
||||
void Arduboy2Core::bootPowerSaving()
|
||||
{
|
||||
// disable Two Wire Interface (I2C) and the ADC
|
||||
// All other bits will be written with 0 so will be enabled
|
||||
PRR0 = _BV(PRTWI) | _BV(PRADC);
|
||||
// disable USART1
|
||||
PRR1 = _BV(PRUSART1);
|
||||
// All other bits will be written with 0 so will be enabled
|
||||
}
|
||||
|
||||
// Shut down the display
|
||||
void Arduboy2Core::displayOff()
|
||||
{
|
||||
LCDCommandMode();
|
||||
SPItransfer(0xAE); // display off
|
||||
SPItransfer(0x8D); // charge pump:
|
||||
SPItransfer(0x10); // disable
|
||||
delayShort(250);
|
||||
bitClear(RST_PORT, RST_BIT); // set display reset pin low (reset state)
|
||||
}
|
||||
|
||||
// Restart the display after a displayOff()
|
||||
void Arduboy2Core::displayOn()
|
||||
{
|
||||
bootOLED();
|
||||
}
|
||||
|
||||
uint8_t Arduboy2Core::width() { return WIDTH; }
|
||||
|
||||
uint8_t Arduboy2Core::height() { return HEIGHT; }
|
||||
|
||||
|
||||
/* Drawing */
|
||||
|
||||
void Arduboy2Core::paint8Pixels(uint8_t pixels)
|
||||
{
|
||||
SPItransfer(pixels);
|
||||
}
|
||||
|
||||
void Arduboy2Core::paintScreen(const uint8_t *image)
|
||||
{
|
||||
#ifdef OLED_SH1106
|
||||
for (uint8_t i = 0; i < HEIGHT / 8; i++)
|
||||
{
|
||||
LCDCommandMode();
|
||||
SPDR = (OLED_SET_PAGE_ADDRESS + i);
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
SPDR = (OLED_SET_COLUMN_ADDRESS_HI); // only reset hi nibble to zero
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
LCDDataMode();
|
||||
for (uint8_t j = WIDTH; j > 0; j--)
|
||||
{
|
||||
SPDR = pgm_read_byte(image++);
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
}
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128) || defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128) || defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128)
|
||||
#if defined(OLED_128X64_ON_96X96)
|
||||
uint16_t i = 16;
|
||||
for (uint8_t col = 0; col < 96 / 2; col++)
|
||||
#else
|
||||
uint16_t i = 0;
|
||||
for (uint8_t col = 0; col < WIDTH / 2; col++)
|
||||
#endif
|
||||
{
|
||||
for (uint8_t row = 0; row < HEIGHT / 8; row++)
|
||||
{
|
||||
uint8_t b1 = pgm_read_byte(image + i);
|
||||
uint8_t b2 = pgm_read_byte(image + i + 1);
|
||||
for (uint8_t shift = 0; shift < 8; shift++)
|
||||
{
|
||||
uint8_t c = 0xFF;
|
||||
if ((b1 & 1) == 0) c &= 0x0F;
|
||||
if ((b2 & 1) == 0) c &= 0xF0;
|
||||
SPDR = c;
|
||||
b1 = b1 >> 1;
|
||||
b2 = b2 >> 1;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
i += WIDTH;
|
||||
}
|
||||
i -= HEIGHT / 8 * WIDTH - 2;
|
||||
}
|
||||
#elif defined(OLED_64X128_ON_128X128)
|
||||
uint16_t i = WIDTH-1;
|
||||
for (uint8_t col = 0; col < WIDTH ; col++)
|
||||
{
|
||||
for (uint8_t row = 0; row < HEIGHT / 8; row++)
|
||||
{
|
||||
uint8_t b = pgm_read_byte(image + i);
|
||||
if (clear) *(image + i) = 0;
|
||||
for (uint8_t shift = 0; shift < 4; shift++)
|
||||
{
|
||||
uint8_t c = 0xFF;
|
||||
if ((b & _BV(0)) == 0) c &= 0x0F;
|
||||
if ((b & _BV(1)) == 0) c &= 0xF0;
|
||||
SPDR = c;
|
||||
b = b >> 2;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
i += WIDTH;
|
||||
}
|
||||
i -= HEIGHT / 8 * WIDTH + 1;
|
||||
}
|
||||
#else
|
||||
//OLED SSD1306 and compatibles
|
||||
for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
|
||||
{
|
||||
SPItransfer(pgm_read_byte(image + i));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// paint from a memory buffer, this should be FAST as it's likely what
|
||||
// will be used by any buffer based subclass
|
||||
void Arduboy2Core::paintScreen(uint8_t image[], bool clear)
|
||||
{
|
||||
#ifdef OLED_SH1106
|
||||
//Assembly optimized page mode display code with clear support.
|
||||
//Each byte transfer takes 18 cycles
|
||||
asm volatile (
|
||||
" ldi r19, %[page_cmd] \n\t"
|
||||
"1: \n\t"
|
||||
" ldi r18, %[col_cmd] ;1 \n\t"
|
||||
" ldi r20, 6 ;1 \n\t"
|
||||
" cbi %[dc_port], %[dc_bit] ;2 cmd mode \n\t"
|
||||
" \n\t"
|
||||
" out %[spdr], r19 ;1 \n\t"
|
||||
"2: dec r20 ;6*3-1 : 17 \n\t"
|
||||
" brne 2b \n\t"
|
||||
" out %[spdr], r18 ;1 \n\t"
|
||||
|
||||
" ldi r18, %[width] ;1 \n\t"
|
||||
" inc r18 ;1 \n\t"
|
||||
" rjmp 5f ;2 \n\t"
|
||||
"4: \n\t"
|
||||
" lpm r20, Z ;3 delay \n\t"
|
||||
" ld r20, Z ;2 \n\t"
|
||||
" sbi %[dc_port], %[dc_bit] ;2 data mode \n\t"
|
||||
" out %[spdr], r20 ;1 \n\t"
|
||||
" cpse %[clear], __zero_reg__ ;1/2 \n\t"
|
||||
" mov r20, __zero_reg__ ;1 \n\t"
|
||||
" st Z+, r20 ;2 \n\t"
|
||||
"5: \n\t"
|
||||
" lpm r20, Z ;3 delay \n\t"
|
||||
" dec r18 ;1 \n\t"
|
||||
" brne 4b ;1/2 \n\t"
|
||||
" inc r19 ;1 \n\t"
|
||||
" cpi r19,%[page_end] ;1 \n\t"
|
||||
" brne 1b ;1/2 \n\t"
|
||||
" in __tmp_reg__, %[spsr] \n\t" //read SPSR to clear SPIF
|
||||
: [ptr] "+&z" (image)
|
||||
:
|
||||
[page_cmd] "M" (OLED_SET_PAGE_ADDRESS),
|
||||
[page_end] "M" (OLED_SET_PAGE_ADDRESS + (HEIGHT / 8)),
|
||||
[dc_port] "I" (_SFR_IO_ADDR(DC_PORT)),
|
||||
[dc_bit] "I" (DC_BIT),
|
||||
[spdr] "I" (_SFR_IO_ADDR(SPDR)),
|
||||
[spsr] "I" (_SFR_IO_ADDR(SPSR)),
|
||||
[col_cmd] "M" (OLED_SET_COLUMN_ADDRESS_HI),
|
||||
[width] "M" (WIDTH),
|
||||
[clear] "r" (clear)
|
||||
: "r18", "r19", "r20"
|
||||
);
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128)|| defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128)
|
||||
// 1 bit to 4-bit expander display code with clear support.
|
||||
// Each transfer takes 18 cycles with additional 4 cycles for a column change.
|
||||
asm volatile(
|
||||
#if defined(OLED_128X64_ON_96X96)
|
||||
" adiw r30, 16 \n\t"
|
||||
#endif
|
||||
" ldi r25, %[col] \n\t"
|
||||
".lcolumn: \n\t"
|
||||
" ldi r24, %[row] ;1 \n\t"
|
||||
".lrow: \n\t"
|
||||
" ldi r21, 7 ;1 \n\t"
|
||||
" ld r22, z ;2 \n\t"
|
||||
" ldd r23, z+1 ;2 \n\t"
|
||||
".lshiftstart: \n\t"
|
||||
" ldi r20, 0xFF ;1 \n\t"
|
||||
" sbrs r22, 0 ;1 \n\t"
|
||||
" andi r20, 0x0f ;1 \n\t"
|
||||
" sbrs r23, 0 ;1 \n\t"
|
||||
" andi r20,0xf0 ;1 \n\t"
|
||||
" out %[spdr], r20 ;1 \n\t"
|
||||
" \n\t"
|
||||
" cp %[clear], __zero_reg__ ;1 \n\t"
|
||||
" brne .lclear1 ;1/2 \n\t"
|
||||
".lshiftothers: \n\t"
|
||||
" movw r18, %A[ptr] ;1 \n\t"
|
||||
" rjmp .+0 ;2 \n\t"
|
||||
" rjmp .lshiftnext ;2 \n\t"
|
||||
".lclear1: \n\t"
|
||||
" st z, __zero_reg__ ;2 \n\t"
|
||||
" std z+1, __zero_reg__ ;2 \n\t"
|
||||
".lshiftnext: \n\t"
|
||||
" \n\t"
|
||||
" lsr r22 ;1 \n\t"
|
||||
" lsr r23 ;1 \n\t"
|
||||
" \n\t"
|
||||
" ldi r20, 0xFF ;1 \n\t"
|
||||
" sbrs r22, 0 ;1/2 \n\t"
|
||||
" andi r20, 0x0f ;1 \n\t"
|
||||
" sbrs r23, 0 ;1/2 \n\t"
|
||||
" andi r20,0xf0 ;1 \n\t"
|
||||
" \n\t"
|
||||
" subi r18, %[top_lsb] ;1 \n\t" //image - (WIDTH * ((HEIGHT / 8) - 1) - 2)
|
||||
" sbci r19, %[top_msb] ;1 \n\t"
|
||||
" subi r21, 1 ;1 \n\t"
|
||||
" out %[spdr], r20 ;1 \n\t"
|
||||
" brne .lshiftothers ;1/2 \n\t"
|
||||
" \n\t"
|
||||
" nop ;1 \n\t"
|
||||
" subi %A[ptr], %[width] ;1 \n\t" //image + width (negated addition)
|
||||
" sbci %B[ptr], -1 ;1 \n\t"
|
||||
" subi r24, 1 ;1 \n\t"
|
||||
" brne .lrow ;1/2 \n\t"
|
||||
" \n\t"
|
||||
" movw %A[ptr], r18 ;1 \n\t"
|
||||
" subi r25, 1 ;1 \n\t"
|
||||
" brne .lcolumn ;1/2 \n\t"
|
||||
" in __tmp_reg__, %[spsr] \n\t" //read SPSR to clear SPIF
|
||||
: [ptr] "+&z" (image)
|
||||
: [spdr] "I" (_SFR_IO_ADDR(SPDR)),
|
||||
[spsr] "I" (_SFR_IO_ADDR(SPSR)),
|
||||
[row] "M" (HEIGHT / 8),
|
||||
#if defined(OLED_128X64_ON_96X96)
|
||||
[col] "M" (96 / 2),
|
||||
#else
|
||||
[col] "M" (WIDTH / 2),
|
||||
#endif
|
||||
[width] "M" (256 - WIDTH),
|
||||
[top_lsb] "M" ((WIDTH * ((HEIGHT / 8) - 1) - 2) & 0xFF),
|
||||
[top_msb] "M" ((WIDTH * ((HEIGHT / 8) - 1) - 2) >> 8),
|
||||
[clear] "r" (clear)
|
||||
: "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25"
|
||||
);
|
||||
#elif defined(OLED_64X128_ON_128X128)
|
||||
uint16_t i = WIDTH-1;
|
||||
for (uint8_t col = 0; col < WIDTH ; col++)
|
||||
{
|
||||
for (uint8_t row = 0; row < HEIGHT / 8; row++)
|
||||
{
|
||||
uint8_t b = *(image + i);
|
||||
if (clear) *(image + i) = 0;
|
||||
for (uint8_t shift = 0; shift < 4; shift++)
|
||||
{
|
||||
uint8_t c = 0xFF;
|
||||
if ((b & _BV(0)) == 0) c &= 0x0F;
|
||||
if ((b & _BV(1)) == 0) c &= 0xF0;
|
||||
SPDR = c;
|
||||
b = b >> 2;
|
||||
while (!(SPSR & _BV(SPIF)));
|
||||
}
|
||||
i += WIDTH;
|
||||
}
|
||||
i -= HEIGHT / 8 * WIDTH + 1;
|
||||
}
|
||||
#else
|
||||
//OLED SSD1306 and compatibles
|
||||
//data only transfer with clear support at 18 cycles per transfer
|
||||
uint16_t count;
|
||||
|
||||
asm volatile (
|
||||
" ldi %A[count], %[len_lsb] \n\t" //for (len = WIDTH * HEIGHT / 8)
|
||||
" ldi %B[count], %[len_msb] \n\t"
|
||||
"1: ld __tmp_reg__, %a[ptr] ;2 \n\t" //tmp = *(image)
|
||||
" out %[spdr], __tmp_reg__ ;1 \n\t" //SPDR = tmp
|
||||
" cpse %[clear], __zero_reg__ ;1/2 \n\t" //if (clear) tmp = 0;
|
||||
" mov __tmp_reg__, __zero_reg__ ;1 \n\t"
|
||||
"2: sbiw %A[count], 1 ;2 \n\t" //len --
|
||||
" sbrc %A[count], 0 ;1/2 \n\t" //loop twice for cheap delay
|
||||
" rjmp 2b ;2 \n\t"
|
||||
" st %a[ptr]+, __tmp_reg__ ;2 \n\t" //*(image++) = tmp
|
||||
" brne 1b ;1/2 :18 \n\t" //len > 0
|
||||
" in __tmp_reg__, %[spsr] \n\t" //read SPSR to clear SPIF
|
||||
: [ptr] "+&e" (image),
|
||||
[count] "=&w" (count)
|
||||
: [spdr] "I" (_SFR_IO_ADDR(SPDR)),
|
||||
[spsr] "I" (_SFR_IO_ADDR(SPSR)),
|
||||
[len_msb] "M" (WIDTH * (HEIGHT / 8 * 2) >> 8), // 8: pixels per byte
|
||||
[len_lsb] "M" (WIDTH * (HEIGHT / 8 * 2) & 0xFF), // 2: for delay loop multiplier
|
||||
[clear] "r" (clear)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Core::blank()
|
||||
{
|
||||
#ifdef OLED_SH1106
|
||||
for (int i = 0; i < (HEIGHT * 132) / 8; i++)
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_128X128)|| defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128)
|
||||
for (int i = 0; i < (HEIGHT * WIDTH) / 2; i++)
|
||||
#else //OLED SSD1306 and compatibles
|
||||
for (int i = 0; i < (HEIGHT * WIDTH) / 8; i++)
|
||||
#endif
|
||||
SPItransfer(0x00);
|
||||
}
|
||||
|
||||
void Arduboy2Core::sendLCDCommand(uint8_t command)
|
||||
{
|
||||
LCDCommandMode();
|
||||
SPItransfer(command);
|
||||
LCDDataMode();
|
||||
}
|
||||
|
||||
// invert the display or set to normal
|
||||
// when inverted, a pixel set to 0 will be on
|
||||
void Arduboy2Core::invert(bool inverse)
|
||||
{
|
||||
sendLCDCommand(inverse ? OLED_PIXELS_INVERTED : OLED_PIXELS_NORMAL);
|
||||
}
|
||||
|
||||
// turn all display pixels on, ignoring buffer contents
|
||||
// or set to normal buffer display
|
||||
void Arduboy2Core::allPixelsOn(bool on)
|
||||
{
|
||||
sendLCDCommand(on ? OLED_ALL_PIXELS_ON : OLED_PIXELS_FROM_RAM);
|
||||
}
|
||||
|
||||
// flip the display vertically or set to normal
|
||||
void Arduboy2Core::flipVertical(bool flipped)
|
||||
{
|
||||
sendLCDCommand(flipped ? OLED_VERTICAL_FLIPPED : OLED_VERTICAL_NORMAL);
|
||||
}
|
||||
|
||||
// flip the display horizontally or set to normal
|
||||
void Arduboy2Core::flipHorizontal(bool flipped)
|
||||
{
|
||||
sendLCDCommand(flipped ? OLED_HORIZ_FLIPPED : OLED_HORIZ_NORMAL);
|
||||
}
|
||||
|
||||
/* RGB LED */
|
||||
|
||||
void Arduboy2Core::setRGBled(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
#ifdef ARDUBOY_10 // RGB, all the pretty colors
|
||||
uint8_t pwmstate = TCCR0A;
|
||||
#ifndef AB_ALTERNATE_WIRING
|
||||
pwmstate &= ~_BV(COM0A1); //default to digital pin for min and max values
|
||||
#else
|
||||
pwmstate &= ~_BV(COM0B1);
|
||||
#endif
|
||||
if (green == 0)
|
||||
bitSet(GREEN_LED_PORT, GREEN_LED_BIT);
|
||||
else if (green == 255)
|
||||
bitClear(GREEN_LED_PORT, GREEN_LED_BIT);
|
||||
else
|
||||
{
|
||||
#ifndef AB_ALTERNATE_WIRING
|
||||
pwmstate |= _BV(COM0A1); //configure pin as pwm pin
|
||||
OCR0A = 255 - green; //set pwm duty
|
||||
#else
|
||||
pwmstate |= _BV(COM0B1);
|
||||
OCR0B = 255 - green;
|
||||
#endif
|
||||
}
|
||||
TCCR0A = pwmstate;
|
||||
pwmstate = TCCR1A & ~(_BV(COM1B1) | _BV(COM1A1)); //default to digital pins for min and max values
|
||||
if (red == 0) bitSet(RED_LED_PORT, RED_LED_BIT);
|
||||
else if (red == 255) bitClear(RED_LED_PORT, RED_LED_BIT);
|
||||
else
|
||||
{
|
||||
pwmstate |= _BV(COM1B1); //configure pin as pwm pin
|
||||
OCR1BH = 0;
|
||||
OCR1BL = 255 - red; //set pwm duty
|
||||
}
|
||||
if (blue == 0) bitSet(BLUE_LED_PORT, BLUE_LED_BIT);
|
||||
else if (blue == 255) bitClear(BLUE_LED_PORT, BLUE_LED_BIT);
|
||||
else
|
||||
{
|
||||
pwmstate |= _BV(COM1A1); //configure pin as pwm pin
|
||||
OCR1AH = 0;
|
||||
OCR1AL = 255 - blue; //set pwm duty
|
||||
}
|
||||
TCCR1A = pwmstate;
|
||||
#elif defined(AB_DEVKIT)
|
||||
// only blue on DevKit, which is not PWM capable
|
||||
(void)red; // parameter unused
|
||||
(void)green; // parameter unused
|
||||
bitWrite(BLUE_LED_PORT, BLUE_LED_BIT, blue ? RGB_ON : RGB_OFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Core::setRGBled(uint8_t color, uint8_t val)
|
||||
{
|
||||
#ifdef ARDUBOY_10
|
||||
if (color == RED_LED)
|
||||
{
|
||||
OCR1BL = val;
|
||||
}
|
||||
else if (color == GREEN_LED)
|
||||
{
|
||||
#ifndef AB_ALTERNATE_WIRING
|
||||
OCR0A = 255 - val;
|
||||
#else
|
||||
OCR0B = 255 - val;
|
||||
#endif
|
||||
}
|
||||
else if (color == BLUE_LED)
|
||||
{
|
||||
OCR1AL = val;
|
||||
}
|
||||
#elif defined(AB_DEVKIT)
|
||||
// only blue on DevKit, which is not PWM capable
|
||||
if (color == BLUE_LED)
|
||||
{
|
||||
bitWrite(BLUE_LED_PORT, BLUE_LED_BIT, val ? RGB_ON : RGB_OFF);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Core::freeRGBled()
|
||||
{
|
||||
#ifdef ARDUBOY_10
|
||||
// clear the COM bits to return the pins to normal I/O mode
|
||||
TCCR0A = _BV(WGM01) | _BV(WGM00);
|
||||
TCCR1A = _BV(WGM10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Core::digitalWriteRGB(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
#ifdef ARDUBOY_10
|
||||
bitWrite(RED_LED_PORT, RED_LED_BIT, red);
|
||||
bitWrite(GREEN_LED_PORT, GREEN_LED_BIT, green);
|
||||
bitWrite(BLUE_LED_PORT, BLUE_LED_BIT, blue);
|
||||
#elif defined(AB_DEVKIT)
|
||||
// only blue on DevKit
|
||||
(void)red; // parameter unused
|
||||
(void)green; // parameter unused
|
||||
bitWrite(BLUE_LED_PORT, BLUE_LED_BIT, blue);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Core::digitalWriteRGB(uint8_t color, uint8_t val)
|
||||
{
|
||||
#ifdef ARDUBOY_10
|
||||
if (color == RED_LED)
|
||||
{
|
||||
bitWrite(RED_LED_PORT, RED_LED_BIT, val);
|
||||
}
|
||||
else if (color == GREEN_LED)
|
||||
{
|
||||
bitWrite(GREEN_LED_PORT, GREEN_LED_BIT, val);
|
||||
}
|
||||
else if (color == BLUE_LED)
|
||||
{
|
||||
bitWrite(BLUE_LED_PORT, BLUE_LED_BIT, val);
|
||||
}
|
||||
#elif defined(AB_DEVKIT)
|
||||
// only blue on DevKit
|
||||
if (color == BLUE_LED)
|
||||
{
|
||||
bitWrite(BLUE_LED_PORT, BLUE_LED_BIT, val);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
uint8_t Arduboy2Core::buttonsState()
|
||||
{
|
||||
#ifndef ARDUBOY_CORE
|
||||
uint8_t buttons;
|
||||
#ifdef ARDUBOY_10
|
||||
// up, right, left, down
|
||||
buttons = ((~PINF) &
|
||||
(_BV(UP_BUTTON_BIT) | _BV(RIGHT_BUTTON_BIT) |
|
||||
_BV(LEFT_BUTTON_BIT) | _BV(DOWN_BUTTON_BIT)));
|
||||
// A
|
||||
if (bitRead(A_BUTTON_PORTIN, A_BUTTON_BIT) == 0) { buttons |= A_BUTTON; }
|
||||
// B
|
||||
if (bitRead(B_BUTTON_PORTIN, B_BUTTON_BIT) == 0) { buttons |= B_BUTTON; }
|
||||
#elif defined(AB_DEVKIT)
|
||||
// down, left, up
|
||||
buttons = ((~PINB) &
|
||||
(_BV(DOWN_BUTTON_BIT) | _BV(LEFT_BUTTON_BIT) | _BV(UP_BUTTON_BIT)));
|
||||
// right
|
||||
if (bitRead(RIGHT_BUTTON_PORTIN, RIGHT_BUTTON_BIT) == 0) { buttons |= RIGHT_BUTTON; }
|
||||
// A
|
||||
if (bitRead(A_BUTTON_PORTIN, A_BUTTON_BIT) == 0) { buttons |= A_BUTTON; }
|
||||
// B
|
||||
if (bitRead(B_BUTTON_PORTIN, B_BUTTON_BIT) == 0) { buttons |= B_BUTTON; }
|
||||
#endif
|
||||
#else
|
||||
register uint8_t buttons asm("r24");
|
||||
asm volatile("call scan_buttons\n\t" : "=d" (buttons));
|
||||
#endif
|
||||
return buttons;
|
||||
}
|
||||
|
||||
// delay in ms with 16 bit duration
|
||||
void Arduboy2Core::delayShort(uint16_t ms)
|
||||
{
|
||||
#ifndef ARDUBOY_CORE
|
||||
delay((unsigned long) ms);
|
||||
#else
|
||||
::delayShort(ms);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arduboy2Core::exitToBootloader()
|
||||
{
|
||||
#ifndef ARDUBOY_CORE
|
||||
cli();
|
||||
// set bootloader magic key
|
||||
// storing two uint8_t instead of one uint16_t saves an instruction
|
||||
// when high and low bytes of the magic key are the same
|
||||
*(uint8_t *)MAGIC_KEY_POS = lowByte(MAGIC_KEY);
|
||||
*(uint8_t *)(MAGIC_KEY_POS + 1) = highByte(MAGIC_KEY);
|
||||
// enable watchdog timer reset, with 16ms timeout
|
||||
wdt_reset();
|
||||
WDTCSR = (_BV(WDCE) | _BV(WDE));
|
||||
WDTCSR = _BV(WDE);
|
||||
while (true) { }
|
||||
#else
|
||||
bootloader_timer = 120; //ms
|
||||
#endif
|
||||
}
|
||||
|
||||
// Replacement main() that eliminates the USB stack code.
|
||||
// Used by the ARDUBOY_NO_USB macro. This should not be called
|
||||
// directly from a sketch.
|
||||
|
||||
void Arduboy2Core::mainNoUSB()
|
||||
{
|
||||
// disable USB
|
||||
UDCON = _BV(DETACH);
|
||||
UDIEN = 0;
|
||||
UDINT = 0;
|
||||
USBCON = _BV(FRZCLK);
|
||||
UHWCON = 0;
|
||||
power_usb_disable();
|
||||
|
||||
init();
|
||||
|
||||
// This would normally be done in the USB code that uses the TX and RX LEDs
|
||||
//TX_RX_LED_INIT; // configured by bootpins
|
||||
|
||||
// Set the DOWN button pin for INPUT_PULLUP
|
||||
bitSet(DOWN_BUTTON_PORT, DOWN_BUTTON_BIT);
|
||||
bitClear(DOWN_BUTTON_DDR, DOWN_BUTTON_BIT);
|
||||
|
||||
// Delay to give time for the pin to be pulled high if it was floating
|
||||
delayShort(10);
|
||||
|
||||
// if the DOWN button is pressed
|
||||
if (bitRead(DOWN_BUTTON_PORTIN, DOWN_BUTTON_BIT) == 0) {
|
||||
exitToBootloader();
|
||||
}
|
||||
|
||||
// The remainder is a copy of the Arduino main() function with the
|
||||
// USB code and other unneeded code commented out.
|
||||
// init() was called above.
|
||||
// The call to function initVariant() is commented out to fix compiler
|
||||
// error: "multiple definition of 'main'".
|
||||
// The return statement is removed since this function is type void.
|
||||
|
||||
// init();
|
||||
|
||||
// initVariant();
|
||||
|
||||
//#if defined(USBCON)
|
||||
// USBDevice.attach();
|
||||
//#endif
|
||||
|
||||
setup();
|
||||
|
||||
for (;;) {
|
||||
loop();
|
||||
// if (serialEventRun) serialEventRun();
|
||||
}
|
||||
|
||||
// return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,920 @@
|
|||
/**
|
||||
* @file Arduboy2Core.h
|
||||
* \brief
|
||||
* The Arduboy2Core class for Arduboy hardware initilization and control.
|
||||
*/
|
||||
|
||||
#ifndef ARDUBOY2_CORE_H
|
||||
#define ARDUBOY2_CORE_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <limits.h>
|
||||
|
||||
extern volatile unsigned char bootloader_timer;
|
||||
|
||||
// main hardware compile flags
|
||||
|
||||
#if !defined(ARDUBOY_10) && !defined(AB_DEVKIT)
|
||||
/* defaults to Arduboy Release 1.0 if not using a boards.txt file
|
||||
*
|
||||
* we default to Arduboy Release 1.0 if a compile flag has not been
|
||||
* passed to us from a boards.txt file
|
||||
*
|
||||
* if you wish to compile for the devkit without using a boards.txt
|
||||
* file simply comment out the ARDUBOY_10 define and uncomment
|
||||
* the AB_DEVKIT define like this:
|
||||
*
|
||||
* // #define ARDUBOY_10
|
||||
* #define AB_DEVKIT
|
||||
*/
|
||||
#define ARDUBOY_10 //< compile for the production Arduboy v1.0
|
||||
// #define AB_DEVKIT //< compile for the official dev kit
|
||||
#endif
|
||||
|
||||
#define RGB_ON LOW /**< For digitially setting an RGB LED on using digitalWriteRGB() */
|
||||
#define RGB_OFF HIGH /**< For digitially setting an RGB LED off using digitalWriteRGB() */
|
||||
|
||||
// ----- Arduboy pins -----
|
||||
#ifdef ARDUBOY_10
|
||||
|
||||
#ifdef AB_ALTERNATE_WIRING
|
||||
#define PIN_CS 1 // Pro Micro alternative display CS pin (pin 12 not not available)
|
||||
#define CS_PORT PORTD
|
||||
#define CS_BIT PORTD3
|
||||
|
||||
#define PIN_RST 2 // Pro Micro alternative display RST pin (pin 6 favoured for 2nd speaker pin)
|
||||
#define RST_PORT PORTD
|
||||
#define RST_BIT PORTD1
|
||||
#else
|
||||
#define PIN_CS 12 // Display CS Arduino pin number
|
||||
#define CS_PORT PORTD // Display CS port
|
||||
#define CS_BIT PORTD6 // Display CS physical bit number
|
||||
|
||||
#define PIN_RST 6 // Display reset Arduino pin number
|
||||
#define RST_PORT PORTD // Display reset port
|
||||
#define RST_BIT PORTD7 // Display reset physical bit number
|
||||
#endif
|
||||
|
||||
#define PIN_DC 4 // Display D/C Arduino pin number
|
||||
#define DC_PORT PORTD // Display D/C port
|
||||
#define DC_BIT PORTD4 // Display D/C physical bit number
|
||||
|
||||
#define PIN_CART 0 // flash cart chip select
|
||||
#define CART_PORT PORTD
|
||||
#define CART_BIT PORTD2
|
||||
|
||||
#define SPI_MOSI_PORT PORTB
|
||||
#define SPI_MOSI_BIT PORTB2
|
||||
|
||||
#define SPI_SCK_PORT PORTB
|
||||
#define SPI_SCK_BIT PORTB1
|
||||
|
||||
#define RED_LED 10 /**< The pin number for the red color in the RGB LED. */
|
||||
#ifdef AB_ALTERNATE_WIRING
|
||||
#define GREEN_LED 3 // Pro Micro alternative green LED pin
|
||||
#else
|
||||
#define GREEN_LED 11 /**< The pin number for the green color in the RGB LED. */
|
||||
#endif
|
||||
#define BLUE_LED 9 /**< The pin number for the blue color in the RGB LED. */
|
||||
|
||||
#define RED_LED_PORT PORTB
|
||||
#define RED_LED_BIT PORTB6
|
||||
|
||||
#ifdef AB_ALTERNATE_WIRING
|
||||
#define GREEN_LED_PORT PORTD // Pro Micro alternative green LED port
|
||||
#define GREEN_LED_BIT PORTD0
|
||||
#else
|
||||
#define GREEN_LED_PORT PORTB
|
||||
#define GREEN_LED_BIT PORTB7
|
||||
#endif
|
||||
|
||||
#define BLUE_LED_PORT PORTB
|
||||
#define BLUE_LED_BIT PORTB5
|
||||
|
||||
#define TX_LED_PORT PORTD
|
||||
#define TX_LED_BIT PORTD5
|
||||
|
||||
#define RX_LED_PORT PORTB
|
||||
#define RX_LED_BIT PORTB0
|
||||
|
||||
// bit values for button states
|
||||
// these are determined by the buttonsState() function
|
||||
#define LEFT_BUTTON _BV(5) /**< The Left button value for functions requiring a bitmask */
|
||||
#define RIGHT_BUTTON _BV(6) /**< The Right button value for functions requiring a bitmask */
|
||||
#define UP_BUTTON _BV(7) /**< The Up button value for functions requiring a bitmask */
|
||||
#define DOWN_BUTTON _BV(4) /**< The Down button value for functions requiring a bitmask */
|
||||
#define A_BUTTON _BV(3) /**< The A button value for functions requiring a bitmask */
|
||||
#define B_BUTTON _BV(2) /**< The B button value for functions requiring a bitmask */
|
||||
|
||||
#define PIN_LEFT_BUTTON A2
|
||||
#define LEFT_BUTTON_PORT PORTF
|
||||
#define LEFT_BUTTON_PORTIN PINF
|
||||
#define LEFT_BUTTON_DDR DDRF
|
||||
#define LEFT_BUTTON_BIT PORTF5
|
||||
|
||||
#define PIN_RIGHT_BUTTON A1
|
||||
#define RIGHT_BUTTON_PORT PORTF
|
||||
#define RIGHT_BUTTON_PORTIN PINF
|
||||
#define RIGHT_BUTTON_DDR DDRF
|
||||
#define RIGHT_BUTTON_BIT PORTF6
|
||||
|
||||
#define PIN_UP_BUTTON A0
|
||||
#define UP_BUTTON_PORT PORTF
|
||||
#define UP_BUTTON_PORTIN PINF
|
||||
#define UP_BUTTON_DDR DDRF
|
||||
#define UP_BUTTON_BIT PORTF7
|
||||
|
||||
#define PIN_DOWN_BUTTON A3
|
||||
#define DOWN_BUTTON_PORT PORTF
|
||||
#define DOWN_BUTTON_PORTIN PINF
|
||||
#define DOWN_BUTTON_DDR DDRF
|
||||
#define DOWN_BUTTON_BIT PORTF4
|
||||
|
||||
#define PIN_A_BUTTON 7
|
||||
#define A_BUTTON_PORT PORTE
|
||||
#define A_BUTTON_PORTIN PINE
|
||||
#define A_BUTTON_DDR DDRE
|
||||
#define A_BUTTON_BIT PORTE6
|
||||
|
||||
#define PIN_B_BUTTON 8
|
||||
#define B_BUTTON_PORT PORTB
|
||||
#define B_BUTTON_PORTIN PINB
|
||||
#define B_BUTTON_DDR DDRB
|
||||
#define B_BUTTON_BIT PORTB4
|
||||
|
||||
#define PIN_SPEAKER_1 5 /**< The pin number of the first lead of the speaker */
|
||||
|
||||
#define SPEAKER_1_PORT PORTC
|
||||
#define SPEAKER_1_DDR DDRC
|
||||
#define SPEAKER_1_BIT PORTC6
|
||||
|
||||
#ifdef AB_ALTERNATE_WIRING
|
||||
#define PIN_SPEAKER_2 6 //Pro Micro alternative for 2nd speaker pin
|
||||
#define SPEAKER_2_PORT PORTD
|
||||
#define SPEAKER_2_DDR DDRD
|
||||
#define SPEAKER_2_BIT PORTD7
|
||||
#else
|
||||
#define PIN_SPEAKER_2 13 /**< The pin number of the second lead of the speaker */
|
||||
#define SPEAKER_2_PORT PORTC
|
||||
#define SPEAKER_2_DDR DDRC
|
||||
#define SPEAKER_2_BIT PORTC7
|
||||
#endif
|
||||
// -----------------------
|
||||
|
||||
// ----- DevKit pins -----
|
||||
#elif defined(AB_DEVKIT)
|
||||
|
||||
#define PIN_CS 6 // Display CS Arduino pin number
|
||||
#define CS_PORT PORTD // Display CS port
|
||||
#define CS_BIT PORTD7 // Display CS physical bit number
|
||||
|
||||
#define PIN_DC 4 // Display D/C Arduino pin number
|
||||
#define DC_PORT PORTD // Display D/C port
|
||||
#define DC_BIT PORTD4 // Display D/C physical bit number
|
||||
|
||||
#define PIN_RST 12 // Display reset Arduino pin number
|
||||
#define RST_PORT PORTD // Display reset port
|
||||
#define RST_BIT PORTD6 // Display reset physical bit number
|
||||
|
||||
#define SPI_MOSI_PORT PORTB
|
||||
#define SPI_MOSI_BIT PORTB2
|
||||
|
||||
#define SPI_SCK_PORT PORTB
|
||||
#define SPI_SCK_BIT PORTB1
|
||||
|
||||
// map all LEDs to the single TX LED on DEVKIT
|
||||
#define RED_LED 17
|
||||
#define GREEN_LED 17
|
||||
#define BLUE_LED 17
|
||||
|
||||
#define RX_LED_BIT PORTB0
|
||||
#define BLUE_LED_PORT PORTB
|
||||
#define BLUE_LED_BIT PORTB0
|
||||
|
||||
// bit values for button states
|
||||
// these are determined by the buttonsState() function
|
||||
#define LEFT_BUTTON _BV(5)
|
||||
#define RIGHT_BUTTON _BV(2)
|
||||
#define UP_BUTTON _BV(4)
|
||||
#define DOWN_BUTTON _BV(6)
|
||||
#define A_BUTTON _BV(1)
|
||||
#define B_BUTTON _BV(0)
|
||||
|
||||
// pin values for buttons, probably shouldn't use these
|
||||
#define PIN_LEFT_BUTTON 9
|
||||
#define LEFT_BUTTON_PORT PORTB
|
||||
#define LEFT_BUTTON_PORTIN PINB
|
||||
#define LEFT_BUTTON_DDR DDRB
|
||||
#define LEFT_BUTTON_BIT PORTB5
|
||||
|
||||
#define PIN_RIGHT_BUTTON 5
|
||||
#define RIGHT_BUTTON_PORT PORTC
|
||||
#define RIGHT_BUTTON_PORTIN PINC
|
||||
#define RIGHT_BUTTON_DDR DDRC
|
||||
#define RIGHT_BUTTON_BIT PORTC6
|
||||
|
||||
#define PIN_UP_BUTTON 8
|
||||
#define UP_BUTTON_PORT PORTB
|
||||
#define UP_BUTTON_PORTIN PINB
|
||||
#define UP_BUTTON_DDR DDRB
|
||||
#define UP_BUTTON_BIT PORTB4
|
||||
|
||||
#define PIN_DOWN_BUTTON 10
|
||||
#define DOWN_BUTTON_PORT PORTB
|
||||
#define DOWN_BUTTON_PORTIN PINB
|
||||
#define DOWN_BUTTON_DDR DDRB
|
||||
#define DOWN_BUTTON_BIT PORTB6
|
||||
|
||||
#define PIN_A_BUTTON A0
|
||||
#define A_BUTTON_PORT PORTF
|
||||
#define A_BUTTON_PORTIN PINF
|
||||
#define A_BUTTON_DDR DDRF
|
||||
#define A_BUTTON_BIT PORTF7
|
||||
|
||||
#define PIN_B_BUTTON A1
|
||||
#define B_BUTTON_PORT PORTF
|
||||
#define B_BUTTON_PORTIN PINF
|
||||
#define B_BUTTON_DDR DDRF
|
||||
#define B_BUTTON_BIT PORTF6
|
||||
|
||||
#define PIN_SPEAKER_1 A2
|
||||
#define SPEAKER_1_PORT PORTF
|
||||
#define SPEAKER_1_DDR DDRF
|
||||
#define SPEAKER_1_BIT PORTF5
|
||||
// SPEAKER_2 is purposely not defined for DEVKIT as it could potentially
|
||||
// be dangerous and fry your hardware (because of the devkit wiring).
|
||||
//
|
||||
// Reference: https://github.com/Arduboy/Arduboy/issues/108
|
||||
|
||||
#endif
|
||||
// --------------------
|
||||
|
||||
// ----- Pins common on Arduboy and DevKit -----
|
||||
|
||||
// Unconnected analog input used for noise by initRandomSeed()
|
||||
#define RAND_SEED_IN A4
|
||||
#define RAND_SEED_IN_PORT PORTF
|
||||
#define RAND_SEED_IN_BIT PORTF1
|
||||
// Value for ADMUX to read the random seed pin: 2.56V reference, ADC1
|
||||
#define RAND_SEED_IN_ADMUX (_BV(REFS0) | _BV(REFS1) | _BV(MUX0))
|
||||
|
||||
// SPI interface
|
||||
#define SPI_MISO_PORT PORTB
|
||||
#define SPI_MISO_BIT PORTB3
|
||||
|
||||
#define SPI_MOSI_PORT PORTB
|
||||
#define SPI_MOSI_BIT PORTB2
|
||||
|
||||
#define SPI_SCK_PORT PORTB
|
||||
#define SPI_SCK_BIT PORTB1
|
||||
|
||||
#define SPI_SS_PORT PORTB
|
||||
#define SPI_SS_BIT PORTB0 //Note SPI SS pin is the same pin as for RXLED
|
||||
|
||||
// --------------------
|
||||
|
||||
// OLED hardware (SSD1306,SSD1309,SH1106,OLED_96X96,OLED_128x96)
|
||||
|
||||
#define OLED_PIXELS_INVERTED 0xA7 // All pixels inverted
|
||||
#define OLED_PIXELS_NORMAL 0xA6 // All pixels normal
|
||||
|
||||
#define OLED_ALL_PIXELS_ON 0xA5 // all pixels on
|
||||
#define OLED_PIXELS_FROM_RAM 0xA4 // pixels mapped to display RAM contents
|
||||
|
||||
#define OLED_VERTICAL_FLIPPED 0xC0 // reversed COM scan direction
|
||||
#define OLED_VERTICAL_NORMAL 0xC8 // normal COM scan direction
|
||||
|
||||
#define OLED_HORIZ_FLIPPED 0xA0 // reversed segment re-map
|
||||
#define OLED_HORIZ_NORMAL 0xA1 // normal segment re-map
|
||||
|
||||
#define OLED_SET_PAGE_ADDRESS 0xB0
|
||||
#ifdef OLED_SH1106
|
||||
#define OLED_SET_COLUMN_ADDRESS_LO 0x02 //SH1106 only: 1st pixel starts on column 2
|
||||
#else
|
||||
#define OLED_SET_COLUMN_ADDRESS_LO 0x00
|
||||
#endif
|
||||
#define OLED_SET_COLUMN_ADDRESS_HI 0x10
|
||||
// -----
|
||||
#if defined (OLED_96X96) || (OLED_96X96_ON_128X128)
|
||||
#define WIDTH 96
|
||||
#else
|
||||
#define WIDTH 128 //The standard width of the display in pixels
|
||||
#endif
|
||||
#if defined(OLED_128X128)
|
||||
#define HEIGHT 128
|
||||
#elif defined(OLED_96X96) || defined(OLED_128X96) || defined(OLED_96X96_ON_128X128) || defined(OLED_128X96_ON_128X128)
|
||||
#define HEIGHT 96
|
||||
#else
|
||||
#define HEIGHT 64 //The standard height of the display in pixels
|
||||
#endif
|
||||
|
||||
#define COLUMN_ADDRESS_END (WIDTH - 1) & 127 // 128 pixels wide
|
||||
#define PAGE_ADDRESS_END ((HEIGHT/8)-1) & 7 // 8 pages high
|
||||
|
||||
/** \brief
|
||||
* Eliminate the USB stack to free up code space.
|
||||
*
|
||||
* \note
|
||||
* **WARNING:** Removing the USB code will make it impossible for sketch
|
||||
* uploader programs to automatically force a reset into the bootloader!
|
||||
* This means that a user will manually have to invoke a reset in order to
|
||||
* upload a new sketch, after one without USB has be been installed.
|
||||
* Be aware that the timing for the point that a reset must be initiated can
|
||||
* be tricky, which could lead to some frustration on the user's part.
|
||||
*
|
||||
* \details
|
||||
* \parblock
|
||||
* This macro will cause the USB code, normally included in the sketch as part
|
||||
* of the standard Arduino environment, to be eliminated. This will free up a
|
||||
* fair amount of program space, and some RAM space as well, at the expense of
|
||||
* disabling all USB functionality within the sketch (except as power input).
|
||||
*
|
||||
* The macro should be placed before the `setup()` function definition:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* #include <Arduboy2.h>
|
||||
*
|
||||
* Arduboy2 arduboy;
|
||||
*
|
||||
* // (Other variable declarations, etc.)
|
||||
*
|
||||
* // Eliminate the USB stack
|
||||
* ARDUBOY_NO_USB
|
||||
*
|
||||
* void setup() {
|
||||
* arduboy.begin();
|
||||
* // any additional setup code
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* As stated in the warning above, without the USB code an uploader program
|
||||
* will be unable to automatically force a reset into the bootloader to upload
|
||||
* a new sketch. The user will have to manually invoke a reset. In addition to
|
||||
* eliminating the USB code, this macro will check if the DOWN button is held
|
||||
* when the sketch first starts and, if so, will call `exitToBootloader()` to
|
||||
* start the bootloader for uploading. This makes it easier for the user than
|
||||
* having to press the reset button.
|
||||
*
|
||||
* However, to make it even more convenient for a user to invoke the bootloader
|
||||
* it is highly recommended that a sketch using this macro include a menu or
|
||||
* prompt that allows the user to press the DOWN button within the sketch,
|
||||
* which should cause `exitToBootloader()` to be called.
|
||||
*
|
||||
* At a minimum, the documentation for the sketch should clearly state that a
|
||||
* manual reset will be required, and give detailed instructions on what the
|
||||
* user must do to upload a new sketch.
|
||||
* \endparblock
|
||||
*
|
||||
* \see Arduboy2Core::exitToBootloader()
|
||||
*/
|
||||
#define ARDUBOY_NO_USB int main() __attribute__ ((OS_main)); \
|
||||
int main() { \
|
||||
Arduboy2Core::mainNoUSB(); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
/** \brief
|
||||
* Lower level functions generally dealing directly with the hardware.
|
||||
*
|
||||
* \details
|
||||
* This class is inherited by Arduboy2Base and thus also Arduboy2, so wouldn't
|
||||
* normally be used directly by a sketch.
|
||||
*
|
||||
* \note
|
||||
* A friend class named _Arduboy2Ex_ is declared by this class. The intention
|
||||
* is to allow a sketch to create an _Arduboy2Ex_ class which would have access
|
||||
* to the private and protected members of the Arduboy2Core class. It is hoped
|
||||
* that this may eliminate the need to create an entire local copy of the
|
||||
* library, in order to extend the functionality, in most circumstances.
|
||||
*/
|
||||
class Arduboy2Core
|
||||
{
|
||||
friend class Arduboy2Ex;
|
||||
|
||||
public:
|
||||
Arduboy2Core();
|
||||
|
||||
/** \brief
|
||||
* Idle the CPU to save power.
|
||||
*
|
||||
* \details
|
||||
* This puts the CPU in _idle_ sleep mode. You should call this as often
|
||||
* as you can for the best power savings. The timer 0 overflow interrupt
|
||||
* will wake up the chip every 1ms, so even at 60 FPS a well written
|
||||
* app should be able to sleep maybe half the time in between rendering
|
||||
* it's own frames.
|
||||
*/
|
||||
void static idle();
|
||||
|
||||
/** \brief
|
||||
* Put the display into data mode.
|
||||
*
|
||||
* \details
|
||||
* When placed in data mode, data that is sent to the display will be
|
||||
* considered as data to be displayed.
|
||||
*
|
||||
* \note
|
||||
* This is a low level function that is not intended for general use in a
|
||||
* sketch. It has been made public and documented for use by derived
|
||||
* classes.
|
||||
*
|
||||
* \see LCDCommandMode() SPItransfer()
|
||||
*/
|
||||
inline void static LCDDataMode() __attribute__((always_inline));
|
||||
/** \brief
|
||||
* Put the display into command mode.
|
||||
*
|
||||
* \details
|
||||
* When placed in command mode, data that is sent to the display will be
|
||||
* treated as commands.
|
||||
*
|
||||
* See the SSD1306 controller and OLED display documents for available
|
||||
* commands and command sequences.
|
||||
*
|
||||
* Links:
|
||||
*
|
||||
* - https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
* - http://www.buydisplay.com/download/manual/ER-OLED013-1_Series_Datasheet.pdf
|
||||
*
|
||||
* \note
|
||||
* This is a low level function that is not intended for general use in a
|
||||
* sketch. It has been made public and documented for use by derived
|
||||
* classes.
|
||||
*
|
||||
* \see LCDDataMode() sendLCDCommand() SPItransfer()
|
||||
*/
|
||||
inline void static LCDCommandMode() __attribute__((always_inline));
|
||||
/** \brief
|
||||
* Transfer a byte to the display.
|
||||
*
|
||||
* \param data The byte to be sent to the display.
|
||||
*
|
||||
* \details
|
||||
* Transfer one byte to the display over the SPI port and wait for the
|
||||
* transfer to complete. The byte will either be interpreted as a command
|
||||
* or as data to be placed on the screen, depending on the command/data
|
||||
* mode.
|
||||
*
|
||||
* \see LCDDataMode() LCDCommandMode() sendLCDCommand()
|
||||
*/
|
||||
uint8_t static SPItransfer(uint8_t data);
|
||||
|
||||
/** \brief
|
||||
* Turn the display off.
|
||||
*
|
||||
* \details
|
||||
* The display will clear and be put into a low power mode. This can be
|
||||
* used to extend battery life when a game is paused or when a sketch
|
||||
* doesn't require anything to be displayed for a relatively long period
|
||||
* of time.
|
||||
*
|
||||
* \see displayOn()
|
||||
*/
|
||||
void static displayOff();
|
||||
|
||||
/** \brief
|
||||
* Turn the display on.
|
||||
*
|
||||
* \details
|
||||
* Used to power up and reinitialize the display after calling
|
||||
* `displayOff()`.
|
||||
*
|
||||
* \note
|
||||
* The previous call to `displayOff()` will have caused the display's
|
||||
* buffer contents to be lost. The display will have to be re-painted,
|
||||
* which is usually done by calling `display()`.
|
||||
*
|
||||
* \see displayOff()
|
||||
*/
|
||||
void static displayOn();
|
||||
|
||||
/** \brief
|
||||
* Get the width of the display in pixels.
|
||||
*
|
||||
* \return The width of the display in pixels.
|
||||
*
|
||||
* \note
|
||||
* In most cases, the defined value `WIDTH` would be better to use instead
|
||||
* of this function.
|
||||
*/
|
||||
uint8_t static width();
|
||||
|
||||
/** \brief
|
||||
* Get the height of the display in pixels.
|
||||
*
|
||||
* \return The height of the display in pixels.
|
||||
*
|
||||
* \note
|
||||
* In most cases, the defined value `HEIGHT` would be better to use instead
|
||||
* of this function.
|
||||
*/
|
||||
uint8_t static height();
|
||||
|
||||
/** \brief
|
||||
* Get the current state of all buttons as a bitmask.
|
||||
*
|
||||
* \return A bitmask of the state of all the buttons.
|
||||
*
|
||||
* \details
|
||||
* The returned mask contains a bit for each button. For any pressed button,
|
||||
* its bit will be 1. For released buttons their associated bits will be 0.
|
||||
*
|
||||
* The following defined mask values should be used for the buttons:
|
||||
*
|
||||
* LEFT_BUTTON, RIGHT_BUTTON, UP_BUTTON, DOWN_BUTTON, A_BUTTON, B_BUTTON
|
||||
*/
|
||||
uint8_t static buttonsState();
|
||||
|
||||
/** \brief
|
||||
* Paint 8 pixels vertically to the display.
|
||||
*
|
||||
* \param pixels A byte whose bits specify a vertical column of 8 pixels.
|
||||
*
|
||||
* \details
|
||||
* A byte representing a vertical column of 8 pixels is written to the
|
||||
* display at the current page and column address. The address is then
|
||||
* incremented. The page/column address will wrap to the start of the
|
||||
* display (the top left) when it increments past the end (lower right).
|
||||
*
|
||||
* The least significant bit represents the top pixel in the column.
|
||||
* A bit set to 1 is lit, 0 is unlit.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* X = lit pixels, . = unlit pixels
|
||||
*
|
||||
* blank() paint8Pixels() 0xFF, 0, 0xF0, 0, 0x0F
|
||||
* v TOP LEFT corner (8x9) v TOP LEFT corner
|
||||
* . . . . . . . . (page 1) X . . . X . . . (page 1)
|
||||
* . . . . . . . . X . . . X . . .
|
||||
* . . . . . . . . X . . . X . . .
|
||||
* . . . . . . . . X . . . X . . .
|
||||
* . . . . . . . . X . X . . . . .
|
||||
* . . . . . . . . X . X . . . . .
|
||||
* . . . . . . . . X . X . . . . .
|
||||
* . . . . . . . . (end of page 1) X . X . . . . . (end of page 1)
|
||||
* . . . . . . . . (page 2) . . . . . . . . (page 2)
|
||||
*/
|
||||
void static paint8Pixels(uint8_t pixels);
|
||||
|
||||
/** \brief
|
||||
* Paints an entire image directly to the display from program memory.
|
||||
*
|
||||
* \param image A byte array in program memory representing the entire
|
||||
* contents of the display.
|
||||
*
|
||||
* \details
|
||||
* The contents of the specified array in program memory is written to the
|
||||
* display. Each byte in the array represents a vertical column of 8 pixels
|
||||
* with the least significant bit at the top. The bytes are written starting
|
||||
* at the top left, progressing horizontally and wrapping at the end of each
|
||||
* row, to the bottom right. The size of the array must exactly match the
|
||||
* number of pixels in the entire display.
|
||||
*
|
||||
* \see paint8Pixels()
|
||||
*/
|
||||
void static paintScreen(const uint8_t *image);
|
||||
|
||||
/** \brief
|
||||
* Paints an entire image directly to the display from an array in RAM.
|
||||
*
|
||||
* \param image A byte array in RAM representing the entire contents of
|
||||
* the display.
|
||||
* \param clear If `true` the array in RAM will be cleared to zeros upon
|
||||
* return from this function. If `false` the RAM buffer will remain
|
||||
* unchanged. (optional; defaults to `false`)
|
||||
*
|
||||
* \details
|
||||
* The contents of the specified array in RAM is written to the display.
|
||||
* Each byte in the array represents a vertical column of 8 pixels with
|
||||
* the least significant bit at the top. The bytes are written starting
|
||||
* at the top left, progressing horizontally and wrapping at the end of
|
||||
* each row, to the bottom right. The size of the array must exactly
|
||||
* match the number of pixels in the entire display.
|
||||
*
|
||||
* If parameter `clear` is set to `true` the RAM array will be cleared to
|
||||
* zeros after its contents are written to the display.
|
||||
*
|
||||
* \see paint8Pixels()
|
||||
*/
|
||||
void static paintScreen(uint8_t image[], bool clear = false);
|
||||
|
||||
/** \brief
|
||||
* Blank the display screen by setting all pixels off.
|
||||
*
|
||||
* \details
|
||||
* All pixels on the screen will be written with a value of 0 to turn
|
||||
* them off.
|
||||
*/
|
||||
void static blank();
|
||||
|
||||
/** \brief
|
||||
* Invert the entire display or set it back to normal.
|
||||
*
|
||||
* \param inverse `true` will invert the display. `false` will set the
|
||||
* display to no-inverted.
|
||||
*
|
||||
* \details
|
||||
* Calling this function with a value of `true` will set the display to
|
||||
* inverted mode. A pixel with a value of 0 will be on and a pixel set to 1
|
||||
* will be off.
|
||||
*
|
||||
* Once in inverted mode, the display will remain this way
|
||||
* until it is set back to non-inverted mode by calling this function with
|
||||
* `false`.
|
||||
*/
|
||||
void static invert(bool inverse);
|
||||
|
||||
/** \brief
|
||||
* Turn all display pixels on or display the buffer contents.
|
||||
*
|
||||
* \param on `true` turns all pixels on. `false` displays the contents
|
||||
* of the hardware display buffer.
|
||||
*
|
||||
* \details
|
||||
* Calling this function with a value of `true` will override the contents
|
||||
* of the hardware display buffer and turn all pixels on. The contents of
|
||||
* the hardware buffer will remain unchanged.
|
||||
*
|
||||
* Calling this function with a value of `false` will set the normal state
|
||||
* of displaying the contents of the hardware display buffer.
|
||||
*
|
||||
* \note
|
||||
* All pixels will be lit even if the display is in inverted mode.
|
||||
*
|
||||
* \see invert()
|
||||
*/
|
||||
void static allPixelsOn(bool on);
|
||||
|
||||
/** \brief
|
||||
* Flip the display vertically or set it back to normal.
|
||||
*
|
||||
* \param flipped `true` will set vertical flip mode. `false` will set
|
||||
* normal vertical orientation.
|
||||
*
|
||||
* \details
|
||||
* Calling this function with a value of `true` will cause the Y coordinate
|
||||
* to start at the bottom edge of the display instead of the top,
|
||||
* effectively flipping the display vertically.
|
||||
*
|
||||
* Once in vertical flip mode, it will remain this way until normal
|
||||
* vertical mode is set by calling this function with a value of `false`.
|
||||
*
|
||||
* \see flipHorizontal()
|
||||
*/
|
||||
void static flipVertical(bool flipped);
|
||||
|
||||
/** \brief
|
||||
* Flip the display horizontally or set it back to normal.
|
||||
*
|
||||
* \param flipped `true` will set horizontal flip mode. `false` will set
|
||||
* normal horizontal orientation.
|
||||
*
|
||||
* \details
|
||||
* Calling this function with a value of `true` will cause the X coordinate
|
||||
* to start at the left edge of the display instead of the right,
|
||||
* effectively flipping the display horizontally.
|
||||
*
|
||||
* Once in horizontal flip mode, it will remain this way until normal
|
||||
* horizontal mode is set by calling this function with a value of `false`.
|
||||
*
|
||||
* \see flipVertical()
|
||||
*/
|
||||
void static flipHorizontal(bool flipped);
|
||||
|
||||
/** \brief
|
||||
* Send a single command byte to the display.
|
||||
*
|
||||
* \param command The command byte to send to the display.
|
||||
*
|
||||
* \details
|
||||
* The display will be set to command mode then the specified command
|
||||
* byte will be sent. The display will then be set to data mode.
|
||||
* Multi-byte commands can be sent by calling this function multiple times.
|
||||
*
|
||||
* \note
|
||||
* Sending improper commands to the display can place it into invalid or
|
||||
* unexpected states, possibly even causing physical damage.
|
||||
*/
|
||||
void static sendLCDCommand(uint8_t command);
|
||||
|
||||
/** \brief
|
||||
* Set the light output of the RGB LED.
|
||||
*
|
||||
* \param red,green,blue The brightness value for each LED.
|
||||
*
|
||||
* \details
|
||||
* The RGB LED is actually individual red, green and blue LEDs placed
|
||||
* very close together in a single package. By setting the brightness of
|
||||
* each LED, the RGB LED can show various colors and intensities.
|
||||
* The brightness of each LED can be set to a value from 0 (fully off)
|
||||
* to 255 (fully on).
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* Certain libraries that take control of the hardware timers may interfere
|
||||
* with the ability of this function to properly control the RGB LED.
|
||||
*_ArduboyPlaytune_ is one such library known to do this.
|
||||
* The digitalWriteRGB() function will still work properly in this case.
|
||||
* \endparblock
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* Many of the Kickstarter Arduboys were accidentally shipped with the
|
||||
* RGB LED installed incorrectly. For these units, the green LED cannot be
|
||||
* lit. As long as the green led is set to off, setting the red LED will
|
||||
* actually control the blue LED and setting the blue LED will actually
|
||||
* control the red LED. If the green LED is turned fully on, none of the
|
||||
* LEDs will light.
|
||||
* \endparblock
|
||||
*
|
||||
* \see setRGBled(uint8_t, uint8_t) digitalWriteRGB() freeRGBled()
|
||||
*/
|
||||
void static setRGBled(uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/** \brief
|
||||
* Set the brightness of one of the RGB LEDs without affecting the others.
|
||||
*
|
||||
* \param color The name of the LED to set. The value given should be one
|
||||
* of RED_LED, GREEN_LED or BLUE_LED.
|
||||
*
|
||||
* \param val The brightness value for the LED, from 0 to 255.
|
||||
*
|
||||
* \note
|
||||
* In order to use this function, the 3 parameter version must first be
|
||||
* called at least once, in order to initialize the hardware.
|
||||
*
|
||||
* \details
|
||||
* This 2 parameter version of the function will set the brightness of a
|
||||
* single LED within the RGB LED without affecting the current brightness
|
||||
* of the other two. See the description of the 3 parameter version of this
|
||||
* function for more details on the RGB LED.
|
||||
*
|
||||
* \see setRGBled(uint8_t, uint8_t, uint8_t) digitalWriteRGB() freeRGBled()
|
||||
*/
|
||||
void static setRGBled(uint8_t color, uint8_t val);
|
||||
|
||||
|
||||
/** \brief
|
||||
* Relinquish analog control of the RGB LED.
|
||||
*
|
||||
* \details
|
||||
* Using the RGB LED in analog mode prevents further use of the LED in
|
||||
* digital mode. This function will restore the pins used for the LED, so
|
||||
* it can be used in digital mode.
|
||||
*
|
||||
* \see digitalWriteRGB() setRGBled()
|
||||
*/
|
||||
void static freeRGBled();
|
||||
|
||||
/** \brief
|
||||
* Set the RGB LEDs digitally, to either fully on or fully off.
|
||||
*
|
||||
* \param red,green,blue Use value RGB_ON or RGB_OFF to set each LED.
|
||||
*
|
||||
* \details
|
||||
* The RGB LED is actually individual red, green and blue LEDs placed
|
||||
* very close together in a single package. This 3 parameter version of the
|
||||
* function will set each LED either on or off, to set the RGB LED to
|
||||
* 7 different colors at their highest brightness or turn it off.
|
||||
*
|
||||
* The colors are as follows:
|
||||
*
|
||||
* RED LED GREEN_LED BLUE_LED COLOR
|
||||
* ------- --------- -------- -----
|
||||
* RGB_OFF RGB_OFF RGB_OFF OFF
|
||||
* RGB_OFF RGB_OFF RGB_ON Blue
|
||||
* RGB_OFF RGB_ON RGB_OFF Green
|
||||
* RGB_OFF RGB_ON RGB_ON Cyan
|
||||
* RGB_ON RGB_OFF RGB_OFF Red
|
||||
* RGB_ON RGB_OFF RGB_ON Magenta
|
||||
* RGB_ON RGB_ON RGB_OFF Yellow
|
||||
* RGB_ON RGB_ON RGB_ON White
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* Using the RGB LED in analog mode will prevent digital control of the
|
||||
* LED. To restore the ability to control the LED digitally, use the
|
||||
* `freeRGBled()` function.
|
||||
* \endparblock
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* Many of the Kickstarter Arduboys were accidentally shipped with the
|
||||
* RGB LED installed incorrectly. For these units, the green LED cannot be
|
||||
* lit. As long as the green led is set to off, turning on the red LED will
|
||||
* actually light the blue LED and turning on the blue LED will actually
|
||||
* light the red LED. If the green LED is turned on, none of the LEDs
|
||||
* will light.
|
||||
* \endparblock
|
||||
*
|
||||
* \see digitalWriteRGB(uint8_t, uint8_t) setRGBled() freeRGBled()
|
||||
*/
|
||||
void static digitalWriteRGB(uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
/** \brief
|
||||
* Set one of the RGB LEDs digitally, to either fully on or fully off.
|
||||
*
|
||||
* \param color The name of the LED to set. The value given should be one
|
||||
* of RED_LED, GREEN_LED or BLUE_LED.
|
||||
*
|
||||
* \param val Indicates whether to turn the specified LED on or off.
|
||||
* The value given should be RGB_ON or RGB_OFF.
|
||||
*
|
||||
* \details
|
||||
* This 2 parameter version of the function will set a single LED within
|
||||
* the RGB LED either fully on or fully off. See the description of the
|
||||
* 3 parameter version of this function for more details on the RGB LED.
|
||||
*
|
||||
* \see digitalWriteRGB(uint8_t, uint8_t, uint8_t) setRGBled() freeRGBled()
|
||||
*/
|
||||
void static digitalWriteRGB(uint8_t color, uint8_t val);
|
||||
|
||||
/** \brief
|
||||
* Initialize the Arduboy's hardware.
|
||||
*
|
||||
* \details
|
||||
* This function initializes the display, buttons, etc.
|
||||
*
|
||||
* This function is called by begin() so isn't normally called within a
|
||||
* sketch. However, in order to free up some code space, by eliminating
|
||||
* some of the start up features, it can be called in place of begin().
|
||||
* The functions that begin() would call after boot() can then be called
|
||||
* to add back in some of the start up features, if desired.
|
||||
* See the README file or documentation on the main page for more details.
|
||||
*
|
||||
* \see Arduboy2Base::begin()
|
||||
*/
|
||||
void static boot();
|
||||
|
||||
/** \brief
|
||||
* Allow upload when the bootloader "magic number" could be corrupted.
|
||||
*
|
||||
* \details
|
||||
* If the UP button is held when this function is entered, the RGB LED
|
||||
* will be lit and timer 0 will be disabled, then the sketch will remain
|
||||
* in a tight loop. This is to address a problem with uploading a new
|
||||
* sketch, for sketches that interfere with the bootloader "magic number".
|
||||
* The problem occurs with certain sketches that use large amounts of RAM.
|
||||
*
|
||||
* This function should be called after `boot()` in sketches that
|
||||
* potentially could cause the problem.
|
||||
*
|
||||
* It is intended to replace the `flashlight()` function when more
|
||||
* program space is required. If possible, it is more desirable to use
|
||||
* `flashlight()`, so that the actual flashlight feature isn't lost.
|
||||
*
|
||||
* \see Arduboy2Base::flashlight() boot()
|
||||
*/
|
||||
void static safeMode();
|
||||
|
||||
/** \brief
|
||||
* Delay for the number of milliseconds, specified as a 16 bit value.
|
||||
*
|
||||
* \param ms The delay in milliseconds.
|
||||
*
|
||||
* \details
|
||||
* This function works the same as the Arduino `delay()` function except
|
||||
* the provided value is 16 bits long, so the maximum delay allowed is
|
||||
* 65535 milliseconds (about 65.5 seconds). Using this function instead
|
||||
* of Arduino `delay()` will save a few bytes of code.
|
||||
*/
|
||||
void static delayShort(uint16_t ms) __attribute__ ((noinline));
|
||||
|
||||
/** \brief
|
||||
* Exit the sketch and start the bootloader
|
||||
*
|
||||
* \details
|
||||
* The sketch will exit and the bootloader will be started in command mode.
|
||||
* The effect will be similar to pressing the reset button.
|
||||
*
|
||||
* This function is intended to be used to allow uploading a new sketch,
|
||||
* when the USB code has been removed to gain more code space.
|
||||
* Ideally, the sketch would present a "New Sketch Upload" menu or prompt
|
||||
* telling the user to "Press and hold the DOWN button when the procedure
|
||||
* to upload a new sketch has been initiated". The sketch would then wait
|
||||
* for the DOWN button to be pressed and then call this function.
|
||||
*
|
||||
* \see ARDUBOY_NO_USB
|
||||
*/
|
||||
void static exitToBootloader();
|
||||
|
||||
// Replacement main() that eliminates the USB stack code.
|
||||
// Used by the ARDUBOY_NO_USB macro. This should not be called
|
||||
// directly from a sketch.
|
||||
void static mainNoUSB();
|
||||
|
||||
protected:
|
||||
// internals
|
||||
void static setCPUSpeed8MHz();
|
||||
void static bootSPI();
|
||||
void static bootOLED();
|
||||
void static bootPins();
|
||||
void static bootPowerSaving();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,232 @@
|
|||
/**
|
||||
* @file Sprites.cpp
|
||||
* \brief
|
||||
* A class for drawing animated sprites from image and mask bitmaps.
|
||||
*/
|
||||
|
||||
#include "Sprites.h"
|
||||
|
||||
void Sprites::drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap,
|
||||
const uint8_t *mask, uint8_t frame, uint8_t mask_frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, mask, mask_frame, SPRITE_MASKED);
|
||||
}
|
||||
|
||||
void Sprites::drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_OVERWRITE);
|
||||
}
|
||||
|
||||
void Sprites::drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK_ERASE);
|
||||
}
|
||||
|
||||
void Sprites::drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK);
|
||||
}
|
||||
|
||||
void Sprites::drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_PLUS_MASK);
|
||||
}
|
||||
|
||||
|
||||
//common functions
|
||||
void Sprites::draw(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, uint8_t frame,
|
||||
const uint8_t *mask, uint8_t sprite_frame,
|
||||
uint8_t drawMode)
|
||||
{
|
||||
unsigned int frame_offset;
|
||||
|
||||
if (bitmap == NULL)
|
||||
return;
|
||||
|
||||
// uint8_t width = pgm_read_byte(bitmap);
|
||||
// uint8_t height = pgm_read_byte(++bitmap);
|
||||
// bitmap++;
|
||||
// if (frame > 0 || sprite_frame > 0) {
|
||||
// frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1)));
|
||||
// // sprite plus mask uses twice as much space for each frame
|
||||
// if (drawMode == SPRITE_PLUS_MASK) {
|
||||
// frame_offset *= 2;
|
||||
// } else if (mask != NULL) {
|
||||
// mask += sprite_frame * frame_offset;
|
||||
// }
|
||||
// bitmap += frame * frame_offset;
|
||||
// }
|
||||
// // if we're detecting the draw mode then base it on whether a mask
|
||||
// // was passed as a separate object
|
||||
// if (drawMode == SPRITE_AUTO_MODE) {
|
||||
// drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED;
|
||||
// }
|
||||
// assembly optimisation of above code saving 20(+) bytes
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
asm volatile(
|
||||
" lpm %[width], Z+ \n\t" // width = pgm_read_byte(bitmap++);
|
||||
" lpm %[height], Z+ \n\t" // height = pgm_read_byte(bitmap++);
|
||||
" cp %[frame], __zero_reg__ \n\t" // if (frame > 0 || sprite_frame > 0)
|
||||
" brne 1f \n\t"
|
||||
" cp %[spr_frame], __zero_reg__ \n\t"
|
||||
" breq 3f \n\t"
|
||||
"1: \n\t"
|
||||
" ldi r20, 7 \n\t" //rows = ((height+7)
|
||||
" add r20, %[height] \n\t"
|
||||
" ror r20 \n\t" //include carry for heights > 248
|
||||
" lsr r20 \n\t" //rows = (height+7) / 8
|
||||
" lsr r20 \n\t"
|
||||
" cpi %[mode], %[sprite_plus_mask] \n\t" //if (drawMode == SPRITE_PLUS_MASK) rows *= 2
|
||||
" brne 2f \n\t"
|
||||
" lsl r20 \n\t"
|
||||
"2: \n\t"
|
||||
" mul r20, %[width] \n\t" //frame offset = rows * width
|
||||
" movw r20, r0 \n\t"
|
||||
" mul %[frame] , r20 \n\t"
|
||||
" add %A[bitmap], r0 \n\t" //bitmap += frame * (frame offset & 0xFF)
|
||||
" adc %B[bitmap], r1 \n\t"
|
||||
" mul %[frame] , r21 \n\t" //bitmap += frame * (frame_offset >> 8 )) << 8
|
||||
" add %B[bitmap], r0 \n\t"
|
||||
" \n\t"
|
||||
" adiw %A[mask], 0 \n\t" //if (mask != NULL)
|
||||
" breq 3f \n\t"
|
||||
" \n\t"
|
||||
" mul %[spr_frame] , r20 \n\t"
|
||||
" add %A[mask], r0 \n\t" //mask += sprite_frame * (frame offset & 0xFF)
|
||||
" adc %B[mask], r1 \n\t"
|
||||
" mul %[spr_frame] , r21 \n\t" //mask += (sprite_frame * (frame_offset >> 8 )) << 8
|
||||
" add %B[mask], r0 \n\t"
|
||||
"3: \n\t"
|
||||
" clr __zero_reg__ \n\t"
|
||||
"4: \n\t"
|
||||
" cpi %[mode], %[sprite_auto_mode] \n\t" //if (drawMode == SPRITE_AUTO_MODE)
|
||||
" brne 5f \n\t"
|
||||
" adiw %A[mask], 0 \n\t" //if (mask = NULL) drawMode = SPRITE_UNMASKED
|
||||
" ldi %[mode], %[sprite_unmasked] \n\t"
|
||||
" breq 5f \n\t"
|
||||
" ldi %[mode], %[sprite_masked] \n\t" //else drawMode = SPRITE_PLUS_MASK
|
||||
"5: \n\t"
|
||||
: [width] "=&r" (width),
|
||||
[height] "=&r" (height),
|
||||
[mask] "+x" (mask),
|
||||
[bitmap] "+z" (bitmap),
|
||||
[mode] "+d" (drawMode)
|
||||
: [frame] "r" (frame),
|
||||
[spr_frame] "r" (sprite_frame),
|
||||
[sprite_plus_mask] "M" (SPRITE_PLUS_MASK),
|
||||
[sprite_auto_mode] "M" (SPRITE_AUTO_MODE),
|
||||
[sprite_unmasked] "M" (SPRITE_UNMASKED),
|
||||
[sprite_masked] "M" (SPRITE_MASKED)
|
||||
: "r20", "r21"
|
||||
);
|
||||
drawBitmap(x, y, bitmap, mask, width, height, drawMode);
|
||||
}
|
||||
|
||||
void Sprites::drawBitmap(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, const uint8_t *mask,
|
||||
uint8_t w, uint8_t h, uint8_t draw_mode)
|
||||
{
|
||||
// no need to draw at all if we're offscreen
|
||||
if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1)
|
||||
return;
|
||||
|
||||
if (bitmap == NULL)
|
||||
return;
|
||||
|
||||
// xOffset technically doesn't need to be 16 bit but the math operations
|
||||
// are measurably faster if it is
|
||||
uint16_t xOffset, ofs;
|
||||
int8_t yOffset = y & 7;
|
||||
int8_t sRow = y / 8;
|
||||
uint8_t loop_h, start_h, rendered_width;
|
||||
|
||||
if (y < 0 && yOffset > 0) {
|
||||
sRow--;
|
||||
}
|
||||
|
||||
// if the left side of the render is offscreen skip those loops
|
||||
if (x < 0) {
|
||||
xOffset = abs(x);
|
||||
} else {
|
||||
xOffset = 0;
|
||||
}
|
||||
|
||||
// if the right side of the render is offscreen skip those loops
|
||||
if (x + w > WIDTH - 1) {
|
||||
rendered_width = ((WIDTH - x) - xOffset);
|
||||
} else {
|
||||
rendered_width = (w - xOffset);
|
||||
}
|
||||
|
||||
// if the top side of the render is offscreen skip those loops
|
||||
if (sRow < -1) {
|
||||
start_h = abs(sRow) - 1;
|
||||
} else {
|
||||
start_h = 0;
|
||||
}
|
||||
|
||||
loop_h = h / 8 + (h % 8 > 0 ? 1 : 0); // divide, then round up
|
||||
|
||||
// if (sRow + loop_h - 1 > (HEIGHT/8)-1)
|
||||
if (sRow + loop_h > (HEIGHT / 8)) {
|
||||
loop_h = (HEIGHT / 8) - sRow;
|
||||
}
|
||||
|
||||
// prepare variables for loops later so we can compare with 0
|
||||
// instead of comparing two variables
|
||||
loop_h -= start_h;
|
||||
|
||||
sRow += start_h;
|
||||
ofs = (sRow * WIDTH) + x + xOffset;
|
||||
|
||||
uint8_t mul_amt = 1 << yOffset;
|
||||
uint16_t mask_data;
|
||||
uint16_t bitmap_data;
|
||||
|
||||
const uint8_t ofs_step = draw_mode == SPRITE_PLUS_MASK ? 2 : 1;
|
||||
const uint8_t ofs_stride = (w - rendered_width)*ofs_step;
|
||||
const uint16_t initial_bofs = ((start_h * w) + xOffset)*ofs_step;
|
||||
|
||||
const uint8_t *bofs = bitmap + initial_bofs;
|
||||
const uint8_t *mask_ofs = !mask ? bitmap : mask;
|
||||
mask_ofs += initial_bofs + ofs_step - 1;
|
||||
|
||||
for (uint8_t a = 0; a < loop_h; a++) {
|
||||
for (uint8_t iCol = 0; iCol < rendered_width; iCol++) {
|
||||
uint8_t data;
|
||||
|
||||
bitmap_data = pgm_read_byte(bofs) * mul_amt;
|
||||
mask_data = ~bitmap_data;
|
||||
|
||||
if (draw_mode == SPRITE_UNMASKED) {
|
||||
mask_data = ~(0xFF * mul_amt);
|
||||
} else if (draw_mode == SPRITE_IS_MASK_ERASE) {
|
||||
bitmap_data = 0;
|
||||
} else {
|
||||
mask_data = ~(pgm_read_byte(mask_ofs) * mul_amt);
|
||||
}
|
||||
|
||||
if (sRow >= 0) {
|
||||
data = Arduboy2Base::sBuffer[ofs];
|
||||
data &= (uint8_t)(mask_data);
|
||||
data |= (uint8_t)(bitmap_data);
|
||||
Arduboy2Base::sBuffer[ofs] = data;
|
||||
}
|
||||
if (yOffset != 0 && sRow < (HEIGHT / 8 - 1)) {
|
||||
data = Arduboy2Base::sBuffer[ofs + WIDTH];
|
||||
data &= (*((unsigned char *) (&mask_data) + 1));
|
||||
data |= (*((unsigned char *) (&bitmap_data) + 1));
|
||||
Arduboy2Base::sBuffer[ofs + WIDTH] = data;
|
||||
}
|
||||
ofs++;
|
||||
mask_ofs += ofs_step;
|
||||
bofs += ofs_step;
|
||||
}
|
||||
sRow++;
|
||||
bofs += ofs_stride;
|
||||
mask_ofs += ofs_stride;
|
||||
ofs += WIDTH - rendered_width;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
/**
|
||||
* @file Sprites.h
|
||||
* \brief
|
||||
* A class for drawing animated sprites from image and mask bitmaps.
|
||||
*/
|
||||
|
||||
#ifndef Sprites_h
|
||||
#define Sprites_h
|
||||
|
||||
#include "Arduboy2.h"
|
||||
#include "SpritesCommon.h"
|
||||
|
||||
/** \brief
|
||||
* A class for drawing animated sprites from image and mask bitmaps.
|
||||
*
|
||||
* \details
|
||||
* The functions in this class will draw to the screen buffer an image
|
||||
* contained in an array located in program memory. A mask can also be
|
||||
* specified or implied, which dictates how existing pixels in the buffer,
|
||||
* within the image boundaries, will be affected.
|
||||
*
|
||||
* A sprite or mask array contains one or more "frames". Each frame is intended
|
||||
* to show whatever the sprite represents in a different position, such as the
|
||||
* various poses for a running or jumping character. By specifying a different
|
||||
* frame each time the sprite is drawn, it can be animated.
|
||||
*
|
||||
* Each image array begins with values for the width and height of the sprite,
|
||||
* in pixels. The width can be any value. The height must be a multiple of
|
||||
* 8 pixels, but with proper masking, a sprite of any height can be created.
|
||||
*
|
||||
* For a separate mask array, as is used with `drawExternalMask()`, the width
|
||||
* and height are not included but must contain data of the same dimensions
|
||||
* as the corresponding image array.
|
||||
*
|
||||
* Following the width and height values for an image array, or from the
|
||||
* beginning of a separate mask array, the array contains the image and/or
|
||||
* mask data for each frame. Each byte represents a vertical column of 8 pixels
|
||||
* with the least significant bit (bit 0) at the top. The bytes are drawn as
|
||||
* 8 pixel high rows from left to right, top to bottom. When the end of a row
|
||||
* is reached, as specified by the width value, the next byte in the array will
|
||||
* be the start of the next row.
|
||||
*
|
||||
* Data for each frame after the first one immediately follows the previous
|
||||
* frame. Frame numbers start at 0.
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* A separate `SpritesB` class is available as an alternative to this class.
|
||||
* The only difference is that the `SpritesB` class is optimized for small
|
||||
* code size rather than for execution speed. One or the other can be used
|
||||
* depending on whether size or speed is more important.
|
||||
*
|
||||
* Even if the speed is acceptable when using `SpritesB`, you should still try
|
||||
* using `Sprites`. In some cases `Sprites` will produce less code than
|
||||
* `SpritesB`, notably when only one of the functions is used.
|
||||
*
|
||||
* You can easily switch between using the `Sprites` class or the `SpritesB`
|
||||
* class by using one or the other to create an object instance:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* Sprites sprites; // Use this to optimize for execution speed
|
||||
* SpritesB sprites; // Use this to (likely) optimize for code size
|
||||
* \endcode
|
||||
* \endparblock
|
||||
*
|
||||
* \note
|
||||
* \parblock
|
||||
* In the example patterns given in each Sprites function description,
|
||||
* a # character represents a bit set to 1 and
|
||||
* a - character represents a bit set to 0.
|
||||
* \endparblock
|
||||
*
|
||||
* \see SpritesB
|
||||
*/
|
||||
class Sprites
|
||||
{
|
||||
public:
|
||||
/** \brief
|
||||
* Draw a sprite using a separate image and mask array.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param mask A pointer to the array containing the mask frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
* \param mask_frame The frame number for the mask to use (can be different
|
||||
* from the image frame number).
|
||||
*
|
||||
* \details
|
||||
* An array containing the image frames, and another array containing
|
||||
* corresponding mask frames, are used to draw a sprite.
|
||||
*
|
||||
* Bits set to 1 in the mask indicate that the pixel will be set to the
|
||||
* value of the corresponding image bit. Bits set to 0 in the mask will be
|
||||
* left unchanged.
|
||||
*
|
||||
* image mask before after (# = 1, - = 0)
|
||||
*
|
||||
* ----- -###- ----- -----
|
||||
* --#-- ##### ----- --#--
|
||||
* ##-## ##-## ----- ##-##
|
||||
* --#-- ##### ----- --#--
|
||||
* ----- -###- ----- -----
|
||||
*
|
||||
* image mask before after
|
||||
*
|
||||
* ----- -###- ##### #---#
|
||||
* --#-- ##### ##### --#--
|
||||
* ##-## ##### ##### ##-##
|
||||
* --#-- ##### ##### --#--
|
||||
* ----- -###- ##### #---#
|
||||
*/
|
||||
static void drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap,
|
||||
const uint8_t *mask, uint8_t frame, uint8_t mask_frame);
|
||||
|
||||
/** \brief
|
||||
* Draw a sprite using an array containing both image and mask values.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image/mask frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
*
|
||||
* \details
|
||||
* An array containing combined image and mask data is used to draw a
|
||||
* sprite. Bytes are given in pairs with the first byte representing the
|
||||
* image pixels and the second byte specifying the corresponding mask.
|
||||
* The width given in the array still specifies the image width, so each
|
||||
* row of image and mask bytes will be twice the width value.
|
||||
*
|
||||
* Bits set to 1 in the mask indicate that the pixel will be set to the
|
||||
* value of the corresponding image bit. Bits set to 0 in the mask will be
|
||||
* left unchanged.
|
||||
*
|
||||
* image mask before after (# = 1, - = 0)
|
||||
*
|
||||
* ----- -###- ----- -----
|
||||
* --#-- ##### ----- --#--
|
||||
* ##-## ##-## ----- ##-##
|
||||
* --#-- ##### ----- --#--
|
||||
* ----- -###- ----- -----
|
||||
*
|
||||
* image mask before after
|
||||
*
|
||||
* ----- -###- ##### #---#
|
||||
* --#-- ##### ##### --#--
|
||||
* ##-## ##### ##### ##-##
|
||||
* --#-- ##### ##### --#--
|
||||
* ----- -###- ##### #---#
|
||||
*/
|
||||
static void drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
/** \brief
|
||||
* Draw a sprite by replacing the existing content completely.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
*
|
||||
* \details
|
||||
* A sprite is drawn by overwriting the pixels in the buffer with the data
|
||||
* from the specified frame in the array. No masking is done. A bit set
|
||||
* to 1 in the frame will set the pixel to 1 in the buffer, and a 0 in the
|
||||
* array will set a 0 in the buffer.
|
||||
*
|
||||
* image before after (# = 1, - = 0)
|
||||
*
|
||||
* ----- ----- -----
|
||||
* --#-- ----- --#--
|
||||
* ##-## ----- ##-##
|
||||
* --#-- ----- --#--
|
||||
* ----- ----- -----
|
||||
*
|
||||
* image before after
|
||||
*
|
||||
* ----- ##### -----
|
||||
* --#-- ##### --#--
|
||||
* ##-## ##### ##-##
|
||||
* --#-- ##### --#--
|
||||
* ----- ##### -----
|
||||
*/
|
||||
static void drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
/** \brief
|
||||
* "Erase" a sprite.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param frame The frame number of the image to erase.
|
||||
*
|
||||
* \details
|
||||
* The data from the specified frame in the array is used to erase a
|
||||
* sprite. To "erase" a sprite, bits set to 1 in the frame will set the
|
||||
* corresponding pixel in the buffer to 0. Frame bits set to 0 will remain
|
||||
* unchanged in the buffer.
|
||||
*
|
||||
* image before after (# = 1, - = 0)
|
||||
*
|
||||
* ----- ----- -----
|
||||
* --#-- ----- -----
|
||||
* ##-## ----- -----
|
||||
* --#-- ----- -----
|
||||
* ----- ----- -----
|
||||
*
|
||||
* image before after
|
||||
*
|
||||
* ----- ##### #####
|
||||
* --#-- ##### ##-##
|
||||
* ##-## ##### --#--
|
||||
* --#-- ##### ##-##
|
||||
* ----- ##### #####
|
||||
*/
|
||||
static void drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
/** \brief
|
||||
* Draw a sprite using only the bits set to 1.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
*
|
||||
* \details
|
||||
* Bits set to 1 in the frame will be used to draw the sprite by setting
|
||||
* the corresponding pixel in the buffer to 1. Bits set to 0 in the frame
|
||||
* will remain unchanged in the buffer.
|
||||
*
|
||||
* image before after (# = 1, - = 0)
|
||||
*
|
||||
* ----- ----- -----
|
||||
* --#-- ----- --#--
|
||||
* ##-## ----- ##-##
|
||||
* --#-- ----- --#--
|
||||
* ----- ----- -----
|
||||
*
|
||||
* image before after
|
||||
*
|
||||
* ----- ##### ##### (no change because all pixels were
|
||||
* --#-- ##### ##### already white)
|
||||
* ##-## ##### #####
|
||||
* --#-- ##### #####
|
||||
* ----- ##### #####
|
||||
*/
|
||||
static void drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
// Master function. Needs to be abstracted into separate function for
|
||||
// every render type.
|
||||
// (Not officially part of the API)
|
||||
static void draw(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, uint8_t frame,
|
||||
const uint8_t *mask, uint8_t sprite_frame,
|
||||
uint8_t drawMode);
|
||||
|
||||
// (Not officially part of the API)
|
||||
static void drawBitmap(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, const uint8_t *mask,
|
||||
uint8_t w, uint8_t h, uint8_t draw_mode);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
* @file SpritesB.cpp
|
||||
* \brief
|
||||
* A class for drawing animated sprites from image and mask bitmaps.
|
||||
* Optimized for small code size.
|
||||
*/
|
||||
|
||||
#include "SpritesB.h"
|
||||
|
||||
void SpritesB::drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap,
|
||||
const uint8_t *mask, uint8_t frame, uint8_t mask_frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, mask, mask_frame, SPRITE_MASKED);
|
||||
}
|
||||
|
||||
void SpritesB::drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_OVERWRITE);
|
||||
}
|
||||
|
||||
void SpritesB::drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK_ERASE);
|
||||
}
|
||||
|
||||
void SpritesB::drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK);
|
||||
}
|
||||
|
||||
void SpritesB::drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
|
||||
{
|
||||
draw(x, y, bitmap, frame, NULL, 0, SPRITE_PLUS_MASK);
|
||||
}
|
||||
|
||||
|
||||
//common functions
|
||||
void SpritesB::draw(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, uint8_t frame,
|
||||
const uint8_t *mask, uint8_t sprite_frame,
|
||||
uint8_t drawMode)
|
||||
{
|
||||
unsigned int frame_offset;
|
||||
|
||||
if (bitmap == NULL)
|
||||
return;
|
||||
|
||||
uint8_t width = pgm_read_byte(bitmap);
|
||||
uint8_t height = pgm_read_byte(++bitmap);
|
||||
bitmap++;
|
||||
if (frame > 0 || sprite_frame > 0) {
|
||||
frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1)));
|
||||
// sprite plus mask uses twice as much space for each frame
|
||||
if (drawMode == SPRITE_PLUS_MASK) {
|
||||
frame_offset *= 2;
|
||||
} else if (mask != NULL) {
|
||||
mask += sprite_frame * frame_offset;
|
||||
}
|
||||
bitmap += frame * frame_offset;
|
||||
}
|
||||
|
||||
// if we're detecting the draw mode then base it on whether a mask
|
||||
// was passed as a separate object
|
||||
if (drawMode == SPRITE_AUTO_MODE) {
|
||||
drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED;
|
||||
}
|
||||
|
||||
drawBitmap(x, y, bitmap, mask, width, height, drawMode);
|
||||
}
|
||||
|
||||
void SpritesB::drawBitmap(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, const uint8_t *mask,
|
||||
uint8_t w, uint8_t h, uint8_t draw_mode)
|
||||
{
|
||||
// no need to draw at all of we're offscreen
|
||||
if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1)
|
||||
return;
|
||||
|
||||
if (bitmap == NULL)
|
||||
return;
|
||||
|
||||
// xOffset technically doesn't need to be 16 bit but the math operations
|
||||
// are measurably faster if it is
|
||||
uint16_t xOffset, ofs;
|
||||
int8_t yOffset = y & 7;
|
||||
int8_t sRow = y / 8;
|
||||
uint8_t loop_h, start_h, rendered_width;
|
||||
|
||||
if (y < 0 && yOffset > 0) {
|
||||
sRow--;
|
||||
}
|
||||
|
||||
// if the left side of the render is offscreen skip those loops
|
||||
if (x < 0) {
|
||||
xOffset = abs(x);
|
||||
} else {
|
||||
xOffset = 0;
|
||||
}
|
||||
|
||||
// if the right side of the render is offscreen skip those loops
|
||||
if (x + w > WIDTH - 1) {
|
||||
rendered_width = ((WIDTH - x) - xOffset);
|
||||
} else {
|
||||
rendered_width = (w - xOffset);
|
||||
}
|
||||
|
||||
// if the top side of the render is offscreen skip those loops
|
||||
if (sRow < -1) {
|
||||
start_h = abs(sRow) - 1;
|
||||
} else {
|
||||
start_h = 0;
|
||||
}
|
||||
|
||||
loop_h = h / 8 + (h % 8 > 0 ? 1 : 0); // divide, then round up
|
||||
|
||||
// if (sRow + loop_h - 1 > (HEIGHT/8)-1)
|
||||
if (sRow + loop_h > (HEIGHT / 8)) {
|
||||
loop_h = (HEIGHT / 8) - sRow;
|
||||
}
|
||||
|
||||
// prepare variables for loops later so we can compare with 0
|
||||
// instead of comparing two variables
|
||||
loop_h -= start_h;
|
||||
|
||||
sRow += start_h;
|
||||
ofs = (sRow * WIDTH) + x + xOffset;
|
||||
|
||||
uint8_t mul_amt = 1 << yOffset;
|
||||
uint16_t mask_data;
|
||||
uint16_t bitmap_data;
|
||||
|
||||
const uint8_t ofs_step = draw_mode == SPRITE_PLUS_MASK ? 2 : 1;
|
||||
const uint8_t ofs_stride = (w - rendered_width)*ofs_step;
|
||||
const uint16_t initial_bofs = ((start_h * w) + xOffset)*ofs_step;
|
||||
|
||||
const uint8_t *bofs = bitmap + initial_bofs;
|
||||
const uint8_t *mask_ofs = !mask ? bitmap : mask;
|
||||
mask_ofs += initial_bofs + ofs_step - 1;
|
||||
|
||||
for (uint8_t a = 0; a < loop_h; a++) {
|
||||
for (uint8_t iCol = 0; iCol < rendered_width; iCol++) {
|
||||
uint8_t data;
|
||||
|
||||
bitmap_data = pgm_read_byte(bofs) * mul_amt;
|
||||
mask_data = ~bitmap_data;
|
||||
|
||||
if (draw_mode == SPRITE_UNMASKED) {
|
||||
mask_data = ~(0xFF * mul_amt);
|
||||
} else if (draw_mode == SPRITE_IS_MASK_ERASE) {
|
||||
bitmap_data = 0;
|
||||
} else {
|
||||
mask_data = ~(pgm_read_byte(mask_ofs) * mul_amt);
|
||||
}
|
||||
|
||||
if (sRow >= 0) {
|
||||
data = Arduboy2Base::sBuffer[ofs];
|
||||
data &= (uint8_t)(mask_data);
|
||||
data |= (uint8_t)(bitmap_data);
|
||||
Arduboy2Base::sBuffer[ofs] = data;
|
||||
}
|
||||
if (yOffset != 0 && sRow < 7) {
|
||||
data = Arduboy2Base::sBuffer[ofs + WIDTH];
|
||||
data &= (*((unsigned char *) (&mask_data) + 1));
|
||||
data |= (*((unsigned char *) (&bitmap_data) + 1));
|
||||
Arduboy2Base::sBuffer[ofs + WIDTH] = data;
|
||||
}
|
||||
ofs++;
|
||||
mask_ofs += ofs_step;
|
||||
bofs += ofs_step;
|
||||
}
|
||||
sRow++;
|
||||
bofs += ofs_stride;
|
||||
mask_ofs += ofs_stride;
|
||||
ofs += WIDTH - rendered_width;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
* @file SpritesB.h
|
||||
* \brief
|
||||
* A class for drawing animated sprites from image and mask bitmaps.
|
||||
* Optimized for small code size.
|
||||
*/
|
||||
|
||||
#ifndef SpritesB_h
|
||||
#define SpritesB_h
|
||||
|
||||
#include "Arduboy2.h"
|
||||
#include "SpritesCommon.h"
|
||||
|
||||
/** \brief
|
||||
* A class for drawing animated sprites from image and mask bitmaps.
|
||||
* Optimized for small code size.
|
||||
*
|
||||
* \details
|
||||
* The functions in this class are identical to the `Sprites` class. The only
|
||||
* difference is that the functions in this class are optimized for smaller
|
||||
* code size rather than execution speed.
|
||||
*
|
||||
* See the `Sprites` class documentation for details on the use of the
|
||||
* functions in this class.
|
||||
*
|
||||
* Even if the speed is acceptable when using `SpritesB`, you should still try
|
||||
* using `Sprites`. In some cases `Sprites` will produce less code than
|
||||
* `SpritesB`, notably when only one of the functions is used.
|
||||
*
|
||||
* You can easily switch between using the `Sprites` class or the `SpritesB`
|
||||
* class by using one or the other to create an object instance:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* Sprites sprites; // Use this to optimize for execution speed
|
||||
* SpritesB sprites; // Use this to (likely) optimize for code size
|
||||
* \endcode
|
||||
*
|
||||
* \see Sprites
|
||||
*/
|
||||
class SpritesB
|
||||
{
|
||||
public:
|
||||
/** \brief
|
||||
* Draw a sprite using a separate image and mask array.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param mask A pointer to the array containing the mask frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
* \param mask_frame The frame number for the mask to use (can be different
|
||||
* from the image frame number).
|
||||
*
|
||||
* \see Sprites::drawExternalMask()
|
||||
*/
|
||||
static void drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap,
|
||||
const uint8_t *mask, uint8_t frame, uint8_t mask_frame);
|
||||
|
||||
/** \brief
|
||||
* Draw a sprite using an array containing both image and mask values.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image/mask frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
*
|
||||
* \see Sprites::drawPlusMask()
|
||||
*/
|
||||
static void drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
/** \brief
|
||||
* Draw a sprite by replacing the existing content completely.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
*
|
||||
* \see Sprites::drawOverwrite()
|
||||
*/
|
||||
static void drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
/** \brief
|
||||
* "Erase" a sprite.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param frame The frame number of the image to erase.
|
||||
*
|
||||
* \see Sprites::drawErase()
|
||||
*/
|
||||
static void drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
/** \brief
|
||||
* Draw a sprite using only the bits set to 1.
|
||||
*
|
||||
* \param x,y The coordinates of the top left pixel location.
|
||||
* \param bitmap A pointer to the array containing the image frames.
|
||||
* \param frame The frame number of the image to draw.
|
||||
*
|
||||
* \see Sprites::drawSelfMasked()
|
||||
*/
|
||||
static void drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);
|
||||
|
||||
// Master function. Needs to be abstracted into separate function for
|
||||
// every render type.
|
||||
// (Not officially part of the API)
|
||||
static void draw(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, uint8_t frame,
|
||||
const uint8_t *mask, uint8_t sprite_frame,
|
||||
uint8_t drawMode);
|
||||
|
||||
// (Not officially part of the API)
|
||||
static void drawBitmap(int16_t x, int16_t y,
|
||||
const uint8_t *bitmap, const uint8_t *mask,
|
||||
uint8_t w, uint8_t h, uint8_t draw_mode);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* @file SpritesCommon.h
|
||||
* \brief
|
||||
* Common header file for sprite functions
|
||||
*/
|
||||
|
||||
#ifndef SpritesCommon_h
|
||||
#define SpritesCommon_h
|
||||
|
||||
#define SPRITE_MASKED 1
|
||||
#define SPRITE_UNMASKED 2
|
||||
#define SPRITE_OVERWRITE 2
|
||||
#define SPRITE_PLUS_MASK 3
|
||||
#define SPRITE_IS_MASK 250
|
||||
#define SPRITE_IS_MASK_ERASE 251
|
||||
#define SPRITE_AUTO_MODE 255
|
||||
|
||||
#endif
|
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* @file ab_logo.c
|
||||
* \brief
|
||||
* The ARDUBOY logo bitmap.
|
||||
*/
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#ifndef ARDUBOY_LOGO_CREATED
|
||||
#define ARDUBOY_LOGO_CREATED
|
||||
|
||||
// arduboy_logo.png
|
||||
// drawBitmap() format
|
||||
// 88x16
|
||||
const uint8_t arduboy_logo[] PROGMEM = {
|
||||
0xF0, 0xF8, 0x9C, 0x8E, 0x87, 0x83, 0x87, 0x8E, 0x9C, 0xF8,
|
||||
0xF0, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFE, 0xFF, 0x83, 0x83, 0x83, 0x83, 0x83, 0xC7,
|
||||
0xEE, 0x7C, 0x38, 0x00, 0x00, 0xF8, 0xFC, 0x0E, 0x07, 0x03,
|
||||
0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0x3F, 0x7F,
|
||||
0xE0, 0xC0, 0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x3F, 0xFF, 0xFF,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x3E, 0x77,
|
||||
0xE3, 0xC1, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x3F, 0x70,
|
||||
0xE0, 0xC0, 0xC0, 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00,
|
||||
0x7F, 0xFF, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xE3, 0x77, 0x3E,
|
||||
0x1C, 0x00, 0x00, 0x1F, 0x3F, 0x70, 0xE0, 0xC0, 0xC0, 0xC0,
|
||||
0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// arduboy_logo.png
|
||||
// drawCompressed() format
|
||||
// 88x16
|
||||
const uint8_t arduboy_logo_compressed[] PROGMEM = {
|
||||
0x57, 0x0F, 0x9C, 0x53, 0x72, 0x75, 0x29, 0xE5, 0x9C, 0x92,
|
||||
0xCE, 0x95, 0x52, 0xAD, 0x4E, 0x49, 0xE7, 0x08, 0x09, 0xED,
|
||||
0x76, 0xBB, 0xDD, 0x2A, 0xAB, 0xAC, 0x55, 0x92, 0x90, 0xD0,
|
||||
0x6E, 0xB7, 0xDB, 0xAD, 0xB2, 0xCA, 0x5A, 0x25, 0xF9, 0xF8,
|
||||
0xF0, 0xC6, 0x47, 0x48, 0x28, 0x95, 0x54, 0x52, 0x49, 0x25,
|
||||
0x9D, 0x3A, 0x95, 0x5A, 0x3A, 0x45, 0x2A, 0xB7, 0x29, 0xA7,
|
||||
0xE4, 0x76, 0xBB, 0x55, 0x56, 0x59, 0xAB, 0x24, 0x9F, 0x5D,
|
||||
0x5B, 0x65, 0xD7, 0xE9, 0xEC, 0x92, 0x29, 0x3B, 0xA1, 0x4E,
|
||||
0xA7, 0xD3, 0xE9, 0x74, 0x9A, 0x8F, 0x8F, 0xEF, 0xED, 0x76,
|
||||
0xBB, 0x55, 0x4E, 0xAE, 0x52, 0xAD, 0x9C, 0x9C, 0x4F, 0xE7,
|
||||
0xED, 0x76, 0xBB, 0xDD, 0x2E, 0x95, 0x53, 0xD9, 0x25, 0xA5,
|
||||
0x54, 0xD6, 0x2A, 0xAB, 0xEC, 0x76, 0xBB, 0x54, 0x4E, 0x65,
|
||||
0x97, 0x94, 0x3A, 0x22, 0xA9, 0xA4, 0x92, 0x4A, 0x2A, 0xE9,
|
||||
0x94, 0x4D, 0x2D, 0x9D, 0xA2, 0x94, 0xCA, 0x5A, 0x65, 0x95,
|
||||
0xDD, 0x6E, 0x97, 0xCA, 0xA9, 0xEC, 0x12, 0x55, 0x69, 0x42,
|
||||
0x7A
|
||||
};
|
||||
|
||||
// arduboy_logo.png
|
||||
// Sprites::drawSelfMasked() format
|
||||
// 88x16
|
||||
const uint8_t arduboy_logo_sprite[] PROGMEM = {
|
||||
88, 16,
|
||||
0xF0, 0xF8, 0x9C, 0x8E, 0x87, 0x83, 0x87, 0x8E, 0x9C, 0xF8,
|
||||
0xF0, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFE, 0xFF, 0x83, 0x83, 0x83, 0x83, 0x83, 0xC7,
|
||||
0xEE, 0x7C, 0x38, 0x00, 0x00, 0xF8, 0xFC, 0x0E, 0x07, 0x03,
|
||||
0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0x3F, 0x7F,
|
||||
0xE0, 0xC0, 0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x3F, 0xFF, 0xFF,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x3E, 0x77,
|
||||
0xE3, 0xC1, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x3F, 0x70,
|
||||
0xE0, 0xC0, 0xC0, 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00,
|
||||
0x7F, 0xFF, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xE3, 0x77, 0x3E,
|
||||
0x1C, 0x00, 0x00, 0x1F, 0x3F, 0x70, 0xE0, 0xC0, 0xC0, 0xC0,
|
||||
0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,274 @@
|
|||
/**
|
||||
* @file glcdfont.c
|
||||
* \brief
|
||||
* The font definitions used to display text characters.
|
||||
*/
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#ifndef FONT5X7_H
|
||||
#define FONT5X7_H
|
||||
|
||||
// standard ascii 5x7 font
|
||||
static const unsigned char font[] PROGMEM =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
|
||||
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
|
||||
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
|
||||
0x18, 0x3C, 0x7E, 0x3C, 0x18,
|
||||
0x1C, 0x57, 0x7D, 0x57, 0x1C,
|
||||
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
|
||||
0x00, 0x18, 0x3C, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
|
||||
0x00, 0x18, 0x24, 0x18, 0x00,
|
||||
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
|
||||
0x30, 0x48, 0x3A, 0x06, 0x0E,
|
||||
0x26, 0x29, 0x79, 0x29, 0x26,
|
||||
0x40, 0x7F, 0x05, 0x05, 0x07,
|
||||
0x40, 0x7F, 0x05, 0x25, 0x3F,
|
||||
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
|
||||
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
|
||||
0x14, 0x22, 0x7F, 0x22, 0x14,
|
||||
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
|
||||
0x06, 0x09, 0x7F, 0x01, 0x7F,
|
||||
0x00, 0x66, 0x89, 0x95, 0x6A,
|
||||
0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x94, 0xA2, 0xFF, 0xA2, 0x94,
|
||||
0x08, 0x04, 0x7E, 0x04, 0x08,
|
||||
0x10, 0x20, 0x7E, 0x20, 0x10,
|
||||
0x08, 0x08, 0x2A, 0x1C, 0x08,
|
||||
0x08, 0x1C, 0x2A, 0x08, 0x08,
|
||||
0x1E, 0x10, 0x10, 0x10, 0x10,
|
||||
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
|
||||
0x30, 0x38, 0x3E, 0x38, 0x30,
|
||||
0x06, 0x0E, 0x3E, 0x0E, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x5F, 0x00, 0x00,
|
||||
0x00, 0x07, 0x00, 0x07, 0x00,
|
||||
0x14, 0x7F, 0x14, 0x7F, 0x14,
|
||||
0x24, 0x2A, 0x7F, 0x2A, 0x12,
|
||||
0x23, 0x13, 0x08, 0x64, 0x62,
|
||||
0x36, 0x49, 0x56, 0x20, 0x50,
|
||||
0x00, 0x08, 0x07, 0x03, 0x00,
|
||||
0x00, 0x1C, 0x22, 0x41, 0x00,
|
||||
0x00, 0x41, 0x22, 0x1C, 0x00,
|
||||
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
|
||||
0x08, 0x08, 0x3E, 0x08, 0x08,
|
||||
0x00, 0x80, 0x70, 0x30, 0x00,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x60, 0x60, 0x00,
|
||||
0x20, 0x10, 0x08, 0x04, 0x02,
|
||||
0x3E, 0x51, 0x49, 0x45, 0x3E,
|
||||
0x00, 0x42, 0x7F, 0x40, 0x00,
|
||||
0x72, 0x49, 0x49, 0x49, 0x46,
|
||||
0x21, 0x41, 0x49, 0x4D, 0x33,
|
||||
0x18, 0x14, 0x12, 0x7F, 0x10,
|
||||
0x27, 0x45, 0x45, 0x45, 0x39,
|
||||
0x3C, 0x4A, 0x49, 0x49, 0x31,
|
||||
0x41, 0x21, 0x11, 0x09, 0x07,
|
||||
0x36, 0x49, 0x49, 0x49, 0x36,
|
||||
0x46, 0x49, 0x49, 0x29, 0x1E,
|
||||
0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x00, 0x40, 0x34, 0x00, 0x00,
|
||||
0x00, 0x08, 0x14, 0x22, 0x41,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x00, 0x41, 0x22, 0x14, 0x08,
|
||||
0x02, 0x01, 0x59, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x5D, 0x59, 0x4E,
|
||||
0x7C, 0x12, 0x11, 0x12, 0x7C,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x36,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x22,
|
||||
0x7F, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x49, 0x49, 0x49, 0x41,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x01,
|
||||
0x3E, 0x41, 0x41, 0x51, 0x73,
|
||||
0x7F, 0x08, 0x08, 0x08, 0x7F,
|
||||
0x00, 0x41, 0x7F, 0x41, 0x00,
|
||||
0x20, 0x40, 0x41, 0x3F, 0x01,
|
||||
0x7F, 0x08, 0x14, 0x22, 0x41,
|
||||
0x7F, 0x40, 0x40, 0x40, 0x40,
|
||||
0x7F, 0x02, 0x1C, 0x02, 0x7F,
|
||||
0x7F, 0x04, 0x08, 0x10, 0x7F,
|
||||
0x3E, 0x41, 0x41, 0x41, 0x3E,
|
||||
0x7F, 0x09, 0x09, 0x09, 0x06,
|
||||
0x3E, 0x41, 0x51, 0x21, 0x5E,
|
||||
0x7F, 0x09, 0x19, 0x29, 0x46,
|
||||
0x26, 0x49, 0x49, 0x49, 0x32,
|
||||
0x03, 0x01, 0x7F, 0x01, 0x03,
|
||||
0x3F, 0x40, 0x40, 0x40, 0x3F,
|
||||
0x1F, 0x20, 0x40, 0x20, 0x1F,
|
||||
0x3F, 0x40, 0x38, 0x40, 0x3F,
|
||||
0x63, 0x14, 0x08, 0x14, 0x63,
|
||||
0x03, 0x04, 0x78, 0x04, 0x03,
|
||||
0x61, 0x59, 0x49, 0x4D, 0x43,
|
||||
0x00, 0x7F, 0x41, 0x41, 0x41,
|
||||
0x02, 0x04, 0x08, 0x10, 0x20,
|
||||
0x00, 0x41, 0x41, 0x41, 0x7F,
|
||||
0x04, 0x02, 0x01, 0x02, 0x04,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x00, 0x03, 0x07, 0x08, 0x00,
|
||||
0x20, 0x54, 0x54, 0x78, 0x40,
|
||||
0x7F, 0x28, 0x44, 0x44, 0x38,
|
||||
0x38, 0x44, 0x44, 0x44, 0x28,
|
||||
0x38, 0x44, 0x44, 0x28, 0x7F,
|
||||
0x38, 0x54, 0x54, 0x54, 0x18,
|
||||
0x00, 0x08, 0x7E, 0x09, 0x02,
|
||||
0x18, 0xA4, 0xA4, 0x9C, 0x78,
|
||||
0x7F, 0x08, 0x04, 0x04, 0x78,
|
||||
0x00, 0x44, 0x7D, 0x40, 0x00,
|
||||
0x20, 0x40, 0x40, 0x3D, 0x00,
|
||||
0x7F, 0x10, 0x28, 0x44, 0x00,
|
||||
0x00, 0x41, 0x7F, 0x40, 0x00,
|
||||
0x7C, 0x04, 0x78, 0x04, 0x78,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x78,
|
||||
0x38, 0x44, 0x44, 0x44, 0x38,
|
||||
0xFC, 0x18, 0x24, 0x24, 0x18,
|
||||
0x18, 0x24, 0x24, 0x18, 0xFC,
|
||||
0x7C, 0x08, 0x04, 0x04, 0x08,
|
||||
0x48, 0x54, 0x54, 0x54, 0x24,
|
||||
0x04, 0x04, 0x3F, 0x44, 0x24,
|
||||
0x3C, 0x40, 0x40, 0x20, 0x7C,
|
||||
0x1C, 0x20, 0x40, 0x20, 0x1C,
|
||||
0x3C, 0x40, 0x30, 0x40, 0x3C,
|
||||
0x44, 0x28, 0x10, 0x28, 0x44,
|
||||
0x4C, 0x90, 0x90, 0x90, 0x7C,
|
||||
0x44, 0x64, 0x54, 0x4C, 0x44,
|
||||
0x00, 0x08, 0x36, 0x41, 0x00,
|
||||
0x00, 0x00, 0x77, 0x00, 0x00,
|
||||
0x00, 0x41, 0x36, 0x08, 0x00,
|
||||
0x02, 0x01, 0x02, 0x04, 0x02,
|
||||
0x3C, 0x26, 0x23, 0x26, 0x3C,
|
||||
0x1E, 0xA1, 0xA1, 0x61, 0x12,
|
||||
0x3A, 0x40, 0x40, 0x20, 0x7A,
|
||||
0x38, 0x54, 0x54, 0x55, 0x59,
|
||||
0x21, 0x55, 0x55, 0x79, 0x41,
|
||||
0x21, 0x54, 0x54, 0x78, 0x41,
|
||||
0x21, 0x55, 0x54, 0x78, 0x40,
|
||||
0x20, 0x54, 0x55, 0x79, 0x40,
|
||||
0x0C, 0x1E, 0x52, 0x72, 0x12,
|
||||
0x39, 0x55, 0x55, 0x55, 0x59,
|
||||
0x39, 0x54, 0x54, 0x54, 0x59,
|
||||
0x39, 0x55, 0x54, 0x54, 0x58,
|
||||
0x00, 0x00, 0x45, 0x7C, 0x41,
|
||||
0x00, 0x02, 0x45, 0x7D, 0x42,
|
||||
0x00, 0x01, 0x45, 0x7C, 0x40,
|
||||
0xF0, 0x29, 0x24, 0x29, 0xF0,
|
||||
0xF0, 0x28, 0x25, 0x28, 0xF0,
|
||||
0x7C, 0x54, 0x55, 0x45, 0x00,
|
||||
0x20, 0x54, 0x54, 0x7C, 0x54,
|
||||
0x7C, 0x0A, 0x09, 0x7F, 0x49,
|
||||
0x32, 0x49, 0x49, 0x49, 0x32,
|
||||
0x32, 0x48, 0x48, 0x48, 0x32,
|
||||
0x32, 0x4A, 0x48, 0x48, 0x30,
|
||||
0x3A, 0x41, 0x41, 0x21, 0x7A,
|
||||
0x3A, 0x42, 0x40, 0x20, 0x78,
|
||||
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
|
||||
0x39, 0x44, 0x44, 0x44, 0x39,
|
||||
0x3D, 0x40, 0x40, 0x40, 0x3D,
|
||||
0x3C, 0x24, 0xFF, 0x24, 0x24,
|
||||
0x48, 0x7E, 0x49, 0x43, 0x66,
|
||||
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
|
||||
0xFF, 0x09, 0x29, 0xF6, 0x20,
|
||||
0xC0, 0x88, 0x7E, 0x09, 0x03,
|
||||
0x20, 0x54, 0x54, 0x79, 0x41,
|
||||
0x00, 0x00, 0x44, 0x7D, 0x41,
|
||||
0x30, 0x48, 0x48, 0x4A, 0x32,
|
||||
0x38, 0x40, 0x40, 0x22, 0x7A,
|
||||
0x00, 0x7A, 0x0A, 0x0A, 0x72,
|
||||
0x7D, 0x0D, 0x19, 0x31, 0x7D,
|
||||
0x26, 0x29, 0x29, 0x2F, 0x28,
|
||||
0x26, 0x29, 0x29, 0x29, 0x26,
|
||||
0x30, 0x48, 0x4D, 0x40, 0x20,
|
||||
0x38, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x38,
|
||||
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
|
||||
0x2F, 0x10, 0x28, 0x34, 0xFA,
|
||||
0x00, 0x00, 0x7B, 0x00, 0x00,
|
||||
0x08, 0x14, 0x2A, 0x14, 0x22,
|
||||
0x22, 0x14, 0x2A, 0x14, 0x08,
|
||||
0x95, 0x00, 0x22, 0x00, 0x95,
|
||||
0xAA, 0x00, 0x55, 0x00, 0xAA,
|
||||
0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x00,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x00,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x00,
|
||||
0x10, 0x10, 0xFF, 0x00, 0xFF,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x14, 0x14, 0x14, 0xFC, 0x00,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xFC,
|
||||
0x14, 0x14, 0x17, 0x10, 0x1F,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0x1F, 0x00,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x10,
|
||||
0x10, 0x10, 0x10, 0xF0, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0xFF, 0x10,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x14,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x17,
|
||||
0x00, 0x00, 0xFC, 0x04, 0xF4,
|
||||
0x14, 0x14, 0x17, 0x10, 0x17,
|
||||
0x14, 0x14, 0xF4, 0x04, 0xF4,
|
||||
0x00, 0x00, 0xFF, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x14, 0x14,
|
||||
0x14, 0x14, 0xF7, 0x00, 0xF7,
|
||||
0x14, 0x14, 0x14, 0x17, 0x14,
|
||||
0x10, 0x10, 0x1F, 0x10, 0x1F,
|
||||
0x14, 0x14, 0x14, 0xF4, 0x14,
|
||||
0x10, 0x10, 0xF0, 0x10, 0xF0,
|
||||
0x00, 0x00, 0x1F, 0x10, 0x1F,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x14,
|
||||
0x00, 0x00, 0x00, 0xFC, 0x14,
|
||||
0x00, 0x00, 0xF0, 0x10, 0xF0,
|
||||
0x10, 0x10, 0xFF, 0x10, 0xFF,
|
||||
0x14, 0x14, 0x14, 0xFF, 0x14,
|
||||
0x10, 0x10, 0x10, 0x1F, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF0, 0x10,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x38, 0x44, 0x44, 0x38, 0x44,
|
||||
0x7C, 0x2A, 0x2A, 0x3E, 0x14,
|
||||
0x7E, 0x02, 0x02, 0x06, 0x06,
|
||||
0x02, 0x7E, 0x02, 0x7E, 0x02,
|
||||
0x63, 0x55, 0x49, 0x41, 0x63,
|
||||
0x38, 0x44, 0x44, 0x3C, 0x04,
|
||||
0x40, 0x7E, 0x20, 0x1E, 0x20,
|
||||
0x06, 0x02, 0x7E, 0x02, 0x02,
|
||||
0x99, 0xA5, 0xE7, 0xA5, 0x99,
|
||||
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
|
||||
0x4C, 0x72, 0x01, 0x72, 0x4C,
|
||||
0x30, 0x4A, 0x4D, 0x4D, 0x30,
|
||||
0x30, 0x48, 0x78, 0x48, 0x30,
|
||||
0xBC, 0x62, 0x5A, 0x46, 0x3D,
|
||||
0x3E, 0x49, 0x49, 0x49, 0x00,
|
||||
0x7E, 0x01, 0x01, 0x01, 0x7E,
|
||||
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
|
||||
0x44, 0x44, 0x5F, 0x44, 0x44,
|
||||
0x40, 0x51, 0x4A, 0x44, 0x40,
|
||||
0x40, 0x44, 0x4A, 0x51, 0x40,
|
||||
0x00, 0x00, 0xFF, 0x01, 0x03,
|
||||
0xE0, 0x80, 0xFF, 0x00, 0x00,
|
||||
0x08, 0x08, 0x6B, 0x6B, 0x08,
|
||||
0x36, 0x12, 0x36, 0x24, 0x36,
|
||||
0x06, 0x0F, 0x09, 0x0F, 0x06,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x10, 0x10, 0x00,
|
||||
0x30, 0x40, 0xFF, 0x01, 0x01,
|
||||
0x00, 0x1F, 0x01, 0x01, 0x1E,
|
||||
0x00, 0x19, 0x1D, 0x17, 0x12,
|
||||
0x00, 0x3C, 0x3C, 0x3C, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
(C) Copyright 2016-2017, Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen
|
||||
Based on work (C) Copyright 2011, 2015, Len Shustek
|
||||
|
||||
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.
|
|
@ -0,0 +1,95 @@
|
|||
# ArduboyPlaytune
|
||||
|
||||
The ArduboyPlaytune library is maintained in a git repository hosted on [GitHub](https://github.com/) at:
|
||||
|
||||
https://github.com/Arduboy/ArduboyPlaytune
|
||||
|
||||
ArduboyPlaytune is based on the [arduino-playtune](https://github.com/LenShustek/arduino-playtune) library written by Len Shustek.
|
||||
|
||||
ArduboyPlaytune interprets a sequence of simple commands ("note on", "note off", and "wait") that represents a one or two part musical score without volume modulation. Once the score has started playing, background interrupt routines use the Arduino counters to generate notes in sequence at the right time. Two notes can play simultaneously. A separate open-source project called [midi2tones](https://github.com/MLXXXp/midi2tones) can generate the command sequence from a standard MIDI file.
|
||||
|
||||
ArduboyPlaytune can also play individual tones on the second channel, given a frequency and duration. If a score is playing when the *tone()* function is called, the tone will replace any notes assigned to the second channel for the tone's duration. By default, notes on the first channel will continue to play during the tone. By calling function
|
||||
*toneMutesScore(boolean mute)* with parameter *mute* set to `true`,
|
||||
the first channel will also be muted during a tone, so only the tone will sound.
|
||||
|
||||
Once a score or tone starts playing, all of the processing happens in interrupt routines, so any other "real" program can be running at the same time, as long as it doesn't use the timers or output pins that ArduboyPlaytune is using.
|
||||
|
||||
There is no volume modulation. All notes and tones are played as square waves by driving the pins high and low, which makes some scores sound strange. This is definitely not a high-quality synthesizer.
|
||||
|
||||
## The Score bytestream
|
||||
|
||||
Scores **must** be stored in Flash memory (using PROGMEM), as an array of bytes. E.g.:
|
||||
|
||||
```cpp
|
||||
const byte score[] PROGMEM = {0x90,83, 0,75, 0x80, 0x90,88, 0,225, 0x80, 0xf0};
|
||||
```
|
||||
|
||||
The bytestream is a series of commands that can turn notes on and off, and can start a waiting period until the next note change. Here are the details, with numbers shown in hexadecimal.
|
||||
|
||||
If the high-order bit of the byte is 1, then it is one of the following commands:
|
||||
|
||||
9t nn Start playing note nn on channel t. Channels are numbered
|
||||
starting with 0. The notes numbers are the MIDI numbers for the chromatic
|
||||
scale, with decimal 60 being Middle C, and decimal 69 being Middle A
|
||||
at 440 Hz. The highest note is decimal 127 at about 12,544 Hz.
|
||||
|
||||
8t Stop playing the note on channel t.
|
||||
|
||||
F0 End of score: stop playing.
|
||||
|
||||
E0 End of score: start playing again from the beginning.
|
||||
|
||||
If the high-order bit of the byte is 0, it is a command to wait. The other 7 bits and the 8 bits of the following byte are interpreted as a 15-bit big-endian integer that is the number of milliseconds to wait before processing the next command.
|
||||
|
||||
For example,
|
||||
|
||||
07 D0
|
||||
|
||||
would cause a wait of 0x07d0 = 2000 decimal milliseconds or 2 seconds. Any tones that were playing before the wait command will continue to play.
|
||||
|
||||
## Audio Mute Control
|
||||
|
||||
ArduboyPlaytune has the ability to mute the sound output based on a boolean value returned by a provided function. A pointer to this function is passed as a parameter to the ArduboyPlaytune class constructor. The function is called by ArduboyPlaytune to determine whether to actually output sound. If sound is muted, ArduboyPlaytune still goes through the motions of playing scores and tones but it doesn't actually toggle the pins. If muting is not required, a function that just returns `true` should be provided.
|
||||
|
||||
The function is called and tested at the point where a note or tone would begin playing. Any sounding notes will continue to play until the current wait time expires. A sounding tone will play for its duration. Sound output won't mute or start in the middle of a score wait or tone duration. Note that the function will be called from within a timer interrupt service routine, at the start of each score note, so it should be as fast as possible.
|
||||
|
||||
## Using a single pin
|
||||
|
||||
If only one pin is available for sound output (such as with the Arduboy DevKit) it's still possible to play both a score and tones, even though tones are always played on the second channel. This is done by using the same pin number to initialise both channels. The first channel of a score (only) and tones will then both output on the same pin.
|
||||
|
||||
When score notes and tones toggle the pin at the same time some very strange sounds are produced. To prevent this, function *toneMutesScore(true)* should be called during initialisation, so the score is muted when a tone is sounding.
|
||||
|
||||
## User Interface
|
||||
|
||||
Functions in this library, that are available for use by sketches, are documented in file *ArduboyPlaytune.h*
|
||||
|
||||
## Arduboy specific information
|
||||
|
||||
- If using the [Arduboy2](https://github.com/MLXXXp/Arduboy2) library, *audio.enabled()* is appropriate to use as the *mute* function passed to the ArduboyPlaytune constructor. For example:
|
||||
|
||||
```cpp
|
||||
Arduboy2 arduboy;
|
||||
ArduboyPlaytune tunes(arduboy.audio.enabled);
|
||||
```
|
||||
|
||||
- The Arduboy2 library defines *PIN_SPEAKER_1* and *PIN_SPEAKER_2* for the speaker pin numbers, which can be used with the *initChannel()* function.
|
||||
|
||||
- ArduboyPlaytune uses timer 1, which is also used for PWM on the pins used for the Arduboy's RGB LED. Using ArduboyPlaytune and attempting to control the RGB LED using PWM, such as with *setRGBled()*, may cause problems. Controlling the RGB LED using standard digital I/O, such as with *digitalWriteRGB()*, will work without conflicts.
|
||||
|
||||
- For the DevKit, only one pin can be used to drive the speaker, so only the first part in a score can be played. As described above under the _Using a single pin_ heading, both channels can be assigned to the same pin so that tones can also be played. To have a single sketch properly configure for either a production Arduboy or a DevKit, the following code can be used:
|
||||
|
||||
```cpp
|
||||
// audio setup
|
||||
tunes.initChannel(PIN_SPEAKER_1);
|
||||
#ifndef AB_DEVKIT
|
||||
// if not a DevKit
|
||||
tunes.initChannel(PIN_SPEAKER_2);
|
||||
#else
|
||||
// if it's a DevKit
|
||||
tunes.initChannel(PIN_SPEAKER_1); // use the same pin for both channels
|
||||
tunes.toneMutesScore(true); // mute the score when a tone is sounding
|
||||
#endif
|
||||
```
|
||||
|
||||
----------
|
||||
|
|
@ -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 = "ArduboyPlaytune 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
|
|
@ -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.
|
||||
|
||||
----------
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#########################################
|
||||
# Syntax Coloring Map For ArduboyPlaytune
|
||||
#########################################
|
||||
|
||||
#########################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#########################################
|
||||
|
||||
ArduboyPlaytune KEYWORD1
|
||||
|
||||
#########################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#########################################
|
||||
|
||||
closeChannels KEYWORD2
|
||||
initChannel KEYWORD2
|
||||
playing KEYWORD2
|
||||
playScore KEYWORD2
|
||||
stopScore KEYWORD2
|
||||
tone KEYWORD2
|
||||
toneMutesScore KEYWORD2
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "ArduboyPlaytune",
|
||||
"keywords": "arduboy, game, sound, music",
|
||||
"description": "A library for playing musical scores and tones that is compatible with the Arduboy game system",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/Arduboy/ArduboyPlaytune.git"
|
||||
},
|
||||
"version": "1.0.3",
|
||||
"exclude": "extras",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "atmelavr"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
name=ArduboyPlaytune
|
||||
version=1.0.3
|
||||
author=Len Shustek, Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen
|
||||
maintainer=Scott Allen <saydisp-git@yahoo.ca>
|
||||
sentence=A library for playing musical scores and tones that is compatible with the Arduboy game system.
|
||||
paragraph=Plays one or two part scores, and tones. Driven by interrupts, so audio plays in the background while the "real" program runs in the foreground.
|
||||
category=Other
|
||||
url=https://github.com/arduboy/ArduboyPlaytune
|
||||
architectures=avr
|
|
@ -0,0 +1,386 @@
|
|||
/**
|
||||
* @file ArduboyPlaytune.cpp
|
||||
* \brief An Arduino library that plays a one or two part musical score and
|
||||
* generates tones. Intended for the Arduboy game system.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* ArduboyPlaytune
|
||||
*
|
||||
* Plays a one or two part musical score and generates tones.
|
||||
*
|
||||
* Derived from:
|
||||
* Playtune: An Arduino tune player library
|
||||
* https://github.com/LenShustek/arduino-playtune
|
||||
*
|
||||
* Modified to work well with the Arduboy game system
|
||||
* https://www.arduboy.com/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* (C) Copyright 2016, Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen
|
||||
* Based on work (C) Copyright 2011, 2015, Len Shustek
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This was inspired by and adapted from "A Tone Generator Library",
|
||||
* written by Brett Hagman, http://www.roguerobotics.com/
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "ArduboyPlaytune.h"
|
||||
#include <avr/power.h>
|
||||
|
||||
static const byte tune_pin_to_timer[] = { 3, 1 };
|
||||
static volatile byte *_tunes_timer1_pin_port;
|
||||
static volatile byte _tunes_timer1_pin_mask;
|
||||
static volatile int32_t timer1_toggle_count;
|
||||
static volatile byte *_tunes_timer3_pin_port;
|
||||
static volatile byte _tunes_timer3_pin_mask;
|
||||
static byte _tune_pins[AVAILABLE_TIMERS];
|
||||
static byte _tune_num_chans = 0;
|
||||
static volatile boolean tune_playing = false; // is the score still playing?
|
||||
static volatile unsigned wait_timer_frequency2; /* its current frequency */
|
||||
static volatile boolean wait_timer_playing = false; /* is it currently playing a note? */
|
||||
static volatile unsigned long wait_toggle_count; /* countdown score waits */
|
||||
static volatile boolean all_muted = false; // indicates all sound is muted
|
||||
static volatile boolean tone_playing = false;
|
||||
static volatile boolean tone_mutes_score = false;
|
||||
static volatile boolean tone_only = false; // indicates don't play score on tone channel
|
||||
static volatile boolean mute_score = false; // indicates tone playing so mute other channels
|
||||
|
||||
// pointer to a function that indicates if sound is enabled
|
||||
static boolean (*outputEnabled)();
|
||||
|
||||
// pointers to your musical score and your position in said score
|
||||
static volatile const byte *score_start = 0;
|
||||
static volatile const byte *score_cursor = 0;
|
||||
|
||||
// Table of midi note frequencies * 2
|
||||
// They are times 2 for greater accuracy, yet still fits in a word.
|
||||
// Generated from Excel by =ROUND(2*440/32*(2^((x-9)/12)),0) for 0<x<128
|
||||
// The lowest notes might not work, depending on the Arduino clock frequency
|
||||
// Ref: http://www.phy.mtu.edu/~suits/notefreqs.html
|
||||
const uint8_t _midi_byte_note_frequencies[48] PROGMEM = {
|
||||
16,17,18,19,21,22,23,24,26,28,29,31,33,35,37,39,41,44,46,49,52,55,58,62,65,
|
||||
69,73,78,82,87,92,98,104,110,117,123,131,139,147,156,165,175,185,196,208,220,
|
||||
233,247
|
||||
};
|
||||
const unsigned int _midi_word_note_frequencies[80] PROGMEM = {
|
||||
262,277,294,311,330,349,370,392,415,440,466,494,523,554,587,622,659,
|
||||
698,740,784,831,880,932,988,1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,
|
||||
1865,1976,2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,3951,4186,
|
||||
4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902,8372,8870,9397,9956,
|
||||
10548,11175,11840,12544,13290,14080,14917,15804,16744,17740,18795,19912,21096,
|
||||
22351,23680,25088
|
||||
};
|
||||
|
||||
ArduboyPlaytune::ArduboyPlaytune(boolean (*outEn)())
|
||||
{
|
||||
outputEnabled = outEn;
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::initChannel(byte pin)
|
||||
{
|
||||
byte timer_num;
|
||||
byte pin_port;
|
||||
byte pin_mask;
|
||||
volatile byte *out_reg;
|
||||
|
||||
// we are all out of timers
|
||||
if (_tune_num_chans == AVAILABLE_TIMERS)
|
||||
return;
|
||||
|
||||
timer_num = tune_pin_to_timer[_tune_num_chans];
|
||||
_tune_pins[_tune_num_chans] = pin;
|
||||
if ((_tune_num_chans == 1) && (_tune_pins[0] == pin)) { // if channels 0 and 1 use the same pin
|
||||
tone_only = true; // don't play the score on channel 1
|
||||
}
|
||||
_tune_num_chans++;
|
||||
|
||||
pin_port = digitalPinToPort(pin);
|
||||
pin_mask = digitalPinToBitMask(pin);
|
||||
out_reg = portOutputRegister(pin_port);
|
||||
|
||||
*portModeRegister(pin_port) |= pin_mask; // set pin to output mode
|
||||
|
||||
switch (timer_num) {
|
||||
case 1: // 16 bit timer
|
||||
power_timer1_enable();
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0;
|
||||
bitWrite(TCCR1B, WGM12, 1);
|
||||
bitWrite(TCCR1B, CS10, 1);
|
||||
_tunes_timer1_pin_port = out_reg;
|
||||
_tunes_timer1_pin_mask = pin_mask;
|
||||
break;
|
||||
case 3: // 16 bit timer
|
||||
power_timer3_enable();
|
||||
TCCR3A = 0;
|
||||
TCCR3B = 0;
|
||||
bitWrite(TCCR3B, WGM32, 1);
|
||||
bitWrite(TCCR3B, CS30, 1);
|
||||
_tunes_timer3_pin_port = out_reg;
|
||||
_tunes_timer3_pin_mask = pin_mask;
|
||||
playNote(0, 60); /* start and stop channel 0 (timer 3) on middle C so wait/delay works */
|
||||
stopNote(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::playNote(byte chan, byte note)
|
||||
{
|
||||
byte timer_num;
|
||||
byte prescalar_bits;
|
||||
unsigned int frequency2; /* frequency times 2 */
|
||||
unsigned long ocr;
|
||||
|
||||
// we can't play on a channel that does not exist
|
||||
if (chan >= _tune_num_chans) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if channel 1 is for tones only
|
||||
if ((chan == 1) && tone_only) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we only have frequencies for 128 notes
|
||||
if (note > 127) {
|
||||
return;
|
||||
}
|
||||
|
||||
timer_num = tune_pin_to_timer[chan];
|
||||
if (note < 48) {
|
||||
frequency2 = pgm_read_byte(_midi_byte_note_frequencies + note);
|
||||
} else {
|
||||
frequency2 = pgm_read_word(_midi_word_note_frequencies + note - 48);
|
||||
}
|
||||
|
||||
//****** 16-bit timer *********
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency2 - 1;
|
||||
prescalar_bits = 0b001;
|
||||
if (ocr > 0xffff) {
|
||||
ocr = F_CPU / frequency2 / 64 - 1;
|
||||
prescalar_bits = 0b011;
|
||||
}
|
||||
// Set the OCR for the given timer, then turn on the interrupts
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
if (!tone_playing) {
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalar_bits;
|
||||
OCR1A = ocr;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
TCCR3B = (TCCR3B & 0b11111000) | prescalar_bits;
|
||||
OCR3A = ocr;
|
||||
wait_timer_frequency2 = frequency2; // for "tune_delay" function
|
||||
wait_timer_playing = true;
|
||||
bitWrite(TIMSK3, OCIE3A, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::stopNote(byte chan)
|
||||
{
|
||||
byte timer_num;
|
||||
timer_num = tune_pin_to_timer[chan];
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
if (!tone_playing) {
|
||||
TIMSK1 &= ~(1 << OCIE1A); // disable the interrupt
|
||||
*_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask); // keep pin low after stop
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
wait_timer_playing = false;
|
||||
if (!mute_score) {
|
||||
*_tunes_timer3_pin_port &= ~(_tunes_timer3_pin_mask); // keep pin low after stop
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::playScore(const byte *score)
|
||||
{
|
||||
score_start = score;
|
||||
score_cursor = score_start;
|
||||
step(); /* execute initial commands */
|
||||
tune_playing = true; /* release the interrupt routine */
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::stopScore()
|
||||
{
|
||||
for (uint8_t i = 0; i < _tune_num_chans; i++)
|
||||
stopNote(i);
|
||||
tune_playing = false;
|
||||
}
|
||||
|
||||
boolean ArduboyPlaytune::playing()
|
||||
{
|
||||
return tune_playing;
|
||||
}
|
||||
|
||||
/* Do score commands until a "wait" is found, or the score is stopped.
|
||||
This is called initially from playScore(), but then is called
|
||||
from the interrupt routine when waits expire.
|
||||
|
||||
If CMD < 0x80, then the other 7 bits and the next byte are a
|
||||
15-bit big-endian number of msec to wait
|
||||
*/
|
||||
void ArduboyPlaytune::step()
|
||||
{
|
||||
byte command, opcode, chan;
|
||||
unsigned duration;
|
||||
|
||||
while (1) {
|
||||
command = pgm_read_byte(score_cursor++);
|
||||
opcode = command & 0xf0;
|
||||
chan = command & 0x0f;
|
||||
if (opcode == TUNE_OP_STOPNOTE) { /* stop note */
|
||||
stopNote(chan);
|
||||
}
|
||||
else if (opcode == TUNE_OP_PLAYNOTE) { /* play note */
|
||||
all_muted = !outputEnabled();
|
||||
playNote(chan, pgm_read_byte(score_cursor++));
|
||||
}
|
||||
else if (opcode < 0x80) { /* wait count in msec. */
|
||||
duration = ((unsigned)command << 8) | (pgm_read_byte(score_cursor++));
|
||||
wait_toggle_count = ((unsigned long) wait_timer_frequency2 * duration + 500) / 1000;
|
||||
if (wait_toggle_count == 0) wait_toggle_count = 1;
|
||||
break;
|
||||
}
|
||||
else if (opcode == TUNE_OP_RESTART) { /* restart score */
|
||||
score_cursor = score_start;
|
||||
}
|
||||
else if (opcode == TUNE_OP_STOP) { /* stop score */
|
||||
tune_playing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::closeChannels()
|
||||
{
|
||||
byte timer_num;
|
||||
for (uint8_t chan=0; chan < _tune_num_chans; chan++) {
|
||||
timer_num = tune_pin_to_timer[chan];
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
TIMSK1 &= ~(1 << OCIE1A);
|
||||
*_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask); // set pin low
|
||||
break;
|
||||
case 3:
|
||||
TIMSK3 &= ~(1 << OCIE3A);
|
||||
*_tunes_timer3_pin_port &= ~(_tunes_timer3_pin_mask); // set pin low
|
||||
break;
|
||||
}
|
||||
}
|
||||
_tune_num_chans = 0;
|
||||
tune_playing = tone_playing = tone_only = mute_score = false;
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::tone(unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
// don't output the tone if sound is muted or
|
||||
// the tone channel isn't initialised
|
||||
if (!outputEnabled() || _tune_num_chans < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
tone_playing = true;
|
||||
mute_score = tone_mutes_score;
|
||||
|
||||
uint8_t prescalarbits = 0b001;
|
||||
int32_t toggle_count = 0;
|
||||
uint32_t ocr = 0;
|
||||
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency / 2 - 1;
|
||||
prescalarbits = 0b001;
|
||||
if (ocr > 0xffff) {
|
||||
ocr = F_CPU / frequency / 2 / 64 - 1;
|
||||
prescalarbits = 0b011;
|
||||
}
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
|
||||
|
||||
// Calculate the toggle count
|
||||
if (duration > 0) {
|
||||
toggle_count = 2 * frequency * duration / 1000;
|
||||
}
|
||||
else {
|
||||
toggle_count = -1;
|
||||
}
|
||||
// Set the OCR for the given timer,
|
||||
// set the toggle count,
|
||||
// then turn on the interrupts
|
||||
OCR1A = ocr;
|
||||
timer1_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
}
|
||||
|
||||
void ArduboyPlaytune::toneMutesScore(boolean mute)
|
||||
{
|
||||
tone_mutes_score = mute;
|
||||
}
|
||||
|
||||
// ===== Interrupt service routines =====
|
||||
|
||||
// TIMER 1
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
if (tone_playing) {
|
||||
if (timer1_toggle_count != 0) {
|
||||
// toggle the pin
|
||||
*_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask;
|
||||
if (timer1_toggle_count > 0) timer1_toggle_count--;
|
||||
}
|
||||
else {
|
||||
tone_playing = mute_score = false;
|
||||
TIMSK1 &= ~(1 << OCIE1A); // disable the interrupt
|
||||
*_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!all_muted) {
|
||||
*_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask; // toggle the pin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TIMER 3
|
||||
ISR(TIMER3_COMPA_vect)
|
||||
{
|
||||
// Timer 3 is the one assigned first, so we keep it running always
|
||||
// and use it to time score waits, whether or not it is playing a note.
|
||||
|
||||
// toggle the pin if we're sounding a note
|
||||
if (wait_timer_playing && !mute_score && !all_muted) {
|
||||
*_tunes_timer3_pin_port ^= _tunes_timer3_pin_mask;
|
||||
}
|
||||
|
||||
if (tune_playing && wait_toggle_count && --wait_toggle_count == 0) {
|
||||
// end of a score wait, so execute more score commands
|
||||
ArduboyPlaytune::step(); // execute commands
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
/**
|
||||
* @file ArduboyPlaytune.h
|
||||
* \brief An Arduino library that plays a one or two part musical score and
|
||||
* generates tones. Intended for the Arduboy game system.
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* ArduboyPlaytune
|
||||
*
|
||||
* Plays a one or two part musical score and generates tones.
|
||||
*
|
||||
* Derived from:
|
||||
* Playtune: An Arduino tune player library
|
||||
* https://github.com/LenShustek/arduino-playtune
|
||||
*
|
||||
* Modified to work well with the Arduboy game system
|
||||
* https://www.arduboy.com/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* (C) Copyright 2016, Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen
|
||||
* Based on work (C) Copyright 2011, 2015, Len Shustek
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This was inspired by and adapted from "A Tone Generator Library",
|
||||
* written by Brett Hagman, http://www.roguerobotics.com/
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef ARDUBOY_PLAYTUNE_H
|
||||
#define ARDUBOY_PLAYTUNE_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#define AVAILABLE_TIMERS 2
|
||||
|
||||
// score commands
|
||||
#define TUNE_OP_PLAYNOTE 0x90 /* play a note: low nibble is generator #, note is next byte */
|
||||
#define TUNE_OP_STOPNOTE 0x80 /* stop a note: low nibble is generator # */
|
||||
#define TUNE_OP_RESTART 0xe0 /* restart the score from the beginning */
|
||||
#define TUNE_OP_STOP 0xf0 /* stop playing */
|
||||
|
||||
/** \brief
|
||||
* The ArduboyPlaytune class for playing two part musical scores and
|
||||
* sounding tones.
|
||||
*/
|
||||
class ArduboyPlaytune
|
||||
{
|
||||
public:
|
||||
/** \brief
|
||||
* The ArduboyPlaytune class constructor.
|
||||
|
||||
* \param outEn
|
||||
* \parblock
|
||||
* The function passed to the constructor must return `true` if
|
||||
* sounds should be played or `false` if all sound should be muted.
|
||||
*
|
||||
* If muting control isn't required, provide a pointer to a function that
|
||||
* always returns `true`.
|
||||
*
|
||||
* The provided function will be called from a timer interrupt service
|
||||
* routine, at the start of each score note, so it should be as fast as
|
||||
* possible.
|
||||
* \endparblock
|
||||
|
||||
* \details
|
||||
* When muting is in effect, scores and tones are still processed
|
||||
* as usual but no sound is produced.
|
||||
*
|
||||
* \note
|
||||
* If using the Arduboy2 library, `audio.enabled()` is appropriate
|
||||
* to use as the mute function.
|
||||
*/
|
||||
ArduboyPlaytune(boolean (*outEn)());
|
||||
|
||||
/** \brief
|
||||
* Assign an output pin to a score channel.
|
||||
*
|
||||
* \param pin The pin number to be used to produce sound for a score channel.
|
||||
*
|
||||
* \details
|
||||
* \parblock
|
||||
* Each time this function is called the next score channel is assigned
|
||||
* to the provided pin number, so it should be called once or twice.
|
||||
*
|
||||
* If the `tone()` function is to be used, the second channel must be
|
||||
* initialized since tones are alway played on it.
|
||||
*
|
||||
* The same pin number can be used for both channels, in which case only the
|
||||
* first score channel will be played and tones will play on the same pin.
|
||||
* Function `toneMutesScore(true)` can be use to prevent the strange sounds
|
||||
* that occur from using the same pin for both the score and tones.
|
||||
* \endparblock
|
||||
*
|
||||
* \note
|
||||
* If using the Arduboy2 library, the defined values `PIN_SPEAKER_1` and
|
||||
* `PIN_SPEAKER_2` should be used for the `pin` parameter.
|
||||
*/
|
||||
void static initChannel(byte pin);
|
||||
|
||||
/** \brief
|
||||
* Start playing the provided score.
|
||||
*
|
||||
* \param score A pointer to an array of bytes containing the score data.
|
||||
* The array must be placed in code space using `PROGMEM`.
|
||||
*
|
||||
* \details
|
||||
* The score will be played in the background until an
|
||||
* "End of score: stop playing" command is read or the `stopScore()` function
|
||||
* is called. Any notes in the score for channels above the one or two that
|
||||
* have been initialized will be ignored.
|
||||
*/
|
||||
void playScore(const byte *score);
|
||||
|
||||
/** \brief
|
||||
* Stop playing a score started using `playScore()`.
|
||||
*
|
||||
* \details
|
||||
* If a score is playing, it will stop. If nothing is playing,
|
||||
* this function will do nothing.
|
||||
*/
|
||||
void stopScore();
|
||||
|
||||
/** \brief
|
||||
* Close all (one or two) initialized channels.
|
||||
*
|
||||
* \details
|
||||
* After calling this function, function `initChannel()` must be
|
||||
* called, to reassign pins to channels, if more sound is to be produced.
|
||||
*/
|
||||
void closeChannels();
|
||||
|
||||
/** \brief
|
||||
* Check if a score is currently playing.
|
||||
*
|
||||
* \return boolean `true` if playing (even if sound is muted).
|
||||
*/
|
||||
boolean playing();
|
||||
|
||||
/** \brief
|
||||
* Play a tone of a given frequency and duration on the second channel.
|
||||
*
|
||||
* \param frequency The frequency of the tone in hertz (cycles per second).
|
||||
* \param duration The duration of the tone in milliseconds.
|
||||
*
|
||||
* \details
|
||||
* If a score is playing that uses the second channel, the notes for
|
||||
* that channel are muted for the duration of the tone. Score notes on the
|
||||
* first channel continue to play unless `toneMutesScore(true)` has been
|
||||
* called.
|
||||
*/
|
||||
void tone(unsigned int frequency, unsigned long duration);
|
||||
|
||||
/** \brief
|
||||
* Set a mode to specify whether playing a tone mutes the first score
|
||||
* channel.
|
||||
*
|
||||
* \param mute
|
||||
* \parblock
|
||||
* If `true` a score part on the first channel will be muted when a tone
|
||||
* is playing. (A score part playing on the second channel is always muted
|
||||
* since the tone plays on it.)
|
||||
*
|
||||
* If `false` (the default) the first channel will continue to
|
||||
* play when a tone is playing.
|
||||
* \endparblock
|
||||
*/
|
||||
void toneMutesScore(boolean mute);
|
||||
|
||||
private:
|
||||
void static playNote(byte chan, byte note);
|
||||
void static stopNote(byte chan);
|
||||
|
||||
public:
|
||||
// called via interrupt. Should not be called by a program.
|
||||
void static step();
|
||||
};
|
||||
|
||||
#endif
|