Ok, I've got some new code here. Please read everything below. This should be a significant improvement over the previous code I put together.

George’s RailDriver Light Switch Replacement Code v0.2b
This document was last updated on: October 12, 2011

Changes from v0.1b (original release)
- Complete code re-write to better determine switch position. The script now does a much better job of detecting the current switch position.

- Added LED Support. The LED now displays the position of the switch, as determined by the script. The purpose is two-fold.
1) You can easily see which code block the script actually ran, and 2) it acts as an indicator so you know that the script has completed running. The LED output should be self-explanatory, but I’ll break it down for you here.
L-0 (Switch is in the ‘Off’ position)
L-1 (Switch is in the ‘Dim’ position)
L-2 (Switch is in the ‘Full’ position)
You will want to wait until the indicator changes back to displaying the current speed, before changing the switch to a different position.




Known Limitations
- There is no support for ‘position hopping’. In other words, the script expects you to stop at each position before moving to the next one. Jumping from the ‘Off’ position to the ‘Full’ position (or vice-versa) will not work properly and can cause odd behavior from the script. If you are switching from ‘Off’ to ‘Full’, you MUST stop at ‘Dim’ (position 1) and let that segment of script run, before moving to the ‘Full’ position. You will know the script for the current position has completed when the switch position indicator on the LED has gone back to displaying speed.


- You MUST let the currently executing script finish what it is doing, before changing to a new position. ALWAYS wait for the Light Switch Position indicator to appear on the LED, then wait for it to go back to displaying the current speed, before switching positions.


- Turning the knob too slowly can cause the script to not execute. Just turn the knob normally from one position to the next, and there should be no problem. If the switch doesn’t respond, turn it back to the ‘Off’ position, wait a couple of seconds, then turn it again. It should start responding again. This can easily be avoided by changing the default thresholds from 4 to 0 as outlined in the ‘Recommendations’ section of this document.


- When turning on the front headlights from the ‘Off’ position, there is a delay before the lights actually turn on. This is because of the way I had to work around the raildriver.dll options, by sending simulated keystrokes to the sim, instead of being able to directly send a value through the dll file. Obviously, if there were a way to properly set the variable, instead of it just being a toggle, there would have been no need for me to try and work around this limitation by modifying the script. In any case, the delay is there to try to prevent ‘position drift’ (where a switch position is acting like a different position), by cycling the headlights off before being turned on for the front (or ‘Dim’) position. From the ‘Off’ position, this gives the appearance of a delay, but in actuality, the code is just making sure the lights actually are off, before turning them on for the front position.


- When turning on the front headlights from the ‘Full’ position, the headlights flash off before coming back on. This is normal, expected behavior. See the paragraph above this one, as it explains that when the switch changes to the front (or ‘Dim’) position, the lights are cycled off before being set to the front position.


- Occasionally, when the speed hasn’t changed (like when the train isn’t moving,) the L code may get ‘stuck’ on the LED. You can correct this by either switching positions and going back again, or just wait until the train starts to move, and it will start displaying the speed again.






Recommendations
- For best results, it is highly recommended that you change the default thresholds to 0 as the script creates and uses its own thresholds. The section that should be changed is as follows:


Find this section (about 80% of the way down the script)
Code:
lever(6).position(0).min = minvals(19) 'rotary 2 position 1 (off)
        lever(6).position(0).max = maxvals(19) 'rotary 2 position 1 (off)
    lever(6).position(0).upperthreshold=4 'must not be 0 w/o changing the logic below
    lever(6).position(0).lowerthreshold=4 'must not be 0 w/o changing the logic below
    lever(6).position(1).min = minvals(20) 'rotary 2 position 2 (slow)
        lever(6).position(1).max = maxvals(20) 'rotary 2 position 2 (slow)
    lever(6).position(1).upperthreshold=4 'must not be 0 w/o changing the logic below
    lever(6).position(1).lowerthreshold=4 'must not be 0 w/o changing the logic below
    lever(6).position(2).min = minvals(21) 'rotary 2 position 1 (full)
        lever(6).position(2).max = maxvals(21) 'rotary 2 position 1 (full)
    lever(6).position(2).upperthreshold=4 'must not be 0 w/o changing the logic below
    lever(6).position(2).lowerthreshold=4  'must not be 0 w/o changing the logic below





Then change the thresholds from 4 to 0, so that it reads as follows:
Code:
lever(6).position(0).min = minvals(19) 'rotary 2 position 1 (off)
        lever(6).position(0).max = maxvals(19) 'rotary 2 position 1 (off)
    lever(6).position(0).upperthreshold=0 'Default value=4, must not be 0 w/o changing the logic below
    lever(6).position(0).lowerthreshold=0 'Default value=4, must not be 0 w/o changing the logic below
    lever(6).position(1).min = minvals(20) 'rotary 2 position 2 (slow)
        lever(6).position(1).max = maxvals(20) 'rotary 2 position 2 (slow)
    lever(6).position(1).upperthreshold=0 'Default value=4, must not be 0 w/o changing the logic below
    lever(6).position(1).lowerthreshold=0 'Default value=4, must not be 0 w/o changing the logic below
    lever(6).position(2).min = minvals(21) 'rotary 2 position 1 (full)
        lever(6).position(2).max = maxvals(21) 'rotary 2 position 1 (full)
    lever(6).position(2).upperthreshold=0 'Default value=4, must not be 0 w/o changing the logic below
    lever(6).position(2).lowerthreshold=0 'Default value=4, must not be 0 w/o changing the logic below





Things I’ve Learned


I can’t say if this is a MacroWorks 3 issue, or a Train Simulator 2012 (RailWorks 3) issue, however during my debugging, I noticed that for no reason that I can pin down, the RailDriver re-reads the configuration of the current train while a scenario is already in progress. This, in and of itself, would not be an issue, but there are times when the information it gets back is wrong, thereby affecting the operation of the unit. For example, I’ve seen the code receive data showing that there should be a dynamic brake when a dynamic brake doesn’t exist. I don’t know if this is something in the MacroWorks 3 software that is causing it to request the data again, or if Train Simulator 2012 itself is sending a ‘train changed’ event or something similar.


In any case, this could easily be worked around IF the Train Simulator 2012 developers were to update the Raildriver.dll file so that it would include some kind of an identifier for each locomotive, and IF the script for the RailDriver itself in MacroWorks 3 were to be updated to identify lever configurations based on the individual locomotive.


How this affects me is that, just like the default RailDriver script, I have to read variables to determine what configuration of throttle and brake types are present, in order to make timing exceptions for certain locomotives, to have as much compatibility as possible.


When the information that comes back is incorrect, then the timings used will change and cause the lights to behave erratically. The throttle, brakes and/or reverser will also usually be affected at this time as well. Hitting the ESC key to bring up the menu, then resuming play from there usually straightens things out, as that apparently causes the RailDriver script to re-read the values (and hopefully get all the correct values back.)