2010-09-13 11 views
8

मेरे पास लूपबैक के रूप में स्थापित एक धारावाहिक डिवाइस है (जिसका अर्थ यह है कि यह किसी भी चरित्र को प्राप्त करने के लिए बस गूंज देगा), और मैं प्रभावी थ्रूपुट गति को मापना चाहता हूं। इस के लिए, मुझे लगता है मैंबैश या सी में सीरियल पोर्ट लूपबैक/डुप्लेक्स परीक्षण? (प्रक्रिया प्रतिस्थापन)

time bash -c '...' 

में time इस्तेमाल कर सकते हैं, के रूप में जहां '...' कुछ कमांड मैं चला सकते हैं होगा आशा व्यक्त की।

अब, पहली समस्या यह है कि मैं 2000000 बीपीएस पर डिवाइस का उपयोग करना चाहता हूं, इसलिए मैं ttylog या screen का उपयोग नहीं कर सकता (वे दोनों केवल 115200 बीपीएस तक जा रहे हैं)। हालांकि, (फ़ाइल पुनर्निर्देशन और cat का प्रयोग करके) एक फ़ाइल के रूप /dev/ttyUSB0 के साथ काम ठीक से काम करने लगता है: अब

# initialize serial port 
stty 2000000 -ixon icanon </dev/ttyUSB0 

# check settings 
stty -a -F /dev/ttyUSB0 

# in one terminal - read from serial port 
while (true) do cat -A /dev/ttyUSB0 ; done 

# in other terminal - write to serial port 
echo "1234567890" > /dev/ttyUSB0 

# back to first terminal, I now have: 
# $ while (true) do cat -A /dev/ttyUSB0 ; done 
# 1234567890$ 
# ... 

, मैं कुछ इसी तरह करना चाहते हैं - मैं करने के लिए cat एक सीरियल पोर्ट के लिए एक फ़ाइल करना चाहते हैं , और सीरियल पोर्ट वापस पढ़ा है - लेकिन एक टर्मिनल कमांड से (इसलिए मैं इसे time पर तर्क के रूप में उपयोग कर सकता हूं)।

मैंने सोचा था कि मैं एक बैश प्रक्रिया प्रतिस्थापन इस्तेमाल कर सकते हैं, "लेखन" और 'समझ' भाग जाना, एक तरह से, "समांतर" में किया है - अगर मैं नामित पाइप के साथ प्रयास करें, यह काम करता है:

# mkfifo my.pipe # same as below: 
$ mknod my.pipe p 

$ comm <(echo -e "test\ntest\ntest\n" > my.pipe) <(cat my.pipe) 
    test 
    test 
    test 
comm: file 2 is not in sorted order 

ऊपर, मैं किसी अन्य उद्देश्य के लिए comm का उपयोग नहीं कर रहा हूं, (प्रक्रियाओं) की तुलना में दो प्रक्रियाओं को एक ही कमांड में मिलाएं (मुझे लगता है, मैं इसके बजाय echo के बजाय भी उपयोग कर सकता था)।

दुर्भाग्य से, कि चाल, एक सीरियल पोर्ट के साथ काम करने क्योंकि जब मैंने यह कोशिश करते हैं, मैं कभी कभी मिलता है प्रतीत नहीं होता:

$ comm <(echo "1234567890" > /dev/ttyUSB0) <(while (true) do cat -A /dev/ttyUSB0 ; done) 
cat: /dev/ttyUSB0: Invalid argument 

... बहरहाल, आम तौर मैं सिर्फ कोई उत्पादन जो भी मिलता है। यह मुझे बताता है कि: या तो कोई प्रक्रिया नहीं है कि कौन सी प्रक्रिया पहले शुरू होती है, और cat बंदरगाह तैयार होने से पहले पढ़ना शुरू कर सकता है (हालांकि, यह ऊपर दिए गए पहले उदाहरण में कोई समस्या नहीं प्रतीत होता है); या लिनक्स/बैश में, आप दोनों एक ही समय में एक सीरियल पोर्ट को पढ़ और लिख नहीं सकते हैं, और इसलिए उन क्षणों में "Invalid argument" उत्पन्न होगा जब दोनों पढ़ और लिखने एक ही समय में होने लगते हैं।

तो मेरी प्रश्न हैं:

  • वहाँ कुछ इस तरह (लूपबैक के रूप में विन्यस्त एक सीरियल पोर्ट के लिए एक फ़ाइल cat, यह वापस पढ़ें और देखें कि यह कितना समय लगता है) करने के लिए एक रास्ता है केवल बैश में, एक समर्पित सी कार्यक्रम लिखने के बिना?
  • यदि मुझे एक समर्पित सी प्रोग्राम की आवश्यकता है, तो नेट पर मौजूद कोई स्रोत उदाहरण मैं उपयोग कर सकता हूं?

किसी भी प्रतिक्रिया के लिए धन्यवाद एक बहुत,

चीयर्स!

 

संपादित करें: मुझे पता है कि while पाश ऊपर लिखा से बाहर नहीं हूं; वह कमांड लाइन प्रारंभिक परीक्षण के लिए थी, और मैं इसे Ctrl-C का उपयोग करके बाधित करता हूं।(timeout -9 0.1 bash -c 'while (true) do echo AA ; done' की तरह कुछ के साथ यह बाधा सिद्धांत है, लेकिन में है कि तब time का उद्देश्य विफल हो जाएगा मैं कर सकता है, :))

