標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第493回]

●HID送信プログラムを変更いたしました

前回([第492回])お見せしましたHID送信プログラムは、ASCIIコードで書かれた16進数データファイル(HTX)を読み込んで、それをバイナリデータに変換してから、PIC18F2550に送信するものでした。
MYCPU80がUSB・RS232C変換IC(FTDI社FT232RL)を使って、Windowsパソコン側もMYCPU80側もRS232Cとして通信を行っていることをそのまま踏襲しているためです。
RS232C通信は、通常は生のバイナリデータを送受信するのではなくて、ASCIIコード文字列として送受信を行います。

もちろんRS232C通信でもバイナリデータをそのまま送受信することができないわけではありません。
ですが、一般的には、ASCII文字列で送受信することが多い、ということを踏まえて、そのようにしました。
MYCPU80のために作った8080アセンブラも、ASCIIコードで記述した16進数ファイル(HTX)を出力するようにしました([第182回])。

んでも、ちょっと、むむ、この記述は?と思いまして、そのふたつ前の[第180回]を見てみましたら、
おや、バイナリファイルも出力してるじゃないの。
というより、もとはバイナリファイルのみ出力していたところを、HTXファイルも出力するように直した、と書いておりますですねえ。

それなら、なにもわざわざHTXファイルを読み込んで、それをまたバイナリファイルに変換してからHIDで送信しなくても、はじめからバイナリファイルを読み込んで、それをそのまま送信すればいいじゃないの。
むむむ。
自分で作った8080アセンブラなのに、そこのところを完全に忘れてしまっておりまする。
こいつぁいよいよ年貢の納めどきか…とほ。

しかし、しかし、さらにここしばらくの思考の過程をさかのぼってみましたら、むむ、やっぱりHTXファイルでないとだめではないか、というところに行きつきました。
そういうことも、すぐ忘れてしまって、同じところを行きつ戻りつしてしまいます。
こりゃあ、やっぱり、いよいよ…。

そうなのでした。
8080アセンブラで出力されるバイナリファイル(拡張子bin)は、そのままROM焼きできるROMイメージファイルだったのでした。
そのままROMに焼くことができますから、オリジナルのZ80アセンブラでも、ずっとそのようにしてきました。
8080アセンブラで出力されるバイナリファイルには、そういうちゃんとした目的がありました。

ところで。
TK80のSTORE、LOADで送受信するデータは、先頭に開始アドレスと終了アドレス4バイトが付加されています。
オリジナルのモニタプログラムの機能をできるだけ尊重する、という考えからすると、ここはそのままにしておきたいところです。
実際に送受信するところは、バイナリでもヘキサ(ASCIIコード)でもいいのですけれど。

そうすると、8080アセンブラで出力されるバイナリファイルには、その先頭のアドレス部分がありませんから、それをそのままHIDプログラムで送信するわけにはいかなかったのです。
一方、8080アセンブラでバイナリファイルと同時に出力されるHTXファイルは、MYCPU80のUSB送信で利用することを目的にしたものですから、先頭にアドレスがついています。
今回のHID送信プログラムで、入力するファイルをHTXファイルとしたことには、そういう理由があったのでした。
その思考の過程をすっかり忘れておりました。

むむむ。
これは悩ましい問題です。
実は、HID送信プログラムだけではなくて、HID受信プログラムも出来あがっているのです。
ところが、受信プログラムの方は、その思考の過程をすっかり忘れてしまっていたものですから、先頭のアドレス付きで、バイナリで受信したものを、そのまま先頭にアドレスをつけたバイナリファイルの形で保存するようにしてしまいました。
ええ。
それも拡張子をbinにして。

これはまずい、です。
同じbinファイルなのに先頭にアドレスが入っているものと、入っていないものの2種類が存在する、というのは先々混乱のもとになります。
かといって、それならHID受信でも、バイナリから16進数(ASCIIコード)に変換して、HTXファイルとして保存するか、ということなのですけれど…。
確かに、MYCPU80でのUSB受信では、もともとASCIIコードで受信していることですから、当然そのままHTXファイルとして出力しておりました。が…。

ASCIIコードで送受信するのではなくて、バイナリのまま送受信しているのに、Windows側のファイルの読み込みと、書き出しのところだけ、ASCIIに変換する、というのもなんだかなあ、という感じなのですよねえ。
そうなってくるとASCIIに変換する意味はほとんど無い、のですから。
先頭にアドレス情報があるか、無いか、つうだけのために、ASCIIコードファイルを作成するというのもねえ。

