古川制御日記

佐賀県武雄市の組み込み開発屋ブログ

MATLAB MEXコマンドのメッセージが文字化けする問題

f:id:fullphong:20220322233832p:plain
これだと肝心のエラーメッセージが読めない。。

> setenv('VSLANG', '1033')

これでエラーメッセージが英語になって文字化けしなくなる。 f:id:fullphong:20220322234003p:plain
無事読めた。

MSVCのメッセージは全部英語でも構わないので環境変数自体を変更しておくとより楽そう。

Teratermでログを取る

Teratermで入出力のログを取る設定

Teraterm
よく使われてますが
「ログをとっておけばよかった。。」
「ログはとったけど、この行が出力された時刻が知りたい。。」
等の声を耳にすることがあります。
そのための設定です。

「設定>その他の設定」メニューをクリック

「ログ」タブに切り替える。

  • 「標準のログ保存先フォルダ」を書き込み権限のある適切なフォルダに設定
  • 「オプション」欄の「タイムスタンプ」にチェックを入れる
  • 「標準ログファイル名」を%Y-%m-%d-teraterm-&h.log等にして日付に応じたファイル名とする。
    • strftime フォーマットなるものが使えるみたいです。
    • 詳しくはこちら
    • &hはシリアルポート接続時にはCOMポート名に置き換えられます。(公式には見つけられませんが)

Teraterm起動時に自動的にログを取るようにする設定

TeratermはWin10の場合は%UserProfile%\Documents\TERATERM.INIから起動時に設定を読み込みますのでここに設定を保存します。

これで次回起動時には自動的にロギング開始してくれます。

タイムスタンプのフォーマット指定

ttssh2.osdn.jp

LogTimestampFormat=%Y-%m-%d %H:%M:%S.%N

CC-RXのBIT操作の挙動

#include "platform.h" // for PORTF

// 引数をそのままBITフィールド値にセットする方法
void dio_F5_set(int x) {
    PORTF.PODR.BIT.B5 = x;
    /* 一回読み出してORして書き戻すので排他が必要
       MOV.L #000000DFH, R15
       MOV.L #0008C02FH, R14
       AND [R14].UB, R15
       SHLL #05H, R1
       AND #20H, R1
       OR R1, R15
       MOV.B R15, [R14]
       RTS*/
}

// 定数1をBITフィールドにセットする方法
static inline void dio_F5_ON(void) {
    PORTF.PODR.BIT.B5 = 1;
    /* 定数を代入する分にはBSET命令に展開される。
       MOV.L #0008C02FH, R14
       BSET #05H, [R14].B
       RTS
    */
}

// 定数0をBITフィールドにセットする方法
static inline void dio_F5_OFF(void) {
    PORTF.PODR.BIT.B5 = 0;
    /* 定数を代入する分にはBCLRに展開される
       MOV.L #0008C02FH, R14
       BCLR #05H, [R14].B
       RTS
   */
}

// 引数で事前に条件分岐して定数を書く方法
void dio_F5_set2(int x) {
    if (x) {
        PORTF.PODR.BIT.B5 = 1;
    } else {
        PORTF.PODR.BIT.B5 = 0;
    }
    /*
       これならBSET,BCLRが呼ばれるため排他不要で使い勝手が良さそう
       CMP #00H, R1
       MOV.L #0008C02FH, R14
       BNE L356
L355:  ; if_else_bb
       BCLR #05H, [R14].B
       RTS
L356:  ; if_then_bb
       BSET #05H, [R14].B
       RTS

   */
}

void dio_F5_set3(int x) {
    if (x) {
        dio_F5_ON();
    } else {
        dio_F5_OFF();
    }
}

e2 studio(というかEclipse CDT)のCプロジェクトにC++ファイルを追加したくなったときの対処方法

  • .project(XMLファイル)のnatures要素の子の中に<nature>org.eclipse.cdt.core.ccnature</nature>という要素を追加
  • ビルド成果物フォルダを一旦削除
  • 再ビルド でいけた。

プロジェクトを作る段階でToolchain Settingsで言語を選ばさられるが、 結果的作られる.cproject, .projectのファイルとしてはこの部分しか違いがない。

www.eclipse.org ここにも書いてあった。

Arduino Due Native Portからのデータを受信する方法

System.IO.Ports.SerialPort.DtrEnable = true; // ほんとはインスタンスプロパティ