कारण यह है कि while है, जा रहा है कि समय के लिए, से cat के माध्यम से पढ़ने है डिवाइस तुरंत निकलता है; कभी-कभी, में डिवाइस सेट अप करता है, ताकि जब cat जारी किया गया हो, तो वास्तव में यह अवरुद्ध हो जाता है और आने वाले डेटा की प्रतीक्षा करता है; लेकिन मैं अभी तक यह नहीं समझ सकता कि क्या हो रहा है (और आंशिक रूप से यही कारण है कि मैं कमांड लाइन से परीक्षण करने का तरीका ढूंढ रहा हूं)।

मामले में मैं while का उपयोग नहीं किया है, मैं समय के लिए कल्पना, मैं की तरह कुछ का उपयोग करेंगे:

time bash -c 'comm <(echo "1234567890" > /dev/ttyUSB0) <(cat -A /dev/ttyUSB0)'

... लेकिन के लिए यह काम करने, एक तरह से, कि मान लिया गया है cat -A /dev/ttyUSB0 पहले और ब्लॉक शुरू होता है; तो echo धारावाहिक बंदरगाह (और निकास) को लिखता है; और फिर cat -A सीरियल पोर्ट से जो कुछ भी पढ़ता है उसे आउटपुट करता है - और फिर बाहर निकलता है। (और मुझे सच में यकीन नहीं है और न ही यदि एक सीरियल पोर्ट इस तरह से व्यवहार कर सकता है, और न ही cat को जैसे मनमाने ढंग से ब्लॉक करने और बाहर निकलने के लिए बनाया जा सकता है)।

सटीक विधि वास्तव में कोई फर्क नहीं पड़ता; यदि संभव हो, तो मैं इस तरह के परीक्षण करने के लिए अपने स्वयं के सी प्रोग्राम को कोडिंग से बचना चाहूंगा - यही कारण है कि मेरी प्राथमिक रुचि यह है कि यदि मूल बैश का उपयोग करके ऐसा "पूर्ण-डुप्लेक्स परीक्षण" चलाने के लिए संभव है, लिनक्स (यानी coreutils); (और यदि नहीं, तो कोई तैयार कोड है तो मैं इस जैसे कुछ के लिए उपयोग कर सकता हूं)।

EDIT2: इसके अलावा संभवतः प्रासंगिक:

+0

आप इस काम करने के लिए प्राप्त करने के लिए थे, तो 'while' पाश कभी नहीं समाप्त हो जाता है। आप ऐसा करने का प्रस्ताव कैसे देते हैं और आप 'time' कमांड कहां रखने की योजना बना रहे हैं? क्या आपने रीड लूप में 'पीवी' के साथ अपनी पहली विधि का उपयोग करने पर विचार किया है? –

+0

हाय डेनिस, आपकी प्रतिक्रिया के लिए बहुत बहुत धन्यवाद! मैंने उपरोक्त पद संपादित किया है, उम्मीद है कि यह आपके द्वारा उठाए गए मुद्दों को स्पष्ट करता है! बीटीडब्ल्यू, मैंने पहले कभी 'पीवी' के बारे में नहीं सुना है, मुझे लगता है कि आप [पीवी (1) के बारे में बात कर रहे हैं: पाइप के माध्यम से डेटा की प्रगति की निगरानी करें - लिनक्स मैन पेज] (http://linux.die.net/man/ 1/पीवी) - मैं इसे देख लूँगा ... – sdaau

उत्तर

4

ठीक है, मैं pthread का उपयोग कर एक पिरोया संस्करण में writeread.c डाल करने में कामयाब (कोड नीचे है - मैं नहीं लगता serial.h बहुत बदल गया; इसका उपयोग थ्रेड संस्करण में कहीं भी नहीं किया जाता है)।मैं भी 115200 करने के लिए गति को कम कर दिया है, और अब मैं डिवाइस के साथ इन मापों, नीचे दिए गए नमूना आदेश पंक्ति सत्र में इस बात की पुष्टि कर सकते हैं:

$ ./writeread /dev/ttyUSB0 115200 writeread.c 3>myout.txt 
stdalt opened; Alternative file descriptor: 3 
Opening port /dev/ttyUSB0; 
Got speed 115200 (4098/0x1002); 
Got file/string 'writeread.c'; opened as file (6131). 
write_thread_function spawned 
    write: 6131 
    read: 18 
    read: 64 
    read: 110 
    read: 156 
    read: 202 
... 
    read: 6066 
    read: 6089 
    read: 6123 
    read: 6131 

+++DONE+++ 
Wrote: 6131 bytes; Read: 6131 bytes; Total: 12262 bytes. 
Start: 1284462824 s 141104 us; End: 1284462824 s 682598 us; Delta: 0 s 541494 us. 
115200 baud for 8N1 is 11520 Bps (bytes/sec). 
Measured: write 11322.38 Bps (98.28%), read 11322.38 Bps (98.28%), total 22644.76 Bps. 

$ diff writeread.c myout.txt 
$ 

ठीक है, माप अब उम्मीद बॉड दर के 99% अप करने के लिए रिपोर्ट, तो मुझे लगता है कि इसका मतलब है कि इस कार्यक्रम के प्रोफाइलिंग पहलू को काम करना चाहिए। नोटिस:

  • इस डिवाइस के लिए, write (यदि आवश्यक हो, के रूप में पीसी के पैकेट के लिए अनुक्रमण संभाल करने में सक्षम होना चाहिए) को एक ही हिस्सा में मार डाला है,
  • जबकि read छोटे में पर चला जाता है मात्रा (शायद यह दर्शाता है कि डिवाइस पूरे हिस्सा के आने का इंतजार नहीं करता है - के बजाय इसे छोटा हिस्सा वापस भेजना शुरू करेगा जैसे ही यह काफी प्राप्त हुआ है के रूप में)

ठीक है, मुझे लगता है कि यह मैं क्या जरूरत है origi nally; मुझे यह भी लगता है कि cat और echo को प्रक्रिया प्रतिस्थापन के माध्यम से निष्पादित करने के लिए संभवतः संभव नहीं है, चलिए इसे "थ्रेडेड", तरीके से कॉल करें :) (अब, मुझे 2000000 बॉड पर ऐसा करने में कोई समस्या है, लेकिन वह डिवाइस डिवाइस के प्रोग्रामिंग के साथ एक समस्या इंगित करता है)।

