public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            switch (reader.TokenType)
            {
            case JsonToken.StartObject:
                existingValue = existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
                serializer.Populate(reader, existingValue);
                switch (existingValue)
                {
                case ObjectMeta om:
                    var nom = new ObjectMeta
                    {
                        Objects = om.Objects,
                        Meta    = om.Meta.Select(mt => ((JObject)mt).ToObject(GetOJtype(om.Objects.Type))).ToArray(),
                        Ticks   = om.Ticks
                    };
                    return(nom);

                case ObjectStateUpdate osu:
                    var nosu = new ObjectStateUpdate
                    {
                        Objects = osu.Objects,
                        States  = osu.States.Select(mt => ((JObject)mt).ToObject(GetOJtype(osu.Objects.Type)))
                                  .ToArray()
                    };
                    return(nosu);

                case ObjectData oda:
                {
                    var noda = new ObjectData
                    {
                        Objects = oda.Objects,
                        Data    = oda.Data.Select(mt => ((JObject)mt).ToObject(GetOJtype(oda.Objects.Type)))
                                  .ToArray(),
                        Ticks = oda.Ticks
                    };
                    return(noda);
                }

                case ObjectEvent oev:
                {
                    var noda = new ObjectEvent
                    {
                        Objects = oev.Objects,
                        Events  = oev.Events.Select(mt => ((JObject)mt).ToObject(GetOJtype(oev.Objects.Type)))
                                  .ToArray(),
                        Ticks = oev.Ticks
                    };
                    return(noda);
                }
                }
                return(null);

            case JsonToken.Null:
                return(null);

            default:
                throw new JsonSerializationException();
            }
        }
