[prog-it] Re: porta seriale

  • From: "Seeman79" <Seeman79@xxxxxxxxx>
  • To: <prog-it@xxxxxxxxxxxxx>
  • Date: Sun, 02 Jun 2002 12:44:41 +0100


From:"valerio" <valerio_ligabue@xxxxxxxxx>
Subject: [prog-it] Re: porta seriale
Date: Thu, 30 May 2002 20:14:44 +0200

| Grazie Seeman, ma penso che tu stia sopravalutando
| le mie capacita` di comprensione.
Oppure tu le stai sottovalutando?
Se rileggi con attenzione le mie mail, non ci troverai
nulla di _veramente_ complicato.

| Gia` il fatto di dover mettere dell'assembler in un
| listato C mi mette un po' a disagio.
Beh il disagio ti puo' essere dato dal fatto che magari
non sai (ancora) come si fa... ma una volta che lo impari
tutto passa; e' un po' come imparare a guidare...

| Ovviero` il problema consultando il buonb vecchio TrickyC
| che sicuramente sapra` aiutarmi.
Non l'ho mai letto, ma mi pare che parli di programmazione
C in ambiente DOS...

| Ma partiamo dal basso.
Questa e' una decisione saggia.

| Mettiamo di voler mandare alto un pin della porta parallela
| (un po' come quel giochino fatto in Delphi su IoProgrammo
| del mese scorso).
Chiedo venia ma non leggendo quel periodico (deduco che sia
un mensile dalle tue parole), non so di che giochino tu stia
parlando.

| Con il C, e ovviamente sbattendomene della grafica, passo
| per passo come si sviluppa il "progetto".
E' una domanda? :)
Beh nelle mie scorse mail ti ho detto tutto cio' di cui hai
veramente bisogno, sia in DOS che in sistemi GNU/Linux.
Visto che leggi TrickyC, deduco che tu voglia iniziare sotto
DOS; se rileggi le mie mail troverai indicato:
- La libreria che devi includere (dos.h)
- Le funzioni che devi usare per leggere (inportb) e per scrivere
  (outportb) sulla porta che vuoi.
- I prototipi di tali funzioni:
  int inportb(int indirizzo_porta);
        void outportb(int indirizzo_porta, unsigned char byte_da_scrivere);
- Gli indirizzi piu' comuni per le porte seriali, con indicazione
  di dove puoi reperirli per il tuo sistema.
        
Come puoi notare ti avevo indicato anche una strada che ti
permettesse di risolvere il tuo problema senza l'uso di codice
assembler (in realta' l'assembler lo usano loro al posto tuo; sono
implementate usando le istruzioni 80x86 IN e OUT).

L'unica cosa che ti viene demandata e' quella di conoscere il
protocollo di comunicazione che devi usare per parlare con l'hardware
che ti interessa.

Se, ad esempio, tu volessi scrivere un "dialer", dovresti conoscere
i comandi AT per comunicare con il modem (non e' l'unico protocollo
esistente per questo scopo).

Ora la domanda e'... quando hai provato a scrivere del codice,
cos'e' che non ti e' riuscito di fare?

Ad ogni modo; premetto che ieri sera ho bevuto oltremodo, che
attualmente non sono a casa mia e che ho ancora la testa che mi
fa male, pero', sfidando la sorte, ti posto queste righe di codice
che ti ho fatto qui (con generosa donazione dei "materiali" da parte
della "padrona di casa"), e che, forse, ti possono aiutare a
comprendere meglio il problema.

Comunico con la porta seriale COM2 (in dos... /dev/ttyS1 in sistemi
GNU/Linux) dove, su questo computer, c'e' attaccato un modem.

Il programma e' fatto "alla veloce" per cui non inizializza niente;
per farlo funzionare e' necessario che tu esegua _prima_ il
"diagnostica" nel menu' modem del pannello di controllo (oppure
qualsiasi altra cosa che inizializzi il modem); fatto quello puoi
far partire il programma.

Non so se conosci i comandi AT, cmq, in breve, la cosa funziona cosi':
una stringa valida per il modem, in generale, inizia con la coppia di
lettere "AT", seguita da uno o piu' codici operativi che vengono
interpretati ed eseguiti nell'ordine in cui li scrivi.

Nel mio programma, in particolare, mando una stringa del tipo:
AT V0 I7
 ^  ^  ^
 |      |        |-- La serie di comandi In (1 <= n <= 7) ci danno informazioni
 |  |      relative al modem.
 |  |
 |  |----- V stabilisce il formato di risposta del modem;
 |         0 = NUMERICA
 |
 |-------- E' la solita "intestazione" del codice.       


Cosi' facendo richiediamo "l'informazione 7" e vogliamo che il modem,
al termine della transazione, ci fornisca una risposta numerica (in
questo caso 0... si spera) anziche' la stringa "OK".