चीयर्स!

 

writeread.c - पिरोया संस्करण

/* 
    writeread.c - based on writeread.cpp 
    [SOLVED] Serial Programming, Write-Read Issue - http://www.linuxquestions.org/questions/programming-9/serial-programming-write-read-issue-822980/ 

    build with: gcc -o writeread -lpthread -Wall -g writeread.c 
*/ 

#include <stdio.h> 
#include <string.h> 
#include <stddef.h> 

#include <stdlib.h> 
#include <sys/time.h> 

#include <pthread.h> 

#include "serial.h" 


int serport_fd; 

//POSIX Threads Programming - https://computing.llnl.gov/tutorials/pthreads/#PassingArguments 
struct write_thread_data{ 
    int fd; 
    char* comm; //string to send 
    int bytesToSend; 
    int writtenBytes; 
}; 

void usage(char **argv) 
{ 
    fprintf(stdout, "Usage:\n"); 
    fprintf(stdout, "%s port baudrate file/string\n", argv[0]); 
    fprintf(stdout, "Examples:\n"); 
    fprintf(stdout, "%s /dev/ttyUSB0 115200 /path/to/somefile.txt\n", argv[0]); 
    fprintf(stdout, "%s /dev/ttyUSB0 115200 \"some text test\"\n", argv[0]); 
} 

// POSIX threads explained - http://www.ibm.com/developerworks/library/l-posix1.html 
// instead of writeport 
void *write_thread_function(void *arg) { 
    int lastBytesWritten; 
    struct write_thread_data *my_data; 
    my_data = (struct write_thread_data *) arg; 

    fprintf(stdout, "write_thread_function spawned\n"); 

    my_data->writtenBytes = 0; 
    while(my_data->writtenBytes < my_data->bytesToSend) 
    { 
     lastBytesWritten = write(my_data->fd, my_data->comm + my_data->writtenBytes, my_data->bytesToSend - my_data->writtenBytes); 
     my_data->writtenBytes += lastBytesWritten; 
     if (lastBytesWritten < 0) 
     { 
      fprintf(stdout, "write failed!\n"); 
      return 0; 
     } 
     fprintf(stderr, " write: %d - %d\n", lastBytesWritten, my_data->writtenBytes); 
    } 
    return NULL; //pthread_exit(NULL) 
} 

int main(int argc, char **argv) 
{ 

    if(argc != 4) { 
     usage(argv); 
     return 1; 
    } 

    char *serport; 
    char *serspeed; 
    speed_t serspeed_t; 
    char *serfstr; 
    int serf_fd; // if < 0, then serfstr is a string 
    int sentBytes; 
    int readChars; 
    int recdBytes, totlBytes; 

    char* sResp; 
    char* sRespTotal; 

    struct timeval timeStart, timeEnd, timeDelta; 
    float deltasec, expectBps, measReadBps, measWriteBps; 

    struct write_thread_data wrdata; 
    pthread_t myWriteThread; 

    /* Re: connecting alternative output stream to terminal - 
    * http://coding.derkeiler.com/Archive/C_CPP/comp.lang.c/2009-01/msg01616.html 
    * send read output to file descriptor 3 if open, 
    * else just send to stdout 
    */ 
    FILE *stdalt; 
    if(dup2(3, 3) == -1) { 
     fprintf(stdout, "stdalt not opened; "); 
     stdalt = fopen("/dev/tty", "w"); 
    } else { 
     fprintf(stdout, "stdalt opened; "); 
     stdalt = fdopen(3, "w"); 
    } 
    fprintf(stdout, "Alternative file descriptor: %d\n", fileno(stdalt)); 

    // Get the PORT name 
    serport = argv[1]; 
    fprintf(stdout, "Opening port %s;\n", serport); 

    // Get the baudrate 
    serspeed = argv[2]; 
    serspeed_t = string_to_baud(serspeed); 
    fprintf(stdout, "Got speed %s (%d/0x%x);\n", serspeed, serspeed_t, serspeed_t); 

    //Get file or command; 
    serfstr = argv[3]; 
    serf_fd = open(serfstr, O_RDONLY); 
    fprintf(stdout, "Got file/string '%s'; ", serfstr); 
    if (serf_fd < 0) { 
     wrdata.bytesToSend = strlen(serfstr); 
     wrdata.comm = serfstr; //pointer already defined 
     fprintf(stdout, "interpreting as string (%d).\n", wrdata.bytesToSend); 
    } else { 
     struct stat st; 
     stat(serfstr, &st); 
     wrdata.bytesToSend = st.st_size; 
     wrdata.comm = (char *)calloc(wrdata.bytesToSend, sizeof(char)); 
     read(serf_fd, wrdata.comm, wrdata.bytesToSend); 
     fprintf(stdout, "opened as file (%d).\n", wrdata.bytesToSend); 
    } 

    sResp = (char *)calloc(wrdata.bytesToSend, sizeof(char)); 
    sRespTotal = (char *)calloc(wrdata.bytesToSend, sizeof(char)); 

    // Open and Initialise port 
    serport_fd = open(serport, O_RDWR | O_NOCTTY | O_NONBLOCK); 
    if (serport_fd < 0) { perror(serport); return 1; } 
    initport(serport_fd, serspeed_t); 

    wrdata.fd = serport_fd; 

    sentBytes = 0; recdBytes = 0; 

    gettimeofday(&timeStart, NULL); 

    // start the thread for writing.. 
    if (pthread_create(&myWriteThread, NULL, write_thread_function, (void *) &wrdata)) { 
     printf("error creating thread."); 
     abort(); 
    } 

    // run read loop 
    while (recdBytes < wrdata.bytesToSend) 
    { 

     while (wait_flag == TRUE); 

     if ((readChars = read(serport_fd, sResp, wrdata.bytesToSend)) >= 0) 
     { 
      //~ fprintf(stdout, "InVAL: (%d) %s\n", readChars, sResp); 
      // binary safe - add sResp chunk to sRespTotal 
      memmove(sRespTotal+recdBytes, sResp+0, readChars*sizeof(char)); 
      /* // text safe, but not binary: 
      sResp[readChars] = '\0'; 
      fprintf(stdalt, "%s", sResp); 
      */ 
      recdBytes += readChars; 
     } else { 
      if (errno == EAGAIN) 
      { 
       fprintf(stdout, "SERIAL EAGAIN ERROR\n"); 
       return 0; 
      } 
      else 
      { 
       fprintf(stdout, "SERIAL read error: %d = %s\n", errno , strerror(errno)); 
       return 0; 
      }   
     } 
     fprintf(stderr, " read: %d\n", recdBytes);   

     wait_flag = TRUE; // was == 
     //~ usleep(50000); 
    } 

    if (pthread_join (myWriteThread, NULL)) { 
     printf("error joining thread."); 
     abort(); 
    } 

    gettimeofday(&timeEnd, NULL); 

    // binary safe - dump sRespTotal to stdalt 
    fwrite(sRespTotal, sizeof(char), recdBytes, stdalt); 

    // Close the open port 
    close(serport_fd); 
    if (!(serf_fd < 0)) { 
     close(serf_fd); 
     free(wrdata.comm); 
    } 
    free(sResp); 
    free(sRespTotal); 

    fprintf(stdout, "\n+++DONE+++\n"); 

    sentBytes = wrdata.writtenBytes; 
    totlBytes = sentBytes + recdBytes; 
    timeval_subtract(&timeDelta, &timeEnd, &timeStart); 
    deltasec = timeDelta.tv_sec+timeDelta.tv_usec*1e-6; 
    expectBps = atoi(serspeed)/10.0f; 
    measWriteBps = sentBytes/deltasec; 
    measReadBps = recdBytes/deltasec; 

    fprintf(stdout, "Wrote: %d bytes; Read: %d bytes; Total: %d bytes. \n", sentBytes, recdBytes, totlBytes); 
    fprintf(stdout, "Start: %ld s %ld us; End: %ld s %ld us; Delta: %ld s %ld us. \n", timeStart.tv_sec, timeStart.tv_usec, timeEnd.tv_sec, timeEnd.tv_usec, timeDelta.tv_sec, timeDelta.tv_usec); 
    fprintf(stdout, "%s baud for 8N1 is %d Bps (bytes/sec).\n", serspeed, (int)expectBps); 
    fprintf(stdout, "Measured: write %.02f Bps (%.02f%%), read %.02f Bps (%.02f%%), total %.02f Bps.\n", measWriteBps, (measWriteBps/expectBps)*100, measReadBps, (measReadBps/expectBps)*100, totlBytes/deltasec); 

    return 0; 
} 
+0

इस कोड से यह स्पष्ट नहीं है कि आप आंतरिक लूपबैक कैसे सेट अप करते हैं। क्या आपने कभी * TCIOM_LOOP * का उपयोग किया है? – 0andriy

5

ठीक है, यहाँ एक आंशिक जवाब की तरह कुछ है - हालांकि पार्टी के उपयोग के बारे सवाल अभी भी खुला है। मैंने कुछ सी कोड समाधानों में थोड़ा सा देखने की कोशिश की - और ऐसा लगता है कि यह छोटा नहीं है!

// from: between write and read:serial port. - C - http://www.daniweb.com/forums/thread286634.html 
// gcc -o sertest -Wall -g sertest.c 

#include <stdio.h> 
#include <sys/types.h> 
#include <string.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <errno.h> 
#include <termios.h> 

int main(int argc, char *argv[]) 
{ 
    char line[1024]; 
    int chkin; 
    char input[1024]; 
    char msg[1024]; 
    char serport[24]; 

    // argv[1] - serial port 
    // argv[2] - file or echo 

    sprintf(serport, "%s", argv[1]); 

    int file= open(serport, O_RDWR | O_NOCTTY | O_NDELAY); 

    if (file == 0) 
    { 
     sprintf(msg, "open_port: Unable to open %s.\n", serport); 
     perror(msg); 
    } 
    else 
     fcntl(file, F_SETFL, FNDELAY); //fcntl(file, F_SETFL, 0); 

    while (1) 
    { 

     printf("enter input data:\n"); 
     scanf("%s",&input[0]); 

     chkin=write(file,input,sizeof input); 

     if (chkin<0) 
     { 
      printf("cannot write to port\n"); 
     } 

     //chkin=read(file,line,sizeof line); 

     while ((chkin=read(file,line,sizeof line))>=0) 
     { 
      if (chkin<0) 
      { 
       printf("cannot read from port\n"); 
      } 
      else 
      { 
       printf("bytes: %d, line=%s\n",chkin, line); 
      } 
     } 

     /*CODE TO EXIT THE LOOP GOES HERE*/ 
     if (input[0] == 'q') break; 
    } 

    close(file); 
    return 0; 
} 

