[リストへもどる]   [VBレスキュー(花ちゃん)]
一括表示

投稿時間:2005/07/25(Mon) 12:31
投稿者名:チロル
Eメール:
URL :
タイトル:
MSCommのOn_Comm受信
こんにちは。
二度ほど質問させて頂いた続きなのですが,よろしくお願い致します。
NAK:6バイト固定で送信されるコマンド
セレクティング:TEXTへ入力されたバイナリー形式の文字列を送信する可変バイトのコマンド
の二つがあります。
コマンドはボタンを押し手動で送信をかける作りになっています。
環境的にはRS232Cには検査器が接続されており、送信されたバイナリーデータを目で確認することが
できます。

NAKに関して
コマンドは問題なく送信され、受信も問題ありません。
*ctlComm. はMSComm1.の事です。

以下送信プログラム
Private Sub cmdOutPutNak_Click()
    ' Nak送信
    Dim Buffer(5) As Byte

    Buffer(0) = COMM_CODE.DLE
    Buffer(1) = COMM_CODE.NAK
    Buffer(2) = COMM_CODE.DLE
    Buffer(3) = COMM_CODE.UA
    Buffer(4) = COMM_CODE.DLE
    Buffer(5) = COMM_CODE.HA
    
    ctlComm.Output = Buffer 
End Sub

セレクティングに関して
コマンドは問題なく送信されています。

以下送信プログラム
Private Sub cmdOutPutSel_Click()
    'セレクティング送信
    Dim Buffer(0 To 2100) As Byte    
    Dim strData As String
    Dim txtLen As Integer
    Dim i As Integer
    Dim j As Integer
    Dim strTxtData As String
    Dim bytBuf As Byte
    Dim tempBuffer() As Byte
    Dim bufLen As Integer

    ' 文字列から空白削除
    strData = Replace(txtOutPutSel.Text, " ", "")
    txtLen = Len(strData) / 2
    
    ' DLNGH・DLNGL設定
    COMM_CODE.DLNGH = "&H" + Left(Format(txtLen, "0000"), 2)
    COMM_CODE.DLNGL = "&H" + Right(Format(txtLen, "0000"), 2)
    
    If COMM_CODE.DLNGL = 0 Then
        MsgBox "送信データがありません"
        Exit Sub
    End If
    
    ' 送信バッファへ代入
    Buffer(0) = COMM_CODE.DLE
    Buffer(1) = COMM_CODE.SEL
    Buffer(2) = COMM_CODE.DLE
    Buffer(3) = COMM_CODE.HA
    Buffer(4) = COMM_CODE.DLE
    Buffer(5) = COMM_CODE.UA
    Buffer(6) = COMM_CODE.DLE
    Buffer(7) = COMM_CODE.STX
    Buffer(8) = COMM_CODE.DLE
    Buffer(9) = COMM_CODE.DLNGH
    Buffer(10) = COMM_CODE.DLE
    Buffer(11) = COMM_CODE.DLNGL

    j = 0
    For i = 0 To txtLen - 1 Step 1
        strTxtData = Mid(strData, 1 + 2 * i, 2)
        bytBuf = CByte("&H" & strTxtData)
        Buffer(i + j + 12) = bytBuf
        
        If bytBuf = &H10 Then
            j = j + 1
            Buffer(i + j + 12) = bytBuf
        End If
    Next i
    
    Buffer(i + j + 12) = COMM_CODE.DLE
    Buffer(i + j + 13) = COMM_CODE.ETX
    
    COMM_CODE.BCC = "&H" & (txtLen + j + 6)
    
    If COMM_CODE.BCC = COMM_CODE.DLE Then
        Buffer(i + j + 14) = COMM_CODE.DLE
        Buffer(i + j + 15) = COMM_CODE.BCC
        bufLen = txtLen + 17
    Else
        Buffer(i + j + 14) = COMM_CODE.BCC
        bufLen = txtLen + 16
    End If
    
    ReDim tempBuffer(0 To bufLen - 1)
    
    For i = 0 To bufLen - 1
        tempBuffer(i) = Buffer(i)
    Next i
    
    ctlComm.Output = tempBuffer


しかし、受信に問題があります。
Buffer(8)の照合の場所でエラーが出てしまいます。

実行時エラー’9’
インデックスが有効範囲にありません。

とエラーが出てしまいます。
おかしいと思う点は、突然、出はじめました。
一度目送信をかけると上手くいき、二度目送信をかけるとエラーとなり
さらに、それ以降はエラーが出続けます。この間プログラムの変更はしていません。
プログラムの変更なしに、上手くいく場合とエラーが出てしまう場合とがあります。

Dim Buffer() As Byte
Buffer = ctlComm.Input
この辺りが怪しいと思い Dim Buffer(0 To 2100) As Byte や Buffer() = ctlComm.Inputにしてみ
たり
色々やってみましたが、どれもエラーになり、手詰まりになってしまいました。
いくつか調べてもみましたが、どうしても解決できないので、またよろしくお願いします。
非常に長く見づらくなってしまっているがお許しください。

