Прием по 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