So I have a pretty unique project I'm attempting. I have an industrial PLC that I would like to interface with TPT. The controller communicates over a TCP socket using a proprietary communication protocol that I am very familiar with. So far I've made a lua script that when loaded into TPT will set and read bits. My issue lies with trying to get my head around how to interface this with the simulation. I tried making an element that just sets a bit if sparked and turns it off when not being sparked. I didn't figure that would work due to the speed at which the game is ticking vs how fast the PLC can send packets, and it did break. Ultimately I'd like to have bits in the PLC trigger sparks, sparks trigger bits in the PLC, and have temperatures and pressures be written to registers.
Edit: Apparently I just needed to sleep on it. I figured it out by using the tick event to make a basic polling timer. I have an element the successfuly triggers a bit in my PLC while being sparked. Now I just have to figure out how to scale it up for dozens of bits. I've seen where some peope use the temp varibles to set attributes, so probably that.
So, I have a very rough version of my interface script working which includes alot of copy paste code from the breakpoint mod and the logic gates mod. To the authors of those mods I am very grateful and sorry. Anyways, I'm just going to toss my script in here just incase it someone else would like to interface something extrenal to TPT and needs some ideas.
local host, port = "192.168.1.1", 1026
local socket = rawget(_G, "socket")
local tcp = assert(socket.tcp())
local updateTime = 15
local xBits = '\x00\x00\x00\x00'
local yBits = '\x00\x00\x00\x00'
local data = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
tcp:settimeout(1, 't')
tcp:connect(host, port)
--This handles talking to the PLC--
event.register(event.tick, function()
--This bit gets 2 words from the PLC starting at Y120
if updateTime == 10 then
buff = '\x00\x00\x05\x00\x1c\x12\x01\x02\x00'
tcp:send(buff)
local buff = tcp:receive(9)
yBits = string.sub(buff, -4)
elseif updateTime == 5 then
--This bit sets 2 words worth of bits in the PLC starting at X100
buff = '\x00\x00\x07\x00\x1d\x10\x01'..xBits
tcp:send(buff)
buff = tcp:receive(5)
xBits = '\x00\x00\x00\x00'
elseif updateTime == 0 then
--This bit sends the data variable to the PLC starting at D100
buff = '\x00\x00\x13\x00\x1d\x10\x10' .. data
tcp:send(buff)
buff = tcp:receive(5)
data = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
updateTime = 15
end
updateTime = updateTime - 1
end)
--This just replaces a section in a string with another string--
function replace_char(i, str, r)
i = i + 1
return str:sub(1, i-1) .. r .. str:sub(i+string.len(r))
end
--This turns on a bit at index "i" in the xBits variable--
function setX(i)
if i > 23 then
i = i - 24
i = bit.lshift(1, i)
local index = 4
local x = string.char(bit.bor(string.byte(string.sub(xBits, index, index)), i))
xBits = replace_char(index-1, xBits, x)
elseif i > 15 then
i = i - 16
i = bit.lshift(1, i)
index = 3
x = string.char(bit.bor(string.byte(string.sub(xBits, index, index)), i))
xBits = replace_char(index-1, xBits, x)
elseif i > 7 then
i = i - 8
i = bit.lshift(1, i)
index = 2
x = string.char(bit.bor(string.byte(string.sub(xBits, index, index)), i))
xBits = replace_char(index-1, xBits, x)
else
i = bit.lshift(1, i)
index = 1
x = string.char(bit.bor(string.byte(string.sub(xBits, index, index)), i))
xBits = replace_char(index-1, xBits, x)
end
end
--This returns a bit from index "i" in the yBits variable--
function readY(i)
if i > 23 then
i = i - 24
x = string.byte(string.sub(yBits, 4, 4))
x = bit.rshift(x, i)
x = bit.band(x, 1)
elseif i > 15 then
i = i - 16
x = string.byte(string.sub(yBits, 3, 3))
x = bit.rshift(x, i)
x = bit.band(x, 1)
elseif i > 7 then
i = i - 8
x = string.byte(string.sub(yBits, 2, 2))
x = bit.rshift(x, i)
x = bit.band(x, 1)
else
x = string.byte(string.sub(yBits, 1, 1))
x = bit.rshift(x, i)
x = bit.band(x, 1)
end
return x
end
function setData(i, temp, press)
temp = math.floor(temp)
local x = bit.band(temp, 255)
local y = bit.band(bit.rshift(temp, 8), 255)
temp = string.char(x) .. string.char(y)
press = math.floor(press)
x = bit.band(press, 255)
y = bit.band(bit.rshift(press, 8), 255)
press = string.char(x) .. string.char(y)
local str = press .. temp
data = replace_char(i * 4, data, str)
end
--This starts the setbit element--
local el_tpsb = elem.allocate("Koolguy", "TPSB")
elem.element(el_tpsb, elem.element(elem.DEFAULT_PT_DMND))
elem.property(el_tpsb, "Name", "TPSB")
elem.property(el_tpsb, "Colour", 0xDEADBEEF)
elem.property(el_tpsb, "Description", "Sets a bit in the PLC when sparked.")
elem.property(el_tpsb, "MenuSection", elem.SC_SENSOR)
elem.property(el_tpsb, "Properties", elem.PROP_LIFE_DEC)
elem.property(el_tpsb, "Temperature", 273.15)
elem.property(el_tpsb, "HeatConduct", 0)
elem.property(el_tpsb, "Update", function (i, x, y, ss, nt)
local life = sim.partProperty(i, "life")
for ry=-1,1,1 do
for rx=-1,1,1 do
if life == 0 and tpt.get_property("type", x+rx, y+ry) == 15 then
local index = sim.partProperty(i, "temp") - 273.15
setX(index)
sim.partProperty(i, "life", 10)
end
end
end
end)
elem.property(el_tpsb, "Graphics", function (i, colr, colg, colb)
local x, y = sim.partPosition(i)
local life = sim.partProperty(i, "life")
if life > 0 then
pixel_mode = 296
colg, colb = 0, 0
colr = 255
else
pixel_mode = 1
end
return 0,pixel_mode,255,colr,colg,colb,255,colr,colg,colb
end)
--This ends the setbit element--
--This starts the readbit element--
local el_tprb = elem.allocate("Koolguy", "TPRB")
elem.element(el_tprb, elem.element(elem.DEFAULT_PT_DMND))
elem.property(el_tprb, "Name", "TPRB")
elem.property(el_tprb, "Colour", 0xDEADBEEF)
elem.property(el_tprb, "Description", "Reads a bit from the PLC and sparks if on.")
elem.property(el_tprb, "MenuSection", elem.SC_SENSOR)
elem.property(el_tprb, "Properties", elem.PROP_LIFE_DEC)
elem.property(el_tprb, "Temperature", 273.15)
elem.property(el_tprb, "HeatConduct", 0)
elem.property(el_tprb, "Update", function (i, x, y, ss, nt)
for dx = -1, 1 do
for dy = -1, 1 do
local index = sim.partProperty(i, "temp") - 273.15
yOn = readY(index)
if yOn == 1 then
sim.partCreate(-1, x + dx, y + dy, elem.DEFAULT_PT_SPRK)
end
end
end
end)
elem.property(el_tprb, "Graphics", function (i, colr, colg, colb)
local x, y = sim.partPosition(i)
if yOn == 1 then
pixel_mode = 296
colr, colg, colb = 0, 255, 64
else
pixel_mode = 1
end
return 0,pixel_mode,255,colr,colg,colb,255,colr,colg,colb
end)
--This ends the readbit element--
--This starts the pressure and temperature sensor element--
local el_tpsb = elem.allocate("Koolguy", "TPTP")
elem.element(el_tpsb, elem.element(elem.DEFAULT_PT_DMND))
elem.property(el_tpsb, "Name", "TPTP")
elem.property(el_tpsb, "Colour", 0xDEADBEEF)
elem.property(el_tpsb, "Description", "Sends temp and press to the PLC in pairs of bytes.")
elem.property(el_tpsb, "MenuSection", elem.SC_SENSOR)
elem.property(el_tpsb, "Properties", elem.PROP_LIFE_DEC)
elem.property(el_tpsb, "HeatConduct", 255)
elem.property(el_tpsb, "Update", function (i, x, y, ss, nt)
setData(sim.partProperty(i, "tmp"), sim.partProperty(i, "temp"), sim.pressure(x/4, y/4))
end)
--This ends the pressure and temperature sensor element--