public void Start()
        {
            if (_cts != null)
            {
                return;
            }

            _cts = new CancellationTokenSource();
            _tkn = _cts.Token;

            Task = new Task(() =>
            {
                // **********************************************************************
                // ** Route Thread
                // **********************************************************************

                bool isRouteSet           = false;                 // flag initialization of route's handling thread
                Locomotive locObject      = null;                  // the current locomotive on the route
                List <ItemData> routeData = new List <ItemData>(); // s88 and switches on the route

                for (;;)
                {
                    var s = SrcBlock.ToString().Replace(" ", "");
                    var d = DestBlock.ToString().Replace(" ", "");

                    if (!isRouteSet)
                    {
                        Route.IsBusy = true;
                        isRouteSet   = true;
                        Autoplayer?.SetRoute(Route, true);
                        int locObjectId = -1;
                        if (Autoplayer != null)
                        {
                            locObjectId = Autoplayer.GetLocObjectIdOfRoute(Route);
                        }
                        locObject = Model.Dispatcher.GetDataProvider().GetObjectBy(locObjectId) as Locomotive;
                        DestBlock.SetLocomotivePreviewObjectId(locObjectId);

                        if (locObject != null)
                        {
                            Model?.LogAutoplay($"{Prefix} Locomotive: {locObject.Name}");
                            Trace.WriteLine($"{Prefix} Locomotive: {locObject.Name}");
                        }

                        TrackWeaveItems weaverItems = new TrackWeaveItems();
                        var weaveFilepath           = Path.Combine(Model.Project.Dirpath, Model.Project.Track.Weave);
                        if (!weaverItems.Load(weaveFilepath))
                        {
                            throw new Exception("Reading weave file failed.");
                        }

                        Dictionary <TrackInfo, List <IItem> > trackObjects = new Dictionary <TrackInfo, List <IItem> >();

                        foreach (var pt in Route)
                        {
                            if (pt == null)
                            {
                                continue;
                            }

                            var item = Model.TrackEntity.Track.Get(pt.X, pt.Y);
                            if (item == null)
                            {
                                continue;
                            }

                            var itemObjects = Model.Dispatcher.Weaver.GetObject(item);
                            if (itemObjects.Count == 0)
                            {
                                continue;
                            }

                            if (trackObjects.ContainsKey(item))
                            {
                                trackObjects[item].AddRange(itemObjects);
                            }
                            else
                            {
                                trackObjects.Add(item, itemObjects);
                            }
                        }

                        #region DEBUG route's track info
                        Trace.WriteLine($"{Prefix} Route's track infos:");
                        foreach (var info in trackObjects.Keys)
                        {
                            var objs = trackObjects[info];

                            Trace.Write($"{Prefix} {info}: ");
                            foreach (var o in objs)
                            {
                                Trace.Write($"{o.ObjectId}, ");
                            }
                            Trace.WriteLine("||");
                        }
                        #endregion

                        Dictionary <TrackInfo, S88> s88TrackObjects = new Dictionary <TrackInfo, S88>();
                        Dictionary <TrackInfo, TrackInformation.Switch> switchTrackObjects = new Dictionary <TrackInfo, TrackInformation.Switch>();

                        #region prepare route data

                        foreach (var trackInfo in trackObjects.Keys)
                        {
                            var itemObjects = trackObjects[trackInfo];
                            if (itemObjects.Count == 0)
                            {
                                continue;
                            }

                            foreach (var obj in itemObjects)
                            {
                                if (obj == null)
                                {
                                    continue;
                                }

                                if (obj is S88)
                                {
                                    s88TrackObjects.Add(trackInfo, obj as S88);
                                }

                                if (obj is TrackInformation.Switch)
                                {
                                    switchTrackObjects.Add(trackInfo, obj as TrackInformation.Switch);
                                }
                            }
                        }

                        foreach (var trackInfo in s88TrackObjects.Keys)
                        {
                            var s88Obj = s88TrackObjects[trackInfo];

                            var fnc = Weaver.GetCheckFnc(s88Obj, trackInfo);
                            if (fnc == null)
                            {
                                Model.LogError($"S88-Checker is missing: {s88Obj}");
                            }

                            var data = new ItemData
                            {
                                Route      = Route,
                                Info       = trackInfo,
                                Item       = s88Obj,
                                S88Checker = fnc
                            };

                            routeData.Add(data);
                        }

                        foreach (var trackInfo in switchTrackObjects.Keys)
                        {
                            var switchObj = switchTrackObjects[trackInfo];

                            var data = new ItemData
                            {
                                Route = Route,
                                Info  = trackInfo,
                                Item  = switchObj
                            };

                            routeData.Add(data);
                        }

                        var sensorsAndEvents = GetBlockData(DestBlock);
                        if (sensorsAndEvents != null)
                        {
                            foreach (var sensorName in sensorsAndEvents.Keys)
                            {
                                var eventName = sensorsAndEvents[sensorName];

                                TrackInfo sensorTrackInfo = null;

                                foreach (var item in Model.TrackEntity.Track)
                                {
                                    if (item == null || string.IsNullOrEmpty(item.Name))
                                    {
                                        continue;
                                    }

                                    if (item.Name.Equals(sensorName))
                                    {
                                        sensorTrackInfo = item;
                                        break;
                                    }
                                }

                                if (sensorTrackInfo != null)
                                {
                                    var it = Get(routeData, sensorTrackInfo.X, sensorTrackInfo.Y);

                                    if (it == null)
                                    {
                                        var s88Obj = Helper.GetObject(Model.Dispatcher, Model.TrackEntity.Track, sensorTrackInfo.X, sensorTrackInfo.Y);

                                        var fnc = Weaver.GetCheckFnc(s88Obj, sensorTrackInfo);
                                        if (fnc == null)
                                        {
                                            Model.LogError($"S88-Checker is missing: {s88Obj}");
                                        }

                                        var data = new ItemData
                                        {
                                            Route          = Route,
                                            Info           = sensorTrackInfo,
                                            Item           = s88Obj,
                                            DestBlockEvent = eventName,
                                            S88Checker     = fnc
                                        };

                                        routeData.Add(data);
                                    }
                                    else
                                    {
                                        it.DestBlockEvent = eventName;
                                    }

                                    Trace.WriteLine($"{Prefix} Sensor({sensorName}) with Event({eventName})");
                                }
                            }
                        }

                        #endregion

                        #region set switches to let the locomotive pass the route

                        foreach (var data in routeData)
                        {
                            if (data == null || !data.IsSwitch || data.ItemSwitch == null)
                            {
                                continue;
                            }

                            var sw = data.ItemSwitch;
                            var v  = data.HasSwitchTurn ? 0 : 1;
                            if (sw.InvertCommand)
                            {
                                if (v == 1)
                                {
                                    v = 0;
                                }
                                else
                                {
                                    v = 1;
                                }
                            }
                            var vs = v == 1 ? "TURN" : "STRAIGHT";
                            Trace.WriteLine($"{Prefix} Switch '{sw.Name1}' change to '{vs}'");
                            sw.ChangeDirection(v);
                        }

                        #endregion

                        if (locObject != null)
                        {
                            locObject.ChangeDirection(false);
                            locObject.ChangeSpeed(locObject.MaxSpeedPercentage);
                        }

                        Model?.LogAutoplay($"{Prefix} {s}  TO  {d}");
                        Trace.WriteLine($"{Prefix} {s}  TO  {d}");

                        Model.UiSyncCtx?.Send((x) =>
                        {
                            Model.TrackEntity.UpdateAllVisualBlocks();
                        }, null);
                    }

                    foreach (var s88Data in routeData)
                    {
                        if (s88Data == null || !s88Data.IsS88 || s88Data.ItemS88 == null)
                        {
                            continue;
                        }

                        if (s88Data.S88HasBeenHandled)
                        {
                            continue;
                        }

                        bool state = false;
                        try
                        {
                            var bb = s88Data.S88Checker();
                            if (bb != null && bb.State != null)
                            {
                                state = bb.State.Value;
                            }
                        }
                        catch (Exception ex)
                        {
                            Model?.LogAutoplay($"{Prefix} {ex.Message}");
                            Trace.WriteLine($"{Prefix} {ex.Message}");
                        }

                        if (state)
                        {
                            s88Data.S88HasBeenHandled = true;

                            //Model?.LogAutoplay($"{Prefix} {s88Data.Info} {s88Data.ItemS88} state '{state}' -> {s88Data.DestBlockEvent}");

                            string evName = s88Data.DestBlockEvent;
                            if (!string.IsNullOrEmpty(evName))
                            {
                                var stopped = false;

                                if (evName.Equals("enter", StringComparison.OrdinalIgnoreCase))
                                {
                                    if (locObject != null)
                                    {
                                        var blockSpeed = locObject.BlockSpeedPercentage;
                                        if (blockSpeed >= locObject.MaxSpeedPercentage)
                                        {
                                            blockSpeed = -1;
                                        }

                                        if (blockSpeed <= 0)
                                        {
                                            var currentSpeed = locObject.Speed;
                                            currentSpeed    -= (int)(currentSpeed / 2.0f);
                                            locObject.ChangeSpeed(currentSpeed);
                                        }
                                        else
                                        {
                                            locObject.ChangeSpeed(blockSpeed);
                                        }

                                        //locObject.ChangeSpeed(Locomotive.SpeedBlockEntered);
                                    }

                                    Trace.WriteLine($"{Prefix} New speed {Locomotive.SpeedBlockEntered} for {locObject.Name}");
                                }
                                else if (evName.Equals("enter in", StringComparison.OrdinalIgnoreCase))
                                {
                                    if (locObject != null)
                                    {
                                        var currentSpeed  = locObject.Speed;
                                        var secondsToStop = 3;
                                        int speedSteps    = currentSpeed / secondsToStop;

                                        var o = locObject;

                                        var task = Task.Run(() =>
                                        {
                                            currentSpeed -= speedSteps;

                                            if (currentSpeed <= 0)
                                            {
                                                o?.ChangeSpeed(Locomotive.SpeedStop);
                                            }
                                            else
                                            {
                                                o?.ChangeSpeed(currentSpeed);
                                            }

                                            Trace.WriteLine($"{Prefix} Loc speed {locObject.Name} is {currentSpeed}");

                                            Thread.Sleep(1 * 1000);
                                        });

                                        task.Wait();

                                        stopped = true;
                                    }
                                }
                                else if (evName.Equals("in", StringComparison.OrdinalIgnoreCase))
                                {
                                    if (locObject != null)
                                    {
                                        locObject.ChangeSpeed(Locomotive.SpeedStop);
                                    }

                                    Trace.WriteLine($"{Prefix} STOP {Locomotive.SpeedStop}");

                                    stopped = true;
                                }

                                if (stopped)
                                {
                                    // move loc from source block to destination block
                                    // reset current route
                                    // be ready for next routing decision

                                    SrcBlock.SetLocomotiveObjectId(-1);
                                    DestBlock.SetLocomotiveObjectId(locObject.ObjectId);
                                    DestBlock.SetLocomotivePreviewObjectId(-1);
                                    Model.UiSyncCtx?.Send(x =>
                                    {
                                        Autoplayer.SetRoute(Route, false);
                                        Model.TrackEntity.UpdateAllVisualBlocks();
                                        Model.Save();
                                    }, null);
                                    Route.IsBusy        = false;
                                    Route.StartBusiness = DateTime.MaxValue;
                                    Route.StopBusiness  = DateTime.Now;

                                    if (_cts != null)
                                    {
                                        try
                                        {
                                            _cts.Dispose();
                                            _cts = null;
                                        }
                                        catch
                                        {
                                            // ignore
                                        }
                                    }

                                    return;
                                }
                            }
                        }
                    }

                    #region Thread stuff

                    Thread.Sleep(1 * 125);

                    if (_tkn.IsCancellationRequested)
                    {
                        Trace.WriteLine($"{Prefix} Stop requested...");
                        Route.IsBusy = false;
                        return;
                    }

                    #endregion
                }

                // **********************************************************************
                // ** END Route Thread
                // **********************************************************************
            }, _tkn);

            Task?.Start();
        }