==========================BEGIN CODE HERE==========================
#include <dos.h>
#include <stdio.h>

#define COM2 0x2F8
#define MAX_BUFF 4096
#define STRINGA "ATV0I7"

int main(void)
  {
    unsigned int i = 0;
    char buff[MAX_BUFF];

    while(STRINGA[i] != '\0')
      {
        outportb(COM2, (unsigned char)STRINGA[i]);
        i++;
      }

    outportb(COM2, '\r');

    for(i = 0; i < MAX_BUFF; i++)
     {
       buff[i] = inportb(COM2);

       if( (buff[i] == '0') && (buff[i-1] == '\n') )
         {
           break;
         }

       putchar(buff[i]);
       delay(200);
     }

    return 0;
  }
===========================END CODE HERE===========================

Mi sembra molto semplice e che non necessiti di notevoli spiegazioni;
l'unica precisazione da fare, forse, e' il metodo di uscita dal ciclo
di lettura; esistono 2 modi per interrompere la lettura:
1. Abbiamo riempito tutto il buffer
2. Leggiamo uno '0' (opcode) all'inizio di una riga (metodo veloce
   ma che in questo caso funziona).

Considerazioni:
1. non era necessario bufferizzare la risposta, ma cosi' facendo puoi
   trarre spunti per scrivere funzioni e/o procedure che restituiscono
         un "char *" contenente la risposta del modem (in questo caso devi
         gestirti anche il carattere '\0' alla fine del buffer).
         
2. Il delay che ho messo e' alto, ma crea sullo schermo un effetto di
   stampa dei caratteri molto carino :)
         
3. Prova a cambiare la stringa da inviare al modem ma, nel qual caso
   tu scelga di inviare la "I5", dovrai leggermente cambiare il codice
         perche', ad un certo punto della lettura dalla porta, il modem ti
         chiedera' di premere un tasto per continuare; dovrai, quindi,
         interrompere il ciclo di lettura, mandare "un carattere" alla porta
         e riprendere la lettura.

Ecco, solo a titolo di esempio, le risposte del modem di questa mia
amica:

ATV0I1
98EE

ATV0I2
OK

ATV0I3
U.S. Robotics 56K FAX EXT Rev. 11.15.19

ATV0I4
U.S. Robotics 56K FAX EXT Settings...
   B0  E0  F1  L0  M1  Q0  V0  X3  Y0
   SPEED=115200  PARITY=N  WORDLEN=8 
   DIAL=TONE    OFF LINE   CID=0

   &A3  &B1  &C1  &D2  &H1  &I0  &K1
   &M4  &N0  &P1  &R2  &S0  &T5  &U0  &Y1

   S00=000  S01=000  S02=043  S03=013  S04=010  S05=008  S06=004
   S07=060  S08=002  S09=006  S10=014  S11=072  S12=050  S13=000
   S15=000  S16=000  S18=000  S19=000  S21=010  S22=017  S23=019
   S25=005  S27=001  S28=008  S29=020  S30=000  S31=128  S32=002
   S33=000  S34=000  S35=000  S36=014  S38=000  S39=012  S40=000
   S41=004  S42=000

   LAST DIALLED #: T1055411055

ATV0I6

U.S. Robotics 56K FAX EXT Link Diagnostics...

Chars sent                87591      Chars Received           294878
Chars lost                    0
Octets sent               50192      Octets Received          177845
Blocks sent                2071      Blocks Received            2167
Blocks resent                 0

Retrains Requested            0      Retrains Granted              1
Line Reversals                0      Blers                         5
Link Timeouts                 0      Link Naks                     0

Data Compression       V42BIS 0/0
Equalisation           Long
Fallback               Enabled
Protocol               LAPM
Speed                  52000/31200
V.90 Peak Speed        52000
Last Call              00:21:15

Disconnect Reason is DTR dropped

ATV0I7

Configuration Profile...

Product type           CTR-21 External
Product ID:            24563002
Options                V32bis,V.80,V.34+,V.90,V.92
Fax Options            Class 1/Class 2.0
Line Options           Caller ID, Distinctive Ring
Clock Freq             92.0Mhz
EPROM                  256k
RAM                    32k

FLASH date             6/25/2001
FLASH rev              11.15.19

DSP date               6/25/2001
DSP rev                11.15.19


Il fatto che ti ripeta o meno il comando che gli mandi sullo schermo
dipende dal comando En (0 <= n <= 1).
E0 Disabilita l'eco.
E1 Abilita l'eco. 

Nel mio caso era E0, quindi sul video non vedevo l'eco del comando
(l'ho aggiunto io qui per farti capire a che comando si riferisce
l'output in oggetto).
Se vuoi forzare il modem a mandari l'eco del comando, cambia la
stringa in "ATE1V0I7".

Alla prossima.
Ciao.


-- 
What a strange game. The only winning move is not to play. -- WOP, 'War Games'.




Other related posts: