///|
pub(all) struct SectionalReleaseResult {
sections_unlocked : Array[@topology.TrackId]
switches_unlocked : Array[@topology.TurnoutId]
is_route_completed : Bool
} derive(Debug)
///|
fn ActiveRouteState::observe_occupancy(
self : ActiveRouteState,
station : @topology.Station,
) -> Unit {
let had_observed_entry = if self.rule.track_sections.length() == 0 {
false
} else {
self.was_occupied(self.rule.track_sections[0])
}
let mut index = 0
while index < self.rule.track_sections.length() {
let track_id = self.rule.track_sections[index]
match station.graph.get_track(track_id) {
Some(track) =>
if track.state == Occupied {
if track_id.id >= 0 && track_id.id < 256 {
self.occupied_sections[track_id.id] = true
}
if index > self.highest_observed_section_index + 1 {
self.occupancy_order_violation = true
}
if index > 0 && !had_observed_entry {
self.occupancy_order_violation = true
}
if index > self.highest_observed_section_index {
self.highest_observed_section_index = index
}
if track.occupying_train_id != "" {
if self.observed_train_id == "" {
self.observed_train_id = track.occupying_train_id
} else if self.observed_train_id != track.occupying_train_id {
self.occupancy_order_violation = true
}
}
if index == 0 {
let _ = station.set_signal_aspect(self.rule.entry_signal, Red)
self.state = TrainInRoute
self.release_stage = StageEntrySectionOccupied
}
}
None => ()
}
index = index + 1
}
}
///|
fn ActiveRouteState::was_occupied(
self : ActiveRouteState,
track_id : @topology.TrackId,
) -> Bool {
if track_id.id < 0 || track_id.id >= 256 {
false
} else {
self.occupied_sections[track_id.id]
}
}
///|
fn ActiveRouteState::was_unlocked(
self : ActiveRouteState,
track_id : @topology.TrackId,
) -> Bool {
if track_id.id < 0 || track_id.id >= 256 {
false
} else {
self.unlocked_sections[track_id.id]
}
}
///|
fn ActiveRouteState::can_release_section(
self : ActiveRouteState,
station : @topology.Station,
index : Int,
) -> Bool {
let sections = self.rule.track_sections
let current_id = sections[index]
if self.occupancy_order_violation {
return false
}
let current_clear = match station.graph.get_track(current_id) {
Some(track) => track.state == Clear
None => false
}
if !current_clear || !self.was_occupied(current_id) {
return false
}
if index == 0 {
if self.state != TrainInRoute {
return false
}
if sections.length() == 1 {
return true
}
let next_id = sections[1]
match station.graph.get_track(next_id) {
Some(next_track) =>
next_track.state == Occupied ||
(next_track.state == Clear && self.was_occupied(next_id))
None => false
}
} else {
let previous_id = sections[index - 1]
self.was_unlocked(previous_id)
}
}
///|
fn ActiveRouteState::mark_released(
self : ActiveRouteState,
track_id : @topology.TrackId,
index : Int,
) -> Unit {
if track_id.id >= 0 && track_id.id < 256 {
self.unlocked_sections[track_id.id] = true
}
if index == 0 {
self.release_stage = StageEntrySectionOccupied
} else if index == self.rule.track_sections.length() - 1 {
self.release_stage = StageExitSectionOccupied
} else {
self.release_stage = StageMiddleSectionOccupied
}
}
///|
fn ActiveRouteState::all_sections_released(self : ActiveRouteState) -> Bool {
for track_id in self.rule.track_sections {
if !self.was_unlocked(track_id) {
return false
}
}
true
}
///|
pub fn InterlockingTable::process_sectional_release(
self : InterlockingTable,
station : @topology.Station,
route_id : RouteId,
) -> SectionalReleaseResult {
let unlocked_sections : Array[@topology.TrackId] = []
let unlocked_switches : Array[@topology.TurnoutId] = []
match self.get_active_route(route_id) {
None =>
{
sections_unlocked: [],
switches_unlocked: [],
is_route_completed: false,
}
Some(active_route) => {
let rule = active_route.rule
let sections = rule.track_sections
if active_route.state == RouteFault {
return {
sections_unlocked: [],
switches_unlocked: [],
is_route_completed: false,
}
}
if sections.length() == 0 {
active_route.release_stage = StageFullyReleased
active_route.state = RouteInactive
self.deactivate_route(route_id)
let _ = station.set_signal_aspect(rule.entry_signal, Red)
let _ = station.unlock_signal(rule.entry_signal)
return {
sections_unlocked: [],
switches_unlocked: [],
is_route_completed: true,
}
}
active_route.observe_occupancy(station)
let mut i = 0
while i < sections.length() {
let track_id = sections[i]
if !active_route.was_unlocked(track_id) &&
active_route.can_release_section(station, i) {
active_route.mark_released(track_id, i)
unlocked_sections.push(track_id)
}
i = i + 1
}
if active_route.all_sections_released() {
for switch_requirement in rule.switches {
let _ = station.unlock_turnout(switch_requirement.turnout_id)
unlocked_switches.push(switch_requirement.turnout_id)
}
for flank in rule.flank_switches {
let _ = station.unlock_turnout(flank.turnout_id)
unlocked_switches.push(flank.turnout_id)
}
active_route.release_stage = StageFullyReleased
active_route.state = RouteInactive
self.deactivate_route(route_id)
let _ = station.set_signal_aspect(rule.entry_signal, Red)
let _ = station.unlock_signal(rule.entry_signal)
{
sections_unlocked: unlocked_sections,
switches_unlocked: unlocked_switches,
is_route_completed: true,
}
} else {
{
sections_unlocked: unlocked_sections,
switches_unlocked: unlocked_switches,
is_route_completed: false,
}
}
}
}
}
///|
pub fn InterlockingTable::process_sectional_release_fast(
self : InterlockingTable,
station : @topology.Station,
route_id : RouteId,
) -> ReleaseCounters {
let counters = ReleaseCounters::empty()
match self.get_active_route(route_id) {
None => counters
Some(active_route) => {
let rule = active_route.rule
let sections = rule.track_sections
if active_route.state == RouteFault {
return counters
}
if sections.length() == 0 {
active_route.release_stage = StageFullyReleased
active_route.state = RouteInactive
self.deactivate_route(route_id)
let _ = station.set_signal_aspect(rule.entry_signal, Red)
let _ = station.unlock_signal(rule.entry_signal)
counters.is_route_completed = true
return counters
}
active_route.observe_occupancy(station)
if active_route.state == TrainInRoute {
counters.entered_route = true
}
let mut i = 0
while i < sections.length() {
let track_id = sections[i]
if !active_route.was_unlocked(track_id) &&
active_route.can_release_section(station, i) {
active_route.mark_released(track_id, i)
counters.sections_unlocked = counters.sections_unlocked + 1
}
i = i + 1
}
if active_route.all_sections_released() {
for switch_requirement in rule.switches {
let _ = station.unlock_turnout(switch_requirement.turnout_id)
counters.switches_unlocked = counters.switches_unlocked + 1
}
for flank in rule.flank_switches {
let _ = station.unlock_turnout(flank.turnout_id)
counters.switches_unlocked = counters.switches_unlocked + 1
}
active_route.release_stage = StageFullyReleased
active_route.state = RouteInactive
self.deactivate_route(route_id)
let _ = station.set_signal_aspect(rule.entry_signal, Red)
let _ = station.unlock_signal(rule.entry_signal)
counters.is_route_completed = true
}
counters
}
}
}