Example #2
0
        /// <summary>
        /// in case there is no route to leave on the sideToLeave
        /// probably the trains' direction must change, if change
        /// is allowed:
        /// (1) check for a new route on the opposide sideToLeave
        /// (2) if one or more route available, check if the train is allowed to change the direction (as well the block) [no check if cleaningPriority:=true]
        /// (3) change the direction
        /// (4) change the sideToLeave
        /// (5) ...start the additional route selection routines
        /// </summary>
        /// <param name="routeList"></param>
        /// <param name="occBlock"></param>
        /// <param name="sideToLeave"></param>
        /// <param name="originalSideEntered"></param>
        /// <param name="locDataEcos"></param>
        /// <param name="locData"></param>
        /// <param name="routesOnOpposide"></param>
        /// <param name="cleaningPriority"></param>
        /// <returns></returns>
        public bool CheckOpposide(
            RouteList routeList,
            Occ.OccBlock occBlock,
            SideMarker sideToLeave,
            SideMarker originalSideEntered,
            Locomotive locDataEcos,
            Locomotives.Data locData,
            out RouteList routesOnOpposide,
            bool cleaningPriority = false)
        {
            routesOnOpposide = new RouteList();

            string step4enterBlockSide;

            var occFromBlock = occBlock.FromBlock;

            if (string.IsNullOrEmpty(occFromBlock))
            {
                return(false);
            }

            LogInfo($"The side to leave {sideToLeave} does not have any route to take.");
            if (sideToLeave == SideMarker.Minus)
            {
                step4enterBlockSide = "'-' Side";
                sideToLeave         = SideMarker.Plus;
            }
            else
            {
                step4enterBlockSide = "'+' Side";
                sideToLeave         = SideMarker.Minus;
            }

            #region (1)

            //
            // (1)
            //
            routesOnOpposide = routeList.GetRoutesWithFromBlock(occFromBlock, sideToLeave, true);
            if (routesOnOpposide.Count == 0)
            {
                LogInfo($"The other side to leave {sideToLeave} does not have any route to take.");
                LogInfo($"No route to take from {occFromBlock} for Locomotive({locDataEcos.Name ?? "-"}).");
                return(false);
            }

            #endregion (1)

            #region (2)

            //
            // (2)
            //
            if (cleaningPriority == false)
            {
                if (locData.Settings.ContainsKey("OptionDirection"))
                {
                    var locState = locData.Settings["OptionDirection"];
                    if (!locState)
                    {
                        LogInfo($"Locomotive({locDataEcos.Name}) is not allowed to change the direction.");
                        return(false);
                    }
                }

                var fbData = GetFeedbackDataOf(occBlock.FromBlock, originalSideEntered);
                if (fbData == null)
                {
                    LogInfo($"No feedback data available for block {occBlock.FromBlock}.");
                    return(false);
                }

                if (fbData.Settings.ContainsKey("OptionDirection"))
                {
                    var blockState = fbData.Settings["OptionDirection"];
                    if (!blockState)
                    {
                        LogInfo($"Block({fbData.BlockId}) does not allow to change the direction.");
                        return(false);
                    }
                }
            }

            #endregion (2)

            #region (3)

            //
            // (3)
            //
            var currentDirection = locDataEcos.Direction;
            var newDirection     = currentDirection == 1 ? 0 : 1;
            if (_ctx.IsSimulationMode())
            {
                locDataEcos.ChangeDirectionSimulation(newDirection == 1);
                _ctx.SaveAll();
                _ctx?._sniffer?.TriggerDataProviderModifiedForSimulation();
            }
            else
            {
                locDataEcos.ChangeDirection(newDirection == 1);
                _ctx?._sniffer?.SendCommandsToEcosStation();
            }

            #endregion (3)

            #region (4)

            //
            // (4)
            //
            // EnterBlockSide = "'+' Side"
            // EnterBlockSide = "'-' Side"
            if (string.IsNullOrEmpty(step4enterBlockSide))
            {
                LogInfo($"Invalid enterBlockSide value for Locomotive({locDataEcos.Name}).");
                return(false);
            }

            locData.EnterBlockSide = step4enterBlockSide;
            SaveLocomotivesAndPromote();
            SaveOccAndPromote();

            #endregion (4)

            return(routesOnOpposide.Count > 0);
        }