以下受信プログラム
Private Sub ctlComm_OnComm()
    ' 受信データ マトリックス
    Dim Buffer() As Byte
    Dim strData As String
    Dim bufLen As Integer
    Dim i As Integer
    Dim j As Integer
    Dim bufTxt(0 To 2100) As Byte
    Dim lenBufTxt As Integer
    Dim check As Integer
    Dim lenH As Byte
    Dim lenL As Byte
    Dim Bcc As Byte
    
    ' 受信データを受信バッファへ格納
    Buffer = ctlComm.Input
    
    ' データの有無確認
    If ctlComm.CommEvent = comEvReceive Then
        bufLen = UBound(Buffer)
    Else
        MsgBox "データがありません"
        Exit Sub
    End If
    
    ' 受信データを照合
    If Buffer(0) <> COMM_CODE.DLE Then
        MsgBox "DLEが一致しません。"
        Exit Sub
    End If
    
    ' バイナリーデータ表示
    txtInPutSel.Text = ""
    For i = 0 To bufLen
        txtInPutSel.Text = txtInPutSel.Text + Format(Hex(Buffer(i)), "00") &
" "
    Next i

    Select Case Buffer(1)

    ' セレクティングと照合
    Case COMM_CODE.SEL
        
        ' セレクティング受信処理
        If Buffer(2) <> COMM_CODE.DLE Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(3) <> COMM_CODE.HA Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(4) <> COMM_CODE.DLE Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(5) <> COMM_CODE.UA Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(6) <> COMM_CODE.DLE Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(7) <> COMM_CODE.STX Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(8) <> COMM_CODE.DLE Then ←ここでエラーがでます。
            MsgBox "Err"
            Exit Sub
        End If
        
        lenH = Buffer(9)
        
        If Buffer(10) <> COMM_CODE.DLE Then
            MsgBox "Err"
            Exit Sub
        End If
        
        lenL = Buffer(11)
        
        j = 0
        i = 0
        Do
            bufTxt(i) = Buffer(i + j + 12)
            If Buffer(i + j + 12) = COMM_CODE.DLE And Buffer(i + j + 13) = COMM_CODE.DLE
Then
                bufTxt(i) = Buffer(i + j + 13)
                j = j + 1
            End If
            If Buffer(i + j + 12) = COMM_CODE.DLE And Buffer(i + j + 13) = COMM_CODE.ETX
Then
                bufTxt(i) = Buffer(i + j + 12)
                bufTxt(i + 1) = Buffer(i + j + 13)
                
                If Buffer(i + j + 14) = COMM_CODE.DLE Then
                    bufTxt(i + 2) = Buffer(i + j + 14)
                    bufTxt(i + 3) = Buffer(i + j + 15)
                    ' BCC取得
                    BCC = Buffer(i + j + 15)
                    check = 0
                Else
                    bufTxt(i + 2) = Buffer(i + j + 14)
                    BCC = Buffer(i + j + 14)
                    check = 1
                End If
        
                Exit Do
            End If
            i = i + 1
        Loop
        
        Select Case check
       Case 0
            lenBufTxt = bufLen - 16
            COMM_CODE.DLNGH = Hex(Left(Format(lenBufTxt, "0000"), 2))
            COMM_CODE.DLNGL = Hex(Right(Format(lenBufTxt, "0000"), 2))
            COMM_CODE.BCC = Hex(lenBufTxt + 6)
        Case 1
            lenBufTxt = bufLen - 15
            COMM_CODE.DLNGH = Hex(Left(Format(lenBufTxt, "0000"), 2))
            COMM_CODE.DLNGL = Hex(Right(Format(lenBufTxt, "0000"), 2))
            COMM_CODE.BCC = Hex(lenBufTxt + 6)
        Case Else
            MsgBox "Err"
            Exit Sub
        End Select
        
        If COMM_CODE.DLNGH <> lenH Then
            MsgBox "lenH が一致しない"
            Exit Sub
        End If
        If COMM_CODE.DLNGL <> lenL Then
            MsgBox "lenL が一致しない"
            Exit Sub
        End If

        If COMM_CODE.BCC <> BCC Then
            MsgBox "BCC が一致しない"
            Exit Sub
        End If
        
        ' セレクティングデータ表示
        txtInPutData.Text = ""
        For i = 0 To bufLen
            txtInPutData.Text = txtInPutData.Text + Format(Hex(bufTxt(i)), "00")
& " "
        Next i
        labInPutData.Caption = "セレクティング受信"

    ' NAKと照合
    Case COMM_CODE.NAK
        If Buffer(2) <> COMM_CODE.DLE Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(3) <> COMM_CODE.HA Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(4) <> COMM_CODE.DLE Then
            MsgBox "Err"
            Exit Sub
        End If
        If Buffer(5) <> COMM_CODE.UA Then
            MsgBox "Err"
            Exit Sub
        Else
            ' 受信データ表示
            txtInPutData.Text = ""
            For i = 0 To bufLen
                txtInPutData.Text = txtInPutData.Text + Format(Hex(Buffer(i)), "00&quo
t;) & " "
            Next i
            labInPutData.Caption = "NAK受信"
            ' RSP送信
        End If

投稿時間:2005/07/25(Mon) 14:39
投稿者名:GOD
Eメール:
URL :
タイトル:
Re: MSCommのOn_Comm受信
> 実行時エラー’9’
> インデックスが有効範囲にありません。
>
OnCommイベントで処理しているようですが、RThresholdは正しく設定していますか。
実際に受信しているサイズは何バイト分ありましたか。

投稿時間:2005/07/25(Mon) 15:02
投稿者名:チロル
Eメール:
URL :
タイトル:
Re^2: MSCommのOn_Comm受信
GODさん、また返答有難うございます。
RThresholdに関してはフォームロードのときに行っており
以下のコードになります。コメントアウトしたり、外したり、両方試しましたが結果は同じでした。

