Elvas Tower: C# Signal Scripts - Elvas Tower

Jump to content

Posting Rules

All new threads will be started by members of the Open Rails team, Staff, and/or Admins. Existing threads started in other forums may get moved here when it makes sense to do so.

Once a thread is started any member may post replies to it.
  • 3 Pages +
  • 1
  • 2
  • 3
  • You cannot start a new topic
  • You cannot reply to this topic

C# Signal Scripts Rate Topic: -----

#1 User is offline   cesarbl 

  • Conductor
  • Group: Status: Active Member
  • Posts: 393
  • Joined: 30-March 20
  • Gender:Male
  • Simulator:Open Rails
  • Country:

Posted 15 January 2021 - 11:20 AM

We have been developing some signal scripts to recreate Spanish signalling systems, and we have found the SIGSCR a bit limiting. Some time ago Serana proposed a C# scripting interface for signals, similar to the one used for Train Control Systems. I made some changes to Serana's code, focusing on fast execution speed and isolation from internal structures, and I would like to integrate the result into OR code. This are some of the reasons for which we think C# could be useful:

  • The 8 MSTS aspects aren't enough to represent all signal aspects (for example, in Spain we have up to 16 different aspects). Each signal shows a subset of the total aspects, so a workaround is to reuse the same MSTS aspect for different aspects. However, this causes issues with advanced train control systems like ETCS which will take different actions depending on the aspect of the signal. Cedric proposed a flexible solution, which is to have an additional text aspect (i.e. a string variable) for each signal. The MSTS (stop, approach, clear...) aspects are still used as a fallback for AI trains, SIGSCR signals and Track Monitor display.

  • Signals are difficult to debug for people not familiar with OR code. Using C# allows the use of Console.WriteLine(), which is useful for simple debugging of the logic.

  • There's no communication between a signal and the following one. There's one specific situation in Spanish signalling where the second signal has to be kept at a restrictive aspect until the first signal is cleared for more than 10 seconds, where this feature is required. I added a SendSignalMessage function call which will send a string message to the required signal.

  • Working with global variables is tedious because they have to be read and stored at each update.

Some of the problems could be solved with the existing SIGSCR interface (e.g. the number of available aspects could be extended as it is done with SIGFN_ and SIGSUBT_ definitions), but others would need to dedicate much time to the SIGSCR parser.

For simple signals (specially non NORMAL signals) using C# is overkill, and the SIGSCR syntax is simple and concise, so I think it's a good idea to have both systems.

This interface doesn't access internal code structures, so it won't stop improvements in signalling. Every query to the signalling system is done through hooks that call the SIGSCR equivalent functions.

#2 User is offline   ebnertra000 

  • Superintendant
  • Group: Status: Elite Member
  • Posts: 1,234
  • Joined: 27-February 17
  • Gender:Male
  • Location:East-Central Minnesota
  • Simulator:OR/TSRE
  • Country:

Posted 15 January 2021 - 11:36 AM

Interesting development... Is there an example of these new features out there? It sounds like it probably won't be necessary for most North American systems, but I could be wrong

#3 User is offline   vince 

  • Superintendant
  • Group: Status: Elite Member
  • Posts: 1,312
  • Joined: 18-June 14
  • Gender:Male
  • Location:West of the Contental Divide
  • Simulator:ORTS_Running MSTS_Editing
  • Country:

Posted 15 January 2021 - 01:29 PM

Isn't Open Rails equipped to handle advanced signal functions?

vince

#4 User is offline   roeter 

  • Vice President
  • Group: Status: Elite Member
  • Posts: 2,420
  • Joined: 25-October 11
  • Gender:Male
  • Country:

Posted 15 January 2021 - 03:21 PM

 cesarbl, on 15 January 2021 - 11:20 AM, said:

We have been developing some signal scripts to recreate Spanish signalling systems, and we have found the SIGSCR a bit limiting. Some time ago Serana proposed a C# scripting interface for signals, similar to the one used for Train Control Systems. I made some changes to Serana's code, focusing on fast execution speed and isolation from internal structures, and I would like to integrate the result into OR code. This are some of the reasons for which we think C# could be useful:

  • The 8 MSTS aspects aren't enough to represent all signal aspects (for example, in Spain we have up to 16 different aspects). Each signal shows a subset of the total aspects, so a workaround is to reuse the same MSTS aspect for different aspects. However, this causes issues with advanced train control systems like ETCS which will take different actions depending on the aspect of the signal. Cedric proposed a flexible solution, which is to have an additional text aspect (i.e. a string variable) for each signal. The MSTS (stop, approach, clear...) aspects are still used as a fallback for AI trains, SIGSCR signals and Track Monitor display.

  • Signals are difficult to debug for people not familiar with OR code. Using C# allows the use of Console.WriteLine(), which is useful for simple debugging of the logic.

  • There's no communication between a signal and the following one. There's one specific situation in Spanish signalling where the second signal has to be kept at a restrictive aspect until the first signal is cleared for more than 10 seconds, where this feature is required. I added a SendSignalMessage function call which will send a string message to the required signal.

  • Working with global variables is tedious because they have to be read and stored at each update.

