diff --git a/display.h b/display.h index 3c9c8f9..f932f3f 100644 --- a/display.h +++ b/display.h @@ -11,19 +11,19 @@ class DisplayBuffer { return row * 192 + col; } - bool getPixel(byte col, byte row) { + inline bool getPixel(byte col, byte row) const { int offset = pixelOffset(col, row); - return (buf[offset / 8] & (1 << (offset % 8))) > 0; + return (buf[offset / 8] & (0b10000000 >> (offset % 8))) > 0; } void setPixelOn(byte col, byte row) { int offset = pixelOffset(col, row); - buf[offset / 8] |= 1 << (offset % 8); + buf[offset / 8] |= (0b10000000 >> (offset % 8)); } void setPixelOff(byte col, byte row) { int offset = pixelOffset(col, row); - buf[offset / 8] &= ~(1 << (offset % 8)); + buf[offset / 8] &= ~(0b10000000 >> (offset % 8)); } void setColumn(byte row, unsigned int columnData) { diff --git a/font.h b/font.h index e7cae07..7b014b6 100644 --- a/font.h +++ b/font.h @@ -1,3 +1,5 @@ +namespace font { + struct FontInfo { byte height, width, first, count; prog_uint8_t* image; @@ -79,4 +81,6 @@ unsigned int charColumn(byte column) { bits += fontInfo.width; } return result; +} + } \ No newline at end of file diff --git a/push_image.py b/push_image.py index 6dbd00f..37f45b2 100644 --- a/push_image.py +++ b/push_image.py @@ -1,29 +1,73 @@ +from __future__ import with_statement, division import serial import sys from time import sleep -from PIL import Image, ImageDraw +from PIL import Image, ImageDraw, ImageEnhance + magic_bytes = [159, 170, 85, 241] +display_size = (192, 14) + +def pan_image(img): + x_diff = max(0, img.size[0] - display_size[0]) + y_diff = max(0, img.size[1] - display_size[1]) + max_diff = max(x_diff, y_diff) + if max_diff < 1: + yield img + raise StopIteration -def push_image(img): - for c in reversed(img.tostring()[:336]): + x_step = x_diff / max_diff + y_step = y_diff / max_diff + x = y = 0 + for i in range(max_diff): + x += x_step + y += y_step + yield img.crop(map(int, (x, y, x+display_size[0], y+display_size[1]))) + +def push_image(ser, img): + ser.write(''.join(chr(x) for x in magic_bytes)) + ser.write(chr(100)) + # sleep(0.1) + assert len(img.convert('1').tostring()) + for c in img.convert('1').tostring()[:336]: ser.write(c) + # sleep(0.01) + sleep(1/(115200/9)) + +def prepare_output(img): + img = img.convert('L') + img = Image.eval(img, lambda x: 255 if x > 200 else 0) + return img.convert('1') + +def wait(ser): + for i in range(5): + if ser.readline(): + return # 115200 if __name__ == '__main__': - ser = serial.Serial(sys.argv[1], baudrate=115200) - sleep(5) - print ser.readline() - # ser.write(''.join(chr(x) for x in magic_bytes)) - # ser.write(chr(10)) - - img = Image.new('1', (192, 14), 0) - draw = ImageDraw.Draw(img) - for y in range(0, 14, 2): - draw.line((0, y, 191, y), fill=1) - for c in img.tostring(): - ser.write(c) - sleep(2) - sleep(2) + ser = serial.Serial(sys.argv[1], baudrate=115200, timeout=1) + wait(ser) + img = Image.open(sys.argv[2]) + img.thumbnail((display_size[0], display_size[0])) + for i, img in enumerate(pan_image(img)): + push_image(ser, prepare_output(img)) + prepare_output(img).save('/tmp/frames/frame-%03d.gif' % i) + sleep(1/25) + # print '.' + # sleep(0.1) + + sleep(500) + # print ser.readline() + # # ser.write(''.join(chr(x) for x in magic_bytes)) + # # ser.write(chr(10)) + # img = Image.new('1', (192, 14), 0) + # draw = ImageDraw.Draw(img) + # for y in range(0, 14, 2): + # draw.line((0, y, 191, y), fill=1) + # for c in img.tostring(): + # ser.write(c) + # sleep(2) + # sleep(2) diff --git a/serial.h b/serial.h index 85e3c0e..4299ef8 100644 --- a/serial.h +++ b/serial.h @@ -5,13 +5,15 @@ static const byte MAGIC_BYTES[4] = {159, 170, 85, 241}; -#define SERIAL_WAIT_AVAILABLE() while (Serial.available() < 0) {} +#define SERIAL_WAIT_AVAILABLE() while (Serial.available() < 1) {} byte seekToFrameStart() { while (1) { SERIAL_WAIT_AVAILABLE(); // read till first magic byte - while (Serial.read() != MAGIC_BYTES[0]) {} + while (Serial.read() != MAGIC_BYTES[0]) { + SERIAL_WAIT_AVAILABLE(); + } // start again (continue) if other three bytes do not match SERIAL_WAIT_AVAILABLE(); if (Serial.read() != MAGIC_BYTES[1]) { continue; } @@ -27,11 +29,12 @@ byte seekToFrameStart() { byte updateDisplayFromSerial(DisplayBuffer *display) { seekToFrameStart(); int bytesRead = 0; - while (bytesRead < display->size) { + while (bytesRead <= display->size) { SERIAL_WAIT_AVAILABLE(); - display->buf[bytesRead] = (byte)Serial.read(); + display->buf[bytesRead] = Serial.read(); bytesRead += 1; } + return 0; } #endif \ No newline at end of file diff --git a/ticker.h b/ticker.h index b29f053..f4e3050 100644 --- a/ticker.h +++ b/ticker.h @@ -66,7 +66,7 @@ static void shiftBlank(byte columns=1) { static void shiftInColumn(unsigned int data) { for (int row = 0; row < 14; row++) { addressRow(row); - if ((data & (1<<(13-row))) > 0) { + if ((data & (1 << row)) > 0) { ledOn(); } else { ledOff(); @@ -163,13 +163,18 @@ class Ticker { } // shift current LED row by ``columns`` to left - static void shiftCurrentRow(byte columns=1) { + static void shiftCurrentRow(byte columns) { for (byte i = 0; i < columns; i++) { PORTD &= ~(1 << 7); PORTD |= 1 << 7; } } + static inline void shiftCurrentRow() { + PORTD &= ~(1 << 7); + PORTD |= 1 << 7; + } + static inline void ledPowerOn() { PORTD |= 1 << 2; } @@ -178,7 +183,24 @@ class Ticker { PORTD &= ~(1 << 2); } - void shiftInDisplayBuffer(DisplayBuffer *displayBuffer) { + static void shiftInColumn(unsigned int data) { + for (int row = 0; row < 14; row++) { + if ((data & (1 << row)) > 0) { + pushOnLed(row); + } else { + pushOffLed(row); + } + } + } + static void shiftBlank(byte columns=1) { + for (int row = 0; row < 14; row++) { + for (int i = 0; i < columns; i++) { + pushOffLed(row); + } + } + } + + static void shiftInDisplayBuffer(const DisplayBuffer *displayBuffer) { for (int row = 0; row < height; ++row) { addressRow(row); for (int col = 0; col < width; ++col) { @@ -192,6 +214,35 @@ class Ticker { } } + static void shiftInDisplayBufferRaw(DisplayBuffer *displayBuffer) { + // shift in display buffer by direct access to the buffer + byte currentByte; + for (int row = 0; row < height; ++row) { + addressRow(row); + for (int col = 0; col < width/8; ++col) { + currentByte = displayBuffer->buf[row * (192/8) + col]; + + // manual loop unrolling + (0b10000000 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + (0b01000000 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + (0b00100000 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + (0b00010000 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + (0b00001000 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + (0b00000100 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + (0b00000010 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + (0b00000001 & currentByte) ? ledPowerOn() : ledPowerOff(); + shiftCurrentRow(); + } + } + } + void shiftInRandom() { for (int row = 0; row < height; ++row) { addressRow(row); @@ -206,6 +257,40 @@ class Ticker { } } + void shiftChar(char c, int colDelay=30) { + font::setChar(c); + for (int i = 0; i < font::charInfo.width; i++) { + shiftInColumn(font::charColumn(i)); + delay(colDelay); + } + shiftBlank(); + delay(colDelay); + } + + void shiftString(char *string, int colDelay=30) { + while (*string != 0) { + if (*string == '\t') { + for (int i = 0; i < 50; ++i) { + shiftBlank(); + delay(colDelay); + } + } else if (*string == ' ') { + for (int i = 0; i < 5; ++i) { + shiftBlank(); + delay(colDelay); + } + } else { + shiftChar(*string, colDelay); + } + string++; + } + + for (int i = 0; i < 192; ++i) { + shiftBlank(); + delay(colDelay); + } + } + }; @@ -218,29 +303,4 @@ void blink(const Ticker *ticker) { ticker->display(50); } -void shiftChar(char c, int colDelay=30) { - setChar(c); - for (int i = 0; i < charInfo.width; i++) { - shiftInColumn(charColumn(i)); - display(colDelay); - } - shiftBlank(); - display(colDelay); -} - -char string[] = "Kreativitaet trifft Technik!"; - -void shiftString(char *string) { - int len = strlen(string); - while (*string != 0) { - shiftChar(*string, 30); - string++; - } - - for (int i = 0; i < (192 - len); ++i) { - shiftBlank(); - display(30); - } -} - #endif diff --git a/ticker.ino b/ticker.ino index 3fc778d..b4064d6 100644 --- a/ticker.ino +++ b/ticker.ino @@ -18,27 +18,23 @@ void blink(int msDelay) { void setup() { Serial.begin(115200); - Serial.println("Hello!"); + Serial.write('?'); ticker.initPins(); pinMode(13, OUTPUT); - setFont(font_helvR10); - blink(1000); + font::setFont(font_helvR10); } -void fillBufferRandom(DisplayBuffer *buffer) { - int bytesRead = 0; - while (bytesRead < buffer->size) { - if (random(5) == 0) { - buffer->buf[bytesRead] = 170; - } else { - buffer->buf[bytesRead] = 0; - } - bytesRead += 1; - } -} +char *msg = { + "Sommer im Quartier." + "\tKreativitaet trifft Technik!" + "\tDer Oldenburger Hackspace stellt sich vor." + "\tBasteln, loeten und diskutieren; 3D-Drucker, Styrophorschneider, LED-Cubes," + " Klackerlaken, Arduino, CNC-Fraese, Terminals" + "\tDer Space ist offen! Kommt einfach rein und Treppe hoch." +}; void loop() { - updateDisplayFromSerial(&buffer); - ticker.shiftInDisplayBuffer(&buffer); - // delay(1000); + ticker.shiftString(msg, 20); + // updateDisplayFromSerial(&buffer); + // ticker.shiftInDisplayBufferRaw(&buffer); }