Private Sub Form_Load()
    ' ポート開放
    ctlComm.PortOpen = True
    ' 初期化 初期設定
    ctlComm.RThreshold = 1
    'ctlComm.SThreshold = 1
    ctlComm.InputLen = 0
    ctlComm.InBufferCount = 0
    ctlComm.InputMode = comInputModeBinary
    
    chkSelectUa(0) = True
End Sub

バイト数に関しては送信側からは
AA 10 BB とテキストへ入力し検査器では前後のデータも付随しており、思い通りの動作で19バイトで
す。
そして以下のコードの部分で

    ' データの有無確認
    If ctlComm.CommEvent = comEvReceive Then
        bufLen = UBound(Buffer)
    Else
        MsgBox "データがありません"
        Exit Sub
    End If

デバック時 bufLen の値が”19”となる時と”-1”となる時があります。

投稿時間:2005/07/25(Mon) 15:13
投稿者名:チロル
Eメール:
URL :
タイトル:
Re^3: MSCommのOn_Comm受信
すみません、訂正です。

> デバック時 bufLen の値が”19”となる時と”-1”となる時があります。

デバック時 bufLen の値が”19”となる時と”7”となる時があります。
でした・・・orz

投稿時間:2005/07/25(Mon) 15:26
投稿者名:GOD
Eメール:
URL :
タイトル:
Re^4: MSCommのOn_Comm受信
> すみません、訂正です。
>
> > デバック時 bufLen の値が”19”となる時と”-1”となる時があります。
>
> デバック時 bufLen の値が”19”となる時と”7”となる時があります。
> でした・・・orz
>
必要なデータが揃ってから処理するようにプログラムを変更してください。

投稿時間:2005/07/25(Mon) 15:22
投稿者名:GOD
Eメール:
URL :
タイトル:
Re^3: MSCommのOn_Comm受信
>             :
>     ctlComm.RThreshold = 1
>             :
> デバック時 bufLen の値が”19”となる時と”-1”となる時があります。
>
RThreshold = 1ということは1Byte以上のデータを受信したとき(2バイトでも3バイトでも)にイベントが
発生
します。(19バイト揃わなくても処理が走ってしまう。将来的にバグにならなければいいけど)
とりあえず、If ctlComm.CommEvent = comEvReceive Thenの判定を処理のトップで行うとどうなります
か。
(データ受信時のみInputからデータを取り出す。)

投稿時間:2005/07/25(Mon) 15:57
投稿者名:チロル
Eメール:
URL :
タイトル:
Re^4: MSCommのOn_Comm受信
Private Sub ctlComm_OnComm()
    ' 受信データ マトリックス
    Dim Buffer() As Byte
    Dim strData As String
    Dim bufLen As Integer
    Dim i As Integer
    Dim j As Integer
    Dim bufTxt(0 To 2100) As Byte
    Dim lenBufTxt As Integer
    Dim check As Integer
    Dim lenH As Byte
    Dim lenL As Byte
    Dim BCC As Byte

    ' データの有無確認
    If ctlComm.CommEvent = comEvReceive Then
       ' 受信データをバッファへ格納
        Buffer = ctlComm.Input
        bufLen = UBound(Buffer)
    Else
        MsgBox "データがありません"
        Exit Sub
    End If
という形にしてみましたが、結果は変わりませんでした。
そして、今一つ発覚したのですが、
Private Sub ctlComm_OnComm() の部分でブレイクポイントを設定すると、期待通りのデータが取れま
す。
これは、
> RThreshold = 1ということは1Byte以上のデータを受信したとき(2バイトでも3バイトでも)にイベ
ント

> 発生
> します。(19バイト揃わなくても処理が走ってしまう。将来的にバグにならなければいいけど)
と関係しているのでしょうか?!

投稿時間:2005/07/25(Mon) 17:00
投稿者名:GOD
Eメール:
URL :
タイトル:
Re^5: MSCommのOn_Comm受信
>If ctlComm.CommEvent = comEvReceive Then
>    ' 受信データをバッファへ格納
>    Buffer = ctlComm.Input
>    bufLen = UBound(Buffer)
>Else
>
と直してもらいましたがまだエラーは出ると思います。(文章の前半部分を参照)
実は
hhttp://www.bcap.co.jp/hanafusa/vbbbs/wforum.cgi?no=3856&reno=3855&oya=3849&mode=m
sgview
を見る前に投稿したので「bufLenが-1を返す」のだと思ってそれを防ぐ為の処理(文章の後半)を投稿し
ました。
要は受信フラグが立ってからデータを受信すれば-1にはならないということです。

■修正追加部分 --- ここから
上記処理は以下の仮説の元に
「-1を返しているというのは、実は他のイベント(ステータスの変化など)でOnCommが発生したが、処理をし
ている最中にデータ受信を行い、ctlComm.CommEvent = comEvReceiveの条件が満たされているのではな
いか。」ということでです。(余りそういうことはなさそうな気はするが一応ね。)
■修正追加部分 --- ここまで

実際には-1でなく8バイト受信しているとの事なのでやはりデータが揃った時点で比較などの処理に移行
するようにしなければなりません。

> Private Sub ctlComm_OnComm() の部分でブレイクポイント・・・
>
↑はブレークポイントで止めている間もOS側は処理が動いており、受信がくればデータを受信バッファ
に移すので、そのタイムラグで全てデータが揃っているということだと思います。

