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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

4832閲覧

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

kokok

総合スコア145

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2019/08/27 00:44

編集2019/08/28 06:26

c

1 2#include <stdio.h> 3#include <stdlib.h> 4#pragma warning(disable: 4996) 5 6#define ROWREADMAX 256 //一行の読み込み最大文字数 7#define BUFFER 1024 8#define ADDRESSBYTE2 2 9#define ADDRESSBYTE3 3 10#define ADDRESSBYTE4 4 11#define FILE_OPEN_ERR 0x01 //ファイルオープンエラー 12#define FILE_SPECIFIED_ERR 0x02 // ファイル指定エラー 13#define OPT_ERR 0x04 //オプションエラー 14#define CHECKSUMBYTE1 1 15#define STYPE_MAX 4 //stypeの指定は4まで 16//オプション 17typedef struct { 18 19 char* infilename; 20 char* outfilename; 21 char input_flag; 22 char output_flag; 23 char help_flag; 24 char write_flag; 25 26 int loadaddress; //ロードアドレス 27 int stype; //Sレコードのタイプ 28 int oneline_data_length; //一行のデータの長さ 29 char srecord0_text[]; //S0に入れるテキスト 30} opts_t; 31 32//プロトタイプ宣言 33void analysis_binary_change_srecord(char read_oneline_data_length[], FILE* wfile, int loadaddress, int stype, int oneline_data_length,int rsize); 34//unsigned char srecord_change_binary(char* ascdata); 35unsigned char srecord_change_binary(char* ascdata); 36header_output(char* srecord0_text, FILE* wfile); 37 38 39//オプションの解析 40int opts_analisys(int argc, char* argv[], opts_t* opts) { 41 42 43 int err = 0; 44 int cnt; 45 FILE* file; 46 47 for (cnt = 1; cnt < argc; cnt++) { //引数の数ループ 48 if (*argv[cnt] == '/') { //引数の最初の文字が/なら 49 50 switch (*(argv[cnt] + 1)) { 51 case 'a': 52 case 'A': 53 54 if (*(argv[cnt] + 2) == '=') { 55 opts->loadaddress = argv[cnt] + 3; 56 } 57 else { 58 opts->loadaddress = argv[cnt] + 2; 59 } 60 break; 61 62 case'r': 63 case'R': 64 65 opts->write_flag = 1; 66 break; 67 68 case 's': 69 case 'S': 70 if (*(argv[cnt] + 2) == '=') { //オプションに= があった場合 71 72 opts->stype = argv[cnt] + 3; 73 } 74 else { 75 opts->stype = argv[cnt] + 2; 76 } 77 break; 78 79 case 'd': 80 case 'D': 81 if (*(argv[cnt] + 2) == '=') { 82 opts->oneline_data_length = argv[cnt] + 3; 83 } 84 else { 85 86 opts->oneline_data_length = argv[cnt] + 2; 87 } 88 break; 89 90 case 't': 91 case'T': 92 93 if (*(argv[cnt] + 2) == '=') { 94 opts->srecord0_text = argv[cnt] + 3; 95 } 96 else { 97 opts->srecord0_text = argv[cnt] + 2; 98 } 99 break; 100 101 case 'z': 102 case 'Z': 103 104 //未実装 105 break; 106 107 case'?': 108 opts->help_flag = 1; 109 110 break; 111 112 default: //オプションが無いとき、エラー 113 114 err |= OPT_ERR; 115 break; 116 } 117 continue; 118 } 119 120 if (opts->infilename == NULL) { 121 122 opts->infilename = argv[cnt]; //引数の一つ目のファイル名はインプットファイル 123 } 124 else if (opts->outfilename == NULL) { 125 opts->outfilename = argv[cnt]; //引数の二つ目のファイル名はアウトプットファイル 126 } 127 else { 128 129 err |= FILE_SPECIFIED_ERR; //ファイル指定エラーのビットを立てる 130 } 131 } 132 return err; 133} 134int main(int argc, char* argv[]) { 135 136 opts_t opts; 137 char read_oneline_data_length[BUFFER]; 138 int result = 0; 139 int rsize; 140 141 FILE* wfile; 142 FILE* file; 143 144 //構造体の初期化 145 opts.infilename = NULL; 146 opts.outfilename = NULL; 147 //opts.input_flag = stdin; 148 //opts.output_flag = stdout; 149 opts.help_flag = 0; 150 opts.loadaddress = 0000; //ロードアドレス 151 opts.stype = 1; //Sレコードのタイプ 152 opts.oneline_data_length = 32; //一行のデータの長さ 153 opts.srecord0_text ; //S0に入れるテキスト 154 155 156 157 result = opts_analisys(argc, argv, &opts); //オプションの解析 158 159 if ((result != 0) || (opts.help_flag)) { 160 if (result & FILE_SPECIFIED_ERR) { 161 fprintf(stderr, "ファイル指定が3つ以上あります\n"); 162 } 163 if (result & FILE_OPEN_ERR) { 164 fprintf(stderr, "ファイルが存在しません\n"); 165 } 166 if (result & OPT_ERR) { 167 168 fprintf(stderr, "オプションの指定が間違っています\n"); 169 } 170 if (opts.help_flag) { 171 172 fprintf(stderr, "Syntax: bin2srec[<opts>][<inpath>][<outpath>][<opts>] \n"); 173 fprintf(stderr, "Function: convert file to S record format\n"); 174 fprintf(stderr, "Options :\n\n"); 175 fprintf(stderr, " /a[=]<hex> ロードアドレスの指定(省略の場合は0000\n"); 176 fprintf(stderr, " /r 出力ファイルが存在するとき、強制的に上書きをする。 \n"); 177 fprintf(stderr, " /s[=]<n> Sレコードタイプの指定(デフォルトは= 1) \n"); 178 fprintf(stderr, " /d[=]<n> 1行のデータ長(デフォルトは= 32) \n"); 179 fprintf(stderr, "/ t[=]<text> S0レコードに入れるテキスト文字\n"); 180 fprintf(stderr, "/z[[=]<file>] コマンドライン引数(パラメータ)をファイルから読み込む(デフォルト= stdin)\n"); 181 fprintf(stderr, "/?使い方の表示"); 182 183 } 184 return; 185 } 186 187 if (opts.outfilename != NULL) { //コマンドラインからファイルの入力があれば 188 189 if ((file = fopen(opts.outfilename, "rb")) != NULL) { //指定した出力ファイルがあれば 190 191 fclose(file); 192 if (opts.write_flag == 0) { // オプション r が指定されてなければ  193 fprintf(stderr, "ファイルが既に存在しています。"); 194 return 0; 195 } 196 } 197 198 if ((wfile = fopen(opts.outfilename, "w")) == NULL) { 199 200 fprintf(stderr, "ファイルが開けませんでした"); 201 return 0; 202 } 203 } 204 else { 205 wfile = stdout; 206 } 207 208 if (opts.infilename != NULL) { //コマンドラインからファイルの入力があれば 209 210 if ((file = fopen(opts.infilename, "r")) == NULL) { //ファイルがなければ 211 212 fprintf(stderr, "ファイルが開けませんでした"); 213 return 0; 214 } 215 } 216 else { 217 file = stdin; 218 } 219 220 while(rsize = fread(read_oneline_data_length,1, opts.oneline_data_length,file) ){ 221 //while (fgets(read_oneline_data_length, opts.oneline_data_length, file) != NULL) { 222 223 analysis_binary_change_srecord(read_oneline_data_length, wfile, opts.loadaddress, opts.stype, opts.oneline_data_length,rsize); 224 225 if (rsize == 0) { 226 break; 227 } 228 } 229 230 if (feof(file) != 0) { 231 fprintf(stderr, "ファイルが終端まで出力されていません"); 232 } 233 234 235 236 if (opts.infilename != NULL) { 237 fclose(file); //ファイルが開かれたらクローズ 238 } 239 if (opts.outfilename != NULL) { 240 fclose(wfile); 241 } 242} 243 244//バイナリからSレコード 245void analysis_binary_change_srecord(char read_oneline_data_length[], FILE* wfile, int loadaddress, int stype, int oneline_data_length,int rsize) { 246 247 int cnt = 0; 248 int recsize; //レコード長 249 int addsize = 0; //アドレスの長さ 250 int datasize; //データの長さ 251 unsigned char checksum = 0; 252 static int row = 1; 253 unsigned char hex_data; 254 unsigned char hex_recsize; 255 static int address; 256 unsigned char hex_text_data_sum = 0; 257 258 char a; 259 char b; 260 char hex_rec_h; 261 char hex_rec_l; 262 char hex_check_sum_h; 263 char hex_check_sum_l; 264 265 266 267 268 if (row == 1) { //初回だけロードアドレス 269 address = loadaddress; 270 } 271 272 if (stype < STYPE_MAX) { 273 274 switch (stype) { 275 276 case 1: 277 case 9: 278 addsize = ADDRESSBYTE2; 279 break; 280 case 2: 281 case 8: 282 addsize = ADDRESSBYTE3; 283 break; 284 case 3: 285 case 7: 286 addsize = ADDRESSBYTE4; 287 break; 288 default: 289 290 break; 291 292 } 293 294 recsize = addsize + oneline_data_length + 1; //レコード長は取得 295 296 297 //fputs("S", wfile); 298 //fputc(stype, wfile); 299 //fputc("%02x", recsize,wfile); 300 //fputs("%02x0000", wfile); 301 302 printf("S"); 303 printf("%d", stype); 304 printf("%02x", recsize); 305 printf("%04x", address); 306 307 for (int i = 0; i < rsize; i++) { 308 309 310 a = (read_oneline_data_length[i] >> 4) & 0xf; //上位ビット 311 b = (read_oneline_data_length[i] & 0xf); //下位ビット 312 313 hex_text_data_sum += (a + b); //データの合計 314 315 316 printf("%x", a); 317 printf("%x", b); 318 } 319 320 hex_rec_h = (recsize >> 4) & 0xf; // レコードサイズの上位ビット 321 hex_rec_l = recsize & 0xf; //レコードサイズの下位ビット 322 323 checksum = address + hex_text_data_sum + hex_rec_h + hex_rec_l; //チェックサムの計算 324 325 //hex_check_sum_h = (checksum >> 4) & 0xf; //チェックサムの上位ビット 326 //hex_check_sum_l = checksum & 0xf; //チェックサムの下位ビット 327 328 //printf("%x", hex_check_sum_h); 329 // printf("%x", hex_check_sum_l); 330 printf("%x",checksum); 331 //checksum += checksum; //チェックサムにチェックサムを足す 332 printf("\n"); 333 /*if (checksum != 0xff) { 334 fprintf(stderr, "%d行目: チェックサムで誤りが検出されました\n", row); 335 } 336 */ 337 } 338 else { 339 fprintf(stderr, "stypeの指定は3までです"); 340 } 341 address += rsize; //アドレスを一行のデータ長だけ足す 342 row++; 343 344} 345 346/*unsigned char srecord_change_binary(char ascdata) { 347 348 unsigned char hex_H; 349 unsigned char hex_L; 350 unsigned char hex_HL; 351 352 hex_H = (ascdata >> 4) & 0xf; //上位ビット 353 hex_L = (ascdata & 0xf); 354 355 hex_HL = hex_H | hex_L; 356 357 return hex_HL; 358} 359*/ 360

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

(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に入れるテキスト
実体化して

c

1 2 case 't': 3 case'T': 4 5 if (*(argv[cnt] + 2) == '=') { 6 opts->srecord0_text = argv[cnt] + 3; 7 } 8 else { 9 opts->srecord0_text = argv[cnt] + 2; 10 } 11 break;

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

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

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

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/27 08:41

編集2019/08/27 08:56
thkana

総合スコア7610

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kokok

2019/08/28 01:49

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

0

C

1const char htohex[]="0123456789ABCDEF"; 2 3// バイト>Hex文字列変換 4void bytetoa(char* bf,int dat) 5{ 6 bf[0]=htohex[(dat>>4)&0xf]; 7 bf[1]=htohex[dat&0xf]; 8 bf[2]='\0'; 9}

こんなんでどーです?

投稿2019/08/27 05:01

編集2019/08/27 05:02
y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kokok

2019/08/27 06:57

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

0

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

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

投稿2019/08/27 02:04

nob.

総合スコア711

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

char buf[10];

sprintf(buf, "%x", 256);

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

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

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

投稿2019/08/27 00:51

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問