Example #1
0
        protected override async Task <List <Datum> > PollAsync(CancellationToken cancellationToken)
        {
            List <Datum> data = new List <Datum>();

            Position currentPosition = await GpsReceiver.Get().GetReadingAsync(cancellationToken, false);

            if (currentPosition == null)
            {
                throw new Exception("Failed to get GPS reading.");
            }
            else
            {
                lock (_previousPositionLocker)
                {
                    if (_previousPosition == null)
                    {
                        _previousPosition = currentPosition;
                    }
                    else if (currentPosition.Timestamp > _previousPosition.Timestamp)  // it has happened (rarely) that positions come in out of order...drop any such positions.
                    {
                        data.Add(new SpeedDatum(currentPosition.Timestamp, _previousPosition, currentPosition));
                        _previousPosition = currentPosition;
                    }
                }
            }

            return(data);
        }
Example #2
0
        protected override IEnumerable <Datum> Poll(CancellationToken cancellationToken)
        {
            SpeedDatum datum = null;

            Position currentPosition = GpsReceiver.Get().GetReading(cancellationToken, false);

            if (currentPosition == null)
            {
                throw new Exception("Failed to get GPS reading.");
            }
            else
            {
                lock (_previousPositionLocker)
                {
                    if (_previousPosition == null)
                    {
                        _previousPosition = currentPosition;
                    }
                    else if (currentPosition.Timestamp > _previousPosition.Timestamp)  // it has happened (rarely) that positions come in out of order...drop any such positions.
                    {
                        datum             = new SpeedDatum(currentPosition.Timestamp, _previousPosition, currentPosition);
                        _previousPosition = currentPosition;
                    }
                }
            }

            if (datum == null)
            {
                return(new Datum[] { });  // datum will be null on the first poll and where polls return locations out of order (rare). these should count toward participation.
            }
            else
            {
                return(new Datum[] { datum });
            }
        }
Example #3
0
        public void Initialize(Geolocator geolocator)
        {
            GpsReceiver.Get().Initialize(geolocator);

            try { InitializeXamarinInsights(); }
            catch (Exception ex) { _logger.Log("Failed to initialize Xamarin insights:  " + ex.Message, LoggingLevel.Normal, GetType()); }
        }
Example #4
0
        protected override async Task StopListeningAsync()
        {
            await base.StopListeningAsync();

            await GpsReceiver.Get().RemoveListenerAsync(_positionChangedHandler);

            _previousPosition = null;
        }
Example #5
0
        protected override void Initialize()
        {
            base.Initialize();

            if (!GpsReceiver.Get().Locator.IsGeolocationEnabled)
            {
                string error = "Geolocation is not enabled on this device. Cannot start speed probe.";
                SensusServiceHelper.Get().FlashNotificationAsync(error);
                throw new Exception(error);
            }
        }
Example #6
0
        protected override IEnumerable <Datum> Poll()
        {
            lock (_locker)
            {
                Position currentPosition = GpsReceiver.Get().GetReading();

                Datum[] data = null;

                if (_previousPosition == null || currentPosition == null || currentPosition.Timestamp == _previousPosition.Timestamp)
                {
                    data = new Datum[] { }
                }
                ;
                else
                {
                    // http://www.movable-type.co.uk/scripts/latlong.html

                    double φ1 = DegreesToRadians(_previousPosition.Latitude);
                    double φ2 = DegreesToRadians(currentPosition.Latitude);
                    double Δφ = DegreesToRadians(currentPosition.Latitude - _previousPosition.Latitude);
                    double Δλ = DegreesToRadians(currentPosition.Longitude - _previousPosition.Longitude);

                    double a = Math.Pow(Math.Sin(Δφ / 2), 2) +
                               Math.Cos(φ1) *
                               Math.Cos(φ2) *
                               Math.Pow(Math.Sin(Δλ / 2), 2);

                    var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));

                    var reportedDistKM = 6371 * c;

                    double elapsedHours     = new TimeSpan(currentPosition.Timestamp.Ticks - _previousPosition.Timestamp.Ticks).TotalHours;
                    double reportedSpeedKPH = reportedDistKM / elapsedHours;

                    float accuracy = 0;
                    if (_previousPosition.Accuracy >= 0 && currentPosition.Accuracy >= 0)
                    {
                        double maxDistKM   = reportedDistKM + _previousPosition.Accuracy / 1000f + currentPosition.Accuracy / 1000f;
                        double maxSpeedKPH = maxDistKM / elapsedHours;
                        accuracy = (float)(maxSpeedKPH - reportedSpeedKPH);
                    }

                    data = new SpeedDatum[] { new SpeedDatum(currentPosition.Timestamp, accuracy, (float)reportedSpeedKPH) };
                }

                if (currentPosition != null)
                {
                    _previousPosition = currentPosition;
                }

                return(data);
            }
        }