投稿時間:2005/07/25(Mon) 16:08
投稿者名:yuta
Eメール:
URL :
タイトル:
Re^4: MSCommのOn_Comm受信
横から失礼します、yutaと申します。
> RThreshold = 1ということは1Byte以上のデータを受信したとき(2バイトでも3バイトでも)にイベ
ント

> 発生
> します。(19バイト揃わなくても処理が走ってしまう。将来的にバグにならなければいいけど)
> とりあえず、If ctlComm.CommEvent = comEvReceive Thenの判定を処理のトップで行うとどうなり


> か。
> (データ受信時のみInputからデータを取り出す。)

まず、OnCommイベントが発生したときには19バイト全てのデータを受信しているとは限りません。
やはり通信速度の関係もありますが、最初に7バイト、多少ずれて、9バイト…のような感じになりま
す。(あくまでも例です。)

データが固定長ならばGODさんの方法で大丈夫だと思います。(自信なし。)

投稿時間:2005/07/25(Mon) 17:13
投稿者名:ガッ
Eメール:
URL :
タイトル:
Re^5: MSCommのOn_Comm受信
ノ<私も横失礼
そういえば生のシリアル通信ってバイト境界を維持しないんでしたっけね…
で、ストリームなら、FIFOバッファを作っておくと非常に楽かも。

投稿時間:2005/07/25(Mon) 17:31
投稿者名:チロル
Eメール:
URL :
タイトル:
Re^6: MSCommのOn_Comm受信
yutaさん有難うございます。
ですが、残念ながら受信データは固定長ではなく可変長です。
折角アドバイス頂いたのに、申し訳ないですorz

GDOさん
>↑はブレークポイントで止めている間もOS側は処理が動いており、受信がくればデータを受信バッ
ファ
>に移すので、そのタイムラグで全てデータが揃っているということだと思います。
いくつか手直しして試してみましたが、間違いなくそのことが原因だとわかりました。

> で、ストリームなら、FIFOバッファを作っておくと非常に楽かも。
ガッさん有難うございます。
これが解決案になるのでしょうか。試してみます。

投稿時間:2005/07/26(Tue) 00:47
投稿者名:G13
Eメール:
URL :
タイトル:
Re^7: MSCommのOn_Comm受信
よこやりスミマセン。
参考になればと思い、投稿致します。
#過去ログ詳しく見ていないので重複した質問があるかも知れません・・・。

受信フォーマットはこんな感じでしょうか?。

&H10(DLE)
&H71(SEL) *1
&H10(DLE)
&H80(HA)
&H10(DLE)
&H8A(UA)
&H10(DLE)
&H02(STX) *2
&H10(DLE)
&H**(LENGTH_HIGH) *3
&H10(DLE)
&H**(LENGTH_LOW) *3

データ(可変長)

&H10(DLE)
&H03(ETX) *4
&H**(BCC) *5

フレームを検定するのに必要そうな箇所を洗い出しました。
それぞれ細かくなりますが、質問があります。

*1:ポーリングに対する応答か否定応答(NAK)を判別する種別コード見ないな感じですか?。
*2:データ長の算出開始位置ですか?
*3:データ長(High/Low)は、どこからどこまでの長さが指定されていますか?。
*4:フレームの最終を示すコードですか?
*5:BCCは、どこからどこまでをどう計算した値ですか?

シリアルのMSCommでOn_Commを使用すると、8バイト以上を受信する場合、8バイト毎に1回
のOn_Commイベントが発生する事が多いです(伝送速度やハードにもよります)。

ですので、可変長が8バイト以下の場合、今回で言うと「NAK」の場合がそれにあたりますが、
現在の受信処理であれば、1回のOn_Commイベントで処理が行えるのは、8バイト以下のフレー
ムのみですから、上手く受信できます。
しかし、SELフレームの場合、8バイト以上のようですから、長いデータ長のフレームを受信
する場合、最初のDLE〜BCCまでを受信するまでは、幾度かのOn_Commイベントが発生し、その
間に受信したデータは、フレームが完全に受信しきるまでは何らかのバイト配列のグローバ
ル変数へ確保する必要があります。
その後、1フレームが受信完了した時点、各コードのチェックやBCCの検定を行うことが必要です。

#ReDim/ReDim Preserveを参照

エラーになる原因:
他の方々から回答もあるように・・・。
今のコードでは1回のイベントで受信したデータのみで全フレームのコートを検定しているので、
On_Commイベント内のまだ受信していないBuffer(8)でエラーとなります。

投稿時間:2005/07/26(Tue) 03:12
投稿者名:Starfish
Eメール:
URL :
タイトル:
Re: MSCommのOn_Comm受信
 通信系は多少はわかりますが、あまり詳しくはないので、違っているところ
があるかもしれませんが。

> NAK:6バイト固定で送信されるコマンド
> セレクティング:TEXTへ入力されたバイナリー形式の文字列を送信する可変バイトのコマンド
> の二つがあります。

 送るのが、NAKとセレクティングですか?又、セレクティングにデータが引っ付いている
のですか?どんなプロトコルですか?

> コマンドはボタンを押し手動で送信をかける作りになっています。

 NAKとかセレクティングって、普通コマンドボタンからいきなり送信するって
普通ないですよね?テストプログラムなの?

>     ' DLNGH・DLNGL設定
>     COMM_CODE.DLNGH = "&H" + Left(Format(txtLen, "0000"), 2)
>     COMM_CODE.DLNGL = "&H" + Right(Format(txtLen, "0000"), 2)

 大文字のみの名前は、定数とか型の名前で使うことが多いから変数名に使うと