C#Arduino Due Native Portと通信するプログラムを組んでいて、
ホストPCからの送信データをArduino側で受信するのはすんなりできたが、
Arduinoからの送信データをホストPCで受信するのに難儀した。

ちなみにTeratermではなんなく送受信できておりあきらかに自作C#プログラムに問題がある、ってのはわかった。
C#ではSystem.IO.Ports.SerialPortを使ってて、Arduino Due Native PortじゃないSerial間の送受信は難なくできてる。 System.IO.Ports.SerialPortのプロパティを色々見てるとDtrEnableというものがあり試しにこれをtrueにしてみると受信できた。

DTRはData Terminal Readyの意味でWikipediaとDeepLによると

DTR(Data Terminal Ready)は、RS-232シリアル通信の制御信号で、
コンピュータなどのデータ端末機器(DTE)からモデムなどのデータ通信機器(DCE)に送信され、
端末が通信の準備ができていることを示し、モデムが通信チャネルを開始することができます。

とのことらしい。
この場合は端末側がC#ホストプログラムで、モデム側はArduinoということになる。
C#ホストプログラムが受信出来るよ、というのを伝えるまではArduino/SerialUSBはホストに送るデータが発生したとしても送信するのを待ってくれる(多分デバイスドライバ側でまってるわけじゃないよな)。
SerialUSBにwriteしたときの挙動としてはとくにブロッキングしてる風ではないので、バッファリングくれてるんだろう(多分デバイスドライバ側でまってるわけじゃないよな)。

DTR値をSerialUSBでモニタできればホスト側のプログラムが活性状態かどうか確認できるので便利になるが、
SerialUSBではその情報を取得するすべがある。(ありがてぇ)
SerialUSBの型であるclass Serial_の定義を見るとそのまんまだけど、bool Serial_::dtr()というインスタンスメソッドがありそれでホストプログラムの活性状態を見ることが出来る。
C#ホストプログラムとしては、
System.IO.Ports.SerialPort.DtrEnableをtrueにする必要がある。
C#ホストプログラムが何らかの例外が発生して予期せず死んで正常に終了処理がなされなかったとしてもSerialUSB.dtr()は正常にfalseになってくれる。

ちなみにSerialUSBではないSerialや、Serial[123]は
UARTClass型(もしくはその派生型)でありこれらにはdtr()メソッドはない。
そもそもそのための信号が物理的につながってないのでまぁそれはそう。
DTRで接続相手の死活を監視できるのはSerialUSBならではの利点ということになる。

MATLABで日時列があるcsv読み込み

例えば以下のcsvデータがあった場合

timestamp,value
2021/06/22-13:46:13,10.425000
2021/06/22-13:46:13,10.425000
2021/06/22-13:46:14,10.425000
2021/06/22-13:46:14,10.425000

detectImportOptionsを使うことで

opts = detectImportOptions('test.csv')

readtable()実行時にデフォルトでどのように解釈されるのかわかる。

opts = 
  DelimitedTextImportOptions のプロパティ:
   形式 プロパティ:
                    Delimiter: {'/'}
                   Whitespace: '\b\t '

ただしこういうふうにDelimiterを'/'と誤検出することがある、 この場合、引数としてプロパティ値を与えることで部分的に正すことができる。

>> opts = detectImportOptions('test.csv', 'Delimiter', ',')
opts = 
  DelimitedTextImportOptions のプロパティ:
   形式 プロパティ:
                    Delimiter: {','}
~~ 略 ~~
   変数のインポート プロパティ:
                VariableNames: {'timestamp', 'value'}
                VariableTypes: {'char', 'double'}
        SelectedVariableNames: {'timestamp', 'value'}
              VariableOptions: Show all 2 VariableOptions 
    Access VariableOptions sub-properties using setvaropts/getvaropts
           VariableNamingRule: 'modify'

これでもまだ,timestamp列をただの'char'だと認識しているため、日時であることを伝える必要がある。

opts = setvartype(opts, 'timestamp', 'datetime')

その上で読み出す

test = readtable('test.csv', opts);
警告: 1 つ以上の変数を datetime に変換できません。DatetimeVariableImportOptions で正しい InputFormat プロパティと
DatetimeLocale プロパティを指定してください。 

文句を言われ、test変数の中身を見ると意図しないものとなる。

>> test(1:4,:)

ans =

  4×2 table

    timestamp    value 
    _________    ______

       NaT       10.425
       NaT       10.425
       NaT       10.425
       NaT       10.425

