mesecons/mesecons_microcontroller/init.lua

412 lines
11 KiB
Lua
Raw Normal View History

2012-08-08 23:35:36 +02:00
EEPROM_SIZE = 255
minetest.register_node("mesecons_microcontroller:microcontroller", {
description = "Microcontroller",
drawtype = "nodebox",
tiles = {"jeija_ic.png"},
inventory_image = {"jeija_ic.png"},
sunlight_propagates = true,
paramtype = "light",
walkable = true,
groups = {dig_immediate=2},
material = minetest.digprop_constanttime(1.0),
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -0.35, 0.5},
},
node_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -0.35, 0.5},
},
on_construct = function(pos)
local meta = minetest.env:get_meta(pos)
meta:set_string("code", "")
meta:set_string("formspec", "size[8,2]"..
"field[0.256,0.5;8,1;code;Code:;]"..
"button_exit[3,0.5;2,2;program;Program]")
meta:set_string("infotext", "Unprogrammed Microcontroller")
2012-08-08 23:35:36 +02:00
local r = ""
for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0"
meta:set_string("eeprom", r)
end,
on_receive_fields = function(pos, formanme, fields, sender)
if fields.program then
local meta = minetest.env:get_meta(pos)
meta:set_string("infotext", "Programmed Microcontroller")
meta:set_string("code", fields.code)
meta:set_string("formspec", "size[8,2]"..
"field[0.256,0.5;8,1;code;Code:;"..fields.code.."]"..
"button_exit[3,0.5;2,2;program;Program]")
reset_yc (pos)
update_yc(pos)
end
end
})
minetest.register_craft({
output = 'craft "mesecons_microcontroller:microcontroller" 2',
recipe = {
{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'mesecons:mesecon_off'},
{'mesecons_materials:silicon', 'mesecons_materials:silicon', 'mesecons:mesecon_off'},
{'mesecons:mesecon_off', 'mesecons:mesecon_off', ''},
}
})
function reset_yc(pos)
mesecon:receptor_off(pos, mesecon:get_rules("microcontrollerA"))
mesecon:receptor_off(pos, mesecon:get_rules("microcontrollerB"))
mesecon:receptor_off(pos, mesecon:get_rules("microcontrollerC"))
mesecon:receptor_off(pos, mesecon:get_rules("microcontrollerD"))
2012-08-08 23:35:36 +02:00
local meta = minetest.env:get_meta(pos)
local r = ""
for i=1, EEPROM_SIZE+1 do r=r.."0" end --Generate a string with EEPROM_SIZE*"0"
meta:set_string("eeprom", r)
end
function update_yc(pos)
local meta = minetest.env:get_meta(pos)
local code = meta:get_string("code")
code = string.gsub(code, " ", "") --Remove all spaces
code = string.gsub(code, " ", "") --Remove all tabs
if parse_yccode(code, pos) == nil then
meta:set_string("infotext", "Code not valid!")
else
meta:set_string("infotext", "Programmed Microcontroller")
end
end
function parse_yccode(code, pos)
local endi = 1
local L = yc_get_portstates(pos)
local c
2012-08-08 23:35:36 +02:00
local eeprom = minetest.env:get_meta(pos):get_string("eeprom")
while true do
command, endi = parse_get_command(code, endi)
if command == nil then return nil end
if command == true then break end
if command == "if" then
2012-08-08 23:35:36 +02:00
r, endi = yc_command_if(code, endi, L, eeprom)
if r == nil then return nil end
if r == true then -- nothing
elseif r == false then
endi = yc_skip_to_endif(code, endi)
if endi == nil then return nil end
end
else
params, endi = parse_get_params(code, endi)
if params == nil then return nil end
end
if command == "on" then
L = yc_command_on (params, L)
elseif command == "off" then
L = yc_command_off(params, L)
2012-08-08 23:35:36 +02:00
elseif command == "sbi" then
eeprom = yc_command_sbi (params, eeprom)
elseif command == "if" then --nothing
else
return nil
end
if L == nil then return nil end
2012-08-08 23:35:36 +02:00
if eeprom == nil then return nil else
minetest.env:get_meta(pos):set_string("eeprom", eeprom) end
end
yc_action(pos, L)
return true
end
function parse_get_command(code, starti)
i = starti
s = nil
while s ~= "" do
s = string.sub(code, i, i)
if s == ";" and starti == i then
starti = starti + 1
i = starti
s = string.sub(code, i, i)
end
if s == "(" then
return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after (
end
i = i + 1
end
if starti == i-1 then
return true, true
end
return nil, nil
end
function parse_get_params(code, starti)
i = starti
s = nil
local params = {}
while s ~= "" do
s = string.sub(code, i, i)
if s == ")" then
table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after )
return params, i + 1
end
if s == "," then
table.insert(params, string.sub(code, starti, i-1)) -- i: ) i+1 after )
starti = i + 1
end
i = i + 1
end
return nil, nil
end
function yc_parse_get_eeprom_param(cond, starti)
2012-08-08 23:35:36 +02:00
i = starti
s = nil
local addr
2012-08-08 23:35:36 +02:00
while s ~= "" do
s = string.sub(cond, i, i)
if string.find("0123456789", s) == nil or s == "" then
addr = string.sub(cond, starti, i-1) -- i: last number i+1 after last number
return addr, i
2012-08-08 23:35:36 +02:00
end
if s == "," then return nil, nil end
i = i + 1
end
return nil, nil
end
function yc_command_on(params, L)
local rules = {}
for i, port in ipairs(params) do
L = yc_set_portstate (port, true, L)
end
return L
end
function yc_command_off(params, L)
local rules = {}
for i, port in ipairs(params) do
L = yc_set_portstate (port, false, L)
end
return L
end
2012-08-08 23:35:36 +02:00
function yc_command_sbi(params, eeprom)
if params[1]==nil or params[2]==nil or params[3] ~=nil or tonumber(params[1])==nil or tonumber(params[2])==nil then return nil end
if tonumber(params[1])>EEPROM_SIZE or tonumber(params[1])<1 or (tonumber(params[2])~=1 and tonumber(params[2]~=0)) then return nil end
new_eeprom = "";
for i=1, #eeprom do
if tonumber(params[1])==i then
new_eeprom = new_eeprom..params[2]
else
new_eeprom = new_eeprom..eeprom:sub(i, i)
end
end
return new_eeprom
end
function yc_command_if(code, starti, L, eeprom)
local cond, endi = yc_command_if_getcondition(code, starti)
if cond == nil then return nil end
2012-08-08 15:09:05 +02:00
2012-08-08 23:35:36 +02:00
cond = yc_command_if_parsecondition(cond, L, eeprom)
2012-08-08 15:09:05 +02:00
if cond == "0" then result = false
elseif cond == "1" then result = true
else result = nil end
return result, endi --endi from local cond, endi = yc_command_if_getcondition(code, starti)
end
function yc_command_if_getcondition(code, starti)
i = starti
s = nil
2012-08-08 23:35:36 +02:00
local brackets = 1 --1 Bracket to close
2012-08-08 15:09:05 +02:00
while s ~= "" do
s = string.sub(code, i, i)
2012-08-08 23:35:36 +02:00
2012-08-08 15:09:05 +02:00
if s == ")" then
2012-08-08 23:35:36 +02:00
brackets = brackets - 1
end
if s == "(" then
brackets = brackets + 1
end
if brackets == 0 then
return string.sub(code, starti, i-1), i + 1 -- i: ( i+1 after (
2012-08-08 15:09:05 +02:00
end
2012-08-08 23:35:36 +02:00
2012-08-08 15:09:05 +02:00
i = i + 1
end
return nil, nil
end
2012-08-08 23:35:36 +02:00
function yc_command_if_parsecondition(cond, L, eeprom)
cond = string.gsub(cond, "A", tostring(L.a and 1 or 0))
cond = string.gsub(cond, "B", tonumber(L.b and 1 or 0))
cond = string.gsub(cond, "C", tonumber(L.c and 1 or 0))
cond = string.gsub(cond, "D", tonumber(L.d and 1 or 0))
2012-08-08 23:35:36 +02:00
local i = 1
local l = string.len(cond)
while i<=l do
local s = cond:sub(i,i)
if s == "#" then
addr, endi = yc_parse_get_eeprom_param(cond, i+1)
buf = yc_eeprom_read(tonumber(addr), eeprom)
2012-08-08 23:35:36 +02:00
if buf == nil then return nil end
local call = cond:sub(i, endi-1)
cond = string.gsub(cond, call, buf)
i = 0
l = string.len(cond)
end
i = i + 1
end
cond = string.gsub(cond, "!0", "1")
cond = string.gsub(cond, "!1", "0")
2012-08-08 15:09:05 +02:00
local i = 2
local l = string.len(cond)
while i<=l do
local s = cond:sub(i,i)
local b = tonumber(cond:sub(i-1, i-1))
local a = tonumber(cond:sub(i+1, i+1))
2012-08-08 20:13:07 +02:00
if cond:sub(i+1, i+1) == nil then break end
2012-08-08 15:09:05 +02:00
if s == "=" then
if a==nil then return nil end
2012-08-08 19:40:39 +02:00
if a == b then buf = "1" end
if a ~= b then buf = "0" end
2012-08-08 15:33:34 +02:00
cond = string.gsub(cond, b..s..a, buf)
2012-08-08 15:09:05 +02:00
i = 1
l = string.len(cond)
end
i = i + 1
end
2012-08-08 23:35:36 +02:00
local i = 2
local l = string.len(cond)
while i<=l do
local s = cond:sub(i,i)
local b = tonumber(cond:sub(i-1, i-1))
local a = tonumber(cond:sub(i+1, i+1))
2012-08-08 20:13:07 +02:00
if cond:sub(i+1, i+1) == nil then break end
if s == "&" then
if a==nil then return nil end
local buf = ((a==1) and (b==1))
if buf == true then buf = "1" end
if buf == false then buf = "0" end
cond = string.gsub(cond, b..s..a, buf)
i = 1
l = string.len(cond)
end
if s == "|" then
if a==nil then return nil end
local buf = ((a == 1) or (b == 1))
if buf == true then buf = "1" end
if buf == false then buf = "0" end
cond = string.gsub(cond, b..s..a, buf)
i = 1
l = string.len(cond)
end
if s == "~" then
if a==nil then return nil end
local buf = (((a == 1) or (b == 1)) and not((a==1) and (b==1)))
if buf == true then buf = "1" end
if buf == false then buf = "0" end
cond = string.gsub(cond, b..s..a, buf)
i = 1
l = string.len(cond)
end
i = i + 1
end
2012-08-08 15:09:05 +02:00
return cond
end
2012-08-08 23:35:36 +02:00
function yc_eeprom_read(number, eeprom)
if number == nil then return nil, nil end
value = eeprom:sub(number, number)
2012-08-08 23:35:36 +02:00
if value == nil then return nil, nil end
return value, endi
end
function yc_get_port_rules(port)
local rules = nil
if port == "A" then
rules = mesecon:get_rules("microcontrollerA")
elseif port == "B" then
rules = mesecon:get_rules("microcontrollerB")
elseif port == "C" then
rules = mesecon:get_rules("microcontrollerC")
elseif port == "D" then
rules = mesecon:get_rules("microcontrollerD")
end
return rules
end
function yc_action(pos, L)
yc_action_setport("A", L.a, pos)
yc_action_setport("B", L.b, pos)
yc_action_setport("C", L.c, pos)
yc_action_setport("D", L.d, pos)
end
function yc_action_setport(port, state, pos)
local rules = mesecon:get_rules("microcontroller"..port)
if state == false then
if mesecon:is_power_on({x=pos.x+rules[1].x, y=pos.y+rules[1].y, z=pos.z+rules[1].z}) then
mesecon:turnoff(pos, rules[1].x, rules[1].y, rules[1].z, false)
end
elseif state == true then
if mesecon:is_power_off({x=pos.x+rules[1].x, y=pos.y+rules[1].y, z=pos.z+rules[1].z}) then
mesecon:turnon(pos, rules[1].x, rules[1].y, rules[1].z, false)
end
end
end
function yc_set_portstate(port, state, L)
if port == "A" then L.a = state
elseif port == "B" then L.b = state
elseif port == "C" then L.c = state
elseif port == "D" then L.d = state
else return nil end
return L
end
function yc_get_portstates(pos)
rulesA = mesecon:get_rules("microcontrollerA")
rulesB = mesecon:get_rules("microcontrollerB")
rulesC = mesecon:get_rules("microcontrollerC")
rulesD = mesecon:get_rules("microcontrollerD")
local L = {
a = mesecon:is_power_on({x=pos.x+rulesA[1].x, y=pos.y+rulesA[1].y, z=pos.z+rulesA[1].z}),
b = mesecon:is_power_on({x=pos.x+rulesB[1].x, y=pos.y+rulesB[1].y, z=pos.z+rulesB[1].z}),
c = mesecon:is_power_on({x=pos.x+rulesC[1].x, y=pos.y+rulesC[1].y, z=pos.z+rulesC[1].z}),
d = mesecon:is_power_on({x=pos.x+rulesD[1].x, y=pos.y+rulesD[1].y, z=pos.z+rulesD[1].z})
}
return L
end
function yc_skip_to_endif(code, starti)
local i = starti
local s = false
while s ~= nil and s~= "" do
s = code:sub(i, i)
if s == ";" then
return i + 1
end
i = i + 1
end
return nil
end
mesecon:register_on_signal_change(function(pos, node)
if node.name == "mesecons_microcontroller:microcontroller" then
minetest.after(0.5, update_yc, pos)
end
end)
mesecon:add_rules("microcontrollerA", {{x = -1, y = 0, z = 0}})
mesecon:add_rules("microcontrollerB", {{x = 0, y = 0, z = 1}})
mesecon:add_rules("microcontrollerC", {{x = 1, y = 0, z = 0}})
mesecon:add_rules("microcontrollerD", {{x = 0, y = 0, z = -1}})
mesecon:add_rules("microcontroller_default", {})
mesecon:add_receptor_node("mesecons_microcontroller:microcontroller", mesecon:get_rules("microcontroller_default"))
mesecon:add_receptor_node("mesecons_microcontroller:microcontroller", mesecon:get_rules("microcontroller_default"))