Example #7
0
        protected override void Initialize()
        {
            base.Initialize();

            if (!GpsReceiver.Get().Locator.IsGeolocationEnabled || !GpsReceiver.Get().Locator.SupportsHeading)
            {
                // throw standard exception instead of NotSupportedException, since the user might decide to enable GPS in the future
                // and we'd like the probe to be restarted at that time.
                string error = "Geolocation / heading are not enabled on this device. Cannot start compass probe.";
                SensusServiceHelper.Get().FlashNotificationAsync(error);
                throw new Exception(error);
            }
        }
        public override async Task LetDeviceSleepAsync()
        {
            lock (_keepAwakeLocker)
            {
                if (_keepAwakeEnabled)
                {
                    _keepAwakeEnabled = false;
                }
                else
                {
                    Logger.Log("Attempted to let device sleep, but keep-awake was already disabled.", LoggingLevel.Normal, GetType());
                    return;
                }
            }

            Logger.Log("Disabling keep-awake by removing GPS listener.", LoggingLevel.Normal, GetType());
            await GpsReceiver.Get().RemoveListenerAsync(KeepAwakePositionChanged);
        }
        public override async Task KeepDeviceAwakeAsync()
        {
            lock (_keepAwakeLocker)
            {
                if (_keepAwakeEnabled)
                {
                    Logger.Log("Attempted to keep device awake, but keep-awake is already enabled.", LoggingLevel.Normal, GetType());
                    return;
                }
                else
                {
                    _keepAwakeEnabled = true;
                }
            }

            Logger.Log("Enabling keep-awake by adding GPS listener.", LoggingLevel.Normal, GetType());
            await GpsReceiver.Get().AddListenerAsync(KeepAwakePositionChanged, false);
        }
Example #10
0
        protected override IEnumerable <Datum> Poll(CancellationToken cancellationToken)
        {
            lock (_locker)
            {
                Position currentPosition = null;

                try
                {
                    currentPosition = GpsReceiver.Get().GetReading(cancellationToken);
                }
                catch (Exception ex)
                {
                    SensusServiceHelper.Get().Logger.Log("Failed to get GPS reading:  " + ex.Message, LoggingLevel.Normal, GetType());
                }

                SpeedDatum datum = null;

                if (currentPosition != null)
                {
                    if (_previousPosition == null)
                    {
                        _previousPosition = currentPosition;
                    }
                    else if (currentPosition.Timestamp > _previousPosition.Timestamp)  // it has happened (rarely) that positions come in out of order...drop any such positions.
                    {
                        datum             = new SpeedDatum(currentPosition.Timestamp, _previousPosition, currentPosition);
                        _previousPosition = currentPosition;
                    }
                }

                if (datum == null)
                {
                    return new Datum[] { }
                }
                ;
                else
                {
                    return new Datum[] { datum }
                };
            }
        }
Example #11
0
        public Main()
        {
            InitializeComponent();

            var earth = CentralBodiesFacet.GetFromContext().Earth;

            // Load the GPS satellites from the almanac, including transmitters for specific block types,
            // using the data from the GPSData.txt file.
            m_gpsConstellation = GetGpsCommunicationsConstellation();

            // create the receiver using a standard setup
            m_receiver = new GpsReceiver
            {
                NumberOfChannels     = 12,
                ReceiverSolutionType = GpsReceiverSolutionType.AllInView, NavigationSatellites = m_gpsConstellation
            };
            m_receiver.ReceiverConstraints.Add(new ElevationAngleConstraint(Trig.DegreesToRadians(5.0)));

            m_location    = new PointCartographic(earth, new Cartographic(Trig.DegreesToRadians(-107.494000), Trig.DegreesToRadians(30.228800), 0));
            m_orientation = new AxesEastNorthUp(earth, m_location);
        }
