Kirjoittaja Aihe: [ ratkaistu, ainakin osittain ] Stty ja fstream -kokeiluja ja ongelmia 2  (Luettu 6090 kertaa)

teele

  • Käyttäjä
  • Viestejä: 852
    • Profiili
Tällä kertaa yritin lukea vuota c++ :n sijaan raaka-c:llä, eikä virheitä ole ilmaantunut ainakaan niin, että niistä olisi tullut valituksia tai toiminta olisi häiriintynyt.

Nyt kuitenkin ongelmana on se, että vuon (streamin) seuraaminen vie  suoritintehoja niin, että läppärin tuuletin pyörii isoilla kierroksilla, vaikka muuten ei juuri koskaan.

Vuon tarkkailu tehdään alla olevassa silmukassa, joka luultavasti on syyllinen suoritintehojen rohmuamiseen.

Koodia: [Valitse]
while (c!='q')
        {
                // if new data is available on the console, send it to the serial port
                if (read(STDIN_FILENO,&c,1)>0)  write(tty_fd,&c,1);
                // if new data is available on the serial port, print it out
                if (read(tty_fd,&c,1)>0)        write(STDOUT_FILENO,&c,1);
                sleep(0.5);   // <----   lisäsin tämän, mutta vaikutus aika olematon
        }


Alkuperäisessä koodissa ei ollut nukuntaa, lisäsin sen, mutta vaikutus on aika olematon. Ehkä tuuletin käy vähän pienemmillä kierroksilla.

Pitäisikö sleepin sijasta seuranta laittaa omaan säikeeseen tms.
« Viimeksi muokattu: 17.06.16 - klo:10.10 kirjoittanut teele »

_Pete_

  • Käyttäjä
  • Viestejä: 1845
  • Fufufuuffuuu
    • Profiili
Vs: Stty ja fstream -kokeiluja ja ongelmia 2
« Vastaus #1 : 24.05.16 - klo:12.13 »

Koodia: [Valitse]
while (c!='q')
        {
                // if new data is available on the console, send it to the serial port
                if (read(STDIN_FILENO,&c,1)>0)  write(tty_fd,&c,1);
                // if new data is available on the serial port, print it out
                if (read(tty_fd,&c,1)>0)        write(STDOUT_FILENO,&c,1);
                sleep(0.5);   // <----   lisäsin tämän, mutta vaikutus aika olematon
        }



http://linux.die.net/man/3/read

Olisikohan kyse siitä, että kuten manuaalissa sanotaan, read() yrittää lukea parametrinä välitetyn määrän, jos ei kuitenkaan ole yhtään saatavilla palautuu 0 ... Tuo siis juurikin aiheuttaa ohjelmassasi busy-loopin joka pyörii niin nopeasti kuin pystyy ja vie paljon CPU:ta.

Parempi tapa olisi käyttää blockkaavaa read kutusua, joka jää odottamaan kunnes oikeasti on jotain saatavilla lukee sen ja vasti sitten kirjoittaa toiseen putkeen luetun ...


teele

  • Käyttäjä
  • Viestejä: 852
    • Profiili
Vs: Stty ja fstream -kokeiluja ja ongelmia 2
« Vastaus #2 : 02.06.16 - klo:23.04 »
sain sen suorittimen rohmuamisen loppumaan pollauksella, ja nyt toiminta on vähän järkevämpää.

Muutin ohjelmaa myös niin, että se lukee päätteeltä rivin ja vasta sitten kirjoittaa sen sarjalaitteelle, joka muokkaa sitä omalla tavallaan ja lähettää muokatun tekstin taikaisin päätteelle.

Nyt ongelmana on se, että vain alle 32 merkin mittaiset rivit tulevat käsitellyiksi. Pitemmän rivin loppuosat jäävät johonkin puskuriin ja tulevat sieltä merkki kerrallaan.

Olisikohan mahdollista, että kääntäjä optimoi koodia niin, että se aloittaa laitteelta lukemisen jo ennen kuin laite on saanut luettua kaikki merkit. Kirjoitaminen ja lukeminen ovat kyllä peräkkäin samssa ohjelmassa, enkä ole laittanut yhtään säiettä ohjelmaan. Ehkä pitäisi laittaa kirjoitussäie ja sitten odottaa, että se on valmis, ja vasta sitten aloittaa lukeminen.

Sekunnin torkkuaika kirjoittamisen ja lukemisen välillä näyttää auttavan niin, että pitemmätkin rivit näkyvät oikein laitteen muutosten jälkeen pääteellä. Mutta tauon pitää olla juri 1 sekunti, 0,95 sekuntia ei käy.

