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

© Copyright 2019 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
--[[---------------------------------------------------------------------------------------]]
-- This test measures the starting distance of an engine.
-- Set the starting and ending speeds and the starting and ending acceleration rates.
-- The script will run all combinations and print the results.
--
-- Creates a table constructor for insertion into the
-- "LayoutX.lua" scripts for each layout
-- [11] = {[1] = 0.0, [2] = 0.5}
--[[---------------------------------------------------------------------------------------]]
title = "Acceleration Test"

require("defines");

-- Counter Labels
Counter01Label = "Outer Loops";
NO_LOOPS = COUNTER01;
Counter02Label = "No of Starts";
NO_STARTS = COUNTER02;
Counter03Label = "No of Stops";
NO_STOPS = COUNTER03;
-- starting time
DTOStart = 0.0;
-- Program Variables
StartingSpeed = 1;		-- starting engine speed in Smph, normally 1
EndingSpeed = 40;		-- ending engine speed in Smph, normally 40
StartingAccel = 1;		-- beginning acceleration rate, normally 1 or 4
EndingAccel = 1;		-- ending acceleration rate, normally 1 or 4

local MyTIUNo, MyEngineNo;

Accel = StartingAccel;
EngSpeed = StartingSpeed;
Spd = 0;
DTORunning = 0.0;
DTOStopped = 0.0;
EngineSoundSave = -1;
SoundOff = false;
-- keep the noise to a minimum
AutoBell = false;
AutoWhistle = false;

-- state machine states
IDLE = 0;
DONE = 1;
S0 = 2;
S1 = 3;
S2 = 4;
S3 = 5;
S4 = 6;
S5 = 7;
S6 = 8;
-- starting state
SM = IDLE;
LastTime = 0;
--[[---------------------------------------------------------------------------------------]]
function setup(Engine)
--
MyEngineNo = Engine;	-- Engine number selected on the RTC Main window
MyTIUNo = GetTIUNo(MyEngineNo);	-- TIU associated with MyEngineNo 
--
print("setup : TIU " .. MyTIUNo .. " Engine " .. MyEngineNo .. " Debug " .. Debug());
print(string.format("Run Time = %.2f Seconds", RunTime()));
print("Check condition of traction tires before using the results of this script");
Smoke(OFF, 0, MyEngineNo, MyTIUNo);
Name, PS = GetName(MyEngineNo);
print("Engine#" .. MyEngineNo .. " " .. Name .. " PS" .. PS);
Title(title .. " - " .. GetName(MyEngineNo));
StartUp(0, MyEngineNo, MyTIUNo);	-- start selected engine
-- let engine startup
Sleep(15);
-- Stop the Garbage collector since this is a real-time program
collectgarbage("stop")
print("Setup : Garbage Collection stopped");
print("StartingSpeed  " .. StartingSpeed);
print("EndingSpeed  " .. EndingSpeed);
print("StartingAccel  " .. StartingAccel);
print("EndingAccel  " .. EndingAccel);

print(string.format("Run Time = %.2f Seconds", RunTime()));
DTOStart = DTO(MyEngineNo, MyTIUNo);
print(string.format("Trip Odometer Start = %.2f Smiles", DTOStart));
print(string.format("Run Time = %.2f Seconds", RunTime()));
print(string.format("Starting Distance-Smph-Rate------Calc------Starting Time"));
print(string.format("Smiles   Inches        Smph/sec  Smph/Sec    Seconds"));
TableConstructor = "[" .. MyEngineNo .. "] = {";
SM = S0;	-- start the state machine
return true;
end
--[[---------------------------------------------------------------------------------------]]
function loop()
--
--[[---------------------------------------------------------------------------------------]]
-- STATE MACHINE
--[[---------------------------------------------------------------------------------------]]	

--[[---------------------------------------------------------------------------------------]]	
if (SM == IDLE) then	-- do nothing 
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
if (SM == DONE) then	-- finish up
	print("Almost Done...");
	return Stop("DONE");
	end
if (SM == S0) then
	if (Accel > EndingAccel) then
		SM = DONE;
		return true;	-- false=stop calling loop(), true=continue to call loop()
		end
	-- set acceleration value
	Rate(Accel, 1, 0, MyEngineNo, MyTIUNo);
	if(Debug() > 1) then print("S0 : Set acceleration rate to " .. Accel); end;
	SM = S1;
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
if (SM == S1) then
	if (EngSpeed > EndingSpeed) then
		SM = S6;
		return true;	-- false=stop calling loop(), true=continue to call loop()
		end 
	-- Measure time to accelerate to "EngSpeed" Smph
	LastTime = MicroSeconds();
	DTOStopped = DTO(MyEngineNo, MyTIUNo);
	if (DTOStopped == nil) then
		return true;
		end;
	BumpCounter(NO_STARTS);
	Beep();
	Throttle(EngSpeed, 0, MyEngineNo, MyTIUNo);
	if(Debug() > 1) then print("S1 : Set speed to " .. EngSpeed .. " Smph"); end
	SM = S2;
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
		