ऊपर कोड के साथ समस्या यह है कि यदि ऐसा नहीं होता है: - :)

पहले, आइए देखते हैं कि संभवतः इस मामले के लिए काम करते नहीं करता चलो नीचे "between write and read:serial port. - C" से एक उदाहरण है चरित्र ("कच्चे") ऑपरेशन के लिए सीरियल पोर्ट को स्पष्ट रूप से प्रारंभ करें; तो कैसे बंदरगाह पहले से स्थापित किया गया था पर निर्भर करता है, एक सत्र ऐसा दिख सकता है:

$ ./sertest /dev/ttyUSB0 
enter input data: 
t1 
enter input data: 
t2 
enter input data: 
t3 
enter input data: 
^C 

... दूसरे शब्दों में, वहाँ इनपुट डेटा का कोई गूंज है। हालांकि, अगर सीरियल पोर्ट ठीक तरह से स्थापित है, हम की तरह एक सत्र प्राप्त कर सकते हैं:

$ ./sertest /dev/ttyUSB0 
enter input data: 
t1 
enter input data: 
t2 
bytes: 127, line=t1 
enter input data: 
t3 
bytes: 127, line=t2 
enter input data: 
t4 
bytes: 127, line=t3 
enter input data: 
^C 

... (लेकिन फिर भी, इस sertest कोड 3 वर्णों से बड़ा इनपुट शब्दों पर विफल रहता है।)

अंत में, कुछ ऑनलाइन खुदाई के माध्यम से, मुझे "(SOLVED) Serial Programming, Write-Read Issue" मिल गया, जो writeread.cpp उदाहरण प्रदान करता है।हालांकि, इस बाइट-बाय-बाइट "डुप्लेक्स" मामले के लिए, यह भी पर्याप्त नहीं था - अर्थात्, "Serial Programming HOWTO" नोट्स: "कैननिकल इनपुट प्रोसेसिंग ... टर्मिनलों के लिए सामान्य प्रसंस्करण मोड है ... जिसका अर्थ है कि एक पढ़ना केवल इनपुट की पूरी लाइन लौटाएगा। एक लाइन डिफ़ॉल्ट रूप से एनएल (एएससीआईआई एलएफ) द्वारा समाप्त की जाती है ... "; एक - और इस प्रकार हम करने के लिए है स्पष्ट रूप से सीरियल पोर्ट के लिए "गैर विहित" (या "कच्चे") ICANON के माध्यम से हमारे कोड में मोड (दूसरे शब्दों में, बस की स्थापना के माध्यम से openO_NONBLOCKनहीं पर्याप्त है) सेट इसके लिए उदाहरण "3.2 How can I read single characters from the terminal? - Unix Programming Frequently Asked Questions - 3. Terminal I/O" पर दिया गया है। एक बार ऐसा करने के बाद, writeread पर कॉल करने से serport उदाहरण (ऊपर) के लिए सीरियल पोर्ट को "सही ढंग से" सेट किया जाएगा।

तो मैंने उस writeread कोड को वापस सी में बदल दिया, आवश्यक प्रारंभिक सामग्री, साथ ही समय माप, स्ट्रिंग या फाइल भेजने की संभावना, और अतिरिक्त आउटपुट स्ट्रीम ('पढ़ने के लिए धारावाहिक डेटा' पाइपिंग ' एक अलग फ़ाइल)। कोड writeread.c और serial.h रूप में नीचे है, और इसके साथ, मैं निम्नलिखित बैश सत्र में की तरह कुछ कर सकते हैं:

$ ./writeread /dev/ttyUSB0 2000000 writeread.c 3>myout.txt 
stdalt opened; Alternative file descriptor: 3 
Opening port /dev/ttyUSB0; 
Got speed 2000000 (4107/0x100b); 
Got file/string 'writeread.c'; opened as file (4182). 

+++DONE+++ 
Wrote: 4182 bytes; Read: 4182 bytes; Total: 8364 bytes. 
Start: 1284422340 s 443302 us; End: 1284422347 s 786999 us; Delta: 7 s 343697 us. 
2000000 baud for 8N1 is 200000 Bps (bytes/sec). 
Measured: write 569.47 Bps, read 569.47 Bps, total 1138.94 Bps. 

$ diff writeread.c myout.txt 

$ ./writeread /dev/ttyUSB0 2000000 writeread.c 3>/dev/null 
stdalt opened; Alternative file descriptor: 3 
Opening port /dev/ttyUSB0; 
Got speed 2000000 (4107/0x100b); 
Got file/string 'writeread.c'; opened as file (4182). 

+++DONE+++ 
Wrote: 4182 bytes; Read: 4182 bytes; Total: 8364 bytes. 
Start: 1284422380 s -461710 us; End: 1284422388 s 342977 us; Delta: 8 s 804687 us. 
2000000 baud for 8N1 is 200000 Bps (bytes/sec). 
Measured: write 474.97 Bps, read 474.97 Bps, total 949.95 Bps. 

खैर:

  • पहले आश्चर्य - यह तेजी से हो जाता है तो मैं लिख रहा हूँ एक फाइल के लिए, अगर मैं /dev/null पर पाइप कर रहा हूँ!
  • इसके अलावा, लगभग 1000 बीपीएस प्राप्त करना - जबकि डिवाइस स्पष्ट रूप से 200000 बीपीएस के लिए सेट है !!

इस बिंदु पर, मैं सोच रहा हूँ कि मंदी है क्योंकि writeread.c में प्रत्येक प्रश्न के लिखित बाइट के बाद, हम एक ध्वज के लिए प्रतीक्षा पढ़ने बाधा से हटाए जाने की इससे पहले कि हम धारावाहिक बफर पढ़ने के लिए आगे बढ़ें। संभवतः, अगर पठन और लेखन अलग धागे थे, तो दोनों पढ़ने और लिखने से एकल read या write कॉल में बाइट्स के बड़े ब्लॉक का उपयोग करने का प्रयास किया जा सकता था, और इसलिए बैंडविड्थ बेहतर उपयोग किया जाएगा?

आह - (?! तो शायद इसी तरह की बाधा हैंडलर के लिए सभी को पढ़े संबंधित कार्यों को ले जाकर प्राप्त किया जा सकता कुछया, शायद बाधा हैंडलर अधिनियम, कुछ अर्थों में समानांतर में चल रहे है, एक "सूत्र" की तरह) ठीक है - इस बिंदु पर, मैं writeread.c जैसे मौजूदा कोड के लिए सुझाव/लिंक के लिए बहुत खुला हूं, लेकिन बहुमत से :) और, ज़ाहिर है, किसी भी अन्य संभावित लिनक्स टूल, या संभवतः बैश विधियों के लिए (हालांकि ऐसा लगता है कि बैश सक्षम नहीं होगा इस तरह के नियंत्रण को लागू करें ...)