見にくいですね。(よく見るとピリオドが入っているんだ>COMM_CODE.DLNGH)
 COMM_CODE.DLNGH って、バイト型の変数だと思うんですが、文字列をセット
していますね。VAL関数とかで、数値に変換してから代入しましょう。
 長さを、BCDでセットしようとしています?普通はバイナリデータだと思うんですが、
であればこんなかんじでいいのでは?

     COMM_CODE.DLNGH = txtLen \ 256
     COMM_CODE.DLNGL = txtLen Mod 256

>     j = 0
>     For i = 0 To txtLen - 1 Step 1
>         strTxtData = Mid(strData, 1 + 2 * i, 2)
>         bytBuf = CByte("&H" & strTxtData)
>         Buffer(i + j + 12) = bytBuf
>        
>         If bytBuf = &H10 Then
>             j = j + 1
>             Buffer(i + j + 12) = bytBuf
>         End If
>     Next i

 データに、DLEがあったら、DLE+DLEにしていますよね。その場合に、
データ長は増やさないのですか?増やさない場合は、受信側が単純に
DLNGH・DLNGLからデータの長さがわからないので、受信側が面倒にな
りますね。

>     COMM_CODE.BCC = "&H" & (txtLen + j + 6)

 変な仕様ですね、これでは文字化けしててもチェックできませんね。又、文字列を
セットしているし、データ長が大きいとオーバフローしそうですね。

>     If COMM_CODE.BCC = COMM_CODE.DLE Then
>         Buffer(i + j + 14) = COMM_CODE.DLE
>         Buffer(i + j + 15) = COMM_CODE.BCC
>         bufLen = txtLen + 17
>     Else
>         Buffer(i + j + 14) = COMM_CODE.BCC
>         bufLen = txtLen + 16
>     End If

 BCCがDLEのときは、DLE+BCCとするのですね。送信側と受信側で
あっていれば問題ないですけどね。
 bufLen ですが、1大きいような気がします。又、+jをしないといけない
のではないでしょうか?

 とりあえず、送信側のみ気になったところを書いて見ました。仕様がよくわから
ないので、中途半端なレスになってしまいましたが。

投稿時間:2005/07/26(Tue) 08:44
投稿者名:G13
Eメール:
URL :
タイトル:
Re^2: MSCommのOn_Comm受信
>  データに、DLEがあったら、DLE+DLEにしていますよね。その場合に、
> データ長は増やさないのですか?増やさない場合は、受信側が単純に
> DLNGH・DLNGLからデータの長さがわからないので、受信側が面倒にな
> りますね。
#多分ですけど。
データ部にDLEがあった場合、DLE+DLEとするのは、データ拡張コードか
データの&H10なのかを区別する為に、連続してDLEを付加するのですが、
この際データ長に反映しない場合も、あることはありますね。
#普通、最後にデータ長を付加して送信すると思われますが、実際に私
#も経験ありません。ただ、そういった仕様を見た事はあります。
受信側は、単純にデータ長で検定できないので、DLE+ETXコードを検定し
て、BCCコードにはDLE+DLE部も反映するはずなので、BCCでフレームの
正否判定を行っているのではないでしょうか?。

#その他、ご指摘の通り。?!的なところはありますけど。

>  BCCがDLEのときは、DLE+BCCとするのですね。送信側と受信側で
> あっていれば問題ないですけどね。
ここもDLEを挿入する事で、データとDLEか&H10というデータなのかを区別
する為だけでしょうね。

投稿時間:2005/07/26(Tue) 10:20
投稿者名:チロル
Eメール:
URL :
タイトル:
Re^3: MSCommのOn_Comm受信
G13さん Starfishさん 追加アドバイス有難うございます。
受信フォーマットの関しG13さんの推測はほとんど正解です。
まず、このプログラムは1台のホストコンピュータに対し複数の従属局が付くことになっています。
とは言うものの、このプログラムはメインではなく、デバック用のツールのような、社内で鑑定するた
めのプログラムです。
当方まだ、始めたばかりであり、これが初案件的なものになります。
参考のためにいくつか質問して頂いていますが、的外れな回答をしてしまったら申し訳ございません。
私の知識範囲の限り回答したいと思います。

Function initialize()
   ' 制御コード初期化
    With COMM_CODE
        .STX = &H2
        .ETX = &H3
        .ENQ = &H5
        .ACK = &H6
        .DLE = &H10
        .NAK = &H15
        .POL = &H70
        .SEL = &H71
        .RSP = &H72
        .HA = &H80
    End With
End Function
ここまでは固定長のものです。

可変長は UA  DLNGH  DLNGL  BCC の四つになります。
UA:従属局のアドレス
DLNGH:TEXTデータ(最大2000)の上二桁の値になります
DLNGL:TEXTデータ(最大2000)の下二桁の値になります
BCC:DLE DLNGH DEL DLNGL TEXTデータ DLE ETX がBCCの計算対象範囲となっています。

>*1:ポーリングに対する応答か否定応答(NAK)を判別する種別コード見ないな感じですか?。
おっしゃる通りです。ポーリングに対しNAKかレスポンスを返す仕様となっています。
また、レスポンスの作りはセレクティングと酷似しています
参考:
ポーリング DEL POL DLE HA DLE UA という6バイト固定の構造です。
他にACK NAK ENQ などありますが、2バイト目のPOLの箇所が ACK NAK ENQ と置き換えるだけで別コマン
ドとしています。
セレクティングとレスポンス
セレクティング DEL SEL DLE HA DLE UA DLE DLNGH DEL DLNGL TEXTデータ DLE ETX (DLE)BCC
という構造です。最後のBCCの前のDLEが()で括られている理由はBCCが10のときはDLEを付加するという
仕様のためです。
レスポンスに関して、6バイトの固定コマンドと同じように2バイト目をRSPに置き換えることで別コマ
ンドとしています。

