@hiroasap

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

シリアルポートの16進数を処理したい

シリアルポートの16進数を処理したい

VC2019で無線機とシリアル通信をするプログラムを作っています。
無線機からは16進数でデータが送られてきてそれの処理をするのがわかりません
のでご教示願えますか
以前他の無線機ではデータがアスキーコードで送られてきたので処理することが
出来たのですが16進数ですとどう処理するのかわかりませんのでお願いします
言語 C++ MFC利用
シリアルを受信のコード

int RADIO1::Readrs232c(CString* RS_Send, CString* RS_Read)
{
CString SSD, RRD;
char In[1024];
DWORD lRead;
int  itemp;

//HANDLE hPort;
int Ret = 0;

strcpy_s(In, 1024, "    ");
//フフフフのゴミが出てしまうのでここでスペース代入

Ret = ReadFile(   // データの受信
    ComPort,   
    //  通信デバイスのハンドル: CreateFile()で取得したハンドルを指定
    In,       
    // 受信バッファーのポインタを指定: 受信データがここに格納されます。
    1024,        
    // 受信するバイト数を指定: ここで指定するバイト数を受信するか
    //またはタイムアウト時間がくるまで
    // ReadFile()関数は( getc()のように )待ちます
    &lRead,  //  実際に受信したバイト数(DWORD)が格納されるポインタを指定
    NULL   // 通信とは関係ない引数なのでNULLを指定
);

if (Ret == FALSE)     //失敗した場合
{
    printf("ReadFile failed. \n");
    CloseHandle(ComPort);
    exit(0);
}

//アスキーの場合は下記で処理出来てます
RRD = In;
*RS_Read = RRD;

//とりあえずintに変換してみました
int kari;
kari = int(In);

return 0;

}

他のシリアル通信モニタープログラムで無線機からの受信したデータを確認したところ
FE FE 00 94 00 60 57 01 07 00 FD
となっていて
中の意味は下記のようになってます
FEFEはコマンド先頭のコード
00は宛先アドレス
94は送信元のアドレス
00はコマンド
60 57 01 07 00
はデータで 0070015760 です
FDはコマンド末尾のコード

vc2019でブレークでkariを16進数で確認した値です
0x6ed1a660

0 likes

5Answer

他のシリアル通信モニタープログラムで無線機からの受信したデータを確認したところ
FE FE 00 94 00 60 57 01 07 00 FD
となっていて・・・

上のように、"FE FE 00 94 00 60 57 01 07 00 FD"と出力させたいのでしょうか?


無線機からは16進数でデータが送られて・・・

その無線機の型式や品名が分かれば、もう少しアドバイスできるかも知れません。

0Like

Comments

  1. @hiroasap

    Questioner

    回答ありがとうございます。
    無線機はICOM IC-7300です
    この例でいいますと
    "FE FE 00 94 00 60 57 01 07 00 FD"
    FEFEのあとの00がコマンドで周波数を表示する意味です
    そのあとの60 57 01 07 00が実際の中身で0007015760が周波数の値を
    取り出したいです
    他にもコマンド01がモードだったりします
    プログラムの方はポインターの使い方がよくわかってなくて苦戦してます

  2. ↑ こちらの取説で 各種フォーマットが理解できました。

    VC++MFCでプログラムを作るのは、他の無線機用のプログラムを改造している ということでしょうか? (おっしゃる通り、ポインターの理解がネックになりますね)
    Pythonであれば、C\C++よりデータの取り扱いが楽にできると思いますが。

  3. CI-V のライブラリが出回っていないかネットを探してみました。
    役に立つか分かりませんが、3つ挙げておきます。

  4. @hiroasap

    Questioner

    ありがとうございます
    色々と紹介していただき助かりました
    だいぶ参考にさせていただきました

    他の無線機用のプログラムを参考に新規で作成しています
    ポインターが苦手でいつも苦労してます。
    Pythonはラズパイで同様に無線機操作のプログラムを作成した経験が
    あります。どうしてもwindowsですとc++を使いがちになってしまってます。

取得部分は何かのサンプルで試しているのでしょうけど
エラーが出ていないなら周波数の値が配列 In に入っているでしょ?

そこから取り出すのにポインタは特に不要かと思います

あとその受信形式はアスキー(テキスト形式)に対してバイナリ形式になります
16進は表示の問題だけで関係ありません

0Like

Comments

  1. @hiroasap

    Questioner

    Inを渡すのに苦労してました

C++のコードは長いこと書いてないので、細かい間違いはあると思います。

