読者から送られてきたプログラム(リスト1−1)には、いっぱい問題点が含まれていて、非常 に参考になります。
オリジナルを、私のプログラムの書き方に準じて修正したものがリスト1−5です。コンパイル はしていますが、ハードがらみなので実行確認はしていません。
リスト1−5 修正版 |
1 /********************************************************************************/ 2 /* */ 3 /* "MLINK3.C" */ 4 /* */ 5 /* USE MELSEC <-> PC9801 LINK Experiment */ 6 /* USING TEX_0,1,2 (one SEND and CATCH) */ 7 /* SPECIAL EDITION */ 8 /* (MELSEC DEBUG SPECIAL) */ 9 /* */ 10 /* BY */ 11 /* */ 12 /* OPTION USING MRS .obj (my rs232-c source) */ 13 /* MIT1.obj (my tool-1 source) */ 14 /* MEL.obj (MELSEC UTILITY FUNCTION source) */ 15 /* make MLINK3.MAK */ 16 /* */ 17 /* 変更履歴 1990. 4.18 MADE(DD1.C) */ 18 /* 5.15 tex_* 対応 */ 19 /* 1991. 2.20 fuji より美しく */ 20 /* */ 21 /********************************************************************************/ 22 23 #include <dos.h> 24 #include <stdio.h> 25 #include <memory.h> 26 #include <time.h> 27 #include <mrs.h> 28 #include <mit1.h> 29 #include <mel.h> 30 #include <process.h> 31 #include <string.h> 32 33 #define TRUE (1) 34 #define FALSE (0) 35 36 #define STX 0x02 /* STX */ 37 #define ETX 0x03 /* ETX */ 38 #define ENQ 0x05 /* ENQ */ 39 #define ACK 0x06 /* ACK */ 40 #define NAK 0x15 /* NAK */ 41 #define ESC 0x1b /* ESC */ 42 43 #define BUFFER_SIZE 250 44 45 #define BYTE_WRITE_STYLE 1 46 #define WORD_WRITE_STYLE 2 47 #define STATUS_READ_STYLE 3 48 #define BYTE_READ_STYLE 4 49 #define WORD_READ_STYLE 5 50 #define BATCH_WRITE_STYLE 6 51 52 #define WAIT 1 /* 計算機側 待ち時間 */ 53 #define START_RENBAN 0 /* 連番 初期値 */ 54 #define FILENAME "meldata.txt" /* データ(text2)ファイル*/ 55 56 #define TEXT_1_LEN 17 /* text1 長さ */ 57 #define TEXT_2_LEN 13 /* text2 長さ */ 58 59 static char dwfname[15]; /* データ ファイル */ 60 static char dwtext2[12*4+1]; /* データ ファイル(イレコ) */ 61 62 static int is_renzoku = FALSE; /* 連続送り */ 63 static int irenban = START_RENBAN; /* 伝文 連番 */ 64 65 /*------------------------ static functions ------------------------*/ 66 67 static int call_melsec(); 68 static int melsec_data_write(); 69 static int melsec_data_read(); 70 static void next_cursor_pos(); 71 static void status_mel(); 72 static void input_batch(); 73 74 /*------------------------------------------------------------------------------*/ 75 /* MELSECの呼び出し */ 76 /* */ 77 /* 戻り値: 1=ACK, 2=NAK, 3=ERR */ 78 /*------------------------------------------------------------------------------*/ 79 static int call_melsec( style, message ) 80 int style; /* 転送形式 */ 81 char *message; /* 転送文字列 */ 82 { 83 char send_d[BUFFER_SIZE]; /* 送信メッセージ本体 */ 84 char *type_code; /* 送信タイプ文字列 */ 85 char xsum[3]; /* サムチェック */ 86 int i; 87 88 cls_t(3); 89 rs_melsec(); 90 91 if(is_renzoku == 0){ 92 printf("\n\n ESC キーで送信開始します \n"); 93 while( keyin() != ESC ) 94 ; 95 } else { 96 printf("\n\n 送信開始します \n"); 97 for( i=0 ; i < 500 ; ++i ) 98 ; 99 } 100 101 switch(style){ 102 case BYTE_WRITE_STYLE: 103 type_code = "00FFBW"; break; 104 case WORD_WRITE_STYLE: 105 type_code = "00FFWW"; break; 106 case BYTE_READ_STYLE: 107 type_code = "00FFBR"; break; 108 case WORD_READ_STYLE: 109 type_code = "00FFWR"; break; 110 } 111 112 sprintf( send_d, "%s%s", type_code, message ); 113 check_sum( send_d, xsum ); 114 strcat( send_d, xsum ); 115 116 rs_out1( ENQ ); 117 for( i=0 ; send_d[i] ; ++i ) 118 rs_out1(send_d[i]); 119 printf( "\n 送信完了、文字数 = %d\n", i ); 120 121 wait_t(WAIT); 122 123 switch( style ) { 124 case BYTE_WRITE_STYLE: 125 case WORD_WRITE_STYLE: 126 return melsec_data_write( style ); 127 case BYTE_READ_STYLE: 128 case WORD_READ_STYLE: 129 return melsec_data_read( style ); 130 } 131 } 132 133 /*------------------------------------------------------------------------------*/ 134 /* MELSECへのデータ書き込み */ 135 /*------------------------------------------------------------------------------*/ 136 static int melsec_data_write( style ) 137 int style; /* BYTE_READ_STYLE, WORD_READ_STYLE */ 138 { 139 int i; 140 int num; /* 入力文字数 */ 141 char r_code; /* リターン コード */ 142 char r_type[BUFFER_SIZE]; /* リターン コード 内容 */ 143 int result; /* 結果 (1=ACK,2=NAK,3=ERR)*/ 144 145 num = rs_inn( 1, &r_code ); 146 147 switch( r_code ) { 148 case ACK: 149 printf("\n ACK(正常返信)を受け取りました。"); 150 num = rs_inn(4,r_type); 151 result = 1; 152 break; 153 case NAK: 154 printf("\n NAK(異常返信)を受け取りました。"); 155 num = rs_inn(6,r_type); 156 result = 2; 157 break; 158 default: 159 printf("\n 変なコードを受け取りました。コード= %c",r_code); 160 result = 3; 161 goto ret; /********** エラー リターン *********/ 162 } 163 164 printf(" \nリターンコード= %c",r_code); 165 for( i=0; i < num; i++ ) { 166 printf(" \n %d 番目のリターンコード= %c",i,r_type[i]); 167 } 168 ret: 169 (result == 1) ? wait_t(1) : wait_key(1); 170 rs_close(); 171 return result; 172 } 173 174 /*------------------------------------------------------------------------------*/ 175 /* MELSECからデータ読み込み */ 176 /*------------------------------------------------------------------------------*/ 177 static int melsec_data_read( style ) 178 int style; /* BYTE_WRITE_STYLE, WORD_WRITE_STYLE */ 179 { 180 char r_code; /* リターン コード */ 181 char r_type[BUFFER_SIZE]; /* リターン コード 内容 */ 182 int result = 1; /* 結果 (1=ACK,2=NAK,3=ERR) */ 183 char xsum[3]; /* サムチェック */ 184 char r_sum[3]; /* 返信 リターン サムチェック */ 185 int num; /* 入力文字数 */ 186 int ikk; 187 int i; 188 189 if( (r_code = rs_in1()) != STX ) { 190 printf("\n 変なコードを受け取りました。コード= %c",r_code); 191 result = 3; 192 goto ret; /********** エラー リターン *********/ 193 } 194 printf("\n 正常返信を受け取りました "); 195 196 num = rs_insd( ETX, r_type ); 197 check_sum( r_type, xsum ); 198 r_sum[0] = rs_in1(); 199 r_sum[1] = rs_in1(); 200 r_sum[2] = 0x00; 201 202 if( strcmpi( xsum, r_sum ) != 0 ) { 203 printf("\n チェックサムが違います \n"); 204 result = 3; 205 goto ret; /********** エラー リターン *********/ 206 } 207 208 printf(" \n リターンコード= %c",r_code); 209 printf(" \n 局番 = %c%c",r_type[0],r_type[1]); 210 printf(" \n PC番号 = %c%c\n\n",r_type[2],r_type[3]); 211 i = 4; 212 next_cursor_pos( TRUE ); 213 214 switch( style ) { 215 case BYTE_READ_STYLE: 216 while(1){ 217 if( r_type[i+1] == ETX ){ 218 printf(" \n %d 番目リターン= %c",i,r_type[i]); 219 break; 220 } 221 printf(" \n %d 番目リターン= %c | %d 番目リターン= %c" 222 ,i,r_type[i],i+1,r_type[i+1]); 223 i += 2; 224 if( r_type[i] == ETX ) break; 225 next_cursor_pos( FALSE ); 226 } 227 break; 228 case WORD_READ_STYLE: 229 for( ikk=1 ; ; ikk++ ){ 230 printf("\n リターン %d.....%c%c%c%c", 231 ikk,r_type[i],r_type[i+1],r_type[i+2],r_type[i+3]); 232 i += 4; 233 if(r_type[i] == ETX ) break; 234 next_cursor_pos( FALSE ); 235 } 236 } 237 ret: 238 if( result == 1 ) { 239 printf("\n ACKコードをおくります"); 240 send_return( 1 ); /* return ACK */ 241 } else { 242 printf("\n NAKコードをおくります"); 243 send_return( 0 ); /* return NAK */ 244 } 245 wait_key(1); 246 rs_close(); 247 return result; 248 } 249 250 /*------------------------------------------------------------------------------*/ 251 /* カーソル位置計算 */ 252 /*------------------------------------------------------------------------------*/ 253 static void next_cursor_pos( is_init ) 254 int is_init; 255 { 256 static int y_len; 257 258 if( is_init ) { 259 wait_t(1); 260 y_len = 0; 261 cls_t(3); 262 locate(0,0); 263 } else { 264 if( ++y_len >= 18 ) { 265 y_len = 0; 266 wait_key(1); 267 cls_t(3); 268 locate(0,0); 269 } 270 } 271 } 272 273 /*------------------------------------------------------------------------------*/ 274 /* MELの状態表示 */ 275 /*------------------------------------------------------------------------------*/ 276 static void status_mel() 277 { 278 int status; 279 int i; 280 int bit[8]; 281 282 rs_melsec(); 283 wait_t(WAIT); 284 285 status = rs_status(); 286 for( i=0 ; i<8 ; i++ ) 287 bit[i] = bit_out( status, i ); 288 289 locate(13,15); 290 printf("\n 送信レディー = %x 受信レディー = %x ", 291 bit[0],bit[1]); 292 printf("\n 送信データ = %x パリティエラー = %x ", 293 bit[2],bit[3]); 294 printf("\n オーバーランエラー = %x フレーミングエラー = %x ", 295 bit[4],bit[5]); 296 printf("\n ブレーク信号 = %x データセットレディー= %x ", 297 bit[6],bit[7]); 298 299 wait_key(1); 300 } 301 302 /*------------------------------------------------------------------------------*/ 303 /* メニュー表示 */ 304 /*------------------------------------------------------------------------------*/ 305 static void display_menu() 306 { 307 struct menu{ 308 int x, y; 309 char *message; 310 }; 311 const struct menu menu_table[] = { 312 { 19, 2, "MELSEC 転送実験プログラム" }, 313 { 11, 4, "1. ビット単位書き込み" }, 314 { 11, 6, "2. ワード単位書き込み(tex2)" }, 315 { 11, 8, "3. 通信データステータス読みだし" }, 316 { 45, 4, "4. ビット単位読み込み" }, 317 { 45, 6, "5. ワード単位読み込み(tex1)" }, 318 { 45, 8, "6. バッチ実行" }, 319 { 37,11, "選択して下さい (0 - 6 、0=終了)" }, 320 { 0, 0, NULL } 321 }; 322 323 const struct menu *menu_ptr; 324 325 cls_t(3); 326 327 for( menu_ptr=menu_table; menu_ptr->message ; ++menu_ptr ) { 328 locate( menu_ptr->x, menu_ptr->y ); 329 printf( "%s", menu_ptr->message ); 330 } 331 } 332 333 /*------------------------------------------------------------------------------*/ 334 335 #define MESX 12 336 #define MESY 18 337 #define MESY0 15 338 #define MESX1 40 339 #define MESY1 20 340 341 /*------------------------------------------------------------------------------*/ 342 /* パラメータの会話入力 */ 343 /*------------------------------------------------------------------------------*/ 344 static void input_para( style, code1 ) 345 int style; 346 char *code1; 347 { 348 int yes_no; /* y(1) n(0) */ 349 int count; 350 int i; 351 char first_dev[10]; 352 char dd[BUFFER_SIZE]; 353 char dw; 354 355 if( style == STATUS_READ_STYLE ){ 356 status_mel(); 357 return; 358 } 359 360 361 do { 362 locate(MESX,MESY0); printf("コマンド="); 363 locate(MESX+12,MESY0); 364 switch( style ) { 365 case BYTE_WRITE_STYLE: printf("BW"); break; 366 case WORD_WRITE_STYLE: printf("WW"); break; 367 case BYTE_READ_STYLE: printf("BR"); break; 368 case WORD_READ_STYLE: printf("WR"); break; 369 } 370 371 while(1){ 372 locate(MESX,MESY); printf("伝文ウエイト= "); 373 locate(MESX+19,MESY); scanf("%c",&dw); 374 if( isxdigit( dw ) ) 375 break; 376 rewind(stdin); 377 } 378 379 while(1){ 380 locate(MESX,MESY+2); printf("先頭デバイス= "); 381 locate(MESX+19,MESY+2); scanf( "%s", first_dev ); 382 if( strlen( first_dev ) == 5 ) 383 break; 384 } 385 386 locate(MESX,MESY+4); printf("デバイス点数= "); 387 locate(MESX+19,MESY+4); 388 switch( style ) { 389 case WORD_WRITE_STYLE: 390 printf( "%d", count=TEXT_2_LEN ); 391 break; 392 case WORD_READ_STYLE: 393 printf( "%d", count=TEXT_1_LEN ); 394 break; 395 default: 396 for( count=0 ; !((count>0) && (count<=255)) ; ) { 397 locate(MESX+19,MESY+4); 398 scanf( "%d", &count ); 399 } 400 } 401 402 rewind(stdin); 403 dd[0]=0; 404 switch( style ) { 405 case BYTE_WRITE_STYLE: 406 for( i=0; i<count; i++ ) { 407 locate(MESX1,MESY1); 408 printf("データ %d = ",i+1); 409 do { 410 locate(MESX1+16,MESY1); 411 scanf("%c",&dd[i]); 412 } while( ! ( dd[i]=='0' || dd[i]=='1' ) ); 413 414 locate(MESX1+16+i,MESY1+2); 415 printf("%c",dd[i]); 416 rewind(stdin); 417 } 418 dd[count]=0; 419 break; 420 case WORD_WRITE_STYLE: 421 sprintf( dd, "%04X%s", irenban, dwtext2 ); 422 locate(MESX1,MESY1+2); printf( "連番 = %X", irenban ); 423 } 424 425 locate(MESX1+5,MESY1+4); printf("よろしいですか(y/n)"); 426 do { 427 locate(MESX1+32,MESY1+4); 428 yes_no = keyyn(1); 429 } while( ! ( yes_no==1 || yes_no == 0 ) ); 430 } while( yes_no == 0 ); 431 432 if( style == WORD_WRITE_STYLE ) 433 irenban++; 434 435 sprintf( code1, "%c%s%02X%s", dw, first_dev, count, dd ); 436 strupr( code1 ); 437 } 438 439 /*------------------------------------------------------------------------------*/ 440 /* バッチ処理 */ 441 /*------------------------------------------------------------------------------*/ 442 static void input_batch() 443 { 444 FILE *fdd; 445 char dwbname[40], dwxy[40], dwsdata[40]; 446 int yes_no; 447 448 for(;;) { 449 locate(MESX,MESY0); printf("バッチファイル = "); 450 locate(MESX+17,MESY0); fscanf(stdin,"%s",dwbname); 451 452 if(dwbname[0] == 'q' || dwbname[0] == 'Q' ) break; 453 454 if((fdd=fopen(dwbname,"r"))==NULL) { 455 locate(MESX,MESY); printf("ファイルが有りません"); 456 rewind(stdin); 457 continue; 458 } 459 460 locate(MESX,MESY0); printf("転送を確認しますか(y/n)"); 461 do { 462 locate(MESX+24,MESY); 463 yes_no = keyyn(1); /* y(1) n(0) */ 464 } while( ! ( yes_no==0 || yes_no==1 ) ); 465 is_renzoku = (yes_no==0); /* 'n' のとき、連続 */ 466 467 locate(MESX,MESY); 468 cls_t(6); 469 470 while( fscanf(fdd,"%s",dwxy ) != EOF ) { 471 if(dwxy[0]==0x40) { 472 strset(dwxy,0x00); 473 continue; 474 } 475 476 dwxy[5]=0x00; 477 sprintf( dwsdata, "0%s01%s", dwxy, &dwxy[6] ); 478 479 locate(MESX,MESY); printf( "send addr. = %s",dwxy ); 480 locate(MESX+22,MESY); printf( "on / off %c", dwxy[6] ); 481 strupr(dwsdata); 482 wait_t(2); 483 484 if( call_melsec( BYTE_WRITE_STYLE, dwsdata ) != 1 ) { 485 fclose( fdd ); 486 return; 487 } 488 } 489 break; 490 } 491 } 492 493 /********************************************************************************/ 494 /* メイン・プログラム */ 495 /********************************************************************************/ 496 void main(int argc,char *argv[]) 497 { 498 int style; 499 int idrnd; 500 FILE *fd; 501 char cc[BUFFER_SIZE]; 502 503 cls_func(1); 504 505 strcpy( dwfname, FILENAME ); 506 if( (fd=fopen( dwfname, "r" )) == NULL ) { 507 cls_t(3); 508 printf("\x1b[>1l"); 509 locate(20,8); printf("TEXT1,2用ファイルが見つかりません"); 510 locate(29,11); printf("終了します\n\n\n\n\n\n\n"); 511 exit(-1); /******** エラー終了 *********/ 512 } 513 514 fscanf(fd,"%d",&idrnd); /* この辺りは理解できない */ 515 idrnd = irenban % idrnd; 516 fd = fd + idrnd; 517 fscanf(fd,"%s",dwtext2); 518 fclose(fd); 519 520 do { 521 display_menu(); 522 do { 523 locate(55,13); 524 style = getchar() - '0'; 525 } while( ! ( (style >= 0) && (style <= 6)) ); 526 527 switch( style ) { 528 case 0: 529 break; 530 case BATCH_WRITE_STYLE: 531 input_batch(); 532 is_renzoku = FALSE; 533 break; 534 default: 535 input_para( style, cc ); 536 if( style != STATUS_READ_STYLE ) 537 call_melsec( style, cc ); 538 } 539 } while( style != 0 ); 540 541 cls_t(3); 542 printf("\x1b[>1l"); 543 locate(29,11); printf("終了します\n\n\n\n\n\n\n"); 544 } 545 546 /********************************************************************************/ 547 /* EOF "MLINK3.C" */ 548 /********************************************************************************/ |
プログラムの書き方には個人差、個性があり、どのような書き方が「正解」とはいえません。こ こに示した修正プログラムは、私なりに、より分かりやすく、かつ元の流れをできるだけ守るよう にしたものです。もし同等のプログラムを私が新規に開発したら、全く異なったものになるでしょ う。
でも、プログラムをどのように書き換えたか2つのリストで比較検討すると、かなり参考になる のではないでしょうか。
関数の頭のコメントの書き方が、説明と違って、
133 /*--------------------------------------------------------------*/ 134 /* MELSECへのデータ書き込み */ 135 /*--------------------------------------------------------------*/のように囲んでいます。static関数は局所的なので、より目立たないコメントということで、私 はこのようにしています。
オリジナルにはgoto文はありませんでしたが、エラー処理にはgoto文で対応してみました。goto 文も、このような使い方なら文句も言われないでしょう。