Soros port kezelése - amit kiírok rá, azt olvasom vissza

Fórumok

Sziasztok...!

Írtam egy kis C programot a Serial Programming HOWTO alapján (holnap behozom), viszont az a gondom, hogy megnyitás után amit write () -tal kiírok a soros portra, a következő read () azt olvassa vissza, és nem az eszköz válaszát.
Van erre a hibára valami tippetek?

Hozzászólások

Be van kapcsolva az echo? (ATE paranccsal lehet ki be kapcsolni, feltéve, hogy egy modemről van szó egyáltalán).

Talan a hozzakotott modemen ki kellene kapcsolni a sorosport echo-zasat.

Csak a regifajta signal kezeles miatt nem fordul le, ami csak az aszinkron feldolgozasnal van, amire neked nem valoszinu hogy szukseged van.
Es nem a program echo-zik, hanem a sorosportra kotott modem. Az azert jo, mert ha terminalbol hasznalod akkor latod azt amit beirsz.
En is csak azt tudom ajanlani amit popacsek, hogy eloszor minicom-mal probald ki, majd itt add ki az ATE0 parancsot (latni fogod amit beirsz).
Es ne felejtsd el, hogy az AT parancsokat "\r"-el(CR) zard le.

nagyon nagy FIXME, de osregi programodzasi ismereteim emlekebol, nem kell flusholni azt a puffert valamikor? Mar nem emlexem hogy ez Pascal volt vagy C vagy C++, de volt valami ilyen hogy "beragadt" valami egy I/O pufferbe amit ki kellett hajitani mielott normalisan lehetett hasznalni.

Én így használom... hátha ez segít...


/* soros port megnyitasa */
int OpenPort(const char *PortName){
    struct termios TermIO;
    int Port=open(PortName,O_RDWR|O_NOCTTY);
    if(Port<0) fprintf(stderr,"%s %s\n",PortName,strerror(errno));
    else{
        TermIO.c_iflag=IGNPAR|ICRNL;           /* input mode flags */
        TermIO.c_oflag=0;                      /* output mode flags */
        TermIO.c_cflag=B9600|CS8|CLOCAL|CREAD; /* control mode flags */
        TermIO.c_lflag=ICANON|ISIG;            /* local mode flags */
                                               /* control characters */
        TermIO.c_cc[VINTR]   =0;   /* Ctrl-c */
        TermIO.c_cc[VQUIT]   =0;   /* Ctrl-\ */
        TermIO.c_cc[VERASE]  =0;   /* del */
        TermIO.c_cc[VKILL]   =0;   /* @ */
        TermIO.c_cc[VEOF]    =4;   /* Ctrl-d */
        TermIO.c_cc[VTIME]   =0;   /* inter-character timer unused */
        TermIO.c_cc[VMIN]    =0;   /* blocking read until 1 character arrives */
        TermIO.c_cc[VSWTC]   =0;   /* '\0' */
        TermIO.c_cc[VSTART]  =0;   /* Ctrl-q */
        TermIO.c_cc[VSTOP]   =0;   /* Ctrl-s */
        TermIO.c_cc[VSUSP]   =0;   /* Ctrl-z */
        TermIO.c_cc[VEOL]    =0; /* '\0' */
        TermIO.c_cc[VREPRINT]=0;   /* Ctrl-r */
        TermIO.c_cc[VDISCARD]=0;   /* Ctrl-u */
        TermIO.c_cc[VWERASE] =0;   /* Ctrl-w */
        TermIO.c_cc[VLNEXT]  =0;   /* Ctrl-v */
        TermIO.c_cc[VEOL2]   =0;   /* '\0' */
        tcflush(Port,TCIFLUSH);
        tcsetattr(Port,TCSANOW,&TermIO);
    }
    return Port;
}

/* soros port lezarasa */
void ClosePort(int Port){
  if(0 < Port) if(close(Port)<0) fprintf(stderr,"%s\n",strerror(errno));
}

/* egy karakter irasa a soros portra */
int WritePort(int Port,char Chr){
    if(write(Port,Chr,1)!=1) return EXIT_FAILURE;
    return EXIT_SUCCESS;
}

/* olvasas a sorosportrol */
int ReadPort(int Port){
    int b=0;
    ioctl(Port,FIONREAD,&b);
    if(b==0) return EXIT_FAILURE;
    memset(Answer,0,sizeof(Answer));
    read(Port,Answer,sizeof(Answer));
    return EXIT_SUCCESS;
}

