質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.34%

バイナリからSレコードに変換してファイルに出力

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,268

score 109

#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable: 4996)

#define  ROWREADMAX 256 //一行の読み込み最大文字数
#define BUFFER 1024  
#define ADDRESSBYTE2 2
#define ADDRESSBYTE3 3
#define ADDRESSBYTE4 4
#define FILE_OPEN_ERR 0x01            //ファイルオープンエラー
#define FILE_SPECIFIED_ERR 0x02   //    ファイル指定エラー
#define OPT_ERR 0x04                       //オプションエラー
#define CHECKSUMBYTE1 1
#define STYPE_MAX 4                       //stypeの指定は4まで
//オプション
typedef  struct {

    char* infilename;
    char* outfilename;
    char  input_flag;
    char output_flag;
    char help_flag;
    char write_flag;

    int loadaddress;  //ロードアドレス
    int stype;            //Sレコードのタイプ
    int oneline_data_length;  //一行のデータの長さ
    char srecord0_text[];     //S0に入れるテキスト
} opts_t;

//プロトタイプ宣言
void analysis_binary_change_srecord(char read_oneline_data_length[], FILE* wfile, int loadaddress, int stype, int oneline_data_length,int rsize);
//unsigned char srecord_change_binary(char* ascdata);
unsigned char srecord_change_binary(char* ascdata);
header_output(char* srecord0_text, FILE* wfile);


//オプションの解析
int opts_analisys(int argc, char* argv[], opts_t* opts) {


    int err = 0;
    int cnt;
    FILE* file;

    for (cnt = 1; cnt < argc; cnt++) { //引数の数ループ
        if (*argv[cnt] == '/') {   //引数の最初の文字が/なら

            switch (*(argv[cnt] + 1)) {
            case 'a':
            case 'A':

                if (*(argv[cnt] + 2) == '=') {
                    opts->loadaddress = argv[cnt] + 3;
                }
                else {
                    opts->loadaddress = argv[cnt] + 2;
                }
                break;

            case'r':
            case'R':

                opts->write_flag = 1;
                break;

            case 's':
            case 'S':
                if (*(argv[cnt] + 2) == '=') {                         //オプションに= があった場合

                    opts->stype = argv[cnt] + 3;
                }
                else {
                    opts->stype = argv[cnt] + 2;
                }
                break;

            case 'd':
            case 'D':
                if (*(argv[cnt] + 2) == '=') {
                    opts->oneline_data_length = argv[cnt] + 3;
                }
                else {

                    opts->oneline_data_length = argv[cnt] + 2;
                }
                break;

            case 't':
            case'T':

                if (*(argv[cnt] + 2) == '=') {
                    opts->srecord0_text = argv[cnt] + 3;
                }
                else {
                    opts->srecord0_text = argv[cnt] + 2;
                }
                break;

            case 'z':
            case 'Z':

                //未実装
                break;

            case'?':
                opts->help_flag = 1;

                break;

            default:    //オプションが無いとき、エラー

                err |= OPT_ERR;
                break;
            }
            continue;
        }

        if (opts->infilename == NULL) {

            opts->infilename = argv[cnt];      //引数の一つ目のファイル名はインプットファイル
        }
        else if (opts->outfilename == NULL) {
            opts->outfilename = argv[cnt];  //引数の二つ目のファイル名はアウトプットファイル
        }
        else {

            err |= FILE_SPECIFIED_ERR;   //ファイル指定エラーのビットを立てる
        }
    }
    return err;
}
int main(int argc, char* argv[]) {

    opts_t opts;
    char read_oneline_data_length[BUFFER];
    int  result = 0;
    int rsize;  

    FILE* wfile;
    FILE* file;

    //構造体の初期化
    opts.infilename = NULL;
    opts.outfilename = NULL;
    //opts.input_flag = stdin;
    //opts.output_flag = stdout;
    opts.help_flag = 0;
    opts.loadaddress = 0000;     //ロードアドレス
    opts.stype = 1;            //Sレコードのタイプ
    opts.oneline_data_length = 32;  //一行のデータの長さ
    opts.srecord0_text ;      //S0に入れるテキスト



    result = opts_analisys(argc, argv, &opts);  //オプションの解析

    if ((result != 0) || (opts.help_flag)) {
        if (result & FILE_SPECIFIED_ERR) {
            fprintf(stderr, "ファイル指定が3つ以上あります\n");
        }
        if (result & FILE_OPEN_ERR) {
            fprintf(stderr, "ファイルが存在しません\n");
        }
        if (result & OPT_ERR) {

            fprintf(stderr, "オプションの指定が間違っています\n");
        }
        if (opts.help_flag) {

            fprintf(stderr, "Syntax:   bin2srec[<opts>][<inpath>][<outpath>][<opts>] \n");
            fprintf(stderr, "Function: convert file to S record format\n");
            fprintf(stderr, "Options :\n\n");
            fprintf(stderr, " /a[=]<hex>     ロードアドレスの指定(省略の場合は0000\n");
            fprintf(stderr, "  /r             出力ファイルが存在するとき、強制的に上書きをする。 \n");
            fprintf(stderr, "  /s[=]<n>       Sレコードタイプの指定(デフォルトは= 1) \n");
            fprintf(stderr, " /d[=]<n>       1行のデータ長(デフォルトは= 32) \n");
            fprintf(stderr, "/ t[=]<text>    S0レコードに入れるテキスト文字\n");
            fprintf(stderr, "/z[[=]<file>]  コマンドライン引数(パラメータ)をファイルから読み込む(デフォルト= stdin)\n");
            fprintf(stderr, "/?使い方の表示");

        }
        return;
    }

    if (opts.outfilename != NULL) {                                                                   //コマンドラインからファイルの入力があれば

        if ((file = fopen(opts.outfilename, "rb")) != NULL) {                               //指定した出力ファイルがあれば                                

            fclose(file);
            if (opts.write_flag == 0) {                                                                    //  オプション r が指定されてなければ 
                fprintf(stderr, "ファイルが既に存在しています。");
                return 0;
            }
        }

        if ((wfile = fopen(opts.outfilename, "w")) == NULL) {

            fprintf(stderr, "ファイルが開けませんでした");
            return 0;
        }
    }
    else {
        wfile = stdout;
    }

    if (opts.infilename != NULL) {      //コマンドラインからファイルの入力があれば

        if ((file = fopen(opts.infilename, "r")) == NULL) {       //ファイルがなければ

            fprintf(stderr, "ファイルが開けませんでした");
            return 0;
        }
    }
    else {
        file = stdin;
    }

    while(rsize = fread(read_oneline_data_length,1, opts.oneline_data_length,file) ){
    //while (fgets(read_oneline_data_length, opts.oneline_data_length, file) != NULL) {

        analysis_binary_change_srecord(read_oneline_data_length, wfile, opts.loadaddress, opts.stype, opts.oneline_data_length,rsize);

        if (rsize == 0) {
            break;
        }
    }

    if (feof(file) != 0) {
        fprintf(stderr, "ファイルが終端まで出力されていません");
    }



    if (opts.infilename != NULL) {
        fclose(file);    //ファイルが開かれたらクローズ
    }
    if (opts.outfilename != NULL) {
        fclose(wfile);
    }
}