むむ。
少し見えてきましたよ。
ちょいと整理してみます。

1)8080アセンブラでは、先頭にアドレス情報をつけて、16進数表記をASCIIコードにしたHTXファイルとバイナリデータのみのBINファイルが作成されます。
2)TK80モニタプログラムのSTORE(SAVE)、LOADでは先頭にアドレス情報が付加されたデータを送受信します。
3)今回のHID送信、HID受信では、データはASCIIコードではなくて、バイナリデータのまま送受信します。
このいずれも、変更はしたくありません。

すると、2)と3)から、先頭にアドレス情報を付加したバイナリファイルが一番フィットすることになります。
しかし、すでに私はもうずっと昔から先頭にアドレス情報を付加しない、生のバイナリファイルをbinという拡張子で使っています。
それを変更したくはありません。

おお、すると、結局これは拡張子の問題、ということになりそうです。
それなら、HID送信、HID受信プログラムでは、先頭にアドレス情報をつけたバイナリデータファイルを扱うこともできるようにして、その拡張子はbin以外の名前にする、ということにすればよいのではありませんでしょうか。

ま、しかしそのあたりにつきましては、それぞれ好みとか、考え方の相違もいろいろあるか、と思います。
応用が利く形としまして、とりあえずはHTXファイルを扱うプログラムと先頭にアドレス情報のついたバイナリファイルを扱うプログラムの2本を作ってしまうのが、手っ取り早いと思います。

むむ。
1)の8080アセンブラも、先頭にアドレス情報を付加した、バイナリファイルを出力できるようにするとよいかもしれません。
これも、現行の8080アセンブラと、アドレス情報を付加したバイナリファイルを出力するアセンブラの2本立てにするか、いっそのことその両方を出力できるように変更してしまうとよいかもしれません。

すでにある、HTXファイルとアドレス情報付きのバイナリファイルとを相互に変換するプログラムも作ってしまうとよいかもしれませんね。

ということで、HTXファイルを読み込んで、それをバイナリに直してHIDで送信するHID送信プログラムのファイル読み込み部分を直して、バイナリファイルを読み込んで、それをそのままHIDで送信するようにしたプログラムを作る作業にかかったのですが…。

ASCIIからバイナリに変換するところが無くなってしまうだけ、より簡単なプログラムにできるはずなのですが、そのように直して新たに作ったプログラムでテストしてみますと、なんだか様子がおかしいのですよね。

ASCIIデータファイルを読み込んでいるところを、バイナリファイルを読み込むようにしただけなのに、まともにファイルを読んでくれません。
むむ。おかしい…。

しばらくして、気が付きました。
うっかりしていました。
fgets()関数はバイナリファイルを読み込む関数ではなくて、TXTファイルなどから文字ストリームを読み込む関数でした。
このプログラムのもとになったのが、RS232C送信プログラムだったものですから、つい文字列を扱うものと思い込んでしまいました。

そのことに気が付いて、あらためて前回のHID送信プログラムをよくよく見てみましたら。
むむむ。
なんだかおかしなことをやっておりますよ。
HTXファイルはASCII文字コードのファイルですから、fgets()関数で読むことはできますけれど、実質的には文字ストリームというよりも、ASCIIコードではあるけれど、バイナリファイルと同じじゃないの、ということに気が付きました(うう。言っていることがおわかりいただけますでしょうか?)。
つまり、文字列データというよりも、1バイトのバイナリデータをASCIIコード2バイトで表現した、そういうバイナリデータだと考えたほうがわかりやすい、ということです(え?ちっともわかりやすくありません?)。

え、と…。
つまり。文字列として読み込んで、それをバイナリに変換する、という考えにムリがあったのです。
ASCIIコードというバイナリデータを読み込んで、その2バイトを変換して、バイナリデータ1バイトを作り出す、という考え方のほうがすっきりしている、ということなのです。

●変更したHID送信プログラムリストです

実際のプログラムリストを見ていただいたほうが話が早い、と思います。

//hidwr2
//for ND80Z write
//
//10/4/29 4/30 5/4
//
#include <windows.h>
#include <setupapi.h>
extern "C" {
#include "hidsdi.h"
}
#include <iostream.h>
#pragma comment(lib, "hid.lib")
//
        HANDLE handle;
        int hidget();
        FILE *rfp;
        char *fname;