Remélem hogy nem rontottam el, mert egy nagyobb kód részletét próbáltam ide írni valami egyszerűb formában...

--
maszili


Nos, meglett a hiba kiváltója, csak az okát nem értem.

Ugyanis a soros portot először elkezdtem a szokványos fájlkezelő eszközökkel használni. És működött is. Mint kiderült, az echo -val nem is volt gond, mert míg az scmxx -et strace -val felderítve mindig az derült ki, hogy a kiküldött "ATZ\r" -ra mindig "OK\r" -ot ír az eszköz. Viszont ltrace -t használva kiderült, hogy a fenti karaktersorozatra nem egyszerűen "OK\r" -t ír vissza az eszköz, hanem "ATZ\r OK\r" -ot. És mivel én csak "egyszavas" válaszra számítottam, ezért érzékeltem azt, hogy a porton azt kapom vissza, amit kiírtam rá (lásd topicindító kérdés).

Szóval, lett egy ilyen alap-változat, amely működik is, a visszaadott válasz első futtatáskor néha egyszerű "OK\r", a legtöbb esetben "AZT\r OK\r".
Forrás:


#include <stdio.h>
#include <stdlib.h>

#define modem "/dev/ttyS0"

int main (int argc, char* argv[])  {
  FILE * serial_port;
  char buffer[200];
  serial_port = fopen (modem, "r+");
  if (!serial_port)  {
    perror (modem);
    exit (-1);
  }
  printf ("kiment: %d\n", fputs ("ATZ\r", serial_port));
  while (1)  {
    fscanf (serial_port, "%s", buffer);
    printf ("+++%s+++\n", buffer);
  }
  fflush (serial_port);
  fclose (serial_port);
}


Ezekután úgy gondoltam, hogy a port-beállítások miatt lemegyek egy kezelési-szinttel lejjebb, az open/read/write/close szintjére, hogy módosíthassam a port szükséges paramétereit. És kiderült, mi a baj az általatok írt, a HOWTO -ban szereplő, esetleg más helyeken fellelt megoldásokkal.
Ez a példaprogram született, nem kanonikus módban kezeli a portot.
Forrás:


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

#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS0"

int main (int argc, char* argv[])  {
  int fd, c;
  char buffer[200];
  struct termios oldtio, newtio;
  fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
  if (fd < 0)  {
    perror (MODEMDEVICE);
    exit (-1);
  }
  tcgetattr(fd, &oldtio);
  bzero(&newtio, sizeof(newtio));
  newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  newtio.c_cc[VTIME]    = 0;
  newtio.c_cc[VMIN]     = 1;
  tcflush(fd, TCIFLUSH);
  /* tcsetattr(fd, TCSANOW, &newtio); */
  printf ("kiirt: %d\n", write (fd, "ATZ\r", 4));
  while (1)  {
    read (fd, &c, 1);
    printf ("+++%c+++\n", c);
  }
  /* tcsetattr(fd, TCSANOW, &oldtio); */
  close (fd);
}


Itt ha a forrásprogram vége felé található (34. sor) tcsetattr függvényt kikommentezem, akkor minden működik szépen. Ha azonban benthagyoma forrásban, hogy beállítsa a port paramétereit, akkor olvasáskor a read függvény nem olvas semmit, és blokkolódik, azaz a program futása ott megszakad. Ez történik akkor is, ha nem kanonikus módban szeretném kezelni a portot. A port annyira blokkolódik, hogy hiába fordítom újra a programot, kikommentezve azt a sort, már az sem olvas semmit.
Blokkolás esetén az eszköz kikapcsolása sem segít, viszont ha lefuttatom az scmxx programot, akkor újra tudom használni a program azon változatát, amelyben az adott sor ki van kommentezve.

Nos, ilyenkor mi a teendő (az scmxx forrása elég nagy ahhoz, hogy átbogarásszam, annyit már megtaláltam, hogy kanonikus és aszinkron módon (szignálkezeléssel) használja a portot, de nekem ez a mód nem lenne túlságosan megfelelő.

U.i.: a tcsetattr függvény visszatérési értéke mindkét (kanonikus és nem kanonikus) esetben 0.

U.i.: A Drupal kiszedte a források include részéből az állományok neveit...  :(