diff options
Diffstat (limited to 'init_code.lua')
-rw-r--r-- | init_code.lua | 453 |
1 files changed, 452 insertions, 1 deletions
diff --git a/init_code.lua b/init_code.lua index 313075b..e44819e 100644 --- a/init_code.lua +++ b/init_code.lua @@ -37,4 +37,455 @@ end function F.timedisplay() digiline_send("time", "Time: | "..rwt.to_string(rwt.now(),true).." | "..os.date("%H:%M:%S")) schedule(rwt.next_rpt(rwt.now(),5,0), "") -end
\ No newline at end of file +end + +-- Stat counter and timetaking utilities +-- Stat from subway +F.stat=function(line, init) +--statistics +-- init +if init then +reftrain = atc_id +a_tbt = 30 +a_tbtmax = 30 +a_rtt = 500 +a_not = 0 +c_not = 0 +c_tbtmax = 0 +time_lt = os.time() +time_rt=os.time() +end +if not a_tbtmax then a_tbtmax = 30 end +if not c_tbtmax then c_tbtmax = 0 end +--real code +if event.train then +local time = os.time() +c_not = c_not + 1 +a_tbt = (a_tbt + (time - time_lt)) / 2 +c_tbtmax = math.max(c_tbtmax, (time - time_lt)) +if atc_id == reftrain then + a_rtt = (a_rtt*0.2 + (time - time_rt)*0.8) + a_not = c_not + c_not = 0 + a_tbtmax = (a_tbtmax + c_tbtmax) / 2 + c_tbtmax = 0 +end + digiline_send("stats", "Stat: "..line.. + " NoT:"..a_not.."("..c_not..")".. + " TbT:"..math.floor(a_tbt).."("..(time-time_lt)..")".. + " Tmx:"..math.floor(a_tbtmax).."("..c_tbtmax..")".. + " R:"..math.floor(a_rtt).."("..(time - time_rt)..")" + ) +time_lt = time +if atc_id == reftrain then + time_rt = time +end +end +end + +S.timetake = {} +function F.timetake_start(ttname) + if not atc_id then return end + local nouw = rwt.to_secs(rwt.now()) + if not S.timetake[ttname] then + S.timetake[ttname] = {} + end + S.timetake[ttname][atc_id] = nouw +end + +--L100 +function F.timetake_end(ttname) + if not atc_id then return end + if not S.timetake[ttname] or not S.timetake[ttname][atc_id] then + digiline_send("timetake", "No start time for "..atc_id) + return + end + local first = S.timetake[ttname][atc_id] + local nouw = rwt.to_secs(rwt.now()) + local tdiff = nouw - first + local cavg = S.timetake[ttname].avg + local cmax = S.timetake[ttname].max + local cmin = S.timetake[ttname].min + if cavg and cmax and cmin then + S.timetake[ttname].avg = tdiff*0.1 + cavg*0.9 + S.timetake[ttname].min = math.min(tdiff, cmin) + S.timetake[ttname].max = math.max(tdiff, cmax) + else + S.timetake[ttname].avg = tdiff + S.timetake[ttname].min = tdiff + S.timetake[ttname].max = tdiff + end + digiline_send("timetake", ttname.. + " this:"..tdiff.. + " min:"..math.floor(S.timetake[ttname].min).. + " avg:"..math.floor(S.timetake[ttname].avg).. + " max:"..math.floor(S.timetake[ttname].max) + ) + +end + +--== Timetable prototype (TTP) === +--[[ table structures: +F.ttp - static timetable data - see below +S.ttp[tt_name] = { - dynamic tt data + recording_train = <id of the train that is recording travel times, or nil> + travel_times = { + <station name> = <time in seconds from initial departure at first station of the line to departure at this station> + } + station_order = { <station 1>, <station 2>...} +} +S.ttt[train_id] = { - trains + timetable = <timetable ID that the train is currently using>, + initial_dep = <departure at first station of the line>, + location = <Station where the train was last seen>, + desired_dep = <Departure time as in timetable>, + planned_dep = <real departure time calculated as the train reaches station>, + actual_dep = <actual departure time at last station. is nil while train is stopped>, + last_delay = <last known delay of the train - calculated every departure>, + } +} +]] + +local STOP_TIME = 10 +local DEPCMD="A1OCD1SM" +local RDEPCMD="RA1OCD1SM" + +if not S.ttp then S.ttp = {} end +if not S.ttt then S.ttt = {} end +F.ttp={ + CFE_N = { + outside_text = "[CFE] Warmoneaye\nvia Ehlodex, Personhood West, Crystal Farms", + inside_line_desc = "CFE to Warmoneaye", + stn_display = "CFE Warmoneaye", + }, + CFE_S = { + outside_text = "[CFE] Origin\nvia Crystal Farms, Personhood West, Ehlodex", + inside_line_desc = "CFE to Origin", + stn_display = "CFE Origin", + }, + NRG_E = { + outside_text = "[NRG] Azena Transirejo", + inside_line_desc = "NRG to Azena Transirejo", + stn_display = "NRG Azena Transirejo", + }, + NRG_W = { + outside_text = "[NRG] New Roses Gardens", + inside_line_desc = "NRG to New Roses Gardens", + stn_display = "NRG New Roses Gardens", + }, + NX_S = { + outside_text = "[NX] Trisiston\nvia Personhood West, Ehlodex, South Forest, Melinka", + inside_line_desc = "NX to Trisiston", + stn_display = "NX Trisiston", + }, + E1_S = { + outside_text = "[E1] Melinka\nvia The Cube, Ehlodex, Spawn Main, Mom Junction", + inside_line_desc = "E1 to Melinka", + stn_display = "E1 Melinka", + }, + testing = { + outside_text = "[testing] Sued via Mitte", + inside_line_desc = "[testing] Sued", + }, + +} + +--[[ +Timetable entry point. The train finalizes its last timetable and +registers itself on the given timetable instance. It departs at the next time slot +(given by interval and offset). +F.ttp_begin({ + stn = "Warmoneaye", -- station name + tt = "CFE_S", -- timetable ID + depint = "05;00", --departure slot interval + depoff = "00;00", --departure slot offset + doorside = "L", + reverse = true, + only_lines = nil, --if given a table, only trains where only_lines[get_line()] is true are considered + force_tt_reset = false, -- force reset of travel times for this timetable +}) +]] +-- Make train depart at the next time slot, and save its start time +function F.ttp_begin(p) + __approach_callback_mode = 1 + + if not F.ttp[p.tt] then error("No TT instance "..p.tt) end + if not atc_id or not atc_arrow then return end + if p.only_lines and not p.only_lines[get_line()] then return end + if not S.ttp[p.tt] then S.ttp[p.tt] = {} end + local tti = S.ttp[p.tt] +--L150 + if event.approach and not event.has_entered then + -- make the train stop + atc_set_ars_disable(true) + atc_set_lzb_tsr(2) + atc_set_text_inside("Next stop: "..p.stn.."\nTerminal Station.\nThis train continues as "..F.ttp[p.tt].inside_line_desc) + end + if event.train then + -- train arrived, planning departure + atc_send("B0 W O"..p.doorside) + + local time_now = rwt.now() + -- Train might have had another TT before, do the cleanup from ttp_end here. + local trno = S.ttt[atc_id] + if trno then + local ttio = S.ttp[trno.timetable] + if ttio.recording_train == atc_id then + ttio.travel_times[p.stn] = rwt.diff(trno.initial_dep, time_now) + ttio.station_order[#ttio.station_order+1] = p.stn + end + end + local next_dep_time = rwt.next_rpt(rwt.add(time_now, 10), p.depint, p.depoff) + schedule(next_dep_time, "departure") + S.ttt[atc_id] = { + timetable = p.tt, + initial_dep = next_dep_time, + location = p.stn, + desired_dep = next_dep_time, + planned_dep = next_dep_time, + last_delay = 0, + } + -- if no travel times are available yet, set this train as recording + if not tti.travel_times or p.force_tt_reset then + tti.travel_times = {} + tti.station_order = {p.stn} + tti.recording_train = atc_id + elseif tti.recording_train == atc_id then + tti.recording_train = nil + end + atc_set_text_outside(F.ttp[p.tt].outside_text) + atc_set_text_inside(p.stn.."\nAa: " + ..rwt.to_string(time_now, true).." Da: " + ..rwt.to_string(next_dep_time, true)) + end + if event.schedule then + -- departure. save actual departure time in tt + S.ttt[atc_id].actual_dep = rwt.now() + local delay = rwt.diff(S.ttt[atc_id].desired_dep, S.ttt[atc_id].actual_dep) + atc_set_text_inside(F.ttp[p.tt].inside_line_desc + .."\nDelay:"..rwt.to_string(delay, true)) + S.ttt[atc_id].last_delay = delay + if p.reverse then + atc_send(RDEPCMD) + else + atc_send(DEPCMD) + end + end +end +--[[ +Generic stop on timetable. Any train that has a TT instance registered +stops here, waits STOP_TIME and continues. Behavior can be altered by options: +F.ttp_stop({ + stn = "Personhood West", -- station name + doorside = "L", + only_lines = nil, --if given a table, only trains where only_lines[get_line()] is true are considered + end_of_tt = { TT_ID = true }, + -- if present and key is true for a TT identifier, this is the last station on this timetable. Trains will stop recording timetable and be deregistered. + departure = { TT_ID = RWT relative to initial departure } + -- If present, override desired departure time. Defaults to travel time + STOP_TIME if not provided +}) +]]function F.ttp_stop(p) + -- set my approach callback mode + __approach_callback_mode = 1 + if not atc_id or not atc_arrow then return end + if not S.ttt[atc_id] then return end + if p.only_lines and not p.only_lines[get_line()] then return end + local trn = S.ttt[atc_id] + local tt = trn.timetable + if not F.ttp[tt] then + S.ttt[atc_id] = nil + end + local tti = S.ttp[tt] + if event.approach and not event.has_entered then + -- make the train stop + atc_set_ars_disable(true) + atc_set_lzb_tsr(2) + atc_set_text_inside("Next stop: "..p.stn) + end + if event.train then + -- train arrived, planning departure + atc_send("B0 W O"..p.doorside) + local time_now = rwt.now() + -- update our location and determine desired and planned departure +--L200 + local next_dep_time = rwt.add(time_now, STOP_TIME) + trn.location = p.stn + trn.desired_dep = nil + trn.actual_dep = nil + + -- calculate desired departure nouw + if p.departure and p.departure[tt] then + trn.desired_dep = rwt.add(trn.initial_dep or 0, + p.departure[tt]) + elseif tti.travel_times[p.stn] then + trn.desired_dep = rwt.add(trn.initial_dep or 0, + tti.travel_times[p.stn] + STOP_TIME) + end + + if trn.desired_dep then + -- if we had a source for desired departure, update planned daparture time + if rwt.to_secs(next_dep_time) < rwt.to_secs(trn.desired_dep) then + -- don't depart before the planned departure time + next_dep_time = trn.desired_dep + end + atc_set_text_inside(p.stn.."\nAa " + ..rwt.to_string(time_now, true).." Dd" + ..rwt.to_string(trn.desired_dep, true).." Da" + ..rwt.to_string(next_dep_time, true)) + else + atc_set_text_inside(p.stn.."\nAa " + ..rwt.to_string(time_now, true).." Dd ? Da" + ..rwt.to_string(next_dep_time, true)) + end + + if tti.recording_train == atc_id then + -- we are recording. save travel time + tti.travel_times[p.stn] = rwt.diff(trn.initial_dep or 0, time_now) + tti.station_order[#tti.station_order+1] = p.stn + atc_set_text_inside(p.stn.."\nRec TT " + ..rwt.to_string(tti.travel_times[p.stn], true).." Da" + ..rwt.to_string(next_dep_time, true)) + end + + trn.planned_dep = next_dep_time + schedule(next_dep_time, "departure") + end + if event.schedule then + -- departure. save actual departure time in tt + trn.actual_dep = rwt.now() + local delay = rwt.diff(trn.desired_dep or trn.actual_dep, trn.actual_dep) + atc_set_text_inside(F.ttp[tt].inside_line_desc + .."\nDelay:"..rwt.to_string(delay, true)) + S.ttt[atc_id].last_delay = delay + atc_send(DEPCMD) + if p.end_of_tt and p.end_of_tt[tt] then + -- end of timetable. Deregister train + if tti.recording_train == atc_id then + tti.recording_train = nil + end + S.ttt[atc_id] = nil + end + end +end + + +function F.ttp_info_times(tt, starttime) + --L307 + local ttf = F.ttp[tt] + local tti = S.ttp[tt] + local p = {} + if tti.recording_train then + p[#p+1] = ("recording "..tti.recording_train) + end + p[#p+1] = ("Di "..rwt.to_string(starttime, true).." "..tti.station_order[1]) + for i=2,#tti.station_order do + local ap = rwt.add(starttime, tti.travel_times[tti.station_order[i]]) + p[#p+1] = ("Ap "..rwt.to_string(ap, true).. + " Dp "..rwt.to_string(rwt.add(ap, STOP_TIME), true).. + " "..tti.station_order[i]) + end + return p +end +function F.ttp_info_trains(tt, starttime) + --L307 + local ttf = F.ttp[tt] + local tti = S.ttp[tt] + local p = {} + for tid,trn in pairs(S.ttt) do + if trn.timetable==tt then + if trn.actual_dep then + p[#p+1] = ("Trn "..tid.. + " after "..trn.location.. + " Dd "..rwt.to_string(trn.desired_dep, true).. + " Da "..rwt.to_string(trn.actual_dep, true).. + " Delay "..rwt.to_string(trn.last_delay)) + else + p[#p+1] = ("Trn "..tid.. + " at "..trn.location.. + " Dd "..rwt.to_string(trn.desired_dep, true).. + " Delay "..rwt.to_string(trn.last_delay)) + end + end + end + return p +end + + + +--[[F.ttp_station_display({ + lines = {"CFE_S", "NX_S", "E1_S"}, + departure = {}, + station = "The Cube", + title = "The Cube (Track 2)", + interval = 30, + display1 = "display1", + display2 = "display2", +}]] +function F.ttp_station_display(p) +--L425 +-- { dep, text } +local next_trains = {} +local function is_past_station(tstn, stnorder) + for _,s in ipairs(stnorder) do + if s==p.station then return true end + if s==tstn then return false end + end + return true +end +local function add_train(deptime, line) + local tent = {dep = deptime, text = + rwt.to_string(deptime,true).." "..F.ttp[line].stn_display} + for i,ntrn in ipairs(next_trains) do + if rwt.diff(ntrn.dep, deptime)<0 then + table.insert(next_trains, i, tent) + return + end + end + table.insert(next_trains, tent) +end + +for _,line in ipairs(p.lines) do + local fttp = F.ttp[line] + local sttp = S.ttp[line] + -- find all trains on this line + for id, train in pairs(S.ttt) do + if train.timetable == line then + if train.location == p.station and not train.actual_dep then + -- the train is currently standing at this station + add_train(train.planned_dep, line) + elseif not is_past_station(train.location, sttp.station_order) then + -- train is still approaching, calculate arrival time + local trav_dep = rwt.add(train.initial_dep, (sttp.travel_times[p.station] or 0) + STOP_TIME) + local act_dep = rwt.add(trav_dep, train.last_delay) + if p.departure and p.departure[line] then + local plan_dep = rwt.add(train.initial_dep, p.departure[line]) + if rwt.to_secs(act_dep) < rwt.to_secs(plan_dep) then + act_dep = plan_dep + end + end + add_train(act_dep, line) + end + end + end +end + +-- make output +local i +local text1 = p.title .. " * "..rwt.to_string(rwt.now(), true).." * " +for i=1,3 do + if next_trains[i] then + text1 = text1 .. "\n".. next_trains[i].text + end +end +digiline_send(p.display1, text1) +if p.display2 then + local text2 = "" + for i=4,7 do + if next_trains[i] then + text2 = text2 .. next_trains[i].text .. "\n" + end + end + digiline_send(p.display2, text2) +end +schedule_in(p.interval or 30,"foo") +end |