Some of the problems could be solved with the existing SIGSCR interface (e.g. the number of available aspects could be extended as it is done with SIGFN_ and SIGSUBT_ definitions), but others would need to dedicate much time to the SIGSCR parser.

For simple signals (specially non NORMAL signals) using C# is overkill, and the SIGSCR syntax is simple and concise, so I think it's a good idea to have both systems.

This interface doesn't access internal code structures, so it won't stop improvements in signalling. Every query to the signalling system is done through hooks that call the SIGSCR equivalent functions.


Most of this has already been dealt with with various additions to the signal scripts.
For instance, signals now have local variables which are specific to each signal and which can be queried by any other signal. These variables can, for instance, be used to set the signal state, thus avoiding the SIGFN limitation. Using multiple 'dummy' display signals you can have as many states as you like.
I have various examples of signal systems using this method if you are interested, for instance full french "9 lights" signals including routing and speed settings which can have many more than 8 states.
Variables can also be used to communicate between signals, passing on much more information than just the state.

As for debug - there is a very extended debug facility, which shows every step of the script and all local values. It can be switched on using #DEBUG settings and can be set to just a specific signal, showing the details for that signal only which helps a great deal when sorting out a problem for a specific signal.

Please first take a good look at all the new functions which have been included, and if you still think you need some additional function then just ask, adding new functions to the parser is actually quite easy, and the code for the new function has to be written anyway.

Creating two different control logics for signals is going to make it far more difficult in future to extend signalling further.

Regards,
Rob Roeterdink

#5 User is offline   YoRyan 

  • Conductor
  • Group: Status: Active Member
  • Posts: 391
  • Joined: 19-February 20
  • Gender:Male
  • Location:California, United States
  • Simulator:Open Rails/unstable
  • Country:

Posted 15 January 2021 - 10:52 PM

I too have been interested in Serana's work and I say, go for it. Even from the perspective of US railroading, it's clear that the MSTS system has its constraints. As in your Spanish railways, the Pennsylvania Railroad pulse code signaling system has over a dozen possible aspects, not to mention the various speed control systems used by rapid transit systems all over the world. This is possible, but needlessly complicated, to simulate with pure SIGSCR and the 8 aspects.

In the long run it's a dead-end, obscure language (QuakeC, anyone?) and if I were a fresh route developer, I would jump at the chance to use something with modern tooling like C#. (You can actually step through C# scripts as they execute in Visual Studio--I wrote a blurb about this in the TCS section of the OR manual.)

Obviously, yes, we will retain the SIGSCR parser indefinitely. Personally, I don't see a problem with maintaining both formats. As long as you don't radically re-architect the core signaling system, it's not like working on one parser is going to break the functionality of the other.

If you pursue this, focus on designing an intuitive and extensible API--no need to get fancy or overthink things. I would be happy to help, through code, critique, or otherwise.

#6 User is offline   cesarbl 

  • Conductor
  • Group: Status: Active Member
  • Posts: 393
  • Joined: 30-March 20
  • Gender:Male
  • Simulator:Open Rails
  • Country:

Posted 16 January 2021 - 01:56 AM

This is an example of one of the last versions of the sigscr before creating the C# script prototype, made by Miguel MouriƱo. He's making intense use of the advanced signalling functions already, and we are planning to use even more (e.g. route_cleared_to_signal for ETCS L2 high speed lines). The problem is not in the number of signalling functions available (I haven't extended them with this proposal, apart from passing messages between signals), but in the way the signals are setup. As Ryan says, most of the things can be done using sigscr, but it becomes too complicated at a certain point. For example, consider a signal which needs two timers: you would have to create one signal for each timer, and use local variables to share the result. With C#, you can set up as many timers as you wish.

Attached File  sigscr.dat.txt (7.04K)
Number of downloads: 442

This is more or less enough for conventional lines, even though we have to reuse the aspect STOP_AND_PROCEED for two different indications (permisive signal which can be passed at stop, and a shunting "stop and proceed" aspect). When switching to high speed lines, there are three more aspects which mean "stop if not in ETCS/LZB", as well as two other aspects used in old interlockings. This lack of aspects could be solved with some use of local variables, but as this variables aren't seen by the scripting interface (at worst they are not available at all in multiplayer clients), it is impossible to distinguish between them for the TCS.

