Last active
August 29, 2015 13:57
-
-
Save smittytone/9548708 to your computer and use it in GitHub Desktop.
Display a side-scrolling message sent over the Internet to an Imp connected to an LED matrix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Log the URLs we need | |
server.log("Print message x: " + http.agenturl() + "?message=x&inv=1"); | |
function requestHandler(request, response) | |
{ | |
try | |
{ | |
// check if the user sent 'print' as a query parameter | |
if ("inv" in request.query) device.send("ts.led.inverse", request.query.inv); | |
if ("message" in request.query) device.send("ts.led.message", request.query.message); | |
response.send(200, ("Message \"" + request.query.message + "\" sent.\nAwaiting new message...")); | |
} | |
catch (ex) | |
{ | |
response.send(500, "Internal Server Error: " + ex); | |
} | |
} | |
function nop(bool_value) | |
{ | |
// Respond to a Device-sent 'ack' notification | |
if (bool_value) server.log("Message displayed. Awaiting new message..."); | |
} | |
// Register the HTTP handler | |
http.onrequest(requestHandler); | |
// Listen for a notification named 'ack' from the Device | |
device.on("ack", nop); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// LED Matrix Scrolling Display 1.1 by Tony Smith | |
// Based on code from LinkSprite http://linksprite.com/wiki/index.php5?title=LED_Matrix_Kit | |
// Additional code copyright © Electric Imp, 2014 | |
// Set the number of characters in your character set | |
const alpha_count = 143; | |
local inv_video = 0; | |
// Create recognisable aliases for the three Imp GPIO pins you will be using | |
// Note: the aliases are global variables, so stored in a Squirrel table | |
// Hence the <- assignment operator, not = | |
led_clk <- hardware.pin9; | |
led_cs <- hardware.pin8; | |
led_din <- hardware.pin7; | |
// Set these pins as digital outputs | |
led_clk.configure(DIGITAL_OUT); | |
led_cs.configure(DIGITAL_OUT); | |
led_din.configure(DIGITAL_OUT); | |
// Establish an array of 8 x 8 character matrices | |
// Have fun making up your own characters! | |
charset <- [ | |
[0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0], // Space - Ascii 32 | |
[0x0,0x10,0x10,0x10,0x10,0x0,0x10,0x0], // ! | |
[0x0,0x24,0x24,0x0,0x0,0x0,0x0,0x0], // ” | |
[0x0,0x24,0x7E,0x24,0x24,0x7E,0x24,0x0], // # | |
[0x0,0x8,0x3E,0x28,0x3E,0xA,0x3E,0x8], // $ | |
[0x0,0x62,0x64,0x8,0x10,0x26,0x46,0x0], // % | |
[0x0,0x10,0x28,0x10,0x2A,0x44,0x3A,0x0], // & | |
[0x0,0x8,0x10,0x0,0x0,0x0,0x0,0x0], // ‘ | |
[0x0,0x4,0x8,0x8,0x8,0x8,0x4,0x0], // ( | |
[0x0,0x20,0x10,0x10,0x10,0x10,0x20,0x0], // ) | |
[0x0,0x0,0x14,0x8,0x3E,0x8,0x14,0x0], // * | |
[0x0,0x0,0x8,0x8,0x3E,0x8,0x8,0x0], // + | |
[0x0,0x0,0x0,0x0,0x0,0x8,0x8,0x10], // , | |
[0x0,0x0,0x0,0x0,0x3E,0x0,0x0,0x0], // - | |
[0x0,0x0,0x0,0x0,0x0,0x18,0x18,0x0], // . | |
[0x0,0x2,0x4,0x8,0x10,0x20,0x40,0x0], // / | |
[0x0,0x3C,0x46,0x4A,0x52,0x62,0x3C,0x0], // 0 - Ascii 48 | |
[0x0,0x30,0x50,0x10,0x10,0x10,0x7C,0x0], // 1 | |
[0x0,0x3C,0x42,0x2,0x3C,0x40,0x7E,0x0], // 2 | |
[0x0,0x3C,0x42,0xC,0x2,0x42,0x3C,0x0], // 3 | |
[0x0,0x8,0x18,0x28,0x48,0x7E,0x8,0x0], // 4 | |
[0x0,0x7E,0x40,0x7C,0x2,0x42,0x3C,0x0], // 5 | |
[0x0,0x3C,0x40,0x7C,0x42,0x42,0x3C,0x0], // 6 | |
[0x0,0x7E,0x2,0x4,0x8,0x10,0x10,0x0], // 7 | |
[0x0,0x3C,0x42,0x3C,0x42,0x42,0x3C,0x0], // 8 | |
[0x0,0x3C,0x42,0x42,0x3E,0x2,0x3C,0x0], // 9 | |
[0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x0], // : - Ascii 58 | |
[0x0,0x0,0x10,0x0,0x0,0x10,0x10,0x20], // ; | |
[0x0,0x0,0x4,0x8,0x10,0x8,0x4,0x0], // < | |
[0x0,0x0,0x0,0x3E,0x0,0x3E,0x0,0x0], // = | |
[0x0,0x0,0x10,0x8,0x4,0x8,0x10,0x0], // > | |
[0x0,0x3C,0x42,0x4,0x8,0x0,0x8,0x0], // ? | |
[0x0,0x3C,0x4A,0x56,0x5E,0x40,0x3C,0x0], // @ | |
[0x0,0x3C,0x42,0x42,0x7E,0x42,0x42,0x0], // A - Ascii 65 | |
[0x0,0x7C,0x42,0x7C,0x42,0x42,0x7C,0x0], // B | |
[0x0,0x3C,0x42,0x40,0x40,0x42,0x3C,0x0], // C | |
[0x0,0x78,0x44,0x42,0x42,0x44,0x78,0x0], // D | |
[0x0,0x7E,0x40,0x7C,0x40,0x40,0x7E,0x0], // E | |
[0x0,0x7E,0x40,0x7C,0x40,0x40,0x40,0x0], // F | |
[0x0,0x3C,0x42,0x40,0x4E,0x42,0x3C,0x0], // G | |
[0x0,0x42,0x42,0x7E,0x42,0x42,0x42,0x0], // H | |
[0x0,0x7C,0x10,0x10,0x10,0x10,0x7C,0x0], // I | |
[0x0,0x2,0x2,0x2,0x2,0x42,0x3C,0x0], // J | |
[0x0,0x44,0x48,0x70,0x48,0x44,0x42,0x0], // K | |
[0x0,0x40,0x40,0x40,0x40,0x40,0x7E,0x0], // L | |
[0x0,0x42,0x66,0x5A,0x42,0x42,0x42,0x0], // M | |
[0x0,0x42,0x62,0x52,0x4A,0x46,0x42,0x0], // N | |
[0x0,0x3C,0x42,0x42,0x42,0x42,0x3C,0x0], // O | |
[0x0,0x7C,0x42,0x42,0x7C,0x40,0x40,0x0], // P | |
[0x0,0x3C,0x42,0x42,0x52,0x4A,0x3C,0x0], // Q | |
[0x0,0x7C,0x42,0x42,0x7C,0x44,0x42,0x0], // R | |
[0x0,0x3C,0x40,0x3C,0x2,0x42,0x3C,0x0], // S | |
[0x0,0x7C,0x10,0x10,0x10,0x10,0x10,0x0], // T | |
[0x0,0x42,0x42,0x42,0x42,0x42,0x3C,0x0], // U | |
[0x0,0x42,0x42,0x42,0x42,0x24,0x18,0x0], // V | |
[0x0,0x42,0x42,0x42,0x42,0x5A,0x24,0x0], // W | |
[0x0,0x42,0x24,0x18,0x18,0x24,0x42,0x0], // X | |
[0x0,0x44,0x28,0x10,0x10,0x10,0x10,0x0], // Y | |
[0x0,0x7E,0x4,0x8,0x10,0x20,0x7E,0x0], // Z - Ascii 90 | |
[0x0,0xE,0x8,0x8,0x8,0x8,0xE,0x0], // [ | |
[0x0,0x0,0x40,0x20,0x10,0x8,0x4,0x0], // \ | |
[0x0,0x70,0x10,0x10,0x10,0x10,0x70,0x0], // ] | |
[0x0,0x10,0x38,0x54,0x10,0x10,0x10,0x0], // ^ | |
[0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xFF], // _ | |
[0x0,0x1C,0x22,0x78,0x20,0x20,0x7E,0x0], // £ | |
[0x0,0x0,0x38,0x4,0x3C,0x44,0x3C,0x0], // a - Ascii 97 | |
[0x0,0x40,0x40,0x78,0x44,0x44,0x78,0x0], // b | |
[0x0,0x0,0x38,0x40,0x40,0x40,0x38,0x0], // c | |
[0x0,0x4,0x4,0x3C,0x44,0x44,0x3C,0x0], // d | |
[0x0,0x0,0x38,0x44,0x78,0x40,0x3C,0x0], // e | |
[0x0,0x30,0x40,0x60,0x40,0x40,0x40,0x0], // f | |
[0x0,0x3C,0x44,0x44,0x3C,0x4,0x38,0x0], // g | |
[0x0,0x40,0x40,0x40,0x78,0x44,0x44,0x0], // h | |
[0x0,0x20,0x0,0x60,0x20,0x20,0x70,0x0], // i | |
[0x0,0x8,0x0,0x8,0x8,0x48,0x30,0x0], // j | |
[0x0,0x40,0x50,0x60,0x60,0x50,0x48,0x0], // k | |
[0x0,0x40,0x40,0x40,0x40,0x40,0x30,0x0], // l | |
[0x0,0x0,0x68,0x54,0x54,0x54,0x54,0x0], // m | |
[0x0,0x0,0x78,0x44,0x44,0x44,0x44,0x0], // n | |
[0x0,0x0,0x38,0x44,0x44,0x44,0x38,0x0], // o | |
[0x0,0x78,0x44,0x44,0x78,0x40,0x40,0x0], // p | |
[0x0,0x3C,0x44,0x44,0x3C,0x4,0x6,0x0], // q | |
[0x0,0x0,0x1C,0x20,0x20,0x20,0x20,0x0], // r | |
[0x0,0x0,0x38,0x40,0x38,0x4,0x78,0x0], // s | |
[0x0,0x20,0x70,0x20,0x20,0x20,0x18,0x0], // t | |
[0x0,0x0,0x44,0x44,0x44,0x44,0x38,0x0], // u | |
[0x0,0x0,0x44,0x44,0x28,0x28,0x10,0x0], // v | |
[0x0,0x0,0x44,0x54,0x54,0x54,0x28,0x0], // w | |
[0x0,0x0,0x44,0x28,0x10,0x28,0x44,0x0], // x | |
[0x0,0x0,0x44,0x44,0x3C,0x4,0x38,0x0], // y | |
[0x0,0x0,0x7C,0x8,0x10,0x20,0x7C,0x0], // z - Ascii 122 | |
[0x0,0xE,0x8,0x30,0x8,0x8,0xE,0x0], // { | |
[0x0,0x8,0x8,0x8,0x8,0x8,0x8,0x0], // | | |
[0x0,0x70,0x10,0xC,0x10,0x10,0x70,0x0], // } | |
[0x0,0x14,0x28,0x0,0x0,0x0,0x0,0x0], // ~ | |
[0x3C,0x42,0x99,0xA1,0xA1,0x99,0x42,0x3C], // © - Ascii 127 | |
[0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF], // Block Graphic 1 | |
[0xF,0xF,0xF,0xF,0xFF,0xFF,0xFF,0xFF], | |
[0xF0,0xF0,0xF0,0xF0,0xFF,0xFF,0xFF,0xFF], | |
[0x0,0x0,0x0,0x0,0xFF,0xFF,0xFF,0xFF], | |
[0xFF,0xFF,0xFF,0xFF,0xF,0xF,0xF,0xF], | |
[0xF,0xF,0xF,0xF,0xF,0xF,0xF,0xF], | |
[0xF0,0xF0,0xF0,0xF0,0xF,0xF,0xF,0xF], | |
[0x0,0x0,0x0,0x0,0xF,0xF,0xF,0xF], | |
[0xFF,0xFF,0xFF,0xFF,0x55,0xAA,0x55,0xAA], | |
[0xAA,0x55,0xAA,0x55,0xFF,0xFF,0xFF,0xFF], | |
[0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55], // Block Graphic 11 | |
[0xFF,0xC3,0xB9,0xB5,0xAD,0x9D,0xC3,0xFF], // 0 Inverse Video | |
[0xFF,0xCF,0xAF,0xEF,0xEF,0xEF,0x83,0xFF], // 1 | |
[0xFF,0xC3,0xBD,0xFD,0xC3,0xBF,0x81,0xFF], // 2 | |
[0xFF,0xC3,0xBD,0xF3,0xFD,0xBD,0xC3,0xFF], // 3 | |
[0xFF,0xF7,0xE7,0xD7,0xB7,0x81,0xF7,0xFF], // 4 | |
[0xFF,0x81,0xBF,0x83,0xFD,0xBD,0xC3,0xFF], // 5 | |
[0xFF,0xC3,0xBF,0x83,0xBD,0xBD,0xC3,0xFF], // 6 | |
[0xFF,0x81,0xFD,0xFB,0xF7,0xEF,0xEF,0xFF], // 7 | |
[0xFF,0xC3,0xBD,0xC3,0xBD,0xBD,0xC3,0xFF], // 8 | |
[0xFF,0xC3,0xBD,0xBD,0xC1,0xFD,0xC3,0xFF], // 9 | |
[0xFF,0xC3,0xBD,0xBD,0x81,0xBD,0xBD,0xFF], // A Inverse Video | |
[0xFF,0x83,0xBD,0x83,0xBD,0xBD,0x83,0xFF], // B | |
[0xFF,0xC3,0xBD,0xBF,0xBF,0xBD,0xC3,0xFF], // C | |
[0xFF,0x87,0xBB,0xBD,0xBD,0xBB,0x87,0xFF], // D | |
[0xFF,0x81,0xBF,0x83,0xBF,0xBF,0x81,0xFF], // E | |
[0xFF,0x81,0xBF,0x83,0xBF,0xBF,0xBF,0xFF], // F | |
[0xFF,0xC3,0xBD,0xBF,0xB1,0xBD,0xC3,0xFF], // G | |
[0xFF,0xBD,0xBD,0x81,0xBD,0xBD,0xBD,0xFF], // H | |
[0xFF,0x83,0xEF,0xEF,0xEF,0xEF,0x83,0xFF], // I | |
[0xFF,0xFD,0xFD,0xFD,0xFD,0xBD,0xC3,0xFF], // J | |
[0xFF,0xBB,0xB7,0x8F,0xB7,0xBB,0xBD,0xFF], // K | |
[0xFF,0xBF,0xBF,0xBF,0xBF,0xBF,0x81,0xFF], // L | |
[0xFF,0xBD,0x99,0xA5,0xBD,0xBD,0xBD,0xFF], // M | |
[0xFF,0xBD,0x9D,0xAD,0xB5,0xB9,0xBD,0xFF], // N | |
[0xFF,0xC3,0xBD,0xBD,0xBD,0xBD,0xC3,0xFF], // O | |
[0xFF,0x83,0xBD,0xBD,0x83,0xBF,0xBF,0xFF], // P | |
[0xFF,0xC3,0xBD,0xBD,0xAD,0xB5,0xC3,0xFF], // Q | |
[0xFF,0x83,0xBD,0xBD,0x83,0xBB,0xBD,0xFF], // R | |
[0xFF,0xC3,0xBF,0xC3,0xFD,0xBD,0xC3,0xFF], // S | |
[0xFF,0x83,0xEF,0xEF,0xEF,0xEF,0xEF,0xFF], // T | |
[0xFF,0xBD,0xBD,0xBD,0xBD,0xBD,0xC3,0xFF], // U | |
[0xFF,0xBD,0xBD,0xBD,0xBD,0xDB,0xE7,0xFF], // V | |
[0xFF,0xBD,0xBD,0xBD,0xBD,0xA5,0xDB,0xFF], // W | |
[0xFF,0xBD,0xDB,0xE7,0xE7,0xDB,0xBD,0xFF], // X | |
[0xFF,0xBB,0xD7,0xEF,0xEF,0xEF,0xEF,0xFF], // Y | |
[0xFF,0x81,0xFB,0xF7,0xEF,0xDF,0x81,0xFF], // Z | |
]; | |
// Define functions | |
function write_LED_byte(byteValue) | |
{ | |
// Writes a single byte of data to the MAX7219 display controller one bit at a time. | |
// Writes data to the LED in the MAX7219’s 16-bit serial format, which puts the | |
// register address in the first eight bits then the data in the second set of eight bits. | |
for (local i = 8 ; i > 0 ; i--) | |
{ | |
led_clk.write(0); | |
led_din.write(byteValue & 0x80); // Extract bit 8 and write it to the LED | |
byteValue = byteValue << 1; // Shift the data bits left by one bit | |
led_clk.write(1); | |
} | |
} | |
function write_LED(RegisterAddress, value) | |
{ | |
// Writes a single value to the MAX7219, preceded by the register | |
// it is being written to | |
led_cs.write(0); | |
write_LED_byte(RegisterAddress); | |
write_LED_byte(value); | |
led_cs.write(1); | |
} | |
function init_LED() | |
{ | |
// Initialise the MAX7219’s parameter registers by writing | |
// the register’s address followed by its 8-bit value | |
// Address and data values from the Maxim Integrated MAX7219 Datasheet: | |
// http://www.maximintegrated.com/datasheet/index.mvp/id/1339 | |
write_LED(0x09, 0x00); // Set MAX7219’s BCD decode mode to ‘none’ | |
write_LED(0x0a, 0x01); // Set MAX7219’s LED intensity to a 2/32 duty cycle | |
write_LED(0x0b, 0x07); // Set MAX7219’s scan limit to all eight LED columns | |
write_LED(0x0c, 0x01); // Set MAX7219’s power mode. 0 = power down, 1 = normal | |
write_LED(0x0f, 0x00); // Set MAX7219’s display test mode off | |
} | |
function delay(value) | |
{ | |
// Delay for ‘value’ milliseconds | |
local a = hardware.millis() + value; | |
while (hardware.millis() < a) | |
{ | |
// NOP | |
} | |
} | |
function shift(value) | |
{ | |
if ((value > 47) && (value < 58)) | |
{ | |
value = value + 91; | |
} | |
else if ((value > 64) && (value < 91)) | |
{ | |
value = value + 84; | |
} | |
else if (value == 32) | |
{ | |
value = 128; | |
} | |
else if ((value > 96) && (value < 123)) | |
{ | |
value = value + 52; | |
} | |
return value; | |
} | |
function rotate_matrix(matrix_in) | |
{ | |
// Rotate the character matrix through 90 degrees anti-clockwise | |
// Used if the LED matrix pins are connected directly to a breadboard | |
local i = 0; | |
local j = 0; | |
local a = 0; | |
local line_value = 0; | |
local matrix_out = [0,0,0,0,0,0,0,0]; | |
for (i = 0 ; i < 8 ; i++) | |
{ | |
line_value = matrix_in[i]; | |
for (j = 7 ; j > -1 ; j--) | |
{ | |
a = (line_value & math.pow(2, j).tointeger()); | |
if (a > 0) matrix_out[7-j] = matrix_out[7-j] + math.pow(2, i).tointeger(); | |
} | |
} | |
return matrix_out; | |
} | |
function display_line(line) | |
{ | |
// Bit-scroll through the characters in the variable ‘line’ | |
local a = 0; | |
local b = 0; | |
local i = 0; | |
local j = 0; | |
local k = 0; | |
local count = 0; | |
local matrix_out = [0,0,0,0,0,0,0,0]; | |
local matrix_one = [0,0,0,0,0,0,0,0]; | |
local matrix_two = [0,0,0,0,0,0,0,0]; | |
foreach (index, character in line) | |
{ | |
// Count the number of characters in the line | |
count++; | |
} | |
if (count == 1) | |
{ | |
count = 2; | |
line = " " + line; | |
} | |
for (k = 0 ; k < (count - 1); k++) | |
{ | |
// Run through the line character by character up to the penultimate character | |
// Get the current character to be displayed and the next character along by | |
// copying them from the character set array | |
a = line[k]; | |
b = line[k + 1]; | |
if (inv_video == 1) | |
{ | |
a = shift(a); | |
b = shift(b); | |
} | |
matrix_one = clone(charset[a - 32]); | |
matrix_two = clone(charset[b - 32]); | |
for (j = 0 ; j < 8 ; j++) | |
{ | |
// We use two character matrices, one on the left and one on the right. | |
// Line by line, we shift the left matrix's bit pattern one bit at a time. | |
// If the seventh bit of a line in the right-hand matrix is set, | |
// we then set bit 0 of the left-hand matrix. | |
// We then shift the right-hand matrix leftward one bit. | |
matrix_out = matrix_one; | |
matrix_out = rotate_matrix(matrix_out); | |
for (i = 0 ; i < 8 ; i++) | |
{ | |
// Write the current character’s matrix | |
write_LED(i+1, matrix_out[i]); | |
// Use the Logical Shift Left operator to move the line one pixel | |
matrix_one[i] = matrix_one[i] << 1; | |
// Move over second matrix by one pixel | |
if ((matrix_two[i] & 128) > 0) | |
{ | |
// If bit 7 of the right-hand character’s line is set, | |
// carry it over to bit 0 of the left-hand character | |
matrix_one[i] = matrix_one[i] | (1 << 0); | |
} | |
// Shift right-hand character line left one pixel | |
matrix_two[i] = (matrix_two[i] << 1); | |
} | |
delay(40); | |
} | |
} | |
// For the final character, we need to perform a last pixel shift to leave | |
// the character completely on the display | |
matrix_out = matrix_one; | |
matrix_out = turn_matrix(matrix_out); | |
for (i = 0 ; i < 8 ; i++) | |
{ | |
write_LED(i+1, matrix_out[i]); | |
matrix_one[i] = matrix_one[i] << 1; | |
if ((matrix_two[i] & 128) > 0) matrix_one[i] = matrix_one[i] | (1 << 0); | |
matrix_two[i] = (matrix_two[i] << 1); | |
} | |
delay(40); | |
} | |
function led_print(message_to_display) | |
{ | |
display_line(message_to_display); | |
agent.send("ack", true); // Send notification name 'ack' to the Agent | |
imp.wakeup(5.0, clear_display); | |
} | |
function vid_set(value) | |
{ | |
if (value == "1" || value == "true") | |
{ | |
inv_video = 1; | |
} | |
else | |
{ | |
inv_video = 0; | |
} | |
} | |
function clear_display() | |
{ | |
display_line(" "); | |
} | |
// Start point for the program | |
init_LED(); // Initialise the LED matrix | |
clear_display(); // Clear the display | |
// Set up agent interaction | |
agent.on("ts.led.message", led_print); // Listen for a notification named 'message' from the Agent | |
agent.on("ts.led.inverse", vid_set); // Listen for inverse video switch |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment