Compare commits

..

No commits in common. "master" and "5.0.0" have entirely different histories.

43 changed files with 2140 additions and 13029 deletions

View File

@ -1,30 +0,0 @@
# Commit message style
When submitting changes via a pull request, or any other means, please format commit messages using ["50/72" guidelines, as suggested by Tim Pope](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
## Summary:
- Maximum 50 character first "title" line, written as a capitalized [imperative sentence](http://examples.yourdictionary.com/imperative-sentence-examples.html).
- If necessary, more detailed explanatory paragraphs following a blank line, with lines wrapped at maximum 72 characters.
- If used, bullet points have a "hanging indent".
## Example 1:
```
Make state variables used by pollButtons() public
The variables currentButtonState and previousButtonState used by
pollButtons(), justPressed() and justReleased() have been made public.
This allows them to be manipulated if circumstances require it.
The documentation added for previousButtonState includes an example.
```
## Example 2:
```
Refactor text code and add char size functions
- Functions write() and drawChar() were refactored for smaller code
size and to make text wrapping operate more like what would normally
be expected.
- A new flag variable, textRaw, has been added, along with functions
setTextRawMode() and getTextRawMode() to set and read it.
```

View File

@ -8,7 +8,7 @@ Software License Agreements
Licensed under the BSD 3-clause license: Licensed under the BSD 3-clause license:
Arduboy2 library: Arduboy2 library:
Copyright (c) 2016-2021, Scott Allen Copyright (c) 2016-2018, Scott Allen
All rights reserved. All rights reserved.
The Arduboy2 library was forked from the Arduboy library: The Arduboy2 library was forked from the Arduboy library:
@ -18,14 +18,13 @@ Copyright (c) 2016, Chris Martinez
Copyright (c) 2016, Josh Goebel Copyright (c) 2016, Josh Goebel
Copyright (c) 2016, Scott Allen Copyright (c) 2016, Scott Allen
All rights reserved. All rights reserved.
which is in turn partially based on the Adafruit_SSD1306 library
- which is in turn partially based on the Adafruit_SSD1306 library
https://github.com/adafruit/Adafruit_SSD1306 https://github.com/adafruit/Adafruit_SSD1306
Copyright (c) 2012, Adafruit Industries Copyright (c) 2012, Adafruit Industries
All rights reserved. All rights reserved.
SetSystemEEPROM example sketch: SetSystemEEPROM example sketch:
Copyright (c) 2018-2020, Scott Allen Copyright (c) 2018, Scott Allen
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -88,6 +87,7 @@ https://github.com/yyyc514/ArduboyExtra
Copyright (c) 2015 Josh Goebel Copyright (c) 2015 Josh Goebel
Code for drawing compressed bitmaps: Code for drawing compressed bitmaps:
https://github.com/TEAMarg/drawCompressed
Copyright (c) 2016 TEAM a.r.g. Copyright (c) 2016 TEAM a.r.g.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -135,167 +135,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. Lesser General Public License for more details.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Licensed under the zlib license: Placed in the public domain:
LodePNG
https://github.com/lvandeve/lodepng
Copyright (c) 2005-2020 Lode Vandevenne
(Used by the Cabi program)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
-------------------------------------------------------------------------------
Placed in the public domain using Creative Commons CC0:
https://creativecommons.org/publicdomain/zero/1.0/
BeepDemo example sketch: BeepDemo example sketch:
By Scott Allen By Scott Allen
FontDemo example sketch:
By Scott Allen
RGBled example sketch: RGBled example sketch:
By Scott Allen By Scott Allen
Cabi PNG file converter program:
By zep
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
=============================================================================== ===============================================================================
\endverbatim \endverbatim
*/ */

159
README.md
View File

@ -4,7 +4,7 @@ The Arduboy2 library is maintained in a git repository hosted on [GitHub](https:
https://github.com/MLXXXp/Arduboy2 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 original *Arduboy* library is no longer being maintained. 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. 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.
@ -12,7 +12,7 @@ For notes on the differences between the *Arduboy2* library and the original *Ar
## Library documentation ## Library documentation
Comments in the library header files are formatted for the [Doxygen](https://www.doxygen.nl/) document generation system. The HTML files generated using the configuration file _extras/Doxyfile_ can be found at: 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 https://MLXXXp.github.io/documents/Arduino/libraries/Arduboy2/Doxygen/html/index.html
@ -41,16 +41,15 @@ The *begin()* function, used to initialize the library, includes features that a
At the start of the sketch, the **ARDUBOY** logo scrolls down from the top of the screen to the center. 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. 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).
A user settable *unit name* 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. 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. Once the logo display sequence completes, the sketch continues.
**Note:** 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 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.
- 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 ### "Flashlight" mode
@ -108,11 +107,11 @@ Sample sketches have been included with the library as examples of how to use it
`File > Examples > Arduboy2` `File > Examples > Arduboy2`
More information on writing sketches for the Arduboy can be found in the [Arduboy Community Forum](https://community.arduboy.com/). 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 <- THIS IS IMPORTANT! ### 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* 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 ### Audio control functions
@ -148,7 +147,7 @@ If you want to be able to play sequences of tones or background music, using the
#### Remove the text functions #### 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](https://playground.arduino.cc/Code/Printclass/). 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*: To eliminate text capability in your sketch, when creating the library object simply use the *Arduboy2Base* class instead of *Arduboy2*:
@ -166,99 +165,63 @@ with
Arduboy2Base arduboy; Arduboy2Base arduboy;
``` ```
#### Substitute or remove boot up features #### Remove boot up features
As previously described in the _Start up features_ section, 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. 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. 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.
You should at least call either *flashlight()* or *safeMode()* as a safeguard to allow uploading a new sketch when the bootloader "magic key" problem is an issue. 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.
Here is a template that provides the equivalent of *begin()* As of this writing, the begin function is:
```cpp ```cpp
void setup() void Arduboy2Base::begin()
{ {
// Required to initialize the hardware. boot(); // raw hardware
arduboy.boot();
// This clears the display. (The screen buffer will be all zeros) display(); // blank the display (sBuffer is global, so cleared automatically)
// It may not be needed if something clears the display later on but
// "garbage" will be displayed if systemButtons() is used without it.
arduboy.display();
// flashlight() or safeMode() should always be included to provide flashlight(); // light the RGB LED and screen if UP button is being held.
// a method of recovering from the bootloader "magic key" problem.
arduboy.flashlight();
// arduboy.safeMode();
// This allows sound to be turned on or muted. If the sketch provides // check for and handle buttons held during start up for system control
// its own way of toggling sound, or doesn't produce any sound, this systemButtons();
// function may not be required.
arduboy.systemButtons();
// This is required to initialize the speaker. It's not needed if audio.begin();
// the sketch doesn't produce any sounds.
arduboy.audio.begin();
// This displays the boot logo sequence but note that the logo can bootLogo();
// be suppressed by the user, by pressing the RIGHT button or using
// a system EEPROM setting. If not removed entirely, an alternative
// bootLogo...() function may save some memory.
arduboy.bootLogo();
// arduboy.bootLogoCompressed();
// arduboy.bootLogoSpritesSelfMasked();
// arduboy.bootLogoSpritesOverwrite();
// arduboy.bootLogoSpritesBSelfMasked();
// arduboy.bootLogoSpritesBOverwrite();
// arduboy.bootLogoText();
// Wait for all buttons to be released, in case a pressed one might
// cause problems by being acted upon when the actual sketch code
// starts. If neither systemButtons() nor bootLogo() is kept, this
// function isn't required.
arduboy.waitNoButtons();
// Additional setup code...
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. 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 *drawBitmap()*, 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. - *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). - *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()* as a safeguard 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()*. - *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()*.
It is also possible to replace the boot logo drawing function with one that uses a different bitmap rendering function used elsewhere in your sketch. This may save memory by using this bitmap function for the logo, instead of the logo using a separate function that only ends up being used once. For example, if you use the *ArdBitmap* library's *drawCompressed()* function in your sketch, you could convert the **ARDUBOY** logo to *Ardbitmap* compressed format, and create *drawLogoArdCompressed()* and *bootLogoArdCompressed()* functions:
```cpp
void drawLogoArdCompressed(int16_t y)
{
ardbitmap.drawCompressed(20, y, arduboy_logo_ardbitmap,
WHITE, ALIGN_CENTER, MIRROR_NONE);
}
void bootLogoArdCompressed()
{
if (arduboy.bootLogoShell(drawLogoArdCompressed))
{
arduboy.bootLogoExtra();
}
}
void setup()
{
arduboy.beginDoFirst();
bootLogoArdCompressed();
arduboy.waitNoButtons();
// Additional setup code...
}
```
The **ARDUBOY** logo, in PNG format, is included in the library repository as file:
`extras/assets/arduboy_logo.png`
#### Use the SpritesB class instead of Sprites #### Use the SpritesB class instead of Sprites
@ -283,8 +246,6 @@ The *ARDUBOY_NO_USB* macro is used to eliminate the USB code. The *exitToBootloa
## What's different from Arduboy library V1.1 ## What's different from Arduboy library V1.1
(These notes apply to when the *Arduboy2* library was first released. There will have been many additional changes, enhancements and features added to *Arduboy2* since then.)
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. 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: Main differences between Arduboy2 and Arduboy V1.1 are:
@ -301,7 +262,7 @@ Main differences between Arduboy2 and Arduboy V1.1 are:
- 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 *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. - 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. *Arglib* library has been added: 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 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. - The *drawCompressed()* function, which allows compressed bitmaps to be drawn. Saving bitmaps in compressed form may reduce overall sketch size.
@ -344,11 +305,11 @@ 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. 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 ### Sketch uses only *tunes.tone()* for sound
If the sketch has sound but only uses *tunes.tone()*, solutions are: If the sketch has sound but only uses *tunes.tone()*, solutions are:
#### Solution 1: Switch to using Arduino tone() #### 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: 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:
@ -411,7 +372,7 @@ See the [ArduboyTones](https://github.com/MLXXXp/ArduboyTones) README file for m
See the following for how to do this: See the following for how to do this:
### Sketch uses tunes.playScore() ### 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. 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.
@ -428,7 +389,7 @@ Arduboy2 arduboy;
ArduboyPlaytune tunes(arduboy.audio.enabled); ArduboyPlaytune tunes(arduboy.audio.enabled);
``` ```
The sound channels must then be initialized and assigned to the speaker pins. This code would go in the *setup()* function: The sound channels must then be initialzed and assigned to the speaker pins. This code would go in the *setup()* function:
```cpp ```cpp
// audio setup // audio setup
@ -461,15 +422,15 @@ If you don't need to play scores containing two parts, and don't require tones t
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. 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() ### Sketch uses the *beginNoLogo()* function instead of *begin()*
The *beginNoLogo()* function has been removed. *beginNoLogo()* can be replaced with *begin()*, since users can choose to suppress the logo sequence using the *RIGHT* button or by setting a flag in system EEPROM. 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:
If using *begin()* results in the sketch program memory size being too large, *beginDoFirst()* or *boot()* can be used with additional functions following it to add back in desired boot functionality. See the information above, under the heading *Substitute or remove boot up features*, for more details. Assuming the object is named *arduboy*, an equivalent replacement for *beginNoLogo()* would be:
```cpp ```cpp
arduboy.beginDoFirst(); arduboy.boot();
arduboy.waitNoButtons(); arduboy.display();
arduboy.flashlight();
arduboy.audio.begin();
``` ```
---------- ----------

View File

@ -3,8 +3,7 @@
Copyright (C) 2011 Sebastian Goscik Copyright (C) 2011 Sebastian Goscik
All rights reserved. All rights reserved.
Modifications by Scott Allen 2016, 2018, 2020 Modifications by Scott Allen 2016 (after previous changes by ???)
after previous changes by person(s) unknown.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -17,38 +16,20 @@
// block in EEPROM to save high scores // block in EEPROM to save high scores
#define EE_FILE 2 #define EE_FILE 2
// EEPROM space used: 35 bytes (7*(3+2)) starting at
// EEPROM_STORAGE_SPACE_START + (EE_FILE * 35)
Arduboy2 arduboy; Arduboy2 arduboy;
BeepPin1 beep; BeepPin1 beep;
constexpr uint8_t frameRate = 40; // Frame rate in frames per second const unsigned int FRAME_RATE = 40; // Frame rate in frames per second
const unsigned int COLUMNS = 13; //Columns of bricks
// Tone frequencies. Converted to count values for the beep class const unsigned int ROWS = 4; //Rows of bricks
constexpr uint16_t tonePaddle = beep.freq(200); // Ball hits paddle
constexpr uint16_t toneBrick = beep.freq(261); // Ball hits a brick
constexpr uint16_t toneEdge = beep.freq(523); // Ball hits top or sides
constexpr uint16_t toneMiss = beep.freq(175); // Ball misses paddle, lose life
constexpr uint16_t toneInitialsChange = beep.freq(523); // Change initials
constexpr uint16_t toneInitialsMove = beep.freq(1046); // Select initials
// Tone durations
constexpr uint8_t toneTimeBeep = 250 / (1000 / frameRate); // Game (frames)
constexpr uint16_t toneTimeMiss = 500; // Miss paddle (milliseconds)
constexpr uint16_t toneTimeInitials = 80; // Initials entry (milliseconds)
constexpr unsigned int columns = 13; //Columns of bricks
constexpr unsigned int rows = 4; //Rows of bricks
int dx = -1; //Initial movement of ball int dx = -1; //Initial movement of ball
int dy = -1; //Initial movement of ball int dy = -1; //Initial movement of ball
int xb; //Ball's starting position int xb; //Balls starting possition
int yb; //Ball's starting position int yb; //Balls starting possition
boolean released; //If the ball has been released by the player boolean released; //If the ball has been released by the player
boolean paused = false; //If the game has been paused boolean paused = false; //If the game has been paused
byte xPaddle; //X position of paddle byte xPaddle; //X position of paddle
boolean isHit[rows][columns]; //Array of if bricks are hit or not boolean isHit[ROWS][COLUMNS]; //Array of if bricks are hit or not
boolean bounced=false; //Used to fix double bounce glitch boolean bounced=false; //Used to fix double bounce glitch
byte lives = 3; //Amount of lives byte lives = 3; //Amount of lives
byte level = 1; //Current level byte level = 1; //Current level
@ -79,7 +60,7 @@ void setup()
{ {
arduboy.begin(); arduboy.begin();
beep.begin(); beep.begin();
arduboy.setFrameRate(frameRate); arduboy.setFrameRate(FRAME_RATE);
arduboy.initRandomSeed(); arduboy.initRandomSeed();
} }
@ -111,9 +92,9 @@ void loop()
//Selects Font //Selects Font
//Draws the new level //Draws the new level
level = 1; level = 1;
initialDraw=true;
newLevel(); newLevel();
score = 0; score = 0;
initialDraw=true;
} }
if (lives>0) if (lives>0)
@ -132,7 +113,7 @@ void loop()
oldpad = pad; oldpad = pad;
drawBall(); drawBall();
if(brickCount == rows * columns) if(brickCount == ROWS * COLUMNS)
{ {
level++; level++;
newLevel(); newLevel();
@ -183,15 +164,12 @@ void moveBall()
if(released) if(released)
{ {
//Move ball //Move ball
if (abs(dx)==2) if (abs(dx)==2) {
{
xb += dx/2; xb += dx/2;
// 2x speed is really 1.5 speed // 2x speed is really 1.5 speed
if (tick%2==0) if (tick%2==0)
xb += dx/2; xb += dx/2;
} } else {
else
{
xb += dx; xb += dx;
} }
yb=yb + dy; yb=yb + dy;
@ -207,18 +185,18 @@ void moveBall()
{ {
yb = 2; yb = 2;
dy = -dy; dy = -dy;
playTone(toneEdge, toneTimeBeep); playTone(523, 250);
} }
//Lose a life if bottom edge hit //Lose a life if bottom edge hit
if (yb >= 64) if (yb >= 64)
{ {
arduboy.drawRect(xPaddle, 63, 11, 1, BLACK); arduboy.drawRect(xPaddle, 63, 11, 1, 0);
xPaddle = 54; xPaddle = 54;
yb=60; yb=60;
released = false; released = false;
lives--; lives--;
playToneTimed(toneMiss, toneTimeMiss); playToneTimed(175, 500);
if (random(0, 2) == 0) if (random(0, 2) == 0)
{ {
dx = 1; dx = 1;
@ -234,7 +212,7 @@ void moveBall()
{ {
xb = 2; xb = 2;
dx = -dx; dx = -dx;
playTone(toneEdge, toneTimeBeep); playTone(523, 250);
} }
//Bounce off right side //Bounce off right side
@ -242,7 +220,7 @@ void moveBall()
{ {
xb = WIDTH - 4; xb = WIDTH - 4;
dx = -dx; dx = -dx;
playTone(toneEdge, toneTimeBeep); playTone(523, 250);
} }
//Bounce off paddle //Bounce off paddle
@ -251,17 +229,16 @@ void moveBall()
dy = -dy; dy = -dy;
dx = ((xb-(xPaddle+6))/3); //Applies spin on the ball dx = ((xb-(xPaddle+6))/3); //Applies spin on the ball
// prevent straight bounce // prevent straight bounce
if (dx == 0) if (dx == 0) {
{ dx = (random(0,2) == 1) ? 1 : -1;
dx = (random(0, 2) == 1) ? 1 : -1;
} }
playTone(tonePaddle, toneTimeBeep); playTone(200, 250);
} }
//Bounce off Bricks //Bounce off Bricks
for (byte row = 0; row < rows; row++) for (byte row = 0; row < ROWS; row++)
{ {
for (byte column = 0; column < columns; column++) for (byte column = 0; column < COLUMNS; column++)
{ {
if (!isHit[row][column]) if (!isHit[row][column])
{ {
@ -271,14 +248,14 @@ void moveBall()
topBrick = 6 * row + 1; topBrick = 6 * row + 1;
bottomBrick = 6 * row + 7; bottomBrick = 6 * row + 7;
//If A collision has occurred //If A collison has occured
if (topBall <= bottomBrick && bottomBall >= topBrick && if (topBall <= bottomBrick && bottomBall >= topBrick &&
leftBall <= rightBrick && rightBall >= leftBrick) leftBall <= rightBrick && rightBall >= leftBrick)
{ {
Score(); Score();
brickCount++; brickCount++;
isHit[row][column] = true; isHit[row][column] = true;
arduboy.drawRect(10*column, 2+6*row, 8, 4, BLACK); arduboy.drawRect(10*column, 2+6*row, 8, 4, 0);
//Vertical collision //Vertical collision
if (bottomBall > bottomBrick || topBall < topBrick) if (bottomBall > bottomBrick || topBall < topBrick)
@ -289,11 +266,11 @@ void moveBall()
dy =- dy; dy =- dy;
yb += dy; yb += dy;
bounced = true; bounced = true;
playTone(toneBrick, toneTimeBeep); playTone(261, 250);
} }
} }
//Horizontal collision //Hoizontal collision
if (leftBall < leftBrick || rightBall > rightBrick) if (leftBall < leftBrick || rightBall > rightBrick)
{ {
//Only bounce once brick each ball move //Only bounce once brick each ball move
@ -302,7 +279,7 @@ void moveBall()
dx =- dx; dx =- dx;
xb += dx; xb += dx;
bounced = true; bounced = true;
playTone(toneBrick, toneTimeBeep); playTone(261, 250);
} }
} }
} }
@ -341,32 +318,35 @@ void moveBall()
void drawBall() void drawBall()
{ {
arduboy.drawPixel(xb, yb, BLACK); // arduboy.setCursor(0,0);
arduboy.drawPixel(xb+1, yb, BLACK); // arduboy.print(arduboy.cpuLoad());
arduboy.drawPixel(xb, yb+1, BLACK); // arduboy.print(" ");
arduboy.drawPixel(xb+1, yb+1, BLACK); 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(); moveBall();
arduboy.drawPixel(xb, yb, WHITE); arduboy.drawPixel(xb, yb, 1);
arduboy.drawPixel(xb+1, yb, WHITE); arduboy.drawPixel(xb+1, yb, 1);
arduboy.drawPixel(xb, yb+1, WHITE); arduboy.drawPixel(xb, yb+1, 1);
arduboy.drawPixel(xb+1, yb+1, WHITE); arduboy.drawPixel(xb+1, yb+1, 1);
} }
void drawPaddle() void drawPaddle()
{ {
arduboy.drawRect(xPaddle, 63, 11, 1, BLACK); arduboy.drawRect(xPaddle, 63, 11, 1, 0);
movePaddle(); movePaddle();
arduboy.drawRect(xPaddle, 63, 11, 1, WHITE); arduboy.drawRect(xPaddle, 63, 11, 1, 1);
} }
void drawGameOver() void drawGameOver()
{ {
arduboy.drawPixel(xb, yb, BLACK); arduboy.drawPixel(xb, yb, 0);
arduboy.drawPixel(xb+1, yb, BLACK); arduboy.drawPixel(xb+1, yb, 0);
arduboy.drawPixel(xb, yb+1, BLACK); arduboy.drawPixel(xb, yb+1, 0);
arduboy.drawPixel(xb+1, yb+1, BLACK); arduboy.drawPixel(xb+1, yb+1, 0);
arduboy.setCursor(37, 42); arduboy.setCursor(37, 42);
arduboy.print("Game Over"); arduboy.print("Game Over");
arduboy.setCursor(31, 56); arduboy.setCursor(31, 56);
@ -379,8 +359,6 @@ void drawGameOver()
void pause() void pause()
{ {
paused = true; paused = true;
//Stop tone if playing
beep.noTone();
//Draw pause to the screen //Draw pause to the screen
arduboy.setCursor(52, 45); arduboy.setCursor(52, 45);
arduboy.print("PAUSE"); arduboy.print("PAUSE");
@ -392,7 +370,7 @@ void pause()
pad2 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON); pad2 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
if (pad2 == true && oldpad2 == false && released) if (pad2 == true && oldpad2 == false && released)
{ {
arduboy.fillRect(52, 45, 30, 11, BLACK); arduboy.fillRect(52, 45, 30, 11, 0);
paused=false; paused=false;
} }
@ -405,16 +383,15 @@ void Score()
score += (level*10); score += (level*10);
} }
void newLevel() void newLevel(){
{
//Undraw paddle //Undraw paddle
arduboy.drawRect(xPaddle, 63, 11, 1, BLACK); arduboy.drawRect(xPaddle, 63, 11, 1, 0);
//Undraw ball //Undraw ball
arduboy.drawPixel(xb, yb, BLACK); arduboy.drawPixel(xb, yb, 0);
arduboy.drawPixel(xb+1, yb, BLACK); arduboy.drawPixel(xb+1, yb, 0);
arduboy.drawPixel(xb, yb+1, BLACK); arduboy.drawPixel(xb, yb+1, 0);
arduboy.drawPixel(xb+1, yb+1, BLACK); arduboy.drawPixel(xb+1, yb+1, 0);
//Alter various variables to reset the game //Alter various variables to reset the game
xPaddle = 54; xPaddle = 54;
@ -423,23 +400,15 @@ void newLevel()
released = false; released = false;
//Draws new bricks and resets their values //Draws new bricks and resets their values
for (byte row = 0; row < 4; row++) for (byte row = 0; row < 4; row++) {
{
for (byte column = 0; column < 13; column++) for (byte column = 0; column < 13; column++)
{ {
isHit[row][column] = false; isHit[row][column] = false;
arduboy.drawRect(10*column, 2+6*row, 8, 4, WHITE); arduboy.drawRect(10*column, 2+6*row, 8, 4, 1);
} }
} }
if (!initialDraw) arduboy.display();
{
arduboy.clear();
}
else
{
arduboy.display();
}
} }
//Used to delay images while reading button input //Used to delay images while reading button input
@ -459,7 +428,7 @@ boolean pollFireButton(int n)
return false; return false;
} }
//Function by nootropic design to display high scores //Function by nootropic design to display highscores
boolean displayHighScores(byte file) boolean displayHighScores(byte file)
{ {
byte y = 8; byte y = 8;
@ -476,7 +445,7 @@ boolean displayHighScores(byte file)
for(int i = 0; i < 7; i++) for(int i = 0; i < 7; i++)
{ {
sprintf(text_buffer, "%2d", i+1); sprintf(text_buffer, "%2d", i+1);
arduboy.setCursor(x, y+(i*8)); arduboy.setCursor(x,y+(i*8));
arduboy.print(text_buffer); arduboy.print(text_buffer);
arduboy.display(); arduboy.display();
hi = EEPROM.read(address + (5*i)); hi = EEPROM.read(address + (5*i));
@ -515,7 +484,7 @@ boolean titleScreen()
{ {
//Clears the screen //Clears the screen
arduboy.clear(); arduboy.clear();
arduboy.setCursor(16, 22); arduboy.setCursor(16,22);
arduboy.setTextSize(2); arduboy.setTextSize(2);
arduboy.print("BREAKOUT"); arduboy.print("BREAKOUT");
arduboy.setTextSize(1); arduboy.setTextSize(1);
@ -568,7 +537,7 @@ void enterInitials()
arduboy.display(); arduboy.display();
arduboy.clear(); arduboy.clear();
arduboy.setCursor(16, 0); arduboy.setCursor(16,0);
arduboy.print("HIGH SCORE"); arduboy.print("HIGH SCORE");
sprintf(text_buffer, "%u", score); sprintf(text_buffer, "%u", score);
arduboy.setCursor(88, 0); arduboy.setCursor(88, 0);
@ -581,10 +550,10 @@ void enterInitials()
arduboy.print(initials[2]); arduboy.print(initials[2]);
for(byte i = 0; i < 3; i++) for(byte i = 0; i < 3; i++)
{ {
arduboy.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, WHITE); arduboy.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1);
} }
arduboy.drawLine(56, 28, 88, 28, BLACK); arduboy.drawLine(56, 28, 88, 28, 0);
arduboy.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, WHITE); arduboy.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, 1);
arduboy.delayShort(70); arduboy.delayShort(70);
if (arduboy.pressed(LEFT_BUTTON) || arduboy.pressed(B_BUTTON)) if (arduboy.pressed(LEFT_BUTTON) || arduboy.pressed(B_BUTTON))
@ -592,7 +561,7 @@ void enterInitials()
if (index > 0) if (index > 0)
{ {
index--; index--;
playToneTimed(toneInitialsMove, toneTimeInitials); playToneTimed(1046, 80);
} }
} }
@ -601,14 +570,14 @@ void enterInitials()
if (index < 2) if (index < 2)
{ {
index++; index++;
playToneTimed(toneInitialsMove, toneTimeInitials); playToneTimed(1046, 80);
} }
} }
if (arduboy.pressed(UP_BUTTON)) if (arduboy.pressed(UP_BUTTON))
{ {
initials[index]++; initials[index]++;
playToneTimed(toneInitialsChange, toneTimeInitials); playToneTimed(523, 80);
// A-Z 0-9 :-? !-/ ' ' // A-Z 0-9 :-? !-/ ' '
if (initials[index] == '0') if (initials[index] == '0')
{ {
@ -631,34 +600,28 @@ void enterInitials()
if (arduboy.pressed(DOWN_BUTTON)) if (arduboy.pressed(DOWN_BUTTON))
{ {
initials[index]--; initials[index]--;
playToneTimed(toneInitialsChange, toneTimeInitials); playToneTimed(523, 80);
if (initials[index] == ' ') if (initials[index] == ' ') {
{
initials[index] = '?'; initials[index] = '?';
} }
if (initials[index] == '/') if (initials[index] == '/') {
{
initials[index] = 'Z'; initials[index] = 'Z';
} }
if (initials[index] == 31) if (initials[index] == 31) {
{
initials[index] = '/'; initials[index] = '/';
} }
if (initials[index] == '@') if (initials[index] == '@') {
{
initials[index] = ' '; initials[index] = ' ';
} }
} }
if (arduboy.pressed(A_BUTTON)) if (arduboy.pressed(A_BUTTON))
{ {
playToneTimed(toneInitialsMove, toneTimeInitials); playToneTimed(1046, 80);
if (index < 2) if (index < 2)
{ {
index++; index++;
} } else {
else
{
return; return;
} }
} }
@ -685,8 +648,7 @@ void enterHighScore(byte file)
// The values are uninitialized, so treat this entry // The values are uninitialized, so treat this entry
// as a score of 0. // as a score of 0.
tmpScore = 0; tmpScore = 0;
} } else
else
{ {
tmpScore = (hi << 8) | lo; tmpScore = (hi << 8) | lo;
} }
@ -736,19 +698,18 @@ void enterHighScore(byte file)
} }
} }
// Play a tone at a frequency corresponding to the specified precomputed count, // Play a tone at the specified frequency for the specified duration.
// for the specified number of frames. void playTone(unsigned int frequency, unsigned int duration)
void playTone(uint16_t count, uint8_t frames)
{ {
beep.tone(count, frames); beep.tone(beep.freq(frequency), duration / (1000 / FRAME_RATE));
} }
// Play a tone at a frequency corresponding to the specified precomputed count, // Play a tone at the specified frequency for the specified duration using
// for the specified duration in milliseconds, using a delay. // a delay to time the tone.
// Used when beep.timer() isn't being called. // Used when beep.timer() isn't being called.
void playToneTimed(uint16_t count, uint16_t duration) void playToneTimed(unsigned int frequency, unsigned int duration)
{ {
beep.tone(count); beep.tone(beep.freq(frequency));
arduboy.delayShort(duration); arduboy.delayShort(duration);
beep.noTone(); beep.noTone();
} }

View File

@ -1,19 +1,11 @@
/* /*
BeepDemo.ino
This sketch provides an example of using the Arduboy2 library's BeepPin1 class This sketch provides an example of using the Arduboy2 library's BeepPin1 class
to play simple tones. to play simple tones.
*/ */
/* /*
Written in 2018 by Scott Allen saydisp-git@yahoo.ca To the extent possible under law, Scott Allen has waived all copyright and
related or neighboring rights to this BeepDemo program.
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/ */
// Comments are only provided for code dealing with tone generation or control. // Comments are only provided for code dealing with tone generation or control.
@ -52,8 +44,6 @@ void loop() {
arduboy.pollButtons(); arduboy.pollButtons();
arduboy.clear();
if (arduboy.justPressed(LEFT_BUTTON)) { if (arduboy.justPressed(LEFT_BUTTON)) {
// Play a 523.251Hz tone (piano note C5) for 5 frames (200ms at 25 FPS) // 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.freq(523.251) is used to convert 523.251Hz to the required count
@ -129,7 +119,7 @@ void loop() {
objectX = 0; objectX = 0;
} }
arduboy.display(); arduboy.display(CLEAR_BUFFER);
} }
void commandText(const char* text) { void commandText(const char* text) {

View File

@ -1,122 +0,0 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -22,10 +22,10 @@ char title[] = "Press Buttons!";
byte x; byte x;
byte y; byte y;
// Width of each character including inter-character space // Width of each charcter including inter-character space
#define CHAR_WIDTH 6 #define CHAR_WIDTH 6
// Height of each character // Height of each charater
#define CHAR_HEIGHT 8 #define CHAR_HEIGHT 8
// To get the number of characters, we subtract 1 from the length of // To get the number of characters, we subtract 1 from the length of
@ -49,7 +49,7 @@ void setup() {
//initiate arduboy instance //initiate arduboy instance
arduboy.begin(); arduboy.begin();
// here we set the frame rate to 30, we do not need to run at default 60 and // here we set the framerate to 30, we do not need to run at default 60 and
// it saves us battery life. // it saves us battery life.
arduboy.setFrameRate(30); arduboy.setFrameRate(30);
@ -101,6 +101,6 @@ void loop() {
// then we print to screen what is stored in our title variable we declared earlier // then we print to screen what is stored in our title variable we declared earlier
arduboy.print(title); arduboy.print(title);
// then we finally we tell the arduboy to display what we just wrote to the display. // then we finaly we tell the arduboy to display what we just wrote to the display.
arduboy.display(); arduboy.display();
} }

View File

@ -1,4 +1,4 @@
Buttons Buttons
======= =======
An example that demonstrates how to capture input from the buttons. A an example that demonstrates how to capture input from the buttons.

View File

@ -1,122 +0,0 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -1,127 +0,0 @@
/*
FontDemo.ino
This sketch draws all the characters of the library's font as a 16 x 16 block.
The bottom half of the block will be initially off screen. An information
overlay will be drawn on top of the block showing the X and Y cursor position
of the start of the block, the current text wrap state and the current text
raw mode state.
The block can be moved around and off the screen using the direction buttons,
to view all the characters and show how the wrap and raw modes behave.
Controls:
Direction Buttons: Move the block 1 pixel.
Hold A with Direction Buttons: Continuously move the block.
B Button: Toggle text raw mode on and off.
Hold A, press B: Toggle text wrap mode on and off.
*/
/*
Written in September 2020 by Scott Allen saydisp-git@yahoo.ca
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <Arduboy2.h>
Arduboy2 arduboy;
constexpr uint8_t charWidth = arduboy.getCharacterWidth() + arduboy.getCharacterSpacing();
constexpr uint8_t charHeight = arduboy.getCharacterHeight() + arduboy.getLineSpacing();
constexpr uint16_t infoX = charWidth * 8;
constexpr uint16_t infoY = charHeight * 2;
constexpr uint8_t infoWidth = charWidth * 5;
constexpr uint8_t infoBorder = 1;
int16_t xPos = 0;
int16_t yPos = 0;
void setup() {
arduboy.begin();
arduboy.setFrameRate(20);
arduboy.clear();
arduboy.print(F("DISPLAY AND MOVE FONT\n\n"
" Dpad: move 1\n"
"A + Dpad: repeat move\n"
" B: toggle raw\n"
" A + B: toggle wrap\n\n"
" Press A to start"));
arduboy.display();
while (!arduboy.pressed(A_BUTTON)) {
arduboy.idle();
}
}
void loop() {
if (!arduboy.nextFrame()) {
return;
}
arduboy.pollButtons();
if (arduboy.justPressed(B_BUTTON)) {
if (arduboy.pressed(A_BUTTON)) {
arduboy.setTextWrap(!arduboy.getTextWrap());
}
else {
arduboy.setTextRawMode(!arduboy.getTextRawMode());
}
}
if (arduboy.justPressed(UP_BUTTON) ||
arduboy.pressed(UP_BUTTON + A_BUTTON)) {
--yPos;
}
if (arduboy.justPressed(DOWN_BUTTON) ||
arduboy.pressed(DOWN_BUTTON + A_BUTTON)) {
++yPos;
}
if (arduboy.justPressed(LEFT_BUTTON) ||
arduboy.pressed(LEFT_BUTTON | A_BUTTON)) {
--xPos;
}
if (arduboy.justPressed(RIGHT_BUTTON) ||
arduboy.pressed(RIGHT_BUTTON | A_BUTTON)) {
++xPos;
}
arduboy.clear();
char code = 0;
for (uint8_t i = 0; i < 16; ++i) {
arduboy.setCursor(xPos, yPos + (charHeight * i));
for (uint8_t j = 0; j < 16; ++j) {
arduboy.print(code);
++code;
}
}
arduboy.fillRect(infoX - infoBorder, infoY - infoBorder,
infoWidth + infoBorder, charHeight * 4 + infoBorder);
arduboy.setTextColor(BLACK);
arduboy.setTextBackground(WHITE);
arduboy.setCursor(infoX, infoY);
arduboy.print(F("X:"));
arduboy.print(xPos);
arduboy.setCursor(infoX, infoY + charHeight);
arduboy.print(F("Y:"));
arduboy.print(yPos);
arduboy.setCursor(infoX, infoY + (charHeight * 2));
arduboy.print(F("W:"));
arduboy.print(arduboy.getTextWrap() ? F("Yes") : F("No"));
arduboy.setCursor(infoX, infoY + (charHeight * 3));
arduboy.print(F("R:"));
arduboy.print(arduboy.getTextRawMode() ? F("Yes") : F("No"));
arduboy.setTextColor(WHITE);
arduboy.setTextBackground(BLACK);
arduboy.display();
}

View File

@ -23,7 +23,7 @@ void setup() {
// initiate arduboy instance // initiate arduboy instance
arduboy.begin(); arduboy.begin();
// here we set the frame rate to 15, we do not need to run at // here we set the framerate to 15, we do not need to run at
// default 60 and it saves us battery life // default 60 and it saves us battery life
arduboy.setFrameRate(15); arduboy.setFrameRate(15);
} }
@ -46,6 +46,6 @@ void loop() {
// then we print to screen what is in the Quotation marks "" // then we print to screen what is in the Quotation marks ""
arduboy.print(F("Hello, world!")); arduboy.print(F("Hello, world!"));
// then we finally we tell the arduboy to display what we just wrote to the display // then we finaly we tell the arduboy to display what we just wrote to the display
arduboy.display(); arduboy.display();
} }

View File

@ -1,122 +0,0 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -1,19 +1,11 @@
/* /*
RGBled
This sketch demonstrates controlling the Arduboy's RGB LED, This sketch demonstrates controlling the Arduboy's RGB LED,
in both analog and digital modes. in both analog and digital modes.
*/ */
/* /*
Written in 2018 by Scott Allen saydisp-git@yahoo.ca To the extent possible under law, Scott Allen has waived all copyright and
related or neighboring rights to this BeepDemo program.
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
*/ */
#include <Arduboy2.h> #include <Arduboy2.h>
@ -321,7 +313,7 @@ void drawBar(int y, Color color, byte value) {
} }
} }
// Draw the information for one digital color // Draw the informaton for one digital color
void drawDigital(int y, Color color, const char* name) { void drawDigital(int y, Color color, const char* name) {
byte state = digitalState[(byte)color]; byte state = digitalState[(byte)color];

View File

@ -18,9 +18,6 @@ This sketch allows manipulation of the following values in system EEPROM:
should be displayed at the end of the boot logo sequence in circumstances should be displayed at the end of the boot logo sequence in circumstances
where it's possible to do so. where it's possible to do so.
- The "Show RGB LEDs with Boot Logo" flag. This flag indicates whether or not
to flash the RGB LEDs while the boot logo is scrolling down.
- The "Show Boot Logo" flag. This flag indicates whether or not to display - The "Show Boot Logo" flag. This flag indicates whether or not to display
the boot logo sequence during start up. the boot logo sequence during start up.
@ -33,11 +30,11 @@ This sketch also allows:
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
*/ */
// Version 2.2 // Version 1.0
/* /*
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Copyright (c) 2018-2020, Scott Allen Copyright (c) 2018, Scott Allen
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -69,23 +66,25 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <EEPROM.h> #include <EEPROM.h>
// The frame rate determines the button auto-repeat rate for unit name entry // The frame rate determines the button auto-repeat rate for unit name entry
constexpr uint8_t frameRate = 10; #define FRAME_RATE 10
// The unit ID auto-repeat rate is slowed, compared to the unit name rate, by // The unit ID auto-repeat rate is slowed, compared to the unit name rate, by
// repeating only once per the defined number of frames // repeating only once per the defined number of frames
constexpr unsigned int idRepeatFrames = 3; #define ID_REPEAT_FRAMES 3
// Delay time before button auto-repeat starts, in milliseconds // Delay time before button auto-repeat starts, in milliseconds
constexpr unsigned int repeatDelay = 700; #define REPEAT_DELAY 700
// All the constant stings // All the constant stings
const char StrName[] PROGMEM = "NAME"; const char StrName[] PROGMEM = "NAME";
const char StrID[] PROGMEM = "ID"; const char StrID[] PROGMEM = "ID";
const char StrFlags[] PROGMEM = "FLAGS";
const char StrYes[] PROGMEM = "YES"; const char StrYes[] PROGMEM = "YES";
const char StrNo[] PROGMEM = "NO"; const char StrNo[] PROGMEM = "NO";
const char StrSaveQ[] PROGMEM = "SAVE?"; const char StrSaveQ[] PROGMEM = "SAVE?";
const char StrSaved[] PROGMEM = "SAVED"; const char StrSaved[] PROGMEM = "SAVED";
const char StrShowNameQ1[] PROGMEM = "LEFT:show unit name";
const char StrShowNameQ2[] PROGMEM = "on logo screen?";
const char StrShowLogoQ[] PROGMEM = "RIGHT:show boot logo?";
const char StrBtnChangeName[] PROGMEM = "UP:change Unit Name"; const char StrBtnChangeName[] PROGMEM = "UP:change Unit Name";
const char StrBtnChangeID[] PROGMEM = "DOWN:change Unit ID"; const char StrBtnChangeID[] PROGMEM = "DOWN:change Unit ID";
const char StrBtnFlags[] PROGMEM = "LEFT:flags"; const char StrBtnFlags[] PROGMEM = "LEFT:flags";
@ -94,10 +93,7 @@ const char StrBtnMenu[] PROGMEM = "A:menu";
const char StrBtnSave[] PROGMEM = "B:save"; const char StrBtnSave[] PROGMEM = "B:save";
const char StrBtnYes[] PROGMEM = "A:yes"; const char StrBtnYes[] PROGMEM = "A:yes";
const char StrBtnNo[] PROGMEM = "B:no"; const char StrBtnNo[] PROGMEM = "B:no";
const char StrShowLogoQ[] PROGMEM = "show boot logo?"; const char StrBtnTestLogo[] PROGMEM = "DOWN:test boot logo";
const char StrShowLEDsQ[] PROGMEM = "show boot LEDs?";
const char StrShowNameQ[] PROGMEM = "show unit name?";
const char StrBtnTestLogo[] PROGMEM = "UP+DOWN:test logo";
const char StrNoLogo1[] PROGMEM = "\"SHOW BOOT LOGO\""; const char StrNoLogo1[] PROGMEM = "\"SHOW BOOT LOGO\"";
const char StrNoLogo2[] PROGMEM = "flag is OFF"; const char StrNoLogo2[] PROGMEM = "flag is OFF";
const char StrBtnResetSys[] PROGMEM = "UP:reset system"; const char StrBtnResetSys[] PROGMEM = "UP:reset system";
@ -119,20 +115,24 @@ const char StrReset[] PROGMEM = "RESET";
const char StrHex[] PROGMEM = "hex"; const char StrHex[] PROGMEM = "hex";
const char StrDecimal[] PROGMEM = "decimal"; const char StrDecimal[] PROGMEM = "decimal";
#define CHAR_WIDTH 6
#define CHAR_HEIGHT 8
#define SMALL_SPACE 4 // The number of pixels for a small space between groups
// Defines for text and field locations // Defines for text and field locations
#define MENU_BTN_CHANGE_NAME_X centerStr_P(StrBtnChangeName) #define MENU_BTN_CHANGE_NAME_X centerStr_P(StrBtnChangeName)
#define MENU_BTN_CHANGE_NAME_Y 0 #define MENU_BTN_CHANGE_NAME_Y 0
#define MENU_NAME_X centerStrLen(ARDUBOY_UNIT_NAME_LEN) #define MENU_NAME_X centerStrLen(ARDUBOY_UNIT_NAME_LEN)
#define MENU_NAME_Y (MENU_BTN_CHANGE_NAME_Y + charHeight + 3) #define MENU_NAME_Y (MENU_BTN_CHANGE_NAME_Y + CHAR_HEIGHT + 3)
#define MENU_BTN_CHANGE_ID_X centerStr_P(StrBtnChangeID) #define MENU_BTN_CHANGE_ID_X centerStr_P(StrBtnChangeID)
#define MENU_BTN_CHANGE_ID_Y 26 #define MENU_BTN_CHANGE_ID_Y 26
#define MENU_HEADING_HEX_X (centerStr_P(StrHex) - (WIDTH / 4)) #define MENU_HEADING_HEX_X (centerStr_P(StrHex) - (WIDTH / 4))
#define MENU_HEADING_DECIMAL_X (centerStr_P(StrDecimal) + (WIDTH / 4)) #define MENU_HEADING_DECIMAL_X (centerStr_P(StrDecimal) + (WIDTH / 4))
#define MENU_HEADINGS_Y (MENU_BTN_CHANGE_ID_Y + charHeight + 1) #define MENU_HEADINGS_Y (MENU_BTN_CHANGE_ID_Y + CHAR_HEIGHT + 1)
#define MENU_ID_HEX_X (centerStrLen(5) - (WIDTH / 4)) #define MENU_ID_HEX_X (centerStrLen(5) - (WIDTH / 4))
#define MENU_ID_DECIMAL_X (centerStrLen(5) + (WIDTH / 4)) #define MENU_ID_DECIMAL_X (centerStrLen(5) + (WIDTH / 4))
#define MENU_ID_Y (MENU_HEADINGS_Y + charHeight + 1) #define MENU_ID_Y (MENU_HEADINGS_Y + CHAR_HEIGHT + 1)
#define MENU_BTN_FLAGS_X 0 #define MENU_BTN_FLAGS_X 0
#define MENU_BTN_FLAGS_Y 56 #define MENU_BTN_FLAGS_Y 56
@ -161,9 +161,9 @@ const char StrDecimal[] PROGMEM = "decimal";
#define NAME_BTN_NO_X rightStr_P(StrBtnNo) #define NAME_BTN_NO_X rightStr_P(StrBtnNo)
#define NAME_BTN_NO_Y NAME_BTN_YES_Y #define NAME_BTN_NO_Y NAME_BTN_YES_Y
#define NAME_SAVE_Q_X (centerStr_P(StrSaveQ) - ((6 * charWidth) + (charWidth / 2))) #define NAME_SAVE_Q_X (centerStr_P(StrSaveQ) - ((6 * CHAR_WIDTH) + (CHAR_WIDTH / 2)))
#define NAME_SAVE_Q_Y (NAME_LARGE_Y + (charHeight / 2) + 3) #define NAME_SAVE_Q_Y (NAME_LARGE_Y + (CHAR_HEIGHT / 2) + 3)
#define NAME_SAVE_X (NAME_SAVE_Q_X + ((strlen_P(StrSaveQ) * charWidth) + charWidth)) #define NAME_SAVE_X (NAME_SAVE_Q_X + ((strlen_P(StrSaveQ) * CHAR_WIDTH) + CHAR_WIDTH))
#define NAME_SAVE_Y (NAME_LARGE_Y + 3) #define NAME_SAVE_Y (NAME_LARGE_Y + 3)
@ -180,7 +180,7 @@ const char StrDecimal[] PROGMEM = "decimal";
#define ID_2_DECIMAL_X 12 #define ID_2_DECIMAL_X 12
#define ID_2_DECIMAL_Y 38 #define ID_2_DECIMAL_Y 38
#define ID_DECIMAL_X (WIDTH - (charWidth * 5 + 12)) #define ID_DECIMAL_X (WIDTH - (CHAR_WIDTH * 5 + 12))
#define ID_DECIMAL_Y ID_2_DECIMAL_Y #define ID_DECIMAL_Y ID_2_DECIMAL_Y
#define ID_BINARY_X 0 #define ID_BINARY_X 0
@ -191,99 +191,101 @@ const char StrDecimal[] PROGMEM = "decimal";
#define ID_BTN_NO_X rightStr_P(StrBtnNo) #define ID_BTN_NO_X rightStr_P(StrBtnNo)
#define ID_BTN_NO_Y ID_BTN_YES_Y #define ID_BTN_NO_Y ID_BTN_YES_Y
#define ID_SAVE_Q_X (centerStr_P(StrSaveQ) - ((5 * charWidth) + (charWidth / 2))) #define ID_SAVE_Q_X (centerStr_P(StrSaveQ) - ((5 * CHAR_WIDTH) + (CHAR_WIDTH / 2)))
#define ID_SAVE_Q_Y (ID_LARGE_Y + (charHeight / 2) + 1) #define ID_SAVE_Q_Y (ID_LARGE_Y + (CHAR_HEIGHT / 2) + 1)
#define ID_SAVE_X (ID_SAVE_Q_X + ((strlen_P(StrSaveQ) * charWidth) + charWidth)) #define ID_SAVE_X (ID_SAVE_Q_X + ((strlen_P(StrSaveQ) * CHAR_WIDTH) + CHAR_WIDTH))
#define ID_SAVE_Y (ID_LARGE_Y + 1) #define ID_SAVE_Y (ID_LARGE_Y + 1)
#define FLAGS_TITLE_X centerStr_P(StrFlags)
#define FLAGS_TITLE_Y 0
#define FLAGS_BTN_MENU_X 0 #define FLAGS_BTN_MENU_X 0
#define FLAGS_BTN_MENU_Y 0 #define FLAGS_BTN_MENU_Y 0
#define FLAGS_BTN_SAVE_X rightStr_P(StrBtnSave) #define FLAGS_BTN_SAVE_X rightStr_P(StrBtnSave)
#define FLAGS_BTN_SAVE_Y FLAGS_BTN_MENU_Y #define FLAGS_BTN_SAVE_Y FLAGS_BTN_MENU_Y
#define FLAGS_NAME_Q_1_X centerStr_P(StrShowNameQ1)
#define FLAGS_LOGO_Y 14 #define FLAGS_NAME_Q_1_Y 9
#define FLAGS_LEDS_Y 27 #define FLAGS_NAME_Q_2_X centerStr_P(StrShowNameQ2)
#define FLAGS_NAME_Y 40 #define FLAGS_NAME_Q_2_Y (FLAGS_NAME_Q_1_Y + 8)
#define FLAGS_NAME_YES_X ((WIDTH / 2) - ((strlen_P(StrYes) + 1) * CHAR_WIDTH))
#define FLAGS_Q_X (charWidth * 2) #define FLAGS_NAME_YES_Y (FLAGS_NAME_Q_2_Y + CHAR_HEIGHT)
#define FLAGS_SET_X rightStr_P(StrYes) #define FLAGS_NAME_NO_X ((WIDTH / 2) + (CHAR_WIDTH))
#define FLAGS_CURSOR_X 0 #define FLAGS_NAME_NO_Y FLAGS_NAME_YES_Y
#define FLAGS_LOGO_Q_X centerStr_P(StrShowLogoQ)
#define FLAGS_LOGO_Q_Y 37
#define FLAGS_LOGO_YES_X ((WIDTH / 2) - ((strlen_P(StrYes) + 1) * CHAR_WIDTH))
#define FLAGS_LOGO_YES_Y FLAGS_LOGO_Q_Y + CHAR_HEIGHT
#define FLAGS_LOGO_NO_X ((WIDTH / 2) + (CHAR_WIDTH))
#define FLAGS_LOGO_NO_Y FLAGS_LOGO_YES_Y
#define FLAGS_TEST_X centerStr_P(StrBtnTestLogo) #define FLAGS_TEST_X centerStr_P(StrBtnTestLogo)
#define FLAGS_TEST_Y 56 #define FLAGS_TEST_Y 56
#define FLAGS_SAVED_X centerStr2_P(StrSaved) #define FLAGS_SAVED_X centerStr2_P(StrSaved)
#define FLAGS_SAVED_Y ((HEIGHT / 2) - (char2Height / 2)) #define FLAGS_SAVED_Y ((HEIGHT / 2) - CHAR_HEIGHT)
#define FLAGS_NO_LOGO_1_X centerStr_P(StrNoLogo1) #define FLAGS_NO_LOGO_1_X centerStr_P(StrNoLogo1)
#define FLAGS_NO_LOGO_1_Y ((HEIGHT / 2) - charHeight - 1) #define FLAGS_NO_LOGO_1_Y ((HEIGHT / 2) - CHAR_HEIGHT - 1)
#define FLAGS_NO_LOGO_2_X centerStr_P(StrNoLogo2) #define FLAGS_NO_LOGO_2_X centerStr_P(StrNoLogo2)
#define FLAGS_NO_LOGO_2_Y (FLAGS_NO_LOGO_1_Y + charHeight + 2) #define FLAGS_NO_LOGO_2_Y (FLAGS_NO_LOGO_1_Y + CHAR_HEIGHT + 2)
#define RESET_BTN_MENU_X centerStr_P(StrBtnMenu) #define RESET_BTN_MENU_X centerStr_P(StrBtnMenu)
#define RESET_BTN_MENU_Y 0 #define RESET_BTN_MENU_Y 0
#define RESET_BTN_SYS_X centerStr_P(StrBtnResetSys) #define RESET_BTN_SYS_X centerStr_P(StrBtnResetSys)
#define RESET_BTN_SYS_Y 16 #define RESET_BTN_SYS_Y 16
#define RESET_BTN_SYS_EEPROM_X centerStr_P(StrEEPROM) #define RESET_BTN_SYS_EEPROM_X centerStr_P(StrEEPROM)
#define RESET_BTN_SYS_EEPROM_Y (RESET_BTN_SYS_Y + charHeight) #define RESET_BTN_SYS_EEPROM_Y (RESET_BTN_SYS_Y + CHAR_HEIGHT)
#define RESET_BTN_USER_X centerStr_P(StrBtnResetUser) #define RESET_BTN_USER_X centerStr_P(StrBtnResetUser)
#define RESET_BTN_USER_Y 40 #define RESET_BTN_USER_Y 40
#define RESET_BTN_USER_EEPROM_X centerStr_P(StrEEPROM) #define RESET_BTN_USER_EEPROM_X centerStr_P(StrEEPROM)
#define RESET_BTN_USER_EEPROM_Y (RESET_BTN_USER_Y + charHeight) #define RESET_BTN_USER_EEPROM_Y (RESET_BTN_USER_Y + CHAR_HEIGHT)
#define RESET_SYS_TEXT_1_X centerStr_P(StrResetSys1) #define RESET_SYS_TEXT_1_X centerStr_P(StrResetSys1)
#define RESET_SYS_TEXT_1_Y 0 #define RESET_SYS_TEXT_1_Y 0
#define RESET_SYS_TEXT_2_X centerStr_P(StrResetSys2) #define RESET_SYS_TEXT_2_X centerStr_P(StrResetSys2)
#define RESET_SYS_TEXT_2_Y (RESET_SYS_TEXT_1_Y + charHeight) #define RESET_SYS_TEXT_2_Y (RESET_SYS_TEXT_1_Y + CHAR_HEIGHT)
#define RESET_SYS_TEXT_3_X centerStr_P(StrResetSys3) #define RESET_SYS_TEXT_3_X centerStr_P(StrResetSys3)
#define RESET_SYS_TEXT_3_Y (RESET_SYS_TEXT_2_Y + charHeight) #define RESET_SYS_TEXT_3_Y (RESET_SYS_TEXT_2_Y + CHAR_HEIGHT)
#define RESET_SYS_SURE_Q_X centerStr_P(StrAreYouSureQ) #define RESET_SYS_SURE_Q_X centerStr_P(StrAreYouSureQ)
#define RESET_SYS_SURE_Q_Y 32 #define RESET_SYS_SURE_Q_Y 32
#define RESET_SYS_BTN_YES_X centerStr_P(StrBtnResetYes) #define RESET_SYS_BTN_YES_X centerStr_P(StrBtnResetYes)
#define RESET_SYS_BTN_YES_Y 48 #define RESET_SYS_BTN_YES_Y 48
#define RESET_SYS_BTN_NO_X centerStr_P(StrBtnResetYes) #define RESET_SYS_BTN_NO_X centerStr_P(StrBtnResetYes)
#define RESET_SYS_BTN_NO_Y (RESET_SYS_BTN_YES_Y + charHeight) #define RESET_SYS_BTN_NO_Y (RESET_SYS_BTN_YES_Y + CHAR_HEIGHT)
#define RESET_SYS_CONFIRMED_1_X centerStr2_P(StrSystem) #define RESET_SYS_CONFIRMED_1_X centerStr2_P(StrSystem)
#define RESET_SYS_CONFIRMED_1_Y 7 #define RESET_SYS_CONFIRMED_1_Y 7
#define RESET_SYS_CONFIRMED_2_X centerStr2_P(StrEEPROM) #define RESET_SYS_CONFIRMED_2_X centerStr2_P(StrEEPROM)
#define RESET_SYS_CONFIRMED_2_Y (RESET_SYS_CONFIRMED_1_Y + char2Height + 2) #define RESET_SYS_CONFIRMED_2_Y (RESET_SYS_CONFIRMED_1_Y + (CHAR_HEIGHT * 2) + 2)
#define RESET_SYS_CONFIRMED_3_X centerStr2_P(StrReset) #define RESET_SYS_CONFIRMED_3_X centerStr2_P(StrReset)
#define RESET_SYS_CONFIRMED_3_Y (RESET_SYS_CONFIRMED_2_Y + char2Height + 2) #define RESET_SYS_CONFIRMED_3_Y (RESET_SYS_CONFIRMED_2_Y + (CHAR_HEIGHT * 2) + 2)
#define RESET_USER_TEXT_1_X centerStr_P(StrResetUser1) #define RESET_USER_TEXT_1_X centerStr_P(StrResetUser1)
#define RESET_USER_TEXT_1_Y 0 #define RESET_USER_TEXT_1_Y 0
#define RESET_USER_TEXT_2_X centerStr_P(StrResetUser2) #define RESET_USER_TEXT_2_X centerStr_P(StrResetUser2)
#define RESET_USER_TEXT_2_Y (RESET_USER_TEXT_1_Y + charHeight) #define RESET_USER_TEXT_2_Y (RESET_USER_TEXT_1_Y + CHAR_HEIGHT)
#define RESET_USER_TEXT_3_X centerStr_P(StrResetUser3) #define RESET_USER_TEXT_3_X centerStr_P(StrResetUser3)
#define RESET_USER_TEXT_3_Y (RESET_USER_TEXT_2_Y + charHeight) #define RESET_USER_TEXT_3_Y (RESET_USER_TEXT_2_Y + CHAR_HEIGHT)
#define RESET_USER_SURE_Q_X centerStr_P(StrAreYouSureQ) #define RESET_USER_SURE_Q_X centerStr_P(StrAreYouSureQ)
#define RESET_USER_SURE_Q_Y 32 #define RESET_USER_SURE_Q_Y 32
#define RESET_USER_BTN_YES_X centerStr_P(StrBtnResetYes) #define RESET_USER_BTN_YES_X centerStr_P(StrBtnResetYes)
#define RESET_USER_BTN_YES_Y 48 #define RESET_USER_BTN_YES_Y 48
#define RESET_USER_BTN_NO_X centerStr_P(StrBtnResetYes) #define RESET_USER_BTN_NO_X centerStr_P(StrBtnResetYes)
#define RESET_USER_BTN_NO_Y (RESET_USER_BTN_YES_Y + charHeight) #define RESET_USER_BTN_NO_Y (RESET_USER_BTN_YES_Y + CHAR_HEIGHT)
#define RESET_USER_CONFIRMED_1_X centerStr2_P(StrUser) #define RESET_USER_CONFIRMED_1_X centerStr2_P(StrUser)
#define RESET_USER_CONFIRMED_1_Y 7 #define RESET_USER_CONFIRMED_1_Y 7
#define RESET_USER_CONFIRMED_2_X centerStr2_P(StrEEPROM) #define RESET_USER_CONFIRMED_2_X centerStr2_P(StrEEPROM)
#define RESET_USER_CONFIRMED_2_Y (RESET_USER_CONFIRMED_1_Y + char2Height + 2) #define RESET_USER_CONFIRMED_2_Y (RESET_USER_CONFIRMED_1_Y + (CHAR_HEIGHT * 2) + 2)
#define RESET_USER_CONFIRMED_3_X centerStr2_P(StrReset) #define RESET_USER_CONFIRMED_3_X centerStr2_P(StrReset)
#define RESET_USER_CONFIRMED_3_Y (RESET_USER_CONFIRMED_2_Y + char2Height + 2) #define RESET_USER_CONFIRMED_3_Y (RESET_USER_CONFIRMED_2_Y + (CHAR_HEIGHT * 2) + 2)
#define RESET_USER_WRITING_X centerStr2_P(StrWriting) #define RESET_USER_WRITING_X centerStr2_P(StrWriting)
#define RESET_USER_WRITING_Y ((HEIGHT / 2) - (char2Height / 2 - 1)) #define RESET_USER_WRITING_Y ((HEIGHT / 2) - (CHAR_HEIGHT - 1))
// EEPROM addresses // EEPROM addresses
constexpr unsigned int EEPROMstart = 0x0000; #define EEPROM_START (0x0000)
constexpr unsigned int EEPROMsize = 1024; #define EEPROM_SIZE (1024)
constexpr unsigned int EEPROMend = EEPROMstart + EEPROMsize - 1; #define EEPROM_END (EEPROM_START + EEPROM_SIZE - 1)
// Calculation of the number of frames to wait before button auto-repeat starts // Calculation of the number of frames to wait before button auto-repeat starts
constexpr unsigned int delayFrames = repeatDelay / (1000 / frameRate); #define DELAY_FRAMES (REPEAT_DELAY / (1000 / FRAME_RATE))
// The Arduino "magic" has trouble creating prototypes for functions called // The Arduino "magic" has trouble creating prototypes for functions called
// by pointers, so they're declared here manually // by pointers, so they're declared here manually
@ -294,39 +296,17 @@ void screenSaveName(), screenSaveID(), screenResetSys(), screenResetUser();
Arduboy2 arduboy; Arduboy2 arduboy;
constexpr uint8_t charSpacing = arduboy.getCharacterSpacing(1); char unitName[ARDUBOY_UNIT_NAME_LEN + 1];
constexpr uint8_t char2Spacing = arduboy.getCharacterSpacing(2); byte nameIndex;
constexpr uint8_t charWidth = arduboy.getCharacterWidth(1) + charSpacing;
constexpr uint8_t char2Width = arduboy.getCharacterWidth(2) + char2Spacing;
constexpr uint8_t charHeight = arduboy.getCharacterHeight(1) +
arduboy.getLineSpacing(1);
constexpr uint8_t char2Height = arduboy.getCharacterHeight(2) +
arduboy.getLineSpacing(2);
// The number of pixels for a small space between groups
constexpr uint8_t smallSpace = 4;
char unitName[ARDUBOY_UNIT_NAME_BUFFER_SIZE];
uint8_t nameIndex;
uint16_t unitID; uint16_t unitID;
uint8_t idIndex; byte idIndex;
bool showLogoFlag; boolean showNameFlag;
bool showLEDsFlag; boolean showLogoFlag;
bool showNameFlag;
// Selected flag
enum class SelectedFlag : uint8_t {
selFlagLogo,
selFlagLEDs,
selFlagName
};
SelectedFlag currentFlag;
// Assign numbers for each state/screen // Assign numbers for each state/screen
enum class State : uint8_t { enum State : byte {
sMain, sMain,
sName, sName,
sID, sID,
@ -339,10 +319,10 @@ enum class State : uint8_t {
sMAX = sResetUser sMAX = sResetUser
}; };
State currentState; byte currentState;
// Function pointer array for button handling // Function pointer array for button handling
void (*stateFunc[static_cast<uint8_t>(State::sMAX) + 1])() = { void (*stateFunc[sMAX + 1])() = {
stateMain, stateMain,
stateName, stateName,
stateID, stateID,
@ -355,7 +335,7 @@ void (*stateFunc[static_cast<uint8_t>(State::sMAX) + 1])() = {
}; };
// Function pointer array for screen drawing // Function pointer array for screen drawing
void (*screenFunc[static_cast<uint8_t>(State::sMAX) + 1])() = { void (*screenFunc[sMAX + 1])() = {
screenMain, screenMain,
screenName, screenName,
screenID, screenID,
@ -368,14 +348,14 @@ void (*screenFunc[static_cast<uint8_t>(State::sMAX) + 1])() = {
}; };
unsigned int delayCount = 0; unsigned int delayCount = 0;
bool repeating = false; boolean repeating = false;
// ============================= SETUP =================================== // ============================= SETUP ===================================
void setup() { void setup() {
arduboy.begin(); arduboy.begin();
arduboy.setFrameRate(frameRate); arduboy.setFrameRate(FRAME_RATE);
setState(State::sMain); setState(sMain);
} }
// ======================================================================= // =======================================================================
@ -388,7 +368,7 @@ void loop() {
arduboy.pollButtons(); arduboy.pollButtons();
(*stateFunc[static_cast<uint8_t>(currentState)])(); (*stateFunc[currentState])();
if ((delayCount != 0) && (--delayCount == 0)) { if ((delayCount != 0) && (--delayCount == 0)) {
repeating = true; repeating = true;
@ -401,7 +381,7 @@ void loop() {
// Set to the given state and display the screen for that state // Set to the given state and display the screen for that state
// Can be called with the current state to update the current screen // Can be called with the current state to update the current screen
void setState(State newState) { void setState(byte newState) {
currentState = newState; currentState = newState;
stopButtonRepeat(); stopButtonRepeat();
drawScreen(); drawScreen();
@ -410,16 +390,16 @@ void setState(State newState) {
// STATE: Main selection screen // STATE: Main selection screen
void stateMain() { void stateMain() {
if (arduboy.justPressed(UP_BUTTON)) { if (arduboy.justPressed(UP_BUTTON)) {
setState(State::sName); setState(sName);
} }
else if (arduboy.justPressed(DOWN_BUTTON)) { else if (arduboy.justPressed(DOWN_BUTTON)) {
setState(State::sID); setState(sID);
} }
else if (arduboy.justPressed(LEFT_BUTTON)) { else if (arduboy.justPressed(LEFT_BUTTON)) {
setState(State::sFlags); setState(sFlags);
} }
else if (arduboy.justPressed(RIGHT_BUTTON)) { else if (arduboy.justPressed(RIGHT_BUTTON)) {
setState(State::sReset); setState(sReset);
} }
} }
@ -446,10 +426,10 @@ void stateName() {
nameCursorLeft(); nameCursorLeft();
} }
else if (arduboy.justPressed(A_BUTTON)) { else if (arduboy.justPressed(A_BUTTON)) {
setState(State::sMain); setState(sMain);
} }
else if (arduboy.justPressed(B_BUTTON)) { else if (arduboy.justPressed(B_BUTTON)) {
setState(State::sSaveName); setState(sSaveName);
} }
else if (repeating) { else if (repeating) {
stopButtonRepeat(); stopButtonRepeat();
@ -467,12 +447,12 @@ void stateID() {
startButtonDelay(); startButtonDelay();
} }
else if (repeating && arduboy.pressed(UP_BUTTON)) { else if (repeating && arduboy.pressed(UP_BUTTON)) {
if (arduboy.everyXFrames(idRepeatFrames)) { if (arduboy.everyXFrames(ID_REPEAT_FRAMES)) {
idDigitInc(); idDigitInc();
} }
} }
else if (repeating && arduboy.pressed(DOWN_BUTTON)) { else if (repeating && arduboy.pressed(DOWN_BUTTON)) {
if (arduboy.everyXFrames(idRepeatFrames)) { if (arduboy.everyXFrames(ID_REPEAT_FRAMES)) {
idDigitDec(); idDigitDec();
} }
} }
@ -483,10 +463,10 @@ void stateID() {
idCursorLeft(); idCursorLeft();
} }
else if (arduboy.justPressed(A_BUTTON)) { else if (arduboy.justPressed(A_BUTTON)) {
setState(State::sMain); setState(sMain);
} }
else if (arduboy.justPressed(B_BUTTON)) { else if (arduboy.justPressed(B_BUTTON)) {
setState(State::sSaveID); setState(sSaveID);
} }
else if (repeating) { else if (repeating) {
stopButtonRepeat(); stopButtonRepeat();
@ -495,47 +475,41 @@ void stateID() {
// STATE: Set system flags // STATE: Set system flags
void stateFlags() { void stateFlags() {
if (arduboy.pressed(UP_BUTTON + DOWN_BUTTON)) { if (arduboy.justPressed(LEFT_BUTTON)) {
showNameToggle();
}
else if (arduboy.justPressed(RIGHT_BUTTON)) {
showLogoToggle();
}
else if (arduboy.justPressed(A_BUTTON)) {
setState(sMain);
}
else if (arduboy.justPressed(B_BUTTON)) {
saveFlags();
setState(sFlags);
}
else if (arduboy.justPressed(DOWN_BUTTON)) {
showNameFlag = arduboy.readShowUnitNameFlag(); showNameFlag = arduboy.readShowUnitNameFlag();
showLEDsFlag = arduboy.readShowBootLogoLEDsFlag();
if ((showLogoFlag = arduboy.readShowBootLogoFlag()) == true) { if ((showLogoFlag = arduboy.readShowBootLogoFlag()) == true) {
arduboy.bootLogo(); arduboy.bootLogo();
} }
else { else {
displayNoLogo(); displayNoLogo();
} }
currentFlag = SelectedFlag::selFlagLogo; setState(sFlags);
setState(State::sFlags);
}
else if (arduboy.justPressed(UP_BUTTON)) {
flagsCursorUp();
}
else if (arduboy.justPressed(DOWN_BUTTON)) {
flagsCursorDown();
}
else if (arduboy.justPressed(RIGHT_BUTTON) ||
arduboy.justPressed(LEFT_BUTTON)) {
flagToggle();
}
else if (arduboy.justPressed(A_BUTTON)) {
setState(State::sMain);
}
else if (arduboy.justPressed(B_BUTTON)) {
saveFlags();
setState(State::sFlags);
} }
} }
// STATE: Reset EEPROM areas // STATE: Reset EEPROM areas
void stateReset() { void stateReset() {
if (arduboy.justPressed(UP_BUTTON)) { if (arduboy.justPressed(UP_BUTTON)) {
setState(State::sResetSys); setState(sResetSys);
} }
else if (arduboy.justPressed(DOWN_BUTTON)) { else if (arduboy.justPressed(DOWN_BUTTON)) {
setState(State::sResetUser); setState(sResetUser);
} }
else if (arduboy.justPressed(A_BUTTON)) { else if (arduboy.justPressed(A_BUTTON)) {
setState(State::sMain); setState(sMain);
} }
} }
@ -543,10 +517,10 @@ void stateReset() {
void stateSaveName() { void stateSaveName() {
if (arduboy.justPressed(A_BUTTON)) { if (arduboy.justPressed(A_BUTTON)) {
arduboy.writeUnitName(unitName); arduboy.writeUnitName(unitName);
setState(State::sMain); setState(sMain);
} }
else if (arduboy.justPressed(B_BUTTON)) { else if (arduboy.justPressed(B_BUTTON)) {
setState(State::sName); setState(sName);
} }
} }
@ -554,10 +528,10 @@ void stateSaveName() {
void stateSaveID() { void stateSaveID() {
if (arduboy.justPressed(A_BUTTON)) { if (arduboy.justPressed(A_BUTTON)) {
arduboy.writeUnitID(unitID); arduboy.writeUnitID(unitID);
setState(State::sMain); setState(sMain);
} }
else if (arduboy.justPressed(B_BUTTON)) { else if (arduboy.justPressed(B_BUTTON)) {
setState(State::sID); setState(sID);
} }
} }
@ -565,13 +539,13 @@ void stateSaveID() {
void stateResetSys() { void stateResetSys() {
if (arduboy.justPressed(B_BUTTON) && arduboy.pressed(A_BUTTON)) { if (arduboy.justPressed(B_BUTTON) && arduboy.pressed(A_BUTTON)) {
resetSysEEPROM(); resetSysEEPROM();
setState(State::sReset); setState(sReset);
} }
else if (arduboy.justPressed(UP_BUTTON) || else if (arduboy.justPressed(UP_BUTTON) ||
arduboy.justPressed(DOWN_BUTTON) || arduboy.justPressed(DOWN_BUTTON) ||
arduboy.justPressed(RIGHT_BUTTON) || arduboy.justPressed(RIGHT_BUTTON) ||
arduboy.justPressed(LEFT_BUTTON)) { arduboy.justPressed(LEFT_BUTTON)) {
setState(State::sReset); setState(sReset);
} }
} }
@ -579,13 +553,13 @@ void stateResetSys() {
void stateResetUser() { void stateResetUser() {
if (arduboy.justPressed(B_BUTTON) && arduboy.pressed(A_BUTTON)) { if (arduboy.justPressed(B_BUTTON) && arduboy.pressed(A_BUTTON)) {
resetUserEEPROM(); resetUserEEPROM();
setState(State::sReset); setState(sReset);
} }
else if (arduboy.justPressed(UP_BUTTON) || else if (arduboy.justPressed(UP_BUTTON) ||
arduboy.justPressed(DOWN_BUTTON) || arduboy.justPressed(DOWN_BUTTON) ||
arduboy.justPressed(RIGHT_BUTTON) || arduboy.justPressed(RIGHT_BUTTON) ||
arduboy.justPressed(LEFT_BUTTON)) { arduboy.justPressed(LEFT_BUTTON)) {
setState(State::sReset); setState(sReset);
} }
} }
@ -594,7 +568,7 @@ void stateResetUser() {
// Display the screen for the current state // Display the screen for the current state
void drawScreen() { void drawScreen() {
arduboy.clear(); arduboy.clear();
(*screenFunc[static_cast<uint8_t>(currentState)])(); (*screenFunc[currentState])();
arduboy.display(); arduboy.display();
} }
@ -602,7 +576,6 @@ void drawScreen() {
void screenMain() { void screenMain() {
readEEPROM(); readEEPROM();
nameIndex = idIndex = 0; nameIndex = idIndex = 0;
currentFlag = SelectedFlag::selFlagLogo;
printStr_P(MENU_BTN_CHANGE_NAME_X, MENU_BTN_CHANGE_NAME_Y, StrBtnChangeName); printStr_P(MENU_BTN_CHANGE_NAME_X, MENU_BTN_CHANGE_NAME_Y, StrBtnChangeName);
printName(MENU_NAME_X, MENU_NAME_Y); printName(MENU_NAME_X, MENU_NAME_Y);
@ -640,11 +613,15 @@ void screenID() {
void screenFlags() { void screenFlags() {
printStr_P(FLAGS_BTN_MENU_X, FLAGS_BTN_MENU_Y, StrBtnMenu); printStr_P(FLAGS_BTN_MENU_X, FLAGS_BTN_MENU_Y, StrBtnMenu);
printStr_P(FLAGS_BTN_SAVE_X, FLAGS_BTN_SAVE_Y, StrBtnSave); printStr_P(FLAGS_BTN_SAVE_X, FLAGS_BTN_SAVE_Y, StrBtnSave);
printStr_P(FLAGS_TITLE_X, FLAGS_TITLE_Y, StrFlags); printStr_P(FLAGS_NAME_Q_1_X, FLAGS_NAME_Q_1_Y, StrShowNameQ1);
printStr_P(FLAGS_Q_X, FLAGS_LOGO_Y, StrShowLogoQ); printStr_P(FLAGS_NAME_Q_2_X, FLAGS_NAME_Q_2_Y, StrShowNameQ2);
printStr_P(FLAGS_Q_X, FLAGS_LEDS_Y, StrShowLEDsQ); printStr_P(FLAGS_NAME_YES_X, FLAGS_NAME_YES_Y, StrYes);
printStr_P(FLAGS_Q_X, FLAGS_NAME_Y, StrShowNameQ); printStr_P(FLAGS_NAME_NO_X, FLAGS_NAME_NO_Y, StrNo);
printFlagSettings(); printShowNameCursor();
printStr_P(FLAGS_LOGO_Q_X, FLAGS_LOGO_Q_Y, StrShowLogoQ);
printStr_P(FLAGS_LOGO_YES_X, FLAGS_LOGO_YES_Y, StrYes);
printStr_P(FLAGS_LOGO_NO_X, FLAGS_LOGO_NO_Y, StrNo);
printShowLogoCursor();
printStr_P(FLAGS_TEST_X, FLAGS_TEST_Y, StrBtnTestLogo); printStr_P(FLAGS_TEST_X, FLAGS_TEST_Y, StrBtnTestLogo);
} }
@ -675,7 +652,7 @@ void screenSaveID() {
printIDLarge(ID_SAVE_X, ID_SAVE_Y); printIDLarge(ID_SAVE_X, ID_SAVE_Y);
} }
// DISPLAY: Prompt to reset the system EEPROM area // DISPLAY: Propmt to reset the system EEPROM area
void screenResetSys() { void screenResetSys() {
printStr_P(RESET_SYS_TEXT_1_X, RESET_SYS_TEXT_1_Y, StrResetSys1); printStr_P(RESET_SYS_TEXT_1_X, RESET_SYS_TEXT_1_Y, StrResetSys1);
printStr_P(RESET_SYS_TEXT_2_X, RESET_SYS_TEXT_2_Y, StrResetSys2); printStr_P(RESET_SYS_TEXT_2_X, RESET_SYS_TEXT_2_Y, StrResetSys2);
@ -685,7 +662,7 @@ void screenResetSys() {
printStr_P(RESET_SYS_BTN_NO_X, RESET_SYS_BTN_NO_Y, StrBtnResetNo); printStr_P(RESET_SYS_BTN_NO_X, RESET_SYS_BTN_NO_Y, StrBtnResetNo);
} }
// DISPLAY: Prompt to reset the user EEPROM area // DISPLAY: Propmt to reset the user EEPROM area
void screenResetUser() { void screenResetUser() {
printStr_P(RESET_USER_TEXT_1_X, RESET_USER_TEXT_1_Y, StrResetUser1); printStr_P(RESET_USER_TEXT_1_X, RESET_USER_TEXT_1_Y, StrResetUser1);
printStr_P(RESET_USER_TEXT_2_X, RESET_USER_TEXT_2_Y, StrResetUser2); printStr_P(RESET_USER_TEXT_2_X, RESET_USER_TEXT_2_Y, StrResetUser2);
@ -708,7 +685,6 @@ void displayNoLogo() {
void saveFlags() { void saveFlags() {
arduboy.writeShowUnitNameFlag(showNameFlag); arduboy.writeShowUnitNameFlag(showNameFlag);
arduboy.writeShowBootLogoFlag(showLogoFlag); arduboy.writeShowBootLogoFlag(showLogoFlag);
arduboy.writeShowBootLogoLEDsFlag(showLEDsFlag);
printStrLargeRev_P(FLAGS_SAVED_X, FLAGS_SAVED_Y, StrSaved); printStrLargeRev_P(FLAGS_SAVED_X, FLAGS_SAVED_Y, StrSaved);
arduboy.display(); arduboy.display();
arduboy.delayShort(1500); arduboy.delayShort(1500);
@ -716,7 +692,7 @@ void saveFlags() {
// Reset the system EEPROM area and display the confirmation message // Reset the system EEPROM area and display the confirmation message
void resetSysEEPROM() { void resetSysEEPROM() {
for (unsigned int i = EEPROMstart; i < EEPROM_STORAGE_SPACE_START; i++) { for (unsigned int i = EEPROM_START; i < EEPROM_STORAGE_SPACE_START; i++) {
EEPROM.update(i, 0xFF); EEPROM.update(i, 0xFF);
} }
arduboy.clear(); arduboy.clear();
@ -734,7 +710,7 @@ void resetUserEEPROM() {
printStr_P(RESET_USER_WRITING_X, RESET_USER_WRITING_Y, StrWriting); printStr_P(RESET_USER_WRITING_X, RESET_USER_WRITING_Y, StrWriting);
arduboy.setTextSize(1); arduboy.setTextSize(1);
arduboy.display(CLEAR_BUFFER); arduboy.display(CLEAR_BUFFER);
for (unsigned int i = EEPROM_STORAGE_SPACE_START; i <= EEPROMend; i++) { for (unsigned int i = EEPROM_STORAGE_SPACE_START; i <= EEPROM_END; i++) {
EEPROM.update(i, 0xFF); EEPROM.update(i, 0xFF);
} }
printStrLargeRev_P(RESET_USER_CONFIRMED_1_X, RESET_USER_CONFIRMED_1_Y, StrUser); printStrLargeRev_P(RESET_USER_CONFIRMED_1_X, RESET_USER_CONFIRMED_1_Y, StrUser);
@ -753,7 +729,7 @@ void printNameScreenCommon() {
printNameDecimal(NAME_DECIMAL_X, NAME_DECIMAL_Y); printNameDecimal(NAME_DECIMAL_X, NAME_DECIMAL_Y);
} }
// Print the ID entry screen common information // Print the name entry screen common information
void printIDScreenCommon() { void printIDScreenCommon() {
printStr_P(ID_TITLE_X, ID_TITLE_Y, StrID); printStr_P(ID_TITLE_X, ID_TITLE_Y, StrID);
printIDDecimalBytes(ID_2_DECIMAL_X, ID_2_DECIMAL_Y); printIDDecimalBytes(ID_2_DECIMAL_X, ID_2_DECIMAL_Y);
@ -763,92 +739,59 @@ void printIDScreenCommon() {
// Print the name screen cursors // Print the name screen cursors
void printNameCursors() { void printNameCursors() {
arduboy.fillRect(NAME_LARGE_X + (nameIndex * char2Width), arduboy.fillRect(NAME_LARGE_X + (nameIndex * CHAR_WIDTH * 2),
NAME_LARGE_Y + char2Height + 2, NAME_LARGE_Y + (CHAR_HEIGHT * 2) + 2,
char2Width - char2Spacing, 2); (CHAR_WIDTH * 2) - 2, 2);
arduboy.drawFastHLine(NAME_HEX_X + arduboy.drawFastHLine(NAME_HEX_X +
(nameIndex * (charWidth * 3 + smallSpace)), (nameIndex * (CHAR_WIDTH * 3 + SMALL_SPACE)),
NAME_HEX_Y + charHeight + 1, NAME_HEX_Y + CHAR_HEIGHT + 1, CHAR_WIDTH * 3 - 1);
charWidth * 3 - charSpacing);
arduboy.drawFastHLine(NAME_DECIMAL_X + arduboy.drawFastHLine(NAME_DECIMAL_X +
(nameIndex * (charWidth * 3 + smallSpace)), (nameIndex * (CHAR_WIDTH * 3 + SMALL_SPACE)),
NAME_DECIMAL_Y + charHeight + 1, NAME_DECIMAL_Y + CHAR_HEIGHT + 1, CHAR_WIDTH * 3 - 1);
charWidth * 3 - charSpacing);
} }
// Print the ID screen cursors // Print the ID screen cursors
void printIDCursors() { void printIDCursors() {
arduboy.fillRect(ID_LARGE_X + ((idIndex + 1) * char2Width), arduboy.fillRect(ID_LARGE_X + ((idIndex + 1) * (CHAR_WIDTH * 2)),
ID_LARGE_Y + char2Height, ID_LARGE_Y + (CHAR_HEIGHT * 2),
char2Width - char2Spacing, 2); (CHAR_WIDTH * 2) - 2, 2);
arduboy.drawFastHLine(ID_2_DECIMAL_X + arduboy.drawFastHLine(ID_2_DECIMAL_X +
((idIndex / 2) * (charWidth * 3 + smallSpace)), ((idIndex / 2) * (CHAR_WIDTH * 3 + SMALL_SPACE)),
ID_2_DECIMAL_Y + charHeight + 1, ID_2_DECIMAL_Y + CHAR_HEIGHT + 1, CHAR_WIDTH * 3 - 1);
charWidth * 3 - charSpacing);
arduboy.drawFastHLine(ID_DECIMAL_X, ID_DECIMAL_Y + charHeight + 1, arduboy.drawFastHLine(ID_DECIMAL_X, ID_DECIMAL_Y + CHAR_HEIGHT + 1,
charWidth * 5 - 1); CHAR_WIDTH * 5 - 1);
arduboy.drawFastHLine((ID_BINARY_X + charWidth + smallSpace) + arduboy.drawFastHLine((ID_BINARY_X + CHAR_WIDTH + SMALL_SPACE) +
(idIndex * (charWidth * 4 + smallSpace)), (idIndex * (CHAR_WIDTH * 4 + SMALL_SPACE)),
ID_BINARY_Y + charHeight + 1, ID_BINARY_Y + CHAR_HEIGHT + 1, CHAR_WIDTH * 4 - 1);
charWidth * 4 - charSpacing);
} }
// Print the values and cursor for the flags // Print the current "Show Unit Name" cursor
void printFlagSettings() { void printShowNameCursor() {
int cursorY;
uint8_t cursorLen = strlen_P(StrYes) * charWidth - charSpacing;
if (showLogoFlag) {
printStr_P(FLAGS_SET_X, FLAGS_LOGO_Y, StrYes);
}
else {
printStr_P(FLAGS_SET_X, FLAGS_LOGO_Y, StrNo);
}
if (showLEDsFlag) {
printStr_P(FLAGS_SET_X, FLAGS_LEDS_Y, StrYes);
}
else {
printStr_P(FLAGS_SET_X, FLAGS_LEDS_Y, StrNo);
}
if (showNameFlag) { if (showNameFlag) {
printStr_P(FLAGS_SET_X, FLAGS_NAME_Y, StrYes); arduboy.drawFastHLine(FLAGS_NAME_YES_X, FLAGS_NAME_YES_Y + (CHAR_HEIGHT),
(strlen_P(StrYes) * CHAR_WIDTH - 1));
} }
else { else {
printStr_P(FLAGS_SET_X, FLAGS_NAME_Y, StrNo); arduboy.drawFastHLine(FLAGS_NAME_NO_X, FLAGS_NAME_NO_Y + (CHAR_HEIGHT),
(strlen_P(StrNo) * CHAR_WIDTH - 1));
} }
switch (currentFlag) {
case SelectedFlag::selFlagLEDs:
cursorY = FLAGS_LEDS_Y;
if (!showLEDsFlag) {
cursorLen = strlen_P(StrNo) * charWidth - charSpacing;
}
break;
case SelectedFlag::selFlagName:
cursorY = FLAGS_NAME_Y;
if (!showNameFlag) {
cursorLen = strlen_P(StrNo) * charWidth - charSpacing;
}
break;
default: // selFlagLogo
cursorY = FLAGS_LOGO_Y;
if (!showLogoFlag) {
cursorLen = strlen_P(StrNo) * charWidth - charSpacing;
}
break;
} }
arduboy.setCursor(FLAGS_CURSOR_X, cursorY); // Print the current "Show boot logo" cursor
arduboy.print('\x10'); void printShowLogoCursor() {
if (showLogoFlag) {
arduboy.drawFastHLine(FLAGS_SET_X, cursorY + charHeight, cursorLen); arduboy.drawFastHLine(FLAGS_LOGO_YES_X, FLAGS_LOGO_YES_Y + (CHAR_HEIGHT),
(strlen_P(StrYes) * CHAR_WIDTH - 1));
}
else {
arduboy.drawFastHLine(FLAGS_LOGO_NO_X, FLAGS_LOGO_NO_Y + (CHAR_HEIGHT),
(strlen_P(StrNo) * CHAR_WIDTH - 1));
}
} }
// Print the unit name in normal size including an extent underline // Print the unit name in normal size including an extent underline
@ -856,9 +799,9 @@ void printFlagSettings() {
void printName(int x, int y) { void printName(int x, int y) {
printStr(x, y, unitName); printStr(x, y, unitName);
y += (charHeight + 1); y += (CHAR_HEIGHT + 1);
for (uint8_t i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++, x += charWidth) { for (byte i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++, x += CHAR_WIDTH) {
arduboy.drawFastHLine(x, y, charWidth - charSpacing); arduboy.drawFastHLine(x, y, CHAR_WIDTH - 1);
} }
} }
@ -876,8 +819,8 @@ void printNameUnderline(int x, int y) {
if (unitName[0] != 0) { if (unitName[0] != 0) {
x -= 1; x -= 1;
y += (char2Height + 6); y += ((CHAR_HEIGHT * 2) + 6);
lWidth = (strlen(unitName) * char2Width); lWidth = (strlen(unitName) * (CHAR_WIDTH * 2));
arduboy.drawPixel(x, y); arduboy.drawPixel(x, y);
arduboy.drawPixel(x + lWidth - 1, y); arduboy.drawPixel(x + lWidth - 1, y);
arduboy.drawFastHLine(x, y + 1, lWidth); arduboy.drawFastHLine(x, y + 1, lWidth);
@ -886,17 +829,17 @@ void printNameUnderline(int x, int y) {
// Print the unit name in hex at the given location // Print the unit name in hex at the given location
void printNameHex(int x, int y) { void printNameHex(int x, int y) {
for (uint8_t i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++) { for (byte i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++) {
printHex8(x, y, unitName[i]); printHex8(x, y, unitName[i]);
x += charWidth * 3 + smallSpace; x += CHAR_WIDTH * 3 + SMALL_SPACE;
} }
} }
// Print the unit name in decimal at the given location // Print the unit name in decimal at the given location
void printNameDecimal(int x, int y) { void printNameDecimal(int x, int y) {
for (uint8_t i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++) { for (byte i = 0; i < ARDUBOY_UNIT_NAME_LEN; i++) {
printDecimal8(x, y, unitName[i]); printDecimal8(x, y, unitName[i]);
x += charWidth * 3 + smallSpace; x += CHAR_WIDTH * 3 + SMALL_SPACE;
} }
} }
@ -915,7 +858,7 @@ void printIDHex(int x, int y) {
// Print the unit ID as 2 decimal bytes at the given location // Print the unit ID as 2 decimal bytes at the given location
void printIDDecimalBytes(int x, int y) { void printIDDecimalBytes(int x, int y) {
printDecimal8(x, y, unitID >> 8); printDecimal8(x, y, unitID >> 8);
printDecimal8(x + charWidth * 3 + smallSpace, y, unitID & 0x00FF); printDecimal8(x + CHAR_WIDTH * 3 + SMALL_SPACE, y, unitID & 0x00FF);
} }
// Print the unit ID in decimal at the given location // Print the unit ID in decimal at the given location
@ -928,17 +871,17 @@ void printIDDecimal(int x, int y) {
void printIDBinary(int x, int y) { void printIDBinary(int x, int y) {
arduboy.setCursor(x, y); arduboy.setCursor(x, y);
arduboy.print('b'); arduboy.print('b');
x += charWidth + smallSpace; x += CHAR_WIDTH + SMALL_SPACE;
for (char i = 3 * 4; i >= 0; i -= 4) { for (char i = 3 * 4; i >= 0; i -= 4) {
printBinaryNybble(x, y, static_cast<uint8_t>(unitID >> i)); printBinaryNybble(x, y, (byte)(unitID >> i));
x += charWidth * 4 + smallSpace; x += CHAR_WIDTH * 4 + SMALL_SPACE;
} }
} }
// Print the save prompt in reverse at the given location // Print the save prompt in reverse at the given location
void printSavePrompt(int x, int y) { void printSavePrompt(int x, int y) {
arduboy.fillRect(x - 2, y - 2, arduboy.fillRect(x - 2, y - 2,
strlen_P(StrSaveQ) * charWidth + 3, charHeight + 3); strlen_P(StrSaveQ) * CHAR_WIDTH + 3, CHAR_HEIGHT + 3);
arduboy.setTextColor(BLACK); arduboy.setTextColor(BLACK);
arduboy.setTextBackground(WHITE); arduboy.setTextBackground(WHITE);
printStr_P(x, y, StrSaveQ); printStr_P(x, y, StrSaveQ);
@ -959,18 +902,18 @@ void printStr_P(int x, int y, const char* str) {
} }
// Print an 8 bit number in decimal, right justified with leading spaces // Print an 8 bit number in decimal, right justified with leading spaces
void printDecimal8(int x, int y, uint8_t val) { void printDecimal8(int x, int y, byte val) {
printDecimalHelper(x, y, 2, 100, val); printDecimalHelper(x, y, 2, 100, val);
} }
// Print a 16 bit number in decimal, right justified with leading spaces // Print a 16 bit number in decimal, right justified with leading spaces
void printDecimal16(int x, int y, uint16_t val) { void printDecimal16(int x, int y, unsigned int val) {
printDecimalHelper(x, y, 4, 10000, val); printDecimalHelper(x, y, 4, 10000, val);
} }
// Print a right justified decimal number, given width-1 and (width-1)^10 // Print a right justified decimal number, given width-1 and (width-1)^10
void printDecimalHelper(int x, int y, uint8_t width, uint16_t pwr10, void printDecimalHelper(int x, int y, byte width, unsigned int pwr10,
uint16_t val) { unsigned int val) {
arduboy.setCursor(x, y); arduboy.setCursor(x, y);
while (width > 0) { while (width > 0) {
if (val >= pwr10) { if (val >= pwr10) {
@ -984,7 +927,7 @@ void printDecimalHelper(int x, int y, uint8_t width, uint16_t pwr10,
} }
// Print an 8 bit hex number with leading x and zeros // Print an 8 bit hex number with leading x and zeros
void printHex8(int x, int y, uint8_t val) { void printHex8(int x, int y, byte val) {
arduboy.setCursor(x, y); arduboy.setCursor(x, y);
arduboy.print('x'); arduboy.print('x');
if (val < 16) { if (val < 16) {
@ -994,7 +937,7 @@ void printHex8(int x, int y, uint8_t val) {
} }
// Print a 16 bit hex number with leading x and zeros // Print a 16 bit hex number with leading x and zeros
void printHex16(int x, int y, uint16_t val) { void printHex16(int x, int y, unsigned int val) {
arduboy.setCursor(x, y); arduboy.setCursor(x, y);
arduboy.print('x'); arduboy.print('x');
for (char i = 3 * 4; i >= 0; i -= 4) { for (char i = 3 * 4; i >= 0; i -= 4) {
@ -1003,7 +946,7 @@ void printHex16(int x, int y, uint16_t val) {
} }
// Print a nybble in binary from the lowest 4 bits of the provided byte // Print a nybble in binary from the lowest 4 bits of the provided byte
void printBinaryNybble(int x, int y, uint8_t val) { void printBinaryNybble(int x, int y, byte val) {
arduboy.setCursor(x, y); arduboy.setCursor(x, y);
for (char i = 3; i >= 0; i--) { for (char i = 3; i >= 0; i--) {
@ -1014,7 +957,7 @@ void printBinaryNybble(int x, int y, uint8_t val) {
// Print a constant string in large size and reversed // Print a constant string in large size and reversed
void printStrLargeRev_P(int x, int y, const char* string) { void printStrLargeRev_P(int x, int y, const char* string) {
arduboy.fillRect(x - 4, y - 4, arduboy.fillRect(x - 4, y - 4,
strlen_P(string) * char2Width + 6, char2Height + 6); strlen_P(string) * CHAR_WIDTH * 2 + 6, CHAR_HEIGHT * 2 + 6);
arduboy.setTextColor(BLACK); arduboy.setTextColor(BLACK);
arduboy.setTextBackground(WHITE); arduboy.setTextBackground(WHITE);
arduboy.setTextSize(2); arduboy.setTextSize(2);
@ -1031,9 +974,8 @@ void readEEPROM() {
memset(unitName, 0, sizeof(unitName)); memset(unitName, 0, sizeof(unitName));
arduboy.readUnitName(unitName); arduboy.readUnitName(unitName);
unitID = arduboy.readUnitID(); unitID = arduboy.readUnitID();
showLogoFlag = arduboy.readShowBootLogoFlag();
showLEDsFlag = arduboy.readShowBootLogoLEDsFlag();
showNameFlag = arduboy.readShowUnitNameFlag(); showNameFlag = arduboy.readShowUnitNameFlag();
showLogoFlag = arduboy.readShowBootLogoFlag();
} }
// Increment the name character at the cursor position // Increment the name character at the cursor position
@ -1049,8 +991,8 @@ void nameCharDec() {
} }
// Return true if the given character is not allowed // Return true if the given character is not allowed
bool invalidChar(char c) { boolean invalidChar(char c) {
return (c == '\n') || (c == '\r') || (static_cast<uint8_t>(c) == 0xFF); return (c == '\n') || (c == '\r') || ((byte)c == 0xFF);
} }
// Move the name cursor right // Move the name cursor right
@ -1109,57 +1051,21 @@ void idCursorLeft() {
drawScreen(); drawScreen();
} }
// Move the Flags cursor down // Toggle the "Show Unit Name" selection
void flagsCursorDown() { void showNameToggle() {
switch (currentFlag) { showNameFlag = !showNameFlag;
case SelectedFlag::selFlagLogo:
currentFlag = SelectedFlag::selFlagLEDs;
break;
case SelectedFlag::selFlagLEDs:
currentFlag = SelectedFlag::selFlagName;
break;
case SelectedFlag::selFlagName:
currentFlag = SelectedFlag::selFlagLogo;
break;
}
drawScreen(); drawScreen();
} }
// Move the Flags cursor up // Toggle the "Show boot logo" selection
void flagsCursorUp() { void showLogoToggle() {
switch (currentFlag) { showLogoFlag = !showLogoFlag;
case SelectedFlag::selFlagName:
currentFlag = SelectedFlag::selFlagLEDs;
break;
case SelectedFlag::selFlagLEDs:
currentFlag = SelectedFlag::selFlagLogo;
break;
case SelectedFlag::selFlagLogo:
currentFlag = SelectedFlag::selFlagName;
break;
}
drawScreen();
}
// Toggle the currently selected flag
void flagToggle() {
switch (currentFlag) {
case SelectedFlag::selFlagLogo:
showLogoFlag = !showLogoFlag;
break;
case SelectedFlag::selFlagLEDs:
showLEDsFlag = !showLEDsFlag;
break;
case SelectedFlag::selFlagName:
showNameFlag = !showNameFlag;
break;
}
drawScreen(); drawScreen();
} }
// Start the button auto-repeat delay // Start the button auto-repeat delay
void startButtonDelay() { void startButtonDelay() {
delayCount = delayFrames; delayCount = DELAY_FRAMES;
repeating = false; repeating = false;
} }
@ -1171,22 +1077,22 @@ void stopButtonRepeat() {
// Calculate the X coordinate to center a string of the given length // Calculate the X coordinate to center a string of the given length
int centerStrLen(unsigned int len) { int centerStrLen(unsigned int len) {
return (WIDTH / 2) - (len * charWidth / 2); return (WIDTH / 2) - (len * CHAR_WIDTH / 2);
} }
// Calculate the X coordinate to center a string located in program memory // Calculate the X coordinate to center a string located in program memory
int centerStr_P(const char* str) { int centerStr_P(const char* str) {
return (WIDTH / 2) - (strlen_P(str) * charWidth / 2); return (WIDTH / 2) - (strlen_P(str) * CHAR_WIDTH / 2);
} }
// Calculate the X coordinate to center a size 2 string located in // Calculate the X coordinate to center a size 2 string located in
// program memory // program memory
int centerStr2_P(const char* str) { int centerStr2_P(const char* str) {
return (WIDTH / 2) - (strlen_P(str) * char2Width / 2); return (WIDTH / 2) - (strlen_P(str) * CHAR_WIDTH);
} }
// Calculate the X coordinate to right justify a string in program memory // Calculate the X coordinate to right justify a string in program memory
int rightStr_P(const char* str) { int rightStr_P(const char* str) {
return WIDTH - (strlen_P(str) * charWidth) + charSpacing; return WIDTH - (strlen_P(str) * CHAR_WIDTH) + 1;
} }

View File

@ -1,50 +1,59 @@
# Doxyfile 1.8.18 # 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 # Project related configuration options
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "Arduboy2 Library" PROJECT_NAME = "Arduboy2 Library"
PROJECT_NUMBER = 6.0.0 PROJECT_NUMBER =
PROJECT_BRIEF = PROJECT_BRIEF =
PROJECT_LOGO = PROJECT_LOGO =
OUTPUT_DIRECTORY = doxygen OUTPUT_DIRECTORY = ./doxygen
CREATE_SUBDIRS = NO CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English OUTPUT_LANGUAGE = English
OUTPUT_TEXT_DIRECTION = None
BRIEF_MEMBER_DESC = YES BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = ABBREVIATE_BRIEF =
ALWAYS_DETAILED_SEC = NO ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = YES INLINE_INHERITED_MEMB = YES
FULL_PATH_NAMES = YES FULL_PATH_NAMES = YES
STRIP_FROM_PATH = src STRIP_FROM_PATH =
STRIP_FROM_INC_PATH = STRIP_FROM_INC_PATH =
SHORT_NAMES = NO SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO JAVADOC_AUTOBRIEF = NO
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 2 TAB_SIZE = 2
ALIASES = ALIASES =
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO EXTENSION_MAPPING = ino=C++
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
AUTOLINK_SUPPORT = YES AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO INLINE_SIMPLE_STRUCTS = NO
@ -55,15 +64,14 @@ LOOKUP_CACHE_SIZE = 0
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
EXTRACT_ALL = NO EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO EXTRACT_PRIVATE = NO
EXTRACT_PRIV_VIRTUAL = NO
EXTRACT_PACKAGE = NO EXTRACT_PACKAGE = NO
EXTRACT_STATIC = YES EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_CLASSES = NO
EXTRACT_LOCAL_METHODS = NO EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = YES HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES CASE_SENSE_NAMES = YES
@ -99,18 +107,14 @@ WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES WARN_NO_PARAMDOC = YES
WARN_AS_ERROR = YES
WARN_FORMAT = "$file:$line: $text" WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE = WARN_LOGFILE =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the input files # Configuration options related to the input files
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
INPUT = src \ INPUT = ./src ./README.md ./LICENSE.txt
README.md \
LICENSE.txt
INPUT_ENCODING = UTF-8 INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.cpp \ FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ *.h *.hh *.hxx *.hpp *.h++
*.h
RECURSIVE = NO RECURSIVE = NO
EXCLUDE = EXCLUDE =
EXCLUDE_SYMLINKS = NO EXCLUDE_SYMLINKS = NO
@ -124,7 +128,7 @@ INPUT_FILTER =
FILTER_PATTERNS = FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS = FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = README.md USE_MDFILE_AS_MAINPAGE = ./README.md
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to source browsing # Configuration options related to source browsing
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -139,11 +143,10 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = NO CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS = CLANG_OPTIONS =
CLANG_DATABASE_PATH =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index # Configuration options related to the alphabetical class index
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5 COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX = IGNORE_PREFIX =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -161,7 +164,6 @@ HTML_COLORSTYLE_HUE = 245
HTML_COLORSTYLE_SAT = 90 HTML_COLORSTYLE_SAT = 90
HTML_COLORSTYLE_GAMMA = 95 HTML_COLORSTYLE_GAMMA = 95
HTML_TIMESTAMP = YES HTML_TIMESTAMP = YES
HTML_DYNAMIC_MENUS = NO
HTML_DYNAMIC_SECTIONS = YES HTML_DYNAMIC_SECTIONS = YES
HTML_INDEX_NUM_ENTRIES = 100 HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO GENERATE_DOCSET = NO
@ -191,13 +193,11 @@ GENERATE_TREEVIEW = YES
ENUM_VALUES_PER_LINE = 4 ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250 TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO EXT_LINKS_IN_WINDOW = NO
HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10 FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES FORMULA_TRANSPARENT = YES
FORMULA_MACROFILE =
USE_MATHJAX = NO USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_EXTENSIONS = MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE = MATHJAX_CODEFILE =
SEARCHENGINE = YES SEARCHENGINE = YES
@ -212,9 +212,8 @@ EXTRA_SEARCH_MAPPINGS =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
GENERATE_LATEX = YES GENERATE_LATEX = YES
LATEX_OUTPUT = latex LATEX_OUTPUT = latex
LATEX_CMD_NAME = LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO COMPACT_LATEX = NO
PAPER_TYPE = a4 PAPER_TYPE = a4
EXTRA_PACKAGES = EXTRA_PACKAGES =
@ -228,8 +227,6 @@ LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = YES
LATEX_EMOJI_DIRECTORY =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the RTF output # Configuration options related to the RTF output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -254,7 +251,6 @@ MAN_LINKS = NO
GENERATE_XML = NO GENERATE_XML = NO
XML_OUTPUT = xml XML_OUTPUT = xml
XML_PROGRAMLISTING = YES XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output # Configuration options related to the DOCBOOK output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -292,10 +288,12 @@ GENERATE_TAGFILE =
ALLEXTERNALS = NO ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the dot tool # Configuration options related to the dot tool
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES CLASS_DIAGRAMS = YES
MSCGEN_PATH =
DIA_PATH = DIA_PATH =
HIDE_UNDOC_RELATIONS = YES HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES HAVE_DOT = YES
@ -306,7 +304,7 @@ DOT_FONTPATH =
CLASS_GRAPH = YES CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES GROUP_GRAPHS = YES
UML_LOOK = NO UML_LOOK = YES
UML_LIMIT_NUM_FIELDS = 10 UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES INCLUDE_GRAPH = YES
@ -322,7 +320,6 @@ DOTFILE_DIRS =
MSCFILE_DIRS = MSCFILE_DIRS =
DIAFILE_DIRS = DIAFILE_DIRS =
PLANTUML_JAR_PATH = PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH = PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50 DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0 MAX_DOT_GRAPH_DEPTH = 0

BIN
extras/assets/arduboy_logo.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
extras/assets/arduboy_screen.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 B

After

Width:  |  Height:  |  Size: 434 B

View File

@ -1,122 +0,0 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.

View File

@ -1,206 +0,0 @@
# Cabi - Compress Arduboy Image
A command line program to read a PNG (Portable Network Graphics) file
containing a bitmap image, compress it using RLE encoding and convert it to
C/C++ code suitable for use with the Team A.R.G. *drawCompressed()* function.
This function is included in the Arduboy2 library.
Written by zep
https://www.lexaloffle.com/bbs/?uid=1
https://twitter.com/lexaloffle
Contributed to Team A.R.G.
This program uses code from the LodePNG project by Lode Vandevenne to read
and decode PNG files.
https://github.com/lvandeve/lodepng
This version of Cabi is maintained as part of the Arduboy2 library so that it
remains available since the demise of Team A.R.G.
## Building the program
Pre-built executable code is not provided due to the difficulty of maintaining
versions for all the many operating systems that it could be run on.
The code is written in C and should compile properly using any ANSI C99
compatible compiler, such as (but not limited to) gcc or clang.
### Build examples
To build from a copy of the cabi directory tree provided, while in the base
directory containing cabi.c use:
`gcc cabi.c lodepng/lodepng.c -o cabi`
or
`clang cabi.c lodepng/lodepng.c -o cabi`
For Windows, it may be more desirable to name the program `CABI.EXE` by using:
`-o CABI.EXE`
Compiler options for optimization, etc. (such as -O2 or -Os) can be added if
desired but likely won't make much difference for most uses.
## Usage
The binary executable file (cabi or CABI.EXE) should be placed somewhere in the
path for executables on the operating system used, or else include the path as
part of the command given.
Running Cabi without any parameters will just output a brief program
description and the usage syntax:
```text
cabi - Compress Arduboy Image
Convert a PNG file into RLE encoded C/C++ source
for use with Arduboy2 drawCompressed()
usage: cabi in.png [array_name_prefix]
```
For `in.png` substitute the name of the PNG file to be converted. If the file
isn't in the current directory, the full path and name can be specified.
For `[array_name_prefix]` an optional prefix for the names of the arrays created
can be given. If this parameter isn't provided, `compressed_image` will be used
for the prefix.
If the program is unable to produce proper output, an error message will be
given and a non-zero exit code will be returned.
## Input file decoding
The input file should be a PNG file containing the image to be converted.
The height of the image must be a multiple of 8 pixels (8, 16, 24, 32, ...).
The width can be any size.
The image will be translated to a raw array of 32 bit RGBA (Red, Green, Blue,
Alpha) pixels internally before being processed to output. Ideally, pixels that
are to be drawn (represented as a 1 in the image output) should be fully white.
Non-drawn (0) pixels should be fully black. Pixels intended to be masked out of
the image (represented as a 0 in both the image and mask output), should be
fully transparent and their color doesn't matter.
However, after translation to RGBA, any pixel with an alpha (opaqueness) value
of 127 or less will be set as non-drawn (0) for both the image and the mask.
For the image, after the alpha value is first taken into account, pixels with a
red color value greater than 127 will be set as drawn (1) and others will be
set as non-drawn (0). For the mask, only the alpha value is used and red is
ignored. Green and blue color values are ignored for both image and mask.
### To summarize:
For the image:
Green and blue are ignored.
| Alpha | Red | Output |
|:------:|:-------:|:------:|
| <= 127 | <= 127 | 0 |
| <= 127 | > 127 | 0 |
| > 127 | <= 127 | 0 |
| > 127 | > 127 | 1 |
For the mask:
Red, green and blue are ignored.
| Alpha | Output |
|:------:|:------:|
| <= 127 | 0 |
| > 127 | 1 |
## Output
Cabi will send all output to `stdout`, which is usually the console unless
redirected. To save the output, you may be able to copy and paste it into your
editor, or you can redirect `stdout` to a file for importing. For example:
`cabi PlayerSprite.png PlayerSprite > PlayerSprite.out`
If conversion is successful, the output will be text representing C/C++ code
for two arrays, an image and a mask, that can be included in a sketch for use
by the *drawCompressed()* function. The image array will be named the same as
the prefix. The mask name will be the prefix with `_mask` appended to it.
Along with the actual array text, a comment will be included before each array
giving the input file name used and the dimensions of the image. A comment
included after each array will give the size of the array and the compression
ratio compared to the non-compressed equivalent (although the ratio is based
on the compressed array including two bytes for the bitmap dimensions compared
to a non-compressed array without bitmap dimensions).
Note that it's possible that the "compressed" array will actually end up
larger than the equivalent non-compressed one would. This is indicated by
a compression ratio greater than 1. The ratio should be noted and taken into
account when determining whether using Cabi compressed bitmaps is suitable for
the intended purpose.
If masking isn't required, the mask array can be ignored or deleted.
Note that the usage message or any error message will also be sent to `stdout`,
rather than `stderr`. Therefore, if you redirect the output to a file, in this
case the file will contain only that text.
## Using the output with *drawCompressed()*
The Arduboy2 *drawCompressed()* function doesn't natively handle a mask for
"transparent" pixels in an image. However, masking can be accomplished by
calling *drawCompressed()* twice with the same coordinates. The first call
specifies the mask array and the color BLACK. The second call specifies the
image array and the color WHITE.
An example PNG bitmap named `sample.png` is included with the program. Here is
an example Arduboy sketch that draws this bitmap with masking, using the Cabi
output imported into the sketch.
```cpp
#include <Arduboy2.h>
Arduboy2 arduboy;
// ===== Cabi output =====
// sample.png width: 32 height: 32
const PROGMEM uint8_t sample[] = {
0x1f,0x1f,0x68,0x93,0xca,0x39,0xe5,0x9c,0x72,0xca,0xe9,0x74,0x4b,0x25,0x95,0xdc,
0x6e,0xb7,0xdb,0xed,0x56,0x49,0x65,0xb7,0x4a,0x3a,0xa9,0xac,0x92,0x4e,0x3a,0xa9,
0x74,0x94,0x8c,0x6a,0xbb,0xdd,0x6e,0xb7,0x8c,0x76,0xbb,0xdd,0x6e,0xb7,0xdb,0xed,
0x76,0xbb,0xdd,0xf2,0xf1,0xa6,0xb7,0x52,0x79,0xc5,0xa4,0xbc,0x92,0x76,0x1d,0x2f,
0x9f,0xdd,0x6e,0xb7,0xdb,0xed,0x76,0xbb,0xdd,0x6e,0xb7,0x8c,0xf4,0xd9,0x15,0x23,
0x65,0x5a,0x49,0x27,0x9d,0x54,0x56,0x49,0x27,0x95,0xdd,0x2a,0xa9,0xec,0x76,0xbb,
0xdd,0x6e,0x97,0x4a,0x2a,0xb9,0x54,0xce,0x39,0xe5,0x94,0x73,0xca,0x39,0x25,0xa3,
0x05
};
// bytes:113 ratio: 0.883
const PROGMEM uint8_t sample_mask[] = {
0x1f,0x1f,0x68,0x93,0xca,0x39,0x25,0x95,0xdc,0xa6,0xd3,0xa1,0x35,0x9d,0x4e,0x6f,
0x95,0x54,0xd2,0x39,0xa9,0x74,0x94,0xe8,0xb4,0xdb,0xed,0x76,0xbb,0xdd,0x6e,0xb7,
0xdb,0xed,0x16,0x8f,0x8a,0x49,0xe1,0xd1,0x6e,0xb7,0xdb,0xed,0x76,0xbb,0xdd,0x6e,
0xb7,0x5b,0x74,0x52,0xa6,0x95,0x74,0x4e,0x2a,0xa9,0xec,0x3a,0x9d,0x0e,0xad,0xe9,
0x74,0x76,0xa9,0xa4,0x72,0x4e,0xc9,0x68,0x01
};
// bytes:73 ratio: 0.570
// =======================
void setup() {
arduboy.begin();
}
void loop() {
arduboy.clear();
arduboy.drawCompressed(20, 10, sample_mask, BLACK);
arduboy.drawCompressed(20, 10, sample, WHITE);
arduboy.display();
}
```

View File

@ -1,385 +0,0 @@
/*
cabi - Compress Arduboy Image
A command line program to read a PNG file containing a bitmap image, compress
it using RLE encoding and convert it to C/C++ code suitable for use with the
Team A.R.G. drawCompressed() function. This function is included in the
Arduboy2 library.
Written by zep
https://www.lexaloffle.com/bbs/?uid=1
https://twitter.com/lexaloffle
Contributed to Team A.R.G.
Modifications by Scott Allen - July 2020, September 2020
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
Usage:
cabi in.png [array_name_prefix]
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <memory.h>
#include "lodepng/lodepng.h"
// alternative pixel order mapping
//#define READING_ORDER 1
unsigned reading_order = 0;
// one byte encodes a 1x8 stick; low byte at top
// for testing
void draw_sprite_ascii(const uint8_t *dat, unsigned w, unsigned h)
{
unsigned x, y;
unsigned row, bit;
for (y = 0; y < h; y ++)
{
row = y/8;
bit = y&7;
for (x = 0; x < w; x++)
{
if (dat[x + (row*w)] & (1 << bit))
printf("#");
else
printf(".");
}
printf("\n");
}
}
// ----------------------------------------------------------------------------
// :: Decompress
// ----------------------------------------------------------------------------
// compression / decompression session state
typedef struct CSESSION{
unsigned byte;
unsigned bit;
const uint8_t *src;
uint8_t *dest;
unsigned src_pos;
unsigned out_pos;
unsigned w, h;
}CSESSION;
static CSESSION cs;
// get an n-bit number from the compressed data stream
static unsigned getval(unsigned bits)
{
unsigned val = 0;
unsigned i;
for (i = 0; i < bits; i++)
{
if (cs.bit == 0x100)
{
cs.bit = 0x1;
cs.byte = cs.src[cs.src_pos];
cs.src_pos ++;
}
if (cs.byte & cs.bit)
val += (1 << i);
cs.bit <<= 1;
}
return val;
}
// decompress_rle
// if not NULL, w and h give back the size of the sprite.
void draw_compressed_sprite_ascii(const uint8_t *src)
{
unsigned col;
unsigned bl, len;
unsigned i;
unsigned w, h;
unsigned x, y;
unsigned total = 0;
memset(&cs, 0, sizeof(cs));
cs.src = src;
cs.bit = 0x100;
cs.src_pos = 0;
// header
w = getval(8) + 1;
h = getval(8) + 1;
col = getval(1); // starting colour
x = y = 0;
while (y < h)
{
bl = 1;
while (!getval(1))
bl += 2;
len = getval(bl)+1; // span length
for (i = 0; i < len; i++)
{
//if ((x%8) == 0) // every 8th bit (format test)
printf("%s", col ? "#":".");
if (col) total++;
x++;
if (x >= w)
{
printf("\n");
y ++;
x = 0;
}
//if ((x+y*w)%(w*8) == 0) printf("\n"); // print every 8th line (format test)
}
col = 1-col; // toggle
}
printf("\ntotal: %u\n", total);
}
// ----------------------------------------------------------------------------
// :: Compress
// ----------------------------------------------------------------------------
/*
getcol
pos is the index of the pixel: 0 .. w*h-1
*/
static unsigned getcol(unsigned pos)
{
unsigned x, y;
// display order
if (reading_order == 0)
{
if (cs.src[pos/8] & (1 << (pos&7))) return 1;
return 0;
}
// reading order (compresses slightly better but harder to optimize sprite blit)
// or use this after loading png into display order (no need for extra conversion)
x = (pos % cs.w);
y = (pos / cs.w);
if (cs.src[x + ((y/8)*cs.w)] & (1 << (y&7))) return 1;
return 0;
}
static unsigned find_rlen(unsigned pos, unsigned plen)
{
unsigned col;
unsigned pos0;
col = getcol(pos);
pos0 = pos;
while(getcol(pos) == col && pos < plen)
pos ++;
return pos-pos0;
}
// write a bit to the stream. non-zero val means 1, otherwise 0.
static void putbit(unsigned val)
{
if (val) cs.byte |= cs.bit;
cs.bit <<= 1;
if (cs.bit == 0x100)
{
//output byte
if (cs.out_pos != 0) printf(",");
if (cs.out_pos % 16 == 0) printf("\n");
printf("0x%02x", cs.byte);
cs.out_pos ++;
cs.bit = 0x1;
cs.byte = 0;
}
}
// write an n-bit (bits) number (val) to the output steam
static void putval(unsigned val, unsigned bits)
{
unsigned i;
if (bits <= 0) return;
for (i = 0; i < bits; i++)
putbit(val & (1 << i));
}
// write a span length
// a string of bits encoding the number of bits needed to encode the length,
// and then the length.
static void putsplen(unsigned len)
{
unsigned blen = 1; // how bits needed to encode length
while ((unsigned)(1 << blen) <= len) {
blen += 2;
}
// write number of bits (1-terminated string of zeroes)
putval(0,(blen-1)/2);
putval(1,1); // terminator
// write length
putval(len, blen);
}
/*
comp
compress plen 1-bit pixels from src to dest
*/
unsigned compress_rle(const uint8_t *src, unsigned w, unsigned h, char *prefix, char *suffix)
{
unsigned pos;
unsigned rlen;
printf("const PROGMEM uint8_t %s%s[] = {", prefix, suffix);
fflush(stdout);
memset(&cs, 0, sizeof(cs));
cs.src = src;
cs.bit = 1;
cs.w = w;
cs.h = h;
// header
putval(w-1, 8);
putval(h-1, 8);
putval(getcol(0), 1); // first colour
pos = 0;
// span data
while (pos < w*h)
{
rlen = find_rlen(pos, w*h);
pos += rlen;
putsplen(rlen-1);
}
// pad with zeros and flush
while (cs.bit != 0x1)
putbit(0);
printf("\n};\n");
return cs.out_pos; // bytes
}
int main(int argc, char **argv)
{
unsigned compressed_len;
unsigned w, h;
unsigned char *bmp = NULL;
unsigned char *bmp0 = NULL;
unsigned char *bmp1 = NULL;
unsigned result;
unsigned rawlen;
unsigned x, y;
unsigned row, bit;
char default_prefix[] = "compressed_image";
char *prefix = default_prefix;
if (argc < 2)
{
printf("cabi - Compress Arduboy Image\n");
printf("Convert a PNG file into RLE encoded C/C++ source\n");
printf("for use with Arduboy2 drawCompressed()\n\n");
printf("usage: cabi in.png [array_name_prefix]\n");
exit(1);
}
if (argc >= 3) {
prefix = argv[2];
}
result = lodepng_decode32_file(&bmp, &w, &h, argv[1]);
if (result != 0) {
printf("error %u: file %s: %s\n", result, argv[1], lodepng_error_text(result));
free(bmp);
exit(result);
}
if (h % 8 != 0) {
printf("error 120: file %s: image height must be a multiple of 8 but is %u\n", argv[1], h);
free(bmp);
exit(120);
}
// generate sprite and mask
rawlen = w * (h+7) / 8;
bmp0 = (unsigned char *)malloc(rawlen); memset(bmp0, 0, rawlen);
bmp1 = (unsigned char *)malloc(rawlen); memset(bmp1, 0, rawlen);
printf("// %s width: %u height: %u\n", argv[1], w, h);
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
row = y/8;
bit = y&7;
if (bmp[(x+y*w)*4 + 3] > 127) // need to be opaque to count
if (bmp[(x+y*w)*4 + 0] > 127)
{
// set sprite
bmp0[x + (row*w)] |= (1 << bit);
}
if (bmp[(x+y*w)*4 + 3] > 127)
{
// set mask
bmp1[x + (row*w)] |= (1 << bit);
}
}
}
compressed_len = compress_rle(bmp0, w, h, prefix, "");
printf("// bytes:%u ratio: %3.3f\n\n", compressed_len, (float)(compressed_len * 8)/ (float)(w*h));
compressed_len = compress_rle(bmp1, w, h, prefix, "_mask");
printf("// bytes:%u ratio: %3.3f\n\n", compressed_len, (float)(compressed_len * 8)/ (float)(w*h));
free(bmp);
free(bmp0);
free(bmp1);
return 0;
}

View File

@ -1,21 +0,0 @@
Copyright (c) 2005-2018 Lode Vandevenne
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 199 B

View File

@ -1,22 +1,22 @@
# File Descriptions # File Descriptions
Documentation for files contained in this repository that aren't self explanatory. Documentation for files contained in this repository which aren't self explanatory.
### /library.properties ### /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). 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 committed just before tagging the new release. 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://arduino.github.io/arduino-cli/library-specification/) for details. See the [Arduino IDE 1.5: Library specification](https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification) for details.
### /library.json ### /library.json
This JSON file is a manifest used by the [PlatformIO IDE](https://platformio.org/) to make this library available in its [Library Manager](https://docs.platformio.org/en/latest/librarymanager/index.html). 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 committed just before tagging the new release. 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](https://docs.platformio.org/en/latest/librarymanager/config.html) documentation for details. 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 ### /extras/assets/arduboy_logo.png<br>/extras/assets/arduboy_screen.png

View File

@ -1,15 +0,0 @@
The following files contain the Arduboy2 library version number.
They must be updated to match the release tag before a new version is released.
library.properties
version=
library.json
"version":
src/Arduboy2.h
#define ARDUBOY_LIB_VER
extras/Doxyfile
PROJECT_NUMBER =

View File

@ -20,13 +20,11 @@ SpritesB KEYWORD1
####################################### #######################################
allPixelsOn KEYWORD2 allPixelsOn KEYWORD2
anyPressed KEYWORD2
begin KEYWORD2 begin KEYWORD2
blank KEYWORD2 blank KEYWORD2
boot KEYWORD2 boot KEYWORD2
bootLogo KEYWORD2 bootLogo KEYWORD2
bootLogoCompressed KEYWORD2 bootLogoCompressed KEYWORD2
bootLogoExtra KEYWORD2
bootLogoShell KEYWORD2 bootLogoShell KEYWORD2
bootLogoSpritesBOverwrite KEYWORD2 bootLogoSpritesBOverwrite KEYWORD2
bootLogoSpritesBSelfMasked KEYWORD2 bootLogoSpritesBSelfMasked KEYWORD2
@ -66,18 +64,12 @@ flashlight KEYWORD2
flipVertical KEYWORD2 flipVertical KEYWORD2
flipHorizontal KEYWORD2 flipHorizontal KEYWORD2
freeRGBled KEYWORD2 freeRGBled KEYWORD2
generateRandomSeed KEYWORD2
getBuffer KEYWORD2 getBuffer KEYWORD2
getCharacterHeight KEYWORD2
getCharacterSpacing KEYWORD2
getCharacterWidth KEYWORD2
getCursorX KEYWORD2 getCursorX KEYWORD2
getCursorY KEYWORD2 getCursorY KEYWORD2
getLineSpacing KEYWORD2
getPixel KEYWORD2 getPixel KEYWORD2
getTextBackground KEYWORD2 getTextBackground KEYWORD2
getTextColor KEYWORD2 getTextColor KEYWORD2
getTextRawMode KEYWORD2
getTextSize KEYWORD2 getTextSize KEYWORD2
getTextWrap KEYWORD2 getTextWrap KEYWORD2
height KEYWORD2 height KEYWORD2
@ -96,31 +88,25 @@ paintScreen KEYWORD2
pollButtons KEYWORD2 pollButtons KEYWORD2
pressed KEYWORD2 pressed KEYWORD2
readShowBootLogoFlag KEYWORD2 readShowBootLogoFlag KEYWORD2
readShowBootLogoLEDsFlag KEYWORD2
readShowUnitNameFlag KEYWORD2 readShowUnitNameFlag KEYWORD2
readUnitID KEYWORD2 readUnitID KEYWORD2
readUnitName KEYWORD2 readUnitName KEYWORD2
safeMode KEYWORD2 safeMode KEYWORD2
saveOnOff KEYWORD2 saveOnOff KEYWORD2
setCursor KEYWORD2 setCursor KEYWORD2
setCursorX KEYWORD2
setCursorY KEYWORD2
setFrameDuration KEYWORD2 setFrameDuration KEYWORD2
setFrameRate KEYWORD2 setFrameRate KEYWORD2
setRGBled KEYWORD2 setRGBled KEYWORD2
setTextBackground KEYWORD2 setTextBackground KEYWORD2
setTextColor KEYWORD2 setTextColor KEYWORD2
setTextRawMode KEYWORD2
setTextSize KEYWORD2 setTextSize KEYWORD2
setTextWrap KEYWORD2 setTextWrap KEYWORD2
SPItransfer KEYWORD2 SPItransfer KEYWORD2
SPItransferAndRead KEYWORD2
systemButtons KEYWORD2 systemButtons KEYWORD2
toggle KEYWORD2 toggle KEYWORD2
waitNoButtons KEYWORD2 waitNoButtons KEYWORD2
width KEYWORD2 width KEYWORD2
writeShowBootLogoFlag KEYWORD2 writeShowBootLogoFlag KEYWORD2
writeShowBootLogoLEDsFlag KEYWORD2
writeShowUnitNameFlag KEYWORD2 writeShowUnitNameFlag KEYWORD2
writeUnitID KEYWORD2 writeUnitID KEYWORD2
writeUnitName KEYWORD2 writeUnitName KEYWORD2
@ -138,21 +124,6 @@ drawOverwrite KEYWORD2
drawPlusMask KEYWORD2 drawPlusMask KEYWORD2
drawSelfMasked KEYWORD2 drawSelfMasked KEYWORD2
##### Public variables #####
audio KEYWORD2
arduboy_logo KEYWORD2
arduboy_logo_compressed KEYWORD2
arduboy_logo_sprite KEYWORD2
currentButtonState KEYWORD2
font5x7 KEYWORD2
frameCount KEYWORD2
previousButtonState KEYWORD2
sBuffer KEYWORD2
# Arduboy2Beep classes
duration KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)
####################################### #######################################
@ -160,7 +131,6 @@ duration KEYWORD2
ARDUBOY_LIB_VER LITERAL1 ARDUBOY_LIB_VER LITERAL1
ARDUBOY_UNIT_NAME_LEN LITERAL1 ARDUBOY_UNIT_NAME_LEN LITERAL1
ARDUBOY_UNIT_NAME_BUFFER_SIZE LITERAL1
EEPROM_STORAGE_SPACE_START LITERAL1 EEPROM_STORAGE_SPACE_START LITERAL1

View File

@ -7,7 +7,7 @@
"type": "git", "type": "git",
"url": "https://github.com/MLXXXp/Arduboy2.git" "url": "https://github.com/MLXXXp/Arduboy2.git"
}, },
"version": "6.0.0", "version": "5.0.0",
"export": "export":
{ {
"exclude": "extras" "exclude": "extras"

View File

@ -1,5 +1,5 @@
name=Arduboy2 name=Arduboy2
version=6.0.0 version=5.0.0
author=Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen, Ross O. Shoger author=Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen, Ross O. Shoger
maintainer=Scott Allen <saydisp-git@yahoo.ca> maintainer=Scott Allen <saydisp-git@yahoo.ca>
sentence=An alternative library for use with the Arduboy game system. sentence=An alternative library for use with the Arduboy game system.

View File

@ -5,6 +5,8 @@
*/ */
#include "Arduboy2.h" #include "Arduboy2.h"
#include "ab_logo.c"
#include "glcdfont.c"
//======================================== //========================================
//========== class Arduboy2Base ========== //========== class Arduboy2Base ==========
@ -12,40 +14,20 @@
uint8_t Arduboy2Base::sBuffer[]; uint8_t Arduboy2Base::sBuffer[];
uint16_t Arduboy2Base::frameCount = 0; Arduboy2Base::Arduboy2Base()
{
uint8_t Arduboy2Base::currentButtonState = 0; currentButtonState = 0;
uint8_t Arduboy2Base::previousButtonState = 0; previousButtonState = 0;
// frame management
uint8_t Arduboy2Base::eachFrameMillis = 16; setFrameDuration(16);
uint8_t Arduboy2Base::thisFrameStart; frameCount = 0;
uint8_t Arduboy2Base::lastFrameDurationMs; justRendered = false;
bool Arduboy2Base::justRendered = false; }
// functions called here should be public so users can create their // functions called here should be public so users can create their
// own init functions if they need different behavior than `begin` // own init functions if they need different behavior than `begin`
// provides by default. // provides by default
//
// This code and it's documentation should be kept in sync with
// Aruduboy2::begin()
void Arduboy2Base::begin() void Arduboy2Base::begin()
{
beginDoFirst();
bootLogo();
// alternative logo functions. Work the same as bootLogo() but may reduce
// memory size if the sketch uses the same bitmap drawing function or
// `Sprites`/`SpritesB` class
// bootLogoCompressed();
// bootLogoSpritesSelfMasked();
// bootLogoSpritesOverwrite();
// bootLogoSpritesBSelfMasked();
// bootLogoSpritesBOverwrite();
waitNoButtons(); // wait for all buttons to be released
}
void Arduboy2Base::beginDoFirst()
{ {
boot(); // raw hardware boot(); // raw hardware
@ -57,6 +39,17 @@ void Arduboy2Base::beginDoFirst()
systemButtons(); systemButtons();
audio.begin(); audio.begin();
bootLogo();
// alternative logo functions. Work the same as bootLogo() but may reduce
// memory size if the sketch uses the same bitmap drawing function
// bootLogoCompressed();
// bootLogoSpritesSelfMasked();
// bootLogoSpritesOverwrite();
// bootLogoSpritesBSelfMasked();
// bootLogoSpritesBOverwrite();
waitNoButtons(); // wait for all buttons to be released
} }
void Arduboy2Base::flashlight() void Arduboy2Base::flashlight()
@ -98,7 +91,7 @@ void Arduboy2Base::sysCtrlSound(uint8_t buttons, uint8_t led, uint8_t eeVal)
digitalWriteRGB(BLUE_LED, RGB_OFF); // turn off blue LED digitalWriteRGB(BLUE_LED, RGB_OFF); // turn off blue LED
delayShort(200); delayShort(200);
digitalWriteRGB(led, RGB_ON); // turn on "acknowledge" LED digitalWriteRGB(led, RGB_ON); // turn on "acknowledge" LED
EEPROM.update(eepromAudioOnOff, eeVal); EEPROM.update(EEPROM_AUDIO_ON_OFF, eeVal);
delayShort(500); delayShort(500);
digitalWriteRGB(led, RGB_OFF); // turn off "acknowledge" LED digitalWriteRGB(led, RGB_OFF); // turn off "acknowledge" LED
@ -168,25 +161,21 @@ void Arduboy2Base::drawLogoSpritesBOverwrite(int16_t y)
// bootLogoText() should be kept in sync with bootLogoShell() // bootLogoText() should be kept in sync with bootLogoShell()
// if changes are made to one, equivalent changes should be made to the other // if changes are made to one, equivalent changes should be made to the other
bool Arduboy2Base::bootLogoShell(void (&drawLogo)(int16_t)) void Arduboy2Base::bootLogoShell(void (*drawLogo)(int16_t))
{ {
bool showLEDs = readShowBootLogoLEDsFlag();
if (!readShowBootLogoFlag()) { if (!readShowBootLogoFlag()) {
return false; return;
} }
if (showLEDs) { digitalWriteRGB(RED_LED, RGB_ON);
digitalWriteRGB(RED_LED, RGB_ON);
}
for (int16_t y = -15; y <= 24; y++) { for (int16_t y = -16; y <= 24; y++) {
if (pressed(RIGHT_BUTTON)) { if (pressed(RIGHT_BUTTON)) {
digitalWriteRGB(RGB_OFF, RGB_OFF, RGB_OFF); // all LEDs off digitalWriteRGB(RGB_OFF, RGB_OFF, RGB_OFF); // all LEDs off
return false; return;
} }
if (showLEDs && y == 4) { if (y == 4) {
digitalWriteRGB(RED_LED, RGB_OFF); // red LED off digitalWriteRGB(RED_LED, RGB_OFF); // red LED off
digitalWriteRGB(GREEN_LED, RGB_ON); // green LED on digitalWriteRGB(GREEN_LED, RGB_ON); // green LED on
} }
@ -199,19 +188,19 @@ bool Arduboy2Base::bootLogoShell(void (&drawLogo)(int16_t))
delayShort(15); delayShort(15);
} }
if (showLEDs) { digitalWriteRGB(GREEN_LED, RGB_OFF); // green LED off
digitalWriteRGB(GREEN_LED, RGB_OFF); // green LED off digitalWriteRGB(BLUE_LED, RGB_ON); // blue LED on
digitalWriteRGB(BLUE_LED, RGB_ON); // blue LED on
}
delayShort(400); delayShort(400);
digitalWriteRGB(BLUE_LED, RGB_OFF); digitalWriteRGB(BLUE_LED, RGB_OFF);
return true; bootLogoExtra();
} }
// Virtual function overridden by derived class
void Arduboy2Base::bootLogoExtra() { }
// wait for all buttons to be released // wait for all buttons to be released
void Arduboy2Base::waitNoButtons() void Arduboy2Base::waitNoButtons() {
{
do { do {
delayShort(50); // simple button debounce delayShort(50); // simple button debounce
} while (buttonsState()); } while (buttonsState());
@ -282,7 +271,15 @@ int Arduboy2Base::cpuLoad()
void Arduboy2Base::initRandomSeed() void Arduboy2Base::initRandomSeed()
{ {
randomSeed(generateRandomSeed()); power_adc_enable(); // ADC on
// do an ADC read from an unconnected input pin
ADCSRA |= _BV(ADSC); // start conversion (ADMUX has been pre-set in boot())
while (bit_is_set(ADCSRA, ADSC)) { } // wait for conversion complete
randomSeed(((unsigned long)ADC << 16) + micros());
power_adc_disable(); // ADC off
} }
/* Graphics */ /* Graphics */
@ -292,65 +289,67 @@ void Arduboy2Base::clear()
fillScreen(BLACK); fillScreen(BLACK);
} }
// Used by drawPixel to help with left bitshifting since AVR has no
// multiple bit shift instruction. We can bit shift from a lookup table
// in flash faster than we can calculate the bit shifts on the CPU.
const uint8_t bitshift_left[] PROGMEM = {
_BV(0), _BV(1), _BV(2), _BV(3), _BV(4), _BV(5), _BV(6), _BV(7)
};
void Arduboy2Base::drawPixel(int16_t x, int16_t y, uint8_t color) void Arduboy2Base::drawPixel(int16_t x, int16_t y, uint8_t color)
{ {
#ifdef PIXEL_SAFE_MODE
if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1)) if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1))
{ {
return; return;
} }
#endif
uint16_t row_offset; uint16_t row_offset;
uint8_t bit; uint8_t bit;
// uint8_t row = (uint8_t)y / 8;
// row_offset = (row*WIDTH) + (uint8_t)x;
// bit = _BV((uint8_t)y % 8);
// the above math can also be rewritten more simply as;
// row_offset = (y * WIDTH/8) & ~0b01111111 + (uint8_t)x;
// which is what the below assembler does
// local variable for the bitshift_left array pointer,
// which can be declared a read-write operand
const uint8_t* bsl = bitshift_left;
asm volatile asm volatile
( (
// bit = 1 << (y & 7) "mul %[width_offset], %A[y]\n"
"ldi %[bit], 1 \n" //bit = 1; "movw %[row_offset], r0\n"
"sbrc %[y], 1 \n" //if (y & _BV(1)) bit = 4; "andi %A[row_offset], 0x80\n" // row_offset &= (~0b01111111);
"ldi %[bit], 4 \n" "clr __zero_reg__\n"
"sbrc %[y], 0 \n" //if (y & _BV(0)) bit = bit << 1; "add %A[row_offset], %[x]\n"
"lsl %[bit] \n" // mask for only 0-7
"sbrc %[y], 2 \n" //if (y & _BV(2)) bit = (bit << 4) | (bit >> 4); "andi %A[y], 0x07\n"
"swap %[bit] \n" // Z += y
//row_offset = y / 8 * WIDTH + x; "add r30, %A[y]\n"
"andi %A[y], 0xf8 \n" //row_offset = (y & 0xF8) * WIDTH / 8 "adc r31, __zero_reg__\n"
"mul %[width_offset], %A[y] \n" // load correct bitshift from program RAM
"movw %[row_offset], r0 \n" "lpm %[bit], Z\n"
"clr __zero_reg__ \n" : [row_offset] "=&x" (row_offset), // upper register (ANDI)
"add %A[row_offset], %[x] \n" //row_offset += x [bit] "=r" (bit),
#if WIDTH != 128 [y] "+d" (y), // upper register (ANDI), must be writable
"adc %B[row_offset], __zero_reg__ \n" // only non 128 width can overflow "+z" (bsl) // is modified to point to the proper shift array element
#endif : [width_offset] "r" ((uint8_t)(WIDTH/8)),
: [row_offset] "=&x" (row_offset), // upper register (ANDI) [x] "r" ((uint8_t)x)
[bit] "=&d" (bit), // upper register (LDI)
[y] "+d" (y) // upper register (ANDI), must be writable
: [width_offset] "r" ((uint8_t)(WIDTH/8)),
[x] "r" ((uint8_t)x)
: :
); );
uint8_t data = sBuffer[row_offset] | bit;
if (!(color & _BV(0))) data ^= bit; if (color) {
sBuffer[row_offset] = data; sBuffer[row_offset] |= bit;
} } else {
#if 0 sBuffer[row_offset] &= ~ bit;
// For reference, this is the C++ equivalent
void Arduboy2Base::drawPixel(int16_t x, int16_t y, uint8_t color)
{
if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1))
{
return;
} }
uint16_t row_offset;
uint8_t bit;
bit = 1 << (y & 7);
row_offset = (y & 0xF8) * WIDTH / 8 + x;
uint8_t data = sBuffer[row_offset] | bit;
if (!color) data ^= bit;
sBuffer[row_offset] = data;
} }
#endif
uint8_t Arduboy2Base::getPixel(uint8_t x, uint8_t y) uint8_t Arduboy2Base::getPixel(uint8_t x, uint8_t y)
{ {
@ -490,13 +489,13 @@ void Arduboy2Base::drawLine
// bresenham's algorithm - thx wikpedia // bresenham's algorithm - thx wikpedia
bool steep = abs(y1 - y0) > abs(x1 - x0); bool steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) { if (steep) {
swapInt16(x0, y0); swap(x0, y0);
swapInt16(x1, y1); swap(x1, y1);
} }
if (x0 > x1) { if (x0 > x1) {
swapInt16(x0, x1); swap(x0, x1);
swapInt16(y0, y1); swap(y0, y1);
} }
int16_t dx, dy; int16_t dx, dy;
@ -581,10 +580,10 @@ void Arduboy2Base::drawFastHLine
w = xEnd - x; w = xEnd - x;
// buffer pointer plus row offset + x offset // buffer pointer plus row offset + x offset
uint8_t *pBuf = sBuffer + ((y / 8) * WIDTH) + x; register uint8_t *pBuf = sBuffer + ((y / 8) * WIDTH) + x;
// pixel mask // pixel mask
uint8_t mask = 1 << (y & 7); register uint8_t mask = 1 << (y & 7);
switch (color) switch (color)
{ {
@ -623,7 +622,7 @@ void Arduboy2Base::fillScreen(uint8_t color)
// { // {
// color = 0xFF; // all pixels on // color = 0xFF; // all pixels on
// } // }
// for (int16_t i = 0; i < WIDTH * HEIGHT / 8; i++) // for (int16_t i = 0; i < WIDTH * HEIGTH / 8; i++)
// { // {
// sBuffer[i] = color; // sBuffer[i] = color;
// } // }
@ -644,7 +643,7 @@ void Arduboy2Base::fillScreen(uint8_t color)
"ldi %[color], 0xFF\n" "ldi %[color], 0xFF\n"
// counter = 0 // counter = 0
"clr __tmp_reg__\n" "clr __tmp_reg__\n"
"1:\n" "loopto:\n"
// (4x) push zero into screen buffer, // (4x) push zero into screen buffer,
// then increment buffer position // then increment buffer position
"st Z+, %[color]\n" "st Z+, %[color]\n"
@ -655,7 +654,7 @@ void Arduboy2Base::fillScreen(uint8_t color)
"inc __tmp_reg__\n" "inc __tmp_reg__\n"
// repeat for 256 loops // repeat for 256 loops
// (until counter rolls over back to 0) // (until counter rolls over back to 0)
"brne 1b\n" "brne loopto\n"
: [color] "+d" (color), : [color] "+d" (color),
"+z" (bPtr) "+z" (bPtr)
: :
@ -705,15 +704,15 @@ void Arduboy2Base::fillTriangle
// Sort coordinates by Y order (y2 >= y1 >= y0) // Sort coordinates by Y order (y2 >= y1 >= y0)
if (y0 > y1) if (y0 > y1)
{ {
swapInt16(y0, y1); swapInt16(x0, x1); swap(y0, y1); swap(x0, x1);
} }
if (y1 > y2) if (y1 > y2)
{ {
swapInt16(y2, y1); swapInt16(x2, x1); swap(y2, y1); swap(x2, x1);
} }
if (y0 > y1) if (y0 > y1)
{ {
swapInt16(y0, y1); swapInt16(x0, x1); swap(y0, y1); swap(x0, x1);
} }
if(y0 == y2) if(y0 == y2)
@ -773,7 +772,7 @@ void Arduboy2Base::fillTriangle
if(a > b) if(a > b)
{ {
swapInt16(a,b); swap(a,b);
} }
drawFastHLine(a, y, b-a+1, color); drawFastHLine(a, y, b-a+1, color);
@ -793,7 +792,7 @@ void Arduboy2Base::fillTriangle
if(a > b) if(a > b)
{ {
swapInt16(a,b); swap(a,b);
} }
drawFastHLine(a, y, b-a+1, color); drawFastHLine(a, y, b-a+1, color);
@ -805,7 +804,7 @@ void Arduboy2Base::drawBitmap
uint8_t color) uint8_t color)
{ {
// no need to draw at all if we're offscreen // no need to draw at all if we're offscreen
if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1) if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
return; return;
int yOffset = abs(y) % 8; int yOffset = abs(y) % 8;
@ -850,7 +849,7 @@ void Arduboy2Base::drawSlowXYBitmap
(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color) (int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color)
{ {
// no need to draw at all of we're offscreen // no need to draw at all of we're offscreen
if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1) if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
return; return;
int16_t xi, yi, byteWidth = (w + 7) / 8; int16_t xi, yi, byteWidth = (w + 7) / 8;
@ -863,18 +862,17 @@ void Arduboy2Base::drawSlowXYBitmap
} }
} }
// Helper for drawCompressed() // Helper for drawCompressed()
class Arduboy2Base::BitStreamReader struct BitStreamReader
{ {
private:
const uint8_t *source; const uint8_t *source;
uint16_t sourceIndex; uint16_t sourceIndex;
uint8_t bitBuffer; uint8_t bitBuffer;
uint8_t byteBuffer; uint8_t byteBuffer;
public: BitStreamReader(const uint8_t *source)
BitStreamReader(const uint8_t *bitmap) : source(source), sourceIndex(), bitBuffer(), byteBuffer()
: source(bitmap), sourceIndex(), bitBuffer(), byteBuffer()
{ {
} }
@ -883,17 +881,17 @@ class Arduboy2Base::BitStreamReader
uint16_t result = 0; uint16_t result = 0;
for (uint16_t i = 0; i < bitCount; i++) for (uint16_t i = 0; i < bitCount; i++)
{ {
if (bitBuffer == 0) if (this->bitBuffer == 0)
{ {
bitBuffer = 0x1; this->bitBuffer = 0x1;
byteBuffer = pgm_read_byte(&source[sourceIndex]); this->byteBuffer = pgm_read_byte(&this->source[this->sourceIndex]);
++sourceIndex; ++this->sourceIndex;
} }
if ((byteBuffer & bitBuffer) != 0) if ((this->byteBuffer & this->bitBuffer) != 0)
result |= (1 << i); result |= (1 << i); // result |= bitshift_left[i];
bitBuffer <<= 1; this->bitBuffer <<= 1;
} }
return result; return result;
} }
@ -902,7 +900,7 @@ class Arduboy2Base::BitStreamReader
void Arduboy2Base::drawCompressed(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t color) void Arduboy2Base::drawCompressed(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t color)
{ {
// set up decompress state // set up decompress state
BitStreamReader cs(bitmap); BitStreamReader cs = BitStreamReader(bitmap);
// read header // read header
int width = (int)cs.readBits(8) + 1; int width = (int)cs.readBits(8) + 1;
@ -910,7 +908,7 @@ void Arduboy2Base::drawCompressed(int16_t sx, int16_t sy, const uint8_t *bitmap,
uint8_t spanColour = (uint8_t)cs.readBits(1); // starting colour uint8_t spanColour = (uint8_t)cs.readBits(1); // starting colour
// no need to draw at all if we're offscreen // no need to draw at all if we're offscreen
if ((sx + width <= 0) || (sx > WIDTH - 1) || (sy + height <= 0) || (sy > HEIGHT - 1)) if ((sx + width < 0) || (sx > WIDTH - 1) || (sy + height < 0) || (sy > HEIGHT - 1))
return; return;
// sy = sy - (frame * height); // sy = sy - (frame * height);
@ -1014,11 +1012,6 @@ bool Arduboy2Base::pressed(uint8_t buttons)
return (buttonsState() & buttons) == buttons; return (buttonsState() & buttons) == buttons;
} }
bool Arduboy2Base::anyPressed(uint8_t buttons)
{
return (buttonsState() & buttons) != 0;
}
bool Arduboy2Base::notPressed(uint8_t buttons) bool Arduboy2Base::notPressed(uint8_t buttons)
{ {
return (buttonsState() & buttons) == 0; return (buttonsState() & buttons) == 0;
@ -1056,21 +1049,21 @@ bool Arduboy2Base::collide(Rect rect1, Rect rect2)
uint16_t Arduboy2Base::readUnitID() uint16_t Arduboy2Base::readUnitID()
{ {
return EEPROM.read(eepromUnitID) | return EEPROM.read(EEPROM_UNIT_ID) |
(((uint16_t)(EEPROM.read(eepromUnitID + 1))) << 8); (((uint16_t)(EEPROM.read(EEPROM_UNIT_ID + 1))) << 8);
} }
void Arduboy2Base::writeUnitID(uint16_t id) void Arduboy2Base::writeUnitID(uint16_t id)
{ {
EEPROM.update(eepromUnitID, (uint8_t)(id & 0xff)); EEPROM.update(EEPROM_UNIT_ID, (uint8_t)(id & 0xff));
EEPROM.update(eepromUnitID + 1, (uint8_t)(id >> 8)); EEPROM.update(EEPROM_UNIT_ID + 1, (uint8_t)(id >> 8));
} }
uint8_t Arduboy2Base::readUnitName(char* name) uint8_t Arduboy2Base::readUnitName(char* name)
{ {
char val; char val;
uint8_t dest; uint8_t dest;
uint8_t src = eepromUnitName; uint8_t src = EEPROM_UNIT_NAME;
for (dest = 0; dest < ARDUBOY_UNIT_NAME_LEN; dest++) for (dest = 0; dest < ARDUBOY_UNIT_NAME_LEN; dest++)
{ {
@ -1086,10 +1079,10 @@ uint8_t Arduboy2Base::readUnitName(char* name)
return dest; return dest;
} }
void Arduboy2Base::writeUnitName(const char* name) void Arduboy2Base::writeUnitName(char* name)
{ {
bool done = false; bool done = false;
uint8_t dest = eepromUnitName; uint8_t dest = EEPROM_UNIT_NAME;
for (uint8_t src = 0; src < ARDUBOY_UNIT_NAME_LEN; src++) for (uint8_t src = 0; src < ARDUBOY_UNIT_NAME_LEN; src++)
{ {
@ -1104,44 +1097,31 @@ void Arduboy2Base::writeUnitName(const char* name)
bool Arduboy2Base::readShowBootLogoFlag() bool Arduboy2Base::readShowBootLogoFlag()
{ {
return (EEPROM.read(eepromSysFlags) & sysFlagShowLogoMask); return (EEPROM.read(EEPROM_SYS_FLAGS) & SYS_FLAG_SHOW_LOGO_MASK);
} }
void Arduboy2Base::writeShowBootLogoFlag(bool val) void Arduboy2Base::writeShowBootLogoFlag(bool val)
{ {
uint8_t flags = EEPROM.read(eepromSysFlags); uint8_t flags = EEPROM.read(EEPROM_SYS_FLAGS);
bitWrite(flags, sysFlagShowLogoBit, val); bitWrite(flags, SYS_FLAG_SHOW_LOGO, val);
EEPROM.update(eepromSysFlags, flags); EEPROM.update(EEPROM_SYS_FLAGS, flags);
} }
bool Arduboy2Base::readShowUnitNameFlag() bool Arduboy2Base::readShowUnitNameFlag()
{ {
return (EEPROM.read(eepromSysFlags) & sysFlagUnameMask); return (EEPROM.read(EEPROM_SYS_FLAGS) & SYS_FLAG_UNAME_MASK);
} }
void Arduboy2Base::writeShowUnitNameFlag(bool val) void Arduboy2Base::writeShowUnitNameFlag(bool val)
{ {
uint8_t flags = EEPROM.read(eepromSysFlags); uint8_t flags = EEPROM.read(EEPROM_SYS_FLAGS);
bitWrite(flags, sysFlagUnameBit, val); bitWrite(flags, SYS_FLAG_UNAME, val);
EEPROM.update(eepromSysFlags, flags); EEPROM.update(EEPROM_SYS_FLAGS, flags);
} }
bool Arduboy2Base::readShowBootLogoLEDsFlag() void Arduboy2Base::swap(int16_t& a, int16_t& b)
{
return (EEPROM.read(eepromSysFlags) & sysFlagShowLogoLEDsMask);
}
void Arduboy2Base::writeShowBootLogoLEDsFlag(bool val)
{
uint8_t flags = EEPROM.read(eepromSysFlags);
bitWrite(flags, sysFlagShowLogoLEDsBit, val);
EEPROM.update(eepromSysFlags, flags);
}
void Arduboy2Base::swapInt16(int16_t& a, int16_t& b)
{ {
int16_t temp = a; int16_t temp = a;
a = b; a = b;
@ -1153,106 +1133,33 @@ void Arduboy2Base::swapInt16(int16_t& a, int16_t& b)
//========== class Arduboy2 ========== //========== class Arduboy2 ==========
//==================================== //====================================
int16_t Arduboy2::cursor_x = 0; Arduboy2::Arduboy2()
int16_t Arduboy2::cursor_y = 0;
uint8_t Arduboy2::textColor = WHITE;
uint8_t Arduboy2::textBackground = BLACK;
uint8_t Arduboy2::textSize = 1;
bool Arduboy2::textWrap = false;
bool Arduboy2::textRaw = false;
// functions called here should be public so users can create their
// own init functions if they need different behavior than `begin`
// provides by default.
//
// This code and it's documentation should be kept in sync with
// Aruduboy2Base::begin()
void Arduboy2::begin()
{ {
beginDoFirst(); cursor_x = 0;
cursor_y = 0;
bootLogo(); textColor = 1;
// alternative logo functions. Work the same as bootLogo() but may reduce textBackground = 0;
// memory size if the sketch uses the same bitmap drawing function or textSize = 1;
// `Sprites`/`SpritesB` class textWrap = 0;
// bootLogoCompressed();
// bootLogoSpritesSelfMasked();
// bootLogoSpritesOverwrite();
// bootLogoSpritesBSelfMasked();
// bootLogoSpritesBOverwrite();
waitNoButtons();
}
void Arduboy2::bootLogo()
{
if (bootLogoShell(drawLogoBitmap))
{
bootLogoExtra();
}
}
void Arduboy2::bootLogoCompressed()
{
if (bootLogoShell(drawLogoCompressed))
{
bootLogoExtra();
}
}
void Arduboy2::bootLogoSpritesSelfMasked()
{
if (bootLogoShell(drawLogoSpritesSelfMasked))
{
bootLogoExtra();
}
}
void Arduboy2::bootLogoSpritesOverwrite()
{
if (bootLogoShell(drawLogoSpritesOverwrite))
{
bootLogoExtra();
}
}
void Arduboy2::bootLogoSpritesBSelfMasked()
{
if (bootLogoShell(drawLogoSpritesBSelfMasked))
{
bootLogoExtra();
}
}
void Arduboy2::bootLogoSpritesBOverwrite()
{
if (bootLogoShell(drawLogoSpritesBOverwrite))
{
bootLogoExtra();
}
} }
// bootLogoText() should be kept in sync with bootLogoShell() // bootLogoText() should be kept in sync with bootLogoShell()
// if changes are made to one, equivalent changes should be made to the other // if changes are made to one, equivalent changes should be made to the other
void Arduboy2::bootLogoText() void Arduboy2::bootLogoText()
{ {
bool showLEDs = readShowBootLogoLEDsFlag();
if (!readShowBootLogoFlag()) { if (!readShowBootLogoFlag()) {
return; return;
} }
if (showLEDs) { digitalWriteRGB(RED_LED, RGB_ON);
digitalWriteRGB(RED_LED, RGB_ON);
}
for (int16_t y = -15; y <= 24; y++) { for (int16_t y = -16; y <= 24; y++) {
if (pressed(RIGHT_BUTTON)) { if (pressed(RIGHT_BUTTON)) {
digitalWriteRGB(RGB_OFF, RGB_OFF, RGB_OFF); // all LEDs off digitalWriteRGB(RGB_OFF, RGB_OFF, RGB_OFF); // all LEDs off
return; return;
} }
if (showLEDs && y == 4) { if (y == 4) {
digitalWriteRGB(RED_LED, RGB_OFF); // red LED off digitalWriteRGB(RED_LED, RGB_OFF); // red LED off
digitalWriteRGB(GREEN_LED, RGB_ON); // green LED on digitalWriteRGB(GREEN_LED, RGB_ON); // green LED on
} }
@ -1269,10 +1176,8 @@ void Arduboy2::bootLogoText()
delayShort(11); delayShort(11);
} }
if (showLEDs) { digitalWriteRGB(GREEN_LED, RGB_OFF); // green LED off
digitalWriteRGB(GREEN_LED, RGB_OFF); // green LED off digitalWriteRGB(BLUE_LED, RGB_ON); // blue LED on
digitalWriteRGB(BLUE_LED, RGB_ON); // blue LED on
}
delayShort(400); delayShort(400);
digitalWriteRGB(BLUE_LED, RGB_OFF); digitalWriteRGB(BLUE_LED, RGB_OFF);
@ -1288,11 +1193,11 @@ void Arduboy2::bootLogoExtra()
return; return;
} }
c = EEPROM.read(eepromUnitName); c = EEPROM.read(EEPROM_UNIT_NAME);
if (c != 0xFF && c != 0x00) if (c != 0xFF && c != 0x00)
{ {
uint8_t i = eepromUnitName; uint8_t i = EEPROM_UNIT_NAME;
cursor_x = 50; cursor_x = 50;
cursor_y = 56; cursor_y = 56;
@ -1301,7 +1206,7 @@ void Arduboy2::bootLogoExtra()
write(c); write(c);
c = EEPROM.read(++i); c = EEPROM.read(++i);
} }
while (i < eepromUnitName + ARDUBOY_UNIT_NAME_LEN); while (i < EEPROM_UNIT_NAME + ARDUBOY_UNIT_NAME_LEN);
display(); display();
delayShort(1000); delayShort(1000);
@ -1310,106 +1215,64 @@ void Arduboy2::bootLogoExtra()
size_t Arduboy2::write(uint8_t c) size_t Arduboy2::write(uint8_t c)
{ {
if ((c == '\r') && !textRaw) if (c == '\n')
{
return 1;
}
if (((c == '\n') && !textRaw) ||
(textWrap && (cursor_x > (WIDTH - (characterWidth * textSize)))))
{ {
cursor_y += textSize * 8;
cursor_x = 0; cursor_x = 0;
cursor_y += fullCharacterHeight * textSize;
} }
else if (c == '\r')
if ((c != '\n') || textRaw) {
// skip em
}
else
{ {
drawChar(cursor_x, cursor_y, c, textColor, textBackground, textSize); drawChar(cursor_x, cursor_y, c, textColor, textBackground, textSize);
cursor_x += fullCharacterWidth * textSize; cursor_x += textSize * 6;
if (textWrap && (cursor_x > (WIDTH - textSize * 6)))
{
// calling ourselves recursively for 'newline' is
// 12 bytes smaller than doing the same math here
write('\n');
}
} }
return 1; return 1;
} }
void Arduboy2::drawChar void Arduboy2::drawChar
(int16_t x, int16_t y, uint8_t c, uint8_t color, uint8_t bg, uint8_t size) (int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size)
{ {
// It is assumed that rendering characters fully off screen will be rare, uint8_t line;
// so let drawPixel() handle off screen checks, to reduce code size at the bool draw_background = bg != color;
// expense of slower off screen character handling. const unsigned char* bitmap = font + c * 5;
#if 0
if ((x >= WIDTH) || // Clip right if ((x >= WIDTH) || // Clip right
(y >= HEIGHT) || // Clip bottom (y >= HEIGHT) || // Clip bottom
((x + characterWidth * size - 1) < 0) || // Clip left ((x + 5 * size - 1) < 0) || // Clip left
((y + characterHeight * size - 1) < 0) // Clip top ((y + 8 * size - 1) < 0) // Clip top
) )
{ {
return; return;
} }
#endif
bool drawBackground = bg != color; for (uint8_t i = 0; i < 6; i++ )
const uint8_t* bitmap =
&font5x7[c * characterWidth * ((characterHeight + 8 - 1) / 8)];
for (uint8_t i = 0; i < fullCharacterWidth; i++)
{ {
uint8_t column; line = pgm_read_byte(bitmap++);
if (i == 5) {
if (characterHeight <= 8) line = 0x0;
{
column = (i < characterWidth) ? pgm_read_byte(bitmap++) : 0;
}
else
{
column = 0;
} }
// draw the character by columns. Top to bottom, left to right for (uint8_t j = 0; j < 8; j++)
// including character spacing on the right
for (uint8_t j = 0; j < characterHeight; j++)
{ {
if (characterHeight > 8) uint8_t draw_color = (line & 0x1) ? color : bg;
{
// at this point variable "column" will be 0, either from initialization
// or by having eight 0 bits shifted in by the >>= operation below
if ((j % 8 == 0) && (i < characterWidth))
{
column = pgm_read_byte(bitmap++);
}
}
// pixelIsSet should be a bool but at the time of writing, if (draw_color || draw_background) {
// the GCC AVR compiler generates less code if it's a uint8_t for (uint8_t a = 0; a < size; a++ ) {
uint8_t pixelIsSet = column & 0x01; for (uint8_t b = 0; b < size; b++ ) {
drawPixel(x + (i * size) + a, y + (j * size) + b, draw_color);
if (pixelIsSet || drawBackground)
{
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,
pixelIsSet ? color : bg);
}
}
}
column >>= 1;
}
// draw the inter-line spacing pixels for this column if required
if (drawBackground)
{
for (uint8_t j = characterHeight; j < fullCharacterHeight; j++)
{
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, bg);
} }
} }
} }
line >>= 1;
} }
} }
} }
@ -1420,16 +1283,6 @@ void Arduboy2::setCursor(int16_t x, int16_t y)
cursor_y = y; cursor_y = y;
} }
void Arduboy2::setCursorX(int16_t x)
{
cursor_x = x;
}
void Arduboy2::setCursorY(int16_t y)
{
cursor_y = y;
}
int16_t Arduboy2::getCursorX() int16_t Arduboy2::getCursorX()
{ {
return cursor_x; return cursor_x;
@ -1481,16 +1334,6 @@ bool Arduboy2::getTextWrap()
return textWrap; return textWrap;
} }
void Arduboy2::setTextRawMode(bool raw)
{
textRaw = raw;
}
bool Arduboy2::getTextRawMode()
{
return textRaw;
}
void Arduboy2::clear() void Arduboy2::clear()
{ {
Arduboy2Base::clear(); Arduboy2Base::clear();

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
*/ */
#include "Arduboy2.h" #include "Arduboy2.h"
#include "Arduboy2Audio.h"
bool Arduboy2Audio::audio_enabled = false; bool Arduboy2Audio::audio_enabled = false;
@ -42,12 +43,12 @@ void Arduboy2Audio::toggle()
void Arduboy2Audio::saveOnOff() void Arduboy2Audio::saveOnOff()
{ {
EEPROM.update(Arduboy2Base::eepromAudioOnOff, audio_enabled); EEPROM.update(EEPROM_AUDIO_ON_OFF, audio_enabled);
} }
void Arduboy2Audio::begin() void Arduboy2Audio::begin()
{ {
if (EEPROM.read(Arduboy2Base::eepromAudioOnOff)) if (EEPROM.read(EEPROM_AUDIO_ON_OFF))
on(); on();
else else
off(); off();

View File

@ -80,9 +80,12 @@ class Arduboy2Audio
* *
* \details * \details
* The speaker is initialized based on the current mute setting saved in * The speaker is initialized based on the current mute setting saved in
* system EEPROM. * system EEPROM. This function is called by `Arduboy2Base::begin()` so it
*/ * isn't normally required to call it within a sketch. However, if
static void begin(); * `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 /** \brief
* Turn sound on. * Turn sound on.
@ -94,7 +97,7 @@ class Arduboy2Audio
* *
* \see off() toggle() saveOnOff() * \see off() toggle() saveOnOff()
*/ */
static void on(); void static on();
/** \brief /** \brief
* Turn sound off (mute). * Turn sound off (mute).
@ -106,7 +109,7 @@ class Arduboy2Audio
* *
* \see on() toggle() saveOnOff() * \see on() toggle() saveOnOff()
*/ */
static void off(); void static off();
/** \brief /** \brief
* Toggle the sound on/off state. * Toggle the sound on/off state.
@ -119,7 +122,7 @@ class Arduboy2Audio
* *
* \see on() off() saveOnOff() * \see on() off() saveOnOff()
*/ */
static void toggle(); void static toggle();
/** \brief /** \brief
* Save the current sound state in EEPROM. * Save the current sound state in EEPROM.
@ -135,7 +138,7 @@ class Arduboy2Audio
* *
* \see on() off() toggle() * \see on() off() toggle()
*/ */
static void saveOnOff(); void static saveOnOff();
/** \brief /** \brief
* Get the current sound state. * Get the current sound state.
@ -149,10 +152,10 @@ class Arduboy2Audio
* *
* \see on() off() toggle() * \see on() off() toggle()
*/ */
static bool enabled(); bool static enabled();
protected: protected:
static bool audio_enabled; bool static audio_enabled;
}; };
#endif #endif

View File

@ -45,9 +45,9 @@
* for. For example, with a rate of 60 frames per second a duration of 30 * 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. * would be used to play a tone for half a second.
* *
* The variable named #duration is the counter that times the duration of a * 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 * 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 * the `#duration` variable is non-zero (assuming it's a timed tone, not a
* continuous tone). * continuous tone).
* *
* To keep the code small and efficient, the frequency of a tone is specified * To keep the code small and efficient, the frequency of a tone is specified

View File

@ -6,15 +6,7 @@
#include "Arduboy2Core.h" #include "Arduboy2Core.h"
#include <avr/wdt.h> const uint8_t PROGMEM lcdBootProgram[] = {
//========================================
//========== class Arduboy2Core ==========
//========================================
// Commands sent to the OLED display to initialize it
const PROGMEM uint8_t Arduboy2Core::lcdBootProgram[] = {
// boot defaults are commented out but left here in case they // boot defaults are commented out but left here in case they
// might prove useful for reference // might prove useful for reference
// //
@ -78,6 +70,9 @@ const PROGMEM uint8_t Arduboy2Core::lcdBootProgram[] = {
// 0x22, 0x00, PAGE_ADDRESS_END // 0x22, 0x00, PAGE_ADDRESS_END
}; };
Arduboy2Core::Arduboy2Core() { }
void Arduboy2Core::boot() void Arduboy2Core::boot()
{ {
#ifdef ARDUBOY_SET_CPU_8MHZ #ifdef ARDUBOY_SET_CPU_8MHZ
@ -85,7 +80,7 @@ void Arduboy2Core::boot()
setCPUSpeed8MHz(); setCPUSpeed8MHz();
#endif #endif
// Select the ADC input here so a delay isn't required in generateRandomSeed() // Select the ADC input here so a delay isn't required in initRandomSeed()
ADMUX = RAND_SEED_IN_ADMUX; ADMUX = RAND_SEED_IN_ADMUX;
bootPins(); bootPins();
@ -241,7 +236,7 @@ void Arduboy2Core::SPItransfer(uint8_t data)
SPDR = data; SPDR = data;
/* /*
* The following NOP introduces a small delay that can prevent the wait * The following NOP introduces a small delay that can prevent the wait
* loop from iterating when running at the maximum speed. This gives * loop form iterating when running at the maximum speed. This gives
* about 10% more speed, even if it seems counter-intuitive. At lower * about 10% more speed, even if it seems counter-intuitive. At lower
* speeds it is unnoticed. * speeds it is unnoticed.
*/ */
@ -249,13 +244,6 @@ void Arduboy2Core::SPItransfer(uint8_t data)
while (!(SPSR & _BV(SPIF))) { } // wait while (!(SPSR & _BV(SPIF))) { } // wait
} }
// Write to and read from the SPI bus (out to MOSI pin, in from MISO pin)
uint8_t Arduboy2Core::SPItransferAndRead(uint8_t data)
{
SPItransfer(data);
return SPDR;
}
void Arduboy2Core::safeMode() void Arduboy2Core::safeMode()
{ {
if (buttonsState() == UP_BUTTON) if (buttonsState() == UP_BUTTON)
@ -308,6 +296,10 @@ void Arduboy2Core::displayOn()
bootOLED(); bootOLED();
} }
uint8_t Arduboy2Core::width() { return WIDTH; }
uint8_t Arduboy2Core::height() { return HEIGHT; }
/* Drawing */ /* Drawing */
@ -561,23 +553,6 @@ uint8_t Arduboy2Core::buttonsState()
return buttons; return buttons;
} }
unsigned long Arduboy2Core::generateRandomSeed()
{
unsigned long seed;
power_adc_enable(); // ADC on
// do an ADC read from an unconnected input pin
ADCSRA |= _BV(ADSC); // start conversion (ADMUX has been pre-set in boot())
while (bit_is_set(ADCSRA, ADSC)) { } // wait for conversion complete
seed = ((unsigned long)ADC << 16) + micros();
power_adc_disable(); // ADC off
return seed;
}
// delay in ms with 16 bit duration // delay in ms with 16 bit duration
void Arduboy2Core::delayShort(uint16_t ms) void Arduboy2Core::delayShort(uint16_t ms)
{ {
@ -599,12 +574,11 @@ void Arduboy2Core::exitToBootloader()
while (true) { } while (true) { }
} }
// 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()
//========== class Arduboy2NoUSB ==========
//=========================================
void Arduboy2NoUSB::mainNoUSB()
{ {
// disable USB // disable USB
UDCON = _BV(DETACH); UDCON = _BV(DETACH);
@ -618,19 +592,17 @@ void Arduboy2NoUSB::mainNoUSB()
// This would normally be done in the USB code that uses the TX and RX LEDs // This would normally be done in the USB code that uses the TX and RX LEDs
TX_RX_LED_INIT; TX_RX_LED_INIT;
TXLED0;
RXLED0;
// Set the DOWN button pin for INPUT_PULLUP // Set the DOWN button pin for INPUT_PULLUP
bitSet(DOWN_BUTTON_PORT, DOWN_BUTTON_BIT); bitSet(DOWN_BUTTON_PORT, DOWN_BUTTON_BIT);
bitClear(DOWN_BUTTON_DDR, 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 // Delay to give time for the pin to be pulled high if it was floating
Arduboy2Core::delayShort(10); delayShort(10);
// if the DOWN button is pressed // if the DOWN button is pressed
if (bitRead(DOWN_BUTTON_PORTIN, DOWN_BUTTON_BIT) == 0) { if (bitRead(DOWN_BUTTON_PORTIN, DOWN_BUTTON_BIT) == 0) {
Arduboy2Core::exitToBootloader(); exitToBootloader();
} }
// The remainder is a copy of the Arduino main() function with the // The remainder is a copy of the Arduino main() function with the

View File

@ -10,6 +10,8 @@
#include <Arduino.h> #include <Arduino.h>
#include <avr/power.h> #include <avr/power.h>
#include <avr/sleep.h> #include <avr/sleep.h>
#include <avr/wdt.h>
#include <limits.h>
// main hardware compile flags // main hardware compile flags
@ -134,6 +136,12 @@
#define RST_PORT PORTD // Display reset port #define RST_PORT PORTD // Display reset port
#define RST_BIT PORTD6 // Display reset physical bit number #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 // map all LEDs to the single TX LED on DEVKIT
#define RED_LED 17 #define RED_LED 17
#define GREEN_LED 17 #define GREEN_LED 17
@ -202,7 +210,7 @@
// ----- Pins common on Arduboy and DevKit ----- // ----- Pins common on Arduboy and DevKit -----
// Unconnected analog input used for noise by generateRandomSeed() // Unconnected analog input used for noise by initRandomSeed()
#define RAND_SEED_IN A4 #define RAND_SEED_IN A4
#define RAND_SEED_IN_PORT PORTF #define RAND_SEED_IN_PORT PORTF
#define RAND_SEED_IN_BIT PORTF1 #define RAND_SEED_IN_BIT PORTF1
@ -248,9 +256,9 @@
/** \brief /** \brief
* Eliminate the USB stack to free up code space. * Eliminate the USB stack to free up code space.
* *
* \warning * \note
* Removing the USB code will make it impossible for sketch uploader * **WARNING:** Removing the USB code will make it impossible for sketch
* programs to automatically force a reset into the bootloader! * 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 * 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. * 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 aware that the timing for the point that a reset must be initiated can
@ -303,20 +311,10 @@
*/ */
#define ARDUBOY_NO_USB int main() __attribute__ ((OS_main)); \ #define ARDUBOY_NO_USB int main() __attribute__ ((OS_main)); \
int main() { \ int main() { \
Arduboy2NoUSB::mainNoUSB(); \ Arduboy2Core::mainNoUSB(); \
return 0; \ return 0; \
} }
// A replacement for the Arduino main() function that eliminates the USB code.
// Used by the ARDUBOY_NO_USB macro.
class Arduboy2NoUSB
{
friend int main();
private:
static void mainNoUSB();
};
/** \brief /** \brief
* Lower level functions generally dealing directly with the hardware. * Lower level functions generally dealing directly with the hardware.
@ -332,11 +330,12 @@ class Arduboy2NoUSB
* that this may eliminate the need to create an entire local copy of the * that this may eliminate the need to create an entire local copy of the
* library, in order to extend the functionality, in most circumstances. * library, in order to extend the functionality, in most circumstances.
*/ */
class Arduboy2Core : public Arduboy2NoUSB class Arduboy2Core
{ {
friend class Arduboy2Ex; friend class Arduboy2Ex;
public: public:
Arduboy2Core();
/** \brief /** \brief
* Idle the CPU to save power. * Idle the CPU to save power.
@ -348,7 +347,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* app should be able to sleep maybe half the time in between rendering * app should be able to sleep maybe half the time in between rendering
* it's own frames. * it's own frames.
*/ */
static void idle(); void static idle();
/** \brief /** \brief
* Put the display into data mode. * Put the display into data mode.
@ -364,7 +363,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see LCDCommandMode() SPItransfer() * \see LCDCommandMode() SPItransfer()
*/ */
static void LCDDataMode(); void static LCDDataMode();
/** \brief /** \brief
* Put the display into command mode. * Put the display into command mode.
@ -388,7 +387,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see LCDDataMode() sendLCDCommand() SPItransfer() * \see LCDDataMode() sendLCDCommand() SPItransfer()
*/ */
static void LCDCommandMode(); void static LCDCommandMode();
/** \brief /** \brief
* Transfer a byte to the display. * Transfer a byte to the display.
@ -401,31 +400,9 @@ class Arduboy2Core : public Arduboy2NoUSB
* or as data to be placed on the screen, depending on the command/data * or as data to be placed on the screen, depending on the command/data
* mode. * mode.
* *
* \see LCDDataMode() LCDCommandMode() sendLCDCommand() SPItransferAndRead() * \see LCDDataMode() LCDCommandMode() sendLCDCommand()
*/ */
static void SPItransfer(uint8_t data); void static SPItransfer(uint8_t data);
/** \brief
* Transfer a byte to, and read a byte from, the SPI bus.
*
* \param data The byte to be sent.
*
* \return The byte that was received.
*
* \details
* This function does the same as the `SPItransfer()` function but also
* reads and returns the byte of data that was received during the
* transfer.
*
* This function is of no use for a standard Arduboy, since only the
* display is connected to the SPI bus and data cannot be received from
* the display. It has been provided for use with homemade or expanded
* units that have had additional peripherals added to the SPI bus that
* are capable of sending data.
*
* \see SPItransfer()
*/
static uint8_t SPItransferAndRead(uint8_t data);
/** \brief /** \brief
* Turn the display off. * Turn the display off.
@ -438,7 +415,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see displayOn() * \see displayOn()
*/ */
static void displayOff(); void static displayOff();
/** \brief /** \brief
* Turn the display on. * Turn the display on.
@ -454,21 +431,29 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see displayOff() * \see displayOff()
*/ */
static void displayOn(); void static displayOn();
/** \brief /** \brief
* Get the width of the display in pixels. * Get the width of the display in pixels.
* *
* \return 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.
*/ */
static constexpr uint8_t width() { return WIDTH; } uint8_t static width();
/** \brief /** \brief
* Get the height of the display in pixels. * Get the height of the display in pixels.
* *
* \return 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.
*/ */
static constexpr uint8_t height() { return HEIGHT; } uint8_t static height();
/** \brief /** \brief
* Get the current state of all buttons as a bitmask. * Get the current state of all buttons as a bitmask.
@ -483,7 +468,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* LEFT_BUTTON, RIGHT_BUTTON, UP_BUTTON, DOWN_BUTTON, A_BUTTON, B_BUTTON * LEFT_BUTTON, RIGHT_BUTTON, UP_BUTTON, DOWN_BUTTON, A_BUTTON, B_BUTTON
*/ */
static uint8_t buttonsState(); uint8_t static buttonsState();
/** \brief /** \brief
* Paint 8 pixels vertically to the display. * Paint 8 pixels vertically to the display.
@ -515,7 +500,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* . . . . . . . . (end of page 1) X . X . . . . . (end of page 1) * . . . . . . . . (end of page 1) X . X . . . . . (end of page 1)
* . . . . . . . . (page 2) . . . . . . . . (page 2) * . . . . . . . . (page 2) . . . . . . . . (page 2)
*/ */
static void paint8Pixels(uint8_t pixels); void static paint8Pixels(uint8_t pixels);
/** \brief /** \brief
* Paints an entire image directly to the display from program memory. * Paints an entire image directly to the display from program memory.
@ -533,7 +518,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see paint8Pixels() * \see paint8Pixels()
*/ */
static void paintScreen(const uint8_t *image); void static paintScreen(const uint8_t *image);
/** \brief /** \brief
* Paints an entire image directly to the display from an array in RAM. * Paints an entire image directly to the display from an array in RAM.
@ -557,7 +542,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see paint8Pixels() * \see paint8Pixels()
*/ */
static void paintScreen(uint8_t image[], bool clear = false); void static paintScreen(uint8_t image[], bool clear = false);
/** \brief /** \brief
* Blank the display screen by setting all pixels off. * Blank the display screen by setting all pixels off.
@ -566,13 +551,13 @@ class Arduboy2Core : public Arduboy2NoUSB
* All pixels on the screen will be written with a value of 0 to turn * All pixels on the screen will be written with a value of 0 to turn
* them off. * them off.
*/ */
static void blank(); void static blank();
/** \brief /** \brief
* Invert the entire display or set it back to normal. * Invert the entire display or set it back to normal.
* *
* \param inverse `true` will invert the display. `false` will set the * \param inverse `true` will invert the display. `false` will set the
* display to non-inverted. * display to no-inverted.
* *
* \details * \details
* Calling this function with a value of `true` will set the display to * Calling this function with a value of `true` will set the display to
@ -583,7 +568,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* until it is set back to non-inverted mode by calling this function with * until it is set back to non-inverted mode by calling this function with
* `false`. * `false`.
*/ */
static void invert(bool inverse); void static invert(bool inverse);
/** \brief /** \brief
* Turn all display pixels on or display the buffer contents. * Turn all display pixels on or display the buffer contents.
@ -604,7 +589,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see invert() * \see invert()
*/ */
static void allPixelsOn(bool on); void static allPixelsOn(bool on);
/** \brief /** \brief
* Flip the display vertically or set it back to normal. * Flip the display vertically or set it back to normal.
@ -622,7 +607,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see flipHorizontal() * \see flipHorizontal()
*/ */
static void flipVertical(bool flipped); void static flipVertical(bool flipped);
/** \brief /** \brief
* Flip the display horizontally or set it back to normal. * Flip the display horizontally or set it back to normal.
@ -640,7 +625,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see flipVertical() * \see flipVertical()
*/ */
static void flipHorizontal(bool flipped); void static flipHorizontal(bool flipped);
/** \brief /** \brief
* Send a single command byte to the display. * Send a single command byte to the display.
@ -656,7 +641,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* Sending improper commands to the display can place it into invalid or * Sending improper commands to the display can place it into invalid or
* unexpected states, possibly even causing physical damage. * unexpected states, possibly even causing physical damage.
*/ */
static void sendLCDCommand(uint8_t command); void static sendLCDCommand(uint8_t command);
/** \brief /** \brief
* Set the light output of the RGB LED. * Set the light output of the RGB LED.
@ -690,7 +675,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see setRGBled(uint8_t, uint8_t) digitalWriteRGB() freeRGBled() * \see setRGBled(uint8_t, uint8_t) digitalWriteRGB() freeRGBled()
*/ */
static void setRGBled(uint8_t red, uint8_t green, uint8_t blue); void static setRGBled(uint8_t red, uint8_t green, uint8_t blue);
/** \brief /** \brief
* Set the brightness of one of the RGB LEDs without affecting the others. * Set the brightness of one of the RGB LEDs without affecting the others.
@ -712,7 +697,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see setRGBled(uint8_t, uint8_t, uint8_t) digitalWriteRGB() freeRGBled() * \see setRGBled(uint8_t, uint8_t, uint8_t) digitalWriteRGB() freeRGBled()
*/ */
static void setRGBled(uint8_t color, uint8_t val); void static setRGBled(uint8_t color, uint8_t val);
/** \brief /** \brief
@ -725,7 +710,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see digitalWriteRGB() setRGBled() * \see digitalWriteRGB() setRGBled()
*/ */
static void freeRGBled(); void static freeRGBled();
/** \brief /** \brief
* Set the RGB LEDs digitally, to either fully on or fully off. * Set the RGB LEDs digitally, to either fully on or fully off.
@ -740,16 +725,16 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* The colors are as follows: * The colors are as follows:
* *
* | RED LED | GREEN LED | BLUE LED | COLOR | * RED LED GREEN_LED BLUE_LED COLOR
* | ------- | --------- | -------- | :-----: | * ------- --------- -------- -----
* | RGB_OFF | RGB_OFF | RGB_OFF | OFF | * RGB_OFF RGB_OFF RGB_OFF OFF
* | RGB_OFF | RGB_OFF | RGB_ON | Blue | * RGB_OFF RGB_OFF RGB_ON Blue
* | RGB_OFF | RGB_ON | RGB_OFF | Green | * RGB_OFF RGB_ON RGB_OFF Green
* | RGB_OFF | RGB_ON | RGB_ON | Cyan | * RGB_OFF RGB_ON RGB_ON Cyan
* | RGB_ON | RGB_OFF | RGB_OFF | Red | * RGB_ON RGB_OFF RGB_OFF Red
* | RGB_ON | RGB_OFF | RGB_ON | Magenta | * RGB_ON RGB_OFF RGB_ON Magenta
* | RGB_ON | RGB_ON | RGB_OFF | Yellow | * RGB_ON RGB_ON RGB_OFF Yellow
* | RGB_ON | RGB_ON | RGB_ON | White | * RGB_ON RGB_ON RGB_ON White
* *
* \note * \note
* \parblock * \parblock
@ -770,7 +755,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see digitalWriteRGB(uint8_t, uint8_t) setRGBled() freeRGBled() * \see digitalWriteRGB(uint8_t, uint8_t) setRGBled() freeRGBled()
*/ */
static void digitalWriteRGB(uint8_t red, uint8_t green, uint8_t blue); void static digitalWriteRGB(uint8_t red, uint8_t green, uint8_t blue);
/** \brief /** \brief
* Set one of the RGB LEDs digitally, to either fully on or fully off. * Set one of the RGB LEDs digitally, to either fully on or fully off.
@ -788,7 +773,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see digitalWriteRGB(uint8_t, uint8_t, uint8_t) setRGBled() freeRGBled() * \see digitalWriteRGB(uint8_t, uint8_t, uint8_t) setRGBled() freeRGBled()
*/ */
static void digitalWriteRGB(uint8_t color, uint8_t val); void static digitalWriteRGB(uint8_t color, uint8_t val);
/** \brief /** \brief
* Initialize the Arduboy's hardware. * Initialize the Arduboy's hardware.
@ -796,23 +781,16 @@ class Arduboy2Core : public Arduboy2NoUSB
* \details * \details
* This function initializes the display, buttons, etc. * This function initializes the display, buttons, etc.
* *
* This function is called by `begin()` so isn't normally called within a * 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 * 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(). * 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 * The functions that begin() would call after boot() can then be called
* called to add back in some of the start up features as space permits. * 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 the README file or main page, in section * \see Arduboy2Base::begin()
* _Substitute or remove boot up features_, for more details.
*
* \warning
* If this function is used, it is recommended that at least `flashlight()`
* or `safeMode()` be called after it to provide a means to upload a new
* sketch if the bootloader "magic number" problem is encountered.
*
* \see Arduboy2::begin() Arduboy2Base::flashlight() safeMode()
*/ */
static void boot(); void static boot();
/** \brief /** \brief
* Allow upload when the bootloader "magic number" could be corrupted. * Allow upload when the bootloader "magic number" could be corrupted.
@ -824,8 +802,8 @@ class Arduboy2Core : public Arduboy2NoUSB
* sketch, for sketches that interfere with the bootloader "magic number". * sketch, for sketches that interfere with the bootloader "magic number".
* The problem occurs with certain sketches that use large amounts of RAM. * The problem occurs with certain sketches that use large amounts of RAM.
* *
* This function should be called after `boot()` in sketches that don't * This function should be called after `boot()` in sketches that
* call `flashlight()`. * potentially could cause the problem.
* *
* It is intended to replace the `flashlight()` function when more * It is intended to replace the `flashlight()` function when more
* program space is required. If possible, it is more desirable to use * program space is required. If possible, it is more desirable to use
@ -833,26 +811,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see Arduboy2Base::flashlight() boot() * \see Arduboy2Base::flashlight() boot()
*/ */
static void safeMode(); void static safeMode();
/** \brief
* Create a seed suitable for use with a pseudorandom number generator.
*
* \return A random value that can be used to seed a
* pseudorandom number generator.
*
* \details
* The returned value will be a random value derived from entropy from an
* ADC reading of a floating pin combined with the microseconds since boot.
*
* \note
* This function will be more effective if called after a semi-random time,
* such as after waiting for the user to press a button to start a game, or
* another event that takes a variable amount of time after boot.
*
* \see Arduboy2Base::initRandomSeed()
*/
static unsigned long generateRandomSeed();
/** \brief /** \brief
* Delay for the number of milliseconds, specified as a 16 bit value. * Delay for the number of milliseconds, specified as a 16 bit value.
@ -865,7 +824,7 @@ class Arduboy2Core : public Arduboy2NoUSB
* 65535 milliseconds (about 65.5 seconds). Using this function instead * 65535 milliseconds (about 65.5 seconds). Using this function instead
* of Arduino `delay()` will save a few bytes of code. * of Arduino `delay()` will save a few bytes of code.
*/ */
static void delayShort(uint16_t ms) __attribute__ ((noinline)); void static delayShort(uint16_t ms) __attribute__ ((noinline));
/** \brief /** \brief
* Exit the sketch and start the bootloader * Exit the sketch and start the bootloader
@ -883,17 +842,20 @@ class Arduboy2Core : public Arduboy2NoUSB
* *
* \see ARDUBOY_NO_USB * \see ARDUBOY_NO_USB
*/ */
static void exitToBootloader(); 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: protected:
// internals // internals
static void setCPUSpeed8MHz(); void static setCPUSpeed8MHz();
static void bootSPI(); void static bootSPI();
static void bootOLED(); void static bootOLED();
static void bootPins(); void static bootPins();
static void bootPowerSaving(); void static bootPowerSaving();
static const PROGMEM uint8_t lcdBootProgram[];
}; };
#endif #endif

View File

@ -1,341 +0,0 @@
/**
* @file Arduboy2Data.cpp
* \brief
* Constant data definintions for the Arduboy2 and Arduboy2Base classes.
*/
#include "Arduboy2.h"
#include <avr/pgmspace.h>
// arduboy_logo.png
// drawBitmap() format
// 88x16 px (176 bytes)
const PROGMEM uint8_t Arduboy2Base::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
};
// arduboy_logo.png
// drawCompressed() format
// 88x16 px (151 bytes)
const PROGMEM uint8_t Arduboy2Base::arduboy_logo_compressed[] = {
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 px (178 bytes)
const PROGMEM uint8_t Arduboy2Base::arduboy_logo_sprite[] = {
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
};
// ASCII based 5x7 font
// IBM PC code page 437
const PROGMEM uint8_t Arduboy2::font5x7[] = {
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,
};

View File

@ -148,11 +148,10 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
Arduboy2Base::sBuffer[ofs] = data; Arduboy2Base::sBuffer[ofs] = data;
} }
if (yOffset != 0 && sRow < 7) { if (yOffset != 0 && sRow < 7) {
const size_t index = static_cast<uint16_t>(ofs + WIDTH); data = Arduboy2Base::sBuffer[ofs + WIDTH];
data = Arduboy2Base::sBuffer[index]; data &= (*((unsigned char *) (&mask_data) + 1));
data &= (uint8_t)(mask_data >> 8); data |= (*((unsigned char *) (&bitmap_data) + 1));
data |= (uint8_t)(bitmap_data >> 8); Arduboy2Base::sBuffer[ofs + WIDTH] = data;
Arduboy2Base::sBuffer[index] = data;
} }
ofs++; ofs++;
bofs++; bofs++;
@ -171,8 +170,7 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
Arduboy2Base::sBuffer[ofs] |= (uint8_t)(bitmap_data); Arduboy2Base::sBuffer[ofs] |= (uint8_t)(bitmap_data);
} }
if (yOffset != 0 && sRow < 7) { if (yOffset != 0 && sRow < 7) {
const size_t index = static_cast<uint16_t>(ofs + WIDTH); Arduboy2Base::sBuffer[ofs + WIDTH] |= (*((unsigned char *) (&bitmap_data) + 1));
Arduboy2Base::sBuffer[index] |= (uint8_t)(bitmap_data >> 8);
} }
ofs++; ofs++;
bofs++; bofs++;
@ -191,8 +189,7 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
Arduboy2Base::sBuffer[ofs] &= ~(uint8_t)(bitmap_data); Arduboy2Base::sBuffer[ofs] &= ~(uint8_t)(bitmap_data);
} }
if (yOffset != 0 && sRow < 7) { if (yOffset != 0 && sRow < 7) {
const size_t index = static_cast<uint16_t>(ofs + WIDTH); Arduboy2Base::sBuffer[ofs + WIDTH] &= ~(*((unsigned char *) (&bitmap_data) + 1));
Arduboy2Base::sBuffer[index] &= ~(uint8_t)(bitmap_data >> 8);
} }
ofs++; ofs++;
bofs++; bofs++;
@ -226,11 +223,10 @@ void Sprites::drawBitmap(int16_t x, int16_t y,
Arduboy2Base::sBuffer[ofs] = data; Arduboy2Base::sBuffer[ofs] = data;
} }
if (yOffset != 0 && sRow < 7) { if (yOffset != 0 && sRow < 7) {
const size_t index = static_cast<uint16_t>(ofs + WIDTH); data = Arduboy2Base::sBuffer[ofs + WIDTH];
data = Arduboy2Base::sBuffer[index]; data &= (*((unsigned char *) (&mask_data) + 1));
data &= (uint8_t)(mask_data >> 8); data |= (*((unsigned char *) (&bitmap_data) + 1));
data |= (uint8_t)(bitmap_data >> 8); Arduboy2Base::sBuffer[ofs + WIDTH] = data;
Arduboy2Base::sBuffer[index] = data;
} }
ofs++; ofs++;
mask_ofs++; mask_ofs++;