このcsvファイルに記述されてる日時書式では正しく'datetime'として解釈してくれないので、書式を伝える必要がある。
現在optsに設定されてる日時書式を確認すると、

>> getvaropts(opts ,'timestamp')
ans =
  DatetimeVariableImportOptions のプロパティ:
   Variable Properties:
              Name: 'timestamp'
              Type: 'datetime'
         FillValue: NaT
    TreatAsMissing: {}
         QuoteRule: 'remove'
          Prefixes: {}
          Suffixes: {}
    EmptyFieldRule: 'missing'
   Datetime Options:
    DatetimeFormat: 'default'
    DatetimeLocale: 'ja_JP'
       InputFormat: ''
          TimeZone: ''

未指定。

>> opts = setvaropts(opts, 'timestamp', 'InputFormat', 'yyyy/MM/dd-HH:mm:ss');

>> getvaropts(opts ,'timestamp')

ans = 

  DatetimeVariableImportOptions のプロパティ:

   Variable Properties:
              Name: 'timestamp'
              Type: 'datetime'
         FillValue: NaT
    TreatAsMissing: {}
         QuoteRule: 'remove'
          Prefixes: {}
          Suffixes: {}
    EmptyFieldRule: 'missing'

   Datetime Options:
    DatetimeFormat: 'default'
    DatetimeLocale: 'ja_JP'
       InputFormat: 'yyyy/MM/dd-HH:mm:ss'
          TimeZone: ''

