--[[
---------------------------------------------------------------------------
Remote Train Control Program for Windows

© Copyright 2025 by Mark DiVecchio

	This file is part of Remote Train Control.

	Remote Train Control is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	Remote Train Control is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with Remote Train Control.  If not, see <http://www.gnu.org/licenses/>.

 Home Page : http://www.silogic.com/trains/RTC_Running.html
---------------------------------------------------------------------------]]
-- Semicolons are not required in Lua code
title = "Layout4 EB Block Occupancy Test"
require([[defines]]);
require([[functions]]);
--[[
Purpose: This test generates tags using SetEvent(). The tags are sent
to "Layout4 APB Master.lua" which controls the signals. It simulates
a train going around the layout and causes the signals to be set appropriately.
]]
--[[
When using this module, all variables (including functions!) must be declared through 
a regular assignment (even assigning nil will do) in a strict scope before being used 
anywhere or assigned to inside a nested scope.
https://github.com/lua-stdlib/strict
]]
local _ENV = require 'std.strict' (_G)	-- strict.lua will detect undeclared global variables

local ErrCount = 0;
local Layout4;
-- OCCUPIED is any value greater than zero
local OCCUPIED = 1;  -- Occupied
local PauseOn = false;
local StepTime = 3;
local MyEngineNo = 8;
local MyDirection = EB;
local OFlag, EFlag;

--[[---------------------------------------------------------------------------------------]]
function setup(Engine, TIU)
	print("setup() Running");	
	-- Instrumented Layout 4
	Layout4 = require([[Layout4]]);		-- All of the details about the Layout
