Skip to content

Instantly share code, notes, and snippets.

@Rami-Sabbagh
Created June 13, 2017 12:38
Show Gist options
  • Save Rami-Sabbagh/1a1532dc57ab0f2e5c2cd4dde81b4c82 to your computer and use it in GitHub Desktop.
Save Rami-Sabbagh/1a1532dc57ab0f2e5c2cd4dde81b4c82 to your computer and use it in GitHub Desktop.
PowderToy Micro Lua Proccessors
--Creating the elements--
local elem_group = "MLUA"
local elem_names = { "LMPU", "LCBL", "LPIN", "LMRC", "LROM" } --The names of the elements to allocate
local elem_id = {} --A table containing the ids of every name in elem_names, [name] = id.
local elem_name = {} --A table to get the name from the id
--Allocate the elements
for k, name in ipairs(elem_names) do
if elements[elem_group.."_PT_"..name] then elements.free(elements[elem_group.."_PT_"..name]) end --Incase the script errored
local id = elements.allocate(elem_group, name)
if id == -1 then --(It failed)
error("Failed to allocate an element, please disable some elements scripts !")
return --Abort the script
else
elem_id[name] = id
elem_name[id] = name
end
end
local elem_clone = { --New elements properties; _Parent is a special key that clones properties from a default elements before applying the changes.
["LMPU"] = {
_Parent = "METL",
Name = "LMPU",
Description = "Lua Microprocessor Unit, used for advanced electornics",
Color = 0x000080, --The color of the Lua logo ;)
MenuSection = elements.SC_POWERED
},
["LCBL"] = {
_Parent = "INSL",
Name = "LCBL",
Description = "Lua Cable, used for connecting peripherals with LMPU",
Flammable = 0, --UnFlammable
MenuSection = elements.SC_POWERED
},
["LPIN"] = {
_Parent = "METL",
Name = "LPIN",
Description = "Lua Pin, Connects as GPIO pin peripheral. TMP as id",
Color = 0xE0E0E0,
MenuSection = elements.SC_POWERED
},
["LMRC"] = {
_Parent = "METL",
Name = "LMRC",
Description = "Lua Memory Reading Controller peripheral. Speciallized in reading LROM",
Color = 0xF4BC42,
MenuSection = elements.SC_POWERED
},
["LROM"] = {
_Parent = "IRON",
Name = "LROM",
Description = "Lua Read Only Memory, Stores 8 Bytes (8 Ascii Characters)",
Color = 0xFFFFFF, --White
Properties = bit.bor(elements.TYPE_SOLID,elements.PROP_HOT_GLOW),
MenuSection = elements.SC_POWERED
}
}
--Applying the properties
for name, props in pairs(elem_clone) do
if not elem_id[name] then error("Un-allocated element: "..name..", report this to the developer !") end
if props._Parent then elements.element(elem_id[name],elements.element(elements["DEFAULT_PT_"..props._Parent])); props._Parent = nil end --Do the clonning
elements.element(elem_id[name],props) --Set the properties
end
local elem_peripherals = {[ elem_id["LPIN"] ] = true, [ elem_id["LMRC"] ] = true} --Use elem_id (for easier programming)
--SC (self call) is a special argument, don't use it !
local mappedIndexes, mappedPeripherals = {}, {}
local function mapCables(x,y, sc)
if not sc then mappedIndexes, mappedPeripherals = {}, {} end --Reset the maps
mappedIndexes[simulation.partID(x,y)] = true --Set the current part as mapped.
local parts = simulation.partNeighbors(x,y, 2) --Scan the around parts.
for _, index in ipairs(parts) do
if not mappedIndexes[index] then
local px, py = simulation.partPosition(index)
local ptype = simulation.partProperty(index,simulation.FIELD_TYPE)
if elem_peripherals[ptype] then --It's a peripheral !
mappedIndexes[index] = true --So don't double detect the peripheral
if not mappedPeripherals[elem_name[ptype]] then mappedPeripherals[elem_name[ptype]] = {} end
table.insert(mappedPeripherals[elem_name[ptype]],index)
elseif elem_id["LCBL"] == ptype then --It's a cable
mapCables(px,py, true)
end
end
end
if not sc then return mappedPeripherals end
end
local function mapROM(x,y)
--X, Y should be the position of the top-left corner.
local mi = {} --Mapped Indexes
local cy = 0
while true do
local ypid = simulation.partID(x,y+cy)
if not ypid then break end
if simulation.partProperty(ypid, simulation.FIELD_TYPE) ~= elem_id["LROM"] then break end --The end of rom block
local cx = 0
while true do
local pid = simulation.partID(x+cx,y+cy)
if not pid then break end --No Part
if simulation.partProperty(pid, simulation.FIELD_TYPE) ~= elem_id["LROM"] then break end --The end of rom line
table.insert(mi,pid)
cx = cx + 1
end
cy = cy + 1
end
return mi
end
--Reads the ROM string, must provide the mappedIndexes array (That can be obtained by mapROM(x,y))
local function readROM(mi)
local data = ""
for _, index in ipairs(mi) do
local ctype = simulation.partProperty(index, simulation.FIELD_CTYPE) --1 byte
local dcolor = simulation.partProperty(index, simulation.FIELD_DCOLOUR) --4 bytes
local life = simulation.partProperty(index, simulation.FIELD_LIFE) --1 byte
local tmp = simulation.partProperty(index, simulation.FIELD_TMP) --1 byte
local tmp2 = simulation.partProperty(index, simulation.FIELD_TMP2) --1 byte
ctype = string.char(ctype)
local cola = string.char(bit.band(dcolor,255))
local colr = string.char(bit.band(bit.rshift(dcolor,8),255))
local colg = string.char(bit.band(bit.rshift(dcolor,16),255))
local colb = string.char(bit.band(bit.rshift(dcolor,24),255))
life = string.char(life)
tmp = string.char(tmp)
tmp2 = string.char(tmp2)
data = data .. ctype..cola..colr..colg..colb..life..tmp..tmp2
end
return data
end
--Writes the ROM string, must provide the mappedIndexes arrays (That can be obtained by mapROM(x,y)) and the data string.
local function flushROM(mi,data)
local dataBytes = {}
for i=1,data:len() do
table.insert(dataBytes,string.byte(data:sub(i,i+1)))
end
local curByte = 0
local function nextByte()
if #dataBytes == curByte then return 0 end
curByte = curByte + 1
return dataBytes[curByte]
end
for _, index in ipairs(mi) do
simulation.partProperty(index, simulation.FIELD_CTYPE, nextByte()) --1 bytes
local cola = nextByte()
local colr = bit.lshift(nextByte(),8)
local colg = bit.lshift(nextByte(),16)
local colb = bit.lshift(nextByte(),24)
local dcolor = bit.bor(cola,colr,colg,colb)
simulation.partProperty(index, simulation.FIELD_DCOLOUR, dcolor) --4 bytes
simulation.partProperty(index, simulation.FIELD_LIFE, nextByte()) --1 byte
simulation.partProperty(index, simulation.FIELD_TMP, nextByte()) --1 byte
simulation.partProperty(index, simulation.FIELD_TMP2, nextByte()) --1 byte
end
end
local MPU_Data = {}
--Elements Update
elements.property( elem_id["LMPU"], "Update", function(index, x, y, surround_space, nt)
local flags = simulation.partProperty(index, simulation.FIELD_FLAGS)
--Check if the processor did boot yet or not.
--I found that it's safe to use the second byte of FLAGS
--And why I'm using flags because it's not saved ;)
--The first bit will be the boot state, 0 = off, 1 = booted.
if bit.band(flags, 256) == 0 then --It did not boot yet !
MPU_Data[index] = {} --Override the old one if exists.
MPU_Data[index].peripherals = mapCables(x,y)
if MPU_Data[index].peripherals.LMRC then
print("Detected Memory Reading Chip, Starting Demo")
local index = MPU_Data[index].peripherals.LMRC[1]
local x,y = simulation.partPosition(index)
local rom = mapROM(x+1,y+1)
--print("Will Flash some data")
--flushROM(rom, "TEST DATA, LET'S SEE12345678901234567890")
--print("Flashed Rom")
local data = readROM(rom)
print("ROM: "..tostring(data))
end
simulation.partProperty(index, simulation.FIELD_FLAGS, bit.bor(flags,256)) --Flag as booted
else --It booted before, tick now.
end
end)
--Console Tools
micro = {} --The MicroLua API
--Read data from a file and flushs it to a LMRC at a given index.
function micro.flushMRC(index,filepath)
--Usage message
if not (index and filepath) then
print([[USAGE: micro.flushMRC(<index>,<filepath>)
Reads data from a file and flushs it to a LMRC at a given index.
<index>: The LMRC part index.
<filepath>: The path to the file to read from.]])
return
end
--Arguments type verification
if type(index) ~= "number" then return error("Index must be a number, provided: "..type(index)) end
if type(filepath) ~= "string" then return error("Filepath must be a string, provided: "..type(filepath)) end
--Part verification
local controllerType = simulation.partProperty(index, simulation.FIELD_TYPE)
if not controllerType then return error("No part exists with id #"..index) end
if controllerType ~= elem_id["LMRC"] then return error("The given part is not a LMRC, instead it's: "..controllerType) end
--File verification
local file, ferr = io.open(filepath, "rb")
if not file then return error("Failed to open the file: "..tostring(ferr)) end
--Load file data
local data = file:read("*a")
file:close()
--Map the ROM indexes
local cx, cy = simulation.partPosition(index) --Controller position.
local mi = mapROM(cx+1,cy+1)
--Check data size
local maxSize = #mi*8 --Every part can hold 8 bytes
if data:len() > maxSize then return error("Data too large to flash ("..data:len().." byte), max: "..maxSize.." byte") end
--Flush the data
flushROM(mi, data)
print("Flushed data successully")
end
--Read data from a LMRC at a given index, and save it into a given file.
function micro.dumpMRC(index,filepath)
--Usage message
if not (index and filepath) then
print([[USAGE: micro.dumpMRC(<index>,<filepath>)
Read data from a LMRC at a given index, and save it into a given file.
<index>: The LMRC part index.
<filepath>: The path to the file to save to.]])
return
end
--Arguments type verification
if type(index) ~= "number" then return error("Index must be a number, provided: "..type(index)) end
if type(filepath) ~= "string" then return error("Filepath must be a string, provided: "..type(filepath)) end
--Part verification
local controllerType = simulation.partProperty(index, simulation.FIELD_TYPE)
if not controllerType then return error("No part exists with id #"..index) end
if controllerType ~= elem_id["LMRC"] then return error("The given part is not a LMRC, instead it's: "..controllerType) end
--File creation
local file, ferr = io.open(filepath, "wb")
if not file then return error("Failed to open the file: "..tostring(ferr)) end
--Map the ROM indexes
local cx, cy = simulation.partPosition(index) --Controller position.
local mi = mapROM(cx+1,cy+1)
--Get ROM data
local data = readROM(cx+1,cy+1)
--Save the data on the file
file:write(data)
file:flush()
file:close()
print("Dumped data successully")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment