· 6 years ago · Jan 19, 2020, 06:30 AM
1--PeachMaster's MTC and Digital Interlocking System: A system for MTC and W-MTC, but this one is for standard MTC
2--Hi! you are not supposted to access this file. get out debil cyka blyat
3--...unless you know what you're doing. I mean, why are you doing this? This file isn't really for editing.
4--You get what you get and you don't throw a fit. That's what my kindergarden teacher said.
5
6-- Menu API provided by cyanisaac and ProjectB, licensed under the MIT license.
7--JSON API provided by ElvishJerricco.
8--Initalize all the things!
9--Initalize signalblocks
10--TrainControl 1.1
11--Use one channel instead of multiple for signal communications
12local sbraw = fs.open("signalDatabase", "r")
13local cdraw = fs.open("computerdatabase", "r")
14local sraw = fs.open("system", "r")
15local craw = fs.open("config", "r")
16os.loadAPI("menu")
17local signalBlocks = textutils.unserialise(sbraw.readAll())
18local system = sraw.readAll()
19local computerDatabase = textutils.unserialise(cdraw.readAll())
20local config
21local clientsDoneInSelfTest = {}
22local radio = peripheral.find("pdmInstructionRadio")
23local sendQueue
24local bundledIO = peripheral.find("bio")
25local lastBundledCable = 0
26sbraw.close()
27sraw.close()
28cdraw.close()
29local modem = peripheral.find("modem")
30if modem == nil then
31error("TrainControl cannot continue because a modem has not been found.")
32end
33
34if fs.exists("menu") == false then
35print("Downloading menu API..stand by..")
36shell.run("pastebin get UK4ATXvH menu")
37sleep(1)
38end
39
40if fs.exists("json") == false then
41 print("Downloading JSON API..stand by..")
42shell.run("pastebin get 4nRg9CHU json")
43sleep(1)
44end
45
46if fs.exists("encrypt") == false then
47 print("Downloading encryption API...stand by..")
48 shell.run("pastebin get WRTfH0yx encrypt")
49 sleep(1)
50end
51
52
53
54
55os.loadAPI("menu")
56os.loadAPI("json")
57os.loadAPI("encrypt")
58
59
60--Oh yeah, don't forget about the main functions.
61
62local function setup()
63 local madeConfig = {}
64 term.clear()
65 term.setCursorPos(1,1)
66 print("Please set a name for this system for identification (ex. railroad/divison name): ")
67 local systemName = read()
68 madeConfig["SystemName"] = systemName
69 menu.doInfoScreen("Welcome to TrainControl!", "Hi, Welcome! This will help you set up the program to get your trains running safely.")
70 local theMenu = {"Modem using Rednet (most recommended)", "Bundled Redstone (requires FirePeripherals for 1.7.10)", "Redstone (least recommended, don't use it)"}
71 madeConfig["SignalConnectionType"] = menu.doMenu("TrainControl Setup | Signal Connection Type", theMenu)
72 theMenu = {"MTC", "W-MTC", "Don't use it"}
73 madeConfig["UseMTC"] = menu.doMenu("TrainControl Setup | MTC Type", theMenu)
74
75 while true do
76 term.clear()
77 term.setCursorPos(1,1)
78
79 print("Please define a channel for Modem communications. It doesn't really matter which one you choose, as long as it's not being used for something else.")
80 local ModemChannel = read()
81 local hmm = tonumber(ModemChannel)
82 if hmm ~= nil then
83
84 if hmm > 65535 then
85
86 print("That was not a valid channel. Channels cannot as be higher than 65535.")
87 else
88 madeConfig["ModemChannel"] = hmm
89 break
90 end
91
92 else
93 print("That was not a valid channel. Channels must be numbers and as high as 65535.")
94 end
95end
96
97 term.clear()
98 term.setCursorPos(1,1)
99 print("Please define a channel for Terminal communications. It doesn't really matter which one you choose, as long as it's not being used for something else.")
100 local terminalChannel = read()
101 madeConfig["TerminalChannel"] = terminalChannel
102
103 term.clear()
104 term.setCursorPos(1,1)
105
106
107
108 menu.doInfoScreen("Setup Complete!", "TrainControl will start after you press ENTER.")
109 print(textutils.serialise(madeConfig))
110 config = madeConfig
111 local writeConfig = fs.open("config", "w")
112 writeConfig.write(textutils.serialise(config))
113 writeConfig.close()
114 sleep(2)
115
116
117end
118
119local function getSomethingFromTable(theTable, thingWanted) -- A workaround to crappy CC/Lua. >:(
120 for k, v in pairs(theTable) do
121 if k == thingWanted then
122 return v
123 end
124 end
125end
126
127local function saveTableFile(path, watchuwant) -- Quicker way to do things w o a h
128 local handle = fs.open(path, "w")
129 handle.write(textutils.serialise(whatchuwant))
130 handle.close()
131end
132
133local function loadTableFile(path) -- Quiciker way to do things w o a h
134 local handle = fs.open(path, "r")
135 local thing = textutils.unserialise(handle.readAll())
136 handle.close()
137 return thing
138end
139
140
141local function doEncrypt(thing1)
142
143 -- local ok = encrypt.encrypt(thing1, "kgkg499tgi34ikg39koowklfow0o349")
144 --return ok
145 return thing1
146end
147
148local function doDecrypt(thing)
149 -- local ok = encrypt.decrypt(thing, "kgkg499tgi34ikg39koowklfow0o349")
150 -- return ok
151 return thing
152end
153
154
155local function controlSignals()
156 --Signal status meanings:
157 --1 = Unoccupied, green
158 --2 = Unoccupied, yellow (train in next block so use caution)
159 --3 = Occupied, train is in it.
160
161 --Reload the signaldatabase, just in case anything was changed.
162 signalDatabase = loadTableFile("signalDatabase")
163 if config.SignalConnectionType == 1 then
164
165 --Connection type is Modem based, so do everything modem related here.
166 local event, side, sendChannel, replyChannel, message, distance = os.pullEvent()
167
168 if event == "modem_message" then
169 local response = doDecrypt(message)
170
171 if response.funct == "blockOccupied" then
172 signalBlocks[response.source].status = 3
173
174 if getSomethingFromTable(signalBlocks[response.source], "prev") ~= "none" then
175 local previousSignal = getSomethingFromTable(signalBlocks[response.source], "prev")
176
177 if getSomethingFromTable(signalBlocks[response.source], "prev").status ~= 3 then signalBlocks[previousSignal].status = 2 end
178 print("Sending a signal update to the previous signal.")
179 modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, previousSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name}))
180 end
181
182 print(response.source.." is occupied. ")
183
184 end
185 if response.funct == "blockReleased" then
186 print(response.source)
187 signalBlocks[response.source].status = 1
188 print(response.source.." is released.")
189
190 if getSomethingFromTable(signalBlocks[response.source], "prev") ~= "none" then
191 local previousSignal = getSomethingFromTable(signalBlocks[response.source], "prev")
192 if getSomethingFromTable(signalBlocks[response.source], "prev").status ~= 3 then signalBlocks[previousSignal].status = 1 end
193 print("Sending signalupdate to the previous signal.")
194 modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, previousSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name}))
195 end
196
197 end
198 if getSomethingFromTable(signalBlocks[response.source], "next") ~= "none" and signalBlocks[response.source].occupiedBy ~= nil and config["UseMTC"] == 2 then
199 local nextSignal = getSomethingFromTable(signalBlocks[response.source], "next")
200 print("Sending a signal update for W-MTC to the previous signal. ")
201 modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, nextSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name, isWMTCOkay = true}))
202 else
203 modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, nextSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name, isWMTCOkay = false}))
204 end
205
206 if response.funct == "switchOccupied" then
207 print(response.source.. " is occupied!")
208 signalBlocks[response.source].status = 1
209
210
211 end
212
213 if response.funct == "switchReleased" then
214 print(response.source.. "is released!")
215 signalBlocks[response.source].status = 0
216 end
217
218 if response.funct == "setSwitchStatus" then
219 --owo
220 modem.transmit(getSomethingFromTable(tonumber(config["ModemChannel"]), tonumber(config["ModemChannel"]), encrypt(textutils.serialise({funct = "updateSwitchStatus", switchStatus = response.switchStatus}))))
221 end
222
223 --Alright, we got that, now send it to the signals.
224 if response.source ~= "Terminal" then
225 modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, response.source).status, to = getSomethingFromTable(signalBlocks, response.source).name, isWMTCOkay = getSomethingFromTable(signalBlocks, response.source).isWMTCOkay}))
226 end
227 if config["UseMTC"] == 2 then
228 --Alright..W-MTC on..generate a MTC data packet.
229 local speedLimit1
230 local nextSpeedLimit1
231 local speedChange1
232 local changeX
233 local changeY
234 local changeZ
235 local endSoon1
236 local xStopPoint
237 local yStopPoint
238 local zStopPoint
239 local mtcStats
240 local nextSignal = getSomethingFromTable(signalBlocks[response.source], "next")
241 if getSomethingFromTable(signalBlocks[nextSignal], "status") == 3 then
242 speedLimit = getSomethingFromTable(signalBlocks[response.source], "yellowSpeedLimit")
243 endSoon = true
244 xStopPoint = getSomethingFromTable(signalBlocks[nextSignal], "positionX")
245 yStopPoint = getSomethingFromTable(signalBlocks[nextSignal], "positionY")
246 zStopPoint = getSomethingFromTable(signalBlocks[nextSignal], "positionZ")
247 end
248 if getSomethingFromTable(signalBlocks[nextSignal], "status") == 2 then
249 nextSpeedLimit = getSomethingFromTable(signalBlocks[response.source], "yellowSpeedLimit")
250 speedChange = true
251 changeX = getSomethingFromTable(signalBlocks[nextSignal], "positionX")
252 changeY = getSomethingFromTable(signalBlocks[nextSignal], "positionY")
253 changeZ = getSomethingFromTable(signalBlocks[nextSignal], "positionZ")
254 end
255
256 --Alright..generate the JSON.
257 local send = {speedLimit = speedLimit1, nextSpeedLimit = nextSpeedLimit1, speedChange = speedChange1, endSoon = endSoon1}
258
259 if endSoon1 then
260 send["xStopPoint"] = xStopPoint
261 send["yStopPoint"] = yStopPoint
262 send["zStopPoint"] = zStopPoint
263 end
264
265 if getSomethingFromTable(signalBlocks[response.source], "next") == "none" then
266 mtcStat = 2
267 send["mtcStatus"] = mtcStat
268 end
269
270 if speedChange1 then
271 send["nextSpeedLimitChangeX"] = changeX
272 send["nextSpeedLimitChangeY"] = changeY
273 send["nextSpeedLimitChangeZ"] = changeZ
274 end
275 --Is it done? Okay, print it just in case.
276 print(textutils.serialise(send))
277 --Okay, it's finally done, put it into the queue.
278 if signalBlocks[response.source].occupiedBy ~= nil then
279
280 signalBlocks[response.source].sendTo = {funct = "sendToTrain", sendTo = signalBlocks[response.source].occupiedBy, send1 = send}
281 end
282 end
283 --Also, finally, save it to the file so it can be used later.
284 -- saveTableFile("signaldatabase", signalDatabase)
285 if response.funct == "radio_message" then
286 --Okay, it came from a train. Let's check it out.
287 local response1 = response.message
288 print(textutils.serialise(response1))
289 if response1.funct == "attemptConnection" then
290 --Attempting..alright..welcome!
291 --Give temp data, actual limits will be sent on the next update
292 local send = {funct = "startlevel2", speedLimit = 60, nextSpeedLimit = 0, speedChange = false, stationStopSoon = false, mtcStatus = 1 }
293
294 end
295
296 if response1.funct == "update" then
297 --Great, an update! There may have been something you have missed, so I'm going to send it to you.
298 signalBlocks[response.signalBlock].occupiedBy = response.sendChannel
299
300 if signalBlocks[response.signalBlock].sendTo ~= nil then
301 modem.transmit(signalBlock[response.signalBlock].wirelessRadioChannel, modem["ModemChannel"], signalBlocks[response.source].sendTo)
302 end
303
304 end
305
306 if response1.funct == "disconnect" then
307
308 end
309
310
311 end
312
313 end
314
315--No? it's not a modem message? Then maybe it's something else.
316elseif config.SignalConnectionType == 2 then
317 local event, input, id = os.pullEvent("redstone")
318--Input is raw color.
319--Green signal output is combined with green
320--Yellow signal output is combined with yellow
321--Red signal output is combined with red
322
323
324 --Alright..let's see what signal is occupied.
325 --[[ if response.funct == "blockOccupied" then
326 signalBlocks[response.source].status = 3
327
328 if getSomethingFromTable(signalBlocks[response.source], "prev") ~= "none" then
329 local previousSignal = getSomethingFromTable(signalBlocks[response.source], "prev")
330
331 if getSomethingFromTable(signalBlocks[response.source], "prev").status ~= 3 then signalBlocks[previousSignal].status = 2 end
332 print("Sending a signal update to the previous signal.")
333 modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, previousSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name}))
334 end
335
336 print(response.source.." is occupied. ")
337
338 end
339]]
340 if lastBundledCable < input then
341 --Someone added
342 connectionRemoved = colors.subtract(lastBundledCable, input)
343 end
344
345 local connectionRemoved
346
347 signalBlocks[input].status = 3
348 print(getSomethingFromTable(signalBlocks[input], "name").." is occupied.")
349 bundledIO.setBundledOutput(colors.combine(input, colors.red))
350 if getSomethingFromTable(signalBlocks[input], "prev") ~= "none" and getSomethingFromTable(signalBlocks[input], "prev") ~= nil and getSomethingFromTable(getSomethingFromTable(signalBlocks[input], "prev"), "status") ~= 3 then
351
352 --Get the previous signal. Let's set that one to yellow, unless it is already occupied, then don't. Also check if it isn't nil for dumb reasons
353
354 getSomethingFromTable(signalBlocks[input], "prev").status = 2
355 --Now that it's set, let's set the colors right.
356 print("Setting the correct aspect to the previous signal.")
357 bundledIO.setBundledOutput(colors.combine(getSomethingFromTable(signalBlocks[input], "prev").color, colors.yellow))
358
359end
360
361if connectionRemoved then
362if getSomethingFromTable(signalBlocks[input], "prev") ~= "none" and getSomethingFromTable(signalBlocks[input], "prev") ~= nil and getSomethingFromTable(getSomethingFromTable(signalBlocks[input], "prev"), "status") ~= 3 then
363
364 --Get the previous signal. Let's set that one to green, unless it is already occupied, then don't. Also check if it isn't nil for dumb reasons
365
366 getSomethingFromTable(signalBlocks[input], "prev").status = 1
367 --Now that it's set, let's set the colors right.
368 print("Setting the correct aspect to the previous signal.")
369 bundledIO.setBundledOutput(colors.combine(getSomethingFromTable(signalBlocks[input], "prev").color, colors.yellow))
370
371end
372
373end
374
375end
376
377end
378
379local function starts_with(str, start)
380 return str:sub(1, #start) == start
381 end
382
383 local function ends_with(str, ending)
384 return ending == "" or str:sub(-#ending) == ending
385 end
386
387local function powerUpSelfTest()
388
389
390--Okay, host the system via rednet.
391
392--...test for all of them.
393if config.SignalConnectionType == 1 then
394 --rednet.send(72, {71, "test", "test!!!"})
395
396 for key,value in pairs( computerDatabase ) do
397 local send = doEncrypt({funct = "attemptConnection", to = key})
398 print("Attempting connection to "..key)
399 modem.transmit(tonumber(config["ModemChannel"]), tonumber(config["ModemChannel"]), send)
400
401 --Wait for a response, but also there's a timeout.
402 local timeout = os.startTimer(15)
403 while true do
404 local event = {os.pullEvent()}
405 if event[1] == "modem_message" then
406 --Decode the response.
407 local response = doDecrypt(event[5])
408 if response.funct == "ok" then
409 print("Connection to "..response.source.."is okay.")
410 table.insert(clientsDoneInSelfTest, response.source)
411 break
412 end
413 elseif event[1] == "timer" and event[2] == timeout then
414 print("Connection to "..key.." aborted because it took too long.")
415
416 return false
417 end
418
419 end
420
421 end
422
423end
424 return true
425end
426
427
428
429
430
431
432
433---..initalized? Great! now print stuff.
434term.setCursorPos(1,1)
435print(fs.exists("config") )
436if fs.exists("config") then
437local craw = fs.open("config", "r")
438local theconfig = textutils.unserialise(craw.readAll())
439config = theconfig
440craw.close()
441else
442setup()
443end
444term.clear()
445term.setTextColor(colors.green)
446print("PeachMaster's MTC and Digital Interlocking System")
447textutils.slowPrint("TrainControl 1.1", 15)
448print("This copy is for: "..getSomethingFromTable(config, "SystemName"))
449term.setTextColor(colors.white)
450modem.open(tonumber(config["ModemChannel"]))
451modem.open(tonumber(config["TerminalChannel"]))
452if powerUpSelfTest() then
453 print("Power Up Self Test completed succesfully!")
454 while true do
455 controlSignals()
456 end
457
458else
459
460end