चीयर्स!

 

writeread.c:

/* 
    writeread.c - based on writeread.cpp 
    [SOLVED] Serial Programming, Write-Read Issue - http://www.linuxquestions.org/questions/programming-9/serial-programming-write-read-issue-822980/ 

    build with: gcc -o writeread -Wall -g writeread.c 
*/ 

#include <stdio.h> 
#include <string.h> 
#include <stddef.h> 

#include <stdlib.h> 
#include <sys/time.h> 

#include "serial.h" 


int serport_fd; 

void usage(char **argv) 
{ 
    fprintf(stdout, "Usage:\n"); 
    fprintf(stdout, "%s port baudrate file/string\n", argv[0]); 
    fprintf(stdout, "Examples:\n"); 
    fprintf(stdout, "%s /dev/ttyUSB0 115200 /path/to/somefile.txt\n", argv[0]); 
    fprintf(stdout, "%s /dev/ttyUSB0 115200 \"some text test\"\n", argv[0]); 
} 


int main(int argc, char **argv) 
{ 

    if(argc != 4) { 
     usage(argv); 
     return 1; 
    } 

    char *serport; 
    char *serspeed; 
    speed_t serspeed_t; 
    char *serfstr; 
    int serf_fd; // if < 0, then serfstr is a string 
    int bytesToSend; 
    int sentBytes; 
    char byteToSend[2]; 
    int readChars; 
    int recdBytes, totlBytes; 

    char sResp[11]; 

    struct timeval timeStart, timeEnd, timeDelta; 
    float deltasec; 

    /* Re: connecting alternative output stream to terminal - 
    * http://coding.derkeiler.com/Archive/C_CPP/comp.lang.c/2009-01/msg01616.html 
    * send read output to file descriptor 3 if open, 
    * else just send to stdout 
    */ 
    FILE *stdalt; 
    if(dup2(3, 3) == -1) { 
     fprintf(stdout, "stdalt not opened; "); 
     stdalt = fopen("/dev/tty", "w"); 
    } else { 
     fprintf(stdout, "stdalt opened; "); 
     stdalt = fdopen(3, "w"); 
    } 
    fprintf(stdout, "Alternative file descriptor: %d\n", fileno(stdalt)); 

    // Get the PORT name 
    serport = argv[1]; 
    fprintf(stdout, "Opening port %s;\n", serport); 

    // Get the baudrate 
    serspeed = argv[2]; 
    serspeed_t = string_to_baud(serspeed); 
    fprintf(stdout, "Got speed %s (%d/0x%x);\n", serspeed, serspeed_t, serspeed_t); 

    //Get file or command; 
    serfstr = argv[3]; 
    serf_fd = open(serfstr, O_RDONLY); 
    fprintf(stdout, "Got file/string '%s'; ", serfstr); 
    if (serf_fd < 0) { 
     bytesToSend = strlen(serfstr); 
     fprintf(stdout, "interpreting as string (%d).\n", bytesToSend); 
    } else { 
     struct stat st; 
     stat(serfstr, &st); 
     bytesToSend = st.st_size; 
     fprintf(stdout, "opened as file (%d).\n", bytesToSend); 
    } 


    // Open and Initialise port 
    serport_fd = open(serport, O_RDWR | O_NOCTTY | O_NONBLOCK); 
    if (serport_fd < 0) { perror(serport); return 1; } 
    initport(serport_fd, serspeed_t); 

    sentBytes = 0; recdBytes = 0; 
    byteToSend[0]='x'; byteToSend[1]='\0'; 
    gettimeofday(&timeStart, NULL); 

    // write/read loop - interleaved (i.e. will always write 
    // one byte at a time, before 'emptying' the read buffer) 
    while (sentBytes < bytesToSend) 
    { 
     // read next byte from input... 
     if (serf_fd < 0) { //interpreting as string 
      byteToSend[0] = serfstr[sentBytes]; 
     } else { //opened as file 
      read(serf_fd, &byteToSend[0], 1); 
     } 

     if (!writeport(serport_fd, byteToSend)) { 
      fprintf(stdout, "write failed\n"); 
     } 
     //~ fprintf(stdout, "written:%s\n", byteToSend); 

     while (wait_flag == TRUE); 

     if ((readChars = readport(serport_fd, sResp, 10)) >= 0) 
     { 
      //~ fprintf(stdout, "InVAL: (%d) %s\n", readChars, sResp); 
      recdBytes += readChars; 
      fprintf(stdalt, "%s", sResp); 
     } 

     wait_flag = TRUE; // was == 
     //~ usleep(50000); 
     sentBytes++; 
    } 

    gettimeofday(&timeEnd, NULL); 

    // Close the open port 
    close(serport_fd); 
    if (!(serf_fd < 0)) close(serf_fd); 

    fprintf(stdout, "\n+++DONE+++\n"); 

    totlBytes = sentBytes + recdBytes; 
    timeval_subtract(&timeDelta, &timeEnd, &timeStart); 
    deltasec = timeDelta.tv_sec+timeDelta.tv_usec*1e-6; 

    fprintf(stdout, "Wrote: %d bytes; Read: %d bytes; Total: %d bytes. \n", sentBytes, recdBytes, totlBytes); 
    fprintf(stdout, "Start: %ld s %ld us; End: %ld s %ld us; Delta: %ld s %ld us. \n", timeStart.tv_sec, timeStart.tv_usec, timeEnd.tv_sec, timeEnd.tv_usec, timeDelta.tv_sec, timeDelta.tv_usec); 
    fprintf(stdout, "%s baud for 8N1 is %d Bps (bytes/sec).\n", serspeed, atoi(serspeed)/10); 
    fprintf(stdout, "Measured: write %.02f Bps, read %.02f Bps, total %.02f Bps.\n", sentBytes/deltasec, recdBytes/deltasec, totlBytes/deltasec); 

    return 0; 
} 