>*2:データ長の算出開始位置ですか?
上記記載
>*3:データ長(High/Low)は、どこからどこまでの長さが指定されていますか?。
上記記載
>*4:フレームの最終を示すコードですか?
構造は上記に記載した通りなのですが・・・最終を示すのはETXかBCCなのでしょうが、私にはどちらが
最終フレームとして扱って良いかわかりません。最後についているという単純な意味合いでBCCだと認識
していました。
>*5:BCCは、どこからどこまでをどう計算した値ですか?
上記記載

>送るのが、NAKとセレクティングですか?又、セレクティングにデータが引っ付いている
>のですか?どんなプロトコルですか?
種類と省略兼ねてNAKとセレクティングを挙げましたが実際は上記記載のようにいくつか存在します。
上記の説明で先回答となってしまいます。
プロトコルに関して、的外れになる予感がしますが、そもそもこのプロジェクト名が「××(社名)プ
ロトコル」なのです。
そのプロトコル仕様書に沿って作っている感じです。

>NAKとかセレクティングって、普通コマンドボタンからいきなり送信するって
>普通ないですよね?テストプログラムなの?
上記の通り、客先ではなく、メインでプログラムを書いている方は別に存在し、その方のデバック用の
ツールとして作成しているため
「手動でもコマンドを投げれるように」との指示の元作成しています。

>COMM_CODE.DLNGH って、バイト型の変数だと思うんですが、文字列をセット
>していますね。VAL関数とかで、数値に変換してから代入しましょう。
有難うございます。まさにその通りで、特定の処理のときはツジツマが合いましたがパターンを変える
とダメになっていました。
なんとか、原因をつきとめれたのですが、まさに指摘されている箇所でした。

>データに、DLEがあったら、DLE+DLEにしていますよね。その場合に、
>データ長は増やさないのですか?増やさない場合は、受信側が単純に
>DLNGH・DLNGLからデータの長さがわからないので、受信側が面倒にな
>りますね。
仕様上テキストデータ内に&H10(DLE)と同じものがあった場合、次に来る値も&H10(DLE)と
二つ連な
って初めて1バイトの&H10として認識させる仕様になっています。
これは従属局がマイコンになる予定があるらしく、そういった透過処理が必要になるみたいです。
受信側も少し工夫がいると言われているので、これは仕様のようです。(自分ではまだわかっていな
く、「みたい」とか「のようだ」の表現が多く申し訳ありません。)

>データに、DLEがあったら、DLE+DLEにしていますよね。その場合に、
>データ長は増やさないのですか?
これは加算しないようです。受信側でも加算されたものを減算させ真の値と扱うようです。

>変な仕様ですね、これでは文字化けしててもチェックできませんね。又、文字列を
>セットしているし、データ長が大きいとオーバフローしそうですね。
おっしゃる通りオーバーフローしました。bufLenに関しても指摘通りで1多かったです。
本当・・・間違いだらけですみません。。。orz

と、回答できるものは以上です。
現在は頂いたアドバイスと併用で一つずつ、試行錯誤しています。
上手くまとまれば、報告したいと思うので、追加アドバイスあれば、どうかよろしくお願いします。

投稿時間:2005/07/26(Tue) 11:30
投稿者名:GOD
Eメール:
URL :
タイトル:
Re^4: MSCommのOn_Comm受信
> With COMM_CODE
> .STX = &H2
>     :
> .HA = &H80
> End With
>
> 追加アドバイスあれば、どうかよろしくお願いします。
>
固定値のところはConstで宣言した方がいいよ。(Enum(列挙型)でもいいけどVBでは使いにくい)
'宣言場所がフォーム内ならPrivate, 標準モジュールならPublicにしてね
Private Const STX as Byte = &H2
         :
Private Const HA as Byte = &H80
↑のようにすると
> COMM_CODE.DLE
とか書いてあるところはDLEのみでOKになるから余分なCOMM_CODEがなくなる分だけプログラムが見やす
くなる
かと。可変値のところは今まで通りで。

投稿時間:2005/07/26(Tue) 11:43
投稿者名:G13
Eメール:
URL :
タイトル:
Re^4: MSCommのOn_Comm受信
おはようございます。
仕様がある程度理解でしました。

> 可変長は UA  DLNGH  DLNGL  BCC の四つになります。
> UA:従属局のアドレス
> DLNGH:TEXTデータ(最大2000)の上二桁の値になります
> DLNGL:TEXTデータ(最大2000)の下二桁の値になります
> BCC:DLE DLNGH DEL DLNGL TEXTデータ DLE ETX がBCCの計算対象範囲となっています。
>
> >*1:ポーリングに対する応答か否定応答(NAK)を判別する種別コード見ないな感じですか?。
> おっしゃる通りです。ポーリングに対しNAKかレスポンスを返す仕様となっています。
> また、レスポンスの作りはセレクティングと酷似しています
> 参考:
> ポーリング DEL POL DLE HA DLE UA という6バイト固定の構造です。
> 他にACK NAK ENQ などありますが、2バイト目のPOLの箇所が ACK NAK ENQ と置き換えるだけで別コマ