if (Layout4.LLLoop == true) then
	print("Balloon Loop");
	else
	return Stop("Point-to-Point layout set - Balloon Loop Required");
	end;
	
	print([[Run "Layout4 APB Master.lua" in PC windows #1 (don't set any block occupied)]]);
	print("Run this Script in a PC window other than #1");
	MyEngineNo = Engine;
	ClearButton(MyEngineNo, TIU);			-- clear all program flags
	OFlag = 1;
	EFlag = MyEngineNo | (MyDirection << 8);
	-- start in Aliquippa Block
	print("Start in the Aliquippa Block, heading " .. DirectionNames[MyDirection] .. " toward McKees Rocks");
	SetOccupancy(ALIQUIPPA_BLOCK, EFlag);	-- set occupancy flag using TrySetFlag() includes direction and engine number
	SetEvent(1, BLOCK_OCCUPANCY_EVENT, ALIQUIPPA_BLOCK, OFlag);	-- set next BlockOccupancy[] in Layout4 APB Master.lua
	print([[SetEvent() calls simulate a tag detection (TAG_EVENT) to the Layout4 APB Master.lua" script]]);
	return true;		-- false=setup failed, true=setup succeeded
end;
--[[---------------------------------------------------------------------------------------]]
function loop(Engine, TIU)
	-- Always call Sleep(X) at least once in this function if it returns true;
	print("loop() Running " .. DirectionNames[MyDirection] .. "  at ", RunTime(), " seconds");
	local res;
	-- using events, cause "Layout4 APB Master.lua" to run a simulated train around the layout
	--
	-- This script always starts in ALIQUIPPA_BLOCK going eastbound
	-- EB sidings are PASSING/STATION
	--
	-- this runs a train by generating a TAG_EVENT just as if a tag passed over a tag reader
	--  SetEvent(1, TAG_EVENT, detector, reader, 1 for Engine or 0 for Caboose)
	--
	local ENGINE_TAG_EVENT = 1;
	local CABOOSE_TAG_EVENT = 0;
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
	res = SetEvent(1, TAG_EVENT, ALIQUIPPA_WEST_DETECTOR, ALIQUIPPA_WEST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
		SetOccupancy(J_L_PASSING_TRACK, EFlag);
	if (type(res) ==  "nil") then
		print("Layout4 APB Master.lua not running in PC#1");
		return Stop("DONE");
		end;		
	Switch(REVERSE, Switches[ALIQUIPPA_WEST][CHAN_NUMBER], Switches[ALIQUIPPA_WEST][AIU_NUMBER], Switches[ALIQUIPPA_WEST][TIU_NUMBER], 0);
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, ALIQUIPPA_WEST_DETECTOR, ALIQUIPPA_WEST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(ALIQUIPPA_BLOCK, EFlag);
	Switch(NORMAL,  Switches[ALIQUIPPA_WEST][CHAN_NUMBER], Switches[ALIQUIPPA_WEST][AIU_NUMBER], Switches[ALIQUIPPA_WEST][TIU_NUMBER], 0)
	
	-- repeat for each block around the layout
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(MCKEES_ROCKS_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, ALIQUIPPA_EAST_DETECTOR, ALIQUIPPA_EAST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Switch(REVERSE, Switches[ALIQUIPPA_EAST][CHAN_NUMBER], Switches[ALIQUIPPA_EAST][AIU_NUMBER], Switches[ALIQUIPPA_EAST][TIU_NUMBER], 0)
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, ALIQUIPPA_EAST_DETECTOR, ALIQUIPPA_EAST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(J_L_PASSING_TRACK, EFlag);
	Switch(NORMAL,  Switches[ALIQUIPPA_EAST][CHAN_NUMBER], Switches[ALIQUIPPA_EAST][AIU_NUMBER], Switches[ALIQUIPPA_EAST][TIU_NUMBER], 0);
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(LIONEL_IVES_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, MCKEES_ROCKS_REPAIR_SHOPS_YARD_DETECTOR, MCKEES_ROCKS_REPAIR_SHOPS_YARD_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, MCKEES_ROCKS_REPAIR_SHOPS_YARD_DETECTOR, MCKEES_ROCKS_REPAIR_SHOPS_YARD_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(MCKEES_ROCKS_BLOCK, EFlag);
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(YOUNGSTOWN_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, GATEWAY_YARD_DETECTOR, GATEWAY_YARD_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, GATEWAY_YARD_DETECTOR, GATEWAY_YARD_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(LIONEL_IVES_BLOCK, EFlag);
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(STRUTHERS_STATION_TRACK, EFlag);
	res = SetEvent(1, TAG_EVENT, STRUTHERS_WEST_DETECTOR, STRUTHERS_WEST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Switch(REVERSE, Switches[STRUTHERS_WEST][CHAN_NUMBER], Switches[STRUTHERS_WEST][AIU_NUMBER], Switches[STRUTHERS_WEST][TIU_NUMBER], 0)
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, STRUTHERS_WEST_DETECTOR, STRUTHERS_WEST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(YOUNGSTOWN_BLOCK, EFlag);
	Switch(NORMAL, Switches[STRUTHERS_WEST][CHAN_NUMBER], Switches[STRUTHERS_WEST][AIU_NUMBER], Switches[STRUTHERS_WEST][TIU_NUMBER], 0)
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(LOWELLVILLE_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, STRUTHERS_EAST_DETECTOR, STRUTHERS_EAST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Switch(REVERSE, Switches[STRUTHERS_EAST][CHAN_NUMBER], Switches[STRUTHERS_EAST][AIU_NUMBER], Switches[STRUTHERS_EAST][TIU_NUMBER], 0)
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, STRUTHERS_EAST_DETECTOR, STRUTHERS_EAST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(STRUTHERS_STATION_TRACK, EFlag);
	Switch(NORMAL, Switches[STRUTHERS_EAST][CHAN_NUMBER], Switches[STRUTHERS_EAST][AIU_NUMBER], Switches[STRUTHERS_EAST][TIU_NUMBER], 0)
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(NEW_CASTLE_JUNCTION_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, LOWELLVILLE_DETECTOR, LOWELLVILLE_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, LOWELLVILLE_DETECTOR, LOWELLVILLE_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(LOWELLVILLE_BLOCK, EFlag);
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(COLLEGE_STATION_TRACK, EFlag);
	res = SetEvent(1, TAG_EVENT, COLLEGE_WEST_DETECTOR, COLLEGE_WEST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Switch(REVERSE, Switches[COLLEGE_WEST][CHAN_NUMBER], Switches[COLLEGE_WEST][AIU_NUMBER], Switches[COLLEGE_WEST][TIU_NUMBER], 0)
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, COLLEGE_WEST_DETECTOR, COLLEGE_WEST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(NEW_CASTLE_JUNCTION_BLOCK, EFlag);
	Switch(NORMAL, Switches[COLLEGE_WEST][CHAN_NUMBER], Switches[COLLEGE_WEST][AIU_NUMBER], Switches[COLLEGE_WEST][TIU_NUMBER], 0)
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(BEAVER_FALLS_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, COLLEGE_EAST_DETECTOR, COLLEGE_EAST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Switch(REVERSE, Switches[COLLEGE_EAST][CHAN_NUMBER], Switches[COLLEGE_EAST][AIU_NUMBER], Switches[COLLEGE_EAST][TIU_NUMBER], 0)
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, COLLEGE_EAST_DETECTOR, COLLEGE_EAST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(COLLEGE_STATION_TRACK, EFlag);
	Switch(NORMAL, Switches[COLLEGE_EAST][CHAN_NUMBER], Switches[COLLEGE_EAST][AIU_NUMBER], Switches[COLLEGE_EAST][TIU_NUMBER], 0)
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(FALLSTON_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, FALLSTON_DETECTOR, FALLSTON_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, FALLSTON_DETECTOR, FALLSTON_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(BEAVER_FALLS_BLOCK, EFlag);		
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(MONACA_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, MONACA_WEST_DETECTOR, MONACA_WEST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, MONACA_WEST_DETECTOR, MONACA_WEST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(FALLSTON_BLOCK, EFlag);
	--	
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(WEST_ALIQUIPPA_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, MONACA_EAST_DETECTOR, MONACA_EAST_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, MONACA_EAST_DETECTOR, MONACA_EAST_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(MONACA_BLOCK, EFlag);	
	--
	Sleep(StepTime);
	while (PauseOn) do Sleep(1); end;
		SetOccupancy(ALIQUIPPA_BLOCK, EFlag);
	res = SetEvent(1, TAG_EVENT, WEST_ALIQUIPPA_DETECTOR, WEST_ALIQUIPPA_READER, ENGINE_TAG_EVENT);	-- Engine detected - set next block occupancy
	Sleep(StepTime);
	res = SetEvent(1, TAG_EVENT, WEST_ALIQUIPPA_DETECTOR, WEST_ALIQUIPPA_READER, CABOOSE_TAG_EVENT);	-- Caboose detected - clear current block occupancy
		ClearOccupancy(WEST_ALIQUIPPA_BLOCK, EFlag);	
	--	
	-----------------------------------------
	--print("Paused at end of test");
	--while (not PauseOn) do Sleep(1); end;
	
	return true;		-- all of the code runs in the loop()
end;
--[[---------------------------------------------------------------------------------------]]

function cleanup(Engine, TIU)
	-- this function is called once when the user presses the [STOP] button or the Stop() function is called
	print("cleanup() Running");
	if (ErrCount == 0) then
		print("No errors");
		else
		print(ErrCount .. " Error(s)");
		end;	
	return true;		-- false=cleanup failed, true=cleanup succeeded
	end
--[[---------------------------------------------------------------------------------------]]

function PZ()
	if (PauseOn) then
		print("...Resumed");
		PauseOn = false;
		else
		print("Paused...");
		PauseOn = true;
		end;
	return true;
end
Function01Name, Function01Label = PZ, "Pause/Resume";
--[[---------------------------------------------------------------------------------------]]
function ClearButton(Eng, TIU)
print("Clear Occupancy Flags");
-- clear occupancy flags
local x;
for x = FIRST_BLOCK, LAST_BLOCK do
	OverrideOccupancy(x, 0);
	end;
print("Occupancy Flags cleared");
return true;
end
Function02Name, Function02Label = ClearButton, "Clear Flags";
--[[---------------------------------------------------------------------------------------]]
function StepUp()
	StepTime = StepTime + 1;
	print ("StepTime = " .. StepTime);
	return true;
end
Function06Name, Function06Label = StepUp, "StepTime ++";
--[[---------------------------------------------------------------------------------------]]
function StepDn()
	if (StepTime > 0) then StepTime = StepTime - 1; end;
	print ("StepTime = " .. StepTime);
	return true;
end
Function07Name, Function07Label = StepDn, "StepTime --";
--[[---------------------------------------------------------------------------------------]]