Exemple #2
0
        private void OnUpdateStateCalled(object sender, ObjectStateUpdate objectstateupdate)
        {
            switch (objectstateupdate.Objects.Type)
            {
            case TLCObjectType.Session:
                if (objectstateupdate.Objects.Ids.Length == 1 && objectstateupdate.Objects.Ids[0] == _stateManager.Session.Id &&
                    objectstateupdate.States.Length == 1)
                {
                    var application = (ControlApplication)objectstateupdate.States[0];
                    if (application == null)
                    {
                        throw new JsonRpcException((int)ProtocolErrorCode.InvalidObjectReference,
                                                   "State could not be properly cast to type ControlApplication (object type: TLCObjectType.Session).", null);
                    }
                    if (!application.ControlState.HasValue)
                    {
                        throw new JsonRpcException((int)ProtocolErrorCode.InvalidAttributeValue,
                                                   "ControlState was not set on ControlApplication object.", null);
                    }
                    _logger.Info("TLC set Application.ControlState from {0} to {1}.",
                                 _stateManager.ControlSession.ControlState, application.ControlState);
                    if (_stateManager.ControlSession.ControlState.HasValue)
                    {
                        if (!TLCFIStateChecker.IsControlStateChangeOk(_stateManager.ControlSession.ControlState.Value,
                                                                      application.ControlState.Value))
                        {
                            _logger.Warn("Invalid ControlState transition made by TLC: from {0} to {1}. Resulting behaviour is undefined.",
                                         _stateManager.ControlSession.ControlState, application.ControlState);
                        }
                    }

                    switch (application.ControlState)
                    {
                    case ControlState.Error:
                        State.SessionControl = false;
                        _logger.Error("TLC set Application.ControlState to ControlState.Error.");
                        ControlStateSetToError?.Invoke(this, EventArgs.Empty);
                        break;

                    case ControlState.NotConfigured:
                        State.SessionControl = false;
                        // During startup, accept transition from 0 (error) to NotConfigured
                        if (_stateManager.ControlSession.ReqControlState == ControlState.Error)
                        {
                            _logger.Info("Will confirm ControlState by setting requested state to ControlState.NotConfigured.");
                            Task.Run(() => SetReqControlStateAsync(ControlState.NotConfigured), _sessionCancellationToken);
                        }
                        // Otherwise, if not requested, this transition is false
                        else if (_stateManager.ControlSession.ReqControlState != ControlState.NotConfigured)
                        {
                            _logger.Warn("TLC set Application.ControlState to ControlState.NotConfigured. " +
                                         "(Requested = {0}).", _stateManager.ControlSession.ReqControlState);
                        }
                        break;

                    case ControlState.Offline:
                        State.SessionControl = false;
                        // Accept Offline during startup
                        if ((_stateManager.ControlSession.ReqControlState == ControlState.Error ||
                             _stateManager.ControlSession.ReqControlState == ControlState.NotConfigured) &&
                            _stateManager.ControlSession.ControlState == ControlState.Offline)
                        {
                            _logger.Info("Will confirm ControlState by setting requested state from ControlState.NotConfigured to ControlState.Offline.");
                            Task.Run(() => SetReqControlStateAsync(ControlState.Offline), _sessionCancellationToken);
                        }
                        // Log Offline as false otherwise: the CLA should have requested this first
                        else if (_stateManager.ControlSession.ReqControlState != ControlState.Offline)
                        {
                            _logger.Warn(
                                "TLC set Application.ControlState to ControlState.Offline. (Requested = {0}).",
                                _stateManager.ControlSession.ReqControlState);
                        }
                        // Otherwise Offline was requested
                        else
                        {
                            _logger.Info("TLC set Application.ControlState to ControlState.Offline.");
                            if (_stateManager.ControlSession.Type == ApplicationType.Control)
                            {
                                _logger.Info("Instruction to request control may now be send using RequestSessionStartControl().");
                            }
                        }
                        break;

                    case ControlState.ReadyToControl:
                        State.SessionControl = false;
                        // Log if not as requested
                        if (_stateManager.ControlSession.ReqControlState != ControlState.ReadyToControl)
                        {
                            _logger.Error("TLC set Application.ControlState to ControlState.ReadyToControl, while requested state is {0}.", _stateManager.ControlSession.ReqControlState);
                        }
                        // Otherwise log awaiting StartControl
                        else
                        {
                            _logger.Info("TLC set Application.ControlState to ControlState.ReadyToControl. Now awaiting StartControl.");
                        }
                        break;

                    case ControlState.InControl:
                        // Log if not as requested
                        if (_stateManager.ControlSession.ReqControlState != ControlState.InControl)
                        {
                            _logger.Error("TLC set Application.ControlState to ControlState.InControl. (Requested = {0}).", _stateManager.ControlSession.ReqControlState);
                        }
                        // Otherwise log confirmation
                        else
                        {
                            _logger.Info("TLC set Application.ControlState to ControlState.InControl.");
                        }
                        break;

                    case ControlState.StartControl:
                        // If we requested control, take action to actually take it
                        if (_stateManager.ControlSession.ReqControlState == ControlState.ReadyToControl)
                        {
                            _logger.Info("Application.ControlState set to ControlState.StartControl. (Requested = {0}).", _stateManager.ControlSession.ReqControlState);
                            State.SessionControl        = true;
                            _gotIntersectionControlTime = DateTime.Now;
                            Task.Run(() => SetReqControlStateAsync(ControlState.InControl), _sessionCancellationToken);
                        }
                        // Otherwise, log the error
                        else
                        {
                            var startControlError = "Application.ControlState set to ControlState.StartControl, but application not ready.";
                            _logger.Error(startControlError);
                            throw new JsonRpcException((int)ProtocolErrorCode.Error, startControlError, null);
                        }
                        break;

                    case ControlState.EndControl:
                        // If the application is not in Control, log the error
                        if (_stateManager.ControlSession.ReqControlState != ControlState.InControl &&
                            _stateManager.ControlSession.ReqControlState != ControlState.EndControl)
                        {
                            _logger.Error("TLC set Application.ControlState to ControlState.EndControl. (Requested = {0}).", _stateManager.ControlSession.ReqControlState);
                            throw new JsonRpcException((int)ProtocolErrorCode.Error, "TLC set Application.ControlState to ControlState.EndControl, but application not in control.", null);
                        }
                        else
                        {
                            if (_stateManager.ControlSession.ReqControlState == ControlState.EndControl)
                            {
                                _logger.Info("TLC set Application.ControlState to ControlState.EndControl, which was requested.");
                            }
                            else
                            {
                                if (DateTime.Now.Subtract(_gotIntersectionControlTime) < TimeSpan.FromSeconds(180))
                                {
                                    _logger.Warn("TLC requested EndControl less than 180 after StartControl: {0} seconds.", DateTime.Now.Subtract(_gotIntersectionControlTime).TotalSeconds);
                                }
                                _logger.Info("TLC set Application.ControlState to ControlState.EndControl (outside request). " +
                                             "Confirming by setting requested state.");
                                Task.Run(() => SetReqControlStateAsync(ControlState.EndControl), _sessionCancellationToken);
                            }
                        }
                        break;

                    default:
                        var error = $"Application.ControlState cannot be set to {application.ControlState}: this state is undefined.";
                        _logger.Error(error);
                        throw new JsonRpcException((int)ProtocolErrorCode.Error, error, null);
                    }
                    _stateManager.ControlSession.ControlState = application.ControlState;
                    if (_stateManager.ControlSession.ControlState.Value != ControlState.Error)
                    {
                        _logger.Debug("Application.ControlState set to " + _stateManager.ControlSession.ControlState);
                    }
                }
                else
                {
                    var error = $"UpdateState called with type Session, but {objectstateupdate.Objects.Ids.Length} instead of 1 object provided.";
                    _logger.Error(error);
                    throw new JsonRpcException((int)ProtocolErrorCode.Error, error, null);
                }
                break;

            case TLCObjectType.Intersection:
                for (var i = 0; i < objectstateupdate.Objects.Ids.Length; ++i)
                {
                    var inter = _stateManager.InternalIntersections.FirstOrDefault(x => x.Id == objectstateupdate.Objects.Ids[i]);
                    if (inter == null)
                    {
                        throw new JsonRpcException((int)ProtocolErrorCode.InvalidObjectReference, "Object " + objectstateupdate.Objects.Ids[i] + " unknown", null);
                    }
                    var sinter = (Intersection)objectstateupdate.States[i];
                    inter.StateTicks = sinter.StateTicks;
                    if (sinter.State.HasValue)
                    {
                        inter.State = sinter.State;
                    }
                    if (sinter.ReqState.HasValue)
                    {
                        inter.ReqState = sinter.ReqState;
                    }
                    switch (sinter.State)
                    {
                    case IntersectionControlState.Error:
                    case IntersectionControlState.Dark:
                    case IntersectionControlState.Standby:
                    case IntersectionControlState.AlternativeStandby:
                    case IntersectionControlState.AllRed:
                    case IntersectionControlState.SwitchOn:
                    case IntersectionControlState.SwitchOff:
                        State.IntersectionControl = false;
                        break;

                    case IntersectionControlState.Control:
                        State.IntersectionControl = true;
                        break;

                    default:
                        var error = $"Intersection.State cannot be set to {sinter.State}: This state is undefined.";
                        _logger.Error(error);
                        throw new JsonRpcException((int)ProtocolErrorCode.Error, error, null);
                    }
                    _logger.Debug("Intersection {0} state set to {1}", objectstateupdate.Objects.Ids[i], sinter.State);
                }
                break;

            case TLCObjectType.SignalGroup:
            case TLCObjectType.Detector:
            case TLCObjectType.Output:
            case TLCObjectType.Input:
            case TLCObjectType.Variable:
                for (var i = 0; i < objectstateupdate.Objects.Ids.Length; ++i)
                {
                    var upob = _stateManager.FindObjectById(objectstateupdate.Objects.Ids[i], TLCFIClientStateManager.GetObjectTypeString(objectstateupdate.Objects.Type));
                    if (upob == null)
                    {
                        throw new JsonRpcException((int)ProtocolErrorCode.InvalidObjectReference, "Object " + objectstateupdate.Objects.Ids[i] + " unknown", null);
                    }
                    try
                    {
                        ((TLCObjectBase)upob).CopyState(objectstateupdate.States[i]);
                    }
                    catch (InvalidCastException e)
                    {
                        throw new JsonRpcException((int)ProtocolErrorCode.InvalidObjectReference, "Object " + objectstateupdate.Objects.Ids[i] + " seems not to be of type " + objectstateupdate.Objects.Type, e);
                    }
                }
                break;

            case TLCObjectType.SpecialVehicleEventGenerator:
                if (objectstateupdate.Objects.Ids.Length == 1 && objectstateupdate.Objects.Ids[0] == _stateManager.ControlSession.Id &&
                    objectstateupdate.States.Length == 1)
                {
                    _stateManager.SpvhGenerator.CopyState(objectstateupdate.States[0]);
                }
                else
                {
                    var error = $"UpdateState called with type SpecialVehicleEventGenerator, but {objectstateupdate.Objects.Ids.Length} instead of 1 object provided.";
                    _logger.Error(error);
                    throw new JsonRpcException((int)ProtocolErrorCode.Error, error, null);
                }
                break;

            case TLCObjectType.TLCFacilities:
                var tlcferror = "UpdateState called with type TLCFacilities, which has no state.";
                _logger.Error(tlcferror);
                throw new JsonRpcException((int)ProtocolErrorCode.Error, tlcferror, null);

            default:
                throw new ArgumentOutOfRangeException();
            }
        }