serial.h:

/* serial.h 
    (C) 2004-5 Captain http://www.captain.at 

    Helper functions for "ser" 

    Used for testing the PIC-MMC test-board 
    http://www.captain.at/electronic-index.php 
*/ 

#include <stdio.h> /* Standard input/output definitions */ 
#include <string.h> /* String function definitions */ 
#include <unistd.h> /* UNIX standard function definitions */ 
#include <fcntl.h> /* File control definitions */ 
#include <errno.h> /* Error number definitions */ 
#include <termios.h> /* POSIX terminal control definitions */ 
#include <sys/signal.h> 
#include <sys/stat.h> 
#include <sys/types.h> 

#define TRUE 1 
#define FALSE 0 

int wait_flag = TRUE; // TRUE while no signal received 

// Definition of Signal Handler 
void DAQ_signal_handler_IO (int status) 
{ 
    //~ fprintf(stdout, "received SIGIO signal %d.\n", status); 
    wait_flag = FALSE; 
} 


int writeport(int fd, char *comm) 
{ 
    int len = strlen(comm); 
    int n = write(fd, comm, len); 

    if (n < 0) 
    { 
     fprintf(stdout, "write failed!\n"); 
     return 0; 
    } 

    return n; 
} 


int readport(int fd, char *resp, size_t nbyte) 
{ 
    int iIn = read(fd, resp, nbyte); 
    if (iIn < 0) 
    { 
     if (errno == EAGAIN) 
     { 
      fprintf(stdout, "SERIAL EAGAIN ERROR\n"); 
      return 0; 
     } 
     else 
     { 
      fprintf(stdout, "SERIAL read error: %d = %s\n", errno , strerror(errno)); 
      return 0; 
     } 
    } 

    if (resp[iIn-1] == '\r') 
     resp[iIn-1] = '\0'; 
    else 
     resp[iIn] = '\0'; 

    return iIn; 
} 


int getbaud(int fd) 
{ 
    struct termios termAttr; 
    int inputSpeed = -1; 
    speed_t baudRate; 
    tcgetattr(fd, &termAttr); 
    // Get the input speed 
    baudRate = cfgetispeed(&termAttr); 
    switch (baudRate) 
    { 
     case B0:  inputSpeed = 0; break; 
     case B50:  inputSpeed = 50; break; 
     case B110: inputSpeed = 110; break; 
     case B134: inputSpeed = 134; break; 
     case B150: inputSpeed = 150; break; 
     case B200: inputSpeed = 200; break; 
     case B300: inputSpeed = 300; break; 
     case B600: inputSpeed = 600; break; 
     case B1200: inputSpeed = 1200; break; 
     case B1800: inputSpeed = 1800; break; 
     case B2400: inputSpeed = 2400; break; 
     case B4800: inputSpeed = 4800; break; 
     case B9600: inputSpeed = 9600; break; 
     case B19200: inputSpeed = 19200; break; 
     case B38400: inputSpeed = 38400; break; 
     case B115200: inputSpeed = 115200; break; 
     case B2000000: inputSpeed = 2000000; break; //added 
    } 
    return inputSpeed; 
} 


/* ser.c 
    (C) 2004-5 Captain http://www.captain.at 

    Sends 3 characters (ABC) via the serial port (/dev/ttyS0) and reads 
    them back if they are returned from the PIC. 

    Used for testing the PIC-MMC test-board 
    http://www.captain.at/electronic-index.php 

*/ 


