Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Controlling the Raspberry Pi 3 Model B Sense HAT 8×8 LED matrix from Lua 5.3
local M = {_TYPE='module', _NAME='sensehat_pixels', _VERSION='0.0.1'}
-- Sleep this thread
function sleep(n)
io.popen("sleep " .. tostring(n)):read()
end
-- Split a string into lines
function lines(str)
local t = {}
local function helper(line)
table.insert(t, line)
return ""
end
helper(str:gsub("(.-)\r?\n", helper))
return t
end
-- Does file $path exist?
function file_exists(path)
local fd = io.open(path, "r")
if fd ~= nil then
io.close(fd)
return true
else
return false
end
end
-- List files and folders in $path
function list_directory(path)
return io.popen([[ls -1 ]] .. path):lines()
end
-- Find sense hat device
function sense_hat_device_path()
local target_name = "RPi-Sense FB"
for node in list_directory("/sys/class/graphics") do
if string.sub(node, 1, 2) == "fb" then
local name_path = "/sys/class/graphics/" .. node .. "/name"
if file_exists(name_path) then
local fd = io.open(name_path, "r")
local content = fd:read()
fd:close()
if content == target_name then
return "/dev/" .. node
end
end
end
end
end
-- Represent a given color as RGB565 byte string
function color_to_bin(rgb)
if rgb:len() ~= 6 then
error("color " .. rgb .. " is not a 6-digit hex color")
end
local r = tonumber(rgb:sub(1, 2), 16)
local g = tonumber(rgb:sub(3, 4), 16)
local b = tonumber(rgb:sub(5, 6), 16)
r = (r >> 3) & 0x1F
g = (g >> 2) & 0x3F
b = (b >> 3) & 0x1F
local comb = (r << 11) + (g << 5) + b
return string.pack("H", comb)
end
-- Given a string with 8 lines with length 8 each,
-- each byte represents a color. The byte to color
-- map is given by the second argument.
function pixel_from_picture(pic, map)
local data = {}
local lineno = 1
for _, line in pairs(lines(pic)) do
if line:len() == 0 then
goto next
end
if line:len() ~= 8 then
error("line must have length 8")
end
for i = 1, #line do
local total_index = (lineno - 1) * 8 + i
if map[line:sub(i, i)] == nil then
error("character '" .. line:sub(i, i) .. "' could not be mapped to color")
end
data[total_index] = map[line:sub(i, i)]
end
lineno = lineno + 1
::next::
end
return data
end
function default_colors()
local color_table = {
["white"] = "FFFFFF", ["silver"] = "C0C0C0", ["gray"] = "808080",
["black"] = "000000", ["red"] = "FF0000", ["maroon"] = "800000",
["yellow"] = "FFFF00", ["olive"] = "808000", ["lime"] = "00FF00",
["green"] = "008000", ["aqua"] = "00FFFF", ["teal"] = "008080",
["blue"] = "0000FF", ["navy"] = "000080", ["fuchsia"] = "FF00FF",
["purple"] = "800080"
}
color_table[" "] = color_table["black"]
color_table["X"] = color_table["teal"]
color_table["0"] = color_table["white"]
color_table["1"] = color_table["blue"]
return color_table
end
function letter_pics()
return {
["E"] = [[
000000
000000
00
000000
000000
00
000000
000000
]],
["H"] = [[
00 00
00 00
00 00
000000
000000
00 00
00 00
00 00
]],
["I"] = [[
00
00
00
00
00
00
00
00
]],
["L"] = [[
00
00
00
00
00
00
000000
000000
]],
["O"] = [[
0000
000000
00 00
00 00
00 00
00 00
000000
0000
]],
}
end
-- Given a map with indices 1..64, each index
-- is mapped to a color to be set on raspberry
-- pi's sense hat
function set_pixels(pixels)
local fd = io.open(sense_hat_device_path(), "w")
for idx, color in pairs(pixels) do
fd:seek("set", 2 * (idx - 1))
fd:write(color_to_bin(color))
end
end
-- clear pixels on the RPi Sense hat
function clear_pixels()
local color_table = {}
for i = 1, 64 do
color_table[i] = "000000"
end
set_pixels(color_table)
end
local text = "HELLO"
local pics = letter_pics()
clear_pixels()
for i = 1, #text do
sleep(2)
print(text:sub(i, i))
local c = pixel_from_picture(pics[text:sub(i, i)], default_colors())
set_pixels(c)
end
sleep(2)
--clear_pixels()
colortable = pixel_from_picture([[
00 00
00 00
00 00
00 00
0000
]], default_colors())
set_pixels(colortable)
clear_pixels()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment