Сниппет LuaDeb
Lua контроллер Mesecons при игре в серверном варианте не имеет даже самых простых средств отладки. Даже простой вывод функцией print не может быть получен на стороне игрока, потому что код контроллера выполняется на сервере игры. Остаётся только выводить отладочную информацию средствами, доступными в игре - digilines:lcd , digiterms:lcd_monitor
, digistuff:touchscreen
. И все не очень удобно, всё имеет недостатки. Чтобы как-то решить проблему требуется логирование с буферизацией. Собственно, эту задачу и решает данный отладчик - предоставляет унифицированную структуру программы, функцию
log()
и возможность просмотра накопленных сообщений по запросу.
Полностью разделить код прикладной программы и отладчика вряд ли получится при текущей реализации системы Lua контроллер Mesecons. Поэтому прикладная часть просто вписывается в данный шаблон.
Унификация структуры сводится к трём функциям - fmain(), fintr(), fdigi()
, которые дополняются прикладным кодом. Плюс механизм дополнения панели отладчика собственными кнопками управления.
Принципиальная схема отладчика:
![]() |
|||
![]() |
![]() |
||
![]() |
![]() |
![]() | |
![]() (ts1) |
![]() (d1) |
![]() (d1) |
Где ts1 и d1 - названия каналов/идентификаторов digiline, которые закреплены за отладчиком, и могут быть заменены через определение констант.
Прикладные датчики и исполнители подключаются к линиям digilines или msecons. Естественное ограничение - использование отладчика требует одного порта контроллера для подключения digilines.
Особенности мониторов.
digiterms:lcd_monitor предоставляет экран в 6 строк по 12 символов. Вывод скроллируется. То есть, можно видеть несколько последовательных выводов, в пределах собственного буфера вывода экрана.
digilines:lcd работает в режиме перезаписи - последний вывод и есть всё содержание экрана. Есть дополнительное свойство - при наведении на экран содержание последнего вывода отображается как статус объекта.
Привязка нескольких мониторов на один канал digiline дублирует информацию. Это может быть полезно для разнесения мониторов в удобные для наблюдения места или для использования двух разных типов мониторов.
Код, с примерами обработки. В данном случае порт А пустой, порт C подключён к mesecons_lamp:lamp_off, к какому-то порту, B или D датчик мезеконс-сигнала, например,
mesecons_button:button_off, и к оставшемуся порту подключён тач-скрин с идентификатором ts1 и дисплей с идентификатором d1.
-- do return end -- выключатель, на всякий случай -- функции приведения к тексту ---- состояния порта local function iostr(pin) return (pin and "1" or "0"); end ---- таблицы local function tblstr(tbl) tmp=""; if type(tbl) ~= "table" then tmp= "="..type(tbl).."="; else for key, val in pairs(tbl) do tmp=tmp.."("..key.."|"..type(val)..")"; end end return tmp; end -- внутренние функции function loginit() -- ! настраиваемые индикаторы дисплеев и тачскрина mem.logscr="d1"; mem.logpan="ts1"; -- ! mem.log={}; mem.logmax=21; mem.logcur=1; mem.logfrs=1; mem.logcmd={command="addlabel",X=1.1,Y=0.1,label="log"}; tscc={command="clear"}; tscl={command="addbutton",X=0.1,Y=0.1,W=1,H=1,name="blog",label="log"} tscx={command="addbutton_exit",X=0.1,Y=1.1,W=1,H=1,name="bexit",label="X"} mem.logset={tscc, tscl, tscx, mem.logcmd}; logmkl(); -- refresh mem.logcmd.label digiline_send (mem.logscr, "\n\n\n\n\n\n"); -- clear lcd digiline_send (mem.logpan, mem.logset); -- set touch screen end function log (txt) digiline_send (mem.logscr, txt); mem.log[mem.logcur]=txt; mem.logcur=mem.logcur+1; if mem.logcur >mem.logmax then mem.logcur=1; end if (mem.logcur-mem.logfrs)<=0 then mem.logfrs=mem.logfrs+1; if mem.logfrs >mem.logmax then mem.logfrs=1; end end end function relog () logmkl(); digiline_send(mem.logpan, mem.logset); end function logmkl() ttmp=mem.log[mem.logfrs]; if (mem.logcur-mem.logfrs)==-1 then ptmp=mem.logfrs; for i=1,mem.logmax-2,1 do ptmp=ptmp+1; if ptmp >mem.logmax then ptmp=1 end ttmp=ttmp.."\n"..mem.log[ptmp]; end elseif (mem.logcur-mem.logfrs)>0 then for i=mem.logfrs+1,mem.logcur-1,1 do ttmp=ttmp.."\n"..mem.log[i]; end end mem.logcmd.label=ttmp; end -- ! пример собственный кнопок на тачскрине tscA={command="addbutton",X=0.1,Y=3.1,W=1,H=1,name="but_a",label="A"} tscB={command="addbutton",X=0.1,Y=4.1,W=1,H=1,name="but_b",label="B"} -- ! -- ! собственные функции, примеры function fA () log("fA: in"); port.c=true; log("fA: out"); end function fB () log("fB: in"); port={a=false;b=false}; log("fB: out"); end -- ! function fmain () loginit(); log("main"); -- test log system -- ! добавление собственных кнопок mem.logset[#mem.logset+1]=tscA; mem.logset[#mem.logset+1]=tscB; -- ! -- ! Место для собственного кода основной программы -- ! relog(); end -- Обработчик прерываний function fintr () log("intr"); -- ! Место для кода обработки прерываний -- ! relog(); end -- Обработчик диджилайн-событий function fdigi () log(":dl:"..event.channel..":msg:"..tblstr(event.msg)); -- ******** logger ******* if (event.channel == mem.logpan) then log(":dl-ts-clicker:"..event.msg.clicker); if (event.msg.blog) then relog(); elseif (event.msg.quit) then relog(); -- ! пример обработки собственных кнопок elseif (event.msg.but_a) then log(":dl: button A pressed"); fA(); elseif (event.msg.but_b) then log(":dl: button B pressed"); fB(); -- ! else log(":dl: other log panel event") relog(); end -- ******** end logger ******* -- ! примеры обработки других диджилайн-событий -- elseif (event.channel == "b1") then -- -- elseif (event.channel == rtc1) then -- -- elseif (event.channel == "io1") then -- ! else log("!oth digi:"..event.channel) end --digiline_send(mem.logpan, mem.logset); relog(); end -- ******** monitor ******* if (event.type == "program") then fmain() elseif (event.type == "interrupt") then fintr() elseif (event.type == "digiline") then fdigi() elseif (event.type == "on") then -- обработка мезеконс-события ON log(":on:a"..iostr(pin.a)..":b"..iostr(pin.b)..":c"..iostr(pin.c)..":d"..iostr(pin.d)); port.c=true; relog(); elseif (event.type == "off") then -- обработка мезеконс-события OFF log(":off:a"..iostr(pin.a)..":b"..iostr(pin.b)..":c"..iostr(pin.c)..":d"..iostr(pin.d)) relog(); else -- и если будут реализование ещё какие-то события.. log("!oth event="..event.type); relog(); end