> ドとしています。
> セレクティングとレスポンス
> セレクティング DEL SEL DLE HA DLE UA DLE DLNGH DEL DLNGL TEXTデータ DLE ETX (DLE)BCC
> という構造です。最後のBCCの前のDLEが()で括られている理由はBCCが10のときはDLEを付加するという
> 仕様のためです。
> レスポンスに関して、6バイトの固定コマンドと同じように2バイト目をRSPに置き換えることで別コマ
> ンドとしています。
>
> >*2:データ長の算出開始位置ですか?
> 上記記載
TEXTデータ部のみのデータ長ということを理解しました。

> >*3:データ長(High/Low)は、どこからどこまでの長さが指定されていますか?。
> 上記記載
了解です。
これがフレーム全体の長さを示すかも知れないと思っておりましたが、*2の通り
TEXTデータの長さのようですから、受信判定には使用しなくても良いでしょう。

> >*4:フレームの最終を示すコードですか?
> 構造は上記に記載した通りなのですが・・・最終を示すのはETXかBCCなのでしょうが、私にはどちらが
> 最終フレームとして扱って良いかわかりません。最後についているという単純な意味合いでBCCだと認
> 識していました。
いえ、最終はETXです。BCCは送るデータによって可変するので。
ETXを検出して、後ろの1バイト(DLEが割込む場合2バイト)をBCCと扱えばいいです。

> >*5:BCCは、どこからどこまでをどう計算した値ですか?
> 上記記載
STXは含まない、ETXは含むなのですね?。ま、仕様なのか・・・。
BCCはフレームが受信して、フレーム形成が正しいか否かの検定の際、受信したフレームデータから
計算して正否を判定しなければなりません。

> >送るのが、NAKとセレクティングですか?又、セレクティングにデータが引っ付いている
> >のですか?どんなプロトコルですか?
> 種類と省略兼ねてNAKとセレクティングを挙げましたが実際は上記記載のようにいくつか存在します。
> 上記の説明で先回答となってしまいます。
> プロトコルに関して、的外れになる予感がしますが、そもそもこのプロジェクト名が「××(社名)プ
> ロトコル」なのです。
> そのプロトコル仕様書に沿って作っている感じです。
>
> >NAKとかセレクティングって、普通コマンドボタンからいきなり送信するって
> >普通ないですよね?テストプログラムなの?
> 上記の通り、客先ではなく、メインでプログラムを書いている方は別に存在し、その方のデバック用の
> ツールとして作成しているため
> 「手動でもコマンドを投げれるように」との指示の元作成しています。
>
> >COMM_CODE.DLNGH って、バイト型の変数だと思うんですが、文字列をセット
> >していますね。VAL関数とかで、数値に変換してから代入しましょう。
> 有難うございます。まさにその通りで、特定の処理のときはツジツマが合いましたがパターンを変える
> とダメになっていました。
> なんとか、原因をつきとめれたのですが、まさに指摘されている箇所でした。
>
> >データに、DLEがあったら、DLE+DLEにしていますよね。その場合に、
> >データ長は増やさないのですか?増やさない場合は、受信側が単純に
> >DLNGH・DLNGLからデータの長さがわからないので、受信側が面倒にな
> >りますね。
> 仕様上テキストデータ内に&H10(DLE)と同じものがあった場合、次に来る値も&H10(DLE)と
> 二つ連な
> って初めて1バイトの&H10として認識させる仕様になっています。
> これは従属局がマイコンになる予定があるらしく、そういった透過処理が必要になるみたいです。
> 受信側も少し工夫がいると言われているので、これは仕様のようです。(自分ではまだわかっていな
> く、「みたい」とか「のようだ」の表現が多く申し訳ありません。)
テキストデータ内に、&H10,&H10という連続したデータが存在しないことを前提としている。
ということでしょう。

> >データに、DLEがあったら、DLE+DLEにしていますよね。その場合に、
> >データ長は増やさないのですか?
> これは加算しないようです。受信側でも加算されたものを減算させ真の値と扱うようです。
了解しました。

非常に単純に、受信した1フレームを取り出せそうですね。

DLE(&H10) + ETX(&H02) を検出するまで1フレーム分のデータは受信し切れていない。
と言えます。但し、この後に続くBCCを取り出す処理は必要ですけど。

受信カウンタ(グローバル変数)を準備し、-1:未受信。0以上を受信中とする。

On_Commイベント内
受信開始からバイト配列データを確認して、DLE & ETXが見つかるまで、バイト配列の
グローバル変数へデータをコピーしていく。
DLE & ETX が検出されたら、BCCの取り出しとして、次の1バイトを検定=&H10か否かで、
もう1バイトを取り出す。

これで1フレームの取り出しが完了。
フレーム内コード及び、BCCを検定し、正常ならテキストデータを表示する。

#言葉で書くと判りにくいかも。

投稿時間:2005/07/27(Wed) 03:34
投稿者名:Starfish
Eメール:
URL :
タイトル:
Re^4: MSCommのOn_Comm受信
受信系を直してみました。デバッグしていないのでバグっているかも

Dim mbytRecvData() As Byte