Example #3
0
        static void Main(string[] args)
        {
            // Lokomotive: 74 854 DB
            int locToTrigger = 1004;
            int maxSpeed     = 40;

            int  s88id       = 102;      // S88 module
            uint s88pinRight = 16;       // S88 module pin: FB3
            uint s88pinLeft  = 13;       // S88 module pin: FBL4

            int waitDelay = 5 * 1000;

            Locomotive locItem = null;
            S88        s88Item = null;

            bool          isStarted         = false;
            bool          isDrivingBackward = true;
            List <string> cmdsToSend        = null;

            var ws = new WsConnect();

            ws.WsData += (sender, dp) =>
            {
                if (dp.GetObjectBy(s88id) is S88 localS88Item)
                {
                    s88Item = localS88Item;
                }
                if (dp.GetObjectBy(locToTrigger) is Locomotive localLocItem)
                {
                    locItem = localLocItem;
                }

                if (s88Item == null)
                {
                    return;
                }
                if (locItem == null)
                {
                    return;
                }

                var stateRight = (s88Item?.Pin(s88pinRight)).Value;
                var stateLeft  = (s88Item?.Pin(s88pinLeft)).Value;

                if (!isStarted)
                {
                    // drive from right -> left, i.e. backward
                    if (stateRight && !stateLeft)
                    {
                        isDrivingBackward = true;
                    }
                    // drive from left -> right, i.e. forward
                    if (stateLeft && !stateRight)
                    {
                        isDrivingBackward = false;
                    }

                    locItem.ChangeDirection(isDrivingBackward);
                    locItem.ChangeSpeed(maxSpeed, true, true);

                    cmdsToSend = locItem.GetCommands() as List <string>;
                    ws.SendCommands(cmdsToSend);
                    cmdsToSend?.Clear();

                    Console.WriteLine("Started!");

                    isStarted = true;
                }
                else
                {
                    if (isDrivingBackward)
                    {
                        if (stateLeft)
                        {
                            Console.WriteLine("Stop left!");

                            locItem.Stop();
                            locItem.ChangeDirection(false);
                            isDrivingBackward = false;
                            cmdsToSend        = locItem.GetCommands() as List <string>;
                            ws.SendCommands(cmdsToSend);
                            cmdsToSend?.Clear();
                            Console.WriteLine($"Wait {waitDelay} msecs!");
                            Thread.Sleep(waitDelay);

                            Console.WriteLine("Start to right!");
                            locItem.ChangeSpeed(maxSpeed, true, true);
                            cmdsToSend = locItem.GetCommands() as List <string>;
                            ws.SendCommands(cmdsToSend);
                            cmdsToSend?.Clear();
                        }
                    }
                    else
                    {
                        if (stateRight)
                        {
                            Console.WriteLine("Stop right!");

                            locItem.Stop();
                            locItem.ChangeDirection(true);
                            isDrivingBackward = true;
                            cmdsToSend        = locItem.GetCommands() as List <string>;
                            ws.SendCommands(cmdsToSend);
                            cmdsToSend?.Clear();
                            Console.WriteLine($"Wait {waitDelay} msecs!");
                            Thread.Sleep(waitDelay);

                            Console.WriteLine("Start to left!");
                            locItem.ChangeSpeed(maxSpeed, true, true);
                            cmdsToSend = locItem.GetCommands() as List <string>;
                            ws.SendCommands(cmdsToSend);
                            cmdsToSend?.Clear();
                        }
                    }
                }
            };

            var res = ws.ConnectTo("ws://127.0.0.1:10050", new[] {
                "enableS88", "enableLocomotives"
            });

            if (res)
            {
                Console.WriteLine("Wait for data...");
            }

            Console.CancelKeyPress += (sender, eArgs) =>
            {
                QuitEvent.Set();
                eArgs.Cancel = true;
            };

            QuitEvent.WaitOne();
        }