InputFormatが書き換わってることが確認できたので再び、`readtable'を実行

test = readtable('test.csv', opts);
>> test(1:4,:)

ans =

  4×2 table

         timestamp         value 
    ___________________    ______

    2021/06/22_13:46:13    10.425
    2021/06/22_13:46:13    10.425
    2021/06/22_13:46:14    10.425
    2021/06/22_13:46:14    10.425

意図した通りに読めた

VSCodeでの(主に)clang-format(C/C++フォーマット)に関する設定

%USERPROFILE%\AppData\Roaming\Code\User\
ここにあるsettings.jsonの中身を変更することで各種動作を制御可能。

{
    "files.autoSave": "onFocusChange",
    "editor.mouseWheelZoom": true,
    "editor.formatOnType": true,
    "editor.formatOnSave": true,
    "editor.autoClosingBrackets": "never",
    "C_Cpp.clang_format_style": "{ BasedOnStyle: LLVM, BreakBeforeBraces: Attach, SpaceBeforeParens: Never, IndentWidth: 4, AllowShortBlocksOnASingleLine: false, AllowShortCaseLabelsOnASingleLine: false, AllowShortFunctionsOnASingleLine: false, AllowShortIfStatementsOnASingleLine: false, AllowShortLoopsOnASingleLine: false, ColumnLimit: 0, TabWidth: 4, UseTab: 'Never', SpacesBeforeTrailingComments: 1, AlignConsecutiveMacros: true, AllowShortCaseLabelsOnASingleLine: false, SpaceBeforeParens: true, PointerAlignment: Left }",
}

各オプション(C_Cpp.clang_format_style)の詳細はClang-Format Style Options — Clang 13 documentationに記載されてます。

C_Cpp.clang_format_style 項目ごとの意味[TODO]

{
    BasedOnStyle: LLVM,
    BreakBeforeBraces: Attach,
    SpaceBeforeParens: Never,
    IndentWidth: 4,
    AllowShortBlocksOnASingleLine: false,
    AllowShortCaseLabelsOnASingleLine: false,
    AllowShortFunctionsOnASingleLine: false,
    AllowShortIfStatementsOnASingleLine: false,
    AllowShortLoopsOnASingleLine: false,
    ColumnLimit: 0,
    TabWidth: 4,
    UseTab: 'Never',
    SpacesBeforeTrailingComments: 1,
    AlignConsecutiveMacros: true,
    AllowShortCaseLabelsOnASingleLine: false,
    SpaceBeforeParens: true,
    PointerAlignment: Left 
}

構造体変数配列の連続アラインメント

これは未対応なので

struct T xs[] = {
// clang-format off
  { 123,   1,  3 },
  { 1  ,  12,  3 },
  { 12 , 312,  3 },
// clang-format on
};

等で逃げる。

stackoverflow.com

clang-format.exeと.clang-formatにてフォーマットする(2021-12-23追記)

clang-format.exeをどこからか持ってきてC:/opt/bin/などに置く。

名前: Clang-Format
ID: xaver.clang-format
説明: Use Clang-Format in Visual Studio Code
バージョン: 1.9.0
パブリッシャー: xaver
VS Marketplace リンク: https://marketplace.visualstudio.com/items?itemName=xaver.clang-format

をインストール

C:\Users\%USERNAME%\AppData\Roaming\Code\User\settings.jsonは以下のように記述。

    "clang-format.executable": "C:/opt/bin/clang-format.exe",
    "[c]": {
        "editor.defaultFormatter": "xaver.clang-format"
    },
    "[cpp]": {
        "editor.defaultFormatter": "xaver.clang-format"
    },
    "[ino]": {
        "editor.defaultFormatter": "xaver.clang-format"
    },

これでフォーマッタの挙動をsettings.jsonではなく、ファイルシステム上の.clang-formatファイルで制御可能となる。

---
BasedOnStyle:       LLVM
IndentWidth:        4
TabWidth:           4
UseTab:             Never
ColumnLimit:        0
AllowShortIfStatementsOnASingleLine: true
AlignConsecutiveMacros: true
SpacesBeforeTrailingComments: 1
PointerAlignment: Left
...

Gated Clock/Clock Multiplex

zakii.la.coocan.jp

www.macnica.co.jp

https://www.intel.co.jp/content/dam/altera-www/global/ja_JP/pdfs/literature/ug/ug_altclkctrl.pdf

https://www.macnica.co.jp/business/semiconductor/articles/Timing_Implementation_design_and_debug_guideline_r1_2.pdf

https://www.intel.co.jp/content/dam/altera-www/global/ja_JP/pdfs/literature/hb/max-10/ug_m10_clkpll_j.pdf

EAGLEのPCB設計ファイルをPADS Proに移行した時のメモ

.schファイル、.brdファイルはそれぞれPADS Designer、PADS Layoutで変換してみることはできるが紐づいた状態にならない

紐づいた状態にするために、、 ・PADS Pro Designerで空のプロジェクトを作成(セントラルライブラリも空のものを作成して指定) ・PADS Pro Designerのファイル->インポート->EAGLEから.schファイルをインポート ・シンボルは取り込まれるがCellが表示されず、Component Explorerにも配置可能な部品としては表示されず、部品の配置ができない

・PADS Layout Translatorで、EAGLEのライブラリ.lbrファイルをPADSのライブラリ.pt9等他4種ファイルに変換 ・PADS Library ToolsのTools->import libraryからさっき変換した.pt9ファイルをインポート ・この手順で.schファイルから変換した部品にCellが紐づいて、Component Explorerから部品配置できるようになる

gitで特定の関数(サブルーチン)の履歴を追う

> git log -L :main:main.c

みたいな感じでOK

$ git log -L :main:main.c --pretty=

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -3,4 +5,5 @@
 int main(void) {
-    printf("Hello World\n");
+    sub();
     return 0;
 }
+

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -3,4 +3,4 @@
 int main(void) {
-    printf("hello world\n");
+    printf("Hello World\n");
     return 0;
 }

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -3,4 +3,4 @@
 int main(void) {
-    printf("hello world");
+    printf("hello world\n");
     return 0;
 }

でも以下のような行頭に宣言部を含むstatic関数の場合は。

#include <stdio.h>

static void sub(void);

int main(void) {
    sub();
    return 0;
}

static void sub(void) {
    printf("Hello World\n");
}
$ git log -L :sub:main.c  --pretty=

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -3,0 +3,2 @@
+static void sub(void);
+

行頭の宣言部を追跡してしまう。。
こういう場合は正規表現で追跡部の開始位置と終了位置を指定してあげればうまく追跡してくれる。

$ git log -L '/static void sub(void) {/,/^}/':main.c  --pretty=

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -10,3 +10,3 @@
 static void sub(void) {
-    printf("hello world\n");
+    printf("Hello World\n");
 }

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -10,3 +10,3 @@
 static void sub(void) {
-    printf("hello world");
+    printf("hello world\n");
 }

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -7,0 +10,3 @@
+static void sub(void) {
+    printf("hello world");
+}

けど面倒くさい。。
git-log(1)読むと前の-Lレンジの最後から追跡を開始する、みたいなこと書いてあるので-Lを2つ並べてみると

$ git log -L 1,4:main.c -L :sub:main.c --pretty=

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -10,3 +10,3 @@
 static void sub(void) {
-    printf("hello world\n");
+    printf("Hello World\n");
 }

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -10,3 +10,3 @@
 static void sub(void) {
-    printf("hello world");
+    printf("hello world\n");
 }

diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -1,2 +1,4 @@
 #include <stdio.h>

+static void sub(void);
+
@@ -7,0 +10,3 @@
+static void sub(void) {
+    printf("hello world");
+}

diff --git a/main.c b/main.c
--- /dev/null
+++ b/main.c
@@ -0,0 +1,2 @@
+#include <stdio.h>

イマイチ。。

単純に行末から探してくれるようなオプションはないぽい
git-log(1)には

“^:<funcname>” searches from the start of file.

from the end of fileな検索があればいいですね。

USBシリアルポートのポート番号をリセットする

WinDDKにdevcon.exeなるものが付属するので使えるようにPATHを通します。
例えばこんなかんじ。

> set PATH=C:\WinDDK\7600.16385.1\tools\devcon\amd64;%PATH%
> devcon
devcon Usage: devcon [-r] [-m:\\<machine>] <command> [<arg>...]
For more information, type: devcon help

現状のWindowsがどのデバイスをどのポート番号に割り当てているか確認するには

> devcon findall =ports

で確認できます。
私の環境ではこんな感じです。

devcon findall =ports
USB\VID_067B&PID_2303\6&42CA04E&0&14                        : Prolific USB-to-Serial Comm Port (COM12)
FTDIBUS\VID_0403+PID_6001+A7043PBTA\0000                    : USB Serial Port (COM10)
FTDIBUS\VID_0403+PID_6001+FTDVN77ZA\0000                    : USB Serial Port (COM3)
FTDIBUS\VID_0403+PID_6015+DN03AIAMA\0000                    : USB Serial Port (COM13)
FTDIBUS\VID_0F87+PID_1037+A3KP4JVA\0000                     : USB-401 RS232C[A] (COM1)
FTDIBUS\VID_0403+PID_6015+DN03AA4GA\0000                    : USB Serial Port (COM11)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4A\0000                     : USB-401 RS232C[E] (COM5)
FTDIBUS\VID_0F87+PID_1037+A3KP4JVB\0000                     : USB-401 RS232C[B] (COM2)
FTDIBUS\VID_0403+PID_6015+DN03AF5KA\0000                    : USB Serial Port (COM9)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4B\0000                     : USB-401 RS232C[F] (COM6)
FTDIBUS\VID_0F87+PID_1037+A3KP4JVC\0000                     : USB-401 RS232C[C] (COM3)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4C\0000                     : USB-401 RS232C[G] (COM7)
FTDIBUS\VID_0F87+PID_1037+A3KP4JVD\0000                     : USB-401 RS232C[D] (COM4)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4D\0000                     : USB-401 RS232C[H] (COM8)
USB\VID_067B&PID_2303\6&16164B29&0&3                        : Prolific USB-to-Serial Comm Port (COM15)
15 matching device(s) found.

見やすくすると以下。

バイスPATH 名前 ポート
FTDIBUS\VID_0F87+PID_1037+A3KP4JVA\0000 USB-401 RS232C[A] (COM1)
FTDIBUS\VID_0403+PID_6001+A7043PBTA\0000 USB Serial Port (COM10)
FTDIBUS\VID_0403+PID_6015+DN03AA4GA\0000 USB Serial Port (COM11)
USB\VID_067B&PID_2303\6&42CA04E&0&14 Prolific USB-to-Serial Comm Port (COM12)
FTDIBUS\VID_0403+PID_6015+DN03AIAMA\0000 USB Serial Port (COM13)
USB\VID_067B&PID_2303\6&16164B29&0&3 Prolific USB-to-Serial Comm Port (COM15)
FTDIBUS\VID_0F87+PID_1037+A3KP4JVB\0000 USB-401 RS232C[B] (COM2)
FTDIBUS\VID_0403+PID_6001+FTDVN77ZA\0000 USB Serial Port (COM3)
FTDIBUS\VID_0F87+PID_1037+A3KP4JVC\0000 USB-401 RS232C[C] (COM3)
FTDIBUS\VID_0F87+PID_1037+A3KP4JVD\0000 USB-401 RS232C[D] (COM4)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4A\0000 USB-401 RS232C[E] (COM5)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4B\0000 USB-401 RS232C[F] (COM6)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4C\0000 USB-401 RS232C[G] (COM7)
FTDIBUS\VID_0F87+PID_1038+B3HWFX4D\0000 USB-401 RS232C[H] (COM8)
FTDIBUS\VID_0403+PID_6015+DN03AF5KA\0000 USB Serial Port (COM9)

COM3が2つあり、FTDIBUS\VID_0403+PID_6001+FTDVN77ZA\0000 これは削除したい。
この場合

> devcon remove "@FTDIBUS\VID_0403+PID_6001+FTDVN77ZA\0000"
FTDIBUS\VID_0403+PID_6001+FTDVN77ZA\0000                    : Remove failed
No devices were removed.

削除失敗しました。
コマンドプロンプトを管理者権限で開けば多分OK。

> devcon remove "@FTDIBUS\VID_0403+PID_6001+FTDVN77ZA\0000"
FTDIBUS\VID_0403+PID_6001+FTDVN77ZA\0000                    : Removed
1 device(s) were removed.

できた。

サーバー側でメール振り分け、sieveで振り分け処理記述してdovecotでLDA

すでにPostfixdovecotでメール送受信できてる状態から、サーバー側でメールのFromなどを参照してフォルダに振り分ける措置を実施したメモ

Postfix関連でやったこと

/etc/postfix/main.cf

mailbox_command = /usr/libexec/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"

Devocot関連でやったこと

# yum install dovecot-pigeonhole

/etc/dovecot/conf.d/

protocol lda {
    mail_plugins = $mail_plugins sieve
}
> mkdir ~/sieve/
> touch ~/sieve/master.sieve
> ln -s ~/sieve/master.sieve ~/.dovecot.sieve

問題

最初全く動作しなかった、試しにメール送ってみても届かなかった。
ログを見ると/var/log/dovecot/dovecot.logにアクセス権限が無い、というエラーがあった。
postfix/usr/libexec/dovecot/dovecot-ldaを起動してその際にログを残そうとこのファイルに書き込みに行くが権限がなくて失敗してるということだろう。
ということでこのファイルの権限を0777に変更したら動いてくれた。(よろしくなさげ)

すでに受信済のメールを振り分ける方法

~/.dovecot.sieveを書き換えれば今後受信するメールは振り分けられるけどすでに受信済のメールの扱いを振り分けたいと思い以下の手順で実施したらうまくいった。

> mkdir ~/tmp
> mv ~/Maildir/cur/* ~/tmp
> for x in ~/tmp/*
do
  /usr/libexec/dovecot/dovecot-lda < $x; echo -n .
done

これで一旦受信済フォルダ(~/Maildir/cur)から~/tmpに移動させた後にローカル配送させることで 新しいメールとして~/Maildir/curの中に配送される。 (echo -n .はただの経過表示)
もっと簡単でいいやり方がありそうな気がする。

Unityライクなマウス左右にスライドさせて数値いじれるSpinBox

public partial class SlidableSpinBox : NumericUpDown {

    bool press = false;
    int mouseX = 0;

    public SlidableSpinBox() {
        InitializeComponent();
        ContextMenu = new ContextMenu();
        mouseX = System.Windows.Forms.Cursor.Position.X;
        Timer t = new Timer();
        t.Tick += (object sender, EventArgs e) => {
            if (0 == (Control.MouseButtons & MouseButtons.Right))
                press = false;
            if (press) {
                var tmp = Value + (System.Windows.Forms.Cursor.Position.X - mouseX) * Increment;
                Value = (tmp > Maximum) ? Maximum : (tmp < Minimum) ? Minimum : tmp;
            }
            mouseX = System.Windows.Forms.Cursor.Position.X;
        };
        t.Interval = 10;
        t.Start();
    }
    protected override void OnMouseDown(MouseEventArgs e) {            
        base.OnMouseDown(e);
        if (e.Button == MouseButtons.Right) {
            ReleaseCapture();
            press = true;
            System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.SizeWE;
        }
    }
    protected override void OnMouseUp(MouseEventArgs e) {
        base.OnMouseUp(e);
        if (e.Button == MouseButtons.Right) {
            press = false;
            System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Arrow;
        }
    }
    [DllImport("user32.dll")]
    public static extern bool ReleaseCapture();
}
  • 自分矩形領域で右クリックを押してそのまま左右にマウスをスライドさせたら数値が上下に振れる
  • NumericUpDownを継承してるので分解能(Increment)や上限(Maximum)下限(Minimum)はNumericUpDownのプロパティが使える
  • 1点てこずったのが自分矩形領域で右クリック後、自分矩形領域外で右ボタンを離したときに謎のコンテキストメニューが表示されてしまった
  • 出来ればTimerで常時監視せず自分矩形領域外でのマウスの動きを必要な時にだけ(press状態時のみ)取得したいが、どうやればいいのやら。

logiCORE PCI

Initiator Data Phase Control

この章では、ユーザーアプリケーションがデータのソースまたはシンクの能力に合わせてイニシエータートランザクションの側面を制御する方法について説明します。
ユーザーアプリケーションは、最初のデータ転送の前に待機状態を挿入して、準備ができていない場合には追加の時間を可能にします
さらに、ユーザーアプリケーションは、トランザクションを完了する時期を示すことによってデータフェーズの数を制御できます。

可能な限り、待機状態での初期レイテンシの生成はお勧めできません。
この手法は、貴重なバス帯域幅を浪費します。
帯域幅の観点からは、トランザクションを実行する準備が整うまで、ユーザーアプリケーションがバス要求の作成を遅らせる方がよいでしょう。

Control Modes

データ位相制御は、M_READYおよびCOMPLETE信号を使用して実現されます。
2つの制御信号の組み合わせは、以下のモードを含む。

  • Wait BurstPCIインターフェイスによるIRDY_IOのアサートを遅延させることによって、 PCIバストランザクションの開始時にウェイトステートを挿入します(最初のデータフェーズを保持します)。
    この特定の待機モードは、イニシエータバーストトランザクションで使用するためのものです。
    このモードを使用すると、PCIインターフェイスに、ユーザーアプリケーションが準備ができていないことが示され、複数のデータフェーズが試行されます。

  • Wait Singleはウェイトバーストモードと同じ方法で、PCIバストランザクションの開始時にウェイトを挿入します。
    ただし、このモードは単一のイニシエータトランザクションで使用するためのモードです。
    このモードの使用は、PCIインターフェイスに対して、ユーザアプリケーションが準備ができておらず、複数のデータフェーズを試みないことを示します。

  • ProceedPCIバスのデータフェーズを中断することなく進めることを可能にします。
    選択したターゲットが待機状態を挿入したり、トランザクションを途中で終了したりすることがありますが、ユーザーアプリケーションはデータをフルスピードで転送する準備が必要です。
    これは、複数のデータフェーズ転送でのみ使用できます。

  • Finishを使用すると、PCIインターフェイスはできるだけ早くトランザクションを完了します。
    これは、単一および複数のデータフェーズ転送の両方で使用するためのものです。

ここでも、正確な切断シーケンスは、選択されたターゲットがトランザクションを終了するかどうかによって影響されます。
PCIインターフェイスは自動的に正しい動作を生成します。

f:id:fullphong:20180614014152p:plain

あるモードから別のモードへの変更は、任意の順序で行うべきではありません
さらに、トランザクションで発生するデータフェーズの数を正確に制御するためには、モード遷移のタイミングが重要です。
これは、フィニッシュモードに切り替えるときに特に重要です。

図11-1に、PCIインタフェースを使用したイニシエータデザインの許可されたデータ位相制御シーケンスを示します。
正確なタイミングの詳細は、この章の次のセクションで定義されています。

f:id:fullphong:20180614014147p:plain

図11-1に示す制御シーケンスは、ユーザーアプリケーションがトランザクションを終了していることを前提としています。
実際には、トランザクションは、ターゲットアプリケーションの終了やタイムアウトなど、ユーザーアプリケーションが制御できない理由で終了することがあります
そのような状態の後にイニシエータ状態マシンが非アクティブになると、シーケンシングルールはもはや適用されない。

厳しいPCIバスのパフォーマンス要件を満たすために、PCIインターフェイスはすべてのバス制御信号とデータパスをパイプラインします。
したがって、M_READY信号およびCOMPLETE信号は、所望の効果の前に提示されなければならない。

ウェイトモードは、トランザクション内の任意のデータフェーズでウェイトステートを挿入するために使用できないことに注意してください。
これらは、イニシエータトランザクション最初のデータフェーズの完了を遅延させるためにのみ使用できます。
これは、PCIローカルバス仕様ではマスタデータレイテンシと呼ばれます。

すべてのイニシエータは、FRAME_IOのアサートから8クロック以内にトランザクションの最初のデータフェーズを完了する必要があります
PCIローカルバス仕様は、マスタデータレイテンシの使用を強く推奨しておらず、一般的にそれを使用する理由はないと述べています。
ユーザアプリケーションは、この要件を遵守する責任があります。

信号M_READYおよびCOMPLETEは、複数の論理レベルを介してイニシエータ状態マシンに接続する。
このため、これらの信号を駆動するロジックをできるだけシンプルに保つことを強く推奨します。
これらの信号をユーザアプリケーションのフリップフロップからドライブすることは有益ですが、これは典型的には最も単純な(バーストではない)デザイン以外では不可能です。

Control Pipeline

ユーザアプリケーションは、REQUESTをアサートしてから1サイクル以内に、正しい初期データ位相制御モードを提示しなければなりません。
この後、図11-1に示すシーケンシングに違反しない限り、ユーザーアプリケーションはモードを変更できます。

いずれの場合も、ユーザアプリケーションがイニシエータトランザクションの終了を決定すると、M_READYとCOMPLETEを適切に設定して終了モードを選択する必要があります。
ユーザアプリケーションがトランザクションを終了することを通知すると、トランザクションの終了時までM_READYおよびCOMPLETEを保持する必要があります。

PCIインタフェースによるM_DATAのアサーション解除は、転送が終了したことを示します

Transaction Termination Rules

ユーザアプリケーションが単一のデータワードを送信または受信している場合、
ユーザアプリケーションは、REQUESTをアサートしてから1サイクル以内に待機シングルモードまたは終了モードを通知する必要があります

ユーザアプリケーションがウェイトシングルモードを使用してウェイトステートを挿入する場合は、
PCIインタフェースがマスタデータレイテンシ仕様に違反する前に終了モードに切り替える必要があります。
再び、ユーザーアプリケーションがトランザクションを終了するように信号を送ると、
M_DATA状態の終わりまでM_READYとCOMPLETEを保持する必要があります。

ユーザアプリケーションが2つのデータワードを送信または受信している場合、ユーザアプリケーションは、ウェイトバーストまたは進行モードのいずれかで開始することができる
ウェイトバーストモードで開始する場合、ユーザインターフェイスは、PCIインターフェイスがマスタデータレイテンシ仕様に違反する前に、進行モードに切り替える必要があります。
進行モードに入ると、次の両方の条件が満たされると、ユーザーアプリケーションは終了モードに切り替える必要があります。

  • 進行モードは、少なくとも1サイクル
  • 信号M_DATAが少なくとも1サイクルアサートされている

3つ以上のデータワードのバースト転送の場合、初期モード選択は2転送の場合と同じである。
3つの転送が残り、M_DATA_VLDがアサートされると、ユーザアプリケーションは終了モードに切り替える必要があります。

Implementation

上に示した規則はテキストで表示すると複雑に見えますが、次の例では一般的なケースでM_READYとCOMPLETEを駆動するために必要なロジックを示します。
この例は、前の章で示した例を基にしており、簡単なバースト転送を実行できます。
このコードは、M_READYとCOMPLETEを生成した以前のロジックを置き換えます。

ほとんどのイニシエータ設計では、転送カウンタを使用して希望のバースト長を追跡します。
次のロジックは転送カウンタを実装し、残りの転送数を示す3つの出力を生成します。
BURST_LENGTHおよびSTART信号は、ユーザアプリケーション内の他の場所で生成されます。
読み書きの場合、M_DATA_VLDは、PCIバス上のデータ転送が成功したことを示すために使用されます。

次のロジックは、後でM_READYおよびCOMPLETEロジックで使用されるイニシエータレディ信号を生成します。
イニシエータとしてウェイトステートを挿入しないユーザアプリケーション設計では、このロジックを最適化することができます。
ロジックは、READY_FLAGという信号をサンプリングします。この信号は、ユーザーアプリケーションの別の場所で生成されます。
この信号は、ユーザーアプリケーションがデータを転送する準備ができていることを示します。

最後のステップは、M_READYとCOMPLETEを生成することです。
典型的には、イニシエータ待ち状態は使用されず、INIT_WAITED信号は方程式から最適化されるべきである。
タイミングの理由から可能な限りロジックを減らすことが重要です。