接收系統回傳的訊息 |
答題得分者是:bernie_w39
|
GGL
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:104 回覆:600 積分:335 註冊:2006-11-05 發送簡訊給我 |
我使用moxa (A)連接到另一個設備(B),A為embedded linux (using C),B為一個送出訊號的機器
我看B的說明書中,Transmit 〈T1 〉會收到 〈 Tyyyy 〉,其中yyyy為0000-FFFF的十六進位碼 [code cpp] char temper[7]; char temperCommand[]=" read (fd, temper,7); printf("Temperature: %c%c%c%c%c%c%c\n",temper[0],temper[1],temper[2],temper[3],temper[4],temper[5],temper[6]); [/code] 但是收到的卻是不是溫度數值,請問是我接收(read)的部分寫錯了嗎? 若使用傳入其他指令,如〈RESET〉讓B RESET的動作似乎也沒作用 char resetCommand[]="〈RESET〉" write(fd, resetCommand, strlen(resetCommand)); 昨天剛接觸embedded linux,很多地方都不懂,看了書以及sample code,執行出來的還是有問題...煩請指教,謝謝 | |
㊣
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:261 回覆:2302 積分:1667 註冊:2005-01-04 發送簡訊給我 |
||
暗黑破壞神
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:9 回覆:2301 積分:1627 註冊:2004-10-04 發送簡訊給我 |
||
GGL
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:104 回覆:600 積分:335 註冊:2006-11-05 發送簡訊給我 |
SORRY..沒說明清楚,A跟B是透過RS232
以下是目前的CODE...謝謝指教 [code cpp] #include #include #include #include #include #include #include <math.h> #include #include #include #include #define BAUDRATE B38400 #define MODEMDEVICE "/dev/ttyM1" #define _POSIX_SOURCE 1 // POSIX compliant source #define MaxConnect 10 // 最大 client 連線數 #define portno 3335 // TCP/IP Port Number int socketClient[MaxConnect]; // size = MaxConnect int isVSconnected = -1 ; // 是否連接到 Ventilator int fd ; // serial port char *rateCommand; // waveform data rate char *rmCommand; // rm configure char *waveCommand; // flow & pres waveform char *resetCommand; // system reset char *temperCommand; //---------------------------------------------------------------- void error(char *msg) { perror(msg); } //---------------------------------------------------------------- //Socket Server Thread void *SocketServer(void *arg) { int sockfd, newsockfd, clilen; int i; struct sockaddr_in serv_addr, cli_addr; char str[30]; printf("create Socket Server Thread\n"); /* Step 1 : socket() */ if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) error("ERROR opening socket\n"); /* Step 2 : fill sockaddr_in structure */ memset(&serv_addr,0, sizeof(serv_addr)); // Clean the server_addr structure serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); /* Step 3 : bind() */ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); /* Step 4 : listen() */ listen(sockfd,MaxConnect); // 可以接受MaxConnect = 10個連線 /* Step 5 : wait for the request from client */ for(;;) { printf("listen on port %d..\n",portno); clilen = sizeof(cli_addr); newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) error("ERROR on accept"); if (isVSconnected == -1) { close(newsockfd); printf("Ventilator is disconnected, reject socket connection.\n"); } else { for (i = 0 ; i < MaxConnect ; i ) { if (socketClient[i] == -1) { socketClient[i] = newsockfd; printf("Client%d is connected \n",socketClient[i]); break; } else { if (i == MaxConnect-1) { printf("Over %d threads\n",MaxConnect); close(newsockfd); } } } } } close(sockfd); } //---------------------------------------------------------------- //Ventilator Reciver Thread void *VentilatorReciver(void *arg) { int res,i,m,n; int times; // times = 0 ~ 9 char buf[10]; // 累積10次資料傳送 char str[100]; fd_set readfds; // 儲存要測試的讀取FD fd_set writefds; // 儲存要測是的寫入FD struct timeval to; // timeout時間設定 char temper[7]; int temp_t; printf("create Ventilator Reciver Thread\n"); for(;;) { while(isVSconnected == -1) { FD_ZERO (&readfds); FD_SET (fd, &readfds); // 設定timeout,如果3秒仍無法收到資料,即重新測試 to.tv_sec = 3; to.tv_usec = 0; select(fd 1, &readfds, NULL, NULL, &to); if (FD_ISSET(fd, &readfds)) { isVSconnected = 1; printf("Ventilator is connected\n"); break; } } res = write(fd, resetCommand, strlen(resetCommand)); //7 printf("resetCommand sent: %s\n",resetCommand); res = write(fd, rateCommand, strlen(rateCommand)); //6 printf("rateCommand sent: %s\n",rateCommand); res = write(fd, rmCommand, strlen(rmCommand)); //5 printf("rmCommand sent: %s\n",rmCommand); res = write(fd, waveCommand, strlen(waveCommand)); //4 printf("waveCommand sent: %s\n",waveCommand); //溫度 write(fd, temperCommand, strlen(temperCommand)); printf("temperCommand sent: %s\n",temperCommand); for(temp_t=0;temp_t<7;temp_t ) read (fd, &temper[temp_t], 1); printf("Temperature: %c%c%c%c%c%c%c\n",temper[0],temper[1],temper[2],temper[3],temper[4],temper[5],temper[6]); printf("te3"); for(;;) { memset(str,0,100); for(times=0;times<10;times ) { FD_ZERO (&readfds); FD_SET (fd, &readfds); // 設定timeout,如果3秒仍無法收到資料,即重送指令 to.tv_sec = 3; to.tv_usec = 0; select(fd 1, &readfds, NULL, NULL, &to); if (FD_ISSET(fd, &readfds)) res = read (fd, buf[times], 1); else break; } n = sprintf(str, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n", buf[0], buf[1], buf[2], buf[3], buf[4],buf[5], buf[6], buf[7], buf[8], buf[9]); for (i = 0 ; i < MaxConnect ; i ) { if (socketClient[i] != -1) // 已連線 { FD_ZERO (&writefds); FD_SET (socketClient[i], &writefds); to.tv_sec = 3; to.tv_usec = 0; select(socketClient[i] 1, NULL, &writefds, NULL, &to); if (FD_ISSET(socketClient[i] , &writefds) == 1) m=write(socketClient[i], str, n); else { close(socketClient[i]); printf("%d is disconnected \n",socketClient[i]); socketClient[i] = -1; } } } } isVSconnected = -1; // 中斷所有socket連結 for (i = 0 ; i < MaxConnect ; i ) { if (socketClient[i] != -1) { close(socketClient[i]); printf("%d is disconnected \n",socketClient[i]); socketClient[i] = -1; } } printf("Ventilator is disconnected\n"); } printf("VentilatorReciver Thread closed"); } //---------------------------------------------------------------- int main(void) { //socketClient = new int[MaxConnect]; int i = 0; pthread_t threadSocketServer, threadVentilatorReciver ; void *threadSocketServerResult, *threadVentilatorReciverResult ; char message[]="Thread is running"; struct termios oldtio, newtio; // initial socket client for (i = 0 ; i < MaxConnect ; i ) { socketClient[i] = -1; } /*04. Waveform data rate: Transmit xx = ascii-hex 00-64 waveform frequency (MAX 100Hz Default) y = ascii-hex 0-F number of samples per packet (Default = 1) */ rateCommand=" /*12. RM configuration: Transmit xx = ascii-hex 00 no numerics parameters to be sent (Default) xx = ascii-hex 01 five numerics parameters(VTexp, PIP, MAP, COMP, RES) xx = ascii-hex FF All numeric parameters */ rmCommand=" /*13. System reset: Transmit */ resetCommand=" /*18. Flow & Pres waveform: Transmit x = ascii-hex 1 Send Flow in liters/min, Pres in cmH2O (Default) x = ascii-hex 2 Send Flow in cmH2O, Pres in cmH2O x = ascii-hex 3 Send Flow in A/D counts, Pres in A/D counts x = ascii-hex 4 Send Example Flow and Pres waveforms */ waveCommand=" temperCommand=" // 開啟數據機裝置以讀取並寫入而不以控制 tty 的模式; 因為我們不想程式在送出 CTRL-C 後就被殺掉 fd = open (MODEMDEVICE, O_RDWR | O_NOCTTY); if (fd < 0) { perror (MODEMDEVICE); exit (-1); } tcgetattr (fd, &oldtio); // 儲存目前的序列埠設定 memset(&newtio,0, sizeof (newtio)); // 清除結構體以放入新的序列埠設定值 /* BAUDRATE: 設定 bps 的速度. 你也可以用 cfsetispeed 及 cfsetospeed 來設定. CRTSCTS : 輸出資料的硬體流量控制 (只能在具完整線路的纜線下工作參考 Serial-HOWTO 第七節) CS8 : 8n1 (8 位元, 不做同位元檢查,1 個終止位元) CLOCAL : 本地連線, 不具數據機控制功能 CREAD : 致能接收字元 */ newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; /* IGNPAR : 忽略經同位元檢查後, 錯誤的位元組 ICRNL : 將 CR 對應成 NL (否則當輸入訊號有 CR 時不會終止輸入) 在不然把裝置設定成 raw 模式(沒有其它的輸入處理) */ newtio.c_iflag = IGNPAR | ICRNL; /* Raw 模式輸出. */ newtio.c_oflag = 0; /* ICANON : 致能標準輸入, 使所有回應機能停用, 並不送出信號以叫用程式 */ newtio.c_lflag = ICANON; newtio.c_cc[VTIME] = 0; // inter-character timer unused newtio.c_cc[VMIN] = 1; // blocking read until 1 character arrives /* 清除數據機線並啟動序列埠的設定 */ tcflush (fd, TCIFLUSH); tcsetattr (fd, TCSANOW, &newtio); if (pthread_create(&threadSocketServer, NULL, SocketServer, (void *)message)) exit(0); if (pthread_create(&threadVentilatorReciver, NULL, VentilatorReciver, (void *)message)) exit(0); // waiting for thread terminate. pthread_join(threadSocketServer, &threadSocketServerResult); printf("Socket Server Thread terminated\n"); pthread_join(threadVentilatorReciver, &threadVentilatorReciverResult); printf("Ventilator Reciver Thread terminated\n"); return 0; }[/code] ===================引 用 ㊣ 文 章=================== 1> 請問兩邊如何通訊? 2> sample code 可以貼上來給大家參考嗎? 3> 兩邊傳是直接傳數值, or ASCII ? or ? |
|
GGL
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:104 回覆:600 積分:335 註冊:2006-11-05 發送簡訊給我 |
謝謝回覆
因為是剛接觸,我第一次看到ioctl這個名詞,剛剛到GOOGLE看了一下,大致上知道他的目的 ===================引 用 暗黑破壞神 文 章=================== 假設你已經會了什麼 ioctl 那些東西了。 假設你的 read, write 是對的。 那你也要去看看你的 read 到的資料。是不是長度為 0 吧。 看你這樣寫。很標準的。讀到長度0的資料。就去動作了。~_~ 不好意思,這一句看不太懂,這句是說,如果他read後雖然長度是0(也就是說沒讀到東西),我仍然會printf嗎? 請問我該如何避免還沒讀到資料就printf出來... |
|
暗黑破壞神
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:9 回覆:2301 積分:1627 註冊:2004-10-04 發送簡訊給我 |
||
GGL
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:104 回覆:600 積分:335 註冊:2006-11-05 發送簡訊給我 |
謝謝回覆,
我不太清楚為何要用non-blocking?我在幾本書跟網路上的code幾乎都是用blocking的方式(沒有non-blocking應該就是blocking了吧?!) 首先我先說明目前發現的問題:(設備B一啟動就會一直送訊息出去,因此程式只要一連到B就會不斷收到訊息) 在143行~156行做修改,在沒有修改前,我用另一支程式去聯到embedded linux的這支程式RM,並抓取RM送出的訊息,發現全部的值都是0, 即buf [i] =0 若修改成 [code cpp] FD_ZERO (&readfds); FD_SET (fd, &readfds); to.tv_sec = 3; to.tv_usec = 0; select(fd 1, &readfds, NULL, NULL, &to); if (FD_ISSET(fd, &readfds)) res = read (fd, buf, 1); //buf宣告改成 char buf[1]; else break; n = sprintf(str, "%d\n",buf[0]); [/code] 則取得的數值大概是60,119,135,20,250,187,128,232,27,182,121,62,轉成設備B的格式為〈w,135,20,250,187,128,232,27,182,121〉
PS.逗號是我方便觀看額外加上去的,原本為〈wxxxxyyyyz〉的format 我不懂的是,為什麼改成for loop會有這種完全不同的結果? 設備B為Cardiopulmonary的Evaluation Kit,說明書只有14頁,只有列出傳入哪些參數會得到哪些結果 write(fd, temperCommand, strlen(temperCommand));送出取得溫度的參數給B,但是B並沒有回傳系統溫度,因為系統溫度的格式為〈Tyyyy〉, 而取得的值均是〈w開頭的,B設備似乎只是一直送出一開始的訊息,並沒有處理 GET TEMPERATIRE的動作,不管送出什麼參數,設備B還是不會有任何動作, 照常送出一開始的訊息,請問是我用write的方式錯誤嗎? 問題還蠻多的,目前比較困擾我的是,A送出指令給B,但是B一直沒反應,請問這是什麼原因?非常感謝 |
|
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
res = read (fd, buf[times], 1);
這樣寫應該是錯的, 可以改成 res = read (fd, buf times, 1); 或是 res = read (fd, &buf[times], 1); 所以你會覺得用 for loop 結果不同. 另外, RS232 的 write, 不一定會全部寫進 buffer, 要看一下回傳值, 如果回傳值等於你傳入的 strlen(ooxx), 才表示全部寫入 buffer. 你還有 14 頁的說明書可以看, 被你詢問的人連這 14 頁都沒有, 只好問你 ^^. 你收到的回傳訊息, 格式是對的嗎? 你說它一直送 "一開始的訊息", 那是不是正確的格式呢? 這點很重要. 因為格式 如果正確, 至少你的 rs232 相關設定是對的 (就是 ioctl 那些東東). |
|
GGL
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:104 回覆:600 積分:335 註冊:2006-11-05 發送簡訊給我 |
Dear bernie_w39
你說它一直送 "一開始的訊息", 那是不是正確的格式呢? Re. 格式應該是正確的,如同上述提到的表格〈w,135,20,250,187,128,232,27,182,121〉 說明書上,
如果正確, 至少你的 rs232 相關設定是對的 (就是 ioctl 那些東東) 我的RS232設定以及read/write沒有用到ioctl。而設定應該是正確的,只是他只能接收預設機器送出的訊息,沒辦法對機器傳送command 剛剛上網找了ioctl的使用方法,改寫如下 [code cpp] #define MOXA_IOC_MAGIC 'k' // Use 'k' as magic number #define IOCTL_RESET _IO(MOXA_IOC_MAGIC, 0) #define IOCTL_TEMERATURE _IOWR(MOXA_IOC_MAGIC, 15, int) static int moxa_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) { switch(cmd) { case IOCTL_TEMERATURE: write(fd, resetCommand, strlen(resetCommand)); break; } } [/code] 會有這一段code,我使用ioctl(fd, IOCTL_TEMERATURE, temperCommand);他並不會執行到moxa_ioctl裡面,我看了幾個範例,並沒有任何地方會呼叫到moxa_ioctl( ),讓我有點疑惑;是不是要先把moxa_ioctl( )這個function"註冊"到系統,但是我找不到方法可以"註冊",因此不確定我的想法是不是正確。 而case IOCTL_TEMERATURE下的動作我也不太清楚該怎麼寫,因此我只能在case下使用write,但是這樣又跟一開始直接使用wirte的方法一樣^^" http://bantolinux.blogspot.com/2007/05/mp3-player-v1.html,看這個網頁的介紹,似乎在寫driver(我沒寫過), 如果真的是要透過寫driver的方式,會不會有點太複雜,畢竟我只是要送訊息給設備B。我的想法,透過RS232及write的方式送出訊息(取得溫度)給設備,而設備會回傳系統溫度,而程式利用read讀取回傳的值,不知道我的想法是否有錯? ps.我測試過write(fd, temperCommand, strlen(temperCommand))的回傳值,跟strlen(temperCommand)一樣 請問是否有哪本書或是網站可以查詢的到,從上星期到現在,看到的資料對我來說有點看不太懂(I/O傳送資料方面),因此觀念不是很正確,煩請指教,謝謝 |
|
暗黑破壞神
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:9 回覆:2301 積分:1627 註冊:2004-10-04 發送簡訊給我 |
1.你的 rs232 傳給你的一個字的時間。是很長的。
你要是做 read from rs232 print the data 那你可能一千次才有一次是對的。 因為你要看你的 read 是不是有傳回你讀到的長度。 通常,read 會讀到長度 0. 因為 9600 的速度。。。夠讓你的 read 跑 n 次 loop 才讀到長度 1 byte 的資料。 所以。如果你是在做實驗。你可以試著用。 for (....) { int n = read(rs232...) if (n != 0) print data } 用這樣來看你讀的結果。 這樣做,你讀到的資料就會正確了。 |
|
bernie_w39
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:3 回覆:199 積分:280 註冊:2007-10-07 發送簡訊給我 |
我覺得你好像會錯意了.
首先, ioctl 是控制 i/o 的一些特性參數. 像是 RS232 這種 i/o, 它的特性參數就有 baud rate, 5/6/7/8 bits per word, 1/0 stop bits, non/odd/even parity, ctsrts on/off .... 等等. ioctl 是用來設定通訊埠的, 不是用來傳資料的. 你既然可以正確收到設備傳來的資料, 表示你的 RS232 設定大部份是正確的. 但是 RS232 還有一些機關, 像是 flow control 的作法. 不曉得你手邊有沒有 RS232 指示器? 就是一個 小盒子, 串連在 RS232 線路上, 然後小盒子上有一堆 LED 燈的那種東西. 用它可以看出你 的 B 設備是否要在特定的 flow control 下才能接收資料. 有沒有試試看用 null modem 的線, 把你的 A 設備連到一台 PC 上, 然後在 PC 上開一個 可以收送 RS232 的程式 (像是 minicom 或是 hyper terminal), 看看可不可以收到你 A 設備傳來的指令. 如果可以, 變換一下 flow control 成為 hardware 模式, 看看是否還是 收到的. |
|
GGL
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:104 回覆:600 積分:335 註冊:2006-11-05 發送簡訊給我 |
||
GGL
資深會員 ![]() ![]() ![]() ![]() ![]() 發表:104 回覆:600 積分:335 註冊:2006-11-05 發送簡訊給我 |
卡了很久,發現原來是設定錯誤
說明書上寫 Baud Rate = 19200 or 38400 Data bits = 8 Parity = odd, even , or no parity 1 or 2 stop bits 結果只有當Baud Rate =38400且Parity = even 時才有動作 因為卡太久,我是用vb寫來測試,元件屬性設定一下就可以了,轉到Linux C的時候發現原來沒這麼簡單 以下是設定的code [code cpp] set_opt(fd,115200,8,'N',1); int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop) { struct termios newtio,oldtio; if ( tcgetattr( fd,&oldtio) != 0) { perror("SetupSerial 1"); return -1; } bzero( &newtio, sizeof( newtio ) ); newtio.c_cflag |= CLOCAL | CREAD; newtio.c_cflag &= ~CSIZE; switch( nBits ) { case 7: newtio.c_cflag |= CS7; break; case 8: newtio.c_cflag |= CS8; break; } switch( nEvent ) { case 'O': newtio.c_cflag |= PARENB; newtio.c_cflag |= PARODD; newtio.c_iflag |= (INPCK | ISTRIP); break; case 'E': newtio.c_iflag |= (INPCK | ISTRIP); newtio.c_cflag |= PARENB; newtio.c_cflag &= ~PARODD; break; case 'N': newtio.c_cflag &= ~PARENB; break; } switch( nSpeed ) { case 2400: cfsetispeed(&newtio, B2400); cfsetospeed(&newtio, B2400); break; case 4800: cfsetispeed(&newtio, B4800); cfsetospeed(&newtio, B4800); break; case 9600: cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break; case 115200: cfsetispeed(&newtio, B115200); cfsetospeed(&newtio, B115200); break; case 460800: cfsetispeed(&newtio, B460800); cfsetospeed(&newtio, B460800); break; default: cfsetispeed(&newtio, B9600); cfsetospeed(&newtio, B9600); break; } if( nStop == 1 ) newtio.c_cflag &= ~CSTOPB; else if ( nStop == 2 ) newtio.c_cflag |= CSTOPB; newtio.c_cc[VTIME] = 0; newtio.c_cc[VMIN] = 0; tcflush(fd,TCIFLUSH); if((tcsetattr(fd,TCSANOW,&newtio))!=0) { perror("com set error"); return -1; } printf("set done!\n"); return 0; } [/code] 暫時把這個問題搞定了....謝謝各位 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |