On the train back from NYC to Pittsburgh, I got the idea to hook up the LoL Shield directly to my computer, so that I could develop animations for it using a desktop graphics program. Using Jay Clegg’s Video Peggy project as a starting point, I wrote up a little framebuffer sketch for the Arduino, along with some Processing code to grab a region of the computer screen, scale it, and send it over to the LoL Shield for display. Pretty simple, but could be useful. Source code is after the break. A version of this project might be included with the next LoL Shield library release.
import processing.serial.*; LolShieldBuffer lolShield; PFont fontA; void setup() { size(14, 9); // Load the font. Fonts must be placed within the data // directory of your sketch. A font must first be created // using the 'Create Font...' option in the Tools menu. fontA = loadFont("LucidaSans-9.vlw"); // Set the font and its size (in units of pixels) textFont(fontA, 9); // I know that the first port in the serial list on my mac // is always my FTDI adaptor, so I open Serial.list()[0]. // On Windows machines, this generally opens COM1. // Open whatever port is the one you're using. String portName = Serial.list()[0]; print(portName); lolShield = new LolShieldBuffer(this, portName); } int i = 0; void draw() { background(0); fill(255); text("The time is now " + hour() + ":" + minute(), i, 8); // lolShield.sendWindow(mouseX,mouseY, 14, 9); lolShield.sendWindow(0,0, 14, 9); i--; if (i < -130) {i = 14;} delay(50); } |
You want to put this code on your Arduino:
#include "Charliplexing.h" #include "Font.h" #include "WProgram.h" // Inspired by Video Peggy: // http://www.planetclegg.com/projects/QC-Peggy.html void setup() // run once, when the sketch starts { Serial.begin(115200); LedSign::Init(DOUBLE_BUFFER); // LedSign::Init(); } int state = 0; int counter = 0; const uint8_t DISP_BUFFER_SIZE = 9*2; void loop() // run over and over again { while( !Serial.available()) {} uint8_t c = Serial.read(); // very simple state machine to look for 6 byte start of frame // marker and copy bytes that follow into buffer if (state < 6) { // must wait for 0xdeadbeef to start frame. // note, I look for two more bytes after that, but // they are reserved for future use. if (state == 0 && c == 0x12) state++; else if (state ==1 && c == 0x34) state++; else if (state ==2 && c == 0x56) state++; else if (state ==3 && c == 0x78) state++; else if (state ==4 && c == 0x1) state++; else if (state ==5) // dont care what 6th byte is { state++; counter = 0; } else state = 0; // error: reset to look for start of frame } else { // inside of a frame, so write to the buffer uint8_t row = counter / 2; uint8_t col = (counter % 2)*8; uint8_t length = (col==0?8:6); for (uint8_t colOffset = 0; colOffset < length ; colOffset++ ) { LedSign::Set(col+colOffset, row, c >> (7 - colOffset) & 1); } counter++; if (counter >= DISP_BUFFER_SIZE) { // buffer filled, so reset everything to wait for next frame state = 0; LedSign::Flip(); } } } |
Put this code in a new tab in your Processing project, called LolShieldBuffer:
import processing.serial.*; class LolShieldBuffer { Serial serial; int ledWidth = 14; int ledHeight = 9; int ledFrameSize = 9*2; LolShieldBuffer(PApplet parent, String portName) { serial = new Serial(parent, portName, 115200); } void sendWindow(int x, int y, int w, int h) { PImage img = get(x, y, w, h); // img.resize(ledWidth, ledHeight); char[] frame = new char[ledFrameSize]; // Grab a 14x9 window for (int row = 0; row < ledHeight; row++) { char buf = 0; for (int col = 0; col < 8; col++) { buf = (char)(buf << 1); buf |= (brightness(img.pixels[row*ledWidth+col])>127) ? 1:0; } frame[row*2] = buf; for (int col = 0; col < 6; col++) { buf = (char)(buf << 1); buf |= (brightness(img.pixels[row*ledWidth+8+col])>127) ? 1:0; } buf = (char)(buf << 2); frame[row*2+1] = buf; } sendFrame(frame); } void sendFrame(char[] frame) { byte[] magicNumber = {0x12, 0x34, 0x56, 0x78, 0x1, 0x0}; serial.write(magicNumber); // TODO: Drop 9*2 magic number for(int index = 0; index < ledFrameSize; index++) { serial.write(frame[index]); } } } |
Pingback: LoL Shield Projects
Pingback: LoL Horse! « adafruit industries blog