//コマンド格納クラス
class CivCommand {
public:
    unsigned char ReceiverAddress;//受信アドレス
    unsigned char SenderAddress;//送信アドレス
    unsigned char Command;//コマンド
    unsigned char SubCommand;//サブコマンド
    unsigned short SubSubCommand;//サブサブコマンド(コマンド0x1Aのみで使用)
    std::vecter<unsigned char> datas;//データエリア
    unsigned int ByteLength;//データ長(プリアンブル、ポストアンブルも含む)

    //コンストラクタ
    //  buffer: 受信バッファ
    //  bufferMaxLength:  受信バッファの最大サイズ
    CivCommand(const unsigned char *buffer, size_t bufferMaxLength) {
        //簡易フォーマットチェック
        if (buffer[0] != 0xFE || buffer[1] != 0xFE) {
            throw "プリアンブル異常";
        }
        unsigned char* postamblePointer = memchr(buffer + 5, 0xFD, bufferMaxLength - 5);
        if (postamblePointer == NULL) {
            throw "ポストアンブル未検出";
        }

        //ヘッダ部取得
        ByteLength = postamblePointer - buffer + 1;
        ReceiverAddress = buffer[2];
        SenderAddress = buffer[3];
        Command = buffer[4];
        int dataHeadIndex = 5;
        if (Command <= 0x06 || Command == 0x09 || Command == 0x0A || Command == 0x0B ||
            Command == 0x10 || Command == 0x11 || Command == 0x17 || Command == 0x25 ||
            Command == 0x26) {
            //サブコマンドなし
        } else if (Command == 0x0E || Command == 0x0F || Command == 0x13 || Command == 0x14 ||
            Command == 0x15 || Command == 0x16 || Command == 0x18 || Command == 0x19 ||
            Command == 0x1B || Command == 0x1C || Command == 0x1E || Command == 0x21 ||
            Command == 0x25 || Command == 0x26 || Command == 0x27 || Command == 0x28) {
            //サブコマンドあり(0x1A以外)
            SubCommand = buffer[5];
            dataHeadIndex = 6;
        } else if (Command == 0x1A) {
            //サブサブコマンドあり(0x1Aのみ)
            SubCommand = buffer[5];
            SubSubCommand = (buffer[6] << 8) + buffer[7];
            dataHeadIndex = 8;
        } else {
            throw "未定義コマンド";
        }

        //データ部をクラスの内部バッファにコピー
        datas.reserve(ByteLength - dataHeadIndex - 1);
        for (int i=dataHeadIndex; i < ByteLength-1; i++) {
            datas.push_back(buffer[i]);
        }
    }
}
0Like

Comments

  1. @hiroasap

    Questioner

    ご丁寧にサンプルまでいただきありがとうございます
    だいぶ参考にさせていただきました

皆さまご回答ありがとうございます。
色々検証に時間がかかってしまって申し訳ありません
今色々ためしてるところです

0Like

みなさまありがとうございます
検証に時間がかかっていまい申し訳ありません

途中で試行錯誤している時にどうしても
int RADIO1::Readrs232c(CString* RS_Send, CString* RS_Read)
の変数InからRS_Readに読み込み結果を渡せませんでした
charからintに変換できませんとかその手の変換できませんのコンパイルエラーが
出てしまってました

最終的には
ReadFile のバッファーを1にしてreturnで返すようにしたら
読み込み結果を利用できるようになりました。
途中は読み込んだデータではなくアドレスを読み込んでしまったり
してるようでした。
どうもポインターはむずかしいです

とりあえずこれでうまくいってるようです

元の関数
int RADIO1::Readrs232c(int* RS_Send, int* RS_Read)
{
CString SSD, RRD;
char In[1024];
DWORD lRead;
int itemp;

//HANDLE hPort;
int Ret = 0;

strcpy_s(In, 1024, " ");
//フフフフのゴミが出てしまうのでここでスペース代入

Ret = ReadFile( // データの受信
ComPort,
//  通信デバイスのハンドル: CreateFile()で取得したハンドルを指定
In,
// 受信バッファーのポインタを指定: 受信データがここに格納されます。
1024,
// 受信するバイト数を指定: ここで指定するバイト数を受信するか
//またはタイムアウト時間がくるまで
// ReadFile()関数は( getc()のように )待ちます
&lRead, // 実際に受信したバイト数(DWORD)が格納されるポインタを指定
NULL // 通信とは関係ない引数なのでNULLを指定
);

if (Ret == FALSE) //失敗した場合
{
printf("ReadFile failed. \n");
CloseHandle(ComPort);
exit(0);
}

//アスキーの場合は下記で処理出来てます
RRD = In;
*RS_Read = RRD;

//とりあえずintに変換してみました
int kari;
kari = int(In);

return 0;

0Like

Your answer might help someone💌