//バイナリからSレコード
void analysis_binary_change_srecord(char read_oneline_data_length[], FILE* wfile, int loadaddress, int stype, int oneline_data_length,int rsize) {

    int cnt = 0;
    int   recsize;   //レコード長
    int addsize = 0;  //アドレスの長さ
    int datasize; //データの長さ
    unsigned char checksum = 0;
    static int row = 1;
    unsigned char hex_data;
    unsigned char hex_recsize;
    static int address;
    unsigned char hex_text_data_sum = 0;

    char a;
    char  b;
    char  hex_rec_h;
    char  hex_rec_l;
    char hex_check_sum_h;
    char hex_check_sum_l;




    if (row == 1) {                                             //初回だけロードアドレス
        address = loadaddress;
    }

    if (stype < STYPE_MAX) {

        switch (stype) {

        case 1:
        case 9:
            addsize = ADDRESSBYTE2;
            break;
        case 2:
        case 8:
            addsize = ADDRESSBYTE3;
            break;
        case 3:
        case 7:
            addsize = ADDRESSBYTE4;
            break;
        default:

            break;

        }

        recsize = addsize + oneline_data_length + 1; //レコード長は取得


        //fputs("S", wfile);
        //fputc(stype, wfile);
        //fputc("%02x", recsize,wfile);
        //fputs("%02x0000", wfile);

        printf("S");
        printf("%d", stype);
        printf("%02x", recsize);
        printf("%04x", address);

        for (int i = 0; i < rsize; i++) {


            a = (read_oneline_data_length[i] >> 4) & 0xf;   //上位ビット
            b = (read_oneline_data_length[i] & 0xf);           //下位ビット

            hex_text_data_sum += (a  + b);      //データの合計


            printf("%x", a);                    
            printf("%x", b);
        }

        hex_rec_h = (recsize >> 4) & 0xf;         // レコードサイズの上位ビット
        hex_rec_l = recsize & 0xf;                    //レコードサイズの下位ビット

        checksum = address + hex_text_data_sum + hex_rec_h + hex_rec_l;    //チェックサムの計算

        //hex_check_sum_h = (checksum >> 4) & 0xf;     //チェックサムの上位ビット
        //hex_check_sum_l = checksum & 0xf;                //チェックサムの下位ビット

        //printf("%x", hex_check_sum_h);
    //    printf("%x", hex_check_sum_l);
        printf("%x",checksum);
        //checksum += checksum;                                                       //チェックサムにチェックサムを足す
        printf("\n");
        /*if (checksum != 0xff) {    
            fprintf(stderr, "%d行目:  チェックサムで誤りが検出されました\n", row);
        }
        */
        }
    else {
        fprintf(stderr, "stypeの指定は3までです");
    }
    address += rsize;   //アドレスを一行のデータ長だけ足す
    row++;

}

