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(); } }
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(); } }