From 05161948af0f6bedbb32ca56f7e1fba28b83db79 Mon Sep 17 00:00:00 2001 From: Chris Tacke Date: Mon, 16 Oct 2023 15:55:03 -0500 Subject: [PATCH] working on sensor service --- source/Meadow.Core/MeadowOS.cs | 3 + source/Meadow.Core/SensorService.cs | 105 ++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 source/Meadow.Core/SensorService.cs diff --git a/source/Meadow.Core/MeadowOS.cs b/source/Meadow.Core/MeadowOS.cs index 75ca7ed3..38b1aaf2 100644 --- a/source/Meadow.Core/MeadowOS.cs +++ b/source/Meadow.Core/MeadowOS.cs @@ -1,5 +1,6 @@ using Meadow.Cloud; using Meadow.Logging; +using Meadow.Peripherals.Sensors; using Meadow.Update; using System; using System.Collections.Generic; @@ -88,6 +89,8 @@ private static async Task Start(string[]? args, IApp? app) ReportAppException(e, "Device (system) Initialization Failure"); } + Resolver.Services.Add(new SensorService()); + if (systemInitialized) { var stepName = "App Initialize"; diff --git a/source/Meadow.Core/SensorService.cs b/source/Meadow.Core/SensorService.cs new file mode 100644 index 00000000..3c36391c --- /dev/null +++ b/source/Meadow.Core/SensorService.cs @@ -0,0 +1,105 @@ +using Meadow.Peripherals.Sensors; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; + +namespace Meadow; + +internal class ThreadedPollingSensorMonitor : ISensorMonitor +{ + public EventHandler SampleAvailable = default!; + + private readonly List<(ISensor sensor, MethodInfo readMethod)> _monitorList = new(); + private Thread? _sampleThread; + private bool _stopRequested = false; + private PropertyInfo? _resultProperty; + private List _sensorList = new(); + private long _tick; + + + public ThreadedPollingSensorMonitor() + { + } + + public void AddSensor(ISensor sensor, TimeSpan updateInterval) + { + // find the Read method, if it exists + // this is just a limitation of C# generics - looking for a better way + var readMethod = sensor.GetType().GetMethod("Read", BindingFlags.Instance | BindingFlags.Public); + + if (readMethod != null) + { + _monitorList.Add((sensor, readMethod)); + } + } + + public void StartSampling(ISensor sensor) + { + if (_sampleThread == null) + { + _sampleThread = new Thread(SamplingThreadProc); + _sampleThread.Start(); + } + + _sensorList.Add(sensor); + } + + private async void SamplingThreadProc() + { + while (!_stopRequested) + { + foreach (var monitor in _monitorList) + { + if (_sensorList.Contains(monitor.sensor)) + { + // TODO: check to see if the sensor should be read + + var task = (Task)monitor.readMethod.Invoke(monitor.sensor, null); + await task.ConfigureAwait(false); + + if (_resultProperty == null) + { + _resultProperty = task.GetType().GetProperty("Result"); + } + SampleAvailable?.Invoke(monitor.sensor, _resultProperty.GetValue(task)); + + _tick++; + } + } + + Thread.Sleep(1000); + } + + _stopRequested = false; + _sampleThread = null; + } + + public void StopSampling(ISensor sensor) + { + _sensorList.Remove(sensor); + } +} + +internal class SensorService : ISensorService +{ + private ThreadedPollingSensorMonitor? _pollMonitor; + + internal SensorService() + { + } + + public void RegisterSensor(ISamplingSensor sensor) + { + if (_pollMonitor == null) + { + _pollMonitor = new ThreadedPollingSensorMonitor(); + } + + if (sensor is ISensor s) + { + _pollMonitor.StartSampling(s); + } + } +}