nm

  • Käyttäjä
  • Viestejä: 16429
    • Profiili
Vs: Stty ja fstream -kokeiluja ja ongelmia 2
« Vastaus #3 : 02.06.16 - klo:23.42 »
Nyt ongelmana on se, että vain alle 32 merkin mittaiset rivit tulevat käsitellyiksi. Pitemmän rivin loppuosat jäävät johonkin puskuriin ja tulevat sieltä merkki kerrallaan.

Olisikohan mahdollista, että kääntäjä optimoi koodia niin, että se aloittaa laitteelta lukemisen jo ennen kuin laite on saanut luettua kaikki merkit. Kirjoitaminen ja lukeminen ovat kyllä peräkkäin samssa ohjelmassa, enkä ole laittanut yhtään säiettä ohjelmaan. Ehkä pitäisi laittaa kirjoitussäie ja sitten odottaa, että se on valmis, ja vasta sitten aloittaa lukeminen.

Et tarvitse säikeitä, ellet halua tehdä jotain muuta samalla, kun odotat siirron valmistumista. Odottaminen taas onnistuu termios-funktiolla tcdrain:

https://en.wikibooks.org/wiki/Serial_Programming/termios#Line-Control_Functions


_Pete_

  • Käyttäjä
  • Viestejä: 1845
  • Fufufuuffuuu
    • Profiili
Vs: Stty ja fstream -kokeiluja ja ongelmia 2
« Vastaus #4 : 03.06.16 - klo:07.32 »
Entäpä jos lukemiseen ja kirjoittamiseen käyttäisi ihan näitä:

http://linux.die.net/man/3/fread

Eli blokkaava luku....


nm

  • Käyttäjä
  • Viestejä: 16429
    • Profiili
Vs: Stty ja fstream -kokeiluja ja ongelmia 2
« Vastaus #5 : 03.06.16 - klo:09.30 »
Entäpä jos lukemiseen ja kirjoittamiseen käyttäisi ihan näitä:

http://linux.die.net/man/3/fread

Eli blokkaava luku....

Myös read ja write ovat blokkaavia, mutta sarjaportin sisäinen puskurointi aiheuttaa havaitsemasi ongelman. Fread ja fwrite käyttävät lisäksi omaa puskuriaan, joka ei ainakaan auta asiaa.

termios tai joku sen päälle rakennettu apukirjasto on oikea ratkaisu sarjaporttihommiin.

teele

  • Käyttäjä
  • Viestejä: 852
    • Profiili
Vs: Stty ja fstream -kokeiluja ja ongelmia 2
« Vastaus #6 : 03.06.16 - klo:16.31 »
Koska kokeilussani sarjalaite tulostaa kirjaimet takaisin isoina kirjaimina ja tämä tulos on se, jota olen voinut tarkkailla, on mahdollista, että ongelma liittyykin siihen, että laite tulostaa ensin nopeasti 32 merkkiä ja sitten jostain syystä viivyttelee. Se tulostaa aina kaikki, mitä olen syöttänyt sitten sekunnin tauon jälkeen, esimerkiksi 75 merkkiä tulevat oikein hienosti ( eikä 75 ole edes 2*32. )

Ohjeiden mukaan read(fd, buf, n) palauttaa luettujen merkkien määrän, jos yritetään lukea n merkkiä varastoon buf vuosta fd.

Mutta olisiko mitään keinoa nähdä, montako merkkiä on odottamassa valmiina linuxin lukupuskurissa jo ennen kuin käyttää read -käskyä. Silloin voisin tarkistaa, mikä on tilanne lukemista odottavien merkkien osalta juuri ennen, kuin 1 sekunnin taukoaika on kulunut.

Tilanne on siis se, että 32 merkkiä tulevat näkyville melkein heti, samoin esim. kaikki 75 merkkiä heti sekunnin odotusajan jälkeen. tcdrain ei näytä vaikuttavan asiaan, vain sleep(1) vaikuttaa.

Luvut 1 sekunti ja 32 merkkiä viittaavat vähän siihen, että nyt ei ole kyse yhteyden siirtonopeuden määräämästä odottelusta. Erityisesti kun nopeuden nostaminen 9600 merkistä 38400 merkkiin ei muuta vaadittavaa odotteluaikaa tai saatavien merkkien lukumäärää.
« Viimeksi muokattu: 03.06.16 - klo:16.33 kirjoittanut teele »

