2024年2月18日日曜日

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

 

.NET IoTってのがあるらしい。で、そいつでデバイスいじれるってのがちょっとすごいよね。で、ちょっと触ってみちゃう。なんと偶然にも、うちにRaspberry Pi3 Model B+ってのがあるので、これを使って、PN5180 - RFID and NFC reader(https://github.com/dotnet/iot/blob/main/src/devices/Pn5180/README.md)ってのをやってみる。

えー今回はガチで参考サイトのまんまです。Microsoftってソフト屋を強く自認しているのか、結線図とかないじゃんね。まぁコード見りゃわかるわけだけど、この辺が取っつきにくさを醸成していることに気付いてほしい。まぁこれを示すだけでも意味があるので本日ここに示すわけですよ。で、フルのコードはこちら(https://github.com/dotnet/iot/blob/main/src/devices/Pn5180/samples/Program.cs)にあるので見てみる。Raspberry Piの場合"HardwareSpi()"ってのをcallするので、そことPN5180のclassのコードと(https://github.com/dotnet/iot/blob/main/src/devices/Pn5180/Pn5180.cs)を見ると、
RST<--4
BUSY-->2
NSS<--3
ってことが、わかる。
で、その結線図はこんなかんじ、
で、実際にはこんなんなる。
で、、、すまソ、今回は環境整備には触れない。.NET IoTのGetting Started見てください。では、Raspberry Piのターミナルで、
cd worklocal
mkdir dotnet_iot
cd dotnet_iot
mkdir study8
cd study8
dotnet new console
dotnet add package System.Device.Gpio
dotnet add package Iot.Device.Bindings
で、実行してみる。
たぶん、うまく動いている。

ところで、Raspberry Pi 5 がついに日本でも販売され始めました。人気商品なのでまったく購入できるめどはないけど、しかし、お高い。8GB SRAMで15,290JPY(SWITCH SCIENCEで)。ほぼ、パソコン買える値段やん。教育での利用とか、安価で趣味として気軽にコンピューティングを始められるとか、って当初のコンセプトとはだいぶかけ離れていっているような、、、円安の影響だけでもないよね、、、なんか、もう、ちゃうんよね、、、

2024年2月9日金曜日

PN5180(NFC Frontend)を使ってみる(1)

 

PN5180のボードを買ってみた。Amazonで1600JPYくらいで買えるもの。まずはArduinoを使って動かしてみる。

Arduinoでは、ATrappmannって方がライブラリを作ってくれている(https://github.com/ATrappmann/PN5180-Library/tree/master)ので、まずはこれを利用してみる。このライブラリはArduinoの「ライブラリ管理」ではインストールできないので、手動で入れていく。まずはgithubからzipでダウンロードする(gitコマンド使えよって言わんでー)。
で、ArduinoIDEの環境設定
で、「スケッチブックの保存場所」ってのを覚える。
で、その場所にlibrariesってフォルダがあるので、そこに解凍すればいいわけだ。

では、ハード側の準備をするっス。ところで、ArduinoUNO R3,ArdinoUNO R4だと、IOの電圧が5Vで、PN5180のIOは3V系なのでちと困ったことになる。ATrappmannさんのreadmeではレベル変換回路を使っているけど、そいつはメンドクサイ。で、3.3VのArduinoを使えばいいじゃんってことで、今回はSeeeduino XIAO (SAMD)を使う。(最近は3.3VのArduinoハードも増えてきたので、まぁこの辺はラクになった。)
こうなる。NSS, BUSY, RSTはスケッチで指定できるのでどこでもいい。今回は
NSS--1
BUSY--2
RST--3
としている。SPIはSPIのポートで。
実際はこんな感じ。

では、スケッチを書く。ATrappmannさんのところにはISO14443の例がないので、
examples/PN5180-FeliCa/PN5180-FeliCa.ino
をベースにこれをいじって、結果、こうなる。(相変わらずのいきなり感)
  1. #include <PN5180.h>
  2. #include <PN5180ISO14443.h>
  3. #define PN5180_NSS 1
  4. #define PN5180_BUSY 2
  5. #define PN5180_RST 3
  6. PN5180ISO14443 nfc(PN5180_NSS, PN5180_BUSY, PN5180_RST);
  7. void setup() {
  8.   delay(10000);
  9.   pinMode(LED_BUILTIN,OUTPUT);
  10.   digitalWrite(LED_BUILTIN, HIGH);
  11.   Serial.begin(115200);
  12.   Serial.println(F("=================================="));
  13.   Serial.println(F("Uploaded: " __DATE__ " " __TIME__));
  14.   Serial.println(F("PN5180 ISO14443 Test Sketch"));
  15.   nfc.begin();
  16.   Serial.println(F("----------------------------------"));
  17.   Serial.println(F("PN5180 Hard-Reset..."));
  18.   nfc.reset();
  19.   Serial.println(F("----------------------------------"));
  20.   Serial.println(F("Reading product version..."));
  21.   uint8_t productVersion[2];
  22.   nfc.readEEprom(PRODUCT_VERSION, productVersion, sizeof(productVersion));
  23.   Serial.print(F("Product version="));
  24.   Serial.print(productVersion[1]);
  25.   Serial.print(".");
  26.   Serial.println(productVersion[0]);
  27.   if (0xff == productVersion[1]) { // if product version 255, the initialization failed
  28.     Serial.println(F("Initialization failed!?"));
  29.     Serial.println(F("Press reset to restart..."));
  30.     Serial.flush();
  31.     exit(-1); // halt
  32.   }
  33.   
  34.   Serial.println(F("----------------------------------"));
  35.   Serial.println(F("Reading firmware version..."));
  36.   uint8_t firmwareVersion[2];
  37.   nfc.readEEprom(FIRMWARE_VERSION, firmwareVersion, sizeof(firmwareVersion));
  38.   Serial.print(F("Firmware version="));
  39.   Serial.print(firmwareVersion[1]);
  40.   Serial.print(".");
  41.   Serial.println(firmwareVersion[0]);
  42.   Serial.println(F("----------------------------------"));
  43.   Serial.println(F("Reading EEPROM version..."));
  44.   uint8_t eepromVersion[2];
  45.   nfc.readEEprom(EEPROM_VERSION, eepromVersion, sizeof(eepromVersion));
  46.   Serial.print(F("EEPROM version="));
  47.   Serial.print(eepromVersion[1]);
  48.   Serial.print(".");
  49.   Serial.println(eepromVersion[0]);
  50.   Serial.println(F("----------------------------------"));
  51.   Serial.println(F("Enable RF field..."));
  52.   nfc.setupRF();
  53.   digitalWrite(LED_BUILTIN, LOW);
  54. }
  55. uint32_t loopCnt = 0;
  56. bool errorFlag = false;
  57. void loop() {
  58.   digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
  59.   Serial.println(F("----------------------------------"));
  60.   Serial.print(F("Loop #"));
  61.   Serial.println(loopCnt++);
  62.   uint8_t uid[20];
  63.   // check for ISO14443 card
  64.   nfc.reset();
  65.   nfc.setupRF();
  66.   uint8_t uidLength = nfc.readCardSerial(uid);
  67.   if (uidLength > 0) {
  68.     Serial.print(F("ISO14443 card found, UID="));
  69.     for (int i=0; i<uidLength; i++) {
  70.       Serial.print(uid[i] < 0x10 ? " 0" : " ");
  71.       Serial.print(uid[i], HEX);
  72.     }
  73.     Serial.println();
  74.     Serial.println(F("----------------------------------"));
  75.     delay(1000);
  76.     return;
  77.   }
  78.   
  79.   // no card detected
  80.   Serial.println(F("*** No card detected!"));
  81.   digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
  82.   delay(100); // wait for a second
  83. }
では動かしてみる。
ちゃちいタグとカードが付録でついてきたので、ちゃちいタグを使ってみる。
で、こんな感じで何か読み出したものが出力される。
とりあえず、めでたし。

NXPの製品ページによるとPN5180は"何でも来い"的なNFCインタフェースらしい。
10年位前にNFCに関わったときはまだ、ISO14443(MiFARE)のNXP, ISO15693のSTマイクロ, FelicaのSONYってそれぞれがあって、NFC Forumってところでそれらをまとめた仕様がやっとこさできたばっかりで、性能として何を目指せばいいのかわからんかったんだけど、、、今もナゾ。こういうのって製造業泣かせだよなー。複数の組み合わせの評価をどこまでやればいいのかって。

2024年2月3日土曜日

.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)さん。
で、「タイミングがカス」説について、基本はそうなんだけど、天才によって補われている。ので克服できる。もしかしたら何か背反があるかもしれないけど、ガチで正確なタイミングが必要な場合は利用しよう。

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

2024年2月2日金曜日

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

.NET IoTってのがあるらしい。で、そいつでデバイスいじれるってのがちょっとすごいよね。で、ちょっと触ってみちゃう。ちと脱線して正確なタイミングでデバイスを操作するにはどうするかを考える。うまくいかなかったので見る価値のない記事。

で、
dotnet timer micro second
あたりでググるとまぁまぁ出てくるんだけど、もうかなり完成された何かを提供しているものと、質問サイトへの質問かなんかが引っかかって、いい感じに説明したものがない。とりあえず世界的な独占的超巨大企業ドキュメントを探るとSystem.Timers名前空間にTimerクラスってのがあるらしい(https://learn.microsoft.com/ja-jp/dotnet/api/system.timers.timer?view=net-8.0)ので、まずはこちらを参考にする。
で、読んでいくと、設定できるタイマーの単位はミリ秒なので、マイクロ秒が設定できるかはあやしい。いちおう、引数の型はDoubleなのでマイクロ秒を設定できないわけではないと思うが、どんなもんなのか。
では、こんなコードでどうでしょう。

  1. using System;
  2. using System.Timers;
  3. using System.Device.Gpio;
  4. using Iot.Device.Ft232H;
  5. using Iot.Device.FtCommon;
  6. public class study4{
  7.     private static System.Timers.Timer? aTimer;
  8.     private static Ft232HDevice? ft232h;
  9.     private static GpioController? controller;
  10.     private static int pin;
  11.     private static int ledOn=0;
  12.     private static PinValue[] pin_state={PinValue.High,PinValue.Low};
  13.     public static void Main(){
  14.         Console.WriteLine("Blinking LED. Press Ctrl+C to end.");
  15.         ft232h = new Ft232HDevice(FtCommon.GetDevices()[0]);
  16.         controller = ft232h.CreateGpioController();
  17.         pin = Ft232HDevice.GetPinNumberFromString("D7");
  18.         controller.OpenPin(pin, PinMode.Output);
  19.         SetTimer(10);
  20.         Console.WriteLine("\nPress the Enter key to exit the application...\n");
  21.         Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now);
  22.         Console.ReadLine();
  23.         aTimer.Stop();
  24.         aTimer.Dispose();
  25.     }
  26.     private static void OnTimedEvent(Object source, ElapsedEventArgs e)
  27.     {
  28.         ledOn^=1;
  29.         controller.Write(pin, pin_state[ledOn]);
  30.     }
  31.    private static void SetTimer(Double intvl)
  32.    {
  33.         // Create a timer with a two second interval.
  34.         // Hook up the Elapsed event for the timer.
  35.         aTimer=new System.Timers.Timer(intvl);
  36.         aTimer.Elapsed += OnTimedEvent;
  37.         aTimer.AutoReset = true;
  38.         aTimer.Enabled = true;
  39.     }
  40. }

で、やってみる。警告が出るorz。
ちょっとよくわからん。参考サイトとそう変わらんので、たぶん参考サイトのそのままでも同じ警告が出るはず。まぁ動いているようなので気にせず。結果、
、、、がっかりだよ。周期もDutyもおかしい。そして、中には
あきらかに狂ってるでしょ。いやー世の中そんなに甘くないよねー。それにしてもなんなんやろ。何かを間違えちゃったのか、それともそもそも10msなんて扱えないのか。

もちっとやりたかったけど閃輝暗点来たので中断。


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

 

.NET IoTってのがあるらしい。で、そいつでデバイスいじれるってのがちょっとすごいよね。で、ちょっと触ってみちゃう。"Use a GPIO device"と"Use an I2C device"。

こちら(https://dotnet.microsoft.com/ja-jp/apps/iot)が本家。
取り組み内容はこちら(https://learn.microsoft.com/en-us/dotnet/iot/usb)。
まずは"Use a GPIO device"ってことでLED Blink(Lチカってやつやね)をやるんだけど、幸か不幸か使っているボードが↑のサイトと全く同じだから、本当にただそのままやっただけ。
mkdir study2
cd study2
dotnet new console
dotnet add package System.Device.Gpio
dotnet add package Iot.Device.Bindings
code .
ってやってVSCodeで(VSCode使う必要すらないけど)Program.csをこうする。
  1. using System.Device.Gpio;
  2. using Iot.Device.Ft232H;
  3. using Iot.Device.FtCommon;
  4. Console.WriteLine("Blinking LED. Press Ctrl+C to end.");
  5. Ft232HDevice ft232h = new Ft232HDevice(FtCommon.GetDevices()[0]);
  6. GpioController controller = ft232h.CreateGpioController();
  7. int pin = Ft232HDevice.GetPinNumberFromString("D7");
  8. controller.OpenPin(pin, PinMode.Output);
  9. bool ledOn = true;
  10. while (true)
  11. {
  12.     controller.Write(pin, ledOn ? PinValue.High : PinValue.Low);
  13.     Thread.Sleep(1000);
  14.     ledOn = !ledOn;
  15. }
で、うちのLinuxPCのおまじないを唱えて、実行。
そすっと、
うまくいった。

次いってみよー
で、次はBME280(I2C環境センサ)の制御なんやけど、さすがにうちでも何でもかんでもあるわけではない。でDevice Bindingsの中でうちにあるI2Cなものと言ったら、、、VL53L0X(赤外線測距センサ)があるので、これやってみる。ちなみにDevice BindingsのページからVL53L0Xのリンクをつつくと制御例がでてくるんだけど、これって、ハード的にどう接続しているつもりかわからんなーって。きっとRaspberry Piを想定しているんやろうな。TutorialがRaspberry Piでやってたからきっとそうだ。今回はLinuxPC-->FT232H-->VL53L0Xって接続なので、その部分だけが工夫のしどころ(というかBME280の例とのマージが必要なところ)。
cd ..
mkdir study3
cd study3
dotnet new console
dotnet add package System.Device.Gpio
dotnet add package Iot.Device.Bindings
code .
ってやってVSCodeでProgram.csをこうする。
  1. using System.Device.I2c;
  2. using Iot.Device.Vl53L0X;
  3. using Iot.Device.Ft232H;
  4. using Iot.Device.FtCommon;
  5. Console.WriteLine("Hello VL53L0X!");
  6. Ft232HDevice ft232h = new Ft232HDevice(FtCommon.GetDevices()[0]);
  7. I2cConnectionSettings i2cSettings = new I2cConnectionSettings(0, Vl53L0X.DefaultI2cAddress);
  8. using I2cDevice i2cDevice = ft232h.CreateI2cDevice(i2cSettings);
  9. using Vl53L0X vL53L0X = new Vl53L0X(i2cDevice);
  10. Console.WriteLine($"Rev: {vL53L0X.Information.Revision}, Prod: {vL53L0X.Information.ProductId}, Mod: {vL53L0X.Information.ModuleId}");
  11. Console.WriteLine($"Offset in ?m: {vL53L0X.Information.OffsetMicrometers}, Signal rate fixed 400 ?m: {vL53L0X.Information.SignalRateMeasuementFixed400Micrometers}");
  12. vL53L0X.MeasurementMode = MeasurementMode.Continuous;
  13. while (!Console.KeyAvailable)
  14. {
  15.     try
  16.     {
  17.         var dist = vL53L0X.Distance;
  18.         if (dist != (ushort)OperationRange.OutOfRange)
  19.         {
  20.             Console.WriteLine($"Distance: {dist}");
  21.         }
  22.         else
  23.         {
  24.             Console.WriteLine("Invalid data");
  25.         }
  26.     }
  27.     catch (Exception ex)
  28.     {
  29.         Console.WriteLine($"Exception: {ex.Message}");
  30.     }
  31.     Thread.Sleep(500);
  32. }
そして、実行する。
おお。うまくいったー。すっげー簡単なんやけど、、、あれ?これやったら、Arduino+PC上のターミナルソフトで良くね?
以下私見
Arduino
○ ある程度正確なタイミング制御ができる
○ 資料が豊富
○ 小規模なスタンドアロンツールが作れる
× SRAM、Flash、EEPROMの容量が小さい(R4なら十分なので「×」ではないかも)
× PCとの双方向通信が必要な場合にプロトコルの実装が面倒

.NET IoT
○ 揮発不揮発メモリがほぼ無限(いや、本当は有限)
○ バックに巨大企業がついている
× タイミングがカス
× それなりの規模のシステムになる(.NEt IoTがインストールできないといけない)

まぁ良し悪しやね。

「タイミングがカス」説を少し検証してみる。日曜技術者としては思い込み記事や引用だけの記事はできるだけ排除し、実際に自分で確認して記述することを重要視しているので。
では、LED Blinkのタイミングを測定してみようではないか。
まずは、"Use a GPIO device"のコードを利用して、Thread.Sleep()の引数を10に変更する。期待値としては10msでトグルで1周期20msだが、
1周期=21.0652msになってますね。やっぱり「タイミングがカス」は事実なのか?いやコードの実装があまりにも拙いでしょ。Arduinoでも正確なタイミングが必要な時はタイマ割り込みを使うよね。おなじ感じでもうちょっとうまい方法があると思う。

スライサーで玉ねぎの薄切り作ってたら親指の薄切りを作りそうになった。痛い。凹む。色々やる気を失った。

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

 

.NET IoTってのがあるらしい。で、そいつでデバイスいじれるってのがちょっとすごいよね。で、ちょっと触ってみちゃう。"List available devices"まで。

こちら(https://dotnet.microsoft.com/ja-jp/apps/iot)が本家。FT232Hのモジュールがうちにあったので、そいつをちょっくら動かしてみる。ところで、この.NET IoTで扱えるデバイスについてはこちら(https://github.com/dotnet/iot/blob/main/src/devices/README.md?WT.mc_id=dotnet-35129-website)にリストがある。ここにない素晴らしいデバイスもあるんだけど、、、業界の闇だね。プレゼンのうまい会社がイニシアチブをとっちゃう。

では、やってみよー٩( 'ω' )و
で、code .って入力してVSCodeを起動するとこうなる。
で、.NET IoTのチュートリアルにFT232Hの例(https://learn.microsoft.com/en-us/dotnet/iot/usb)が運よくあったので、これをそのままやってみる。

最初の「List available devices」をコピペすると、
こんな感じで赤い線が引かれちゃう。なぜか、、、必要なpackageが開発環境に入ってないからでございます。
dotnet add package System.Device.Gpio
dotnet add package Iot.Device.Bindings
ってのをコマンドプロンプトから実行すればいいらしい。
Tutorialを最初っから通してやればわかるようだけど、なんとも不親切。世の中の人は通してやるほど気が長くないよね。
VSCodeのTerminalで実行するス。すると、赤い線が消える。
で、Terminalで
dotnet build
ってする。
こうなる。で、
dotnet run
ってする。
まぁぼっこぼこにされちゃう。ftd2xx.soがないぞgmksって言われているらしい。いや、こちら(https://github.com/dotnet/iot/blob/main/src/devices/Ft232H/README.md)にLinuxなら要らんって書いてあるような気がするんやけどな(あ、うちは今メインPCはLinuxなんであります)、、、ちなみにWindowsならftdiのドライバがインストールされていればこの段階でちゃんと動きます。
で、エラーメッセージによると、
Unhandled exception. System.DllNotFoundException: Unable to load shared library 'ftd2xx' or one of its dependencies. In order to help diagnose loading problems, consider using a tool like strace. If you're using glibc, consider setting the LD_DEBUG environment variable:
/home/hoge/worklocal/dotnet_iot/study1/bin/Debug/net7.0/runtimes/linux-x64/native/ftd2xx.so: cannot open shared object file: No such file or directory
/usr/lib/dotnet/shared/Microsoft.NETCore.App/7.0.15/ftd2xx.so: cannot open shared object file: No such file or directory
/home/hoge/worklocal/dotnet_iot/study1/bin/Debug/net7.0/ftd2xx.so: cannot open shared object file: No such file or directory
ってなっているので、言われたとおりの場所にftd2xx.soを入れちゃいたくなるけど、それじゃダメだった。

愚直にftdiのドライバをftdiのマニュアルに従って入れていく。
ftdiのドライバのページ(https://ftdichip.com/drivers/d2xx-drivers/)からLinux用ドライバをもってきて、ReadMe.txtを読んで、まったくその通りにすればよい。で、Linuxのkernel次第らしいけど、うちの場合は
sudo rmmod ftdi_sio
sudo rmmod usbserial
までやらんといかんかった。これってデバイスを抜き差しするたんびにせんといかんらしい。要注意や(kernelから消し去ればいいらしいけど、まぁこれはこれで放置する)。で、
でけた。

色々つまずいて、こんなんやったら、DLL直叩きやらpyftdiのほうがいいわいって言いたくなるけど、きっと何かイイコトがあるに違いない。