Перейти к содержанию

Сниппет LuaDeb: различия между версиями

Материал из Luanti НашиТут
Нет описания правки
мНет описания правки
 
(не показаны 4 промежуточные версии этого же участника)
Строка 13: Строка 13:
|||{{Obj|digilines|wire_std_11100000|64}}||{{Obj|digilines|wire_std_11100000|64|r}}||{{Obj|digilines|wire_std_11100000|64|r}}
|||{{Obj|digilines|wire_std_11100000|64}}||{{Obj|digilines|wire_std_11100000|64|r}}||{{Obj|digilines|wire_std_11100000|64|r}}
|-
|-
|||{{Obj|digistuff|touchscreen|64}}<br>(p1)||{{Obj|digiterms|lcd_monitor|64}}<br>(d1)||{{Obj|digilines|lcd|64}}<br>(d1)
|||{{Obj|digistuff|touchscreen|64}}<br>(ts1)||{{Obj|digiterms|lcd_monitor|64}}<br>(d1)||{{Obj|digilines|lcd|64}}<br>(d1)
|-
|-
|}
|}
Где p1 и d1 - названия каналов digiline, которые закреплены за отладчиком, и могут быть заменены через определение констант.
Где ts1 и d1 - названия каналов/идентификаторов digiline, которые закреплены за отладчиком, и могут быть заменены через определение констант.


Прикладные датчики и исполнители подключаются к линиям digilines или msecons. Естественное ограничение - использование отладчика требует одного порта контроллера для подключения digilines.
Прикладные датчики и исполнители подключаются к линиям digilines или msecons. Естественное ограничение - использование отладчика требует одного порта контроллера для подключения digilines.
Строка 24: Строка 24:
* {{Obj|digilines|lcd|4=id}} работает в режиме перезаписи - последний вывод и есть всё содержание экрана. Есть дополнительное свойство - при наведении на экран содержание последнего вывода отображается как статус объекта.
* {{Obj|digilines|lcd|4=id}} работает в режиме перезаписи - последний вывод и есть всё содержание экрана. Есть дополнительное свойство - при наведении на экран содержание последнего вывода отображается как статус объекта.
Привязка нескольких мониторов на один канал digiline дублирует информацию. Это может быть полезно для разнесения мониторов в удобные для наблюдения места или для использования двух разных типов мониторов.
Привязка нескольких мониторов на один канал digiline дублирует информацию. Это может быть полезно для разнесения мониторов в удобные для наблюдения места или для использования двух разных типов мониторов.
Код, с примерами обработки. В данном случае
* порт А пустой,
* порт C подключён к {{Obj|mesecons_lamp|lamp_off|4=id}},
* к какому-то порту, B или D, подключён датчик мезеконс-сигнала, например, {{Obj|mesecons_button|button_off|4=id}},
* и к оставшемуся порту подключён тач-скрин с идентификатором ts1 и дисплей  с идентификатором d1.


<pre>
<pre>
-- 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;c=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


do return 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


</pre>
</pre>


[[Category:Всё]][[Category:Сниппеты]]
[[Category:Всё]][[Category:Сниппеты]]

Текущая версия от 19:20, 11 февраля 2025

Lua контроллер Mesecons при игре в серверном варианте не имеет даже самых простых средств отладки. Даже простой вывод функцией print не может быть получен на стороне игрока, потому что код контроллера выполняется на сервере игры. Остаётся только выводить отладочную информацию средствами, доступными в игре - digilines:lcd , digiterms:lcd_monitor , digistuff:touchscreen . И все не очень удобно, всё имеет недостатки. Чтобы как-то решить проблему требуется логирование с буферизацией. Собственно, эту задачу и решает данный отладчик - предоставляет унифицированную структуру программы, функцию log() и возможность просмотра накопленных сообщений по запросу.

Полностью разделить код прикладной программы и отладчика вряд ли получится при текущей реализации системы Lua контроллер Mesecons. Поэтому прикладная часть просто вписывается в данный шаблон.

Унификация структуры сводится к трём функциям - fmain(), fintr(), fdigi(), которые дополняются прикладным кодом. Плюс механизм дополнения панели отладчика собственными кнопками управления.

Принципиальная схема отладчика:

mesecons:wire_00000000_off
mesecons:wire_00000000_off
mesecons_luacontroller:luacontroller0000
digilines:wire_std_11100000
digilines:wire_std_11100000
digilines:wire_std_11100000
digistuff:touchscreen
(ts1)
digiterms:lcd_monitor
(d1)
digilines:lcd
(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;c=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