/*unsigned char srecord_change_binary(char ascdata) {

    unsigned char hex_H;
    unsigned char hex_L;
    unsigned char hex_HL;

      hex_H = (ascdata >> 4) & 0xf;   //上位ビット
      hex_L = (ascdata & 0xf);

      hex_HL = hex_H | hex_L;

      return hex_HL;
}
*/

データは出力されているのですが、チェックサムで引っかかります。

(S)(stype)(レコード長)(アドレス)(データ)(チェックサム)     表示

recsize = addsize + oneline_data_length + 1; //レコード長は取得  

checksum = address + hex_text_data_sum + hex_rec_h + hex_rec_l;    //チェックサムの計算

checksum +=checksum;        //チェックサムにチェックサムを足す

チェックサムは、レコード長からチェックサムまで足して、結果が0xFFになればOK (16進数変換した値は、すべて足し算をする。)

アドバイス頂けると助かります。

-----追記3-----

checksum = address + hex_text_data_sum + hex_rec_h + hex_rec_l;    //チェックサムの計算

チェックサムの計算が正しく行えません。

例 一行目チェックサム(現在)   8f
正しい計算                    D6

どこが間違ってるのかあまり理解できなかったのでアドバイス頂けると助かります。

--追記4--

コマンドラインから渡されたテキストを受け取り
構造体で定義した  char srecord0_text[];     //S0に入れるテキスト

をmain関数で  opts.srecord0_text ;      //S0に入れるテキスト
実体化して

            case 't':
            case'T':

                if (*(argv[cnt] + 2) == '=') {
                    opts->srecord0_text = argv[cnt] + 3;
                }
                else {
                    opts->srecord0_text = argv[cnt] + 2;
                }
                break;

オプションの解析で オプションがt , T だったら
テキストを  opts->srecord0_text  に格納したいのですが

E0137    式は変更可能な左辺値である必要があります    bin_change_srecord        

上記のエラーが出てしまいます。

解決出来なかったので、アドバイスお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+4

main()中
if ((file = fopen(opts.infilename, "r")) != NULL) {    //ファイルがあれば
他の質問と同様、ここもバイナリファイルは"rb"で開きましょう。

同じくmain()中
while (fgets(readline, ROWREADMAX, file) != NULL) {
バイナリデータには行の概念がないというか改行コードも普通にデータの一つなので、改行コードを単位としてデータを切り出すfget()では適切な読み出しが出来ません。fread()あたりを使って、oneline_data_length バイトずつデータを読み出すことになるかと思います。。readlineという変数名も不適切ですね。

analysis_binary_change_srecord(char readline[], FILE* wfile, int loadaddress, int stype, int oneline_data_length) {
戻り値がないのなら、void を指定しましょう。

analysis_binary_change_srecord()中
for (int i = 0; i < oneline_data_length; i++) {
バイナリファイルのサイズは必ずoneline_data_lengthで割り切れるのでしょうか。そうでない可能性があるのなら、先述のfread()の戻り値等を使って適切な処理をする必要があると思います。

チェックサムの考え方も計算式も目茶苦茶です。
バイナリS-recordにエンコードするときには元データから計算したチェックサムを付加するだけ。
そのデータが様々な経路を通った後、元のバイナリにデコードする時に再計算したチェックサムと付加しておいたチェックサムとが適切な関係であればデータ化けはなさそうだ、という判断の材料にするものです(チェックサムはあまり強力な検出手段ではありませんが、それは今回は関係ない話)。
つまり、バイナリ->S-recordの変換時にはチェックサムの検査は行いません。

その他、きちんと見ていませんが、書き出されるaddressの値も適切でない気がします。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/28 10:49

    丁寧に回答ありがとうがざいます。
    勉強になります。 ありがとうございます。

    キャンセル

0

整数→16進数文字列だったら

char buf[10];
sprintf(buf, "%x", 256);

こんな感じでいいんじゃないでしょうか。
直接ファイルに書き出す場合は

fprintf(fp, "%x", 256);

のように書いてもいいです。
%dで10進数、%xで16進数で出力できます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

strtol()の第1引数は ポインタ じゃないですか?
recsize って、int ですよね?

strtol() の仕様を確認して下さい。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

const char htohex[]="0123456789ABCDEF";

// バイト>Hex文字列変換
void bytetoa(char* bf,int dat)
{
    bf[0]=htohex[(dat>>4)&0xf];
    bf[1]=htohex[dat&0xf];
    bf[2]='\0';
}

こんなんでどーです?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/27 15:57

    ありがとうございます。
    参考にします。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る