Louis Mayencourt
/
NRF_OLED
Arduboy lib for NRF and mbed
Revision 0:2b6d7af79c9c, committed 2016-12-27
- Comitter:
- lmayencou
- Date:
- Tue Dec 27 11:27:14 2016 +0000
- Commit message:
- first publish
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.gitignore Tue Dec 27 11:27:14 2016 +0000 @@ -0,0 +1,4 @@ +.build +.mbed +projectfiles +*.py*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adafruit_GFX.lib Tue Dec 27 11:27:14 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/nkhorman/code/Adafruit_GFX/#7fb1d4d3525d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Tue Dec 27 11:27:14 2016 +0000 @@ -0,0 +1,89 @@ +# Getting started with Blinky on mbed OS + +This is a very simple guide, reviewing the steps required to get Blinky working on an mbed OS platform. + +Please install [mbed CLI](https://github.com/ARMmbed/mbed-cli#installing-mbed-cli). + +## Get the example application! + +From the command line, import the example: + +``` +mbed import mbed-os-example-blinky +cd mbed-os-example-blinky +``` + +### Now compile + +Invoke `mbed compile` specifying the name of your platform and your favorite toolchain (`GCC_ARM`, `ARM`, `IAR`). For example, for the ARM Compiler 5: + +``` +mbed compile -m K64F -t ARM +``` + +Your PC may take a few minutes to compile your code. At the end you should get the following result: + +``` +[snip] ++----------------------------+-------+-------+------+ +| Module | .text | .data | .bss | ++----------------------------+-------+-------+------+ +| Misc | 13939 | 24 | 1372 | +| core/hal | 16993 | 96 | 296 | +| core/rtos | 7384 | 92 | 4204 | +| features/FEATURE_IPV4 | 80 | 0 | 176 | +| frameworks/greentea-client | 1830 | 60 | 44 | +| frameworks/utest | 2392 | 512 | 292 | +| Subtotals | 42618 | 784 | 6384 | ++----------------------------+-------+-------+------+ +Allocated Heap: unknown +Allocated Stack: unknown +Total Static RAM memory (data + bss): 7168 bytes +Total RAM memory (data + bss + heap + stack): 7168 bytes +Total Flash memory (text + data + misc): 43402 bytes +Image: .\.build\K64F\ARM\mbed-os-example-blinky.bin +``` + +### Program your board + +1. Connect your mbed device to the computer over USB. +1. Copy the binary file to the mbed device . +1. Press the reset button to start the program. + +You should see the LED of your platform turning on and off. + +Congratulations if you managed to complete this test! + +## Export the project to Keil MDK and debug your application + +From the command line, run the following command: + +``` +mbed export -m K64F -i uvision +``` + +To debug the application: + +1. Start uVision. +1. Import the uVision project generated earlier. +1. Compile your application and generate an `.axf` file. +1. Make sure uVision is configured to debug over CMSIS-DAP (From the Project menu > Options for Target '...' > Debug tab > Use CMSIS-DAP Debugger). +1. Set breakpoints and start a debug session. + +![Image of uVision](img/uvision.png) + +## Troubleshooting + +1. Make sure `mbed-cli` is working correctly and its version is greater than `0.8.9` + + ``` + mbed --version + ``` + + If not, you can update it easily: + + ``` + pip install mbed-cli --upgrade + ``` + +2. If using Keil MDK, make sure you have a license installed. [MDK-Lite](http://www.keil.com/arm/mdk.asp) has a 32KB restriction on code size.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core.cpp Tue Dec 27 11:27:14 2016 +0000 @@ -0,0 +1,606 @@ +#include "core.h" + +unsigned char Arduboy::sBuffer[]; + +Arduboy::Arduboy() : + i2c(SDA,SCL), + Adafruit_SSD1306_I2c(i2c,p13) +{ } + +void Arduboy::start() +{ +#if F_CPU == 8000000L + slowCPU(); +#endif + + // init pin + DigitalOut led1(LED1); + + bootLCD(); + +#ifdef SAFE_MODE + if (pressed(LEFT_BUTTON + UP_BUTTON)) + safeMode(); +#endif + + + audio.setup(); + 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 Arduboy::slowCPU() +{ + +} +#endif + +void Arduboy::bootLCD() +{ + clearDisplay(); + display(); +} + +// 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. +void Arduboy::safeMode() +{ + display(); // too avoid random gibberish + while (true) {}; +} + +/* Power Management */ + +void Arduboy::idle() +{ +} + +void Arduboy::saveMuchPower() +{ +} + + +/* 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; +} + +// 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 Arduboy::cpuLoad() +{ + return lastFrameDurationMs * 100 / eachFrameMillis; +} + +// seed 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 Arduboy::initRandomSeed() +{ +} + +uint16_t Arduboy::rawADC(byte adc_bits) +{ + return 0; +} + + +unsigned char* Arduboy::getBuffer() { + return sBuffer; +} + +uint8_t Arduboy::width() { + return WIDTH; +} + +uint8_t Arduboy::height() { + return HEIGHT; +} + + +void Arduboy::poll() +{ + previousButtonState = currentButtonState; + currentButtonState = getInput(); +} + +// returns true if the button mask passed in is pressed +// +// if (pressed(LEFT_BUTTON + A_BUTTON)) +boolean Arduboy::pressed(uint8_t buttons) +{ + uint8_t button_state = getInput(); + return (button_state & buttons) == buttons; +} + +// returns true if the button mask passed in not pressed +// +// if (not_pressed(LEFT_BUTTON)) +boolean Arduboy::notPressed(uint8_t buttons) +{ + uint8_t button_state = getInput(); + return (button_state & buttons) == 0; +} + +// returns true if a button has just been pressed +// if the button has been held down for multiple frames this will return +// false. You should only use this to poll a single button. +boolean Arduboy::justPressed(uint8_t button) +{ + uint8_t button_state = getInput(); + return (!(previousButtonState & button) && (currentButtonState & button)); +} + + + +uint8_t Arduboy::getInput() +{ + uint8_t buttons; + + return buttons; +} + +void Arduboy::swap(int16_t& a, int16_t& b) { + int temp = a; + a = b; + b = temp; +} + + +/* AUDIO */ + +void ArduboyAudio::on() { + + audio_enabled = true; +} + +bool ArduboyAudio::enabled() { + return audio_enabled; +} + +void ArduboyAudio::off() { + + audio_enabled = false; +} + +void ArduboyAudio::saveOnOff() { +} + +void ArduboyAudio::setup() { + +} + +void ArduboyAudio::tone(unsigned int frequency, unsigned long duration) +{ + +} + + +///////////////////////// +// Sprites by Dreamer3 // +///////////////////////// +Sprites::Sprites(Arduboy &a) +{ + arduboy = &a; + sBuffer = arduboy->getBuffer(); +} + +// new API + +void Sprites::drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap, + const uint8_t *mask, uint8_t frame, uint8_t mask_frame) +{ + draw(x, y, bitmap, frame, mask, mask_frame, SPRITE_MASKED); +} + +void Sprites::drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) +{ + draw(x, y, bitmap, frame, NULL, 0, SPRITE_OVERWRITE); +} + +void Sprites::drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) +{ + draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK_ERASE); +} + +void Sprites::drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) +{ + draw(x, y, bitmap, frame, NULL, 0, SPRITE_IS_MASK); +} + +void Sprites::drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame) +{ + draw(x, y, bitmap, frame, NULL, 0, SPRITE_PLUS_MASK); +} + + +//common functions +void Sprites::draw(int16_t x, int16_t y, + const uint8_t *bitmap, uint8_t frame, + const uint8_t *mask, uint8_t sprite_frame, + uint8_t drawMode + ) +{ + unsigned int frame_offset; + + if (bitmap == NULL) + return; + + uint8_t width = pgm_read_byte(bitmap); + uint8_t height = pgm_read_byte(++bitmap); + bitmap++; + if (frame > 0 || sprite_frame > 0) { + frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1))); + // sprite plus mask uses twice as much space for each frame + if (drawMode == SPRITE_PLUS_MASK) { + frame_offset *= 2; + } else if (mask != NULL) { + mask += sprite_frame * frame_offset; + } + bitmap += frame * frame_offset; + } + + // if we're detecting the draw mode then base it on whether a mask + // was passed as a separate object + if (drawMode == SPRITE_AUTO_MODE) { + drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED; + } + + drawBitmap(x, y, bitmap, mask, width, height, drawMode); +} + +void Sprites::drawBitmap(int16_t x, int16_t y, + const uint8_t *bitmap, const uint8_t *mask, + int8_t w, int8_t h, uint8_t draw_mode) { + // no need to draw at all of we're offscreen + if (x + w <= 0 || x > WIDTH - 1 || y + h <= 0 || y > HEIGHT - 1) + return; + + if (bitmap == NULL) + return; + + // xOffset technically doesn't need to be 16 bit but the math operations + // are measurably faster if it is + uint16_t xOffset, ofs; + int8_t yOffset = abs(y) % 8; + int8_t sRow = y / 8; + uint8_t loop_h, start_h, rendered_width; + + if (y < 0 && yOffset > 0) { + sRow--; + yOffset = 8 - yOffset; + } + + // if the left side of the render is offscreen skip those loops + if (x < 0) { + xOffset = abs(x); + } else { + xOffset = 0; + } + + // if the right side of the render is offscreen skip those loops + if (x + w > WIDTH - 1) { + rendered_width = ((WIDTH - x) - xOffset); + } else { + rendered_width = (w - xOffset); + } + + // if the top side of the render is offscreen skip those loops + if (sRow < -1) { + start_h = abs(sRow) - 1; + } else { + start_h = 0; + } + + loop_h = h / 8 + (h % 8 > 0 ? 1 : 0); // divide, then round up + + // if (sRow + loop_h - 1 > (HEIGHT/8)-1) + if (sRow + loop_h > (HEIGHT / 8)) { + loop_h = (HEIGHT / 8) - sRow; + } + + // prepare variables for loops later so we can compare with 0 + // instead of comparing two variables + loop_h -= start_h; + + sRow += start_h; + ofs = (sRow * WIDTH) + x + xOffset; + uint8_t *bofs = (uint8_t *)bitmap + (start_h * w) + xOffset; + uint8_t *mask_ofs; + if (mask != 0) + mask_ofs = (uint8_t *)mask + (start_h * w) + xOffset; + uint8_t data; + + uint8_t mul_amt = 1 << yOffset; + uint16_t mask_data; + uint16_t bitmap_data; + + switch (draw_mode) { + case SPRITE_UNMASKED: + // we only want to mask the 8 bits of our own sprite, so we can + // calculate the mask before the start of the loop + mask_data = ~(0xFF * mul_amt); + // really if yOffset = 0 you have a faster case here that could be + // optimized + for (uint8_t a = 0; a < loop_h; a++) { + for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { + bitmap_data = pgm_read_byte(bofs) * mul_amt; + + if (sRow >= 0) { + data = sBuffer[ofs]; + data &= (uint8_t)(mask_data); + data |= (uint8_t)(bitmap_data); + sBuffer[ofs] = data; + } + if (yOffset != 0 && sRow < 7) { + data = sBuffer[ofs + WIDTH]; + data &= (*((unsigned char *) (&mask_data) + 1)); + data |= (*((unsigned char *) (&bitmap_data) + 1)); + sBuffer[ofs + WIDTH] = data; + } + ofs++; + bofs++; + } + sRow++; + bofs += w - rendered_width; + ofs += WIDTH - rendered_width; + } + break; + + case SPRITE_IS_MASK: + for (uint8_t a = 0; a < loop_h; a++) { + for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { + bitmap_data = pgm_read_byte(bofs) * mul_amt; + if (sRow >= 0) { + sBuffer[ofs] |= (uint8_t)(bitmap_data); + } + if (yOffset != 0 && sRow < 7) { + sBuffer[ofs + WIDTH] |= (*((unsigned char *) (&bitmap_data) + 1)); + } + ofs++; + bofs++; + } + sRow++; + bofs += w - rendered_width; + ofs += WIDTH - rendered_width; + } + break; + + case SPRITE_IS_MASK_ERASE: + for (uint8_t a = 0; a < loop_h; a++) { + for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { + bitmap_data = pgm_read_byte(bofs) * mul_amt; + if (sRow >= 0) { + sBuffer[ofs] &= ~(uint8_t)(bitmap_data); + } + if (yOffset != 0 && sRow < 7) { + sBuffer[ofs + WIDTH] &= ~(*((unsigned char *) (&bitmap_data) + 1)); + } + ofs++; + bofs++; + } + sRow++; + bofs += w - rendered_width; + ofs += WIDTH - rendered_width; + } + break; + + case SPRITE_MASKED: + for (uint8_t a = 0; a < loop_h; a++) { + for (uint8_t iCol = 0; iCol < rendered_width; iCol++) { + // NOTE: you might think in the yOffset==0 case that this results + // in more effort, but in all my testing the compiler was forcing + // 16-bit math to happen here anyways, so this isn't actually + // compiling to more code than it otherwise would. If the offset + // is 0 the high part of the word will just never be used. + + // load data and bit shift + // mask needs to be bit flipped + mask_data = ~(pgm_read_byte(mask_ofs) * mul_amt); + bitmap_data = pgm_read_byte(bofs) * mul_amt; + + if (sRow >= 0) { + data = sBuffer[ofs]; + data &= (uint8_t)(mask_data); + data |= (uint8_t)(bitmap_data); + sBuffer[ofs] = data; + } + if (yOffset != 0 && sRow < 7) { + data = sBuffer[ofs + WIDTH]; + data &= (*((unsigned char *) (&mask_data) + 1)); + data |= (*((unsigned char *) (&bitmap_data) + 1)); + sBuffer[ofs + WIDTH] = data; + } + ofs++; + mask_ofs++; + bofs++; + } + sRow++; + bofs += w - rendered_width; + mask_ofs += w - rendered_width; + ofs += WIDTH - rendered_width; + } + break; + + + case SPRITE_PLUS_MASK: + // *2 because we use double the bits (mask + bitmap) + bofs = (uint8_t *)(bitmap + ((start_h * w) + xOffset) * 2); + + uint8_t xi = rendered_width; // used for x loop below + uint8_t yi = loop_h; // used for y loop below + + asm volatile( + "push r28\n" // save Y + "push r29\n" + "mov r28, %A[buffer_page2_ofs]\n" // Y = buffer page 2 offset + "mov r29, %B[buffer_page2_ofs]\n" + "loop_y:\n" + "loop_x:\n" + // load bitmap and mask data + "lpm %A[bitmap_data], Z+\n" + "lpm %A[mask_data], Z+\n" + + // shift mask and buffer data + "tst %[yOffset]\n" + "breq skip_shifting\n" + "mul %A[bitmap_data], %[mul_amt]\n" + "mov %A[bitmap_data], r0\n" + "mov %B[bitmap_data], r1\n" + "mul %A[mask_data], %[mul_amt]\n" + "mov %A[mask_data], r0\n" + // "mov %B[mask_data], r1\n" + + + // SECOND PAGE + // if yOffset != 0 && sRow < 7 + "cpi %[sRow], 7\n" + "brge end_second_page\n" + // then + "ld %[data], Y\n" + // "com %B[mask_data]\n" // invert high byte of mask + "com r1\n" + "and %[data], r1\n" // %B[mask_data] + "or %[data], %B[bitmap_data]\n" + // update buffer, increment + "st Y+, %[data]\n" + + "end_second_page:\n" + "skip_shifting:\n" + + + // FIRST PAGE + "ld %[data], %a[buffer_ofs]\n" + // if sRow >= 0 + "tst %[sRow]\n" + "brmi end_first_page\n" + // then + "com %A[mask_data]\n" + "and %[data], %A[mask_data]\n" + "or %[data], %A[bitmap_data]\n" + + "end_first_page:\n" + // update buffer, increment + "st %a[buffer_ofs]+, %[data]\n" + + + // "x_loop_next:\n" + "dec %[xi]\n" + "brne loop_x\n" + + // increment y + "next_loop_y:\n" + "dec %[yi]\n" + "breq finished\n" + "mov %[xi], %[x_count]\n" // reset x counter + // sRow++; + "inc %[sRow]\n" + "clr __zero_reg__\n" + // sprite_ofs += (w - rendered_width) * 2; + "add %A[sprite_ofs], %A[sprite_ofs_jump]\n" + "adc %B[sprite_ofs], __zero_reg__\n" + // buffer_ofs += WIDTH - rendered_width; + "add %A[buffer_ofs], %A[buffer_ofs_jump]\n" + "adc %B[buffer_ofs], __zero_reg__\n" + // buffer_ofs_page_2 += WIDTH - rendered_width; + "add r28, %A[buffer_ofs_jump]\n" + "adc r29, __zero_reg__\n" + + "rjmp loop_y\n" + "finished:\n" + // put the Y register back in place + "pop r29\n" + "pop r28\n" + "clr __zero_reg__\n" // just in case + : [xi] "+&r" (xi), + [yi] "+&r" (yi), + [sRow] "+&a" (sRow), // CPI requires an upper register + [data] "+&r" (data), + [mask_data] "+&r" (mask_data), + [bitmap_data] "+&r" (bitmap_data) + : + [x_count] "r" (rendered_width), + [y_count] "r" (loop_h), + [sprite_ofs] "z" (bofs), + [buffer_ofs] "x" (sBuffer+ofs), + [buffer_page2_ofs] "r" (sBuffer+ofs+WIDTH), // Y pointer + [buffer_ofs_jump] "r" (WIDTH-rendered_width), + [sprite_ofs_jump] "r" ((w-rendered_width)*2), + [yOffset] "r" (yOffset), + [mul_amt] "r" (mul_amt) + : + ); + break; + + } +} + + +///////////////////////////////// +// Basic Collision by Dreamer3 // +///////////////////////////////// +bool Arduboy::collide(Point point, Rect rect) +{ + // does point fall within the bounds of rect + return ((point.x >= rect.x) && (point.x < rect.x + rect.width) && + (point.y >= rect.y) && (point.y < rect.y + rect.height)); +} + +bool Arduboy::collide(Rect rect1, Rect rect2) +{ + return !( rect2.x >= rect1.x + rect1.width || + rect2.x + rect2.width <= rect1.x || + rect2.y >= rect1.y + rect1.height || + rect2.y + rect2.height <= rect1.y); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core.h Tue Dec 27 11:27:14 2016 +0000 @@ -0,0 +1,332 @@ +#ifndef FABOY_BLE_H +#define FABOY_BLE_H + +#include "Adafruit_SSD1306.h" +#include <stdint.h> + +// main hardware compile flags + +#if !defined(FABOY_BLE) + #define FABOY_BLE //< compile for the ble board +#endif + +// 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 needed for audio + +#define PIXEL_SAFE_MODE +#define SAFE_MODE + +#ifdef FABOY_BLE +#define SCL p12 +#define SDA p11 +#elif defined(FABOY_DEV) +#define CS 19 +#define DC 8 +#define RST 18 +#else +#define CS 12 +#define DC 4 +#define RST 6 +#endif + +#ifdef FABOY_BLE +#define RED_LED p17 +#define GREEN_LED p18 +#define BLUE_LED p19 +//#define TX_LED p20 +//#define RX_LED p20 + +#define PIN_LEFT_BUTTON p13 +#define PIN_RIGHT_BUTTON p14 +#define PIN_UP_BUTTON p15 +#define PIN_DOWN_BUTTON p16 +#define PIN_A_BUTTON p16 +#define PIN_B_BUTTON p16 + +#define LEFT_BUTTON _BV(0) +#define RIGHT_BUTTON _BV(1) +#define UP_BUTTON _BV(2) +#define DOWN_BUTTON _BV(3) +#define A_BUTTON _BV(4) +#define B_BUTTON _BV(5) + +#define PIN_SPEAKER_1 p20 + +#elif defined(FABOY_DEV) +#define LEFT_BUTTON _BV(5) +#define RIGHT_BUTTON _BV(0) +#define UP_BUTTON _BV(4) +#define DOWN_BUTTON _BV(1) +#define A_BUTTON _BV(3) +#define B_BUTTON _BV(2) + +#define PIN_LEFT_BUTTON A2 +#define PIN_RIGHT_BUTTON A5 +#define PIN_UP_BUTTON A3 +#define PIN_DOWN_BUTTON A4 +#define PIN_A_BUTTON 0 +#define PIN_B_BUTTON 1 + +#define RED_LED 10 +#define GREEN_LED 11 +#define BLUE_LED 9 +#define TX_LED 7 +#define RX_LED 7 + +#define PIN_SPEAKER_1 5 +#define PIN_SPEAKER_2 13 + +#else +#error no platform defined ! +#endif + +#define WIDTH 128 +#define HEIGHT 64 + +#define WHITE 1 +#define BLACK 0 + +#define COLUMN_ADDRESS_END (WIDTH - 1) & 0x7F +#define PAGE_ADDRESS_END ((HEIGHT/8)-1) & 0x07 + +#define SPRITE_MASKED 1 +#define SPRITE_UNMASKED 2 +#define SPRITE_OVERWRITE 2 +#define SPRITE_PLUS_MASK 3 +#define SPRITE_IS_MASK 250 +#define SPRITE_IS_MASK_ERASE 251 +#define SPRITE_AUTO_MODE 255 + +class ArduboyAudio +{ + public: + void setup(); + void on(); + void off(); + void saveOnOff(); + bool enabled(); + void tone(unsigned int frequency, unsigned long duration); + + protected: + bool audio_enabled; +}; + +struct Rect +{ + public: + int x; + int y; + uint8_t width; + int height; +}; + +struct Point +{ + public: + int x; + int y; +}; + +class Arduboy : public Adafruit_SSD1306_I2c +{ + public: + Arduboy(); +// void LCDDataMode(); +// void LCDCommandMode(); + + I2C i2c; + + uint8_t getInput(); + void poll(); + bool pressed(uint8_t buttons); + bool notPressed(uint8_t buttons); + bool justPressed(uint8_t buttons); + void start(); + void saveMuchPower(); + void idle(); + void blank(); + void clearDisplay(); + void display(); +// void drawScreen(const unsigned char *image); +// void drawScreen(unsigned char image[]); +// void drawPixel(int x, int y, uint8_t color); +// uint8_t getPixel(uint8_t x, uint8_t y); +// void drawCircle(int16_t x0, int16_t y0, int16_t r, uint8_t color); +// void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint8_t color); +// void fillCircle(int16_t x0, int16_t y0, int16_t r, uint8_t color); +// void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint8_t color); +// void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t color); +// void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t color); +// void drawFastVLine(int16_t x, int16_t y, int16_t h, uint8_t color); +// void drawFastHLine(int16_t x, int16_t y, int16_t w, uint8_t color); +// void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t color); +// void fillScreen(uint8_t color); +// void drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint8_t color); +// void fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint8_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint8_t color); + void drawCompressed(int16_t sx, int16_t sy, const uint8_t *bitmap, uint8_t color); + unsigned char* getBuffer(); + uint8_t width(); + uint8_t height(); + virtual size_t write(uint8_t); + void initRandomSeed(); + void swap(int16_t& a, int16_t& b); + + //ArduboyTunes tunes; + ArduboyAudio audio; + + void setFrameRate(uint8_t rate); + bool nextFrame(); + bool everyXFrames(uint8_t frames); + int cpuLoad(); + uint8_t frameRate ; + uint16_t frameCount ; + uint8_t eachFrameMillis ; + long lastFrameStart; + long nextFrameStart ; + bool post_render; + uint8_t lastFrameDurationMs; + + bool static collide(Point point, Rect rect); + bool static collide(Rect rect, Rect rect2); + + private: + static unsigned char sBuffer[(HEIGHT * WIDTH) / 8]; + + void bootLCD() __attribute__((always_inline)); + void safeMode() __attribute__((always_inline)); + void slowCPU() __attribute__((always_inline)); + uint8_t readCapacitivePin(int pinToMeasure); + uint8_t readCapXtal(int pinToMeasure); + uint16_t rawADC(char adc_bits); + volatile uint8_t *mosiport, *clkport, *csport, *dcport; + uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask; + uint8_t currentButtonState ; + uint8_t previousButtonState ; +}; + + +///////////////////////////////// +// sprites by Dreamer3 // +///////////////////////////////// +class Sprites +{ + public: + Sprites(Arduboy &arduboy); + + // drawExternalMask() uses a separate mask to mask image (MASKED) + // + // image mask before after + // + // ..... .OOO. ..... ..... + // ..O.. OOOOO ..... ..O.. + // OO.OO OO.OO ..... OO.OO + // ..O.. OOOOO ..... ..O.. + // ..... .OOO. ..... ..... + // + // image mask before after + // + // ..... .OOO. OOOOO O...O + // ..O.. OOOOO OOOOO ..O.. + // OO.OO OOOOO OOOOO OO.OO + // ..O.. OOOOO OOOOO ..O.. + // ..... .OOO. OOOOO O...O + // + void drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap, const uint8_t *mask, uint8_t frame, uint8_t mask_frame); + + // drawPlusMask has the same behavior as drawExternalMask except the + // data is arranged in byte tuples interposing the mask right along + // with the image data (SPRITE_PLUS_MASK) + // + // typical image data (8 bytes): + // [I][I][I][I][I][I][I][I] + // + // interposed image/mask data (8 byes): + // [I][M][I][M][I][M][I][M] + // + // The byte order does not change, just for every image byte you mix + // in it's matching mask byte. Softare tools make easy work of this. + // + // See: https://github.com/yyyc514/img2ard + void drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); + + // drawOverwrite() replaces the existing content completely (UNMASKED) + // + // image before after + // + // ..... ..... ..... + // ..O.. ..... ..O.. + // OO.OO ..... OO.OO + // ..O.. ..... ..O.. + // ..... ..... ..... + // + // image before after + // + // ..... OOOOO ..... + // ..O.. OOOOO ..O.. + // OO.OO OOOOO OO.OO + // ..O.. OOOOO ..O.. + // ..... OOOOO ..... + // + void drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); + + // drawErase() removes the lit pixels in the image from the display + // (SPRITE_IS_MASK_ERASE) + // + // image before after + // + // ..... ..... ..... + // ..O.. ..... ..... + // OO.OO ..... ..... + // ..O.. ..... ..... + // ..... ..... ..... + // + // image before after + // + // ..... OOOOO OOOOO + // ..O.. OOOOO OO.OO + // OO.OO OOOOO ..O.. + // ..O.. OOOOO OO.OO + // ..... OOOOO OOOOO + // + + void drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); + + // drawSelfMasked() only draws lit pixels, black pixels in + // your image are treated as "transparent" (SPRITE_IS_MASK) + // + // image before after + // + // ..... ..... ..... + // ..O.. ..... ..O.. + // OO.OO ..... OO.OO + // ..O.. ..... ..O.. + // ..... ..... ..... + // + // image before after + // + // ..... OOOOO OOOOO (no change because all pixels were + // ..O.. OOOOO OOOOO already white) + // OO.OO OOOOO OOOOO + // ..O.. OOOOO OOOOO + // ..... OOOOO OOOOO + // + void drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame); + // master function, needs to be abstracted into sep function for + // every render type + void draw(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame, const uint8_t *mask, uint8_t sprite_frame, uint8_t drawMode); + void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, const uint8_t *mask, int8_t w, int8_t h, uint8_t draw_mode); + + private: + + Arduboy *arduboy; + unsigned char *sBuffer; +}; + +#endif
Binary file img/uvision.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Dec 27 11:27:14 2016 +0000 @@ -0,0 +1,17 @@ +#include "mbed.h" +#include "core.h" + +DigitalOut led1(LED1); + +// main() runs in its own thread in the OS +// (note the calls to Thread::wait below for delays) +int main() { + + Arduboy arduboy; + + while (true) { + led1 = !led1; + Thread::wait(500); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Tue Dec 27 11:27:14 2016 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#c3b9436e12610acaab723f730ab15b48a539a5ac