mirror of https://github.com/MLXXXp/Arduboy2.git
Squash commits up to Arduboy V1.1 release
This commit is contained in:
parent
7c4b38cb7d
commit
982175ecac
|
@ -1 +1,15 @@
|
|||
# Ignore vim temp and swap files
|
||||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Ignore working files
|
||||
.build
|
||||
Makefile
|
||||
ino.ini
|
||||
work
|
||||
*.eep
|
||||
|
||||
# Ignore OS bookkeeping
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
|
681
Arduboy.cpp
681
Arduboy.cpp
|
@ -1,681 +0,0 @@
|
|||
#include "Arduboy.h"
|
||||
#include "glcdfont.c"
|
||||
|
||||
Arduboy::Arduboy() { }
|
||||
|
||||
void Arduboy::start()
|
||||
{
|
||||
pinMode(DC, OUTPUT);
|
||||
pinMode(CS, OUTPUT);
|
||||
pinMode(8, INPUT_PULLUP);
|
||||
pinMode(9, INPUT_PULLUP);
|
||||
pinMode(10, INPUT_PULLUP);
|
||||
pinMode(5, INPUT_PULLUP);
|
||||
pinMode(A0, INPUT_PULLUP);
|
||||
pinMode(A1, INPUT_PULLUP);
|
||||
|
||||
csport = portOutputRegister(digitalPinToPort(CS));
|
||||
cspinmask = digitalPinToBitMask(CS);
|
||||
dcport = portOutputRegister(digitalPinToPort(DC));
|
||||
dcpinmask = digitalPinToBitMask(DC);
|
||||
|
||||
/**
|
||||
* Setup reset pin direction (used by both SPI and I2C)
|
||||
*/
|
||||
pinMode(RST, OUTPUT);
|
||||
digitalWrite(RST, HIGH);
|
||||
delay(1); // VDD (3.3V) goes high at start, lets just chill for a ms
|
||||
digitalWrite(RST, LOW); // bring reset low
|
||||
delay(10); // wait 10ms
|
||||
digitalWrite(RST, HIGH); // bring out of reset
|
||||
|
||||
*csport |= cspinmask;
|
||||
*dcport &= ~dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
|
||||
SPI.transfer(0xAE); // Display Off
|
||||
SPI.transfer(0XD5); // Set Display Clock Divisor v
|
||||
SPI.transfer(0xF0); // 0x80 is default
|
||||
SPI.transfer(0xA8); // Set Multiplex Ratio v
|
||||
SPI.transfer(0x3F);
|
||||
SPI.transfer(0xD3); // Set Display Offset v
|
||||
SPI.transfer(0x0);
|
||||
SPI.transfer(0x40); // Set Start Line (0)
|
||||
SPI.transfer(0x8D); // Charge Pump Setting v
|
||||
SPI.transfer(0x14); // Enable
|
||||
SPI.transfer(0x20); // Set Memory Mode v
|
||||
SPI.transfer(0x00); // Horizontal Addressing
|
||||
SPI.transfer(0xA1); // Set Segment Re-map (A0) | (b0001)
|
||||
SPI.transfer(0xC8); // Set COM Output Scan Direction
|
||||
SPI.transfer(0xDA); // Set COM Pins v
|
||||
SPI.transfer(0x12);
|
||||
SPI.transfer(0x81); // Set Contrast v
|
||||
SPI.transfer(0xCF);
|
||||
SPI.transfer(0xD9); // Set Precharge
|
||||
SPI.transfer(0xF1);
|
||||
SPI.transfer(0xDB); // Set VCom Detect
|
||||
SPI.transfer(0x40);
|
||||
SPI.transfer(0xA4); // Entire Display ON
|
||||
SPI.transfer(0xA6); // Set normal/inverse display
|
||||
SPI.transfer(0xAF); // Display On
|
||||
|
||||
*csport |= cspinmask;
|
||||
*csport |= cspinmask;
|
||||
*dcport &= ~dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
|
||||
SPI.transfer(0x20); // set display mode
|
||||
SPI.transfer(0x00); // horizontal addressing mode
|
||||
SPI.transfer(0x21); // set col address
|
||||
|
||||
unsigned char start = 0;
|
||||
unsigned char end = WIDTH - 1;
|
||||
SPI.transfer(start & 0x7F);
|
||||
SPI.transfer(end & 0x7F);
|
||||
SPI.transfer(0x22); // set page address
|
||||
|
||||
start = 0;
|
||||
end = (HEIGHT/8)-1;
|
||||
SPI.transfer(start & 0x07);
|
||||
SPI.transfer(end & 0x07);
|
||||
|
||||
*dcport |= dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
}
|
||||
|
||||
void Arduboy::blank()
|
||||
{
|
||||
for (int a = 0; a < (HEIGHT*WIDTH)/8; a++) SPI.transfer(0x00);
|
||||
}
|
||||
|
||||
void Arduboy::clearDisplay()
|
||||
{
|
||||
for (int a = 0; a < (HEIGHT*WIDTH)/8; a++) sBuffer[a] = 0x00;
|
||||
}
|
||||
|
||||
void Arduboy::drawPixel(int x, int y, uint16_t value)
|
||||
{
|
||||
if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int row = y / 8;
|
||||
if (value)
|
||||
{
|
||||
sBuffer[(row*WIDTH) + x] |= 1 << (y % 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sBuffer[(row*WIDTH) + x] &= ~(1 << (y % 8));
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
|
||||
{
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
drawPixel(x0, y0+r, color);
|
||||
drawPixel(x0, y0-r, color);
|
||||
drawPixel(x0+r, y0, color);
|
||||
drawPixel(x0-r, y0, color);
|
||||
|
||||
while (x<y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawCircleHelper
|
||||
(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color)
|
||||
{
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x<y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
if (cornername & 0x4)
|
||||
{
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
}
|
||||
if (cornername & 0x2)
|
||||
{
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
}
|
||||
if (cornername & 0x8)
|
||||
{
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
}
|
||||
if (cornername & 0x1)
|
||||
{
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
|
||||
{
|
||||
drawFastVLine(x0, y0-r, 2*r+1, color);
|
||||
fillCircleHelper(x0, y0, r, 3, 0, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillCircleHelper
|
||||
(
|
||||
int16_t x0,
|
||||
int16_t y0,
|
||||
int16_t r,
|
||||
uint8_t cornername,
|
||||
int16_t delta,
|
||||
uint16_t color
|
||||
)
|
||||
{
|
||||
// used to do circles and roundrects!
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x < y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
if (cornername & 0x1)
|
||||
{
|
||||
drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
|
||||
if (cornername & 0x2)
|
||||
{
|
||||
drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawLine
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
|
||||
{
|
||||
// bresenham's algorithm - thx wikpedia
|
||||
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
|
||||
if (steep) {
|
||||
swap(x0, y0);
|
||||
swap(x1, y1);
|
||||
}
|
||||
|
||||
if (x0 > x1) {
|
||||
swap(x0, x1);
|
||||
swap(y0, y1);
|
||||
}
|
||||
|
||||
int16_t dx, dy;
|
||||
dx = x1 - x0;
|
||||
dy = abs(y1 - y0);
|
||||
|
||||
int16_t err = dx / 2;
|
||||
int16_t ystep;
|
||||
|
||||
if (y0 < y1)
|
||||
{
|
||||
ystep = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ystep = -1;
|
||||
}
|
||||
|
||||
for (; x0 <= x1; x0++)
|
||||
{
|
||||
if (steep)
|
||||
{
|
||||
drawPixel(y0, x0, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawPixel(x0, y0, color);
|
||||
}
|
||||
|
||||
err -= dy;
|
||||
if (err < 0)
|
||||
{
|
||||
y0 += ystep;
|
||||
err += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawRect
|
||||
(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
||||
{
|
||||
drawFastHLine(x, y, w, color);
|
||||
drawFastHLine(x, y+h-1, w, color);
|
||||
drawFastVLine(x, y, h, color);
|
||||
drawFastVLine(x+w-1, y, h, color);
|
||||
}
|
||||
|
||||
void Arduboy::drawFastVLine
|
||||
(int16_t x, int16_t y, int16_t h, uint16_t color)
|
||||
{
|
||||
int end = y+h;
|
||||
for (int a = max(0,y); a < min(end,HEIGHT); a++)
|
||||
{
|
||||
drawPixel(x,a,color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawFastHLine
|
||||
(int16_t x, int16_t y, int16_t w, uint16_t color)
|
||||
{
|
||||
int end = x+w;
|
||||
for (int a = max(0,x); a < min(end,WIDTH); a++)
|
||||
{
|
||||
drawPixel(a,y,color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillRect
|
||||
(int16_t x, int16_t y, int16_t w, int16_t h, int16_t color)
|
||||
{
|
||||
// stupidest version - update in subclasses if desired!
|
||||
for (int16_t i=x; i<x+w; i++)
|
||||
{
|
||||
drawFastVLine(i, y, h, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillScreen(uint16_t color)
|
||||
{
|
||||
fillRect(0, 0, WIDTH, HEIGHT, color);
|
||||
}
|
||||
|
||||
void Arduboy::drawRoundRect
|
||||
(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
|
||||
{
|
||||
// smarter version
|
||||
drawFastHLine(x+r, y, w-2*r, color); // Top
|
||||
drawFastHLine(x+r, y+h-1, w-2*r, color); // Bottom
|
||||
drawFastVLine(x, y+r, h-2*r, color); // Left
|
||||
drawFastVLine(x+w-1, y+r, h-2*r, color); // Right
|
||||
// draw four corners
|
||||
drawCircleHelper(x+r, y+r, r, 1, color);
|
||||
drawCircleHelper(x+w-r-1, y+r, r, 2, color);
|
||||
drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
|
||||
drawCircleHelper(x+r, y+h-r-1, r, 8, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillRoundRect
|
||||
(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
|
||||
{
|
||||
// smarter version
|
||||
fillRect(x+r, y, w-2*r, h, color);
|
||||
|
||||
// draw four corners
|
||||
fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
|
||||
fillCircleHelper(x+r, y+r, r, 2, h-2*r-1, color);
|
||||
}
|
||||
|
||||
void Arduboy::drawTriangle
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
|
||||
{
|
||||
drawLine(x0, y0, x1, y1, color);
|
||||
drawLine(x1, y1, x2, y2, color);
|
||||
drawLine(x2, y2, x0, y0, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillTriangle
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
|
||||
{
|
||||
|
||||
int16_t a, b, y, last;
|
||||
// Sort coordinates by Y order (y2 >= y1 >= y0)
|
||||
if (y0 > y1)
|
||||
{
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
if (y1 > y2)
|
||||
{
|
||||
swap(y2, y1); swap(x2, x1);
|
||||
}
|
||||
if (y0 > y1)
|
||||
{
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
|
||||
if(y0 == y2)
|
||||
{ // Handle awkward all-on-same-line case as its own thing
|
||||
a = b = x0;
|
||||
if(x1 < a)
|
||||
{
|
||||
a = x1;
|
||||
}
|
||||
else if(x1 > b)
|
||||
{
|
||||
b = x1;
|
||||
}
|
||||
if(x2 < a)
|
||||
{
|
||||
a = x2;
|
||||
}
|
||||
else if(x2 > b)
|
||||
{
|
||||
b = x2;
|
||||
}
|
||||
drawFastHLine(a, y0, b-a+1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t dx01 = x1 - x0,
|
||||
dy01 = y1 - y0,
|
||||
dx02 = x2 - x0,
|
||||
dy02 = y2 - y0,
|
||||
dx12 = x2 - x1,
|
||||
dy12 = y2 - y1,
|
||||
sa = 0,
|
||||
sb = 0;
|
||||
|
||||
// For upper part of triangle, find scanline crossings for segments
|
||||
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
|
||||
// is included here (and second loop will be skipped, avoiding a /0
|
||||
// error there), otherwise scanline y1 is skipped here and handled
|
||||
// in the second loop...which also avoids a /0 error here if y0=y1
|
||||
// (flat-topped triangle).
|
||||
if (y1 == y2)
|
||||
{
|
||||
last = y1; // Include y1 scanline
|
||||
}
|
||||
else
|
||||
{
|
||||
last = y1-1; // Skip it
|
||||
}
|
||||
|
||||
|
||||
for(y = y0; y <= last; y++)
|
||||
{
|
||||
a = x0 + sa / dy01;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx01;
|
||||
sb += dx02;
|
||||
|
||||
if(a > b)
|
||||
{
|
||||
swap(a,b);
|
||||
}
|
||||
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
|
||||
// For lower part of triangle, find scanline crossings for segments
|
||||
// 0-2 and 1-2. This loop is skipped if y1=y2.
|
||||
sa = dx12 * (y - y1);
|
||||
sb = dx02 * (y - y0);
|
||||
|
||||
for(; y <= y2; y++)
|
||||
{
|
||||
a = x1 + sa / dy12;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx12;
|
||||
sb += dx02;
|
||||
|
||||
if(a > b)
|
||||
{
|
||||
swap(a,b);
|
||||
}
|
||||
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
}
|
||||
void Arduboy::drawBitmap
|
||||
(int16_t x,
|
||||
int16_t y,
|
||||
const uint8_t *bitmap,
|
||||
int16_t w,
|
||||
int16_t h,
|
||||
uint16_t color
|
||||
)
|
||||
{
|
||||
//bitmap is off screen
|
||||
if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1) return;
|
||||
|
||||
int yOffset = abs(y) % 8;
|
||||
int sRow = y / 8;
|
||||
|
||||
if (y < 0)
|
||||
{
|
||||
sRow--;
|
||||
yOffset = 8 - yOffset;
|
||||
}
|
||||
|
||||
for (int a = 0; a < h/8; a++)
|
||||
{
|
||||
int bRow = sRow + a;
|
||||
if (bRow > (HEIGHT/8)-1) break;
|
||||
if (bRow > -2) {
|
||||
for (int iCol = 0; iCol<w; iCol++)
|
||||
{
|
||||
if (iCol + x > (WIDTH-1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (iCol + x > 0)
|
||||
{
|
||||
if (bRow >= 0)
|
||||
{
|
||||
if (color)
|
||||
{
|
||||
this->sBuffer[ (bRow*WIDTH) + x + iCol ]
|
||||
|= pgm_read_byte(bitmap+(a*w)+iCol) << yOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->sBuffer[ (bRow*WIDTH) + x + iCol ]
|
||||
&= ~(pgm_read_byte(bitmap+(a*w)+iCol) << yOffset);
|
||||
}
|
||||
}
|
||||
if (yOffset && bRow<(HEIGHT/8)-1 && bRow > -2)
|
||||
{
|
||||
if (color)
|
||||
{
|
||||
this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ]
|
||||
|= pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ]
|
||||
&= ~(pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawChar
|
||||
(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)
|
||||
{
|
||||
|
||||
if ((x >= WIDTH) || // Clip right
|
||||
(y >= HEIGHT) || // Clip bottom
|
||||
((x + 5 * size - 1) < 0) || // Clip left
|
||||
((y + 8 * size - 1) < 0) // Clip top
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int8_t i=0; i<6; i++ )
|
||||
{
|
||||
uint8_t line;
|
||||
if (i == 5)
|
||||
{
|
||||
line = 0x0;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = pgm_read_byte(font+(c*5)+i);
|
||||
}
|
||||
|
||||
for (int8_t j = 0; j<8; j++)
|
||||
{
|
||||
if (line & 0x1)
|
||||
{
|
||||
if (size == 1) // default size
|
||||
{
|
||||
drawPixel(x+i, y+j, color);
|
||||
}
|
||||
else // big size
|
||||
{
|
||||
fillRect(x+(i*size), y+(j*size), size, size, color);
|
||||
}
|
||||
}
|
||||
else if (bg != color)
|
||||
{
|
||||
if (size == 1) // default size
|
||||
{
|
||||
drawPixel(x+i, y+j, bg);
|
||||
}
|
||||
else
|
||||
{ // big size
|
||||
fillRect(x+i*size, y+j*size, size, size, bg);
|
||||
}
|
||||
}
|
||||
|
||||
line >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::setCursor(int16_t x, int16_t y)
|
||||
{
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
void Arduboy::setTextSize(uint8_t s)
|
||||
{
|
||||
textsize = (s > 0) ? s : 1;
|
||||
}
|
||||
|
||||
void Arduboy::setTextWrap(boolean w)
|
||||
{
|
||||
wrap = w;
|
||||
}
|
||||
|
||||
size_t Arduboy::write(uint8_t c)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
cursor_y += textsize*8;
|
||||
cursor_x = 0;
|
||||
}
|
||||
else if (c == '\r')
|
||||
{
|
||||
// skip em
|
||||
}
|
||||
else
|
||||
{
|
||||
drawChar(cursor_x, cursor_y, c, 1, 0, textsize);
|
||||
cursor_x += textsize*6;
|
||||
if (wrap && (cursor_x > (WIDTH - textsize*6)))
|
||||
{
|
||||
cursor_y += textsize*8;
|
||||
cursor_x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::display()
|
||||
{
|
||||
this->drawScreen(sBuffer);
|
||||
}
|
||||
|
||||
void Arduboy::drawScreen(const unsigned char *image)
|
||||
{
|
||||
for (int a = 0; a < (HEIGHT*WIDTH)/8; a++)
|
||||
{
|
||||
SPI.transfer(pgm_read_byte(image + a));
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawScreen(unsigned char image[])
|
||||
{
|
||||
for (int a = 0; a < (HEIGHT*WIDTH)/8; a++)
|
||||
{
|
||||
SPI.transfer(image[a]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Arduboy::width() { return WIDTH; }
|
||||
|
||||
uint8_t Arduboy::height() { return HEIGHT; }
|
||||
|
||||
uint8_t Arduboy::getInput()
|
||||
{
|
||||
// b00lurdab
|
||||
uint8_t value = B00000000;
|
||||
|
||||
if (digitalRead(9) == 0) { value = value | B00100000; } // left
|
||||
if (digitalRead(8) == 0) { value = value | B00010000; } // up
|
||||
if (digitalRead(5) == 0) { value = value | B00001000; } // right
|
||||
if (digitalRead(10) == 0) { value = value | B00000100; } // down
|
||||
if (digitalRead(A0) == 0) { value = value | B00000010; } // a?
|
||||
if (digitalRead(A1) == 0) { value = value | B00000001; } // b?
|
||||
return value;
|
||||
}
|
||||
|
||||
void Arduboy::swap(int16_t& a, int16_t& b) {
|
||||
int temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
64
Arduboy.h
64
Arduboy.h
|
@ -1,64 +0,0 @@
|
|||
#ifndef Arduboy_h
|
||||
#define Arduboy_h
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Print.h>
|
||||
|
||||
#define CS 6
|
||||
#define DC 4
|
||||
#define RST 12
|
||||
|
||||
#define WIDTH 128
|
||||
#define HEIGHT 64
|
||||
|
||||
class Arduboy : public Print
|
||||
{
|
||||
public:
|
||||
Arduboy();
|
||||
uint8_t getInput();
|
||||
void start();
|
||||
void blank();
|
||||
void clearDisplay();
|
||||
void display();
|
||||
void drawScreen(const unsigned char *image);
|
||||
void drawScreen(unsigned char image[]);
|
||||
void drawPixel(int x, int y, uint16_t value);
|
||||
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
|
||||
void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color);
|
||||
void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
|
||||
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color);
|
||||
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
|
||||
void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t color);
|
||||
void fillScreen(uint16_t color);
|
||||
void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color);
|
||||
void fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color);
|
||||
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
|
||||
void fillTriangle (int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
|
||||
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);
|
||||
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size);
|
||||
void setCursor(int16_t x, int16_t y);
|
||||
void setTextSize(uint8_t s);
|
||||
void setTextWrap(boolean w);
|
||||
uint8_t width();
|
||||
uint8_t height();
|
||||
virtual size_t write(uint8_t);
|
||||
void swap(int16_t& a, int16_t& b);
|
||||
|
||||
private:
|
||||
unsigned char sBuffer[(HEIGHT*WIDTH)/8];
|
||||
uint8_t readCapacitivePin(int pinToMeasure);
|
||||
uint8_t readCapXtal(int pinToMeasure);
|
||||
volatile uint8_t *mosiport, *clkport, *csport, *dcport;
|
||||
uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask;
|
||||
|
||||
// Adafruit stuff
|
||||
protected:
|
||||
int16_t cursor_x, cursor_y;
|
||||
uint8_t textsize;
|
||||
boolean wrap; // If set, 'wrap' text at right edge of display
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
# Individual Contributors
|
||||
|
||||
- Kevin "Arduboy" Bates (@Arduboy)
|
||||
- arduboychris (@arduboychris)
|
||||
- Ross (@rogosher)
|
||||
- Andrew (@ace-dent)
|
||||
- Josh Goebel (@yyyc514)
|
||||
|
||||
|
||||
# Included code from other open source projects
|
||||
|
||||
- Original SSD1306 library
|
||||
https://github.com/adafruit/Adafruit_SSD1306
|
||||
BSD License
|
||||
Copyright (c) 2012, Adafruit Industries
|
||||
|
||||
- arduino-playtune
|
||||
https://github.com/LenShustek/arduino-playtune
|
||||
GNU General Public License v3
|
||||
(C) Copyright 2011, 2015, Len Shustek
|
|
@ -0,0 +1,32 @@
|
|||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2015, Kevin "Arduboy" Bates
|
||||
Copyright (c) 2015, Chris Martinez
|
||||
Copyright (c) 2015, Josh Goebel
|
||||
All rights reserved.
|
||||
|
||||
Please see CONTRIBUTORS.md for license information and copyright
|
||||
notices for any libraries we built on or redistribute.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
69
README.md
69
README.md
|
@ -1 +1,68 @@
|
|||
#ArduBreak
|
||||
Arduboy Library
|
||||
===============
|
||||
This library provides Arduboy's core functionality.
|
||||
|
||||
## Using the Library
|
||||
To use the Arduboy library, it must be installed and then included in your project.
|
||||
|
||||
### Install
|
||||
Install the library by cloning its repository.
|
||||
```
|
||||
$ git clone https://github.com/Arduboy/Arduboy.git
|
||||
```
|
||||
|
||||
#### Where to Install
|
||||
|
||||
The library should be installed into your user's home Arduino `libraries` directory. Refer to the following list for the location of the Arduino `libraries` folder.
|
||||
|
||||
**Linux**
|
||||
```
|
||||
/home/username/Documents/Arduino/libraries
|
||||
```
|
||||
**Mac**
|
||||
```
|
||||
/Users/username/Documents/Arduino/libraries
|
||||
```
|
||||
**Windows**
|
||||
```
|
||||
C:\Users\username\My Documents\Arduino\libraries
|
||||
```
|
||||
|
||||
If you don't find the `libraries` folder in one of the above locations, you can determine its location using the navigation menu `File > Preferences`. In the `Settings` tab will be a `Sketchbook location:` field. The `libraries` folder will be in the folder set in this field.
|
||||
|
||||
### Include
|
||||
To use the Arduboy library in your own sketches, include the `Arduboy.h` header file. To do so, add the following line to the top of your `.ino` file.
|
||||
```C
|
||||
#include "Arduboy.h"
|
||||
```
|
||||
|
||||
You can have the Arduino IDE add `#include "Arduboy.h"` to your sketch automatically by using the navigation menu `Sketch > Include Library > Arduboy`.
|
||||
|
||||
### Board Selection
|
||||
Select the **Leonardo** board as the target platform.
|
||||
|
||||
### Examples
|
||||
Example games and source can be found in the `examples` directory.
|
||||
|
||||
#### Playing Examples
|
||||
Find and play an example by opening it through the Arduino IDE, compiling, and uploading the example to the Arduboy.
|
||||
Examples can be found in the Arduino IDE in the navigation menu under, `File > Examples > Arduboy > Example_Name`.
|
||||
|
||||
### Running on a Development Board
|
||||
To run this library on a development Arduboy board, edit `src/core/core.h` so that `#define AB_DEVKIT` is uncommented and `#define ARDUBOY_10` is comment out.
|
||||
|
||||
```cpp
|
||||
//#define ARDUBOY_10 //< compile for the production Arduboy v1.0
|
||||
#define AB_DEVKIT //< compile for the official dev kit
|
||||
```
|
||||
|
||||
### Sketches Already Including the Arduboy Library
|
||||
Sketches that include copies of the Arduboy library may not compile if the Arduboy library has been installed system wide. In these cases the Arduino compiler will try and link the system Arduboy library source with the local header file, which can cause compilation errors if the local library source differs from the system's Arduboy source.
|
||||
|
||||
To compile sketches that have included copies of the Aruboy Library,
|
||||
|
||||
>Remove the local `Arduboy.cpp` and `Arduboy.h` files and try recompiling. This will only work in some cases.
|
||||
>
|
||||
>**OR**
|
||||
>
|
||||
>Rename `Arduboy.h` to `CustomArduboy.h` (or a similar name) and add `#include "CustomArduboy.h"` to the `.ino` sketch file.
|
||||
|
|
|
@ -9,23 +9,13 @@
|
|||
version 2.1 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include "Arduboy.h"
|
||||
|
||||
#include <EEPROM.h>
|
||||
#include "breakout_bitmaps.h"
|
||||
|
||||
#define OLED_DC 8
|
||||
#define OLED_CS 10 // SPI slave-select
|
||||
#define OLED_CLK 13 // hardware SPI clock
|
||||
#define OLED_MOSI 11 // hardware SPI MOSI
|
||||
#define OLED_RESET 7
|
||||
Arduboy arduboy;
|
||||
|
||||
Arduboy display;
|
||||
|
||||
const byte width = 128; //Width of screen
|
||||
const byte height = 64; //Hight of screen
|
||||
const unsigned int COLUMNS = 13; //Columns of bricks
|
||||
const unsigned int ROWS = 4; //Rows of bricks
|
||||
int dx = -1; //Initial movement of ball
|
||||
int dy = -1; //Initial movement of ball
|
||||
int xb; //Balls starting possition
|
||||
|
@ -33,7 +23,7 @@ int yb; //Balls starting possition
|
|||
boolean released; //If the ball has been released by the player
|
||||
boolean paused = false; //If the game has been paused
|
||||
byte xPaddle; //X position of paddle
|
||||
boolean isHit[5][12]; //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
|
||||
byte lives = 3; //Amount of lives
|
||||
byte level = 1; //Current level
|
||||
|
@ -58,71 +48,61 @@ byte rightBrick;
|
|||
byte topBrick;
|
||||
byte bottomBrick;
|
||||
|
||||
int ballclock = 0;
|
||||
byte tick;
|
||||
|
||||
#include "pins_arduino.h" // Arduino pre-1.0 needs this
|
||||
|
||||
PROGMEM const unsigned char arduino [] =
|
||||
{
|
||||
0x3F, 0xFF, 0xFF, 0xFC, 0x40, 0x00, 0x00, 0x02, 0x89, 0x99,0x54,
|
||||
0x91, 0x95, 0x55, 0x56, 0xA9, 0x9D, 0x95, 0x55, 0xA9, 0x95, 0x59,
|
||||
0xD4, 0x91, 0x40, 0x00, 0x00, 0x02, 0x3F, 0xFF, 0xFF, 0xFC
|
||||
};
|
||||
|
||||
void intro()
|
||||
{
|
||||
for(int i = -8; i < 28; i = i + 2)
|
||||
{
|
||||
display.clearDisplay();
|
||||
display.setCursor(46, i);
|
||||
display.print("ARDUBOY");
|
||||
display.display();
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(46, i);
|
||||
arduboy.print("ARDUBOY");
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
tone(A2, 987, 160);
|
||||
arduboy.tunes.tone(987, 160);
|
||||
delay(160);
|
||||
tone(A2, 1318, 400);
|
||||
arduboy.tunes.tone(1318, 400);
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
SPI.begin();
|
||||
display.start();
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0, 0);
|
||||
display.print("Hello World!");
|
||||
display.display();
|
||||
intro();
|
||||
}
|
||||
|
||||
void movePaddle()
|
||||
{
|
||||
//Move right
|
||||
if(xPaddle < width - 12)
|
||||
if(xPaddle < WIDTH - 12)
|
||||
{
|
||||
if( !digitalRead(5) )
|
||||
if (arduboy.pressed(RIGHT_BUTTON))
|
||||
{
|
||||
xPaddle++;
|
||||
xPaddle+=2;
|
||||
}
|
||||
}
|
||||
|
||||
//Move left
|
||||
if(xPaddle > 0)
|
||||
{
|
||||
if( !digitalRead(9))
|
||||
if (arduboy.pressed(LEFT_BUTTON))
|
||||
{
|
||||
xPaddle--;
|
||||
xPaddle-=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void moveBall()
|
||||
{
|
||||
tick++;
|
||||
if(released)
|
||||
{
|
||||
//Move ball
|
||||
xb=xb + dx;
|
||||
if (abs(dx)==2) {
|
||||
xb += dx/2;
|
||||
// 2x speed is really 1.5 speed
|
||||
if (tick%2==0)
|
||||
xb += dx/2;
|
||||
} else {
|
||||
xb += dx;
|
||||
}
|
||||
yb=yb + dy;
|
||||
|
||||
//Set bounds
|
||||
|
@ -136,19 +116,19 @@ void moveBall()
|
|||
{
|
||||
yb = 2;
|
||||
dy = -dy;
|
||||
tone(A2, 523, 250);
|
||||
arduboy.tunes.tone(523, 250);
|
||||
}
|
||||
|
||||
//Lose a life if bottom edge hit
|
||||
if (yb >= 64)
|
||||
{
|
||||
display.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
xPaddle = 54;
|
||||
yb=60;
|
||||
released = false;
|
||||
lives--;
|
||||
drawLives();
|
||||
tone(A2, 175, 250);
|
||||
arduboy.tunes.tone(175, 250);
|
||||
if (random(0, 2) == 0)
|
||||
{
|
||||
dx = 1;
|
||||
|
@ -164,15 +144,15 @@ void moveBall()
|
|||
{
|
||||
xb = 2;
|
||||
dx = -dx;
|
||||
tone(A2, 523, 250);
|
||||
arduboy.tunes.tone(523, 250);
|
||||
}
|
||||
|
||||
//Bounce off right side
|
||||
if (xb >= width - 2)
|
||||
if (xb >= WIDTH - 2)
|
||||
{
|
||||
xb = width - 4;
|
||||
xb = WIDTH - 4;
|
||||
dx = -dx;
|
||||
tone(A2, 523, 250);
|
||||
arduboy.tunes.tone(523, 250);
|
||||
}
|
||||
|
||||
//Bounce off paddle
|
||||
|
@ -180,13 +160,17 @@ void moveBall()
|
|||
{
|
||||
dy = -dy;
|
||||
dx = ((xb-(xPaddle+6))/3); //Applies spin on the ball
|
||||
tone(A2, 200, 250);
|
||||
// prevent straight bounce
|
||||
if (dx == 0) {
|
||||
dx = (random(0,2) == 1) ? 1 : -1;
|
||||
}
|
||||
arduboy.tunes.tone(200, 250);
|
||||
}
|
||||
|
||||
//Bounce off Bricks
|
||||
for (byte row = 0; row < 4; row++)
|
||||
for (byte row = 0; row < ROWS; row++)
|
||||
{
|
||||
for (byte column = 0; column < 14; column++)
|
||||
for (byte column = 0; column < COLUMNS; column++)
|
||||
{
|
||||
if (!isHit[row][column])
|
||||
{
|
||||
|
@ -203,7 +187,7 @@ void moveBall()
|
|||
Score();
|
||||
brickCount++;
|
||||
isHit[row][column] = true;
|
||||
display.drawRect(10*column, 2+6*row, 8, 4, 0);
|
||||
arduboy.drawRect(10*column, 2+6*row, 8, 4, 0);
|
||||
|
||||
//Vertical collision
|
||||
if (bottomBall > bottomBrick || topBall < topBrick)
|
||||
|
@ -214,7 +198,7 @@ void moveBall()
|
|||
dy =- dy;
|
||||
yb += dy;
|
||||
bounced = true;
|
||||
tone(A2, 261, 250);
|
||||
arduboy.tunes.tone(261, 250);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +211,7 @@ void moveBall()
|
|||
dx =- dx;
|
||||
xb += dx;
|
||||
bounced = true;
|
||||
tone(A2, 261, 250);
|
||||
arduboy.tunes.tone(261, 250);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +227,7 @@ void moveBall()
|
|||
xb=xPaddle + 5;
|
||||
|
||||
//Release ball if FIRE pressed
|
||||
pad3 = !digitalRead(A0);
|
||||
pad3 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if (pad3 == 1 && oldpad3 == 0)
|
||||
{
|
||||
released=true;
|
||||
|
@ -266,50 +250,47 @@ void moveBall()
|
|||
|
||||
void drawBall()
|
||||
{
|
||||
display.drawPixel(xb, yb, 0);
|
||||
display.drawPixel(xb+1, yb, 0);
|
||||
display.drawPixel(xb, yb+1, 0);
|
||||
display.drawPixel(xb+1, yb+1, 0);
|
||||
// arduboy.setCursor(0,0);
|
||||
// arduboy.print(arduboy.cpuLoad());
|
||||
// arduboy.print(" ");
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
|
||||
if(ballclock>4)
|
||||
{
|
||||
moveBall();
|
||||
ballclock=0;
|
||||
}
|
||||
moveBall();
|
||||
|
||||
ballclock++;
|
||||
|
||||
display.drawPixel(xb, yb, 1);
|
||||
display.drawPixel(xb+1, yb, 1);
|
||||
display.drawPixel(xb, yb+1, 1);
|
||||
display.drawPixel(xb+1, yb+1, 1);
|
||||
arduboy.drawPixel(xb, yb, 1);
|
||||
arduboy.drawPixel(xb+1, yb, 1);
|
||||
arduboy.drawPixel(xb, yb+1, 1);
|
||||
arduboy.drawPixel(xb+1, yb+1, 1);
|
||||
}
|
||||
|
||||
void drawPaddle()
|
||||
{
|
||||
display.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
movePaddle();
|
||||
display.drawRect(xPaddle, 63, 11, 1, 1);
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 1);
|
||||
}
|
||||
|
||||
void drawLives()
|
||||
{
|
||||
sprintf(text, "LIVES:%u", lives);
|
||||
display.setCursor(0, 90);
|
||||
display.print(text);
|
||||
arduboy.setCursor(0, 90);
|
||||
arduboy.print(text);
|
||||
}
|
||||
|
||||
void drawGameOver()
|
||||
{
|
||||
display.drawPixel(xb, yb, 0);
|
||||
display.drawPixel(xb+1, yb, 0);
|
||||
display.drawPixel(xb, yb+1, 0);
|
||||
display.drawPixel(xb+1, yb+1, 0);
|
||||
display.setCursor(52, 42);
|
||||
display.print( "Game");
|
||||
display.setCursor(52, 54);
|
||||
display.print("Over");
|
||||
display.display();
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
arduboy.setCursor(52, 42);
|
||||
arduboy.print( "Game");
|
||||
arduboy.setCursor(52, 54);
|
||||
arduboy.print("Over");
|
||||
arduboy.display();
|
||||
delay(4000);
|
||||
}
|
||||
|
||||
|
@ -317,17 +298,17 @@ void pause()
|
|||
{
|
||||
paused = true;
|
||||
//Draw pause to the screen
|
||||
display.setCursor(52, 45);
|
||||
display.print("PAUSE");
|
||||
display.display();
|
||||
arduboy.setCursor(52, 45);
|
||||
arduboy.print("PAUSE");
|
||||
arduboy.display();
|
||||
while (paused)
|
||||
{
|
||||
delay(150);
|
||||
//Unpause if FIRE is pressed
|
||||
pad2 = !digitalRead(A0);
|
||||
pad2 = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if (pad2 > 1 && oldpad2 == 0 && released)
|
||||
{
|
||||
display.fillRect(52, 45, 30, 11, 0);
|
||||
arduboy.fillRect(52, 45, 30, 11, 0);
|
||||
|
||||
paused=false;
|
||||
}
|
||||
|
@ -339,19 +320,19 @@ void Score()
|
|||
{
|
||||
score += (level*10);
|
||||
sprintf(text, "SCORE:%u", score);
|
||||
display.setCursor(80, 90);
|
||||
display.print(text);
|
||||
arduboy.setCursor(80, 90);
|
||||
arduboy.print(text);
|
||||
}
|
||||
|
||||
void newLevel(){
|
||||
//Undraw paddle
|
||||
display.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
arduboy.drawRect(xPaddle, 63, 11, 1, 0);
|
||||
|
||||
//Undraw ball
|
||||
display.drawPixel(xb, yb, 0);
|
||||
display.drawPixel(xb+1, yb, 0);
|
||||
display.drawPixel(xb, yb+1, 0);
|
||||
display.drawPixel(xb+1, yb+1, 0);
|
||||
arduboy.drawPixel(xb, yb, 0);
|
||||
arduboy.drawPixel(xb+1, yb, 0);
|
||||
arduboy.drawPixel(xb, yb+1, 0);
|
||||
arduboy.drawPixel(xb+1, yb+1, 0);
|
||||
|
||||
//Alter various variables to reset the game
|
||||
xPaddle = 54;
|
||||
|
@ -364,7 +345,7 @@ void newLevel(){
|
|||
for (byte column = 0; column < 13; column++)
|
||||
{
|
||||
isHit[row][column] = false;
|
||||
display.drawRect(10*column, 2+6*row, 8, 4, 1);
|
||||
arduboy.drawRect(10*column, 2+6*row, 8, 4, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -373,8 +354,8 @@ void newLevel(){
|
|||
|
||||
//Draws the initial score
|
||||
sprintf(text, "SCORE:%u", score);
|
||||
display.setCursor(80, 90);
|
||||
display.print(text);
|
||||
arduboy.setCursor(80, 90);
|
||||
arduboy.print(text);
|
||||
}
|
||||
|
||||
//Used to delay images while reading button input
|
||||
|
@ -383,7 +364,7 @@ boolean pollFireButton(int n)
|
|||
for(int i = 0; i < n; i++)
|
||||
{
|
||||
delay(15);
|
||||
pad = !digitalRead(A0);
|
||||
pad = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
if(pad == 1 && oldpad == 0)
|
||||
{
|
||||
oldpad3 = 1; //Forces pad loop 3 to run once
|
||||
|
@ -403,17 +384,17 @@ boolean displayHighScores(byte file)
|
|||
// is 5 bytes long: 3 bytes for initials and two bytes for score.
|
||||
int address = file*10*5;
|
||||
byte hi, lo;
|
||||
display.clearDisplay();
|
||||
display.setCursor(32, 0);
|
||||
display.print("HIGH SCORES");
|
||||
display.display();
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(32, 0);
|
||||
arduboy.print("HIGH SCORES");
|
||||
arduboy.display();
|
||||
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
sprintf(text, "%2d", i+1);
|
||||
display.setCursor(x,y+(i*8));
|
||||
display.print( text);
|
||||
display.display();
|
||||
arduboy.setCursor(x,y+(i*8));
|
||||
arduboy.print( text);
|
||||
arduboy.display();
|
||||
hi = EEPROM.read(address + (5*i));
|
||||
lo = EEPROM.read(address + (5*i) + 1);
|
||||
|
||||
|
@ -433,9 +414,9 @@ boolean displayHighScores(byte file)
|
|||
if (score > 0)
|
||||
{
|
||||
sprintf(text, "%c%c%c %u", initials[0], initials[1], initials[2], score);
|
||||
display.setCursor(x + 24, y + (i*8));
|
||||
display.print(text);
|
||||
display.display();
|
||||
arduboy.setCursor(x + 24, y + (i*8));
|
||||
arduboy.print(text);
|
||||
arduboy.display();
|
||||
}
|
||||
}
|
||||
if (pollFireButton(300))
|
||||
|
@ -443,18 +424,18 @@ boolean displayHighScores(byte file)
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
display.display();
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
boolean titleScreen()
|
||||
{
|
||||
//Clears the screen
|
||||
display.clearDisplay();
|
||||
display.setCursor(16,22);
|
||||
display.setTextSize(2);
|
||||
display.print("ARAKNOID");
|
||||
display.setTextSize(1);
|
||||
display.display();
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(16,22);
|
||||
arduboy.setTextSize(2);
|
||||
arduboy.print("ARAKNOID");
|
||||
arduboy.setTextSize(1);
|
||||
arduboy.display();
|
||||
if (pollFireButton(25))
|
||||
{
|
||||
return true;
|
||||
|
@ -464,24 +445,24 @@ boolean titleScreen()
|
|||
for(byte i = 0; i < 5; i++)
|
||||
{
|
||||
//Draws "Press FIRE"
|
||||
//display.bitmap(31, 53, fire); display.display();
|
||||
display.setCursor(31, 53);
|
||||
display.print("PRESS FIRE!");
|
||||
display.display();
|
||||
//arduboy.bitmap(31, 53, fire); arduboy.display();
|
||||
arduboy.setCursor(31, 53);
|
||||
arduboy.print("PRESS FIRE!");
|
||||
arduboy.display();
|
||||
|
||||
if (pollFireButton(50))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//Removes "Press FIRE"
|
||||
display.clearDisplay();
|
||||
display.setCursor(16,22);
|
||||
display.setTextSize(2);
|
||||
display.print("ARAKNOID");
|
||||
display.setTextSize(1);
|
||||
display.display();
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(16,22);
|
||||
arduboy.setTextSize(2);
|
||||
arduboy.print("ARAKNOID");
|
||||
arduboy.setTextSize(1);
|
||||
arduboy.display();
|
||||
|
||||
display.display();
|
||||
arduboy.display();
|
||||
if (pollFireButton(25))
|
||||
{
|
||||
return true;
|
||||
|
@ -496,7 +477,7 @@ void enterInitials()
|
|||
{
|
||||
char index = 0;
|
||||
|
||||
display.clearDisplay();
|
||||
arduboy.clear();
|
||||
|
||||
initials[0] = ' ';
|
||||
initials[1] = ' ';
|
||||
|
@ -504,29 +485,29 @@ void enterInitials()
|
|||
|
||||
while (true)
|
||||
{
|
||||
display.display();
|
||||
display.clearDisplay();
|
||||
arduboy.display();
|
||||
arduboy.clear();
|
||||
|
||||
display.setCursor(16,0);
|
||||
display.print("HIGH SCORE");
|
||||
arduboy.setCursor(16,0);
|
||||
arduboy.print("HIGH SCORE");
|
||||
sprintf(text, "%u", score);
|
||||
display.setCursor(88, 0);
|
||||
display.print(text);
|
||||
display.setCursor(56, 20);
|
||||
display.print(initials[0]);
|
||||
display.setCursor(64, 20);
|
||||
display.print(initials[1]);
|
||||
display.setCursor(72, 20);
|
||||
display.print(initials[2]);
|
||||
arduboy.setCursor(88, 0);
|
||||
arduboy.print(text);
|
||||
arduboy.setCursor(56, 20);
|
||||
arduboy.print(initials[0]);
|
||||
arduboy.setCursor(64, 20);
|
||||
arduboy.print(initials[1]);
|
||||
arduboy.setCursor(72, 20);
|
||||
arduboy.print(initials[2]);
|
||||
for(byte i = 0; i < 3; i++)
|
||||
{
|
||||
display.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1);
|
||||
arduboy.drawLine(56 + (i*8), 27, 56 + (i*8) + 6, 27, 1);
|
||||
}
|
||||
display.drawLine(56, 28, 88, 28, 0);
|
||||
display.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, 1);
|
||||
arduboy.drawLine(56, 28, 88, 28, 0);
|
||||
arduboy.drawLine(56 + (index*8), 28, 56 + (index*8) + 6, 28, 1);
|
||||
delay(150);
|
||||
|
||||
if (!digitalRead(5))
|
||||
if (arduboy.pressed(LEFT_BUTTON) || arduboy.pressed(B_BUTTON))
|
||||
{
|
||||
index--;
|
||||
if (index < 0)
|
||||
|
@ -534,25 +515,25 @@ void enterInitials()
|
|||
index = 0;
|
||||
} else
|
||||
{
|
||||
tone(A2, 1046, 250);
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
}
|
||||
}
|
||||
|
||||
if (!digitalRead(9))
|
||||
if (arduboy.pressed(RIGHT_BUTTON))
|
||||
{
|
||||
index++;
|
||||
if (index > 2)
|
||||
{
|
||||
index = 2;
|
||||
} else {
|
||||
tone(A2, 1046, 250);
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
}
|
||||
}
|
||||
|
||||
if (!digitalRead(8))
|
||||
if (arduboy.pressed(DOWN_BUTTON))
|
||||
{
|
||||
initials[index]++;
|
||||
tone(A2, 523, 250);
|
||||
arduboy.tunes.tone(523, 250);
|
||||
// A-Z 0-9 :-? !-/ ' '
|
||||
if (initials[index] == '0')
|
||||
{
|
||||
|
@ -572,10 +553,10 @@ void enterInitials()
|
|||
}
|
||||
}
|
||||
|
||||
if (!digitalRead(10))
|
||||
if (arduboy.pressed(UP_BUTTON))
|
||||
{
|
||||
initials[index]--;
|
||||
tone(A2, 523, 250);
|
||||
arduboy.tunes.tone(523, 250);
|
||||
if (initials[index] == ' ') {
|
||||
initials[index] = '?';
|
||||
}
|
||||
|
@ -590,14 +571,14 @@ void enterInitials()
|
|||
}
|
||||
}
|
||||
|
||||
if (!digitalRead(A0))
|
||||
if (arduboy.pressed(A_BUTTON))
|
||||
{
|
||||
if (index < 2)
|
||||
{
|
||||
index++;
|
||||
tone(A2, 1046, 250);
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
} else {
|
||||
tone(A2, 1046, 250);
|
||||
arduboy.tunes.tone(1046, 250);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -675,13 +656,24 @@ void enterHighScore(byte file)
|
|||
}
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
arduboy.setFrameRate(60);
|
||||
arduboy.print("Hello World!");
|
||||
arduboy.display();
|
||||
intro();
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
display.display();
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
//Title screen loop switches from title screen
|
||||
//and high scores utill FIRE is pressed
|
||||
//and high scores until FIRE is pressed
|
||||
while (!start)
|
||||
{
|
||||
start = titleScreen();
|
||||
|
@ -691,12 +683,12 @@ void loop()
|
|||
}
|
||||
}
|
||||
|
||||
//Inital level draw
|
||||
//Initial level draw
|
||||
if (!initialDraw)
|
||||
{
|
||||
//Clears the screen
|
||||
display.display();
|
||||
display.clearDisplay();
|
||||
arduboy.display();
|
||||
arduboy.clear();
|
||||
//Selects Font
|
||||
//Draws the new level
|
||||
newLevel();
|
||||
|
@ -708,7 +700,7 @@ void loop()
|
|||
drawPaddle();
|
||||
|
||||
//Pause game if FIRE pressed
|
||||
pad = !digitalRead(A0);
|
||||
pad = arduboy.pressed(A_BUTTON) || arduboy.pressed(B_BUTTON);
|
||||
|
||||
if(pad >1 && oldpad==0 && released)
|
||||
{
|
||||
|
@ -719,7 +711,7 @@ void loop()
|
|||
oldpad=pad;
|
||||
drawBall();
|
||||
|
||||
if(brickCount==60)
|
||||
if(brickCount == ROWS * COLUMNS)
|
||||
{
|
||||
level++;
|
||||
newLevel();
|
||||
|
@ -733,13 +725,15 @@ void loop()
|
|||
enterHighScore(2);
|
||||
}
|
||||
|
||||
display.clearDisplay();
|
||||
arduboy.clear();
|
||||
initialDraw=false;
|
||||
start=false;
|
||||
lives=3;
|
||||
score=0;
|
||||
newLevel();
|
||||
}
|
||||
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# ArduBreakout
|
||||
|
||||
Brick breaking game in the vein of Atari's *Breakout*.
|
||||
|
||||
Control the paddle with the directional keys to keep a ball bouncing against a brick wall until all of the bricks are broken.
|
||||
|
||||
High scores are saved to EEPROM and can be saved through Arduboy restarts.
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef ASTEROID_BITMAPS_H
|
||||
#define ASTEROID_BITMAPS_H
|
||||
#ifndef BREAKOUT_BITMAPS_H
|
||||
#define BREAKOUT_BITMAPS_H
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
|
@ -8,6 +8,3 @@ extern const unsigned char title[];
|
|||
extern const unsigned char arrow[];
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
Buttons example
|
||||
June 11, 2015
|
||||
Copyright (C) 2015 David Martinez
|
||||
All rights reserved.
|
||||
This code is the most basic barebones code for showing how to use buttons in
|
||||
Arduboy.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "Arduboy.h"
|
||||
|
||||
// Make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
// Variables for your game go here.
|
||||
char text[] = "Press Buttons!";
|
||||
byte x;
|
||||
byte y;
|
||||
|
||||
// Width of each charcter including inter-character space
|
||||
#define CHAR_WIDTH 6
|
||||
|
||||
// Height of each charater
|
||||
#define CHAR_HEIGHT 8
|
||||
|
||||
// To get the number of characters, we subtract 1 from the length of
|
||||
// the array because there will be a NULL terminator at the end.
|
||||
#define NUM_CHARS (sizeof(text) - 1)
|
||||
|
||||
// This is the highest value that x can be without the end of the text
|
||||
// going farther than the right side of the screen. We add one because
|
||||
// there will be a 1 pixel space at the end of the last character.
|
||||
// WIDTH and HEIGHT are defined in the Arduboy library.
|
||||
#define X_MAX (WIDTH - (NUM_CHARS * CHAR_WIDTH) + 1)
|
||||
|
||||
// This is the highest value that y can be without the text going below
|
||||
// the bottom of the screen.
|
||||
#define Y_MAX (HEIGHT - CHAR_HEIGHT)
|
||||
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
//initiate arduboy instance
|
||||
arduboy.begin();
|
||||
|
||||
// here we set the framerate to 30, we do not need to run at default 60 and
|
||||
// it saves us battery life.
|
||||
arduboy.setFrameRate(30);
|
||||
|
||||
// set x and y to the middle of the screen
|
||||
x = (WIDTH / 2) - (NUM_CHARS * CHAR_WIDTH / 2);
|
||||
y = (HEIGHT / 2) - (CHAR_HEIGHT / 2);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// the next couple of lines will deal with checking if the D-pad buttons
|
||||
// are pressed and move our text accordingly.
|
||||
// We check to make sure that x and y stay within a range that keeps the
|
||||
// text on the screen.
|
||||
|
||||
// if the right button is pressed move 1 pixel to the right every frame
|
||||
if(arduboy.pressed(RIGHT_BUTTON) && (x < X_MAX)) {
|
||||
x++;
|
||||
}
|
||||
|
||||
// if the left button is pressed move 1 pixel to the left every frame
|
||||
if(arduboy.pressed(LEFT_BUTTON) && (x > 0)) {
|
||||
x--;
|
||||
}
|
||||
|
||||
// if the up button or B button is pressed move 1 pixel up every frame
|
||||
if((arduboy.pressed(UP_BUTTON) || arduboy.pressed(B_BUTTON)) && (y > 0)) {
|
||||
y--;
|
||||
}
|
||||
|
||||
// if the down button or A button is pressed move 1 pixel down every frame
|
||||
if((arduboy.pressed(DOWN_BUTTON) || arduboy.pressed(A_BUTTON)) && (y < Y_MAX)) {
|
||||
y++;
|
||||
}
|
||||
|
||||
|
||||
// we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
// we set our cursor x pixels to the right and y down from the top
|
||||
arduboy.setCursor(x, y);
|
||||
|
||||
// then we print to screen what is stored in our text variable we declared earlier
|
||||
arduboy.print(text);
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display.
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Hello, World! example
|
||||
June 11, 2015
|
||||
Copyright (C) 2015 David Martinez
|
||||
All rights reserved.
|
||||
This code is the most basic barebones code for writing a program for Arduboy.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "Arduboy.h"
|
||||
|
||||
// make an instance of arduboy used for many functions
|
||||
Arduboy arduboy;
|
||||
|
||||
|
||||
// This function runs once in your game.
|
||||
// use it for anything that needs to be set only once in your game.
|
||||
void setup() {
|
||||
// initiate arduboy instance
|
||||
arduboy.begin();
|
||||
|
||||
// here we set the framerate to 15, we do not need to run at
|
||||
// default 60 and it saves us battery life
|
||||
arduboy.setFrameRate(15);
|
||||
}
|
||||
|
||||
|
||||
// our main game loop, this runs once every cycle/frame.
|
||||
// this is where our game logic goes.
|
||||
void loop() {
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
// first we clear our screen to black
|
||||
arduboy.clear();
|
||||
|
||||
// we set our cursor 5 pixels to the right and 10 down from the top
|
||||
// (positions start at 0, 0)
|
||||
arduboy.setCursor(4, 9);
|
||||
|
||||
// then we print to screen what is in the Quotation marks ""
|
||||
arduboy.print(F("Hello, world!"));
|
||||
|
||||
// then we finaly we tell the arduboy to display what we just wrote to the display
|
||||
arduboy.display();
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
### Benchmark run as of June 2015
|
||||
|
||||
- drawPixel
|
||||
- drawTriangle
|
||||
- fillTriangle
|
||||
- drawRect
|
||||
- fillRect
|
||||
- drawCircle
|
||||
- fillCircle
|
||||
- drawRoundRect
|
||||
- fillRoundRect
|
||||
- drawLine
|
||||
- drawFastHLine
|
||||
- drawFastVLine
|
||||
- drawBitmap
|
||||
- drawSlowBitmap
|
||||
- paint
|
|
@ -0,0 +1,4 @@
|
|||
# Tunes
|
||||
Play a musical composition using the Arduboy.
|
||||
|
||||
A small composition is stored by `byte PROGMEM score`. The score is played in the sketch loop using `playScore(score)`.
|
|
@ -0,0 +1,201 @@
|
|||
#include "Arduboy.h"
|
||||
|
||||
const byte PROGMEM score [] = {
|
||||
// Sinfonia No.12 in A major BWV.798 J.S.Bach
|
||||
// Conductor Track
|
||||
7,208, 0x90,0x45, 0x91,0x39, 1,77, 0x80, 0x81, 0x90,0x44, 0,166, 0x80, 0x90,0x45, 0,166, 0x80, 0x90,0x47,
|
||||
0x91,0x38, 1,77, 0x80, 0x81, 0x90,0x45, 0,166, 0x80, 0x90,0x44, 0,166, 0x80, 0x90,0x45, 0x91,0x36, 1,77,
|
||||
0x81, 1,77, 0x91,0x31, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x44, 0,166, 0x80, 0x90,0x45,
|
||||
0,166, 0x80, 0x90,0x47, 0x91,0x32, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x49, 0,166, 0x80,
|
||||
0x90,0x40, 0,166, 0x80, 0x90,0x4A, 0x91,0x34, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x4C, 1,77,
|
||||
0x80, 0x90,0x49, 0x91,0x2D, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x39, 0,166, 0x80,
|
||||
0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x38, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x81, 0x90,0x4C,
|
||||
0x91,0x36, 0,166, 0x80, 0x90,0x4E, 0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x34, 0x92,0x40, 0,166, 0x80, 0x90,0x51,
|
||||
0,166, 0x80, 0x81, 0x82, 0x90,0x53, 0x91,0x3F, 0,166, 0x81, 0x91,0x40, 0,166, 0x81, 0x91,0x3F, 0x92,0x42,
|
||||
0,166, 0x80, 0x90,0x51, 0,166, 0x80, 0x81, 0x82, 0x90,0x50, 0x91,0x40, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x3F,
|
||||
0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x3D, 0x92,0x40, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x90,0x4C, 0x91,0x38, 0,166, 0x82, 0x92,0x42, 0,166, 0x81, 0x82,
|
||||
0x91,0x3F, 0,166, 0x81, 0x91,0x40, 0,166, 0x81, 0x91,0x42, 0x92,0x39, 0,166, 0x81, 0x91,0x3B, 0,166,
|
||||
0x81, 0x82, 0x91,0x44, 0,166, 0x81, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x4B, 0x92,0x3B, 0,166,
|
||||
0x80, 0x82, 0x90,0x3B, 0,166, 0x80, 0x90,0x47, 1,77, 0x80, 0x81, 0x90,0x4C, 0x91,0x44, 0x92,0x40, 0,166,
|
||||
0x81, 0x91,0x45, 0,166, 0x80, 0x81, 0x82, 0x90,0x4A, 0x91,0x47, 0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x45, 0,166,
|
||||
0x80, 0x81, 0x90,0x4A, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x40,
|
||||
0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x3E, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x3D, 0x92,0x39, 0,166, 0x81,
|
||||
0x91,0x49, 0,166, 0x81, 0x82, 0x91,0x4E, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x39, 0,166, 0x80,
|
||||
0x82, 0x90,0x50, 0x92,0x3B, 0,166, 0x81, 0x91,0x4B, 0,166, 0x81, 0x82, 0x91,0x4C, 0x92,0x39, 0,166, 0x80,
|
||||
0x82, 0x90,0x50, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x4E, 0x92,0x39, 0,166, 0x81, 0x91,0x49, 0,166, 0x81,
|
||||
0x91,0x4A, 0,166, 0x80, 0x90,0x4E, 0,166, 0x80, 0x90,0x4C, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x3B, 0,166,
|
||||
0x81, 0x82, 0x91,0x49, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x4C, 0x92,0x39, 0,166, 0x80, 0x81, 0x82, 0x90,0x3B,
|
||||
0x91,0x4A, 0x92,0x44, 0,166, 0x80, 0x90,0x34, 0,166, 0x80, 0x81, 0x82, 0x90,0x3D, 0x91,0x49, 0x92,0x45, 0,166,
|
||||
0x80, 0x90,0x34, 0,166, 0x80, 0x81, 0x90,0x3E, 0x91,0x47, 0,166, 0x80, 0x90,0x34, 0,166, 0x80, 0x82, 0x90,0x44,
|
||||
0x92,0x40, 1,77, 0x80, 0x81, 0x82, 0x90,0x3D, 0x91,0x45, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x90,0x39,
|
||||
0x92,0x49, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x82, 0x90,0x3D, 0x92,0x4E, 0,166, 0x80, 0x90,0x3F, 0,166,
|
||||
0x80, 0x81, 0x90,0x45, 0x91,0x40, 0,166, 0x81, 0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x44, 0x91,0x3B, 0,166,
|
||||
0x81, 0x91,0x39, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x38, 0,166, 0x82, 0x92,0x39, 0,166, 0x81, 0x82, 0x91,0x4C,
|
||||
0x92,0x3B, 0,166, 0x82, 0x92,0x3D, 0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x3F, 0,166, 0x82, 0x92,0x40, 0,166,
|
||||
0x80, 0x82, 0x90,0x42, 0x92,0x39, 0,166, 0x82, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x4B, 0x92,0x36, 0,166,
|
||||
0x81, 0x82, 0x91,0x4C, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x4E, 0x92,0x39, 0,166, 0x82, 0x92,0x38, 0,166,
|
||||
0x81, 0x82, 0x91,0x4C, 0x92,0x39, 0,166, 0x81, 0x82, 0x91,0x4B, 0x92,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x4C,
|
||||
0x91,0x38, 0,166, 0x92,0x4B, 0,166, 0x81, 0x82, 0x91,0x49, 0x92,0x39, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x3B,
|
||||
0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x3D, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x4B,
|
||||
0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x40, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x3F, 0,166, 0x80,
|
||||
0x82, 0x90,0x47, 0x92,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x50, 0x91,0x39, 0x92,0x40, 0,166, 0x80, 0x81, 0x90,0x47,
|
||||
0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x36, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x82, 0x90,0x53,
|
||||
0x91,0x3F, 0x92,0x3B, 1,77, 0x80, 0x81, 0x82, 0x90,0x50, 0x91,0x34, 0x92,0x40, 0,166, 0x80, 0x90,0x51, 0,166,
|
||||
0x80, 0x90,0x53, 0,166, 0x80, 0x90,0x51, 0,166, 0x80, 0x81, 0x82, 0x90,0x50, 0,166, 0x80, 0x90,0x4E, 0x91,0x39,
|
||||
0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0x91,0x35, 0,166, 0x81, 0x91,0x31, 0,166, 0x81, 0x91,0x44, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x31,
|
||||
0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x38, 0,166, 0x82, 0x92,0x31, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x35,
|
||||
0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x31, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x36, 0,166, 0x82, 0x92,0x31,
|
||||
0,166, 0x80, 0x82, 0x90,0x38, 0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x31, 0x92,0x4A, 0,166, 0x80, 0x82, 0x90,0x36,
|
||||
0x92,0x4C, 0,166, 0x80, 0x90,0x31, 0,166, 0x80, 0x82, 0x90,0x34, 0x92,0x4A, 0,166, 0x80, 0x82, 0x90,0x31,
|
||||
0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x33, 0x92,0x47, 0,166, 0x80, 0x90,0x2F, 0,166, 0x80, 0x81, 0x90,0x34,
|
||||
0x91,0x42, 0,166, 0x80, 0x81, 0x90,0x2F, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x36, 0x91,0x45, 0,166, 0x80,
|
||||
0x90,0x2F, 0,166, 0x80, 0x81, 0x90,0x33, 0x91,0x44, 0,166, 0x80, 0x81, 0x90,0x2F, 0x91,0x42, 0,166, 0x80,
|
||||
0x81, 0x90,0x44, 0x91,0x34, 0,166, 0x81, 0x91,0x2F, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x36, 0,166, 0x81,
|
||||
0x82, 0x91,0x49, 0x92,0x2F, 0,166, 0x81, 0x82, 0x91,0x4A, 0x92,0x34, 0,166, 0x82, 0x92,0x2F, 0,166, 0x81,
|
||||
0x82, 0x91,0x49, 0x92,0x32, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x2F, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x31,
|
||||
0,166, 0x82, 0x92,0x2D, 0,166, 0x80, 0x82, 0x90,0x32, 0x92,0x41, 0,166, 0x80, 0x82, 0x90,0x42, 0x92,0x2D,
|
||||
0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x34, 0,166, 0x82, 0x92,0x2D, 0,166, 0x80, 0x82, 0x90,0x42, 0x92,0x31,
|
||||
0,166, 0x80, 0x82, 0x90,0x2D, 0x92,0x41, 0,166, 0x80, 0x82, 0x90,0x42, 0x92,0x32, 0,166, 0x82, 0x92,0x2D,
|
||||
0,166, 0x81, 0x82, 0x91,0x34, 0x92,0x45, 0,166, 0x81, 0x82, 0x91,0x2D, 0x92,0x47, 0,166, 0x81, 0x82, 0x91,0x32,
|
||||
0x92,0x49, 0,166, 0x81, 0x91,0x2D, 0,166, 0x81, 0x82, 0x91,0x31, 0x92,0x47, 0,166, 0x81, 0x82, 0x91,0x2D,
|
||||
0x92,0x45, 0,166, 0x81, 0x82, 0x91,0x30, 0x92,0x44, 0,166, 0x81, 0x91,0x2C, 0,166, 0x80, 0x81, 0x90,0x31,
|
||||
0x91,0x3F, 0,166, 0x80, 0x81, 0x90,0x2C, 0x91,0x41, 0,166, 0x80, 0x81, 0x90,0x33, 0x91,0x42, 0,166, 0x80,
|
||||
0x90,0x2C, 0,166, 0x80, 0x81, 0x90,0x30, 0x91,0x41, 0,166, 0x80, 0x81, 0x90,0x2C, 0x91,0x3F, 0,166, 0x80,
|
||||
0x81, 0x90,0x31, 0x91,0x41, 1,77, 0x81, 0x82, 0x91,0x44, 0x92,0x41, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x42,
|
||||
0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x44, 1,77, 0x81, 0x82, 0x91,0x45, 0x92,0x42, 0,166, 0x81, 0x82, 0x91,0x44,
|
||||
0x92,0x41, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x42, 1,77, 0x81, 0x91,0x46, 0,166, 0x81, 0x91,0x48, 0,166,
|
||||
0x81, 0x82, 0x91,0x49, 0x92,0x40, 1,77, 0x81, 0x91,0x48, 0,166, 0x81, 0x91,0x46, 0,166, 0x81, 0x82, 0x91,0x3F,
|
||||
0x92,0x48, 1,77, 0x82, 0x92,0x48, 0,166, 0x82, 0x92,0x49, 0,166, 0x81, 0x82, 0x91,0x4B, 0x92,0x42, 1,77,
|
||||
0x81, 0x91,0x49, 0,166, 0x81, 0x91,0x48, 0,166, 0x80, 0x81, 0x90,0x49, 0,166, 0x91,0x3E, 0,166, 0x80,
|
||||
0x81, 0x90,0x44, 0x91,0x3D, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x47, 0x91,0x3D,
|
||||
0x92,0x41, 0,166, 0x81, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x44,
|
||||
0x91,0x3D, 0,166, 0x80, 0x81, 0x82, 0x90,0x45, 0x91,0x42, 0x92,0x36, 0,166, 0x80, 0x81, 0x90,0x42, 0,166,
|
||||
0x80, 0x82, 0x90,0x44, 0x91,0x35, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x38,
|
||||
0,166, 0x80, 0x90,0x49, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x35,
|
||||
0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x36, 0,166, 0x92,0x49, 0,166, 0x82, 0x92,0x47, 0,166, 0x80, 0x90,0x4A,
|
||||
0,166, 0x80, 0x90,0x49, 0,166, 0x81, 0x82, 0x91,0x47, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x35,
|
||||
0,166, 0x80, 0x82, 0x90,0x49, 0x92,0x36, 0,166, 0x80, 0x81, 0x82, 0x90,0x38, 0x91,0x47, 0x92,0x41, 0,166,
|
||||
0x80, 0x90,0x31, 0,166, 0x80, 0x81, 0x82, 0x90,0x39, 0x91,0x42, 0x92,0x45, 0,166, 0x80, 0x90,0x31, 0,166,
|
||||
0x80, 0x82, 0x90,0x3B, 0x92,0x44, 0,166, 0x80, 0x90,0x31, 0,166, 0x80, 0x81, 0x90,0x3D, 0x91,0x41, 0,166,
|
||||
0x80, 0x90,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x39, 0x91,0x42, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x90,0x3D,
|
||||
0x92,0x49, 0,166, 0x80, 0x90,0x3B, 0,166, 0x80, 0x82, 0x90,0x39, 0x92,0x4E, 0,166, 0x80, 0x90,0x38, 0,166,
|
||||
0x80, 0x81, 0x90,0x36, 0x91,0x45, 0,166, 0x80, 0x90,0x34, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x3B, 0,166,
|
||||
0x81, 0x91,0x3D, 0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x3E, 0,166, 0x82, 0x92,0x3D, 0,166, 0x81, 0x82, 0x91,0x50,
|
||||
0x92,0x3B, 0,166, 0x82, 0x92,0x39, 0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x38, 0,166, 0x82, 0x92,0x36, 0,166,
|
||||
0x80, 0x82, 0x90,0x4C, 0x92,0x3D, 0,166, 0x82, 0x92,0x3E, 0,166, 0x81, 0x82, 0x91,0x49, 0x92,0x40, 0,166,
|
||||
0x82, 0x92,0x3E, 0,166, 0x81, 0x82, 0x91,0x51, 0x92,0x3D, 0,166, 0x82, 0x92,0x3B, 0,166, 0x80, 0x82, 0x90,0x49,
|
||||
0x92,0x39, 0,166, 0x82, 0x92,0x38, 0,166, 0x80, 0x82, 0x90,0x3F, 0x92,0x4E, 0,166, 0x80, 0x90,0x40, 0,166,
|
||||
0x80, 0x81, 0x90,0x42, 0x91,0x4B, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x3F, 0x91,0x53, 0,166,
|
||||
0x80, 0x90,0x3D, 0,166, 0x80, 0x81, 0x90,0x3B, 0x91,0x51, 0,166, 0x80, 0x90,0x39, 0,166, 0x80, 0x81, 0x90,0x50,
|
||||
0x91,0x40, 1,77, 0x80, 0x82, 0x90,0x50, 0x92,0x47, 0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x49, 0,166, 0x80,
|
||||
0x82, 0x90,0x53, 0x92,0x4A, 1,77, 0x80, 0x82, 0x90,0x51, 0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x50, 0x92,0x47,
|
||||
0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x49, 1,77, 0x82, 0x92,0x49, 0,166, 0x82, 0x92,0x4B, 0,166, 0x80,
|
||||
0x82, 0x90,0x50, 0x92,0x4C, 1,77, 0x82, 0x92,0x4B, 0,166, 0x82, 0x92,0x49, 0,166, 0x80, 0x82, 0x90,0x4E,
|
||||
0x92,0x4B, 1,77, 0x82, 0x92,0x4B, 0,166, 0x82, 0x92,0x4C, 0,166, 0x80, 0x82, 0x90,0x51, 0x92,0x4E, 1,77,
|
||||
0x82, 0x92,0x4C, 0,166, 0x82, 0x92,0x4B, 0,166, 0x82, 0x92,0x4C, 0,166, 0x81, 0x91,0x3D, 0,166, 0x80,
|
||||
0x81, 0x90,0x50, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x53, 0x91,0x38,
|
||||
0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x4E,
|
||||
0x91,0x32, 0,166, 0x80, 0x81, 0x82, 0x90,0x4C, 0x91,0x31, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x39, 0,166,
|
||||
0x80, 0x81, 0x90,0x49, 0x91,0x32, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x34,
|
||||
0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x31, 0,166, 0x80, 0x81, 0x90,0x4F,
|
||||
0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x32, 0x91,0x4E, 0,166, 0x80, 0x90,0x39, 0,166, 0x80, 0x90,0x34, 0x92,0x45,
|
||||
0,166, 0x80, 0x82, 0x90,0x39, 0x92,0x47, 0,166, 0x80, 0x82, 0x90,0x32, 0x92,0x49, 0,166, 0x80, 0x90,0x39,
|
||||
0,166, 0x80, 0x82, 0x90,0x31, 0x92,0x47, 0,166, 0x80, 0x82, 0x90,0x39, 0x92,0x45, 0,166, 0x80, 0x82, 0x90,0x2F,
|
||||
0x92,0x44, 0,166, 0x80, 0x90,0x38, 0,166, 0x80, 0x81, 0x90,0x31, 0x91,0x4A, 0,166, 0x80, 0x81, 0x90,0x38,
|
||||
0x91,0x4C, 0,166, 0x80, 0x81, 0x90,0x32, 0x91,0x4E, 0,166, 0x80, 0x90,0x38, 0,166, 0x80, 0x81, 0x90,0x2F,
|
||||
0x91,0x4C, 0,166, 0x80, 0x81, 0x90,0x38, 0x91,0x4A, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x31, 0,166, 0x81,
|
||||
0x91,0x38, 0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x32, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x38, 0,166, 0x81,
|
||||
0x82, 0x91,0x47, 0x92,0x31, 0,166, 0x82, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x2F, 0,166, 0x81,
|
||||
0x82, 0x91,0x44, 0x92,0x38, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x2E, 0,166, 0x82, 0x92,0x36, 0,166, 0x80,
|
||||
0x82, 0x90,0x49, 0x92,0x2F, 0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x36, 0,166, 0x80, 0x82, 0x90,0x4C, 0x92,0x31,
|
||||
0,166, 0x82, 0x92,0x36, 0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x2E, 0,166, 0x80, 0x82, 0x90,0x49, 0x92,0x36,
|
||||
0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x2F, 0,166, 0x82, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x31,
|
||||
0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x45, 0x92,0x2F, 0,166, 0x82, 0x92,0x36,
|
||||
0,166, 0x81, 0x82, 0x91,0x44, 0x92,0x2D, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x36, 0,166, 0x81, 0x82, 0x91,0x2C,
|
||||
0x92,0x40, 0,166, 0x81, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x28, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x2A, 0,166, 0x81, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x49,
|
||||
0x91,0x2C, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x34, 0,166, 0x80, 0x81, 0x90,0x49, 0x91,0x2D, 0,166, 0x80,
|
||||
0x90,0x45, 0,166, 0x80, 0x81, 0x82, 0x90,0x4E, 0x91,0x2C, 0,166, 0x81, 0x91,0x45, 0x92,0x2D, 0,166, 0x81,
|
||||
0x82, 0x91,0x44, 0x92,0x2F, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x82, 0x90,0x4C, 0x92,0x2D, 0,166, 0x81,
|
||||
0x82, 0x91,0x44, 0x92,0x2C, 0,166, 0x81, 0x82, 0x91,0x42, 0x92,0x2D, 0,166, 0x80, 0x90,0x49, 0,166, 0x80,
|
||||
0x90,0x4A, 0,166, 0x81, 0x91,0x42, 0,166, 0x81, 0x91,0x40, 0,166, 0x80, 0x82, 0x90,0x47, 0x92,0x2F, 0,166,
|
||||
0x80, 0x82, 0x90,0x49, 0x92,0x2C, 0,166, 0x81, 0x82, 0x91,0x2D, 0x92,0x40, 0,166, 0x80, 0x81, 0x82, 0x90,0x2F,
|
||||
0x91,0x44, 0x92,0x3E, 0,166, 0x80, 0x90,0x28, 0,166, 0x80, 0x81, 0x82, 0x90,0x31, 0x91,0x3D, 0x92,0x45, 0,166,
|
||||
0x80, 0x90,0x28, 0,166, 0x80, 0x81, 0x90,0x32, 0x91,0x3B, 0,166, 0x80, 0x90,0x28, 0,166, 0x80, 0x82, 0x90,0x34,
|
||||
0x92,0x44, 1,77, 0x80, 0x81, 0x82, 0x90,0x31, 0x91,0x45, 0x92,0x40, 0,166, 0x82, 0x92,0x3D, 0,166, 0x80,
|
||||
0x81, 0x82, 0x90,0x36, 0x91,0x44, 0x92,0x3E, 0,166, 0x81, 0x91,0x45, 0,166, 0x81, 0x91,0x47, 0,166, 0x82,
|
||||
0x92,0x3B, 0,166, 0x80, 0x81, 0x82, 0x90,0x35, 0x91,0x45, 0x92,0x3D, 0,166, 0x81, 0x91,0x44, 0,166, 0x80,
|
||||
0x81, 0x90,0x45, 0x91,0x36, 0,166, 0x82, 0x92,0x39, 0,166, 0x82, 0x92,0x3B, 0,166, 0x82, 0x92,0x38, 0,166,
|
||||
0x82, 0x92,0x39, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x44, 0x91,0x34, 0,166, 0x80, 0x90,0x45,
|
||||
0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x32, 0,166, 0x80, 0x82, 0x90,0x38, 0x92,0x40, 0,166, 0x80, 0x81, 0x82,
|
||||
0x90,0x49, 0x91,0x31, 0x92,0x39, 0,166, 0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x90,0x4A, 0x91,0x2F, 0,166,
|
||||
0x80, 0x90,0x40, 0,166, 0x80, 0x81, 0x82, 0x90,0x4C, 0x91,0x34, 0x92,0x38, 1,77, 0x80, 0x81, 0x82, 0x90,0x49,
|
||||
0x91,0x39, 0x92,0x2D, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3D, 0,166, 0x80, 0x90,0x47,
|
||||
0,166, 0x80, 0x81, 0x82, 0x90,0x49, 0x91,0x42, 0,166, 0x80, 0x90,0x4B, 0,166, 0x80, 0x90,0x4C, 0x92,0x39,
|
||||
0,166, 0x80, 0x90,0x4E, 0,166, 0x80, 0x82, 0x90,0x47, 0x92,0x38, 0,166, 0x80, 0x90,0x45, 0,166, 0x80,
|
||||
0x81, 0x90,0x44, 0x91,0x3B, 0,166, 0x80, 0x90,0x45, 0,166, 0x80, 0x81, 0x90,0x47, 0x91,0x40, 0,166, 0x80,
|
||||
0x90,0x49, 0,166, 0x80, 0x82, 0x90,0x4A, 0x92,0x38, 0,166, 0x80, 0x90,0x4C, 0,166, 0x80, 0x82, 0x90,0x45,
|
||||
0x92,0x36, 0,166, 0x80, 0x90,0x44, 0,166, 0x80, 0x81, 0x90,0x42, 0x91,0x39, 0,166, 0x80, 0x90,0x44, 0,166,
|
||||
0x80, 0x81, 0x90,0x45, 0x91,0x3E, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x82, 0x90,0x49, 0x92,0x36, 0,166,
|
||||
0x80, 0x90,0x4A, 0,166, 0x80, 0x82, 0x90,0x44, 0x92,0x34, 0,166, 0x80, 0x90,0x47, 0,166, 0x80, 0x81, 0x90,0x44,
|
||||
0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x3D, 0x91,0x40, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x3E, 1,77, 0x81,
|
||||
0x91,0x3D, 0,166, 0x81, 0x91,0x3B, 0,166, 0x81, 0x91,0x3D, 0,166, 0x80, 0x90,0x4C, 0,166, 0x80, 0x81,
|
||||
0x90,0x49, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x45, 0x91,0x3B, 0,166, 0x80, 0x81, 0x90,0x51, 0x91,0x3D, 1,77,
|
||||
0x81, 0x91,0x3B, 0,166, 0x81, 0x91,0x39, 0,166, 0x81, 0x91,0x3B, 0,166, 0x80, 0x90,0x47, 0,166, 0x80,
|
||||
0x81, 0x90,0x4A, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x39, 0,166, 0x80, 0x81, 0x90,0x50, 0x91,0x3B,
|
||||
1,77, 0x81, 0x91,0x39, 0,166, 0x81, 0x91,0x38, 0,166, 0x81, 0x91,0x39, 0,166, 0x80, 0x90,0x45, 0,166,
|
||||
0x80, 0x81, 0x90,0x49, 0x91,0x36, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4E, 0x91,0x39,
|
||||
1,77, 0x81, 0x91,0x38, 0,166, 0x81, 0x91,0x36, 0,166, 0x81, 0x91,0x38, 0,166, 0x80, 0x82, 0x90,0x4C,
|
||||
0x92,0x34, 0,166, 0x80, 0x81, 0x82, 0x90,0x4B, 0x91,0x38, 0,166, 0x80, 0x81, 0x90,0x4C, 0x91,0x3B, 0,166,
|
||||
0x80, 0x81, 0x90,0x4E, 0x91,0x45, 0x92,0x3C, 0,166, 0x82, 0x92,0x38, 0,166, 0x80, 0x81, 0x82, 0x90,0x39, 0,166,
|
||||
0x80, 0x90,0x33, 0,166, 0x80, 0x90,0x49, 0x91,0x45, 0x92,0x34, 0,13, 1,29, 0,246, 0x80, 0x81, 0x90,0x4A,
|
||||
0x91,0x47, 0,53, 0,141, 0x80, 0x81, 0x82, 0x90,0x47, 0x91,0x44, 0x92,0x28, 0,95, 1,77, 0,202,
|
||||
0x80, 0x81, 0x90,0x45, 0,91, 0,136, 0x80, 0x82, 0x90,0x45, 0x91,0x2D, 7,83, 0x80, 0x81, 0xf0};
|
||||
|
||||
Arduboy arduboy;
|
||||
|
||||
void setup()
|
||||
{
|
||||
arduboy.begin();
|
||||
arduboy.setTextSize(4);
|
||||
arduboy.setCursor(0,0);
|
||||
arduboy.print("Music\nDemo");
|
||||
arduboy.display();
|
||||
}
|
||||
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
void loop ()
|
||||
{
|
||||
// pause render until it's time for the next frame
|
||||
if (!(arduboy.nextFrame()))
|
||||
return;
|
||||
|
||||
if (arduboy.pressed(UP_BUTTON)) {
|
||||
y-=1;
|
||||
} else if (arduboy.pressed(DOWN_BUTTON)) {
|
||||
y+=1;
|
||||
} else if (arduboy.pressed(LEFT_BUTTON)) {
|
||||
x-=1;
|
||||
} else if (arduboy.pressed(RIGHT_BUTTON)) {
|
||||
x+=1;
|
||||
}
|
||||
|
||||
if (arduboy.pressed(A_BUTTON)) {
|
||||
arduboy.invert(true);
|
||||
} else if (arduboy.pressed(B_BUTTON)) {
|
||||
arduboy.invert(false);
|
||||
}
|
||||
|
||||
arduboy.clear();
|
||||
arduboy.setCursor(x,y);
|
||||
arduboy.print("Music\nDemo");
|
||||
arduboy.display();
|
||||
|
||||
// play the tune if we aren't already
|
||||
if (!arduboy.tunes.playing())
|
||||
arduboy.tunes.playScore(score);
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 434 B |
|
@ -0,0 +1,61 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Arduboy
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Arduboy KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
allPixelsOn KEYWORD2
|
||||
blank KEYWORD2
|
||||
clear KEYWORD2
|
||||
cpuLoad KEYWORD2
|
||||
display KEYWORD2
|
||||
drawBitmap KEYWORD2
|
||||
drawChar KEYWORD2
|
||||
drawCircle KEYWORD2
|
||||
drawFastHLine KEYWORD2
|
||||
drawFastVLine KEYWORD2
|
||||
drawLine KEYWORD2
|
||||
drawPixel KEYWORD2
|
||||
drawRect KEYWORD2
|
||||
drawRoundRect KEYWORD2
|
||||
drawSlowXYBitmap KEYWORD2
|
||||
drawTriangle KEYWORD2
|
||||
everyXFrames KEYWORD2
|
||||
fillCircle KEYWORD2
|
||||
fillRect KEYWORD2
|
||||
fillRoundRect KEYWORD2
|
||||
fillScreen KEYWORD2
|
||||
fillTriangle KEYWORD2
|
||||
flipVertical KEYWORD2
|
||||
flipHorizontal KEYWORD2
|
||||
getBuffer KEYWORD2
|
||||
getInput KEYWORD2
|
||||
idle KEYWORD2
|
||||
initRandomSeed KEYWORD2
|
||||
invert KEYWORD2
|
||||
nextFrame KEYWORD2
|
||||
notPressed KEYWORD2
|
||||
paint8Pixels KEYWORD2
|
||||
paintScreen KEYWORD2
|
||||
pressed KEYWORD2
|
||||
setCursor KEYWORD2
|
||||
setFrameRate KEYWORD2
|
||||
setRGBled KEYWORD2
|
||||
setTextSize KEYWORD2
|
||||
setTextWrap KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
BLACK LITERAL1
|
||||
WHITE LITERAL1
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
name=Arduboy
|
||||
version=1.0.0
|
||||
author=Chris J. Martinez, Kevin Bates, Josh Goebel, Scott Allen, Ross O. Shoger
|
||||
maintainer=Ross O. Shoger ros@arduboy.com
|
||||
sentence=The Arduboy core library.
|
||||
paragraph=This library is for content creation on the Arduboy, a portable gaming platform. The library provides access to the sound, display, and input of the Arduboy.
|
||||
category=Other
|
||||
url=https://github.com/arduboy/arduboy
|
||||
architectures=avr
|
|
@ -0,0 +1,758 @@
|
|||
#include "Arduboy.h"
|
||||
#include "glcdfont.c"
|
||||
#include "ab_logo.c"
|
||||
|
||||
Arduboy::Arduboy()
|
||||
{
|
||||
// frame management
|
||||
setFrameRate(60);
|
||||
frameCount = 0;
|
||||
nextFrameStart = 0;
|
||||
post_render = false;
|
||||
// init not necessary, will be reset after first use
|
||||
// lastFrameStart
|
||||
// lastFrameDurationMs
|
||||
|
||||
// font rendering
|
||||
cursor_x = 0;
|
||||
cursor_y = 0;
|
||||
textsize = 1;
|
||||
}
|
||||
|
||||
void Arduboy::start() // deprecated
|
||||
{
|
||||
begin();
|
||||
}
|
||||
|
||||
void Arduboy::begin()
|
||||
{
|
||||
boot(); // required
|
||||
bootUtils();
|
||||
|
||||
bootLogo();
|
||||
|
||||
// Audio
|
||||
tunes.initChannel(PIN_SPEAKER_1);
|
||||
tunes.initChannel(PIN_SPEAKER_2);
|
||||
audio.begin();
|
||||
}
|
||||
|
||||
// this is pusposely duplicated (without logo) so that
|
||||
// whichever is actually used is linked and the one
|
||||
// that is not is gone without wasting any space in flash
|
||||
void Arduboy::beginNoLogo()
|
||||
{
|
||||
boot(); // required
|
||||
bootUtils();
|
||||
|
||||
// Audio
|
||||
tunes.initChannel(PIN_SPEAKER_1);
|
||||
tunes.initChannel(PIN_SPEAKER_2);
|
||||
audio.begin();
|
||||
}
|
||||
|
||||
void Arduboy::bootUtils()
|
||||
{
|
||||
// flashlight
|
||||
if(pressed(UP_BUTTON)) {
|
||||
// sendLCDCommand(OLED_ALL_PIXELS_ON); // smaller than allPixelsOn()
|
||||
blank();
|
||||
setRGBled(255,255,255);
|
||||
while(true) {}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::bootLogo()
|
||||
{
|
||||
// setRGBled(10,0,0);
|
||||
for(int8_t y = -18; y<=24; y++) {
|
||||
setRGBled(24-y, 0, 0);
|
||||
|
||||
clear();
|
||||
drawBitmap(20,y, arduboy_logo, 88, 16, WHITE);
|
||||
display();
|
||||
delay(27);
|
||||
// longer delay post boot, we put it inside the loop to
|
||||
// save the flash calling clear/delay again outside the loop
|
||||
if (y==-16) {
|
||||
delay(250);
|
||||
}
|
||||
}
|
||||
|
||||
delay(750);
|
||||
setRGBled(0,0,0);
|
||||
}
|
||||
|
||||
/* Frame management */
|
||||
|
||||
void Arduboy::setFrameRate(uint8_t rate)
|
||||
{
|
||||
frameRate = rate;
|
||||
eachFrameMillis = 1000/rate;
|
||||
}
|
||||
|
||||
bool Arduboy::everyXFrames(uint8_t frames)
|
||||
{
|
||||
return frameCount % frames == 0;
|
||||
}
|
||||
|
||||
bool Arduboy::nextFrame()
|
||||
{
|
||||
long now = millis();
|
||||
uint8_t remaining;
|
||||
|
||||
// post render
|
||||
if (post_render) {
|
||||
lastFrameDurationMs = now - lastFrameStart;
|
||||
frameCount++;
|
||||
post_render = false;
|
||||
}
|
||||
|
||||
// if it's not time for the next frame yet
|
||||
if (now < nextFrameStart) {
|
||||
remaining = nextFrameStart - now;
|
||||
// if we have more than 1ms to spare, lets sleep
|
||||
// we should be woken up by timer0 every 1ms, so this should be ok
|
||||
if (remaining > 1)
|
||||
idle();
|
||||
return false;
|
||||
}
|
||||
|
||||
// pre-render
|
||||
|
||||
// technically next frame should be last frame + each frame but if we're
|
||||
// running a slow render we would constnatly be behind the clock
|
||||
// keep an eye on this and see how it works. If it works well the
|
||||
// lastFrameStart variable could be eliminated completely
|
||||
nextFrameStart = now + eachFrameMillis;
|
||||
lastFrameStart = now;
|
||||
post_render = true;
|
||||
return post_render;
|
||||
}
|
||||
|
||||
int Arduboy::cpuLoad()
|
||||
{
|
||||
return lastFrameDurationMs*100 / eachFrameMillis;
|
||||
}
|
||||
|
||||
void Arduboy::initRandomSeed()
|
||||
{
|
||||
power_adc_enable(); // ADC on
|
||||
randomSeed(~rawADC(ADC_TEMP) * ~rawADC(ADC_VOLTAGE) * ~micros() + micros());
|
||||
power_adc_disable(); // ADC off
|
||||
}
|
||||
|
||||
uint16_t Arduboy::rawADC(byte adc_bits)
|
||||
{
|
||||
ADMUX = adc_bits;
|
||||
// we also need MUX5 for temperature check
|
||||
if (adc_bits == ADC_TEMP) {
|
||||
ADCSRB = _BV(MUX5);
|
||||
}
|
||||
|
||||
delay(2); // Wait for ADMUX setting to settle
|
||||
ADCSRA |= _BV(ADSC); // Start conversion
|
||||
while (bit_is_set(ADCSRA,ADSC)); // measuring
|
||||
|
||||
return ADC;
|
||||
}
|
||||
|
||||
/* Graphics */
|
||||
|
||||
void Arduboy::clearDisplay() // deprecated
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void Arduboy::clear()
|
||||
{
|
||||
fillScreen(BLACK);
|
||||
}
|
||||
|
||||
void Arduboy::drawPixel(int x, int y, uint8_t color)
|
||||
{
|
||||
#ifdef PIXEL_SAFE_MODE
|
||||
if (x < 0 || x > (WIDTH-1) || y < 0 || y > (HEIGHT-1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t row = (uint8_t)y / 8;
|
||||
if (color)
|
||||
{
|
||||
sBuffer[(row*WIDTH) + (uint8_t)x] |= _BV((uint8_t)y % 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
sBuffer[(row*WIDTH) + (uint8_t)x] &= ~ _BV((uint8_t)y % 8);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Arduboy::getPixel(uint8_t x, uint8_t y)
|
||||
{
|
||||
uint8_t row = y / 8;
|
||||
uint8_t bit_position = y % 8;
|
||||
return (sBuffer[(row*WIDTH) + x] & _BV(bit_position)) >> bit_position;
|
||||
}
|
||||
|
||||
void Arduboy::drawCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color)
|
||||
{
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
drawPixel(x0, y0+r, color);
|
||||
drawPixel(x0, y0-r, color);
|
||||
drawPixel(x0+r, y0, color);
|
||||
drawPixel(x0-r, y0, color);
|
||||
|
||||
while (x<y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawCircleHelper
|
||||
(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, uint8_t color)
|
||||
{
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x<y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
if (cornername & 0x4)
|
||||
{
|
||||
drawPixel(x0 + x, y0 + y, color);
|
||||
drawPixel(x0 + y, y0 + x, color);
|
||||
}
|
||||
if (cornername & 0x2)
|
||||
{
|
||||
drawPixel(x0 + x, y0 - y, color);
|
||||
drawPixel(x0 + y, y0 - x, color);
|
||||
}
|
||||
if (cornername & 0x8)
|
||||
{
|
||||
drawPixel(x0 - y, y0 + x, color);
|
||||
drawPixel(x0 - x, y0 + y, color);
|
||||
}
|
||||
if (cornername & 0x1)
|
||||
{
|
||||
drawPixel(x0 - y, y0 - x, color);
|
||||
drawPixel(x0 - x, y0 - y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color)
|
||||
{
|
||||
drawFastVLine(x0, y0-r, 2*r+1, color);
|
||||
fillCircleHelper(x0, y0, r, 3, 0, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillCircleHelper
|
||||
(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, int16_t delta,
|
||||
uint8_t color)
|
||||
{
|
||||
// used to do circles and roundrects!
|
||||
int16_t f = 1 - r;
|
||||
int16_t ddF_x = 1;
|
||||
int16_t ddF_y = -2 * r;
|
||||
int16_t x = 0;
|
||||
int16_t y = r;
|
||||
|
||||
while (x < y)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
y--;
|
||||
ddF_y += 2;
|
||||
f += ddF_y;
|
||||
}
|
||||
|
||||
x++;
|
||||
ddF_x += 2;
|
||||
f += ddF_x;
|
||||
|
||||
if (cornername & 0x1)
|
||||
{
|
||||
drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
|
||||
if (cornername & 0x2)
|
||||
{
|
||||
drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
|
||||
drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawLine
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color)
|
||||
{
|
||||
// bresenham's algorithm - thx wikpedia
|
||||
boolean steep = abs(y1 - y0) > abs(x1 - x0);
|
||||
if (steep) {
|
||||
swap(x0, y0);
|
||||
swap(x1, y1);
|
||||
}
|
||||
|
||||
if (x0 > x1) {
|
||||
swap(x0, x1);
|
||||
swap(y0, y1);
|
||||
}
|
||||
|
||||
int16_t dx, dy;
|
||||
dx = x1 - x0;
|
||||
dy = abs(y1 - y0);
|
||||
|
||||
int16_t err = dx / 2;
|
||||
int8_t ystep;
|
||||
|
||||
if (y0 < y1)
|
||||
{
|
||||
ystep = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ystep = -1;
|
||||
}
|
||||
|
||||
for (; x0 <= x1; x0++)
|
||||
{
|
||||
if (steep)
|
||||
{
|
||||
drawPixel(y0, x0, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
drawPixel(x0, y0, color);
|
||||
}
|
||||
|
||||
err -= dy;
|
||||
if (err < 0)
|
||||
{
|
||||
y0 += ystep;
|
||||
err += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color)
|
||||
{
|
||||
drawFastHLine(x, y, w, color);
|
||||
drawFastHLine(x, y+h-1, w, color);
|
||||
drawFastVLine(x, y, h, color);
|
||||
drawFastVLine(x+w-1, y, h, color);
|
||||
}
|
||||
|
||||
void Arduboy::drawFastVLine
|
||||
(int16_t x, int16_t y, uint8_t h, uint8_t color)
|
||||
{
|
||||
int end = y+h;
|
||||
for (int a = max(0,y); a < min(end,HEIGHT); a++)
|
||||
{
|
||||
drawPixel(x,a,color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawFastHLine
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t color)
|
||||
{
|
||||
int end = x+w;
|
||||
for (int a = max(0,x); a < min(end,WIDTH); a++)
|
||||
{
|
||||
drawPixel(a,y,color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color)
|
||||
{
|
||||
// stupidest version - update in subclasses if desired!
|
||||
for (int16_t i=x; i<x+w; i++)
|
||||
{
|
||||
drawFastVLine(i, y, h, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::fillScreen(uint8_t color)
|
||||
{
|
||||
// C version :
|
||||
//
|
||||
// if (color) color = 0xFF; //change any nonzero argument to b11111111 and insert into screen array.
|
||||
// for(int16_t i=0; i<1024; i++) { sBuffer[i] = color; } //sBuffer = (128*64) = 8192/8 = 1024 bytes.
|
||||
|
||||
asm volatile
|
||||
(
|
||||
// load color value into r27
|
||||
"mov r27, %1 \n\t"
|
||||
// if value is zero, skip assigning to 0xff
|
||||
"cpse r27, __zero_reg__ \n\t"
|
||||
"ldi r27, 0xff \n\t"
|
||||
// load sBuffer pointer into Z
|
||||
"movw r30, %0\n\t"
|
||||
// counter = 0
|
||||
"clr __tmp_reg__ \n\t"
|
||||
"loopto: \n\t"
|
||||
// (4x) push zero into screen buffer,
|
||||
// then increment buffer position
|
||||
"st Z+, r27 \n\t"
|
||||
"st Z+, r27 \n\t"
|
||||
"st Z+, r27 \n\t"
|
||||
"st Z+, r27 \n\t"
|
||||
// increase counter
|
||||
"inc __tmp_reg__ \n\t"
|
||||
// repeat for 256 loops
|
||||
// (until counter rolls over back to 0)
|
||||
"brne loopto \n\t"
|
||||
// input: sBuffer, color
|
||||
// modified: Z (r30, r31), r27
|
||||
:
|
||||
: "r" (sBuffer), "r" (color)
|
||||
: "r30", "r31", "r27"
|
||||
);
|
||||
}
|
||||
|
||||
void Arduboy::drawRoundRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color)
|
||||
{
|
||||
// smarter version
|
||||
drawFastHLine(x+r, y, w-2*r, color); // Top
|
||||
drawFastHLine(x+r, y+h-1, w-2*r, color); // Bottom
|
||||
drawFastVLine(x, y+r, h-2*r, color); // Left
|
||||
drawFastVLine(x+w-1, y+r, h-2*r, color); // Right
|
||||
// draw four corners
|
||||
drawCircleHelper(x+r, y+r, r, 1, color);
|
||||
drawCircleHelper(x+w-r-1, y+r, r, 2, color);
|
||||
drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
|
||||
drawCircleHelper(x+r, y+h-r-1, r, 8, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillRoundRect
|
||||
(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color)
|
||||
{
|
||||
// smarter version
|
||||
fillRect(x+r, y, w-2*r, h, color);
|
||||
|
||||
// draw four corners
|
||||
fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
|
||||
fillCircleHelper(x+r, y+r, r, 2, h-2*r-1, color);
|
||||
}
|
||||
|
||||
void Arduboy::drawTriangle
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
|
||||
{
|
||||
drawLine(x0, y0, x1, y1, color);
|
||||
drawLine(x1, y1, x2, y2, color);
|
||||
drawLine(x2, y2, x0, y0, color);
|
||||
}
|
||||
|
||||
void Arduboy::fillTriangle
|
||||
(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
|
||||
{
|
||||
|
||||
int16_t a, b, y, last;
|
||||
// Sort coordinates by Y order (y2 >= y1 >= y0)
|
||||
if (y0 > y1)
|
||||
{
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
if (y1 > y2)
|
||||
{
|
||||
swap(y2, y1); swap(x2, x1);
|
||||
}
|
||||
if (y0 > y1)
|
||||
{
|
||||
swap(y0, y1); swap(x0, x1);
|
||||
}
|
||||
|
||||
if(y0 == y2)
|
||||
{ // Handle awkward all-on-same-line case as its own thing
|
||||
a = b = x0;
|
||||
if(x1 < a)
|
||||
{
|
||||
a = x1;
|
||||
}
|
||||
else if(x1 > b)
|
||||
{
|
||||
b = x1;
|
||||
}
|
||||
if(x2 < a)
|
||||
{
|
||||
a = x2;
|
||||
}
|
||||
else if(x2 > b)
|
||||
{
|
||||
b = x2;
|
||||
}
|
||||
drawFastHLine(a, y0, b-a+1, color);
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t dx01 = x1 - x0,
|
||||
dy01 = y1 - y0,
|
||||
dx02 = x2 - x0,
|
||||
dy02 = y2 - y0,
|
||||
dx12 = x2 - x1,
|
||||
dy12 = y2 - y1,
|
||||
sa = 0,
|
||||
sb = 0;
|
||||
|
||||
// For upper part of triangle, find scanline crossings for segments
|
||||
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
|
||||
// is included here (and second loop will be skipped, avoiding a /0
|
||||
// error there), otherwise scanline y1 is skipped here and handled
|
||||
// in the second loop...which also avoids a /0 error here if y0=y1
|
||||
// (flat-topped triangle).
|
||||
if (y1 == y2)
|
||||
{
|
||||
last = y1; // Include y1 scanline
|
||||
}
|
||||
else
|
||||
{
|
||||
last = y1-1; // Skip it
|
||||
}
|
||||
|
||||
|
||||
for(y = y0; y <= last; y++)
|
||||
{
|
||||
a = x0 + sa / dy01;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx01;
|
||||
sb += dx02;
|
||||
|
||||
if(a > b)
|
||||
{
|
||||
swap(a,b);
|
||||
}
|
||||
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
|
||||
// For lower part of triangle, find scanline crossings for segments
|
||||
// 0-2 and 1-2. This loop is skipped if y1=y2.
|
||||
sa = dx12 * (y - y1);
|
||||
sb = dx02 * (y - y0);
|
||||
|
||||
for(; y <= y2; y++)
|
||||
{
|
||||
a = x1 + sa / dy12;
|
||||
b = x0 + sb / dy02;
|
||||
sa += dx12;
|
||||
sb += dx02;
|
||||
|
||||
if(a > b)
|
||||
{
|
||||
swap(a,b);
|
||||
}
|
||||
|
||||
drawFastHLine(a, y, b-a+1, color);
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::drawBitmap
|
||||
(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h,
|
||||
uint8_t color)
|
||||
{
|
||||
// no need to dar at all of we're offscreen
|
||||
if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
|
||||
return;
|
||||
|
||||
int yOffset = abs(y) % 8;
|
||||
int sRow = y / 8;
|
||||
if (y < 0) {
|
||||
sRow--;
|
||||
yOffset = 8 - yOffset;
|
||||
}
|
||||
int rows = h/8;
|
||||
if (h%8!=0) rows++;
|
||||
for (int a = 0; a < rows; a++) {
|
||||
int bRow = sRow + a;
|
||||
if (bRow > (HEIGHT/8)-1) break;
|
||||
if (bRow > -2) {
|
||||
for (int iCol = 0; iCol<w; iCol++) {
|
||||
if (iCol + x > (WIDTH-1)) break;
|
||||
if (iCol + x >= 0) {
|
||||
if (bRow >= 0) {
|
||||
if (color == WHITE) this->sBuffer[ (bRow*WIDTH) + x + iCol ] |= pgm_read_byte(bitmap+(a*w)+iCol) << yOffset;
|
||||
else if (color == BLACK) this->sBuffer[ (bRow*WIDTH) + x + iCol ] &= ~(pgm_read_byte(bitmap+(a*w)+iCol) << yOffset);
|
||||
else this->sBuffer[ (bRow*WIDTH) + x + iCol ] ^= pgm_read_byte(bitmap+(a*w)+iCol) << yOffset;
|
||||
}
|
||||
if (yOffset && bRow<(HEIGHT/8)-1 && bRow > -2) {
|
||||
if (color == WHITE) this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] |= pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset);
|
||||
else if (color == BLACK) this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] &= ~(pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset));
|
||||
else this->sBuffer[ ((bRow+1)*WIDTH) + x + iCol ] ^= pgm_read_byte(bitmap+(a*w)+iCol) >> (8-yOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Arduboy::drawSlowXYBitmap
|
||||
(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color)
|
||||
{
|
||||
// no need to dar at all of we're offscreen
|
||||
if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
|
||||
return;
|
||||
|
||||
int16_t xi, yi, byteWidth = (w + 7) / 8;
|
||||
for(yi = 0; yi < h; yi++) {
|
||||
for(xi = 0; xi < w; xi++ ) {
|
||||
if(pgm_read_byte(bitmap + yi * byteWidth + xi / 8) & (128 >> (xi & 7))) {
|
||||
drawPixel(x + xi, y + yi, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Arduboy::drawChar
|
||||
(int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size)
|
||||
{
|
||||
boolean draw_background = bg != color;
|
||||
|
||||
if ((x >= WIDTH) || // Clip right
|
||||
(y >= HEIGHT) || // Clip bottom
|
||||
((x + 5 * size - 1) < 0) || // Clip left
|
||||
((y + 8 * size - 1) < 0) // Clip top
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int8_t i=0; i<6; i++ )
|
||||
{
|
||||
uint8_t line;
|
||||
if (i == 5)
|
||||
{
|
||||
line = 0x0;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = pgm_read_byte(font+(c*5)+i);
|
||||
}
|
||||
|
||||
for (int8_t j = 0; j<8; j++)
|
||||
{
|
||||
uint8_t draw_color = (line & 0x1) ? color : bg;
|
||||
|
||||
if (draw_color || draw_background) {
|
||||
for (uint8_t a = 0; a < size; a++ ) {
|
||||
for (uint8_t b = 0; b < size; b++ ) {
|
||||
drawPixel(x + (i * size) + a, y + (j * size) + b, draw_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
line >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::setCursor(int16_t x, int16_t y)
|
||||
{
|
||||
cursor_x = x;
|
||||
cursor_y = y;
|
||||
}
|
||||
|
||||
void Arduboy::setTextSize(uint8_t s)
|
||||
{
|
||||
// textsize must always be 1 or higher
|
||||
textsize = max(1,s);
|
||||
}
|
||||
|
||||
void Arduboy::setTextWrap(boolean w)
|
||||
{
|
||||
wrap = w;
|
||||
}
|
||||
|
||||
size_t Arduboy::write(uint8_t c)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
cursor_y += textsize*8;
|
||||
cursor_x = 0;
|
||||
}
|
||||
else if (c == '\r')
|
||||
{
|
||||
// skip em
|
||||
}
|
||||
else
|
||||
{
|
||||
drawChar(cursor_x, cursor_y, c, 1, 0, textsize);
|
||||
cursor_x += textsize*6;
|
||||
if (wrap && (cursor_x > (WIDTH - textsize*6)))
|
||||
{
|
||||
// calling ourselves recursively for 'newline' is
|
||||
// 12 bytes smaller than doing the same math here
|
||||
write('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arduboy::display()
|
||||
{
|
||||
this->paintScreen(sBuffer);
|
||||
}
|
||||
|
||||
unsigned char* Arduboy::getBuffer()
|
||||
{
|
||||
return sBuffer;
|
||||
}
|
||||
|
||||
|
||||
boolean Arduboy::pressed(uint8_t buttons)
|
||||
{
|
||||
return (buttonsState() & buttons) == buttons;
|
||||
}
|
||||
|
||||
boolean Arduboy::notPressed(uint8_t buttons)
|
||||
{
|
||||
return (buttonsState() & buttons) == 0;
|
||||
}
|
||||
|
||||
void Arduboy::swap(int16_t& a, int16_t& b)
|
||||
{
|
||||
int temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
#ifndef Arduboy_h
|
||||
#define Arduboy_h
|
||||
|
||||
#include "core/core.h"
|
||||
#include <SPI.h>
|
||||
#include <Print.h>
|
||||
#include <limits.h>
|
||||
|
||||
// EEPROM settings
|
||||
#define EEPROM_VERSION 0
|
||||
#define EEPROM_BRIGHTNESS 1
|
||||
#define EEPROM_AUDIO_ON_OFF 2
|
||||
|
||||
// we reserve the first 16 byte of EEPROM for system use
|
||||
#define EEPROM_STORAGE_SPACE_START 16 // and onward
|
||||
|
||||
// eeprom settings above are neded for audio
|
||||
#include "audio/audio.h"
|
||||
|
||||
#define PIXEL_SAFE_MODE
|
||||
|
||||
// compare Vcc to 1.1 bandgap
|
||||
#define ADC_VOLTAGE (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1))
|
||||
// compare temperature to 2.5 internal reference and _BV(MUX5)
|
||||
#define ADC_TEMP (_BV(REFS0) | _BV(REFS1) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0))
|
||||
|
||||
class Arduboy : public Print, public ArduboyCore
|
||||
{
|
||||
public:
|
||||
Arduboy();
|
||||
|
||||
/// Returns true if the button mask passed in is pressed.
|
||||
/**
|
||||
* if (pressed(LEFT_BUTTON + A_BUTTON))
|
||||
*/
|
||||
boolean pressed(uint8_t buttons);
|
||||
|
||||
/// Returns true if the button mask passed in not pressed.
|
||||
/**
|
||||
* if (notPressed(LEFT_BUTTON))
|
||||
*/
|
||||
boolean notPressed(uint8_t buttons);
|
||||
|
||||
/// Initializes the hardware
|
||||
void begin();
|
||||
/// Initializes the hardware (but with no boot logo)
|
||||
void beginNoLogo();
|
||||
void start() __attribute__ ((deprecated("use begin() instead")));
|
||||
|
||||
/// Scrolls in the Arduboy logo
|
||||
void bootLogo();
|
||||
|
||||
/// Boot utils such as flashlight, etc
|
||||
void inline bootUtils() __attribute__((always_inline));
|
||||
|
||||
/// Clears display.
|
||||
void clear();
|
||||
void clearDisplay() __attribute__ ((deprecated("use clear() instead")));
|
||||
|
||||
/// Copies the contents of the screen buffer to the screen.
|
||||
/**
|
||||
* X and Y positions on the display are from the top left corner, thus a Y of 64
|
||||
* is the bottom of the screen and an X of 128 is the right side of the screen.
|
||||
* "Color" or "value" means choosing whether a pixel is lit or not - if color is
|
||||
* 0, the pixel is off (black), if color is 1, the pixel is on (white).
|
||||
*/
|
||||
void display();
|
||||
|
||||
/// Sets a single pixel on the screen buffer to white or black.
|
||||
void drawPixel(int x, int y, uint8_t color);
|
||||
|
||||
uint8_t getPixel(uint8_t x, uint8_t y);
|
||||
|
||||
/// Draw a circle of a defined radius.
|
||||
/**
|
||||
* Draws a circle in white or black. X and Y are the center point of the circle.
|
||||
*/
|
||||
void drawCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws one or more "corners" of a circle.
|
||||
void drawCircleHelper(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, uint8_t color);
|
||||
|
||||
/// Draws a filled-in circle.
|
||||
void fillCircle(int16_t x0, int16_t y0, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws one or both vertical halves of a filled-in circle.
|
||||
void fillCircleHelper(int16_t x0, int16_t y0, uint8_t r, uint8_t cornername, int16_t delta, uint8_t color);
|
||||
|
||||
/// Draws a line between two points.
|
||||
/**
|
||||
* Uses Bresenham's algorithm.
|
||||
*/
|
||||
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color);
|
||||
|
||||
/// Draws a rectangle of a width and height.
|
||||
void drawRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws vertical line.
|
||||
void drawFastVLine(int16_t x, int16_t y, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws a horizontal line.
|
||||
void drawFastHLine(int16_t x, int16_t y, uint8_t w, uint8_t color);
|
||||
|
||||
/// Draws a filled-in rectangle.
|
||||
void fillRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Fills the screen buffer with white or black.
|
||||
void fillScreen(uint8_t color);
|
||||
|
||||
/// Draws a rectangle with rounded edges.
|
||||
void drawRoundRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws a filled-in rectangle with rounded edges.
|
||||
void fillRoundRect(int16_t x, int16_t y, uint8_t w, uint8_t h, uint8_t r, uint8_t color);
|
||||
|
||||
/// Draws the outline of a triangle.
|
||||
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color);
|
||||
|
||||
/// Draws a filled-in triangle.
|
||||
void fillTriangle (int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color);
|
||||
|
||||
/// Draws a bitmap from program memory to a specific X/Y
|
||||
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws images that are bit-oriented horizontally.
|
||||
/**
|
||||
* This requires a lot of additional CPU power and will draw images slower
|
||||
* than drawBitmap, where the images are stored in a format that
|
||||
* allows them to be directly written to the screen. It is
|
||||
* recommended you use drawBitmap when possible.
|
||||
*/
|
||||
void drawSlowXYBitmap(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color);
|
||||
|
||||
/// Draws an ASCII character at a point.
|
||||
void drawChar(int16_t x, int16_t y, unsigned char c, uint8_t color, uint8_t bg, uint8_t size);
|
||||
|
||||
/// Sets the location of the screen cursor.
|
||||
void setCursor(int16_t x, int16_t y);
|
||||
|
||||
/// Set text size
|
||||
/**
|
||||
* As mentioned in drawChar(), individual ASCII characters are 6x8 pixels
|
||||
* (5x7 with spacing on two edges). The size is a pixel multiplier,
|
||||
* so a size of 2 means each character will be 12x16, etc.
|
||||
*/
|
||||
void setTextSize(uint8_t s);
|
||||
|
||||
/// Sets whether text will wrap at screen edges.
|
||||
void setTextWrap(boolean w);
|
||||
|
||||
unsigned char* getBuffer();
|
||||
|
||||
/// Writes a single ASCII character to the screen.
|
||||
virtual size_t write(uint8_t);
|
||||
|
||||
/// Seeds the random number generator with entropy from the temperature, voltage reading, and microseconds since boot.
|
||||
/**
|
||||
* This method is still most effective when called semi-randomly such
|
||||
* as after a user hits a button to start a game or other semi-random
|
||||
* events
|
||||
*/
|
||||
void initRandomSeed();
|
||||
|
||||
/// Swap the references of two pointers.
|
||||
void swap(int16_t& a, int16_t& b);
|
||||
|
||||
ArduboyTunes tunes;
|
||||
ArduboyAudio audio;
|
||||
|
||||
void setFrameRate(uint8_t rate);
|
||||
bool nextFrame();
|
||||
bool everyXFrames(uint8_t frames);
|
||||
|
||||
/// Returns the load on the CPU as a percentage.
|
||||
/**
|
||||
* This is based on how much of the time your app is spends rendering
|
||||
* frames. This number can be higher than 100 if your app is rendering
|
||||
* really slowly.
|
||||
*/
|
||||
int cpuLoad();
|
||||
|
||||
uint8_t frameRate;
|
||||
uint16_t frameCount;
|
||||
uint8_t eachFrameMillis;
|
||||
long lastFrameStart;
|
||||
long nextFrameStart;
|
||||
bool post_render;
|
||||
uint8_t lastFrameDurationMs;
|
||||
|
||||
/// useful for getting raw approximate voltage values
|
||||
uint16_t rawADC(byte adc_bits);
|
||||
|
||||
protected:
|
||||
unsigned char sBuffer[(HEIGHT*WIDTH)/8];
|
||||
|
||||
|
||||
// Adafruit stuff
|
||||
protected:
|
||||
int16_t cursor_x;
|
||||
int16_t cursor_y;
|
||||
uint8_t textsize;
|
||||
boolean wrap; // If set, 'wrap' text at right edge of display
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
#include <avr/pgmspace.h>
|
||||
|
||||
#ifndef ARDUBOY_LOGO_CREATED
|
||||
#define ARDUBOY_LOGO_CREATED
|
||||
|
||||
// arduboy_logo.png
|
||||
// 88x16
|
||||
PROGMEM const unsigned char arduboy_logo[] = {
|
||||
0xF0, 0xF8, 0x9C, 0x8E, 0x87, 0x83, 0x87, 0x8E, 0x9C, 0xF8,
|
||||
0xF0, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFE, 0xFF, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0xFE, 0xFF, 0x83, 0x83, 0x83, 0x83, 0x83, 0xC7,
|
||||
0xEE, 0x7C, 0x38, 0x00, 0x00, 0xF8, 0xFC, 0x0E, 0x07, 0x03,
|
||||
0x03, 0x03, 0x07, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0x3F, 0x7F,
|
||||
0xE0, 0xC0, 0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x3F, 0xFF, 0xFF,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x3E, 0x77,
|
||||
0xE3, 0xC1, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x1F, 0x3F, 0x70,
|
||||
0xE0, 0xC0, 0xC0, 0xC0, 0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00,
|
||||
0x7F, 0xFF, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xE3, 0x77, 0x3E,
|
||||
0x1C, 0x00, 0x00, 0x1F, 0x3F, 0x70, 0xE0, 0xC0, 0xC0, 0xC0,
|
||||
0xE0, 0x70, 0x3F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,319 @@
|
|||
#include "Arduboy.h"
|
||||
#include "audio.h"
|
||||
|
||||
const byte PROGMEM tune_pin_to_timer_PGM[] = { 3, 1 };
|
||||
volatile byte *_tunes_timer1_pin_port;
|
||||
volatile byte _tunes_timer1_pin_mask;
|
||||
volatile int32_t timer1_toggle_count;
|
||||
volatile byte *_tunes_timer3_pin_port;
|
||||
volatile byte _tunes_timer3_pin_mask;
|
||||
byte _tune_pins[AVAILABLE_TIMERS];
|
||||
byte _tune_num_chans = 0;
|
||||
volatile boolean tune_playing; // is the score still playing?
|
||||
volatile unsigned wait_timer_frequency2; /* its current frequency */
|
||||
volatile boolean wait_timer_playing = false; /* is it currently playing a note? */
|
||||
volatile boolean tonePlaying = false;
|
||||
volatile unsigned long wait_toggle_count; /* countdown score waits */
|
||||
|
||||
// pointers to your musical score and your position in said score
|
||||
volatile const byte *score_start = 0;
|
||||
volatile const byte *score_cursor = 0;
|
||||
|
||||
// Table of midi note frequencies * 2
|
||||
// They are times 2 for greater accuracy, yet still fits in a word.
|
||||
// Generated from Excel by =ROUND(2*440/32*(2^((x-9)/12)),0) for 0<x<128
|
||||
// The lowest notes might not work, depending on the Arduino clock frequency
|
||||
// Ref: http://www.phy.mtu.edu/~suits/notefreqs.html
|
||||
const uint8_t PROGMEM _midi_byte_note_frequencies[48] = {
|
||||
16,17,18,19,21,22,23,24,26,28,29,31,33,35,37,39,41,44,46,49,52,55,58,62,65,
|
||||
69,73,78,82,87,92,98,104,110,117,123,131,139,147,156,165,175,185,196,208,220,
|
||||
233,247
|
||||
};
|
||||
const unsigned int PROGMEM _midi_word_note_frequencies[80] = {
|
||||
262,277,294,311,330,349,370,392,415,440,466,494,523,554,587,622,659,
|
||||
698,740,784,831,880,932,988,1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,
|
||||
1865,1976,2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,3951,4186,
|
||||
4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902,8372,8870,9397,9956,
|
||||
10548,11175,11840,12544,13290,14080,14917,15804,16744,17740,18795,19912,21096,
|
||||
22351,23680,25088 };
|
||||
|
||||
/* AUDIO */
|
||||
|
||||
bool ArduboyAudio::audio_enabled = false;
|
||||
|
||||
void ArduboyAudio::on()
|
||||
{
|
||||
power_timer1_enable();
|
||||
power_timer3_enable();
|
||||
audio_enabled = true;
|
||||
}
|
||||
|
||||
bool ArduboyAudio::enabled()
|
||||
{
|
||||
return audio_enabled;
|
||||
}
|
||||
|
||||
void ArduboyAudio::off()
|
||||
{
|
||||
audio_enabled = false;
|
||||
power_timer1_disable();
|
||||
power_timer3_disable();
|
||||
}
|
||||
|
||||
void ArduboyAudio::saveOnOff()
|
||||
{
|
||||
EEPROM.write(EEPROM_AUDIO_ON_OFF, audio_enabled);
|
||||
}
|
||||
|
||||
void ArduboyAudio::begin()
|
||||
{
|
||||
tune_playing = false;
|
||||
if (EEPROM.read(EEPROM_AUDIO_ON_OFF))
|
||||
on();
|
||||
}
|
||||
|
||||
/* TUNES */
|
||||
|
||||
void ArduboyTunes::initChannel(byte pin)
|
||||
{
|
||||
byte timer_num;
|
||||
|
||||
// we are all out of timers
|
||||
if (_tune_num_chans == AVAILABLE_TIMERS)
|
||||
return;
|
||||
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + _tune_num_chans);
|
||||
_tune_pins[_tune_num_chans] = pin;
|
||||
_tune_num_chans++;
|
||||
pinMode(pin, OUTPUT);
|
||||
switch (timer_num) {
|
||||
case 1: // 16 bit timer
|
||||
TCCR1A = 0;
|
||||
TCCR1B = 0;
|
||||
bitWrite(TCCR1B, WGM12, 1);
|
||||
bitWrite(TCCR1B, CS10, 1);
|
||||
_tunes_timer1_pin_port = portOutputRegister(digitalPinToPort(pin));
|
||||
_tunes_timer1_pin_mask = digitalPinToBitMask(pin);
|
||||
break;
|
||||
case 3: // 16 bit timer
|
||||
TCCR3A = 0;
|
||||
TCCR3B = 0;
|
||||
bitWrite(TCCR3B, WGM32, 1);
|
||||
bitWrite(TCCR3B, CS30, 1);
|
||||
_tunes_timer3_pin_port = portOutputRegister(digitalPinToPort(pin));
|
||||
_tunes_timer3_pin_mask = digitalPinToBitMask(pin);
|
||||
playNote(0, 60); /* start and stop channel 0 (timer 3) on middle C so wait/delay works */
|
||||
stopNote(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::playNote(byte chan, byte note)
|
||||
{
|
||||
byte timer_num;
|
||||
byte prescalar_bits;
|
||||
unsigned int frequency2; /* frequency times 2 */
|
||||
unsigned long ocr;
|
||||
|
||||
// we can't plan on a channel that does not exist
|
||||
if (chan >= _tune_num_chans)
|
||||
return;
|
||||
|
||||
// we only have frequencies for 128 notes
|
||||
if (note > 127) {
|
||||
return;
|
||||
}
|
||||
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
|
||||
if (note < 48) {
|
||||
frequency2 = pgm_read_byte(_midi_byte_note_frequencies + note);
|
||||
} else {
|
||||
frequency2 = pgm_read_word(_midi_word_note_frequencies + note - 48);
|
||||
}
|
||||
|
||||
//****** 16-bit timer *********
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency2 - 1;
|
||||
prescalar_bits = 0b001;
|
||||
if (ocr > 0xffff) {
|
||||
ocr = F_CPU / frequency2 / 64 - 1;
|
||||
prescalar_bits = 0b011;
|
||||
}
|
||||
// Set the OCR for the given timer, then turn on the interrupts
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalar_bits;
|
||||
OCR1A = ocr;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
break;
|
||||
case 3:
|
||||
TCCR3B = (TCCR3B & 0b11111000) | prescalar_bits;
|
||||
OCR3A = ocr;
|
||||
wait_timer_frequency2 = frequency2; // for "tune_delay" function
|
||||
wait_timer_playing = true;
|
||||
bitWrite(TIMSK3, OCIE3A, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::stopNote(byte chan)
|
||||
{
|
||||
byte timer_num;
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
TIMSK1 &= ~(1 << OCIE1A); // disable the interrupt
|
||||
*_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask); // keep pin low after stop
|
||||
break;
|
||||
case 3:
|
||||
wait_timer_playing = false;
|
||||
*_tunes_timer3_pin_port &= ~(_tunes_timer3_pin_mask); // keep pin low after stop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::playScore(const byte *score)
|
||||
{
|
||||
score_start = score;
|
||||
score_cursor = score_start;
|
||||
step(); /* execute initial commands */
|
||||
tune_playing = true; /* release the interrupt routine */
|
||||
}
|
||||
|
||||
void ArduboyTunes::stopScore (void)
|
||||
{
|
||||
for (uint8_t i = 0; i < _tune_num_chans; i++)
|
||||
stopNote(i);
|
||||
tune_playing = false;
|
||||
}
|
||||
|
||||
bool ArduboyTunes::playing()
|
||||
{
|
||||
return tune_playing;
|
||||
}
|
||||
|
||||
/* Do score commands until a "wait" is found, or the score is stopped.
|
||||
This is called initially from tune_playcore, but then is called
|
||||
from the interrupt routine when waits expire.
|
||||
*/
|
||||
/* if CMD < 0x80, then the other 7 bits and the next byte are a 15-bit big-endian number of msec to wait */
|
||||
void ArduboyTunes::step()
|
||||
{
|
||||
byte command, opcode, chan;
|
||||
unsigned duration;
|
||||
|
||||
while (1) {
|
||||
command = pgm_read_byte(score_cursor++);
|
||||
opcode = command & 0xf0;
|
||||
chan = command & 0x0f;
|
||||
if (opcode == TUNE_OP_STOPNOTE) { /* stop note */
|
||||
stopNote(chan);
|
||||
}
|
||||
else if (opcode == TUNE_OP_PLAYNOTE) { /* play note */
|
||||
playNote(chan, pgm_read_byte(score_cursor++));
|
||||
}
|
||||
else if (opcode == TUNE_OP_RESTART) { /* restart score */
|
||||
score_cursor = score_start;
|
||||
}
|
||||
else if (opcode == TUNE_OP_STOP) { /* stop score */
|
||||
tune_playing = false;
|
||||
break;
|
||||
}
|
||||
else if (opcode < 0x80) { /* wait count in msec. */
|
||||
duration = ((unsigned)command << 8) | (pgm_read_byte(score_cursor++));
|
||||
wait_toggle_count = ((unsigned long) wait_timer_frequency2 * duration + 500) / 1000;
|
||||
if (wait_toggle_count == 0) wait_toggle_count = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::closeChannels(void)
|
||||
{
|
||||
byte timer_num;
|
||||
for (uint8_t chan=0; chan < _tune_num_chans; chan++) {
|
||||
timer_num = pgm_read_byte(tune_pin_to_timer_PGM + chan);
|
||||
switch (timer_num) {
|
||||
case 1:
|
||||
TIMSK1 &= ~(1 << OCIE1A);
|
||||
break;
|
||||
case 3:
|
||||
TIMSK3 &= ~(1 << OCIE3A);
|
||||
break;
|
||||
}
|
||||
digitalWrite(_tune_pins[chan], 0);
|
||||
}
|
||||
_tune_num_chans = 0;
|
||||
tune_playing = false;
|
||||
}
|
||||
|
||||
void ArduboyTunes::soundOutput()
|
||||
{
|
||||
if (wait_timer_playing) { // toggle the pin if we're sounding a note
|
||||
*_tunes_timer3_pin_port ^= _tunes_timer3_pin_mask;
|
||||
}
|
||||
if (tune_playing && wait_toggle_count && --wait_toggle_count == 0) {
|
||||
// end of a score wait, so execute more score commands
|
||||
ArduboyTunes::step(); // execute commands
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyTunes::tone(unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
tonePlaying = true;
|
||||
uint8_t prescalarbits = 0b001;
|
||||
int32_t toggle_count = 0;
|
||||
uint32_t ocr = 0;
|
||||
|
||||
// two choices for the 16 bit timers: ck/1 or ck/64
|
||||
ocr = F_CPU / frequency / 2 - 1;
|
||||
prescalarbits = 0b001;
|
||||
if (ocr > 0xffff) {
|
||||
ocr = F_CPU / frequency / 2 / 64 - 1;
|
||||
prescalarbits = 0b011;
|
||||
}
|
||||
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
|
||||
|
||||
// Calculate the toggle count
|
||||
if (duration > 0) {
|
||||
toggle_count = 2 * frequency * duration / 1000;
|
||||
}
|
||||
else {
|
||||
toggle_count = -1;
|
||||
}
|
||||
// Set the OCR for the given timer,
|
||||
// set the toggle count,
|
||||
// then turn on the interrupts
|
||||
OCR1A = ocr;
|
||||
timer1_toggle_count = toggle_count;
|
||||
bitWrite(TIMSK1, OCIE1A, 1);
|
||||
}
|
||||
|
||||
// TIMER 1
|
||||
ISR(TIMER1_COMPA_vect)
|
||||
{
|
||||
if (tonePlaying) {
|
||||
if (timer1_toggle_count != 0) {
|
||||
// toggle the pin
|
||||
*_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask;
|
||||
if (timer1_toggle_count > 0) timer1_toggle_count--;
|
||||
}
|
||||
else {
|
||||
tonePlaying = false;
|
||||
TIMSK1 &= ~(1 << OCIE1A); // disable the interrupt
|
||||
*_tunes_timer1_pin_port &= ~(_tunes_timer1_pin_mask); // keep pin low after stop
|
||||
}
|
||||
}
|
||||
else {
|
||||
*_tunes_timer1_pin_port ^= _tunes_timer1_pin_mask; // toggle the pin
|
||||
}
|
||||
}
|
||||
|
||||
// TIMER 3
|
||||
ISR(TIMER3_COMPA_vect)
|
||||
{
|
||||
// Timer 3 is the one assigned first, so we keep it running always
|
||||
// and use it to time score waits, whether or not it is playing a note.
|
||||
ArduboyTunes::soundOutput();
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#ifndef ArduboyAudio_h
|
||||
#define ArduboyAudio_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/power.h>
|
||||
|
||||
#define AVAILABLE_TIMERS 2
|
||||
#define TUNE_OP_PLAYNOTE 0x90 /* play a note: low nibble is generator #, note is next byte */
|
||||
#define TUNE_OP_STOPNOTE 0x80 /* stop a note: low nibble is generator # */
|
||||
#define TUNE_OP_RESTART 0xe0 /* restart the score from the beginning */
|
||||
#define TUNE_OP_STOP 0xf0 /* stop playing */
|
||||
|
||||
|
||||
class ArduboyAudio
|
||||
{
|
||||
public:
|
||||
void static begin();
|
||||
void static on();
|
||||
void static off();
|
||||
void static saveOnOff();
|
||||
bool static enabled();
|
||||
|
||||
protected:
|
||||
bool static audio_enabled;
|
||||
};
|
||||
|
||||
|
||||
class ArduboyTunes
|
||||
{
|
||||
public:
|
||||
// Playtune Functions
|
||||
|
||||
/// Assign a timer to an output pin.
|
||||
void initChannel(byte pin);
|
||||
|
||||
/// Start playing a polyphonic score.
|
||||
void playScore(const byte *score);
|
||||
|
||||
/// Stop playing the score.
|
||||
void stopScore();
|
||||
|
||||
/// Delay in milliseconds.
|
||||
void delay(unsigned msec);
|
||||
|
||||
/// Stop all timers.
|
||||
void closeChannels();
|
||||
|
||||
bool playing();
|
||||
void tone(unsigned int frequency, unsigned long duration);
|
||||
|
||||
// called via interrupt
|
||||
void static step();
|
||||
void static soundOutput();
|
||||
|
||||
private:
|
||||
void static playNote (byte chan, byte note);
|
||||
void static stopNote (byte chan);
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,333 @@
|
|||
#include "core.h"
|
||||
|
||||
// need to redeclare these here since we declare them static in .h
|
||||
volatile uint8_t *ArduboyCore::mosiport,
|
||||
*ArduboyCore::csport, *ArduboyCore::dcport;
|
||||
uint8_t ArduboyCore::mosipinmask,
|
||||
ArduboyCore::cspinmask, ArduboyCore::dcpinmask;
|
||||
|
||||
const uint8_t PROGMEM pinBootProgram[] = {
|
||||
// buttons
|
||||
PIN_LEFT_BUTTON, INPUT_PULLUP,
|
||||
PIN_RIGHT_BUTTON, INPUT_PULLUP,
|
||||
PIN_UP_BUTTON, INPUT_PULLUP,
|
||||
PIN_DOWN_BUTTON, INPUT_PULLUP,
|
||||
PIN_A_BUTTON, INPUT_PULLUP,
|
||||
PIN_B_BUTTON, INPUT_PULLUP,
|
||||
|
||||
// OLED SPI
|
||||
DC, OUTPUT,
|
||||
CS, OUTPUT,
|
||||
RST, OUTPUT,
|
||||
0
|
||||
};
|
||||
|
||||
const uint8_t PROGMEM lcdBootProgram[] = {
|
||||
// boot defaults are commented out but left here incase they
|
||||
// might prove useful for reference
|
||||
//
|
||||
// Further reading: https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
//
|
||||
// Display Off
|
||||
// 0xAE,
|
||||
|
||||
// Set Display Clock Divisor v = 0xF0
|
||||
// default is 0x80
|
||||
0xD5, 0xF0,
|
||||
|
||||
// Set Multiplex Ratio v = 0x3F
|
||||
// 0xA8, 0x3F,
|
||||
|
||||
// Set Display Offset v = 0
|
||||
// 0xD3, 0x00,
|
||||
|
||||
// Set Start Line (0)
|
||||
// 0x40,
|
||||
|
||||
// Charge Pump Setting v = enable (0x14)
|
||||
// default is disabled
|
||||
0x8D, 0x14,
|
||||
|
||||
// Set Segment Re-map (A0) | (b0001)
|
||||
// default is (b0000)
|
||||
0xA1,
|
||||
|
||||
// Set COM Output Scan Direction
|
||||
0xC8,
|
||||
|
||||
// Set COM Pins v
|
||||
// 0xDA, 0x12,
|
||||
|
||||
// Set Contrast v = 0xCF
|
||||
0x81, 0xCF,
|
||||
|
||||
// Set Precharge = 0xF1
|
||||
0xD9, 0xF1,
|
||||
|
||||
// Set VCom Detect
|
||||
// 0xDB, 0x40,
|
||||
|
||||
// Entire Display ON
|
||||
// 0xA4,
|
||||
|
||||
// Set normal/inverse display
|
||||
// 0xA6,
|
||||
|
||||
// Display On
|
||||
0xAF,
|
||||
|
||||
// set display mode = horizontal addressing mode (0x00)
|
||||
0x20, 0x00,
|
||||
|
||||
// set col address range
|
||||
// 0x21, 0x00, COLUMN_ADDRESS_END,
|
||||
|
||||
// set page address range
|
||||
// 0x22, 0x00, PAGE_ADDRESS_END
|
||||
};
|
||||
|
||||
|
||||
ArduboyCore::ArduboyCore() {}
|
||||
|
||||
void ArduboyCore::boot()
|
||||
{
|
||||
#if F_CPU == 8000000L
|
||||
slowCPU();
|
||||
#endif
|
||||
|
||||
SPI.begin();
|
||||
bootPins();
|
||||
bootLCD();
|
||||
|
||||
#ifdef SAFE_MODE
|
||||
if (buttonsState() == (LEFT_BUTTON | UP_BUTTON))
|
||||
safeMode();
|
||||
#endif
|
||||
|
||||
saveMuchPower();
|
||||
}
|
||||
|
||||
#if F_CPU == 8000000L
|
||||
// if we're compiling for 8Mhz we need to slow the CPU down because the
|
||||
// hardware clock on the Arduboy is 16MHz
|
||||
void ArduboyCore::slowCPU()
|
||||
{
|
||||
uint8_t oldSREG = SREG;
|
||||
cli(); // suspend interrupts
|
||||
CLKPR = _BV(CLKPCE); // allow reprogramming clock
|
||||
CLKPR = 1; // set clock divisor to 2 (0b0001)
|
||||
SREG = oldSREG; // restore interrupts
|
||||
}
|
||||
#endif
|
||||
|
||||
void ArduboyCore::bootPins()
|
||||
{
|
||||
uint8_t pin, mode;
|
||||
const uint8_t *i = pinBootProgram;
|
||||
|
||||
while(true) {
|
||||
pin = pgm_read_byte(i++);
|
||||
mode = pgm_read_byte(i++);
|
||||
if (pin==0) break;
|
||||
pinMode(pin, mode);
|
||||
}
|
||||
|
||||
digitalWrite(RST, HIGH);
|
||||
delay(1); // VDD (3.3V) goes high at start, lets just chill for a ms
|
||||
digitalWrite(RST, LOW); // bring reset low
|
||||
delay(10); // wait 10ms
|
||||
digitalWrite(RST, HIGH); // bring out of reset
|
||||
}
|
||||
|
||||
void ArduboyCore::bootLCD()
|
||||
{
|
||||
// setup the ports we need to talk to the OLED
|
||||
csport = portOutputRegister(digitalPinToPort(CS));
|
||||
cspinmask = digitalPinToBitMask(CS);
|
||||
dcport = portOutputRegister(digitalPinToPort(DC));
|
||||
dcpinmask = digitalPinToBitMask(DC);
|
||||
|
||||
SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
|
||||
LCDCommandMode();
|
||||
// run our customized boot-up command sequence against the
|
||||
// OLED to initialize it properly for Arduboy
|
||||
for (int8_t i=0; i < sizeof(lcdBootProgram); i++) {
|
||||
SPI.transfer(pgm_read_byte(lcdBootProgram + i));
|
||||
}
|
||||
LCDDataMode();
|
||||
}
|
||||
|
||||
void ArduboyCore::LCDDataMode()
|
||||
{
|
||||
*dcport |= dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
}
|
||||
|
||||
void ArduboyCore::LCDCommandMode()
|
||||
{
|
||||
*csport |= cspinmask;
|
||||
*dcport &= ~dcpinmask;
|
||||
*csport &= ~cspinmask;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ArduboyCore::safeMode()
|
||||
{
|
||||
blank(); // too avoid random gibberish
|
||||
while (true) {
|
||||
asm volatile("nop \n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Power Management */
|
||||
|
||||
void ArduboyCore::idle()
|
||||
{
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sleep_mode();
|
||||
}
|
||||
|
||||
void ArduboyCore::saveMuchPower()
|
||||
{
|
||||
power_adc_disable();
|
||||
power_usart0_disable();
|
||||
power_twi_disable();
|
||||
// timer 0 is for millis()
|
||||
// timers 1 and 3 are for music and sounds
|
||||
power_timer2_disable();
|
||||
power_usart1_disable();
|
||||
// we need USB, for now (to allow triggered reboots to reprogram)
|
||||
// power_usb_disable()
|
||||
}
|
||||
|
||||
uint8_t ArduboyCore::width() { return WIDTH; }
|
||||
|
||||
uint8_t ArduboyCore::height() { return HEIGHT; }
|
||||
|
||||
|
||||
/* Drawing */
|
||||
|
||||
void ArduboyCore::paint8Pixels(uint8_t pixels)
|
||||
{
|
||||
SPI.transfer(pixels);
|
||||
}
|
||||
|
||||
void ArduboyCore::paintScreen(const unsigned char *image)
|
||||
{
|
||||
for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
|
||||
{
|
||||
SPI.transfer(pgm_read_byte(image + i));
|
||||
}
|
||||
}
|
||||
|
||||
// paint from a memory buffer, this should be FAST as it's likely what
|
||||
// will be used by any buffer based subclass
|
||||
void ArduboyCore::paintScreen(unsigned char image[])
|
||||
{
|
||||
for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
|
||||
{
|
||||
// SPI.transfer(image[i]);
|
||||
|
||||
// we need to burn 18 cycles between sets of SPDR
|
||||
// 4 clock cycles
|
||||
SPDR = image[i];
|
||||
// 7 clock cycles
|
||||
asm volatile(
|
||||
"mul __zero_reg__, __zero_reg__ \n" // 2 cycles
|
||||
"mul __zero_reg__, __zero_reg__ \n" // 2 cycles
|
||||
"mul __zero_reg__, __zero_reg__ \n" // 2 cycles
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ArduboyCore::blank()
|
||||
{
|
||||
for (int i = 0; i < (HEIGHT*WIDTH)/8; i++)
|
||||
SPI.transfer(0x00);
|
||||
}
|
||||
|
||||
void ArduboyCore::sendLCDCommand(uint8_t command)
|
||||
{
|
||||
LCDCommandMode();
|
||||
SPI.transfer(command);
|
||||
LCDDataMode();
|
||||
}
|
||||
|
||||
// invert the display or set to normal
|
||||
// when inverted, a pixel set to 0 will be on
|
||||
void ArduboyCore::invert(boolean inverse)
|
||||
{
|
||||
sendLCDCommand(inverse ? OLED_PIXELS_INVERTED : OLED_PIXELS_NORMAL);
|
||||
}
|
||||
|
||||
// turn all display pixels on, ignoring buffer contents
|
||||
// or set to normal buffer display
|
||||
void ArduboyCore::allPixelsOn(boolean on)
|
||||
{
|
||||
sendLCDCommand(on ? OLED_ALL_PIXELS_ON : OLED_PIXELS_FROM_RAM);
|
||||
}
|
||||
|
||||
// flip the display vertically or set to normal
|
||||
void ArduboyCore::flipVertical(boolean flipped)
|
||||
{
|
||||
sendLCDCommand(flipped ? OLED_VERTICAL_FLIPPED : OLED_VERTICAL_NORMAL);
|
||||
}
|
||||
|
||||
#define OLED_HORIZ_FLIPPED 0xA0 // reversed segment re-map
|
||||
#define OLED_HORIZ_NORMAL 0xA1 // normal segment re-map
|
||||
|
||||
// flip the display horizontally or set to normal
|
||||
void ArduboyCore::flipHorizontal(boolean flipped)
|
||||
{
|
||||
sendLCDCommand(flipped ? OLED_HORIZ_FLIPPED : OLED_HORIZ_NORMAL);
|
||||
}
|
||||
|
||||
/* RGB LED */
|
||||
|
||||
void ArduboyCore::setRGBled(uint8_t red, uint8_t green, uint8_t blue)
|
||||
{
|
||||
#ifdef ARDUBOY_10 // RGB, all the pretty colors
|
||||
// inversion is necessary because these are common annode LEDs
|
||||
analogWrite(RED_LED, 255 - red);
|
||||
analogWrite(GREEN_LED, 255 - green);
|
||||
analogWrite(BLUE_LED, 255 - blue);
|
||||
#elif defined(AB_DEVKIT)
|
||||
// only blue on devkit
|
||||
digitalWrite(BLUE_LED, ~blue);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
uint8_t ArduboyCore::getInput()
|
||||
{
|
||||
return buttonsState();
|
||||
}
|
||||
|
||||
|
||||
uint8_t ArduboyCore::buttonsState()
|
||||
{
|
||||
uint8_t buttons;
|
||||
|
||||
// using ports here is ~100 bytes smaller than digitalRead()
|
||||
#ifdef AB_DEVKIT
|
||||
// down, left, up
|
||||
buttons = ((~PINB) & B01110000);
|
||||
// right button
|
||||
buttons = buttons | (((~PINC) & B01000000) >> 4);
|
||||
// A and B
|
||||
buttons = buttons | (((~PINF) & B11000000) >> 6);
|
||||
#elif defined(ARDUBOY_10)
|
||||
// down, up, left right
|
||||
buttons = ((~PINF) & B11110000);
|
||||
// A (left)
|
||||
buttons = buttons | (((~PINE) & B01000000) >> 3);
|
||||
// B (right)
|
||||
buttons = buttons | (((~PINB) & B00010000) >> 2);
|
||||
#endif
|
||||
|
||||
return buttons;
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
#ifndef ArduboyCore_h
|
||||
#define ArduboyCore_h
|
||||
|
||||
#include <avr/power.h>
|
||||
#include <SPI.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// main hardware compile flags
|
||||
|
||||
#if !defined(ARDUBOY_10) && !defined(AB_DEVKIT)
|
||||
/// defaults to Arduboy Release 1.0 if not using a boards.txt file
|
||||
/**
|
||||
* we default to Arduboy Release 1.0 if a compile flag has not been
|
||||
* passed to us from a boards.txt file
|
||||
*
|
||||
* if you wish to compile for the devkit without using a boards.txt
|
||||
* file simply comment out the ARDUBOY_10 define and uncomment
|
||||
* the AB_DEVKIT define like this:
|
||||
*
|
||||
* // #define ARDUBOY_10
|
||||
* #define AB_DEVKIT
|
||||
*/
|
||||
#define ARDUBOY_10 //< compile for the production Arduboy v1.0
|
||||
// #define AB_DEVKIT //< compile for the official dev kit
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef AB_DEVKIT
|
||||
#define DEVKIT //< for compatibilty with older sketches
|
||||
#define SAFE_MODE //< include safe mode (44 bytes)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ARDUBOY_10
|
||||
|
||||
#define CS 12
|
||||
#define DC 4
|
||||
#define RST 6
|
||||
|
||||
#define RED_LED 10
|
||||
#define GREEN_LED 11
|
||||
#define BLUE_LED 9
|
||||
#define TX_LED 30
|
||||
#define RX_LED 17
|
||||
|
||||
// pin values for buttons, probably shouldn't use these
|
||||
#define PIN_LEFT_BUTTON A2
|
||||
#define PIN_RIGHT_BUTTON A1
|
||||
#define PIN_UP_BUTTON A0
|
||||
#define PIN_DOWN_BUTTON A3
|
||||
#define PIN_A_BUTTON 7
|
||||
#define PIN_B_BUTTON 8
|
||||
|
||||
// bit values for button states
|
||||
#define LEFT_BUTTON _BV(5)
|
||||
#define RIGHT_BUTTON _BV(6)
|
||||
#define UP_BUTTON _BV(7)
|
||||
#define DOWN_BUTTON _BV(4)
|
||||
#define A_BUTTON _BV(3)
|
||||
#define B_BUTTON _BV(2)
|
||||
|
||||
#define PIN_SPEAKER_1 5
|
||||
#define PIN_SPEAKER_2 13
|
||||
|
||||
#define PIN_SPEAKER_1_PORT &PORTC
|
||||
#define PIN_SPEAKER_2_PORT &PORTC
|
||||
|
||||
#define PIN_SPEAKER_1_BITMASK _BV(6)
|
||||
#define PIN_SPEAKER_2_BITMASK _BV(7)
|
||||
|
||||
#elif defined(AB_DEVKIT)
|
||||
|
||||
#define CS 6
|
||||
#define DC 4
|
||||
#define RST 12
|
||||
|
||||
// map all LEDs to the single TX LED on DEVKIT
|
||||
#define RED_LED 17
|
||||
#define GREEN_LED 17
|
||||
#define BLUE_LED 17
|
||||
#define TX_LED 17
|
||||
#define RX_LED 17
|
||||
|
||||
// pin values for buttons, probably shouldn't use these
|
||||
#define PIN_LEFT_BUTTON 9
|
||||
#define PIN_RIGHT_BUTTON 5
|
||||
#define PIN_UP_BUTTON 8
|
||||
#define PIN_DOWN_BUTTON 10
|
||||
#define PIN_A_BUTTON A0
|
||||
#define PIN_B_BUTTON A1
|
||||
|
||||
// bit values for button states
|
||||
#define LEFT_BUTTON _BV(5)
|
||||
#define RIGHT_BUTTON _BV(2)
|
||||
#define UP_BUTTON _BV(4)
|
||||
#define DOWN_BUTTON _BV(6)
|
||||
#define A_BUTTON _BV(1)
|
||||
#define B_BUTTON _BV(0)
|
||||
|
||||
#define PIN_SPEAKER_1 A2
|
||||
#define PIN_SPEAKER_2 A3
|
||||
|
||||
#define PIN_SPEAKER_1_PORT &PORTF
|
||||
#define PIN_SPEAKER_2_PORT &PORTF
|
||||
|
||||
#define PIN_SPEAKER_1_BITMASK _BV(5)
|
||||
#define PIN_SPEAKER_2_BITMASK _BV(4)
|
||||
|
||||
#endif
|
||||
|
||||
// OLED hardware (SSD1306)
|
||||
|
||||
#define OLED_PIXELS_INVERTED 0xA7 // All pixels inverted
|
||||
#define OLED_PIXELS_NORMAL 0xA6 // All pixels normal
|
||||
|
||||
#define OLED_ALL_PIXELS_ON 0xA5 // all pixels on
|
||||
#define OLED_PIXELS_FROM_RAM 0xA4 // pixels mapped to display RAM contents
|
||||
|
||||
#define OLED_VERTICAL_FLIPPED 0xC0 // reversed COM scan direction
|
||||
#define OLED_VERTICAL_NORMAL 0xC8 // normal COM scan direction
|
||||
|
||||
// -----
|
||||
|
||||
#define COLUMN_ADDRESS_END (WIDTH - 1) & 0x7F // 128 pixels wide
|
||||
#define PAGE_ADDRESS_END ((HEIGHT/8)-1) & 0x07 // 8 pages high
|
||||
|
||||
#define WIDTH 128
|
||||
#define HEIGHT 64
|
||||
|
||||
#define INVERT 2 //< lit/unlit pixel
|
||||
#define WHITE 1 //< lit pixel
|
||||
#define BLACK 0 //< unlit pixel
|
||||
|
||||
class ArduboyCore
|
||||
{
|
||||
public:
|
||||
ArduboyCore();
|
||||
|
||||
/// allows the CPU to idle between frames
|
||||
/**
|
||||
* This puts the CPU in "Idle" sleep mode. You should call this as often
|
||||
* as you can for the best power savings. The timer 0 overflow interrupt
|
||||
* will wake up the chip every 1ms - so even at 60 FPS a well written
|
||||
* app should be able to sleep maybe half the time in between rendering
|
||||
* it's own frames.
|
||||
*
|
||||
* See the Arduboy class nextFrame() for an example of how to use idle()
|
||||
* in a frame loop.
|
||||
*/
|
||||
void static idle();
|
||||
|
||||
void static LCDDataMode(); //< put the display in data mode
|
||||
|
||||
/// put the display in command mode
|
||||
/**
|
||||
* See SSD1306 documents for available commands and command sequences.
|
||||
*
|
||||
* Links:
|
||||
* - https://www.adafruit.com/datasheets/SSD1306.pdf
|
||||
* - http://www.eimodule.com/download/SSD1306-OLED-Controller.pdf
|
||||
*/
|
||||
void static LCDCommandMode();
|
||||
|
||||
uint8_t static width(); //< return display width
|
||||
uint8_t static height(); // < return display height
|
||||
|
||||
/// get current state of all buttons (bitmask)
|
||||
/**
|
||||
* Bit mask that is returned:
|
||||
*
|
||||
* Hi Low
|
||||
* DevKit 00000000 - reserved
|
||||
* -DLU-RAB D down
|
||||
* U up
|
||||
* 1.0 00000000 L left
|
||||
* URLDAB-- R right
|
||||
*
|
||||
* Of course you shouldn't worry about bits (they may change with future
|
||||
* hardware revisions) and should instead use the button defines:
|
||||
* LEFT_BUTTON, A_BUTTON, UP_BUTTON, etc.
|
||||
*/
|
||||
|
||||
uint8_t static getInput(); __attribute__ ((deprecated("use buttonsState() instead")));
|
||||
uint8_t static buttonsState();
|
||||
|
||||
// paints 8 pixels (vertically) from a single byte
|
||||
// - 1 is lit, 0 is unlit
|
||||
//
|
||||
// NOTE: You probably wouldn't actually use this, you'd build something
|
||||
// higher level that does it's own calls to SPI.transfer(). It's
|
||||
// included for completeness since it seems there should be some very
|
||||
// rudimentary low-level draw function in the core that supports the
|
||||
// minimum unit that the hardware allows (which is a strip of 8 pixels)
|
||||
//
|
||||
// This routine starts in the top left and then across the screen.
|
||||
// After each "page" (row) of 8 pixels is drawn it will shift down
|
||||
// to start drawing the next page. To paint the full screen you call
|
||||
// this function 1,024 times.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// X = painted pixels, . = unpainted
|
||||
//
|
||||
// blank() paint8Pixels() 0xFF, 0, 0x0F, 0, 0xF0
|
||||
// v TOP LEFT corner (8x9) v TOP LEFT corner
|
||||
// ........ (page 1) X...X... (page 1)
|
||||
// ........ X...X...
|
||||
// ........ X...X...
|
||||
// ........ X...X...
|
||||
// ........ X.X.....
|
||||
// ........ X.X.....
|
||||
// ........ X.X.....
|
||||
// ........ (end of page 1) X.X..... (end of page 1)
|
||||
// ........ (page 2) ........ (page 2)
|
||||
void static paint8Pixels(uint8_t pixels);
|
||||
|
||||
/// paints an entire image directly to hardware (from PROGMEM)
|
||||
/*
|
||||
* Each byte will be 8 vertical pixels, painted in the same order as
|
||||
* explained above in paint8Pixels.
|
||||
*/
|
||||
void static paintScreen(const unsigned char *image);
|
||||
|
||||
/// paints an entire image directly to hardware (from RAM)
|
||||
/*
|
||||
* Each byte will be 8 vertical pixels, painted in the same order as
|
||||
* explained above in paint8Pixels.
|
||||
*/
|
||||
void static paintScreen(unsigned char image[]);
|
||||
|
||||
/// paints a blank (black) screen to hardware
|
||||
void static blank();
|
||||
|
||||
/// invert the display or set to normal
|
||||
/**
|
||||
* when inverted, a pixel set to 0 will be on
|
||||
*/
|
||||
void static invert(boolean inverse);
|
||||
|
||||
/// turn all display pixels on, or display the buffer contents
|
||||
/**
|
||||
* when set to all pixels on, the display buffer will be
|
||||
* ignored but not altered
|
||||
*/
|
||||
void static allPixelsOn(boolean on);
|
||||
|
||||
/// flip the display vertically or set to normal
|
||||
void static flipVertical(boolean flipped);
|
||||
|
||||
/// flip the display horizontally or set to normal
|
||||
void static flipHorizontal(boolean flipped);
|
||||
|
||||
/// send a single byte command to the OLED
|
||||
void static sendLCDCommand(uint8_t command);
|
||||
|
||||
/// set the light output of the RGB LEB
|
||||
void setRGBled(uint8_t red, uint8_t green, uint8_t blue);
|
||||
|
||||
protected:
|
||||
/// boots the hardware
|
||||
/**
|
||||
* - sets input/output/pullup mode for pins
|
||||
* - powers up the OLED screen and initializes it properly
|
||||
* - sets up power saving
|
||||
* - kicks CPU down to 8Mhz if needed
|
||||
* - allows Safe mode to be entered
|
||||
*/
|
||||
void static boot();
|
||||
|
||||
/// Safe mode
|
||||
/**
|
||||
* Safe Mode is engaged by holding down both the LEFT button and UP button
|
||||
* when plugging the device into USB. It puts your device into a tight
|
||||
* loop and allows it to be reprogrammed even if you have uploaded a very
|
||||
* broken sketch that interferes with the normal USB triggered auto-reboot
|
||||
* functionality of the device.
|
||||
*
|
||||
* This is most useful on Devkits because they lack a built-in reset
|
||||
* button.
|
||||
*/
|
||||
void static inline safeMode() __attribute__((always_inline));
|
||||
|
||||
// internals
|
||||
void static inline bootLCD() __attribute__((always_inline));
|
||||
void static inline bootPins() __attribute__((always_inline));
|
||||
void static inline slowCPU() __attribute__((always_inline));
|
||||
void static inline saveMuchPower(); __attribute__((always_inline));
|
||||
|
||||
|
||||
private:
|
||||
volatile static uint8_t *mosiport, *csport, *dcport;
|
||||
uint8_t static mosipinmask, cspinmask, dcpinmask;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -183,6 +183,7 @@ const static unsigned char font[] PROGMEM =
|
|||
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,
|
Loading…
Reference in New Issue