/// <summary>
        /// Manage a race from real sensor data
        /// </summary>
        public void Start(RaceConfig config, List <Rider> riders)
        {
            Stop();

            CommunicationManager CommunicationManager = new CommunicationManager(source.Token);

            SerialTimingUnit timer = new SerialTimingUnit(CommunicationManager.GetCommunicationDevice(config.TimingUnitId), "timerUnit", source.Token, config.StartTimingGateId, config.EndTimingGateId);

            timing = timer;
            displays.Add(timer);
            BLERiderIdUnit realStartId = new BLERiderIdUnit(CommunicationManager.GetCommunicationDevice(config.StartIdUnitId), "startUnit", config.StartIdRange, source.Token);

            endGate = new BLERiderIdUnit(CommunicationManager.GetCommunicationDevice(config.EndIdUnitId), "finishUnit", config.EndIdRange, source.Token);

            startGate  = realStartId;
            startLight = realStartId;

            startGate?.ClearKnownRiders();
            endGate?.ClearKnownRiders();

            startLight.SetStartLightColor(StartLightColor.YELLOW);

            startGate.AddKnownRiders(riders);

            tracker = new RaceTracker(timing, startGate, endGate, config.ExtractTrackerConfig(), riders);
            HookEvents(tracker);

            CombinedTasks = tracker.Run(source.Token);
        }
        public void Stop()
        {
            startGate?.ClearKnownRiders();
            endGate?.ClearKnownRiders();
            //give the units time to process the commaands
            Thread.Sleep(1000);

            source.Cancel();
            CombinedTasks?.Wait();
            source = new CancellationTokenSource();
            displays.Clear();
        }