Welcome to TrainThing’s Laptop documentation!¶
Note
Under Active Development.
Todo
TT_4 Add first train.
TT_4¶
This is the top level software for the Laptop, part (4), of the TrainThing¶
- TT_4.main()¶
Setup link to trainThing get status of all sensors call set_signals to set all signals based on sensors/tracks/turnouts watch link for changes in sensors :return:
Module client¶
This module provides: A socket client for the internet (Wi-Fi LAN) connection to the Raspberry Pi (3), running TrainThing software, and on to the Arduino (2), running the DCC++ Base Station. All DCC++ and TrainThing commands strings passed to this module are sent to the Raspberry Pi. All received status messages are converted from bytes to strings bounded by “<” and “>”.
- class client.Client(gg)¶
Establish internet client (Wi-Fi LAN) connection with Raspberry Pi server send ~~ send a message to RPI or SB get ~~ get a response from the RPI que if available -> string
- __init__(gg) None ¶
Initialize link to Raspberry Pi. Start thread to receive responses
Constants:
- FORMAT¶
encoding format
- _send() None ¶
Send command to Raspberry Pi/Arduino
- send(msg: str) None ¶
- _receive() None ¶
Thread to receive responses from RPi/Arduino
- get() str ¶
- stop_client() None ¶
Globals¶
This module defines the global variables that reflect the status of TrainThing physical assets, blocks of track, turnouts and the Crossover.
sys_state -> the current state of the TrainThing system path_names -> string name of each path paths -> the blocks, in order, for each CW path in path_names order requirements -> assets required to move for one block to the next in a path.
Constants:
- globals.B_not: int = 0¶
(int) Block of track not in use.
- globals.B_staging: int = 4¶
(int) Block 14 is being used as the staging yard.
- globals.T_unk: int = 0¶
(int) Turnout is in an unknown state
- globals.T_clear: int = 1¶
(int) Turnout is in the CLEAR state (mainline path)
- globals.T_thrown: int = 2¶
(int) Turnout is in the THROWN state (divergent path)
- globals.X_not: int = 0¶
(int) the crossover is not in use
- globals.X_upLeft: int = 1¶
(int) the crossover is in use for track blocks 7 & 9
- globals.X_upRight: int = 2¶
(int) the crossover is in use for track blocks 8 & 10
- globals.sys_state = 0¶
(int) The current state of TrainThing
- globals.No_train = 0¶
(int) No loco
- globals.RED = 1¶
(int) Order of the red loco
- globals.ORANGE = 2¶
(int) Order of the orange loco
- globals.YELLOW = 3¶
(int) Order of the yellow loco
- globals.GREEN = 4¶
(int) Order of the green loco
- globals.BIGO = 1¶
index into path_names and paths for the Big Oval
- globals.SMALLO = 2¶
index into path_names and paths for the Small Oval
- globals.BIG8 = 3¶
index into path_names and paths for the Big Figure-8
- globals.SMALL8 = 4¶
index into path_names and paths for the Small Figure-8
- globals.BEGINNING = 5¶
index into path_names and paths for exiting the staging yard
- globals.ENDING = 6¶
index into path_names and paths for returning to the staging yard
- globals.GTOUR = 7¶
for testing a grand tour
- globals.requirements = {'10>15': [['T', 11, 2], ['T', 12, 2], ['T', 4, 2], ['B', 15], ['B', 16]], '10>5': [['T', 11, 2], ['T', 12, 1], ['B', 5], ['B', 6]], '10>8': [['X', 2], ['B', 8]], '11>12': [['T', 2, 1], ['B', 12], ['B', 13]], '11>16': [['T', 1, 1], ['B', 16], ['B', 15]], '12>1': [['T', 2, 2], ['T', 8, 2], ['T', 7, 1], ['B', 1]], '12>11': [['T', 2, 1], ['B', 11]], '12>13': [['B', 13]], '12>8': [['T', 2, 2], ['T', 8, 2], ['T', 7, 2], ['B', 8], ['B', 10]], '13>12': [['B', 12]], '13>14': [['T', 3, 1], ['B', 14]], '13>20': [['T', 3, 1], ['B', 20]], '13>4': [['T', 3, 2], ['T', 9, 2], ['T', 10, 1], ['B', 4]], '13>9': [['T', 3, 2], ['T', 9, 2], ['T', 10, 2], ['B', 9], ['B', 7]], '14>13': [['T', 3, 1], ['B', 13], ['B', 12]], '14>15': [['T', 4, 1], ['B', 15], ['B', 16]], '15>10': [['T', 4, 2], ['T', 12, 2], ['T', 11, 2], ['B', 10], ['B', 8]], '15>14': [['T', 4, 1], ['B', 14]], '15>16': [['B', 16]], '15>4': [['T', 4, 2], ['T', 12, 2], ['T', 11, 1], ['B', 4]], '16>1': [['T', 1, 2], ['T', 5, 2], ['T', 6, 1], ['B', 1]], '16>11': [['T', 1, 1], ['B', 11]], '16>15': [['B', 15]], '16>7': [['T', 1, 2], ['T', 5, 2], ['T', 6, 2], ['B', 7], ['B', 9]], '17>15': [['T', 4, 1], ['B', 15]], '18>17': [['B', 17]], '19>18': [['B', 18]], '1>12': [['T', 7, 1], ['T', 8, 2], ['T', 2, 2], ['B', 12], ['B', 13]], '1>16': [['T', 6, 1], ['T', 5, 2], ['T', 1, 2], ['B', 16], ['B', 15]], '1>2': [['T', 7, 1], ['T', 8, 1], ['B', 2], ['B', 3]], '1>6': [['T', 6, 1], ['T', 5, 1], ['B', 6], ['B', 5]], '20>19': [['B', 19]], '2>1': [['T', 8, 1], ['T', 7, 1], ['B', 1]], '2>3': [['B', 3]], '2>8': [['T', 8, 1], ['T', 7, 2], ['B', 8], ['B', 10]], '3>2': [['B', 2]], '3>4': [['T', 9, 1], ['T', 10, 1], ['B', 4]], '3>9': [['T', 9, 1], ['T', 10, 2], ['B', 9], ['B', 7]], '4>13': [['T', 10, 1], ['T', 9, 2], ['T', 3, 2], ['B', 13], ['B', 12]], '4>15': [['T', 11, 1], ['T', 12, 2], ['T', 4, 2], ['B', 15], ['B', 16]], '4>3': [['T', 10, 1], ['T', 9, 1], ['B', 3], ['B', 2]], '4>5': [['T', 11, 1], ['T', 12, 1], ['B', 5], ['B', 6]], '5>10': [['T', 12, 1], ['T', 11, 2], ['B', 10], ['B', 8]], '5>4': [['T', 12, 1], ['T', 11, 1], ['B', 4]], '5>6': [['B', 6]], '6>1': [['T', 5, 1], ['T', 6, 1], ['B', 1]], '6>5': [['B', 5]], '6>7': [['T', 5, 1], ['T', 6, 2], ['B', 7], ['B', 9]], '7>16': [['T', 6, 2], ['T', 5, 2], ['T', 1, 2], ['B', 16], ['B', 15]], '7>6': [['T', 6, 2], ['T', 5, 1], ['B', 6], ['B', 5]], '7>9': [['X', 1], ['B', 9]], '8>10': [['X', 2], ['B', 10]], '8>12': [['T', 7, 2], ['T', 8, 2], ['T', 2, 2], ['B', 12], ['B', 13]], '8>2': [['T', 7, 2], ['T', 8, 1], ['B', 2], ['B', 3]], '9>13': [['T', 10, 2], ['T', 9, 2], ['T', 3, 2], ['B', 13], ['B', 12]], '9>3': [['T', 10, 2], ['T', 9, 1], ['B', 3], ['B', 2]], '9>7': [['X', 1], ['B', 7]]}¶
Assets required to move from one block to the next requirements[‘a>b’][array of assets]
- globals.restart() None ¶
Think I will need this to restart a run
- globals.ir_update(status: str) None ¶
Receives sensor status message from traffic/client and changes the state in IR_status, block_status and turnout_status :param status: string <Qnn> | <qnn> :return: None
Layout¶
This module defines the graphic functions and procedures to draw the TrainThing layout using the current status of blocks of track, turnouts, the crossover, and trains location as reflected in module globals.
- class layout.Layout(gg)¶
- __init__(gg)¶
Defines: self.xover, self.turnout[], self.block[], self.signal[t/f,[x,y],[x,y]] and self.train[]
- start_graph()¶
- update()¶
Do forever loop polling displaying the current status of blocks of track, turnouts, the crossover and the trains.
- set_signal(pol: int, top: bool, aspect: int) None ¶
- stop()¶
- layout.random() x in the interval [0, 1). ¶
Sensors¶
This module receives all changes in sensor status for TrainThing and sets the status of assets for global access //TODO: Needs testing
- class sensors.Sensors(gg, cc, lout)¶
set_14() new_sensor()
- __init__(gg, cc, lout) None ¶
- set_14(inuse: bool) None ¶
when the staging yard is in use, sys_state 0,1,2 & 6 track block 14 is blocked. This controls signals 4,6,9,11 top - ‘blocking’ access to track block 14, protecting the staging yard.
- new_sensor(msg: str) None ¶
When the client module receives a <Q ID> or <q ID> status response from TrainThing the message is passed here. The status of the corresponding block of track or turnout is updated. parse of Sensors ID 1 - 32 relate to track blocks 1 - 16 Sensors ID 33 - 36 relate to staging yard parking places (blocks) 17 - 20 parse of sensors ID 51 - 74 relate to turnouts 1 - 12 :param msg: <Q sensor #> went high or <q sensor #> went low :return: None
Signals¶
This module sets one or all signals based on status of blocks, turnouts and crossover. //TODO: testing needed
- class signals.Signals(gg, cc, lout)¶
lock/unlock used in sys_state 0-1 to hold signals 8 and 33 red lock(pole, top, aspect) force a signal to the given aspect Unlock(pole, top) Release signal update(pole, top) update a signal update_all() update all signals changed(‘TBX’, #) asset changed. update all related signals state_change() system state changed. change signal requirements _valid(pole, top, aspect) check for valid input parameters _one(pole, top) internal evaluate aspect of a signal _set(pole, top, aspect) internal Send command to change aspect of a signal
- signal_control = [[], [False, [['T', 1, 1], ['B', 16], ['B', 15]]], [False, [['T', 2, 1], ['B', 12], ['B', 13]]], [True, [['T', 2, 1], ['B', 11], ['T', 1, 1], ['B', 16]], [['T', 2, 2], ['T', 8, 2], ['T', 7, 2], ['B', 8], ['X', 2], ['B', 10]]], [True, [['B', 13], ['T', 3, 1], ['B', 14]], [['B', 13], ['T', 3, 2], ['T', 9, 2], ['T', 10, 2], ['B', 9]]], [True, [['B', 12], ['T', 2, 1], ['B', 11]], [['B', 12], ['T', 2, 2], ['T', 8, 2], ['T', 7, 2], ['B', 8]]], [True, [['T', 3, 1], ['B', 14], ['T', 4, 1], ['B', 15]], [['T', 3, 2], ['T', 9, 2], ['T', 10, 2], ['B', 9], ['X', 1], ['B', 7]]], [False, [['T', 3, 1], ['B', 13], ['B', 12]]], [False, [['T', 4, 1], ['B', 15], ['B', 16]]], [True, [['T', 4, 1], ['B', 14], ['T', 3, 1], ['B', 13]], [['T', 4, 2], ['T', 12, 2], ['T', 11, 2], ['B', 10], ['X', 2], ['B', 8]]], [True, [['B', 16], ['T', 1, 1], ['B', 11]], [['B', 16], ['T', 1, 2], ['T', 5, 2], ['T', 6, 2], ['B', 7]]], [True, [['B', 15], ['T', 4, 1], ['B', 14]], [['B', 15], ['T', 4, 2], ['T', 12, 2], ['T', 11, 2], ['B', 10]]], [True, [['T', 1, 1], ['B', 11], ['T', 2, 1], ['B', 12]], [['T', 1, 2], ['T', 5, 2], ['T', 6, 2], ['B', 7], ['X', 1], ['B', 9]]], [True, [['T', 6, 1], ['T', 5, 1], ['B', 6], ['B', 5]], [['T', 6, 1], ['T', 5, 2], ['T', 1, 2], ['B', 16], ['B', 15]]], [True, [['T', 7, 1], ['T', 8, 1], ['B', 2], ['B', 3]], [['T', 7, 1], ['T', 8, 2], ['T', 2, 2], ['B', 12], ['B', 13]]], [True, [['T', 8, 1], ['T', 7, 1], ['B', 1], ['T', 6, 1], ['T', 5, 1], ['B', 6]], [['T', 8, 1], ['T', 7, 2], ['B', 8], ['X', 2], ['B', 10]]], [True, [['B', 3], ['T', 9, 1], ['T', 10, 1], ['B', 4]], [['B', 3], ['T', 9, 1], ['T', 10, 2], ['B', 9]]], [True, [['B', 2], ['T', 8, 1], ['T', 7, 1], ['B', 1]], [['B', 2], ['T', 8, 1], ['T', 7, 2], ['B', 8]]], [True, [['T', 9, 1], ['T', 10, 1], ['B', 4], ['T', 11, 1], ['T', 12, 1], ['B', 5]], [['T', 9, 1], ['T', 10, 2], ['B', 9], ['X', 1], ['B', 7]]], [True, [['T', 10, 1], ['T', 9, 1], ['B', 3], ['B', 2]], [['T', 10, 1], ['T', 9, 2], ['T', 3, 2], ['B', 13], ['B', 12]]], [True, [['T', 11, 1], ['T', 12, 1], ['B', 5], ['B', 6]], [['T', 11, 1], ['T', 12, 2], ['T', 4, 2], ['B', 15], ['B', 16]]], [True, [['T', 12, 1], ['T', 11, 1], ['B', 4], ['T', 10, 1], ['T', 9, 1], ['B', 3]], [['T', 12, 1], ['T', 11, 2], ['B', 10], ['X', 2], ['B', 8]]], [True, [['B', 6], ['T', 5, 1], ['T', 6, 1], ['B', 1]], [['B', 6], ['T', 5, 1], ['T', 6, 2], ['B', 7]]], [True, [['B', 5], ['T', 12, 1], ['T', 11, 1], ['B', 4]], [['B', 5], ['T', 12, 1], ['T', 11, 2], ['B', 10]]], [True, [['T', 5, 1], ['T', 6, 1], ['B', 1], ['T', 7, 1], ['T', 8, 1], ['B', 2]], [['T', 5, 1], ['T', 6, 2], ['B', 7], ['X', 1], ['B', 9]]], [True, [['T', 6, 2], ['T', 5, 1], ['B', 6], ['B', 5]], [['T', 6, 2], ['T', 5, 2], ['T', 1, 2], ['B', 16], ['B', 15]]], [True, [['X', 1], ['B', 9], ['T', 10, 2], ['T', 9, 1], ['B', 3]], [['X', 1], ['B', 9], ['T', 10, 2], ['T', 9, 2], ['T', 3, 2], ['B', 13]]], [True, [['T', 7, 2], ['T', 8, 1], ['B', 2], ['B', 3]], [['T', 7, 2], ['T', 8, 2], ['T', 2, 2], ['B', 12], ['B', 13]]], [True, [['X', 2], ['B', 10], ['T', 11, 2], ['T', 12, 1], ['B', 5]], [['X', 2], ['B', 10], ['T', 11, 2], ['T', 12, 2], ['T', 4, 2], ['B', 15]]], [True, [['T', 10, 2], ['T', 9, 1], ['B', 3], ['B', 2]], [['T', 10, 2], ['T', 9, 2], ['T', 3, 2], ['B', 13], ['B', 12]]], [True, [['X', 1], ['B', 7], ['T', 6, 2], ['T', 5, 1], ['B', 6]], [['X', 1], ['B', 7], ['T', 6, 2], ['T', 5, 2], ['T', 1, 2], ['B', 16]]], [True, [['T', 11, 2], ['T', 12, 1], ['B', 5], ['B', 6]], [['T', 11, 2], ['T', 12, 2], ['T', 4, 2], ['B', 15], ['B', 16]]], [True, [['X', 2], ['B', 8], ['T', 7, 2], ['T', 8, 1], ['B', 2]], [['X', 2], ['B', 8], ['T', 7, 2], ['T', 8, 2], ['T', 2, 2], ['B', 12]]], [False, [['T', 4, 1], ['B', 15], ['B', 16]]], [False, [['B', 17], ['T', 4, 1], ['B', 15]]], [False, [['B', 18], ['B', 17]]], [False, [['B', 19], ['B', 18]]]]¶
- signal_default = [[4, 1, [['B', 13], ['T', 3, 1], ['B', 14]]], [6, 1, [['T', 3, 1], ['B', 14], ['T', 4, 1], ['B', 15]]]]¶
- signal_change = [[4, 1, [['B', 13], ['T', 3, 1], ['B', 20]]], [6, 1, [['T', 3, 1], ['B', 20], ['B', 19]]]]¶
- counter = 0¶
- run_control = True¶
- OFF = 0¶
- RED = 1¶
- YELLOW = 2¶
- GREEN = 3¶
- __init__(gg, cc, lout) None ¶
- locked = []¶
- state_change(new: int) None ¶
- _set(pole: int, top: bool, aspect: int) None ¶
send command to Raspberry Pi to set a signal <K pole top aspect :param pole: :param top: :param aspect: :return: None
- _one(pole: int, top: bool) None ¶
check the assets identified for pole/top in signal_control, to define the aspect of the signal then call _set() :param pole: :param top:
- _valid(pole: int, top: bool, aspect: int = 1) bool ¶
check for valid parameters :param pole: Signal pole/tower number 1-36 :param top: True if top signal, False otherwise :param aspect: 1-red, 2-yellow, 3-green, 0-off (33-36 only) :return: True if parameters pole, top and aspect are valid, False otherwise
- lock(pole: int, top: bool, aspect: int) bool ¶
if parameters are valid . Lock a signal to aspect until unlocked :param pole: Signal pole/tower number 1-36 :param top: True if top signal, False if lower semaphore :param aspect: 1-RED, 2-YELLOW, 3-GREEN, 0-OFF (33-36 only) :return bool: True of locked, False if failed (already locked | not valid
- unlock(pole: int, top: bool) bool ¶
if pole/top is locked . removed from list, and set signal :param pole: :param top: :return bool: True if parameters have been locked, False otherwise
- update(pole: int, top: bool) bool ¶
Force the update of a given signal by calling _one() :param pole: :param top: :return: True if parameters are valid
- update_all() bool ¶
update all signals by stepping through signal_control
- changed(btx: str, nnum: int = 0) None ¶
The Block of track | Turnout | Crossover “num” has changed. Update affected signals listed in tables :param btx: :param nnum:
Turnout¶
This module sends all commands to change turnouts.
//TODO: testing needed
- class turnout.Turnout(gg)¶
clear() Set all 12 turnouts to CLEAR set(key: str) key is a pointer into globals requirements, the key is used here as a pointer into rout to identify the Wabbit Smart Rout that will set all turnouts needed to move from block N to M (“N>M”)
- __init__(gg)¶
- rout = {'10>15': '<T 128 1>', '10>5': '<T 127 1>', '11>12': '<T 102 0>', '11>16': '<T 101 0>', '12>1': '<T 124 0>', '12>11': '<T 102 0>', '12>8': '<T 124 1>', '13>14': '<T 103 0>', '13>20': '<T 103 0>', '13>4': '<T 126 0>', '13>9': '<T 126 1>', '14>13': '<T 103 0>', '14>15': '<T 104 0>', '15>10': '<T 128 1>', '15>14': '<T 104 0>', '15>4': '<T 128 0>', '16>1': '<T 122 0>', '16>11': '<T 101 0>', '16>7': '<T 122 1>', '17>15': '<T 104 0>', '1>12': '<T 124 0>', '1>16': '<T 122 0>', '1>2': '<T 123 0>', '1>6': '<T 121 0>', '2>1': '<T 123 0>', '2>8': '<T 123 1>', '3>4': '<T 125 0>', '3>9': '<T 125 1>', '4>13': '<T 126 0>', '4>15': '<T 128 0>', '4>3': '<T 125 0>', '4>5': '<T 127 0>', '5>10': '<T 127 1>', '5>4': '<T 127 0>', '6>1': '<T 121 0>', '6>7': '<T 121 1>', '7>16': '<T 122 1>', '7>6': '<T 121 1>', '8>12': '<T 124 1>', '8>2': '<T 123 1>', '9>13': '<T 126 1>', '9>3': '<T 125 1>'}¶
- static clear() None ¶
Set all 12 turnouts to CLEAR <T 120 0>
- set(key: str) bool ¶
<T ID 0|1> 0-CLEAR 1-THROWN :param key: str index into globals.requirements and self.rout :return: bool True if turnout command sent, else False
Train¶
Each instance of this module will represent one of the 4 trains operating as part of TrainThing
- class train.Train(gg, path: str, direction: str, color: str)¶
Each instance of this class manages the movement of one of the four trains.
__init__: init all self variables, and call setup. setup(path, direction, color): initialize all self variables for this train based on passed values _find_target(path) -> path, direction: _check_change() -> bool: changed _find_key() -> str: on > next _available() -> bool: _set_assets() -> bool: Need to wait _release_assets() -> None: clear required _check_turnouts() -> bool: when all set True _steps() -> None: run() -> None: moves a train based on the state of the train and the state of the system. Abort() -> None: ends this instance of the train clearing all variables.
_add() -> None: _new_path() -> None:
- __init__(gg, path: str, direction: str, color: str) None ¶
Initialize an instance of a train given the path to follow and the color (therefore the location) of the train :param path: Assigned target path for this train :param direction: Assigned direction for the target path (‘CW’, ‘CCW’) :param color: Assigned color for this train (‘red’, ‘orange’, ‘yellow’, ‘green’)
- setup(path: str, direction: str, color: str) None ¶
this is a comment :param path: :param direction: Assigned direction for the target path :param color: :return: None
- _find_target(path: int) tuple ¶
look for the given path in self.gg,target :param path: :return: tuple of found path, direction
- _check_change() bool ¶
if ‘on’ in paths[pointer+1] . if ‘on+1’ in pointer == paths[pointer+1] . switch . return true . else return false else return false :return bool True switched paths:
- _find_key() str ¶
find the key into requirements :return str: key
- _available(key: str) bool ¶
check if all assets are available if all available set all required :return bool: True if all assets are available
- _release_assets(key: str) None ¶
use key to set assets required to false
- _check_turnouts(key: str) bool ¶
check turnout status when all set as required return True else False :return bool:
- _steps() None ¶
0: Check/require assets if all available set required 1: Set turnouts and Xover as required 2: wait for turnouts to change 3: move to next block 4: check for train on next block then release assets, reset to 0 :return:
- run() None ¶
take next step based of train_path & sys_state train_path: meaning depends on which sys_state
- static abort() None ¶
stop the train :return: None
new_path¶
This module/function is included in module train only. Based on sys_state, train_path, and the target path and direction (CW) this function adds “the next” path to where the train needs to follow moving from the staging area, to its target path, and finally back to the staging area.
- new_path._add(self, path: int, direction: bool) None ¶
add a path & direction for this train
- new_path._new_path(self) None ¶
if the current path/direction = t_path/t_CW done else: add new next path to get to the target
if sys_state: 0,1 nothing 2 - if target is small oval or SMALL8 add SMALL8 CW 3 - head to target path/CW 4 - nothing 5 - head to BIG8 CCW 6 - in order ENDING