Example #12
0
        /// <summary>
        /// Run the specified script.
        /// </summary>
        /// <param name="script">Script.</param>
        /// <param name="previousDatum">Previous datum.</param>
        /// <param name="currentDatum">Current datum.</param>
        private void Run(Script script, Datum previousDatum = null, Datum currentDatum = null)
        {
            SensusServiceHelper.Get().Logger.Log($"Running \"{Name}\".", LoggingLevel.Normal, GetType());

            script.RunTime = DateTimeOffset.UtcNow;

            // scheduled scripts have their expiration dates set when they're scheduled. scripts triggered by other probes
            // as well as on-start scripts will not yet have their expiration dates set. so check the script we've been
            // given and set the expiration date if needed. triggered scripts don't have windows, so the only expiration
            // condition comes from the maximum age.
            if (script.ExpirationDate == null && _maxAge.HasValue)
            {
                script.ExpirationDate = script.Birthdate + _maxAge.Value;
            }

            // script could have already expired (e.g., if user took too long to open notification).
            if (script.ExpirationDate.HasValue && script.ExpirationDate.Value < DateTime.Now)
            {
                SensusServiceHelper.Get().Logger.Log("Script expired before it was run.", LoggingLevel.Normal, GetType());
                return;
            }

            // do not run a one-shot script if it has already been run
            if (OneShot && RunTimes.Count > 0)
            {
                SensusServiceHelper.Get().Logger.Log("Not running one-shot script multiple times.", LoggingLevel.Normal, GetType());
                return;
            }

            lock (RunTimes)
            {
                // track participation by recording the current time. use this instead of the script's run timestamp, since
                // the latter is the time of notification on ios rather than the time that the user actually viewed the script.
                RunTimes.Add(DateTime.Now);
                RunTimes.RemoveAll(r => r < Probe.Protocol.ParticipationHorizon);
            }

            #region submit a separate datum indicating each time the script was run.
            Task.Run(async() =>
            {
                // geotag the script-run datum if any of the input groups are also geotagged. if none of the groups are geotagged, then
                // it wouldn't make sense to gather location data from a user.
                double?latitude  = null;
                double?longitude = null;
                DateTimeOffset?locationTimestamp = null;
                if (script.InputGroups.Any(inputGroup => inputGroup.Geotag))
                {
                    try
                    {
                        Position currentPosition = GpsReceiver.Get().GetReading(new CancellationToken(), false);

                        if (currentPosition == null)
                        {
                            throw new Exception("GPS receiver returned null position.");
                        }

                        latitude          = currentPosition.Latitude;
                        longitude         = currentPosition.Longitude;
                        locationTimestamp = currentPosition.Timestamp;
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get().Logger.Log("Failed to get position for script-run datum:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
                }

                await Probe.StoreDatumAsync(new ScriptRunDatum(script.RunTime.Value, Script.Id, Name, script.Id, script.ScheduledRunTime, script.CurrentDatum?.Id, latitude, longitude, locationTimestamp), default(CancellationToken));
            });
            #endregion

            // this method can be called with previous / current datum values (e.g., when the script is first triggered). it
            // can also be called without previous / current datum values (e.g., when triggering on a schedule). if
            // we have such values, set them on the script.

            if (previousDatum != null)
            {
                script.PreviousDatum = previousDatum;
            }

            if (currentDatum != null)
            {
                script.CurrentDatum = currentDatum;
            }

            SensusServiceHelper.Get().AddScriptToRun(script, RunMode);
        }
Example #13
0
 public VideoManager(GpsReceiver gpsRcvr)
 {
     gps = gpsRcvr;
     FpsDisplayer.Elapsed += new System.Timers.ElapsedEventHandler(FpsDisplayer_Tick);
     FpsDisplayer.Interval = 1000;
 }
Example #14
0
 protected sealed override void StopListening()
 {
     GpsReceiver.Get().RemoveListener(_positionChangedHandler);
     _previousPosition = null;
 }
Example #15
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AddProximityTriggerPage"/> class.
        /// </summary>
        /// <param name="proximityProbe">Proximity probe to add trigger to.</param>
        public AddProximityTriggerPage(IPointsOfInterestProximityProbe proximityProbe)
        {
            _proximityProbe = proximityProbe;

            Title = "Add Trigger";

            List <PointOfInterest> pointsOfInterest = SensusServiceHelper.Get().PointsOfInterest.Union(_proximityProbe.Protocol.PointsOfInterest).ToList();

            if (pointsOfInterest.Count == 0)
            {
                Content = new Label
                {
                    Text     = "No points of interest defined. Please define one or more before creating triggers.",
                    FontSize = 20
                };

                return;
            }

            StackLayout contentLayout = new StackLayout
            {
                Orientation     = StackOrientation.Vertical,
                VerticalOptions = LayoutOptions.FillAndExpand
            };

            #region point of interest
            Label pointOfInterestLabel = new Label
            {
                Text     = "POI:",
                FontSize = 20
            };

            Picker pointOfInterestPicker = new Picker
            {
                Title             = "Select POI",
                HorizontalOptions = LayoutOptions.FillAndExpand
            };

            foreach (string poiDesc in pointsOfInterest.Select(poi => poi.ToString()))
            {
                pointOfInterestPicker.Items.Add(poiDesc);
            }

            pointOfInterestPicker.SelectedIndexChanged += (o, e) =>
            {
                if (pointOfInterestPicker.SelectedIndex < 0)
                {
                    _pointOfInterestName = _pointOfInterestType = null;
                }
                else
                {
                    PointOfInterest poi = pointsOfInterest[pointOfInterestPicker.SelectedIndex];
                    _pointOfInterestName = poi.Name;
                    _pointOfInterestType = poi.Type;
                }
            };

            contentLayout.Children.Add(new StackLayout
            {
                Orientation       = StackOrientation.Horizontal,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children          = { pointOfInterestLabel, pointOfInterestPicker }
            });
            #endregion

            #region distance threshold
            Label distanceThresholdLabel = new Label
            {
                Text     = "Distance Threshold (Meters):",
                FontSize = 20
            };

            Entry distanceThresholdEntry = new Entry
            {
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Keyboard          = Keyboard.Numeric
            };

            distanceThresholdEntry.TextChanged += async(o, e) =>
            {
                if (!double.TryParse(distanceThresholdEntry.Text, out _distanceThresholdMeters))
                {
                    _distanceThresholdMeters = -1;
                }
                else if (_distanceThresholdMeters < GpsReceiver.Get().MinimumDistanceThreshold)
                {
                    await SensusServiceHelper.Get().FlashNotificationAsync("Distance threshold must be at least " + GpsReceiver.Get().MinimumDistanceThreshold + ".");
                }
            };

            contentLayout.Children.Add(new StackLayout
            {
                Orientation       = StackOrientation.Horizontal,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children          = { distanceThresholdLabel, distanceThresholdEntry }
            });
            #endregion

            #region threshold direction
            Label thresholdDirectionLabel = new Label
            {
                Text     = "Threshold Direction:",
                FontSize = 20
            };

            ProximityThresholdDirection[] thresholdDirections = new ProximityThresholdDirection[] { ProximityThresholdDirection.Within, ProximityThresholdDirection.Outside };
            Picker thresholdDirectionPicker = new Picker
            {
                Title             = "Select Threshold Direction",
                HorizontalOptions = LayoutOptions.FillAndExpand
            };

            foreach (ProximityThresholdDirection thresholdDirection in thresholdDirections)
            {
                thresholdDirectionPicker.Items.Add(thresholdDirection.ToString());
            }

            thresholdDirectionPicker.SelectedIndexChanged += (o, e) =>
            {
                if (thresholdDirectionPicker.SelectedIndex < 0)
                {
                    _thresholdDirection = ProximityThresholdDirection.Within;
                }
                else
                {
                    _thresholdDirection = thresholdDirections[thresholdDirectionPicker.SelectedIndex];
                }
            };

            contentLayout.Children.Add(new StackLayout
            {
                Orientation       = StackOrientation.Horizontal,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children          = { thresholdDirectionLabel, thresholdDirectionPicker }
            });
            #endregion

            Button okButton = new Button
            {
                Text     = "OK",
                FontSize = 20
            };

            okButton.Clicked += async(o, e) =>
            {
                try
                {
                    _proximityProbe.Triggers.Add(new PointOfInterestProximityTrigger(_pointOfInterestName, _pointOfInterestType, _distanceThresholdMeters, _thresholdDirection));
                    await Navigation.PopAsync();
                }
                catch (Exception ex)
                {
                    string message = "Failed to add trigger:  " + ex.Message;
                    await SensusServiceHelper.Get().FlashNotificationAsync(message);

                    SensusServiceHelper.Get().Logger.Log(message, LoggingLevel.Normal, GetType());
                }
            };

            contentLayout.Children.Add(okButton);

            Content = new ScrollView
            {
                Content = contentLayout
            };
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="PointsOfInterestPage"/> class.
        /// </summary>
        /// <param name="pointsOfInterest">Points of interest to display.</param>
        public PointsOfInterestPage(List <PointOfInterest> pointsOfInterest)
        {
            _pointsOfInterest = pointsOfInterest;

            Title = "Points of Interest";

            _pointsOfInterestList = new ListView();
            _pointsOfInterestList.ItemTemplate = new DataTemplate(typeof(TextCell));
            _pointsOfInterestList.ItemTemplate.SetBinding(TextCell.TextProperty, new Binding(".", stringFormat: "{0}"));
            _pointsOfInterestList.ItemTapped += async(o, e) =>
            {
                if (_pointsOfInterestList.SelectedItem == null)
                {
                    return;
                }

                PointOfInterest selectedPointOfInterest = _pointsOfInterestList.SelectedItem as PointOfInterest;

                string selectedAction = await DisplayActionSheet(selectedPointOfInterest.ToString(), "Cancel", null, "Delete");

                if (selectedAction == "Delete")
                {
                    if (await DisplayAlert("Delete " + selectedPointOfInterest.Name + "?", "This action cannot be undone.", "Delete", "Cancel"))
                    {
                        _pointsOfInterest.Remove(selectedPointOfInterest);
                        _pointsOfInterestList.SelectedItem = null;  // reset it manually, since it isn't done automatically.

                        Bind();
                    }
                }
            };

            Bind();

            Content = _pointsOfInterestList;

            ToolbarItems.Add(new ToolbarItem(null, "plus.png", () =>
            {
                SensusServiceHelper.Get().PromptForInputsAsync(
                    "Define Point Of Interest",
                    new Input[]
                {
                    new SingleLineTextInput("POI Name:", Keyboard.Text)
                    {
                        Required = false
                    },
                    new SingleLineTextInput("POI Type:", Keyboard.Text)
                    {
                        Required = false
                    },
                    new SingleLineTextInput("Address:", Keyboard.Text)
                    {
                        Required = false
                    }
                },
                    null,
                    true,
                    null,
                    null,
                    null,
                    null,
                    false,
                    inputs =>
                {
                    if (inputs == null)
                    {
                        return;
                    }

                    string name    = inputs[0].Value as string;
                    string type    = inputs[1].Value as string;
                    string address = inputs[2].Value as string;

                    if (string.IsNullOrWhiteSpace(name) && string.IsNullOrWhiteSpace(type))
                    {
                        SensusServiceHelper.Get().FlashNotificationAsync("You must enter either a name or type (or both).");
                    }
                    else
                    {
                        Action <List <Position> > addPOI = new Action <List <Position> >(poiPositions =>
                        {
                            SensusContext.Current.MainThreadSynchronizer.ExecuteThreadSafe(async() =>
                            {
                                if (poiPositions != null && poiPositions.Count > 0 && await DisplayAlert("Add POI?", "Would you like to add " + poiPositions.Count + " point(s) of interest?", "Yes", "No"))
                                {
                                    foreach (Position poiPosition in poiPositions)
                                    {
                                        _pointsOfInterest.Add(new PointOfInterest(name, type, poiPosition.ToGeolocationPosition()));

                                        Bind();
                                    }
                                }
                            });
                        });

                        string newPinName = name + (string.IsNullOrWhiteSpace(type) ? "" : " (" + type + ")");

                        if (string.IsNullOrWhiteSpace(address))
                        {
                            // cancel existing token source if we have one
                            if (_gpsCancellationTokenSource != null && !_gpsCancellationTokenSource.IsCancellationRequested)
                            {
                                _gpsCancellationTokenSource.Cancel();
                            }

                            _gpsCancellationTokenSource = new CancellationTokenSource();

                            Plugin.Geolocator.Abstractions.Position gpsPosition = GpsReceiver.Get().GetReading(_gpsCancellationTokenSource.Token);

                            if (gpsPosition != null)
                            {
                                SensusServiceHelper.Get().GetPositionsFromMapAsync(gpsPosition.ToFormsPosition(), newPinName, addPOI);
                            }
                        }
                        else
                        {
                            SensusServiceHelper.Get().GetPositionsFromMapAsync(address, newPinName, addPOI);
                        }
                    }
                });
            }));

            Disappearing += (o, e) =>
            {
                if (_gpsCancellationTokenSource != null && !_gpsCancellationTokenSource.IsCancellationRequested)
                {
                    _gpsCancellationTokenSource.Cancel();
                }
            };
        }
Example #17
0
 protected sealed override void StartListening()
 {
     _previousPosition = null;
     GpsReceiver.Get().AddListener(_positionChangedHandler, false);
 }
Example #18
0
        public void PromptForInputsAsync(Datum triggeringDatum, bool isReprompt, DateTimeOffset firstPromptTimestamp, IEnumerable <InputGroup> inputGroups, CancellationToken?cancellationToken, Action <IEnumerable <InputGroup> > callback)
        {
            new Thread(() =>
            {
                if (inputGroups == null || inputGroups.All(inputGroup => inputGroup == null))
                {
                    callback(inputGroups);
                    return;
                }

                // only one prompt can run at a time...enforce that here.
                lock (PROMPT_FOR_INPUTS_LOCKER)
                {
                    if (PROMPT_FOR_INPUTS_RUNNING)
                    {
                        callback(inputGroups);
                        return;
                    }
                    else
                    {
                        PROMPT_FOR_INPUTS_RUNNING = true;
                    }
                }

                InputGroup[] incompleteGroups = inputGroups.Where(inputGroup => !inputGroup.Complete).ToArray();

                bool firstPageDisplay = true;

                for (int incompleteGroupNum = 0; inputGroups != null && incompleteGroupNum < incompleteGroups.Length && !cancellationToken.GetValueOrDefault().IsCancellationRequested; ++incompleteGroupNum)
                {
                    InputGroup incompleteGroup    = incompleteGroups[incompleteGroupNum];
                    ManualResetEvent responseWait = new ManualResetEvent(false);

                    if (incompleteGroup.Inputs.Count == 1 && incompleteGroup.Inputs[0] is VoiceInput)
                    {
                        VoiceInput promptInput = incompleteGroup.Inputs[0] as VoiceInput;
                        promptInput.RunAsync(triggeringDatum, isReprompt, firstPromptTimestamp, response =>
                        {
                            responseWait.Set();
                        });
                    }
                    else
                    {
                        BringToForeground();

                        Device.BeginInvokeOnMainThread(async() =>
                        {
                            PromptForInputsPage promptForInputsPage = new PromptForInputsPage(incompleteGroup, incompleteGroupNum + 1, incompleteGroups.Length, result =>
                            {
                                if (result == PromptForInputsPage.Result.Cancel || result == PromptForInputsPage.Result.NavigateBackward && incompleteGroupNum == 0)
                                {
                                    inputGroups = null;
                                }
                                else if (result == PromptForInputsPage.Result.NavigateBackward)
                                {
                                    incompleteGroupNum -= 2;              // we're past the first page, so decrement by two so that, after the for-loop post-increment, the previous input group will be shown
                                }
                                responseWait.Set();
                            });

                            await App.Current.MainPage.Navigation.PushModalAsync(promptForInputsPage, firstPageDisplay);          // animate first page
                            firstPageDisplay = false;
                        });
                    }

                    responseWait.WaitOne();
                }

                // geotag input groups if the user didn't cancel and we've got input groups with inputs that are complete and lacking locations
                if (inputGroups != null && incompleteGroups.Any(incompleteGroup => incompleteGroup.Geotag && incompleteGroup.Inputs.Any(input => input.Complete && (input.Latitude == null || input.Longitude == null))))
                {
                    SensusServiceHelper.Get().Logger.Log("Geotagging input groups.", LoggingLevel.Normal, GetType());

                    try
                    {
                        Position currentLocation = GpsReceiver.Get().GetReading(cancellationToken.GetValueOrDefault());

                        if (currentLocation != null)
                        {
                            foreach (InputGroup incompleteGroup in incompleteGroups)
                            {
                                if (incompleteGroup.Geotag)
                                {
                                    foreach (Input input in incompleteGroup.Inputs)
                                    {
                                        if (input.Complete)
                                        {
                                            if (input.Latitude == null)
                                            {
                                                input.Latitude = currentLocation.Latitude;
                                            }

                                            if (input.Longitude == null)
                                            {
                                                input.Longitude = currentLocation.Longitude;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get().Logger.Log("Error geotagging input groups:  " + ex.Message, LoggingLevel.Normal, GetType());
                    }
                }

                callback(inputGroups);

                PROMPT_FOR_INPUTS_RUNNING = false;
            }).Start();
        }
Example #19
0
        protected SensusServiceHelper()
        {
            if (SINGLETON != null)
            {
                throw new SensusException("Attempted to construct new service helper when singleton already existed.");
            }

            _stopped              = true;
            _registeredProtocols  = new ObservableCollection <Protocol>();
            _runningProtocolIds   = new List <string>();
            _healthTestCallbackId = null;
            _idCallback           = new Dictionary <string, ScheduledCallback>();
            _hasher           = new SHA256Managed();
            _pointsOfInterest = new List <PointOfInterest>();

            if (!Directory.Exists(SHARE_DIRECTORY))
            {
                Directory.CreateDirectory(SHARE_DIRECTORY);
            }

            #if DEBUG
            LoggingLevel loggingLevel = LoggingLevel.Debug;
            #elif RELEASE
            LoggingLevel loggingLevel = LoggingLevel.Normal;
            #else
            #error "Unrecognized configuration."
            #endif

            _logger = new Logger(LOG_PATH, loggingLevel, Console.Error);
            _logger.Log("Log file started at \"" + LOG_PATH + "\".", LoggingLevel.Normal, GetType());

            GpsReceiver.Get().Initialize(Geolocator);  // initialize GPS receiver with platform-specific geolocator

            if (Insights.IsInitialized)
            {
                _logger.Log("Xamarin Insights is already initialized.", LoggingLevel.Normal, GetType());
            }
            else if (string.IsNullOrWhiteSpace(XAMARIN_INSIGHTS_APP_KEY))
            {
                _logger.Log("Xamarin Insights API key is empty. Not initializing.", LoggingLevel.Normal, GetType());  // xamarin allows to initialize with a null key, which fails with exception but results in IsInitialized being true. prevent that here.
            }
            else
            {
                try
                {
                    _logger.Log("Initializing Xamarin Insights.", LoggingLevel.Normal, GetType());

                    // wait for startup crash to be logged -- https://insights.xamarin.com/docs
                    Insights.HasPendingCrashReport += (sender, isStartupCrash) =>
                    {
                        if (isStartupCrash)
                        {
                            Insights.PurgePendingCrashReports().Wait();
                        }
                    };

                    InitializeXamarinInsights();
                }
                catch (Exception ex)
                {
                    _logger.Log("Failed to initialize Xamarin insights:  " + ex.Message, LoggingLevel.Normal, GetType());
                }
            }
        }
Example #20
0
 protected sealed override void StartListening()
 {
     GpsReceiver.Get().AddListener(_positionChangedHandler, true);
 }
Example #21
0
        protected override async Task StartListeningAsync()
        {
            await base.StartListeningAsync();

            await GpsReceiver.Get().AddListenerAsync(_positionChangedHandler, true);
        }
        /// <summary>
        /// Method to calculate all the data required for the graphs.
        /// </summary>
        private void OnAddReceiverClick(object sender, EventArgs e)
        {
            #region CreateAndConfigureReceiver
            // Let's create the GPSReceiver. The receiver stores many properties and has a defined location. This location
            // is the point of reference for visibility calculations.
            receiver = new GpsReceiver();

            // add receiver to the tree
            TreeNode newNode = new TreeNode(Localization.Receiver);
            rootNode.Nodes.Add(newNode);

            // Easy reference to Earth Central body used to initialize the ElevationAngleAccessConstraint and
            // to calculate the Az/El/Range Data.
            EarthCentralBody earth = CentralBodiesFacet.GetFromContext().Earth;

            // set the receiver properties based on user selections
            // The receiver has a receiver FrontEnd that contains the visibility and tracking constraints
            // Be sure to convert your angles to Radians!
            double minimumAngle = Trig.DegreesToRadians(Double.Parse(MaskAngle.Text));
            receiver.ReceiverConstraints.Clear();
            receiver.ReceiverConstraints.Add(new ElevationAngleConstraint(earth, minimumAngle));
            receiver.NumberOfChannels = (int)NumberOfChannels.Value;
            receiver.NoiseModel       = new ConstantGpsReceiverNoiseModel(0.8);

            // The receiver's methods of reducing the number of visible satellites to the limit imposed by the number of channels
            if (BestNSolType.Checked)
            {
                receiver.ReceiverSolutionType = GpsReceiverSolutionType.BestN;
            }
            else
            {
                receiver.ReceiverSolutionType = GpsReceiverSolutionType.AllInView;
            }

            // create a new location for the receiver by using the Cartographic type from AGI.Foundation.Coordinates
            // again, remember to convert from degrees to Radians! (except the height of course)
            Cartographic position = new Cartographic(Trig.DegreesToRadians(double.Parse(Longitude.Text)),
                                                     Trig.DegreesToRadians(double.Parse(Latitude.Text)),
                                                     double.Parse(ReceiverHeight.Text));

            // Now create an antenna for the GPS receiver. We specify the location of the antenna by assigning a
            // PointCartographic instance to the LocationPoint property. We specify that the antenna should be oriented
            // according to the typically-used East-North-Up axes by assigning an instance of AxesEastNorthUp to
            // the OrientationAxes property. While the orientation of the antenna won't affect which satellites are visible
            // or tracked in this case, it will affect the DOP values. For example, the EDOP value can be found in
            // DilutionOfPrecision.X, but only if we've configured the antenna to use East-North-Up axes.
            PointCartographic antennaLocationPoint = new PointCartographic(earth, position);
            Platform          antenna = new Platform
            {
                LocationPoint   = antennaLocationPoint,
                OrientationAxes = new AxesEastNorthUp(earth, antennaLocationPoint)
            };
            receiver.Antenna = antenna;

            #endregion

            // update the tree to reflect the correct receiver info
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.FixedMaskAngle + "= {0:0.00} " + Localization.degrees, MaskAngle.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.NumberOfChannels + "= {0}", NumberOfChannels.Value)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.SolutionType + "= {0}", receiver.ReceiverSolutionType == GpsReceiverSolutionType.AllInView ? Localization.AllInView : Localization.BestN)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Latitude + "= {0:0.000000} " + Localization.degrees, Latitude.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Longitude + "= {0:0.000000} " + Localization.degrees, Longitude.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Height + "= {0:0.000} " + Localization.meters, ReceiverHeight.Text)));

            rootNode.Expand();
            newNode.Expand();

            #region CalculateDataForGraphs

            // Now, we'll open the almanac
            SemAlmanac almanac;
            using (Stream stream = openAlmanacDialog.OpenFile())
                using (StreamReader reader = new StreamReader(stream))
                {
                    // Read the SEM almanac from an almanac stream reader.
                    almanac = SemAlmanac.ReadFrom(reader, 1);
                }

            // Now create a PlatformCollection to hold GpsSatellite object instances. The SemAlmanac method CreateSatellitesFromRecords returns
            // just such a collection. We'll use this set of satellites as the set from which we'll try and track. There is a
            // GpsSatellite object for each satellite specified in the almanac.
            PlatformCollection gpsSatellites = almanac.CreateSatelliteCollection();

            // We provide the receiver with the complete set of gpsSatellites to consider for visibility calculations.
            // This is usually all SVs defined in the almanac - however you may want to remove SVs that aren't healthy. This can
            // be done by creating the gpsSatellites collection above using another version of the CreateSatellitesFromRecords method that
            // takes a SatelliteOutageFileReader.
            receiver.NavigationSatellites = gpsSatellites;

            // Optimization opportunity: Add the following code in a thread. This will help for long duration analyses.

            // Now that we have the receiver and location setup, we need to evaluate all the pertinent data.
            // using a SatelliteTrackingEvaluator, we can track satellites and using a DOP Evaluator,
            // we can calculate DOP at a specified time.
            // The receiver's GetSatelliteTrackingEvaluator method will provide a SatelliteTrackingEvaluator for you.
            // Similarly, the GetDilutionOfPrecisionEvaluator provides the DOP evaluator.
            // We create all evaluators in the same EvaluatorGroup for the best performance.

            EvaluatorGroup    group = new EvaluatorGroup();
            Evaluator <int[]> satTrackingEvaluator       = receiver.GetSatelliteTrackingIndexEvaluator(group);
            Evaluator <DilutionOfPrecision> dopEvaluator = receiver.GetDilutionOfPrecisionEvaluator(group);

            // We also need to create an evaluator to compute Azimuth/Elevation for each of the SVs
            MotionEvaluator <AzimuthElevationRange>[] aerEvaluators = new MotionEvaluator <AzimuthElevationRange> [gpsSatellites.Count];
            for (int i = 0; i < gpsSatellites.Count; ++i)
            {
                Platform satellite            = receiver.NavigationSatellites[i];
                VectorTrueDisplacement vector = new VectorTrueDisplacement(antenna.LocationPoint, satellite.LocationPoint);
                aerEvaluators[i] = earth.GetAzimuthElevationRangeEvaluator(vector, group);
            }

            // First we'll initialize the data structures used to plot the data
            for (int i = 0; i < DOPData.Length; i++)
            {
                // PointPairList is defined in the ZedGraph reference
                DOPData[i] = new PointPairList();
            }

            // We need to know which time standard to use here. If the user has specified that GPS time is to be used
            // we need to create the JulianDates with the GlobalPositioningSystemTime standard.
            if (GPSTimeRadio.Checked)
            {
                startjd = new JulianDate(StartTime.Value, TimeStandard.GlobalPositioningSystemTime);
                stopjd  = new JulianDate(StopTime.Value, TimeStandard.GlobalPositioningSystemTime);
            }
            else
            {
                // otherwise, the default time standard is UTC
                startjd = new JulianDate(StartTime.Value);
                stopjd  = new JulianDate(StopTime.Value);
            }

            // Now we''ll create the variables we'll need for iterating through time.
            // The propagator requires a Duration type be used to specify the timestep.
            Duration dur      = stopjd - startjd;
            double   timestep = Double.Parse(TimeStep.Text);

            // Initialize the progressbar with appropriate values
            progressBar1.Maximum = (int)dur.TotalSeconds;
            progressBar1.Step    = (int)timestep;

            // now we'll iterate through time by adding seconds to the start time JulianDate
            // creating a new JulianDate 'evaluateTime' each time step.
            for (double t = 0; t <= dur.TotalSeconds; t += timestep)
            {
                JulianDate evaluateTime = startjd.AddSeconds(t);

                // The string 'trackedSVs' is the start of a string we'll continue to build through this time
                // iteration. It will contain the info we'll need to put in the DOP graph tooltips for the different
                // DOP series (VDOP, HDOP, etc.)
                String trackedSVs = Localization.Tracked + ": ";

                // The evaluator method GetTrackedSatellites will take the current time and the initial list of satellites and
                // determine which satellites can be tracked based on the receiver constraints setup earlier. This method
                // returns a PlatformCollection object as well (though we'll cast each member of the Collection to a GPSSatellite type)
                int[] trackedSatellites = satTrackingEvaluator.Evaluate(evaluateTime);

                foreach (int satelliteIndex in trackedSatellites)
                {
                    Platform satellite = receiver.NavigationSatellites[satelliteIndex];

                    // Now we have access to a Platform object representing a GPS satellite and calculate the azimuth and elevation
                    // of each.  Note that we're just calculating the azimuth and elevation, but could just as easily get the
                    // range as well.
                    AzimuthElevationRange aer = aerEvaluators[satelliteIndex].Evaluate(evaluateTime);

                    // Get the GpsSatelliteExtension attached to the platform. The extension extends a
                    // platform with GPS-specific information. In this case, we need the
                    // satellites PRN.
                    GpsSatelliteExtension extension = satellite.Extensions.GetByType <GpsSatelliteExtension>();

                    // Create two separate PointPairLists to hold the data stored by Time and Azimuth
                    PointPairList thisTimePointList, thisAzPointList;

                    // Before we can arbitrarily create new PointPair Lists, we have to see if the Data Storage structures already contain a list
                    // for this PRN.
                    // The variables AzElData_TimeBased and AzElData_AzimuthBased are dictionaries that hold the PointPairLists using the PRN
                    // as a key. We use this structure to store a large amount of data for every satellite in a single, easy to access, variable.
                    // if the satellite we're currently looking at already has a list defined in the dictionary, we'll use that one, otherwise
                    // we'll create a new list
                    if (AzElData_TimeBased.ContainsKey(extension.PseudoRandomNumber))
                    {
                        thisTimePointList = AzElData_TimeBased[extension.PseudoRandomNumber];
                        AzElData_TimeBased.Remove(extension.PseudoRandomNumber);
                    }
                    else
                    {
                        thisTimePointList = new PointPairList();
                    }

                    if (AzElData_AzimuthBased.ContainsKey(extension.PseudoRandomNumber))
                    {
                        thisAzPointList = AzElData_AzimuthBased[extension.PseudoRandomNumber];
                        AzElData_AzimuthBased.Remove(extension.PseudoRandomNumber);
                    }
                    else
                    {
                        thisAzPointList = new PointPairList();
                    }

                    // Now to get the actual Azimuth and elevation data

                    // Converting your Radians to degrees here makes the data appear in a more readable format. We also constrain the azimuth
                    // to be within the interval [0, 2*pi]
                    double azimuth   = Trig.RadiansToDegrees(Trig.ZeroToTwoPi(aer.Azimuth));
                    double elevation = Trig.RadiansToDegrees(aer.Elevation);
                    #endregion

                    // now create the point for the Azimuth based data
                    PointPair thisAzPoint = new PointPair(azimuth, elevation);
                    // and add the tooltip (ZedGraph uses the Tag property on a PointPair for the tooltip on that datapoint )
                    thisAzPoint.Tag = String.Format("PRN {0}, {1}, " + Localization.Az + ": {2:0.000}, " + Localization.El + ": {3:0.000}", extension.PseudoRandomNumber, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), azimuth, elevation);
                    // and finally add this point to the list
                    thisAzPointList.Add(thisAzPoint);

                    // now we'll do the same for the time-based data, instead of adding the Az and El, we'll add the time and El.
                    // Create a new XDate object to store the time for this point
                    double txd = (double)new XDate(evaluateTime.ToDateTime());
                    // add the time and elevation data to this point
                    PointPair thisTimePoint = new PointPair(txd, Trig.RadiansToDegrees(aer.Elevation));
                    // Create the tooltip tag
                    thisTimePoint.Tag = String.Format("PRN {0}, {1}, " + Localization.Az + ": {2:0.000}, " + Localization.El + ": {3:0.000}", extension.PseudoRandomNumber, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), azimuth, elevation);
                    // finally add this point to the list
                    thisTimePointList.Add(thisTimePoint);

                    //Now that this data is all calculated, we'll add the point lists to the correct data structures for the GpsSatellite we're working with
                    AzElData_TimeBased.Add(extension.PseudoRandomNumber, thisTimePointList);
                    AzElData_AzimuthBased.Add(extension.PseudoRandomNumber, thisAzPointList);

                    // now update the 'trackedSVs' string to be used for the DOP data tooltip
                    // wee need to do this inside the GpsSatellite loop because we need to get the entire list of tracked SVs for this time step.
                    // we won't use this string until we're out of the loop however.
                    trackedSVs += extension.PseudoRandomNumber.ToString() + ", ";
                }

                // now we're out of the GpsSatellite loop, we'll do some string manipulation to get the tooltip for the DOP data.
                // (gets rid of the last inserted comma)
                string svs = trackedSVs.Substring(0, trackedSVs.LastIndexOf(' ') - 1);
                try
                {
                    // Now we use the evaluator to calculate the DilutionOfPrecision for us for this timestep
                    DilutionOfPrecision dop = dopEvaluator.Evaluate(evaluateTime);

                    // if the dop object throws an exception, there aren't enough tracked satellites to form a navigation solution (typically < 4 tracked)
                    // in that case we leave the data for this time unfilled. The graph will then have empty spots for this time.

                    // Here we create a new PointPair and a new XDate to add to the X-Axis
                    PointPair pp;
                    double    txd = (double)new XDate(evaluateTime.ToDateTime());
                    // add the East DOP value and the time to the PointPair and set the tooltip tag property for this series.
                    pp     = new PointPair(txd, dop.X);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.EDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.X);
                    // add the point to the 0th element of the DOPData structure
                    DOPData[0].Add(pp);
                    // repeat for North DOP
                    pp     = new PointPair(txd, dop.Y);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.NDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Y);
                    DOPData[1].Add(pp);
                    // repeat for the Vertical DOP
                    pp     = new PointPair(txd, dop.Z);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.VDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Z);
                    DOPData[2].Add(pp);
                    // repeat for the Horizontal DOP
                    pp     = new PointPair(txd, dop.XY);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.HDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.XY);
                    DOPData[3].Add(pp);
                    // repeat for the Position DOP
                    pp     = new PointPair(txd, dop.Position);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.PDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Position);
                    DOPData[4].Add(pp);
                    // repeat for the Time DOP
                    pp     = new PointPair(txd, dop.Time);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.TDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Time);
                    DOPData[5].Add(pp);
                    // repeat for the Geometric DOP
                    pp     = new PointPair(txd, dop.Geometric);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.GDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Geometric);
                    DOPData[6].Add(pp);

                    // Notice here that the different DOP values (East, North, etc) were denoted by the dop.X, dop.Y etc. This is because the
                    // DOP values could be in any coordinate system. In our case, we're in the ENU coordinate system an X represents East, Y
                    // represents North, Z represents Vertical, XY represents horizontal. You can change the reference frame the DOP is reported in
                    // but you will then have to understand that the dop.X value corresponds to your X-defined axis and so on.
                }
                catch
                {
                    // Do Nothing here - we just won't add the data to the data list
                }
                // update the progress bar - we're done with this time step!
                progressBar1.PerformStep();
            }
            // finally update the graphs
            UpdateDopGraph();
            updateAzElGraph();

            // reset the progress bar
            progressBar1.Value = 0;

            // and set the appropriate button states
            SetControlStates(true);
        }