View File

@ -89,9 +89,6 @@ class Sprites
* An array containing the image frames, and another array containing * An array containing the image frames, and another array containing
* corresponding mask frames, are used to draw a sprite. * corresponding mask frames, are used to draw a sprite.
* *
* For the mask array, the width and height are not included but must
* contain data of the same dimensions as the corresponding image array.
*
* Bits set to 1 in the mask indicate that the pixel will be set to the * 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 * value of the corresponding image bit. Bits set to 0 in the mask will be
* left unchanged. * left unchanged.

View File

@ -159,11 +159,10 @@ void SpritesB::drawBitmap(int16_t x, int16_t y,
Arduboy2Base::sBuffer[ofs] = data; Arduboy2Base::sBuffer[ofs] = data;
} }
if (yOffset != 0 && sRow < 7) { if (yOffset != 0 && sRow < 7) {
const size_t index = static_cast<uint16_t>(ofs + WIDTH); data = Arduboy2Base::sBuffer[ofs + WIDTH];
data = Arduboy2Base::sBuffer[index]; data &= (*((unsigned char *) (&mask_data) + 1));
data &= (uint8_t)(mask_data >> 8); data |= (*((unsigned char *) (&bitmap_data) + 1));
data |= (uint8_t)(bitmap_data >> 8); Arduboy2Base::sBuffer[ofs + WIDTH] = data;
Arduboy2Base::sBuffer[index] = data;
} }
ofs++; ofs++;
mask_ofs += ofs_step; mask_ofs += ofs_step;

View File

@ -1,7 +1,7 @@
/** /**
* @file SpritesCommon.h * @file SpritesCommon.h
* \brief * \brief
* Common header file for sprite functions. * Common header file for sprite functions
*/ */
#ifndef SpritesCommon_h #ifndef SpritesCommon_h

83
src/ab_logo.c Normal file
View File

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

274
src/glcdfont.c Normal file
View File

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