Прием по mailbox закодированного сообщения для включения светодиодов¶
От некоторого устройства в сети должен приходить закодированный байт следующей структуры:
· 7-5 бит - команда (001 - установить значение светодиодов)
· 4-3 бит - незначащие биты
· 2-0 бит - вкл/выкл красный, зеленый и синий светодиод соответственно
Например, 0b00100111 (0b - обозначение двоичной системы, 001 - биты 7-5, т.е команда установки светодиодов; 00 - биты 4-3, незначащие биты; 111 - биты 2-0, включить все светодиоды)
После приема этой структуры как единого байта, его необходимо раскодировать в несколько переменных с помощью битовых сдвигов.
Битовый сдвиг - это операция, как понятно из названия, сдвигающая все биты числа в одну из сторон: вправо или влево. Например, если число 1 (0b00000001) сдвинуть на 2 влево, то получится число 4 (0b00000100). В используемой версии луа нет такой математической операции, поэтому необхдимо написать функции, добавляющие такой функционал.
Функция сдвига влево:
function lshift(x, by)
return x * 2 ^ by
end
Функция сдвига вправо:
function rshift(x, by)
return math.floor(x / 2 ^ by)
end
В обоих функциях первым указывается число, биты которого подвергаются сдвигу, а вторым параметром указывается на сколько бит будет произведен сдвиг.
Однако одних лишь двигов недостаточно, чтобы раскодировать и правильно интерпретировать полученное сообщение, поскольку когда, например, мы смотрим на биты 2-0, то нужно не забывать, что значения есть еще и в битах 7-5, т.е. нельзя сообщение сравнивать кокнретными числами, когда оно «в сборе», нужно как-то вычленять биты 7-5, когда проверяется команда, биты 2-0, когда проверяются значения светодиодов…
Для этого используется еще одна битовая операция - Битовое И. Эта операция оперирует двумя числами: изменяемым числом и маской. Изменяемое число - это то число, в котором мы хотим вычленить некоторые биты, а маска - это маркер, который показывает, какие позиции мы хотим рассматривать, а какаие отбросить.
Например, у нас есть следующее двоичное число - 0b00100101, и мы хотим оставить в нем только последние 3 бита (отсчет ведется справа). Поэтому мы должны взять следующую двоичную маску - 0b11100000. И после применения «Битового И» у нас останется число 0b00100000.
Ну а теперь, чтобы полученное число было легче обрабатывать, можно все его биты сдвинуть на 5 вправо: 0b00100000 -> 0b00000001.
Функция, реализующая операцию Побитовое И:
function BitAND(a,b)
local p,c=1,0
while a>0 and b>0 do
local ra,rb=a%2,b%2
if ra+rb>1 then c=c+p end
a,b,p=(a-ra)/2,(b-rb)/2,p*2
end
return c
end
Затем, если командой является установка значений светодиодов, то происходит соответсвующее действие.
-- Simplification and caching table.unpack calls
local unpack = table.unpack
-- Base pcb number of RGB LEDs
local ledNumber = 4
-- RGB LED control port initialize
local leds = Ledbar.new(ledNumber)
-- Function changes color on all LEDs
local function changeColor(color)
-- Changing color on each LED one after another
for i=0, ledNumber - 1, 1 do
leds:set(i, unpack(color))
end
end
-- Table of colors in RGB form for changeColor function
local colors = {
{1, 0, 0}, -- r
{0, 1, 0}, -- g
{0, 0, 1}, -- b
{1, 1, 1}, -- w
}
-- Event processing function called automatically by autopilot
function callback(event)
end
function lshift(x, by)
return x * 2 ^ by
end
function rshift(x, by)
return math.floor(x / 2 ^ by)
end
function BitAND(a,b)
local p,c=1,0
while a>0 and b>0 do
local ra,rb=a%2,b%2
if ra+rb>1 then c=c+p end
a,b,p=(a-ra)/2,(b-rb)/2,p*2
end
return c
end
mailbox.setHullNumber(45)
while(true)
do
hull, msg = mailbox.receive(true)
cmd = rshift(BitAND(tonumber(msg), 224), 5)
if(msg=="0") then
changeColor({0,0,0})
break
end
if(cmd == 1) then
local r = rshift(BitAND(tonumber(msg), 4), 2)
local g = rshift(BitAND(tonumber(msg), 2), 1)
local b = BitAND(tonumber(msg), 1)
changeColor({r,g,b})
end