2018年04月28日

tcc-win32

少しコードを書いてきたが、どうやってテストしよう?

AVR の USBasp かその手のライタに、I2C ブリッジ機能を持たせるという方向で検討しているのだが、今回は Windows 側 の アプリの話。

実をいうと Windows 10 になってから、開発環境を インストールしていない。一から構築である。普段使いのノーパソの Disk 容量が小さいので、入れるにしても容量が気になる。また、WindowsUpdate のために クリーンインストールを何度かしている。

今回 Windows でもちょっとしたものは、作りたいのだが、最小の環境でというのを考えている。

最小のコンパイル環境 tcc-win32

    最小と言えば、これはもう TinyCC - tcc である。
    ダウンロードのページを見ると、まだ更新がある。そして tcc-win32 なんてものが ... バイナリまで置いてある。このバイナリの zip は、全部で 386K 。これで、ヘッダファイル、ライブラリが含まれているのである。

    この tcc は、フルセットの C 言語 である。__asm__ とかも使え、gcc の拡張も一部入っている。
    (今は 分からないが)かつては、Linux を高速にビルドできることを 宣伝していたのだ。

    ひょっとして、libusb とか使うアプリも これで作れるのだろうか?

tcc の dll 関係の機能

    tcc-win32 をインストールすると、

    tcc/lib に
     gdi32.def user32.def kernel32.def msvcrt.def

    という ファイルがある。これは、 windows の dll の関数一覧で、テキストファイル。
    これらは標準で使える API だが、def ファイルを 作成し コンパイルで指定すると dll が使える。(def ファイルではなく、dll を指定しても良い)

      -lwinusb
      でいける。/tcc/lib に def ファイルを置けば、ライブラリパスを指定しなくて良い。

      なお、
      tcc -impdef dllファイル

      とすることで、 この def ファイルを作ることが出来る。

libusb は使えるのか?

    libusb (相当機能)が使えないと 意味がない。これが出来ないのであれば、windows でちょっとテストすることが厳しくなってしまう。

    で、作れるのか? libusb-win32 の libusb0-x86.dll を試してみた。

    ... 結果はリンクして exe は出来る。しかし、正しくリンクできていないらしく、起動でエラー。

    制限事項があり、関数のみの dll しか使えないということであった。

他の dll は?

    そんなことでは諦めないのである。そう言えば winusb はどうだろう?

    というわけで \Windows\system32 にあった winusb.dll をコピーして来て def ファイルを作ってみた。

    exe が出来て、起動でエラーが起きない!

    ヘッダファイルをなんとかすれば、使えるようになりそうである。user32, kernel32 なんてものが使えているのであるから、多分大丈夫だろう。

    そういえば、ws2_32.dll なんてものも system32 にある -- WinSock2 である。

    これもいけた。USB とネットワークが使える! (かも)

    現時点では、可能性があるというだけだが、期待できそうである。

    忘れていた。FTDI は、どうだろう? ftd2xx.dll を試してみた。... ダメであった。

tcc で perl4 のビルド (の調査)

    perl4 というのは、今の perl5 の前のバージョンである。かつては、perl3 なども当然あったわけだが、今ダウンロードできるのは、perl4 の最終版のみである。

    perl4 は、perl5 のように膨大なライブラリ環境がない。機能も少ないから コンパクトなのである。テスト用のスクリプトなどこの程度で十分である。過去に作った ガーバーファイルのツールも 多分動く。

    というわけで perl4 を Windows に移植したいと思っている。

    サポートしたい DLL は、windows 10 標準の ws2_32 + winusb 。あと 非標準のいくつか。

    GDBM
    SQLITE3

    ダメだった。思ったより制限がきついようだ。

      追記:後で気が付いたのだが、LoadLibrary() は、使えるはずである。直接 リンクできないものは、そうすれば良い。非標準だし、必ずあるという保証もないわけで、むしろ LoadLibrary() を使うべしということにしよう。

winusb

    perl は、長期間で考えているので、早急に結論をださなくて良い。気を取り直して winusb を使うことだけ考えよう。

    winusb.dll はあった。ドライバ自体をインストールするには、Zadig を使えば良い。足りないのは ... ヘッダファイルである。

    tcc の ダウンロードに winapi-full-for-0.9.27.zip がある。

    期待したのだが、DDK はあるが、winusb.h はなかった。一応 usb100.h などはある。他に winsock2.h などはあった。

    Microsoft の API リファレンス を見れば、作れそうなのではあるが、決定的に足りない定義があるかも知れない。まずは ... Github になにかないか探してみる。

    探したら winusb.h があった! psplinkusb というもの、psplinkusb がなにか興味はないのだが、libusb , winusb 両対応で、使い方を対比するのに助かりそうな、コードまである。
     ・ https://github.com/tyranid/psplinkusb/tree/master/usbhostfs_pc

    これで必要なものは揃いそうだ。

tcc ディレクトリへのファイルのコピー

    psplinkusb から

      winusb.h
      winusbio.h

    winapi-full-for-0.9.27/ddk から

      usb.h
      usb100.h
      usb200.h

    winapi-full-for-0.9.27/winapi から

      initguid.h
      qos.h
      winsock2.h

      setupapi.h
      commctrl.h
      prsht.h

    を tcc/include/winapi にコピー
    作った

      ws2_32.def
      winusb.def

    に加えて setupapi.def も作り tcc/lib にコピー

    WINUSB をリンクするときは、

      -lwinusb -lsetupapi

    とする。
    これで(試す)準備は出来た。

