· 

.NET IoTをやってみる(4)

 

.NET IoTってのがあるらしい。で、そいつでデバイスいじれるってのがちょっとすごいよね。で、ちょっと触ってみちゃう。ちと脱線して正確なタイミングでデバイスを操作するにはどうするかを考える。いやーすごい人がいるもんだね、、、
酒飲んで少し元気になった。
前回(https://sunday-engineer.blogspot.com/2024/02/net-iot3.html)うまくいかなかったSystem.Timers.Timerに代えてSystem.Threading.Timerでやってみる。
独占的超巨大世界企業によるリファレンスはこちら(https://learn.microsoft.com/ja-jp/dotnet/standard/threading/timers)。 で、こういうコードでどうだろう。
  1. using System;
  2. using System.Threading;
  3. using System.Threading.Tasks;
  4. using System.Device.Gpio;
  5. using Iot.Device.Ft232H;
  6. using Iot.Device.FtCommon;
  7. class Program
  8. {
  9.     private static System.Threading.Timer? timer;
  10.     private static Ft232HDevice? ft232h;
  11.     private static GpioController? controller;
  12.     private static int pin;
  13.     private static int ledOn=0;
  14.     private static PinValue[] pin_state={PinValue.High,PinValue.Low};
  15.     static void Main(string[] args)
  16.     {
  17.         ft232h = new Ft232HDevice(FtCommon.GetDevices()[0]);
  18.         controller = ft232h.CreateGpioController();
  19.         pin = Ft232HDevice.GetPinNumberFromString("D7");
  20.         controller.OpenPin(pin, PinMode.Output);
  21.         timer = new Timer(new TimerCallback(TimerTask),null,10,10);
  22.         Console.ReadLine();
  23.         timer.Dispose();
  24.     }
  25.     private static void TimerTask(object timerState)
  26.     {
  27.         ledOn^=1;
  28.         controller.Write(pin, pin_state[ledOn]);
  29.     }
  30. }
ビルドするとやはり警告が出るが、ビルドはできる。(ちなみに一度リファレンスのままビルドしてみましたが、やはり警告が出ます。独占的超巨大世界企業から何か修正方法がアナウンスされることを望む。)
で、出力はというと、、、
いやー、、、またもダメなんよ。明らかにDUTYおかしくなっているし、、、このままだと本当に「タイミングがカス」ってことになる。
先人の知恵を試してみるか。
MicroLibrary.cs
  1. using System;
  2. namespace MicroLibrary
  3. {
  4.     /// <summary>
  5.     /// MicroStopwatch class
  6.     /// </summary>
  7.     public class MicroStopwatch : System.Diagnostics.Stopwatch
  8.     {
  9.         readonly double _microSecPerTick =
  10.             1000000D / System.Diagnostics.Stopwatch.Frequency;
  11.         public MicroStopwatch()
  12.         {
  13.             if (!System.Diagnostics.Stopwatch.IsHighResolution)
  14.             {
  15.                 throw new Exception("On this system the high-resolution " +
  16.                                     "performance counter is not available");
  17.             }
  18.         }
  19.         public long ElapsedMicroseconds
  20.         {
  21.             get
  22.             {
  23.                 return (long)(ElapsedTicks * _microSecPerTick);
  24.             }
  25.         }
  26.     }
  27.     /// <summary>
  28.     /// MicroTimer class
  29.     /// </summary>
  30.     public class MicroTimer
  31.     {
  32.         public delegate void MicroTimerElapsedEventHandler(
  33.                              object sender,
  34.                              MicroTimerEventArgs timerEventArgs);
  35.         public event MicroTimerElapsedEventHandler MicroTimerElapsed;
  36.         System.Threading.Thread _threadTimer = null;
  37.         long _ignoreEventIfLateBy = long.MaxValue;
  38.         long _timerIntervalInMicroSec = 0;
  39.         bool _stopTimer = true;
  40.         public MicroTimer()
  41.         {
  42.         }
  43.         public MicroTimer(long timerIntervalInMicroseconds)
  44.         {
  45.             Interval = timerIntervalInMicroseconds;
  46.         }
  47.         public long Interval
  48.         {
  49.             get
  50.             {
  51.                 return System.Threading.Interlocked.Read(
  52.                     ref _timerIntervalInMicroSec);
  53.             }
  54.             set
  55.             {
  56.                 System.Threading.Interlocked.Exchange(
  57.                     ref _timerIntervalInMicroSec, value);
  58.             }
  59.         }
  60.         public long IgnoreEventIfLateBy
  61.         {
  62.             get
  63.             {
  64.                 return System.Threading.Interlocked.Read(
  65.                     ref _ignoreEventIfLateBy);
  66.             }
  67.             set
  68.             {
  69.                 System.Threading.Interlocked.Exchange(
  70.                     ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value);
  71.             }
  72.         }
  73.         public bool Enabled
  74.         {
  75.             set
  76.             {
  77.                 if (value)
  78.                 {
  79.                     Start();
  80.                 }
  81.                 else
  82.                 {
  83.                     Stop();
  84.                 }
  85.             }
  86.             get
  87.             {
  88.                 return (_threadTimer != null && _threadTimer.IsAlive);
  89.             }
  90.         }
  91.         public void Start()
  92.         {
  93.             if (Enabled || Interval <= 0)
  94.             {
  95.                 return;
  96.             }
  97.             _stopTimer = false;
  98.             System.Threading.ThreadStart threadStart = delegate()
  99.             {
  100.                 NotificationTimer(ref _timerIntervalInMicroSec,
  101.                                   ref _ignoreEventIfLateBy,
  102.                                   ref _stopTimer);
  103.             };
  104.             _threadTimer = new System.Threading.Thread(threadStart);
  105.             _threadTimer.Priority = System.Threading.ThreadPriority.Highest;
  106.             _threadTimer.Start();
  107.         }
  108.         public void Stop()
  109.         {
  110.             _stopTimer = true;
  111.         }
  112.         public void StopAndWait()
  113.         {
  114.             StopAndWait(System.Threading.Timeout.Infinite);
  115.         }
  116.         public bool StopAndWait(int timeoutInMilliSec)
  117.         {
  118.             _stopTimer = true;
  119.             if (!Enabled || _threadTimer.ManagedThreadId ==
  120.                 System.Threading.Thread.CurrentThread.ManagedThreadId)
  121.             {
  122.                 return true;
  123.             }
  124.             return _threadTimer.Join(timeoutInMilliSec);
  125.         }
  126.         public void Abort()
  127.         {
  128.             _stopTimer = true;
  129.             if (Enabled)
  130.             {
  131.                 _threadTimer.Abort();
  132.             }
  133.         }
  134.         void NotificationTimer(ref long timerIntervalInMicroSec,
  135.                                ref long ignoreEventIfLateBy,
  136.                                ref bool stopTimer)
  137.         {
  138.             int timerCount = 0;
  139.             long nextNotification = 0;
  140.             MicroStopwatch microStopwatch = new MicroStopwatch();
  141.             microStopwatch.Start();
  142.             while (!stopTimer)
  143.             {
  144.                 long callbackFunctionExecutionTime =
  145.                     microStopwatch.ElapsedMicroseconds - nextNotification;
  146.                 long timerIntervalInMicroSecCurrent =
  147.                     System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
  148.                 long ignoreEventIfLateByCurrent =
  149.                     System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
  150.                 nextNotification += timerIntervalInMicroSecCurrent;
  151.                 timerCount++;
  152.                 long elapsedMicroseconds = 0;
  153.                 while ( (elapsedMicroseconds = microStopwatch.ElapsedMicroseconds)
  154.                         < nextNotification)
  155.                 {
  156.                     System.Threading.Thread.SpinWait(10);
  157.                 }
  158.                 long timerLateBy = elapsedMicroseconds - nextNotification;
  159.                 if (timerLateBy >= ignoreEventIfLateByCurrent)
  160.                 {
  161.                     continue;
  162.                 }
  163.                 MicroTimerEventArgs microTimerEventArgs =
  164.                      new MicroTimerEventArgs(timerCount,
  165.                                              elapsedMicroseconds,
  166.                                              timerLateBy,
  167.                                              callbackFunctionExecutionTime);
  168.                 MicroTimerElapsed(this, microTimerEventArgs);
  169.             }
  170.             microStopwatch.Stop();
  171.         }
  172.     }
  173.     /// <summary>
  174.     /// MicroTimer Event Argument class
  175.     /// </summary>
  176.     public class MicroTimerEventArgs : EventArgs
  177.     {
  178.         // Simple counter, number times timed event (callback function) executed
  179.         public int TimerCount { get; private set; }
  180.         // Time when timed event was called since timer started
  181.         public long ElapsedMicroseconds { get; private set; }
  182.         // How late the timer was compared to when it should have been called
  183.         public long TimerLateBy { get; private set; }
  184.         // Time it took to execute previous call to callback function (OnTimedEvent)
  185.         public long CallbackFunctionExecutionTime { get; private set; }
  186.         public MicroTimerEventArgs(int timerCount,
  187.                                    long elapsedMicroseconds,
  188.                                    long timerLateBy,
  189.                                    long callbackFunctionExecutionTime)
  190.         {
  191.             TimerCount = timerCount;
  192.             ElapsedMicroseconds = elapsedMicroseconds;
  193.             TimerLateBy = timerLateBy;
  194.             CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
  195.         }
  196.     }
  197. }

Program.cs
  1. using System.Device.Gpio;
  2. using Iot.Device.Ft232H;
  3. using Iot.Device.FtCommon;

  4. public class study4{
  5.     private static Ft232HDevice? ft232h;
  6.     private static GpioController? controller;
  7.     private static int pin;
  8.     private static int ledOn=0;
  9.     private static PinValue[] pin_state={PinValue.High,PinValue.Low};
  10.     public static void Main(){
  11.         ft232h = new Ft232HDevice(FtCommon.GetDevices()[0]);
  12.         controller = ft232h.CreateGpioController();
  13.         pin = Ft232HDevice.GetPinNumberFromString("D7");
  14.         controller.OpenPin(pin, PinMode.Output);
  15.         MicroLibrary.MicroTimer microTimer = new MicroLibrary.MicroTimer();
  16.         microTimer.MicroTimerElapsed += new MicroLibrary.MicroTimer.MicroTimerElapsedEventHandler(OnTimedEvent);
  17.         microTimer.Interval = 10000;
  18.         microTimer.Enabled = true;
  19.         Console.ReadLine();
  20.     }
  21.     private static void OnTimedEvent(object sender,MicroLibrary.MicroTimerEventArgs timerEventArgs)
  22.     {
  23.         ledOn^=1;
  24.         controller.Write(pin, pin_state[ledOn]);
  25.     }
  26. }

で、実行すると、
いや、カンペキ。すごいっスken.loveday(@ken-loveday)さん。
で、「タイミングがカス」説について、基本はそうなんだけど、天才によって補われている。ので克服できる。もしかしたら何か背反があるかもしれないけど、ガチで正確なタイミングが必要な場合は利用しよう。

いやーたまにブツ触るとそれはそれで楽しいもんだね。こういうの家でやるのってまぁまぁな投資だけど、あーでもないこーでもないやりながら考えることで、脳が鍛えられるって信じてる。初老の(もはや初老じゃないかも)おじさんの脳トレ。