====== Implementation: new-ks branch ======
//Please refer to the source code for implementation details and API documentation. This information is provided here. The filenames provided below are relative to ''[[http://git.bananach.space/advtrains.git/tree/advtrains_interlocking?h=new-ks|/advtrains_interlocking]]''.//
* The distant signaling API is implemented in ''[[http://git.bananach.space/advtrains.git/tree/advtrains_interlocking/distant.lua?h=new-ks|distant.lua]]''
* Formspecs have been partially modified to support distant signaling. Some formspecs are now implemented in various ''*_ui.lua'' files.
* Signal aspect accessors have been modified and are now found in ''[[http://git.bananach.space/advtrains.git/tree/advtrains_interlocking/signal_aspect_accessors.lua?h=new-ks|signal_aspect_accessors.lua]]''
* A signal aspect API is introduced. This allows manipulating signal aspect objects (implemented using tables) and creating signal aspect groups, the latter of which makes it possible to create route signals. The relevant code can be found in ''[[http://git.bananach.space/advtrains.git/tree/advtrains_interlocking/aspect.lua?h=new-ks|aspect.lua]]''
* A ''[[http://git.bananach.space/advtrains.git/tree/advtrains_interlocking/README.md?h=new-ks|README.md]]'' file is added that gives some information on working with the new signaling system.
**The changes break a few minor things:**
* The signal aspect formspec uses dropdown indexing, which requires Minetest 5.4.0 or later.
* ''advtrains.interlocking.signal_get_aspect'' and ''advtrains.interlocking.signal_set_aspect'' are changed:
* The results are cached.
* The signal aspect is "adjusted" before being passed to the signal, i.e., the signal aspect passed to the signal is not guaranteed to be the same as the one passed to ''advtrains.interlocking.signal_set_aspect''.
* ''advtrains.interlocking.signal_get_real_aspect'' gets the aspect of the signal directly from the node definitions. Note that, especially for Ks signals, the result is not guaranteed to be constant.
* There is no API for setting the signal aspect while bypassing the cache and signal aspect adjustments, as the latter is necessary for distant signaling. **Do not call the ''advtrains.set_aspect'' function in the node definitions directly as doing so is not guaranteed to give the expected result.**
* ''advtrains.interlocking.signal_get_aspect'' returns signal aspect objects instead of plain tables.
* When setting a field of the signal aspect object to ''nil'' while an aspect is named, the default value for the named aspect is used instead of ''false''. In particular, this may break certain shunt setups.
* Certain features of signal aspect objects are implemented using metatables. These objects are therefore not suitable for serialization, and it is not recommended to use ''next''-related functions (e.g. ''pairs'') on these objects. If you want to get a plain table, call the ''plain'' method of these objects.
It is planned to merge the newly introduced signal aspect cache with its counterpart in the routesetting system.
Please refer to the source code (listed above) for details.
====== Proposal: Distant signaling (second draft) ======
//This draft has been superseded. Please refer to the actual implementation (mentioned above).//
//This draft is mainly written to address the issues that appeared in the first draft. In particular, it addresses a request to implement route signaling.//
===== Distant signal assignment =====
==== Manual signal assignment ====
Distant signals may be assigned to any signal. These distant signals are automatically set with the signals they are assigned to.
==== Automatic signal assignment ====
With automatic distant signal assignment, the user needs to assign distant signals to TCBs. A TCB may have multiple distant signals assigned to it. For combined main/distant signals, however, the main and distant aspects may not be assigned separately.
These distant signals are then assigned to main signals when needed and unassigned when the aspect of the distant signal become irrelevant to rail operation. Specifically:
* When a route is set, the distant signals along the route are assigned to the upcoming signal (i.e. the signal first signal a train should encounter after passing the TCB). These distant signals are then set correspondingly.
* When a train leaves a TCB, the distant signal, if assigned to another signal, is unassigned. This should, at least theoretically, be safe as no other train is, at the moment, allowed to pass the TCB that the distant signal is assigned to.
===== Setting distant signals =====
* When a signal aspect is set, the distant signals are set correspondingly.
* When a distant signal is unassigned, its distant aspect is set to ''nil''.
===== API Changes =====
The functions are given as indices of the ''advtrains.interlocking'' table.
==== Signal aspect table ====
* The ''name'' field includes the name of the main aspect, if the alternative signal aspect table is used.
* The ''dst'' field includes the distant aspect. This is mentioned in the current source code, but not used at the moment and may need further discussion.
* The ''dst_name'' field includes the name of the distant aspect, if the alternative signal aspect table is used,
* The ''dst_repeater'' field is set if the signal is a distant signal repeater.
* The ''dst_shortened_distance'' field may, in the future, be used to indicate that the distance to the oncoming signal is shortened.
==== Distant signal assignment ====
* ''assign_distant(pos, dst)'' - Assign ''dst'' to the signal at ''pos''
* ''unassign_distant(dst)'' - Unassign the distant signal ''dst''
* ''distant_of(pos)'' - Get the distant signals assigned to ''pos''
* ''get_assignment(pos)'' - Get the signal that ''pos'' is a distant signal of
==== Setting signal aspect ====
* ''set_distant(pos, dst)'' - Set the distant aspect of ''pos'' to ''dst''
* ''set_main(pos, main)'' - Set the main aspect of ''pos'' to ''dst''
==== Alternative signal aspect table ====
The alternative signal aspect table is mainly intended for route signaling.
=== Supported aspects ===
The table of supported aspects should include the following fields:
* ''name'': A name identifying the signal aspect table. Note that this is //not// shown to the user
* ''label'': The name of the signal aspect to show to the user (e.g. in a UI). The use of ''attrans'' is recommended here.
* ''main'': A list of supported main aspects. An error is signaled if this list has less than two entries.
* ''dst'': A translation table where each key is the ''name'' field of the aspect and the value is a name that is passed to the set_aspect field of the distant signal.
* ''alt_translation'': A translation table where the key is the name of the table of supported aspects and the value is a table with key-value pairs of the original aspect name and the translated aspect name (as in the ''main'' field of the aspect)
When registering, the signal should provide the following fields:
* ''aspects'': The name of the table of supported aspects (see above).
* ''is_dst'': A boolean indicating whether the current signal is a distant signal.
Each main aspect entry should contain the following fields:
* ''name'': The internal name of the particular aspect.
* ''main'': The maximum allows speed. This is ''-1'' in a lot of cases.
The last entry in the list of supported aspects should have the ''main'' field set to 0 (i.e. stop). The //n//th entry in the list (which is not the first or last entry) indicates that the next signal has the same aspect defined by the //n+1//th entry in the list. The first entry in the list indicates that the next signal has the same aspect of the first //or// the second entry in the list.
=== Signal aspect translation ===
* When a distant signal defined with the alternative signal aspect definition table is assigned to a signal that is not defined with the same signal aspect table, the distant signal is always given the //n-1//th entry (with //n// being the number of defined main aspects of the distant signal) unless the main aspect of the upcoming signal is -1, in which case the distant signal is given the first entry of the defined main aspects of the distant signal, or an entry in the translation table can be used to determine the distant signal aspect.
* When a distant signal defined with the current signal aspect definition table is assigned to a signal defined with the alternative current signal aspect definition table, the ''main'' field of the signal aspect is passed to the distant signal.
====== Proposal: Distant signaling (first draft) ======
//This draft has been superseded.//
In this proposal, error situations do not need to be detected unless it is explicitly stated that the error is signaled.
===== Setup =====
* Each TCB side can have one distant signal and multiple distant signal repeaters assigned to it.
* The main signal can also be assigned as a distant signal, but it is an error if the main signal is a distant signal repeater.
* Distant signals should be able to operate as a regular distant signal or as a repeater. It is an error if this condition is not satisfied.
* It is an error if there is no regular distant signal between a distant signal repeater and a main signal.
//Edit: I think I should allow having only one distant signal assigned to a TCB side at a time. This is likely easier to implement; alternatively, it should be possible to assign a distant signal to reflect the signal aspect of a main signal or a distant signal (e.g. for a distant signal repeater). --- ywang 2022-01-01 03:00//
===== Signal handling =====
==== Setting distant signals ====
The distant signals of a main signal is only set when the route to the main signal is set and goes through the distant signals. The interlocking system can do so by traversing through the route to the main signal and setting the distant signals on its way. The first distant signal is treated as a regular distant signal, and the rest are treated as distant signal repeaters. A list of distant signals assigned to the main signal should be kept to make sure that the distant signals are updated as the aspect of the main signal changes.
//It should be selectable whether a signal on the route should be treated as distant signal and which not. At least the user shoud be able to set which is the first intermediate signal on the route that should serve as distant signal. The reason for this is that there may be a very long block (the route start signal should not pre-display any distant aspect here) and there is a dedicated distant-only signal before the next main signal. --- orwell 2021-12-31 17:22//
//What I thought about was that you need to explicitly set a signal as a distant signal by assigning it to a TCB (separately from the main signal - if you have e.g. a Ks signal you need to assign it twice) or by assigning it to an existing signal. --- ywang 2022-01-01 03:00//
//I thought about this again: the main and distant aspects, when both assigned, should be assigned to the same TCB. It does not make much sense otherwise. --- ywang 2022-02-10 17:49//
==== Distant signals without TCB? ====
--- //orwell 2021-12-31 17:22//
The above approach requires that each distant signal (even if it is a pure distant signal without main signal function) is assigned to a TCB (correct?).
I propose a separate mode where the distant signal is not assigned to a TCB, but instead shows the distant aspect of one (user-selected) main signal at all times, irregardless of route settings. Of course this only makes sense for pure-distant signals.
We can use this for simple distant signals before mainline main signals when we don't want to add another TCB (and thus make the block section 2 track sections instead of just one).
//Makes sense. I have appended it to the previous section. --- ywang 2022-01-01 03:00//
==== Unsetting distant signals ====
The procedure of setting the aspect of distant signals must be done in a way that the distant signal(s) showing the aspect of the main signal can be found. Distant signals are unset (i.e. set to ''nil'') when the main signal and/or the distant signal becomes irrelevant for any train, such as when the distant signal is a combined signal showing the Hp 0 aspect.
==== Example ====
In the following case:
^
|
+---- Main signal H1
|
| ^
| |
| +- Main signal H2
| |
|\/|
|/\|
| |
| +- Combined signal H4 (main)/V2 (distant)
| |
| V
|
+---- Combined signal H3 (main)/V1 (distant)
|
V
If both routes ''H4->H2'' and ''H3->H1'' are set, then
* ''V1'' is set to reflect the main aspect of ''H1''. It is unset when the train passes ''H1''.
* ''V2'' is set to reflect the main aspect of ''H2''. It is unset when the train passes ''H2''.
If the route ''H3->H2'' is set, then
* ''V1'' is set to reflect the main aspect of ''H2''. It is unset when the train passes ''H2''.
* ''V2'' remains unset as it is not relevant for the train using the route.
==== Representation in Signal Aspect Table ====
--- //orwell 2021-12-31 17:22//
IMO the easiest way to provide clean distant signal support is via extending the "Signal Aspect" table. Proposal:
asp = {
... other fields as usual ...
dst_pos = ,
dst = nil, -- 'dst' field is not provided directly
Then, within ''advtrains.interlocking.signal_set_aspect(pos, asp)'', the ''dst_pos'' field is looked up and the ''dst'' field is set accordingly before the ''set_aspect()'' of the node definition is called.
2 things need to be taken care of:
- the signal API somehow needs to keep track of the aspects the signals are supposed show - not only for the TCB-assigned signals but for all signals
- the signal API needs to remember a reverse lookup of signals that have dst_pos set on a signal, to trigger aspect updates accordingly.
With this implementation, the distant signals feature can also easily be used from LuaATC-controlled signals. The route mechanism can just plug into that and set the position of the route end signal as dst_pos.
Whether signal is a distant signal repeater would then be another field in the aspect definition (''dst_repeater = '')
Also, there is this "Verkürzter Bremswegabstand" light in Ks signals - ''dst_short = ''?
//In an earlier implementation I simply put the distant signal information (position of the main signal or the distant signal) in the signal table itself instead of the aspect table. That made it possible to keep track of what is assigned to what. I would prefer having the signal aspect table as a fallback when the source of the train is unknown. The "verkürzter Bemswegabstand" feature might be a bit complicated when you have a distant signal that can be assigned to multiple main signals (e.g. at a turnout), and I would prefer a method that computationally figures out whether the braking distance is reduced, which is beyond my abilities at the moment. --- ywang 2022-01-01 03:00//