Another advantage for C# for complex signal scripts is that it improves the readability of the code, for example structuring the code in different functions.

My idea is having a direct equivalence between C# and SIGSCR functions so the code duplication is minimal, for example:
public abstract class CsSignalScript
{
    public bool RouteSet => SignalHead.route_set() > 0;
    public int SignalNumClearAhead { get { return SignalObject.SignalNumClearAheadActive; } set { SignalObject.SetSignalNumClearAhead(value); } }
    public int NextSignalId(string sigfn, int count = 0)
    {
        return SignalObject.next_nsig_id(SigFnIndex(sigfn), count + 1);
    }
    public bool IdSignalHasNormalSubtype(int id, string normalSubtype)
    {
        return SignalHead.id_sig_hasnormalsubtype(id, SignalObject.signalRef.ORTSNormalsubtypes.IndexOf(normalSubtype)) == 1;
    }
}


However, we could take an object oriented programming approach such as:
class Signal
{
    private SignalObject SignalObject;
    public int SignalId;
    public MstsSignalAspect GetMstsAspect(string sigfn, bool mostRestrictive, bool checkRouting=false)
    {
        return SignalObject.id_sig_lr(SignalId, sigfn); // same for id_sig_mr
    }
    public bool HasNormalSubtype(string subtype)
    {
        return SignalObject.id_sig_hasnormalsubtype(SignalId, SignalObject.signalRef.ORTSNormalsubtypes.IndexOf(normalSubtype)) == 1;
    }
}


I've drafted a PR so the implementation details can be easily commented.

#7 User is offline   roeter 

  • Vice President
  • Group: Status: Elite Member
  • Posts: 2,420
  • Joined: 25-October 11
  • Gender:Male
  • Country:

Posted 16 January 2021 - 03:18 AM

What saddens me is that arguments are used to promote this which simply are not true.
For instance, the remark that certain US signals cannot be properly set up because it's not possible to capture these in 8 states makes no sense as signals are no longer restricted to 8 states. I have set up signals according to the french signalling rules, the main signal in this set handles 26 states.
Also, the remark that TCS scripts cannot access these local variables is not true. To get the state of a signal, the TCS script must have access to the signal object. But it is precisely that object which holds these variables, so if you can access the state you can access these variables.

Furthermore, certain restrictions, as the max. 8 external states, and the max. 8 states for display definitions, are not lifted using scripting because these restrictions are the result of other definitions or code, e.g. the external state is used in track monitor, cabview, dispatcher window and AI control. The max. of display states used for a signal type is defined in the sigcfg.dat. These restrictions will therefor apply just a much to C# scripted signalling as to the present scripting.

The greatest danger of C# scripting is that it takes related code out of the program. If that code uses certain variables or calls of a specific class, it cannot be verified if changes to that class will affect these scripts. That either means that such classes must be fully frozen, which could seriously hamper future development, or there is a risks of script becoming incompatble due to program changes. One cannot expect that a developer will first check all scripts before making changes, so in practice it would come down to a full freeze. That does really worry me. If it were really true that the required functionality cannot be provided through the existing scripting, than it might be a valid choice. But most if not all of the arguments which have been given so far are just not true.
So before going down these uncharted and possibly dangerous waters, I would like to suggest to make one more dedicated attempt to capture the functionality within the existing structure. I am quite willing to help in this, and without boasting I dare say I know a thing or two about OR signalling.

I am not ruling out C# scripting as alternative for ever, but it should be part of a more general renewal of signal definitions, not only looking at scripting but also at signal definition through the sigcfg file, for only then will it be possible to really lift the most troublesome restrictions.

Regards,
Rob Roeterdink

#8 User is offline   cesarbl 

  • Conductor
  • Group: Status: Active Member
  • Posts: 393
  • Joined: 30-March 20
  • Gender:Male
  • Simulator:Open Rails
  • Country:

Posted 16 January 2021 - 04:44 AM

 roeter, on 16 January 2021 - 03:18 AM, said:

What saddens me is that arguments are used to promote this which simply are not true.
For instance, the remark that certain US signals cannot be properly set up because it's not possible to capture these in 8 states makes no sense as signals are no longer restricted to 8 states. I have set up signals according to the french signalling rules, the main signal in this set handles 26 states.
Also, the remark that TCS scripts cannot access these local variables is not true. To get the state of a signal, the TCS script must have access to the signal object. But it is precisely that object which holds these variables, so if you can access the state you can access these variables.

