読者から送られてきたプログラム(リスト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 文も、このような使い方なら文句も言われないでしょう。