Announcement

Collapse
No announcement yet.

RailDriver New Light Switch Code v0.2b

Collapse
This topic is closed.
X
This is a sticky topic.
X
X
Collapse
First Prev Next Last
 
  • Filter
  • Time
  • Show
Clear All
new posts

    RailDriver New Light Switch Code v0.2b

    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.)

    #2
    RailDriver New Light Switch Code v0.2b - Code Installation

    I had intended to add this as a reply to my previous post (so mods, if you could merge the two, it would be appreciated), but the first post has to wait for moderator approval (as I'm sure this one will too), so I wanted to get them both up together.

    The Code - Installation


    Below is the replacement light code. You should have already performed the changes that were recommended previously, in the Recommendations section. If you do not perform those steps, the script will still work, but the responsiveness can decrease
    and “position drift” (where one switch position is acting as another) is more likely to happen.


    Make sure you have backed up your default script before making any changes. I am not responsible if you don’t have a backup if things go wrong. In MacroWorks 3, choose “File -> Save As” and save a copy of the script someplace you’ll easily remember, (like
    your ‘Documents’ folder, and give it a name that you can easily identify later.


    Once you have backed up the default script, in the MacroWorks interface, click on “View -> Advanced View”.


    Scroll down to the section that reads “Case 2007”, and highlight from there down to the line that reads “End Select 'Analog Check End [/MWTAG13]”. Then replace that with the code in the next post I make.


    (Please go to the next post on this for the actual code.)



    The following locomotives have been tested and work on both my laptop and my main pc. The specs are quite far apart, so they are a good representation of opposing ends of the spectrum of pc performance.


    Invincible
    7F 2-8-0
    BR101
    BR143
    BR151
    BR294
    BR52 2-10-0
    Big Boy (Properly activates on HUD, but lights are fixed)
    Black 5 4-6-0
    Class 166
    Class 37
    Class 43 (Just Trains)
    Class 450
    Class 47
    Class 483
    Class 55
    EMD F7
    EMD GP7
    EMD SD40-2
    GE ES44AC
    GP40
    HST BR Blue
    HST FGW Blue
    Permaculp Carrier
    Super Express Concept


    The following locomotives do not work correctly:
    B&M E7a - Lights will frequently show pos 1 is active on the HUD, but the lights only flicker on then go off.


    BRV200 - This could be fixed if I could make an exception that applied to this loco only, as it is a timing issue. But fixing the timing for this one breaks it for four other locos, so I felt it was better to leave this one not working, and four others working.


    The following locomotives are not tested because I have no scenarios to test them on:
    Class 43 (RSC)
    Consolidation 2-8-0 (Scenario I have fails to load.)
    DB BR 151 002-3


    Those represent all the locomotives I currently have. So no other locomotives have been tested. If it's not listed here, I don't have it and can't test it.


    Hope this is helpful to my fellow RailDriver users.


    -George

    Comment


      #3
      The Code - Installation


      Below is the replacement light code. You should have already performed the changes
      that were recommended previously, in the Recommendations section. If you do not
      perform those steps, the script will still work, but the responsiveness can decrease
      and “position drift” (where one switch position is acting as another) is more likely to
      happen.


      Make sure you have backed up your default script before making any changes. I am
      not responsible if you don’t have a backup if things go wrong. In MacroWorks 3, choose
      “File -> Save As” and save a copy of the script someplace you’ll easily remember, (like
      your ‘Documents’ folder, and give it a name that you can easily identify later.
      Once you have backed up the default script, in the MacroWorks interface, click on
      “View -> Advanced View”.


      Scroll down to the section that reads “Case 2007”, and highlight from there down to
      the line that reads “End Select 'Analog Check End [/MWTAG13]”. Then replace that
      with the following:
      Code (First part since it would not all fit into one reply)
      Code:
      		Case 2007 '3 Position Rotary Switch 2
      			Dim LightSWPosSensitivity as Integer 'Used to create a buffer around the Off and Full positions
      			Dim LightSWDimSensitivity as Integer 'Used to create a buffer around the Dim position
      			Dim HoldKeyTime as Integer 'Used to determine how long a key press is held down
      			Dim HoldKeyDoubleTime as Integer 'Used for double-length keypresses
      			Dim CurLightSWPos as Integer 'Values are 0=Off 1=Dim 2=Full 3=Not In Range
      			Dim LightSwitchPosChanged as Boolean 'Used to verify switch is in a different position
      			Dim LtSwLastAnalog as Integer 'Used to check if switch is still moving
      			Dim LtSwLEDVal as Integer=0
      			Dim LtOffLo as Integer
      			Dim LtOffHi as Integer
      			Dim LtDimLo as Integer
      			Dim LtDimHi as Integer
      			Dim LtFullLo as Integer
      			Dim LtFullHi as Integer
      			Dim LtSwFirstRun as Boolean
      			Dim LtSwWriteToLED as Boolean
      			Dim LtSwSkipThrottleStyleCheck as Boolean = False
      
      
      			'Locomotive features variables used for creating exceptions to timing rules
      			Dim LtSwCombinedThrottle as Boolean = False
      			Dim LtSwGearLever as Boolean = False
      			Dim LtSwTrainBrake as Boolean = False
      			Dim LtSwLocoBrake as Boolean = False
      			Dim LtSwDynamicBrake as Boolean = False
      
      
      			'Debugging variables
      			Dim LightSwitchDebug as Boolean	
      			Dim LightSwitchReportedValue as String		
      			Dim LtOffLoDebug as String
      			Dim LtOffHiDebug as String
      			Dim LtDimLoDebug as String
      			Dim LtDimHiDebug as String
      			Dim LtFullLoDebug as String
      			Dim LtFullHiDebug as String
      			
      			LightSwitchDebug=False 'Should be set to False or message boxes will appear every time the switch changes positions
      
      
      			'Tweakable values to modify sensitivity of each position and length of time keys are held down
      			LightSWPosSensitivity = 5 'the higher the number, the broader the acceptable range for off and full positions
      			LightSWDimSensitivity = 20 'Same as above but only for the dim position to account for drifting values coming from the center point of the switch
      			HoldKeyTime = 250 'Base value for holding keys for this amount of time in milliseconds and gets adjusted later in the script based on ThrottleStyle
      
      
      			'Do not change anything below this line as it will break the script
      			LightSwitchPosChanged = False
      			
      			'Check for switch movement			
      			If (AnalogValue(0)<>lever(6).LastValue) Then	'Switch movement detected
      
      
      				'Determine Locomotive Features
      				If (RailSimCombinedThrottleBrakeMin<>0 Or RailSimCombinedThrottleBrakeMax<>0) Then 'Combined Throttle
      					LtSwCombinedThrottle=True
      					'MsgBox("Combined Throttle Exists",1)
      				Else
      					LtSwCombinedThrottle=False
      				End If
      
      
      				If (RailSimGearLeverMin<>0 Or RailSimGearLeverMax<>0) Then 'Gear lever
      					LtSwGearLever=True
      					'MsgBox("Gear Lever Exists.",1)
      				Else
      					LtSwGearLever=False
      				End If
      
      
      				If (RailSimTrainBrakeMin<>0 Or RailSimTrainBrakeMax<>0) Then 'Train Brake
      					LtSwTrainBrake=True
      					'MsgBox ("Train Brake Exists.",1)
      				Else
      					LtSwTrainBrake=False
      				End If
      
      
      				If (RailSimLocoBrakeMin<>0 Or RailSimLocoBrakeMax<>0) Then 'Locomotive Brake
      					LtSwLocoBrake=True
      					'MsgBox ("Locomotive Brake Exists.",1)
      				Else
      					LtSwLocoBrake=False
      				End If
      
      
      				If (RailSimDynamicBrakeMin<>0 Or RailSimDynamicBrakeMax<>0) Then 'Dynamic Brake
      					LtSwDynamicBrake=True
      					'MsgBox ("Dynamic Brake Exists.",1)
      				Else
      					LtSwDynamicBrake=False
      				End If
      
      
      				LtSwLastAnalog=lever(6).LastValue
      				LightSwitchReportedValue=AnalogValue(0) 'Convert the analog value to a string for debugging message boxes
      
      
      				'Create ranges for switch positions
      				LtOffLo = (lever(6).position(0).min-lever(6).position(0).lowerthreshold - LightSWPosSensitivity)
      				LtOffHi = (lever(6).position(0).max-lever(6).position(0).upperthreshold + LightSWPosSensitivity)
      				LtDimLo = (lever(6).position(1).min-lever(6).position(1).lowerthreshold - LightSWDimSensitivity) 
      				LtDimHi = (lever(6).position(1).max-lever(6).position(1).upperthreshold + LightSWDimSensitivity) 
      				LtFullLo = (lever(6).position(2).min-lever(6).position(2).lowerthreshold - LightSWPosSensitivity)
      				LtFullHi = (lever(6).position(2).max-lever(6).position(2).upperthreshold + LightSWPosSensitivity)
      
      
      				LtOffLoDebug = LtOffLo
      				LtOffHiDebug = LtOffHi
      				LtDimLoDebug = LtDimLo
      				LtDimHiDebug = LtDimHi
      				LtFullLoDebug = LtFullLo
      				LtFullHiDebug = LtFullHi
      
      
      				'Check if this is the first movement of the switch
      				If (lastrp2=-1) Then
      					LtSwFirstRun=True 'First run
      				Else
      				End If
      
      
      				'Check current light switch position
      				If (AnalogValue(0)<LtOffHi) Then 'Switch is in the Off position
      					CurLightSWPos=0
      				Else If (AnalogValue(0)>LtDimLo) And (AnalogValue(0)<LtDimHi) Then 'Switch is in the Dim position
      					CurLightSWPos=1
      				Else If (AnalogValue(0)>LtFullLo) Then 'Switch is in the Full position
      					CurLightSWPos=2
      				Else 'Switch is in between positions
      					CurLightSWPos=3
      				End If
      
      
      				If (LtSwFirstRun=True) Then
      					lastrp2=CurLightSWPos 'Since this is the first run we need to set the position the switch is in at the start
      				Else
      				End If			
      
      
      				'Make sure current switch position is different than the last position
      				If (CurLightSWPos<lastrp2) Or (CurLightSWPos>lastrp2) Then 'The switch is in a different range so run the code
      					LightSwitchPosChanged=True 'The switch is in a valid range so continue running code
      				Else
      					LightSwitchPosChanged=False 'The switch is in the same range as the last position
      				End If	
      				
      				If (CurLightSWPos<>3) Then 'Switch is in a valid position
      					lastrp2=CurLightSWPos	
      				Else
      				End if

      Comment


        #4
        Code Part 2 (paste in directly where you left off from the code above)

        Code:
        
        				If (LightSwitchPosChanged=True) Then 'The switch is in a different position so run the code below
        
        
        					'Create special case exceptions to the rules below based on locomotive features.
        					'Rule exception for BR294. This works because it is the only locomotive with a combined throttle with train and locomotive brakes
        					If (LtSwCombinedThrottle=True And LtSwTrainBrake=True And LtSwLocoBrake=True And LtSwDynamicBrake=False And LtSwGearLever=False) Then
        						HoldKeyTime=HoldKeyTime-100
        						LtSwSkipThrottleStyleCheck=True
        						'MsgBox("BR294 Detected.",1)
        					End If
        
        
        					If (LtSwSkipThrottleStyleCheck=False) Then 'no exceptions have been applied so use default ThrottleStyle timing configuration
        						'Check ThrottleStyle to modify hold key times
        						Select Case (ThrottleStyle)
        							Case 0 'throttle as labeled on RD (throttle on bottom half)
        								'MsgBox("Throttle as labeled on RD",1)
        								HoldKeyTime=HoldKeyTime-50
        							Case 1 'throttle/train brake
        								'MsgBox("Throttle-Train Brake",1)
        								HoldKeyTime=HoldKeyTime
        							Case 2 'throttle/dynamic brake
        								'MsgBox("Throttle-Dynamic Brake",1)
        								HoldKeyTime=HoldKeyTime-100
        							Case 3 'all throttle
        								'MsgBox("All Throttle",1)
        								HoldKeyTime=HoldKeyTime-50
        						End Select
        					End If 
        
        
        					HoldKeyDoubleTime = (HoldKeyTime + HoldKeyTime + 200) 'This is used to calculate how long to hold down the key to simulate an extended keypress
        			
        					Select Case (CurLightSWPos)
        						Case (0) 'Set lights to Off						
        							'SetRailSimValue(eRailSimControlID.HEADLIGHTS_ID, 1) 'toggle off headlights
        							'The following ScanCodes tell RD to send SHIFT+H to RW long enough to ensure lights turn off
        							MW3.sendScanCode("42:1,35:1") 'Press SHIFT (42) H (35)
        							MW3.insertDelay(HoldKeyDoubleTime) 'Uses double HoldKeyTime for extended keypress
        							MW3.sendScanCode("35:0,42:0") 'Release SHIFT (42) H (35)
        							LtSwLEDVal=63 'LED Value for 0
        							LtSwWriteToLED=True 'Finished this code block so it is ok to write to the LED
        							If (LightSwitchDebug=True) Then 'Switch debugging messages are turned on so display them
        								MsgBox("The current light switch position is: OFF. Current switch value is: " & LightSwitchReportedValue & ". Valid numbers for the range are: " & LtOffLoDebug & " - " & LtOffHiDebug & ".",1)
        							Else
        							End If
        						Case (1) 'Set lights to position 1							
        							MW3.sendScanCode("42:1,35:1") 'Press SHIFT (42) H (35) 'Hold down SHIFT+H long enough to turn off lights
        							MW3.insertDelay(HoldKeyDoubleTime ) 'HoldKeyTime is doubled for extended keypress
        							MW3.sendScanCode("35:0,42:0") 'Release SHIFT (42) H (35)
        							MW3.insertDelay(50) 'Small delay before sending new keystrokes
        							MW3.sendScanCode("35:1") 'Press lower-case h (35)
        							MW3.insertDelay(HoldKeyTime)
        							MW3.sendScanCode("35:0") 'Release lower-case h (35)
        							LtSwLEDVal=6 'LED Value for 1
        							LtSwWriteToLED=True 'Finished this code block so it is ok to write to the LED
        							If (LightSwitchDebug=True) Then 'Switch debugging messages are turned on so display them
        								MsgBox("The current light switch position is: DIM (Front). Current switch value is: " & LightSwitchReportedValue & ". Valid numbers for the range are: " & LtDimLoDebug & " - " & LtDimHiDebug & ".",1)
        							Else
        							End If
        						Case (2) 'Set lights to position 2
        							'SetRailSimValue(eRailSimControlID.HEADLIGHTS_ID, 1) 'toggle on headlights
        							MW3.sendScanCode("35:1") 'Press lower-case h (35)
        							MW3.insertDelay(HoldKeyDoubleTime) 'Double the HoldKeyTime for extended keypress
        							MW3.sendScanCode("35:0") 'Release lower-case h (35)
        							LtSwLEDVal=91 'LED Value for 2
        							LtSwWriteToLED=True 'Finished this code block so it is ok to write to the LED
        							If (LightSwitchDebug=True) Then 'Switch debugging messages are turned on so display them
        								MsgBox("The current light switch position is: FULL (Rear). Current switch value is: " & LightSwitchReportedValue & ". Valid numbers for the range are: " & LtFullLoDebug & " - " & LtFullHiDebug & ".",1)
        							Else
        							End If
        						Case (3) 'Light switch is in an area between positions so do nothing
        					End Select
        
        
        					'write switch position to LEDs
        					If (LtSwWriteToLED=True) Then 'OK to write to LEDs
        						Dim OutputReport() as Byte = {0,134,LtSwLEDVal,64,56,0,0,0,0}
        						Dim LtSwLEDDisplayCounter as Integer=0
        						Dim LtSwLEDWriteSpeedCounter as Integer=0
        
        
        						For LtSwLEDDisplayCounter=1 to 200
        							MW3.SendGenericOutput(MyDevice,OutputReport)
        						Next 
        
        
        						'Finished writing L code so get current speed to display
        						Dim speed As Single = GetRailSimValue(30, 0) 'speedometer
        						'make absolute and put in desired units
        						speed=Math.Abs(speed)
        
        
        						If (speedunit=True) Then speed=Math.Abs(speed*1.609344)			
        							Dim speeds As String=speed.ToString("000") 'assumes that the train will never be faster than 999, this rounds also
        
        
        							If (appactive=true) Then 'write current speed if RailWorks is still the active app
        								'write to LEDs
        								Dim AltOutputReport() as Byte = {0,134,ToDigits(speeds.Substring(2, 1)),ToDigits(speeds.Substring(1, 1)),ToDigits(speeds.Substring(0, 1)),0,0,0,0}
        								For LtSwLEDWriteSpeedCounter=1 to 5
        									MW3.SendGenericOutput(MyDevice,AltOutputReport)
        								Next
        								lastspeed=speeds
        							End If
        
        
        						LtSwLEDDisplayCounter=0
        						LtSwLEDWriteSpeedCounter=0
        						LtSwWriteToLED=False
        
        
        					Else 'Do not write to LEDs
        					End If
        					LtSwWriteToLED=False
        
        
        				Else 'The switch is in the same position as last time so do not run the code
        				End if
        
        
        			Else
        			End If 
        			lever(6).LastValue=AnalogValue(0)
        
        
        		End Select 'Analog Check End [/MWTAG13]

        Comment


          #5
          Mods, sorry I did not intend to make 2 topics, if possible, please merge this one and the other one, so that this post appears as the top-most in the topic (so move the other thread into this one as replies if possible).

          Thank you.
          -George
          Last edited by GeorgeT93; 10-12-2011, 01:50 PM.

          Comment


            #6
            To any of the moderators,

            You can unsticky this post now, as the new version of Macroworks for TS2013 has now incorporated this code, so there's no longer a need for any users to manually put this code in.

            Thanks!

            -George

            Comment

            Working...
            X