The TCS does not have access to the SignalObject, only to a restricted set of variables collected from it. Certainly, the local variable dictionary could be added to the TCS interface (it should have to be serialized in order to work in multiplayer operation though). However, I have the impression that using
if(NextSignalTextAspect() == "SomeAspect")
is much more intuitive than
if(NextSignalLocalVariable(some_arbitrary_key_number) == custom_aspect_index)

 roeter, on 16 January 2021 - 03:18 AM, said:

Furthermore, certain restrictions, as the max. 8 external states, and the max. 8 states for display definitions, are not lifted using scripting because these restrictions are the result of other definitions or code, e.g. the external state is used in track monitor, cabview, dispatcher window and AI control. The max. of display states used for a signal type is defined in the sigcfg.dat. These restrictions will therefor apply just a much to C# scripted signalling as to the present scripting.

You are right. That's why we have kept the MstsSignalAspect variable as a fallback. In the signalling system we are building for Spain, non NORMAL signals use the SIGSCR script, so they don't have access to the text aspect and use the fallback aspect instead. It is also used for TrackMonitor and AI trains, as you say.

 roeter, on 16 January 2021 - 03:18 AM, said:

The greatest danger of C# scripting is that it takes related code out of the program. If that code uses certain variables or calls of a specific class, it cannot be verified if changes to that class will affect these scripts. That either means that such classes must be fully frozen, which could seriously hamper future development, or there is a risks of script becoming incompatble due to program changes. One cannot expect that a developer will first check all scripts before making changes, so in practice it would come down to a full freeze. That does really worry me. If it were really true that the required functionality cannot be provided through the existing scripting, than it might be a valid choice. But most if not all of the arguments which have been given so far are just not true.
So before going down these uncharted and possibly dangerous waters, I would like to suggest to make one more dedicated attempt to capture the functionality within the existing structure. I am quite willing to help in this, and without boasting I dare say I know a thing or two about OR signalling.

The C# scripts won't have access to OR internal structures and classes. They only have access to a well defined set of functions, which are equivalent to the SIGSCR ones. The risk of incompatibility is the same as for SIGSCR scripts: for example, if the route_cleared_to_signal is modified, both SIGSCR and C# scripts will be affected.

 roeter, on 16 January 2021 - 03:18 AM, said:

I am not ruling out C# scripting as alternative for ever, but it should be part of a more general renewal of signal definitions, not only looking at scripting but also at signal definition through the sigcfg file, for only then will it be possible to really lift the most troublesome restrictions.

Even if the sigcfg structure, or the whole signalling environment is modified, we have to keep SIGSCR functionality for compatibility. Since the C# scripting only uses functions already existing for SIGSCR, I don't see why we would need to wait for this.

You are right that using C# scripting is not really necessary, as we could build our signal system using 30 different heads for each signal, but I think it allows configuring signals in an easier way. The SIGSCR syntax is really simple, and I think extending it to allow using some features like function definitions, that C# offers out of the box, is to reinvent the wheel.

#9 User is offline   YoRyan 

  • Conductor
  • Group: Status: Active Member
  • Posts: 391
  • Joined: 19-February 20
  • Gender:Male
  • Location:California, United States
  • Simulator:Open Rails/unstable
  • Country:

Posted 16 January 2021 - 10:48 AM

 roeter, on 16 January 2021 - 03:18 AM, said:

The greatest danger of C# scripting is that it takes related code out of the program.

This is not true as long as you create well-defined interfaces that don't expose internal classes. I know we had a recent case in the TCS interface that violated this rule, but we've come to a consensus that this is not a good idea going forward.

 roeter, on 16 January 2021 - 03:18 AM, said:

So before going down these uncharted and possibly dangerous waters, I would like to suggest to make one more dedicated attempt to capture the functionality within the existing structure.

"But we can use the formats we already have" is sort of orthogonal to the question of "What file format is the best tool for the job?" Technically, if you add enough tokens to the .eng format, you can define any kind of braking or train control system. But we didn't do that, and still created the brake and TCS scripting interfaces, because it is so much easier to accomplish complex simulations in C#.

#10 User is offline   vitro 

  • Apprentice
  • Group: Status: New Hire
  • Posts: 10
  • Joined: 09-December 14
  • Simulator:Open Rails
  • Country:

Posted 17 April 2021 - 10:30 AM

I also find SIGSCR quite limiting. There's no:
  • Ability to check clearance of a track when signal is not enabled. Sometimes it necessary to check the track not only on the path of the train.
  • Ability to switch junctions from the signal script. It required for implementing "guard" switches, for example in a crossover very often both switches must be in the same position.
  • Ability to check clearance in front of a signal.
  • Ability to change trains priority in a multiplayer. It leads to deadly locked switches, often leading to already occupied track


I can provide examples for all situations I described.

  • 3 Pages +
  • 1
  • 2
  • 3
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users