private async Task <ControlCompletionCheck> BeginControlAsync(SensingAgentState controlState, CancellationToken cancellationToken) { // this is a convenience method for beginning both active and opportunistic control. control state must be one of these two. if (controlState != SensingAgentState.ActiveControl && controlState != SensingAgentState.OpportunisticControl) { throw new Exception("Unrecognized control state: " + controlState); } ControlCompletionCheck controlCompletionCheck = null; if (await TransitionToNewStateAsync(controlState, true, cancellationToken)) { controlCompletionCheck = new ControlCompletionCheck(async controlCompletionCheckCancellationToken => { // the current check is called when a protocol is shutting down, and periodically while the // protocol remains running. as long as the protocol is running and the observed data meet // the control criterion, continue with sensing control; otherwise, end control and return // to idle. if (Protocol.State == ProtocolState.Running && ObservedDataMeetControlCriterion()) { SensusServiceHelper.Logger.Log("Continuing sensing control in state: " + StateDescription, LoggingLevel.Normal, GetType()); } else { await ReturnToIdle(controlCompletionCheckCancellationToken); } return(State); }, ControlCompletionCheckInterval, "Sensus would like to measure your environment. Please open this notification.", "Measuring environment. You may close this alert."); SensusServiceHelper.Logger.Log("Established sensing control in state: " + StateDescription, LoggingLevel.Normal, GetType()); } return(controlCompletionCheck); }
public SensingAgentStateDatum(DateTimeOffset timestamp, SensingAgentState previousState, SensingAgentState currentState, string description) : base(timestamp) { PreviousState = previousState; CurrentState = currentState; Description = description; }
protected override async Task OnStateChangedAsync(SensingAgentState previousState, SensingAgentState currentState, CancellationToken cancellationToken) { await base.OnStateChangedAsync(previousState, currentState, cancellationToken); if (currentState == SensingAgentState.OpportunisticControl) { throw new Exception("Error, opportunistic control should be disabled for this agent"); } var previousDesignDocumentState = ToDesignDocumentState(previousState); var currentDesignDocumentState = ToDesignDocumentState(currentState); if (currentDesignDocumentState != previousDesignDocumentState) { var previousProbes = ToDesignDocumentProbes(previousDesignDocumentState).ToArray(); var currentProbes = ToDesignDocumentProbes(currentDesignDocumentState).ToArray(); var probesToIgnore = previousProbes.Intersect(currentProbes).ToArray(); var probesToStop = previousProbes.Except(probesToIgnore).ToArray(); var probesToStart = currentProbes.Except(probesToIgnore).ToArray(); foreach (var probe in probesToStop) { await probe.StopAsync(); } foreach (var probe in probesToStart) { probe.MaxDataStoresPerSecond = ProbeHz; await probe.StartAsync(); } } }
protected override async Task OnStateChangedAsync(SensingAgentState previousState, SensingAgentState currentState, CancellationToken cancellationToken) { await base.OnStateChangedAsync(previousState, currentState, cancellationToken); if (currentState == SensingAgentState.OpportunisticControl) { // keep device awake await SensusServiceHelper.KeepDeviceAwakeAsync(); // increase sampling rate if (Protocol.TryGetProbe <ICompassDatum, IListeningProbe>(out IListeningProbe compassProbe)) { // increase sampling rate compassProbe.MaxDataStoresPerSecond = 20; // restart probe to take on new settings await compassProbe.RestartAsync(); } } else if (currentState == SensingAgentState.EndingControl) { if (Protocol.TryGetProbe <ICompassDatum, IListeningProbe>(out IListeningProbe compassProbe)) { // decrease sampling rate compassProbe.MaxDataStoresPerSecond = 5; // restart probe to take on original settings await compassProbe.RestartAsync(); } // let device sleep await SensusServiceHelper.LetDeviceSleepAsync(); } }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { SensingAgentState state = (SensingAgentState)value; SensingAgentState label = (SensingAgentState)parameter; return(state == label ? Color.Green : Color.Gray); }
/// <summary> /// A function to map state to the constructs used/defined in the design document /// </summary> /// <param name="state">a sensing agent state</param> /// <returns>The state in terms of design document constructs</returns> private DesignDocumentState ToDesignDocumentState(SensingAgentState state) { if (state == SensingAgentState.ActiveObservation) { return(DesignDocumentState.ListeningWindow); } else if (state == SensingAgentState.ActiveControl) { return(DesignDocumentState.ActivePredictionWindow); } else { return(DesignDocumentState.InactivePredictionWindow); } }
protected override async Task OnStateChangedAsync(SensingAgentState previousState, SensingAgentState currentState, CancellationToken cancellationToken) { await base.OnStateChangedAsync(previousState, currentState, cancellationToken); List <ProtocolSetting> newSettings = new List <ProtocolSetting>(); // first gather up settings to apply as a result of exiting the previous state if (previousState == SensingAgentState.ActiveObservation) { newSettings.AddRange(EndActiveObservationSettings); } // next gather up settings to apply as a result of entering the current state if (currentState == SensingAgentState.ActiveObservation) { newSettings.AddRange(BeginActiveObservationSettings); } else if (currentState == SensingAgentState.OpportunisticControl || currentState == SensingAgentState.ActiveControl) { // hang on to the begin-control statement. we need ensure that the // same statement used to begin control is also used to end it. _ongoingControlStatement = _statementToBeginControl; // reset the begin-control statement. we won't set it again until // control has ended and we've reset the ongoing control statement. _statementToBeginControl = null; // add the begin-control settings newSettings.AddRange(_ongoingControlStatement.BeginControlSettings); // update state description to include the ongoing-control statement StateDescription += ": " + _ongoingControlStatement.Id; } else if (currentState == SensingAgentState.EndingControl) { newSettings.AddRange(_ongoingControlStatement.EndControlSettings); _ongoingControlStatement = null; } if (newSettings.Count > 0) { SensusServiceHelper.Logger.Log("Applying " + newSettings.Count + " protocol setting(s) for transition from " + previousState + " to " + currentState + ".", LoggingLevel.Normal, GetType()); await(Protocol as Protocol).ApplySettingsAsync(newSettings, cancellationToken); } }
protected virtual Task OnStateChangedAsync(SensingAgentState previousState, SensingAgentState currentState, CancellationToken cancellationToken) { StateDescription = previousState + " --> " + currentState; return(Task.CompletedTask); }
/// <summary> /// The state machine for all <see cref="SensingAgent"/> classes. /// </summary> /// <returns><c>true</c>, if the <see cref="SensingAgent"/> transitioned into the new state, <c>false</c> otherwise. If the /// new state equals the current state, then <c>false</c> will be returned indicating no state change.</returns> /// <param name="newState">New state.</param> /// <param name="writeSensingAgentStateDatum">Whether to write a <see cref="ISensingAgentStateDatum"/> to the local data store /// to record the transition, if made.</param> /// <param name="cancellationToken">Cancellation token.</param> private async Task <bool> TransitionToNewStateAsync(SensingAgentState newState, bool writeSensingAgentStateDatum, CancellationToken cancellationToken) { bool stateChanged = false; SensingAgentState?previousState = null; lock (_stateLocker) { if (!_stateIsTransitioning && newState != State) { bool transitionPermitted = false; // the state machine... if (State == SensingAgentState.Idle) { transitionPermitted = newState == SensingAgentState.OpportunisticObservation || newState == SensingAgentState.ActiveObservation; } else if (State == SensingAgentState.OpportunisticObservation) { transitionPermitted = newState == SensingAgentState.Idle || newState == SensingAgentState.OpportunisticControl; } else if (State == SensingAgentState.OpportunisticControl) { transitionPermitted = newState == SensingAgentState.EndingControl; } else if (State == SensingAgentState.ActiveObservation) { transitionPermitted = newState == SensingAgentState.Idle || newState == SensingAgentState.ActiveControl; } else if (State == SensingAgentState.ActiveControl) { transitionPermitted = newState == SensingAgentState.EndingControl; } else if (State == SensingAgentState.EndingControl) { transitionPermitted = newState == SensingAgentState.Idle; } if (transitionPermitted) { previousState = State; State = newState; stateChanged = true; _stateIsTransitioning = true; } } } if (stateChanged) { // notify the concrete class. catch exceptions as we don't know who is implementing this method. try { await OnStateChangedAsync(previousState.Value, State, cancellationToken); if (writeSensingAgentStateDatum) { // record the state change within the protocol's local data store. this needs to come after the // call to the concrete class implementation of OnStateChangedAsync, as the state description might // be updated in that call, and we'd like to use the new description here. Protocol.WriteSensingAgentStateDatum(previousState.Value, State, StateDescription, cancellationToken); } } catch (Exception ex) { SensusServiceHelper.Logger.Log("Exception while notifying concrete class of change from state " + previousState.Value + " to state " + State + ": " + ex.Message, LoggingLevel.Normal, GetType()); throw ex; } finally { _stateIsTransitioning = false; FireStateChangedEvent(); } } return(stateChanged); }