//
void main(int argn,char *args[])
{
        cout << hex;
        fname=args[1];
//file open
        if(!(rfp=fopen(fname,"rb")))
        {
                printf("ファイル名が指定されていないかまたはファイルがみつかりません %s\n",fname);
                return;
        }
// get hid handle       
        if (!hidget()){cout <<"hid device is not found" <<endl;return;}
//
        DWORD nwrite=65;//not 64!
        DWORD nwritn=0;
        unsigned char wbf[65]="\0";
//read file
        int n;
        int d;
        int dx;
        int inbfn;
        int dtbyte=0;
        fseek(rfp,0,SEEK_END);
        inbfn=ftell(rfp);
        fseek(rfp,0,SEEK_SET);
        while(inbfn!=0)
        {
// data set to wbf,max 63 bytes
                for (n=0;n<63;inbfn--)
                {
                if (inbfn==0)break;
// ascii(hex) to bynary
// high 4bits
                d=fgetc(rfp);
                if (d<30)continue;//pass 0d0a
                if (d<=0x39)dx=(d-0x30)*16;
                else dx=(d-0x37)*16;
//low 4bits
                d=fgetc(rfp);
                inbfn--;
                if (d<30)continue;
                if (d<=0x39)dx=dx+(d-0x30);
                else dx=dx+(d-0x37);
//set binary data to wbf[]
                wbf[n+2]=dx;
                n++;
                }
//set number of send data to wbf[1]
                printf("n=%d\n",n);
                if (n==0)break;
                wbf[1]=n;
                if (dtbyte==0)printf("s=%x,e=%x\n",wbf[2]*256+wbf[3],wbf[4]*256+wbf[5]);
                dtbyte=dtbyte+n;
// send data (64bytes)
                if(!WriteFile(handle,&wbf,nwrite,&nwritn,NULL))cout<<"write error"<<endl;
        }
        printf("send data %d(=%x) bytes\n",dtbyte,dtbyte);
	fclose(rfp);
        CloseHandle(handle);
}
//
// get hid handle
int hidget()
   {
        int getmk=0;
        GUID hidGuid;
        HidD_GetHidGuid(&hidGuid);
        HDEVINFO devinf;             
        devinf = SetupDiGetClassDevs(&hidGuid, NULL, 0, DIGCF_PRESENT |
 DIGCF_DEVICEINTERFACE);
        SP_DEVICE_INTERFACE_DATA spid;
        spid.cbSize = sizeof(spid);
//      
        for( int index = 0; ; index++ )
     {
        if(!SetupDiEnumDeviceInterfaces(devinf, NULL, &hidGuid, index, &spid))break;
        unsigned long size;
        SetupDiGetDeviceInterfaceDetail( devinf, &spid, NULL, 0, &size, 0 );
        PSP_INTERFACE_DEVICE_DETAIL_DATA dev_det =new SP_INTERFACE_DEVICE_DETAIL_DATA[size];
        dev_det->cbSize=sizeof(*dev_det);
        SetupDiGetDeviceInterfaceDetail( devinf, &spid, dev_det, size, &size, 0 );
//
        handle = CreateFile( dev_det->DevicePath, GENERIC_READ|GENERIC_WRITE,
 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
        if(handle==INVALID_HANDLE_VALUE){cout<<"INVALID_HANDLE"<<endl;continue;}
        HIDD_ATTRIBUTES attr;
        HidD_GetAttributes( handle, &attr ) ;
        if (attr.VendorID==0x4d8 && attr.ProductID==0xa){getmk=1;break;}
     } 
        return getmk;
   }
//end

main()の前で宣言していた
char inbf[4096]="\0";
を削除しました。
今回はfgets()ではなくてfgetc()を使いますから、入力バッファは不要です。
main()の中で変更しているのは、
//read file
から
// send data (64bytes)
までのところです。
最初にfseek()関数とftell()関数を使って、入力ファイルの総バイト数inbfnを得ます。
あとはfgetc()関数で入力ファイルから1バイトずつデータを読み込んで処理するごとにinbfnを−1していきます。
for文でHID出力バッファに63バイト書き込むまで繰り返してから、WriteFile()で送信します。
inbfn=0になったら処理終了です。

今回変更したHIDプログラムを実行した画面です。



2010.5.4upload

前へ
次へ
ホームページトップへ戻る