int initport(int fd, speed_t baudRate) 
{ 
    struct termios options; 
    struct sigaction saio; // Definition of Signal action 

    // Install the signal handler before making the device asynchronous 
    saio.sa_handler = DAQ_signal_handler_IO; 
    saio.sa_flags = 0; 
    saio.sa_restorer = NULL; 
    sigaction(SIGIO, &saio, NULL); 

    // Allow the process to receive SIGIO 
    fcntl(fd, F_SETOWN, getpid()); 
    // Make the file descriptor asynchronous (the manual page says only 
    // O_APPEND and O_NONBLOCK, will work with F_SETFL...) 
    fcntl(fd, F_SETFL, FASYNC); 
    //~ fcntl(fd, F_SETFL, FNDELAY); //doesn't work; //fcntl(file, F_SETFL, 0); 

    // Get the current options for the port... 
    tcgetattr(fd, &options); 
/*  
    // Set port settings for canonical input processing 
    options.c_cflag = BAUDRATE | CRTSCTS | CLOCAL | CREAD; 
    options.c_iflag = IGNPAR | ICRNL; 
    //options.c_iflag = IGNPAR; 
    options.c_oflag = 0; 
    options.c_lflag = ICANON; 
    //options.c_lflag = 0; 
    options.c_cc[VMIN] = 0; 
    options.c_cc[VTIME] = 0; 
*/ 
    /* ADDED - else 'read' will not return, unless it sees LF '\n' !!!! 
    * From: Unix Programming Frequently Asked Questions - 3. Terminal I/O - 
    * http://www.steve.org.uk/Reference/Unix/faq_4.html 
    */ 
    /* Disable canonical mode, and set buffer size to 1 byte */ 
    options.c_lflag &= (~ICANON); 
    options.c_cc[VTIME] = 0; 
    options.c_cc[VMIN] = 1; 

    // Set the baud rates to... 
    cfsetispeed(&options, baudRate); 
    cfsetospeed(&options, baudRate); 

    // Enable the receiver and set local mode... 
    options.c_cflag |= (CLOCAL | CREAD); 
    options.c_cflag &= ~PARENB; 
    options.c_cflag &= ~CSTOPB; 
    options.c_cflag &= ~CSIZE; 
    options.c_cflag |= CS8; 

    // Flush the input & output... 
    tcflush(fd, TCIOFLUSH); 

    // Set the new options for the port... 
    tcsetattr(fd, TCSANOW, &options); 

    return 1; 
} 


/* 
    ripped from 
    http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/stty.c 
*/ 

#define STREQ(a, b)  (strcmp((a), (b)) == 0) 

struct speed_map 
{ 
    const char *string;  /* ASCII representation. */ 
    speed_t speed;  /* Internal form. */ 
    unsigned long int value; /* Numeric value. */ 
}; 

static struct speed_map const speeds[] = 
{ 
    {"0", B0, 0}, 
    {"50", B50, 50}, 
    {"75", B75, 75}, 
    {"110", B110, 110}, 
    {"134", B134, 134}, 
    {"134.5", B134, 134}, 
    {"150", B150, 150}, 
    {"200", B200, 200}, 
    {"300", B300, 300}, 
    {"600", B600, 600}, 
    {"1200", B1200, 1200}, 
    {"1800", B1800, 1800}, 
    {"2400", B2400, 2400}, 
    {"4800", B4800, 4800}, 
    {"9600", B9600, 9600}, 
    {"19200", B19200, 19200}, 
    {"38400", B38400, 38400}, 
    {"exta", B19200, 19200}, 
    {"extb", B38400, 38400}, 
#ifdef B57600 
    {"57600", B57600, 57600}, 
#endif 
#ifdef B115200 
    {"115200", B115200, 115200}, 
#endif 
#ifdef B230400 
    {"230400", B230400, 230400}, 
#endif 
#ifdef B460800 
    {"460800", B460800, 460800}, 
#endif 
#ifdef B500000 
    {"500000", B500000, 500000}, 
#endif 
#ifdef B576000 
    {"576000", B576000, 576000}, 
#endif 
#ifdef B921600 
    {"921600", B921600, 921600}, 
#endif 
#ifdef B1000000 
    {"1000000", B1000000, 1000000}, 
#endif 
#ifdef B1152000 
    {"1152000", B1152000, 1152000}, 
#endif 
#ifdef B1500000 
    {"1500000", B1500000, 1500000}, 
#endif 
#ifdef B2000000 
    {"2000000", B2000000, 2000000}, 
#endif 
#ifdef B2500000 
    {"2500000", B2500000, 2500000}, 
#endif 
#ifdef B3000000 
    {"3000000", B3000000, 3000000}, 
#endif 
#ifdef B3500000 
    {"3500000", B3500000, 3500000}, 
#endif 
#ifdef B4000000 
    {"4000000", B4000000, 4000000}, 
#endif 
    {NULL, 0, 0} 
}; 

static speed_t 
string_to_baud (const char *arg) 
{ 
    int i; 

    for (i = 0; speeds[i].string != NULL; ++i) 
    if (STREQ (arg, speeds[i].string)) 
     return speeds[i].speed; 
    return (speed_t) -1; 
} 



/* http://www.gnu.org/software/libtool/manual/libc/Elapsed-Time.html 
Subtract the `struct timeval' values X and Y, 
storing the result in RESULT. 
Return 1 if the difference is negative, otherwise 0. */ 
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) 
{ 
    /* Perform the carry for the later subtraction by updating y. */ 
    if (x->tv_usec < y->tv_usec) { 
    int nsec = (y->tv_usec - x->tv_usec)/1000000 + 1; 
    y->tv_usec -= 1000000 * nsec; 
    y->tv_sec += nsec; 
    } 
    if (x->tv_usec - y->tv_usec > 1000000) { 
    int nsec = (x->tv_usec - y->tv_usec)/1000000; 
    y->tv_usec += 1000000 * nsec; 
    y->tv_sec -= nsec; 
    } 

    /* Compute the time remaining to wait. 
     tv_usec is certainly positive. */ 
    result->tv_sec = x->tv_sec - y->tv_sec; 
    result->tv_usec = x->tv_usec - y->tv_usec; 

    /* Return 1 if result is negative. */ 
    return x->tv_sec < y->tv_sec; 
} 
संबंधित मुद्दे