Private Sub ctlComm_OnComm()
Dim lngLen As Long
Dim lngEtxPos As Long
Dim lngDlePos As Long
Dim bytlenH As Byte
Dim bytlenL As Byte
Dim i As Long
Dim bytDataDLE() As Byte
Dim bytData() As Byte
Dim bytBcc As Byte

    ' イベントの確認(テストプログラムなので受信以外は終了)
    If ctlComm.CommEvent <> comEvReceive Then
        MsgBox "受信以外のイベント発生" & CStr(ctlComm.CommEvent)
        Exit Sub
    End If
    
    ' 受信データを受信バッファへ格納
    mbytRecvData = CStr(mbytRecvData) & ctlComm.Input
    
    ' 受信データ長
    lngLen = UBound(mbytRecvData) + 1
    
    ' 受信データを照合
    If mbytRecvData(0) <> COMM_CODE.DLE Then
        MsgBox "DLEが一致しません。"
        mbytRecvData = ""       ' 受信バッファをクリア
        Exit Sub
    End If

    Select Case mbytRecvData(1)
    ' セレクティングと照合
    Case COMM_CODE.SEL
        lngEtxPos = InStrB(CStr(mbytRecvData), ChrB(COMM_CODE.DLE) & ChrB(COMM_CODE.ETX))
        If lngEtxPos = 0 Then Exit Sub              ' DLE ETX 未受信
        If lngLen = lngEtxPos + 1 Then Exit Sub     ' BCC未受信
        If (lngLen = lngEtxPos + 2) And (mbytRecvData(lngLen - 1) = COMM_CODE.DLE) Then
            Exit Sub                                ' BCCがDLE で1文字のみ受信
        End If
        
        ' セレクティング受信処理
        If (mbytRecvData(2) <> COMM_CODE.DLE) Or _
           (mbytRecvData(3) <> COMM_CODE.HA) Or _
           (mbytRecvData(4) <> COMM_CODE.DLE) Or _
           (mbytRecvData(5) <> COMM_CODE.UA) Or _
           (mbytRecvData(6) <> COMM_CODE.DLE) Or _
           (mbytRecvData(7) <> COMM_CODE.STX) Or _
           (mbytRecvData(8) <> COMM_CODE.DLE) Or _
           (mbytRecvData(10) <> COMM_CODE.DLE) Then
            MsgBox "セレクティングを受信しましたがデータ異常"
            mbytRecvData = ""       ' 受信バッファをクリア
            Exit Sub
        End If
        
        ' データ長
        bytlenH = mbytRecvData(9)
        bytlenL = mbytRecvData(11)

        ' データ部(DLE付)
        bytDataDLE = MidB(mbytRecvData, 13, lngEtxPos - 13)
        
        ' BCC
        bytBcc = mbytRecvData(lngEtxPos + 1)

        ' データ部からDLEを削除(元のデータ)
        For i = 0 To UBound(bytDataDLE)
            If bytDataDLE(i) = COMM_CODE.DLE Then
                i = i + 1
            End If
            bytData = CStr(bytData) & ChrB(bytDataDLE(i))
        Next

        ' データ長チェック
        If (bytlenH * 256 + bytlenL) <> UBound(bytData) + 1 Then
            MsgBox "データ長が一致しない"
            mbytRecvData = ""       ' 受信バッファをクリア
            Exit Sub
        End If

        ' BCCのチェックを追加してください
        
        ' セレクティングデータ表示
        txtInPutData.Text = ""
        For i = 0 To UBound(bytData)
            txtInPutData.Text = txtInPutData.Text & Right("00" & Hex(bytData(i)), 2) & " "
        Next i
        labInPutData.Caption = "セレクティング受信"
        mbytRecvData = ""       ' 受信バッファをクリア

    ' NAKと照合
    Case COMM_CODE.NAK
        If lngLen < 6 Then Exit Sub ' 未完了
        If (mbytRecvData(2) <> COMM_CODE.DLE) Or _
           (mbytRecvData(3) <> COMM_CODE.HA) Or _
           (mbytRecvData(4) <> COMM_CODE.DLE) Or _
           (mbytRecvData(5) <> COMM_CODE.UA) Then
            MsgBox "NAKを受信しましたが、データが異常です"
            mbytRecvData = ""   ' 受信バッファをクリア
            Exit Sub
        End If
        labInPutData.Caption = "NAK受信"
        mbytRecvData = ""       ' 受信バッファをクリア
        ' RSP送信

投稿時間:2005/07/27(Wed) 16:26
投稿者名:G13
Eメール:
URL :
タイトル:
Re^5: MSCommのOn_Comm受信
Starfishさん すばらしい。
机上での確認ですがOKそうですね。

個人的には、今回の使用が主局〜複数の従局へポーリングしていくようなので、
1フレームが受信完了した時の、受信バッファクリア時に、ctlComm.InBufferCount = 0 を
入れておきたいかな・・・と。

仮定として、モデム回線を使用している場合、Host側がRTS/CTSを用いたキャリア制御を行
っていると、たまに受信バッファへゴミが入ってくることがあるので、受信完了時等で一度
クリアした方が個人的に気持ちが良い・・・ということだけですけど。

#余計なお世話でしたね。失礼致しました<(__)>

投稿時間:2005/07/29(Fri) 13:08
投稿者名:チロル
Eメール:
URL :
タイトル:
Re^6: MSCommのOn_Comm受信
アドバイス頂いた方々、返答が遅れてしまい申し訳ございません。
二日ほどオフラインの環境で仕事をしていたもので。
本当に色々なアドバイス有難うございます。
最後にまとめて頂いたStarfishさん のプログラムで動作確認できました。
ただ、まだ自分自身理解しきれていないので、もう少しじっくり解釈していきたいと思います。
本当に有難うございました。&また、書き込むことがあると思うのでよろしくお願いしますm(__)m