if (SM == S2) then
	Spd = GetSpeed(MyEngineNo, MyTIUNo);
	if (Spd ~= nil and Spd == EngSpeed) then
		-- Save the time to accelerate to "EngSpeed" Smph in the TableConstructor
		now = MicroSeconds();
		DTORunning = DTO(MyEngineNo, MyTIUNo);
		if (DTORunning == nil) then
			return true;
			end;		
		if(Debug() > 1) then print(string.format("S4 : Trip Odometer at " .. Spd .. " Smph = %.5f Smiles", DTORunning)); end
		Smiles = DTORunning - DTOStopped;
		SFeet = Smiles * 5280.0;
		SInches = SFeet * 12.0;
		Inches = SInches / 48.0;
		-- d = 1/2 a (t^2) from Physics I
		-- a = 2 * d /( t * t)
		delta = (now - LastTime)/ 1000000.0;
		CalcAccel = 2.0 * Smiles * 3600.0 / (delta * delta);	-- Smiles/hr/sec
		print(string.format("%7.5f %5.1f     %2d   %2d        %4.1f        %6.3f", Smiles, Inches, EngSpeed, Accel, CalcAccel, delta));
		TableConstructor = TableConstructor .. "[" .. EngSpeed .. "] = " .. Inches .. ", ";
		Sleep(10);
		SM = S3;
		return true;	-- false=stop calling loop(), true=continue to call loop()
		end
	-- for highest accuracy, check the speed as quickly as possible
	-- stay in S2
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
		
if (SM == S3) then
	BumpCounter(NO_STOPS);
	Beep();
	Throttle(0, 0, MyEngineNo, MyTIUNo);
	if(Debug() > 1) then print("S3 : Set speed to 0"); end
	SM = S4;
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
		
if (SM == S4) then
	Spd = GetSpeed(MyEngineNo, MyTIUNo);
	if (Spd ~= nil and Spd == 0) then
		if(Debug() > 1) then print("S4 : Stopped"); end
		Sleep(5);
		SM = S5;
		return true;	-- false=stop calling loop(), true=continue to call loop()
		end
	-- for highest accuracy, check the speed as quickly as possible
	-- stay in S4
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
	
if (SM == S5) then
	EngSpeed = EngSpeed + 1;
	if(Debug() > 1) then print("S5 : New Engine Speed = " .. EngSpeed); end
	SM = S1;
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
		
if (SM == S6) then
	Accel = Accel + 1;
	EngSpeed = StartingSpeed;
	BumpCounter(NO_LOOPS);
	print(" ");
	if(Debug() > 1) then print("S6 : New acceleration rate = " .. Accel); end
	SM = S0;
	return true;	-- false=stop calling loop(), true=continue to call loop()
	end
print("Invalid State " .. SM);		
return false;	-- false=stop calling loop(), true=continue to call loop()
end
--[[---------------------------------------------------------------------------------------]]
function cleanup()
--
print("cleanup : TIU " .. MyTIUNo .. " Engine " .. MyEngineNo .. " Debug " .. Debug());

SetSpeed(0, 0, MyEngineNo, MyTIUNo);
DTOFinish = DTO(MyEngineNo, MyTIUNo);
-- wait for dispatch list to empty
while(CountDispatchList() > 0) do Sleep(1); end
print(string.format("Run Time = %.2f Seconds", RunTime()));
print(string.format("Trip Odometer Finish = %.2f Smiles", DTOFinish));
-- reset acceleration and deceleration values
Rate(1, 1, 0, MyEngineNo, MyTIUNo);
ShutDown(0, MyEngineNo, MyTIUNo);
if (SoundOff) then
	SoundOnButton(MyEngineNo, MyTIUNo)
	end;
if (TableConstructor ~= nil) then
	TableConstructor = string.sub(TableConstructor, 1, -3) .. "}";	-- remove ending comma
	print (TableConstructor);
	end;
return true;
end
--[[---------------------------------------------------------------------------------------]]
function PTC()
	print(string.format("Run Time = %.2f Seconds", RunTime()));
	print(TableConstructor);
	return true;
end
Function01Name, Function01Label = PTC, "Table Constructor";
--[[---------------------------------------------------------------------------------------]]
function ShowDTO()
	print(string.format("Run Time = %.2f Seconds", RunTime()));
	print(string.format("Trip Odometer = %.2f Smiles", DTO(MyEngineNo, MyTIUNo)));
	return true;
end
Function10Name, Function10Label = ShowDTO, "Trip Odometer";
--[[---------------------------------------------------------------------------------------]]

--[[---------------------------------------------------------------------------------------]]
function SoundOffButton()
	print("Sound Off Button()");
	SD = GetVolume(MASTER_VOLUME, MyEngineNo, MyTIUNo);	-- get Volume
	if (SD == nil) then
		return Stop("GetVolume() failed in SoundOffButton()");
		end; 
	if (SD == 0) then SD = 30; end;	
	print(" Sound Off - Engine " .. MyEngineNo .. " Level was " .. SD);
	EngineSoundSave = SD;
	SoundOff = true;
	SetVolume(MASTER_VOLUME, 0, 0, MyEngineNo, MyTIUNo);
	return true;
