Skip to content

Instantly share code, notes, and snippets.

@smittytone
Last active August 29, 2015 13:57
Show Gist options
  • Save smittytone/9548708 to your computer and use it in GitHub Desktop.
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
// 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);
// 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