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?
- 5613 megtekintés
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).
- A hozzászóláshoz be kell jelentkezni
A soros port megnyitása után kiküldöm az "ATZ" szöveget, amire egy "OK" -nak kellene jönnie válasznak. Ehelyett visszaolvasom az "ATZ" -t. Úgy gondolom, hogy az "ATZ" elött érdemben nem tudok kiadni más parancsot, így "ATE" -t sem.
- A hozzászóláshoz be kell jelentkezni
AT&V -vel kiírja az aktuális konfigurációt, abban azt is, hogy az echo be van-e kapcsolva.
Esetleg próbálgasd a minicom-al.
- A hozzászóláshoz be kell jelentkezni
Próbáltam a minicom -ot tegnap, de sehogy sem tudtam elérni, hogy manuálisan tudjak parancsokat kiadni a soros porton lévő eszköznek. Valaki használta már ilyen célra?
- A hozzászóláshoz be kell jelentkezni
Először "minicom -s" -el indítsd, és úgy állítsd be a minicom-nak, hogy melyik soros portot kezelje (érdemes elmenteni a beállításokat).
Azután már elméletileg mennie kellene a dolognak.
- A hozzászóláshoz be kell jelentkezni
Talan a hozzakotott modemen ki kellene kapcsolni a sorosport echo-zasat.
- A hozzászóláshoz be kell jelentkezni
Ezt a példát vettem alapul, akkor ezekszerint ez is echo -zik...?
- A hozzászóláshoz be kell jelentkezni
2001. -es a HOWTO, és 2.0.29 -es kernellel lettek a példák tesztelve... ez a példa pl. le sem fordul 2.6.9 -es kernel alatt...
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
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.
- A hozzászóláshoz be kell jelentkezni
É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
- A hozzászóláshoz be kell jelentkezni
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... :(
- A hozzászóláshoz be kell jelentkezni