end
Function04Name, Function04Label = SoundOffButton, "Sound Off";
--[[---------------------------------------------------------------------------------------]]
function SoundOnButton()
	print("Sound On Button()");
	if (SoundOff) then
		SD = EngineSoundSave;		
		print(" Sound On - Engine " .. MyEngineNo .. " Level restored to " .. SD);
		SoundOff = false;;
		SetVolume(MASTER_VOLUME, SD, 0, MyEngineNo, MyTIUNo);
		if (SD == nil) then
			return Stop("GetVolume() failed in SoundOnButton()");
			end			
		end;
	return true;
end
Function05Name, Function05Label = SoundOnButton, "Sound On";
--[[---------------------------------------------------------------------------------------]]
--[[
---------------------------------------------------------------------------
Success compiling C:\trains\MTH\PC Control\Scripts\Acceleration Test.lua
setup : TIU 1 Engine 12 Debug 0
Run Time = 0.00 seconds
Engine#12 P&LE GP38-2#2057 PS3
Run Time = 15.00 seconds
Trip Odometer Start 0.00 Smiles
Run Time = 15.80 seconds
Starting Distance-Smph-Rate------Calc------Starting Time
Smiles   Inches        Smph/sec  Smph/Sec    Seconds
0.00000   0.0      1    1         0.0         0.798
0.00000   0.0      2    1         0.0         0.713
0.00018   0.2      3    1         0.9         1.199
0.00040   0.5      4    1         2.2         1.156
0.00089   1.2      5    1         2.1         1.727
0.00124   1.6      6    1         2.5         1.905
0.00170   2.2      7    1         2.8         2.102
0.00221   2.9      8    1         3.5         2.143
0.00323   4.3      9    1         3.1         2.731
0.00360   4.8     10    1         3.1         2.885
0.00485   6.4     11    1         3.2         3.294
0.00554   7.3     12    1         3.3         3.497
0.00629   8.3     13    1         3.3         3.679
0.00778  10.3     14    1         3.4         4.087
0.00842  11.1     15    1         3.4         4.208
0.01010  13.3     16    1         3.8         4.374
0.01040  13.7     17    1         3.4         4.661
0.01186  15.7     18    1         3.5         4.922
0.01354  17.9     19    1         3.5         5.264
0.01570  20.7     20    1         3.6         5.607
0.01698  22.4     21    1         3.6         5.824
0.01861  24.6     22    1         3.6         6.091
0.01918  25.3     23    1         3.6         6.192
0.02157  28.5     24    1         3.8         6.363
0.02401  31.7     25    1         3.6         6.913
0.02524  33.3     26    1         3.7         7.026
0.02739  36.1     27    1         3.9         7.150
0.02934  38.7     28    1         3.7         7.578
0.03160  41.7     29    1         3.7         7.873
0.03432  45.3     30    1         3.9         7.992
0.03484  46.0     31    1         3.7         8.251
0.03813  50.3     32    1         3.7         8.607
0.03953  52.2     33    1         3.7         8.770
0.04282  56.5     34    1         3.7         9.120
0.04510  59.5     35    1         3.7         9.381
0.04791  63.2     36    1         3.8         9.468
0.05089  67.2     37    1         3.7         9.891
0.05243  69.2     38    1         3.9         9.848
0.05518  72.8     39    1         3.7        10.300
0.05862  77.4     40    1         3.7        10.617
 
Almost Done...
DONE
cleanup : TIU 1 Engine 12 Debug 0
Run Time = 945.90 seconds
Trip Odometer Finish 1.71 Smiles
[12] = {[1] = 0.0055460553681194, [2] = 0.0, [3] = 0.24402643619725, [4] = 0.53242131533946, [5] = 1.1757637380413, [6] = 1.6360863335952, [7] = 2.2461524240884, [8] = 2.9227711789989, [9] = 4.2593705227157, [10] = 4.7529694504783, [11] = 6.4056939501779, [12] = 7.3097009751814, [13] = 8.3024448860748, [14] = 10.271294541757, [15] = 11.108748902343, [16] = 13.332717104959, [17] = 13.732033091464, [18] = 15.650968248833, [19] = 17.869390396081, [20] = 20.720062855294, [21] = 22.417155797939, [22] = 24.563479225401, [23] = 25.317742755465, [24] = 28.467902204557, [25] = 31.690160373434, [26] = 33.315154596293, [27] = 36.149188889402, [28] = 38.72255858021, [29] = 41.706336368258, [30] = 45.3001802468, [31] = 45.993437167814, [32] = 50.335998521052, [33] = 52.177288903268, [34] = 56.525396311873, [35] = 59.536904376762, [36] = 63.247215418034, [37] = 67.173822618662, [38] = 69.209224938762, [39] = 72.841891204881, [40] = 77.38411055137}

---------------------------------------------------------------------------]]