teele

  • Käyttäjä
  • Viestejä: 852
    • Profiili
Vs: Stty ja fstream -kokeiluja ja ongelmia 2
« Vastaus #7 : 17.06.16 - klo:10.08 »

Tämän hetken kokeiluiden mukaan sueraava koodi vaikuttaa toimivan. Luettava rivi on vain merkattava tarpeeksi pitkäksi.

Yksi ongelmahan on, että sarjaporttiin päätteeltä lähtevä ja sarjaportista päätteelle tuleva teksti ovat kummatkin samassa (pääte)ikkunassa. Sarjaportista pienellä viiveellä tuleva vastausteksti voi sotkea uutta kirjoitettavaa tekstiä.

Olisikohan apua, jos tuleva teksti lähetettäisiin vaikka std::err -vuohon, ja miten sen saisi näkymään omassa ikkunassaan.

Koodia: [Valitse]

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

#include <sys/poll.h>

#include <ctype.h>  // vain isspacea varten

int main(int argc,char** argv)
{
        struct termios tio;  // käytettävät asetukset
        struct termios old_stdio;  // vanhat sarjatiedsotoasetukset
        int tty_fd;  // sarjatiedoston tiedostonumero

        struct pollfd fds[1];  // polling -rakenteet
        int pollrc; // luettujen merkkien määrä pollista

        unsigned char cbuf[80];
        cbuf[0]='d'; // luettava merkki, ei ainkaan \n alussa

        if(argc < 2) // tarvitaan sarjavuon nimi käynnistyksessä
          { printf("Usage %s ",argv[0]);
            printf(" /dev/ttyUSB0 (for example) \n" );
            exit(11);
          }

        memset(&tio,0,sizeof(tio)); // nollataan sarjavuon asetukset
        tio.c_iflag=0;
        tio.c_oflag=0;
        tio.c_cflag=CS8|CREAD|CLOCAL;     // 8n1, see termios.h for more information
        tio.c_lflag=0;
        tio.c_cc[VMIN]=1;  // 1 merkki riittää käsittelyn aloittamiseen
        tio.c_cc[VTIME]= 1; // 5 sarjatiedoston merkkiä voidaan odottaa

        tty_fd=open(argv[1], O_RDWR | O_NONBLOCK); // avataan rw ja noblcking -asetuksin   
        cfsetospeed(&tio,B9600);     // 9600 baudia sarjatiedostn kirjoitusnopeudeksi
        cfsetispeed(&tio,B9600);     // 9600 baudia sarjatiedostn lukunopeudeksi

        tcsetattr(tty_fd,TCSANOW,&tio);

        fds[0].fd = tty_fd;      // tarkkailtavan tiedoston tunnistenumero
        fds[0].events = POLLIN ; // valitaan tuleva tieto tarkkailtavaksi

       while( 1 )
        {

          unsigned char ch;
          int k = 0;
          while( (ch = getchar()) != '\n' )
            {
              cbuf[k++] = ch;
            }   // vain merkit käsitellään, \n ei mene mukaan

          write(tty_fd, cbuf, k); // /tiedostonumero, char-osoite, merkkilkm)
          tcdrain( tty_fd ); //tämä ei auta, pitkä rivi loppuu kesken
          sleep(1);  // tämän avulla pitkä rivi tulostuu, miksi ???????????

          pollrc = poll(fds, 1, 1000); // onko vastaus tulossa 1000 ms aikana
          if(pollrc < 0) // poll -virhe, aikaylitys ehkä, tai muu virhe
            {
              perror("poll");
            }
          else

          if( pollrc > 0)  // ainakin poll onnistui ilman virhettä
            {
              if(fds[0].revents & POLLIN ) // merkkejä on tulossa
                {
                  ssize_t rc = read(tty_fd, cbuf, 79 ); // luettiin rc kpl merkkejä
                  if(rc > 0) 
                    {
                            /////printf("%zu %s\n", rc, " chars read from stream" );
                            write(0, "\n", 1);
                      write(0, cbuf, rc); // k ???, merkki saatu sarjavuosta, sen voi käsitellä ohjelmassa
                           write(0, "\n", 1);
                      fds[0].revents = 0; // nollataan paluu(virhe)ilmoitukset
                    }
                 }
              } // if( pollrc > 0) loppuu

        } // while loppuu

        close(tty_fd); // suljetaan sarjavuo
        tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio); // palautetaan pääteasetukset
        printf("\n %s \n", "program ended ");
        return EXIT_SUCCESS;
}