API の調査

    WINUSB の API は、全然知らない。libusb は以前は弄ったことがあったが、ほぼ忘れてしまった。一からである。

    インクルード

      #include<windows.h>
      #include<winusb.h>
      #include<setupapi.h>

      インクルードは、最低これだけ必要。

    初期化

      dev = OpenDevice(TRUE);
      r = WinUsb_Initialize(dev, &winusb);

      OpenDevice() でハンドルを得る。それに対して、WinUsb_Initialize() で 初期化をして 新たに ハンドルを得る。オーバライド可の指定をすると、同じハンドルが返ってくる(らしい)

      と書いたが、間違いである。setupapi を使って デバイスを特定・オープンし、それに対して WinUsb_Initialize() を行う。これについて、後で詳しく。

    終了処理

      WinUsb_Free(winusb);

    Setupパケットの送信とリプライの受信

      r = WinUsb_ControlTransfer(winusb,
      setupPacket,
      buf,
      buf_max,
      &buf_len,
      NULL);

      USBasp などは、だいたいは、これを使って通信するが、他に、Flash の Read/Write では、エンドポイントを使う。

    エンドポイントの通信

      WinUsb_ReadPipe()
      WinUsb_WritePipe()

      を使う。
      面倒になったが、基本はこれだけみたいなのである。そんなことより、どうやって USB装置を特定するか? libusb でもめんどくさいことをやっていたが WINUSB でも同様らしい。
      そこさえクリアできれば、使うのは簡単という気になってきた。

      ただ、libusb と共通化できるようにして、しっかりここを作ると、libusb へのラッパーライブラリを作っている気分になる。それはたぶん既にあるだろうから無駄である。もともと、V-USB で作る典型的な装置にしか対応する気がないのである。できるだけ簡略化の方向で。

デバイスのスキャン

     ・https://ameblo.jp/new3bon/entry-10461467643.html
    たぶんここに書いてあることをする。

      (要約)
      SetupDiEnumDeviceInterfaces() のMemberIndex引数で何番目を指定できる。これをループすれば良い。

      やってみた結果、SetupDiEnumDeviceInterfaces() は、すでに使われていて使えないデバイスも含まれているようだ。CreateFileでファイルをオープンしてみて開けたら使えるということで認識することにした。
      あとはこのハンドルをWinUsb_Initializeかければいい。

    SetupDiEnumDeviceInterfaces() を理解すればよいようだ。

    すべての存在するデバイスを指定して、SetupDiEnumDeviceInterfaces()をループで回して、VID/PID や クラス、デバイス名 が一致するものを選ぶ。2個刺している場合もあるわけで、n 番目に見つかったものという指定も必要だ。

    Handle = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);

    すべての存在するデバイスの指定は、これで良いらしい。

    SetupDiEnumDeviceInterfaces()のループでは、
      ・SetupDiGetDeviceInterfaceDetail()でデバイスパスを取得する
      ・CreateFile() にデバイスパスを指定してハンドルを開く
      ・WinUsb_Initialize()
    そこまで来るとようやく
      WinUsb_GetDescriptor(handle, USB_DEVICE_DESCRIPTOR_TYPE,....)
    が call できる。お目当てのものでなければ、ループ再開。

    戻りは、USB_DEVICE_DESCRIPTOR構造体。この中は、Descriptor の情報そのものっぽい。

    CreateFile()は、

    handle = CreateFile((LPTSTR)device_path,
    GENERIC_WRITE | GENERIC_READ,
    FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
    NULL);

    で、もう分からないのでおまじないとして捉える。

    ここから先は、コードを書いてみて確認しないとダメそうだ。

だいぶ遠回りしてしまったような気がする。LoadLibrary() を使ってすなおに、libusb を使えば良かったとも思うのだが、WINUSB をどう使うか気になっていたので、それはそれで。open のところまで行くのが、すごくめんどくさいが、libusb でも同じことなのである。ここまで来たからには、WINUSB でと考えている。

とにかく、テストツールを作れる目途が立ったが、結局は libusb を使った Linux 版も作ることになるだろう。それだけではなく、SBC 用ならば、USB を通さず 直接 GPIO でということに。USB-I2C ブリッジを検討していると書いたが、そのコードを Linux に持ってきて、テストツールに加えることになるだろう。

それも考えて、テストツールを作ることになる。実際に作り出すのは、USB-I2C ブリッジの後ということになりそうだ。


Rasberry Pi での I2C 制御 (例) の調査

    カーネルで i2c ドライバが 構成されると、/dev/i2cdev-1 といった デバイスファイルが出来る。

    これを Open して使うというのが、最も ベーシックな使い方で、

     ・ioctl(fd, I2C_SLAVE,i2cAddress)
    で、装置アドレスを指定

    fd に対する read/write で 送受信 (たぶん)。

    どうもこれだけのようである。

    これにマッピングできる レイヤを作る。--- これで良いようだ。
posted by すz at 21:35| Comment(0) | TrackBack(0) | I2CKEYBOARD
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/183101155
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック