• ベストアンサー

C#にてCTI。RS232Cの受信と送信について。

C#でCTI機能の実現を目指しております。 プログラムは以下サイトからDLして改造しています。 http://tmp.junkbox.info/e14.html しかし、エラーが頻発し原因不明です。 構成、仕様としては、 アロハPC1という機械から電話番号データを受信しPCに受け渡し。 ・データを受け取る(ここは問題なし) データ形式は STX(02H)、着信日時(月日曜時分9桁)、電話番号(20桁)、ETX(03H) として送られてきます。 例) 1214112050457771111 ・正常データの場合はACK(06H)を返信(これをしない場合1秒後に同データが再送される) ・データ整形 ・データ表示 というような形にしたいのです。 上記サイトのプログラムをアロハPC1に合わせて通信できるようにした状態ですと、例のような生データが問題なく表示されます。 これを以下のようにしてみましたが、エラーが出てしまいます。 private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { // 受信文字列の取得 string receivedData = ""; string moji = ""; string moji2 = ""; try { receivedData = this.serialPort1.ReadExisting(); receivedData = receivedData.Replace(this.serialPort1.NewLine, "\r\n"); string[] week = { "(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)" }; string stx = receivedData.Substring(0, 1); string etx = receivedData.Substring(30, 1); // ACKを返す。 byte[] ack_data = new byte[1]; ack_data[0] = 06; serialPort1.Write(ack_data,0,1); string data_m = receivedData.Substring(1, 2); string data_d = receivedData.Substring(3, 2); string w = receivedData.Substring(5, 1); int w2 = int.Parse(w); string data_w = week[w2]; string data_h = receivedData.Substring(6, 2); string data_i = receivedData.Substring(8, 2); moji2 = receivedData.Substring(10, 20); // スペースを痴漢 moji2 = moji2.Replace(" ", ""); moji = data_m + "月" + data_d + "日" + data_w + data_h + "時" + data_i + "分 "; if (moji2 == "P") { moji = moji + "着信番号非通知\n"; } else if (moji2 == "O") { moji = moji + "着信番号提供地域外\n"; } else if (moji2 == "C") { moji = moji + "公衆電話\n"; } else { moji = moji + moji2 + "\n"; } } catch (Exception ex) { moji = ex.Message; } // richTextBox側のスレッドに AddRecievedDataメソッドのポインタを渡して、 // 受信文字列を追加させる AddRecievedDataDelegate add = new AddRecievedDataDelegate(AddRecievedData); this.richTextBox1.Invoke(add, moji); } 結果: 1221112260457771111 12月21日(月)12時26分 0457771111 1221112 startIndex に文字列の長さより大きい値を指定することはできません。 パラメータ名: startIndex260457771111 startIndex に文字列の長さより大きい値を指定することはできません。 パラメータ名: startIndex Substringを削除すると「startIndex に文字列の長さより大きい値を指定することはできません。」というようなエラーは出てきません。 receivedData = this.serialPort1.ReadExisting(); を文字列を直接代入した場合はエラーは発生しません。 これをどのようにすれば正常に動くのでしょうか。 また、ACKが正常に送信できてないみたいなのも解れば助かります。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

>・データを受け取る(ここは問題なし) 確認も無しに断言してはいけません。 このプログラムの問題点は、受信したデータ(receivedDat)が必ずしも31文字にならないことです。 SerialPortのDataReceived()イベントは、1文字受信するたびに発生します。 従って受信したデータには、ReadExisting()した時点でSerialPortに受信されている分しか入りません。 解決方法を2種類示しますが、動作確認はしていません。 ◎解決方法1 ReadExisting()する前にBytesToReadをチェックして31文字未満ならReadしない。 ◎解決方法2 一度に1文字ずつReadして文字をつないでいく。 このとき、 STXを受信する前は、Readしたデータは捨てる。(受信データは空にする) STXを受信した後は、Readしたデータを受信データに継ぎ足していく。 ETXを受信したら(継ぎ足したデータがETXなら)、受信データ長を確認してACK送信にすすむ。

moon_night
質問者

お礼

仰るとおりでした。 常にデータがすべて来る訳ではないのですね。 こういうプログラムははじめてなのでわからないことだらけです。 解決方法の通り、BytesToReadでチェックしたらうまくいきました。 ありがとうございました。

その他の回答 (1)

  • AKARI0418
  • ベストアンサー率67% (112/166)
回答No.1

string etx = receivedData.Substring(30, 1); この行がいけないのでは?? エラーの原因はSubstringだと思います、Substringの第一パラメータの名称はstartIndexですから。 ACKが送られていないということなので、ACKの送信前のコードに限定できます、そして怪しいのがこの1行となるわけです。 送信データが 1214112050457771111 であれば、30字に満たないので、発生しそうですね。

moon_night
質問者

お礼

回答ありがとうございます。 しかしならが、申し訳ありませんが、送信データは投稿の最、半角スペースデータが削除されてしまったようですが、元の受信データはたしかに STX(02H)、着信日時(月日曜時分9桁)、電話番号(20桁)、ETX(03H) という31文字分受信されています。(電話番号が20文字に足りない場合半角スペース(20H)で埋められる) また、テストしましたが、 string stx = receivedData.Substring(0, 1); のみ残して、他を消した状態でも「startIndex に~」というエラーが発生します。 なぜこのような挙動になるのか不思議です。

関連するQ&A

  • C#でserialPort送信。RS232Cへ。

    前回からの続きです。 http://oshiete1.goo.ne.jp/qa5537662.html データ取得はうまくいきましたが、データを受け取ったというACK(0x06)を送信しようとしていますが、うまく受け取ってくれません。 http://www.robotsfx.com/robot/robohow/RoboHow60/RoboHow60.html というサイトを参考にして、 // ACKを返す。 byte[] ack_data = new byte[1]; ack_data[0] = 06; this.serialPort1.Write(ack_data, 0, 1); というようにやっていますが、通信機器(アロハPC1)が受け取ってくれません。(最初のデータを送信後ACKを受け取らないと1秒後にデータを再送信される=同じデータが二回来る) このような送信でよいのでしょうか?

  • C言語 文字列の比較 compare

    プログラミング初心者です。 60文字以内の文字列を入力して、 大小関係を比較・表示するプログラムなのですが・・ 「AはBより大きい」という結果しか出ません。 どこが間違っているのか、ご指摘お願いしますっ。 #include<stdio.h> int main(void) { char moji1[61]; char moji2[61]; printf("文字列Aを入力===>"); scanf("%60s" ,&moji1); printf("文字列Bを入力===>"); scanf("%60s" ,&moji2); if(moji1-moji2>0){ printf("===AはBより大きい===\n"); } else if(moji1-moji2<0){ printf("===AはBより小さい===\n"); } else if(moji1-moji2==0){ printf("===AとBは等しい===\n"); } return 0; } int compare(char *x, char*y) { while(*x==*y){ if(*x=='\0') return 0; x++; y++; } return (*x-*y); }

  • C言語 strlen 再入力を促す

    文字列の比較で、 文字列の長さが60以上の時、再入力を促します。 while文を使って書いてみたのですが、 文字列Bの入力の前に、もう一度意味もなく 「文字列Aを入力===>」が表示されたり。 文字列Aのほうが小さいのに「Aのほうが大きい」と 表示されるようになったり、変な感じです。 どなたかご指摘・ご指導のほどよろしくお願いします。 int main(void) { char moji1[100]; char moji2[100]; while(strlen(moji1)>60){     printf("文字列Aを入力===>"); scanf("%80s" ,moji1); } while(strlen(moji2)>60){     printf("文字列Bを入力===>"); scanf("%80s" ,moji2);    } if(compare(moji1,moji2)>0){ printf("===AはBより大きい===\n"); } else if(compare(moji1, moji2)<0){ printf("===AはBより小さい===\n"); } else if(compare(moji1, moji2)==0){ printf("===AとBは等しい===\n"); } return 0; } int compare(char *x, char*y) { while(*x==*y && *x!=0){ x++; y++; } return (*x-*y); }

  • C言語での文字列ソート動作について

    任意の文字列を入力し、その文字列を昇順にソートするプログラムを作ったのですが、入力する文字の文字数が大きく異なると期待した結果が得られません。 文字数が少なくなったり、他の配列の文字が混ざったりと言う結果に成ってしまっています。 何が原因か分からない状態です。 以下にサンプルを記載させて頂きますので、助言よろしくお願いします。 /*----------------------------------------- 入力例 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC BBBBBBBBBBBBBBBB AAAAAA -----------------------------------------*/ #include <stdio.h> #include <string.h> #include <stdlib.h> void swapc(char *cx , char *cy){ char tmp[100]; strcpy(tmp, cx); strcpy(cx, cy); strcpy(cy, tmp); } int main(){ char *num[100]; char str_tmp[100]; //文字列一時格納 int moji_cnt; //入力した文字列のカウント int n , m; // 文字列入力処理開始 printf("文字列を入力してください\n"); for( moji_cnt = 0 ; moji_cnt != 3 ; moji_cnt++){ scanf("%s", str_tmp); *(num+moji_cnt) = (char *)malloc(sizeof(char) * (strlen(str_tmp)+1)); //メモリ確保 strcpy(*(num+moji_cnt), str_tmp); } puts("\n"); // 文字数ソート処理 for(n = 0 ; n < moji_cnt-1 ; n++){ for(m = 1 ; m < moji_cnt-n ; m++){ if(strcmp(*(num+n) , *(num+n+m)) > 0){ swapc(*(num+n) , *(num+n+m)); // 文字列入れ替え } } } puts("\n"); for(n = 0;n != moji_cnt;n++){ printf("%s\n" , *(num+n)); } free(num); }

  • C言語のプログラムの流れについて

    下に貼り付けたプログラムの流れを順番に教えて頂きたいです。 特にadd関数とinsert関数の中身の動きについてが分からないので教えていただきたいです。 (a,b,c,sentouなどの動きなど。) 参考にですが リスト構造を用いて、read関数で読み込んだ単語をアルファベット順にソートしてリストのセルに入れ、同じ単語はまとめてその単語と個数を順に表示するプログラムです。 1からの説明を要求して申し訳ありませんがよろしくお願いいたします。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> typedef struct moji{ char w[50]; int cnt; struct moji *next; }moji; int main(){ FILE *fp; char data[50]; moji *sentou; moji *p=NULL; if((sentou=(moji *)malloc(sizeof(moji)))==NULL){ printf("malloc error\n"); exit(1); } fp=fopen("tango.txt","r"); if((fp = fopen("tango.txt","r"))==NULL){ printf("can't open\n"); exit(1); } while(read(data,fp)){ add(data,sentou); } p=sentou->next; while(p != NULL){ printf("%s %d\n",p->w,p->cnt); free(p); p=p->next; } fclose(fp); return (0); } int read(char data[],FILE *fp){ /*1つの単語(連続したアルファベット)をdataに格納して、スペースで区切られたらそこで格納をやめ、値1を返す。再度単語を格納するときはdataを初期化し、再度1つの単語を取得する。ファイルの単語がなくなれば(EOFなら)0を返す関数read()*/ } void add(char data[],moji *sentou){ moji *a,*c; for(c=sentou;c!=NULL;c=c->next){ if(strcmp(c->w,data)==0){ c->cnt++; return; } if(strcmp(c->w,data)>0){ break; } else{ a=c; } } insert(a,c,data); } void insert(moji *a,moji *c,char data[]){ moji *b; if((b=(moji *)malloc(sizeof(moji)))==NULL){ printf("malloc error\n"); exit(1); } strcpy(b->w,data); b->cnt=1; a->next=b; b->next=c; }

  • ソースコードの間違い (C言語)

    変数に、文字列を入れた配列の文字列の最後の要素数を入れたいのですが(つまり'\0')、うまくいきません。いつも2個多い値になってしまいます。 #include <stdio.h> void main() { char moji[100]={0}; int c=0; fgets(moji,sizeof moji,stdin); while( moji[c] != '\0' ) ++c; printf("\n%d\n",c); // } 例えば5文字の1ビット文字を入れると、最後の文字はmoji[4]にあるのでprintfで4と表示されるはずじゃないですか。でも6になるんです。いつも+2の値になるんですよ。どうやらfgetsを使っているからそうなるらしく、scanfを使うと結果は1多い値に、普通に配列に直接文字列を代入すると正常な結果になります。別にcに-2してもいいのですが、それはなんだか癪といいますか・・・。なぜこういうことがおきるのでしょうか?回答よろしくお願いします。

  • C言語

    forの直後で1+2+3+4+5+・・・・・・・と加算し続ける式がわからないので教えてください。 #include<stdio.h> int main(void) { char moji; int i,sum; printf("正の整数を1から順に加算します。n\"); printf("加算を開始してよろしいですか。(Y=実行。N=終了)\n"); moji=getchar(); if(moji==y) { for(i=2;sum>=1001;i++) { この部分がわかりません; printf("加算値は%dです。¥n",sum); } }else if(moji=='n'){ printf("終了します。\n"); }else{ printf("YまたはNを入力してください。\n"); } return 0; }

  • VS.NET2005 C#にてSerialPort受信されたときのイベントについて質問

    Visual Studio.NET2005ProにてSerialPort接続アプリケーションを開発しております。 受信が来たときのイベント DataReceived のところで、受信された文字列をテキストボックスへ表示させるということを行いたいのですが、エラーが出てしまいます。 ちなみにプログラムはこうです。 private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { //シリアルポートからデータを受信するたびに発生する textBox_all_in.Text = (string)serialPort.ReadByte(); } それで、エラーは エラー 1 型 'int' を型 'string' に変換できません。 このように出てしまいました。プログラミング初心者で、つまずいてしまいどうすればよいのかわからなく困っております。アドバイスよろしくお願いします。

  • 文字列での代入 (C言語)

    こんにちは。 C言語を勉強しているのですが、どうしても分からないことがあるので質問しました。 まず下記のソースを見てください。 #include <stdio.h> int main() { char* moji; moji = "right Test \n"; printf(" moji = %s\n", moji); moji = "dot 255 left up down \n"; printf(" moji = %s\n", moji); getchar(); return 0; } char* mojiがメモリを取らずに代入できているのですがこういった事が可能なのは何故でしょうか? その後もmojiの変数を別の文字列定数で書き換えています。 こういったことはできなかったはずなんですがどうしてでしょうか? 自分の開発環境だとVS.2005 VC++です。 よろしくおねがいします。

  • C#で、C言語で作ったdllに文字列の参照渡し

    Cで int test(char* moji) {   moji = "test";   return 0; } のようなdllを作り、C#側から   test(ref cs_moji); としても変数cs_mojiに"test"という文字列は帰ってきませんでした。 数時間調べたりしてcs_mojiの型をstringやStringBuilder等としたのですが、どれもうまくいきませんでした。 ポインタのポインタを利用したときは文字列は帰ってきたものの文字化けがたくさんしていて理想とはかけ離れていました。 どのようにしたらCのdllからC#に文字列を送ることができるでしょうか。 初歩的な質問かもしれないですがよろしくお願いいたします。

専門家に質問してみよう