Il 05/06/2014 16:04, PaoloC ha scritto:
> Puo' essere che l'implementazione varii con il modulo GSM a
> disposizione. Io l'ho fatto con un oggetto Nokia 30 e ATmega diretto (no
> Arduino).
Diciamo che la maggior parte dei comandi AT per un modem GSM sono
standardizzati, quindi l'implementazione ᅵ generalmente modem-indipendente.
Ovviamente lato micro la questione ᅵ diversa. Anch'io sto lavorando con
un ATMega "diretto".
> La mia applicazione ᅵ probabilmente piᅵ semplice della tua: riceve una
> chiamata, hang-up, manda un SMS.
>
> Io ho implementato solo i comandi che mi servono, non gli invio altro:
> inizializzazione di visualizzazione del CLIP, lettura del livello di
> segnale e invio dell'SMS. Non essendo una applicazione mission-critical,
> ignoro le risposte tranne per il livello di segnale.
Cosa vuoi dire che ignori le risposte? La comunicazione ᅵ bloccante? Tipo:
invia_comando("AT+CLIP=1\r");
aspetta_ok();
Cosa succede se non ricevi l'OK? Ti fermi lᅵ a vita?
Purtroppo, anche per applicazioni non mission-critical, non me la sento
di ignorare queste, seppur rare, situazioni.
>> - il modem puᅵ inviare, in qualsiasi momento, un comando asincrono
>> unsolicited (tipo il RING, oppure NO CARRIER se cade la connessione in
>> corso, ...)... quindi il protocollo ᅵ definitivamente full-duplex.
>
> L'unsolicited lo gestisco usando un HW interrupt (linea RI) e a quel
> punto leggo il buffer con il numero chiamante. Forse al secondo squillo,
> avendo liberato il buffer di ingresso.
Se quando arriva il RING (il tuo interrupt hw) stai inviando un comando
al modem? Hai implementato un meccanismo per interrompere quel task che
impegna il modem?
>> Siccome sono sempre molto bravo a far diventare complicate cose
>> semplici, ho la sensazione che stia sbagliando strada e ci sia un modo
>> migliore... me ne consigliate uno?
>
> La gestione del modem in ambiente embedded ᅵ complessa, essendo
> simpaticamente asincrona da entrambe le parti.
Me ne sono accorto.
> Sei sicuro che non ci sia una libreria preconfezionata per la tua
> piattaforma HW+SW?
Arduino ha qualche libreria, ma sono troppo semplici per il grado di
affidabilitᅵ che vorrei raggiungere. Sono routine tutte bloccanti che
non mi piacciono affatto (per esempio, mentre compongo un numero non
posso fare altro).
Non dico di aver risolto, ma ho raggiunto un livello decente nel
seguente modo.
Ho scritto un driver di "basso livello" che gestisce il modem GSM.
Questo driver *non* ᅵ "comando agnostico", nel senso che l'applicazione
dice di voler inviare il comando ATH, piuttosto che AT+CMGR, mediante
degli identificativi dei comandi (ed eventuali parametri associati, se
servono).
Il driver sa che all'ATH il modem risponde normalmente con OK, mentre
all'AT+CMGR con un messaggio +CMGR su una riga e poi OK su un'altra
riga. Quindi, in base al comando che l'applicazione vuole inviare, il
driver si sposta su uno stato apposito.
La stessa risposta viene decodificata nel driver e tornata indietro
all'applicazione, mediante un messaggio comprendente i vari parametri
presenti nella risposta del modem (per esempio, il numero mittente di un
SMS e il testo).
Naturalmente il driver gestisce, sempre in base al comando, risposte
errate, inattese o timeout di non risposta, inviando all'applicazione il
relativo messaggio.
Per fare in modo che piᅵ task possano accedere "contemporaneamente" al
modem in modo indipendente, la funzione di invio comando in realtᅵ si
limita a riempire una FIFO di comandi che il driver, con calma,
consumerᅵ. Ad ogni comando ᅵ legato il task generatore (nel mio caso,
una state-machine). La risposta verrᅵ inviata solo a quel task.
Per quanto riguarda gli URC, ho proceduto in questo modo. Il driver
legge byte a byte dalla seriale e si ferma al <CR><LF>. Controlla subito
se si tratta di un URC (RING, NO CARRIER, ...) e, se sᅵ, lo invia ad un
gestore di URC generico per tutta l'applicazione. Altrimenti lo passa
allo stato che si occupa della ricezione (sempre se stiamo aspettando
una risposta ad un comando, altrimenti ignora la riga).
Lo stato interpreta i messaggi ricevuti in base al comando inviato. In
alcuni casi puᅵ essere settato un flag urc_notadmitted per evitare di
controllare gli URC quando abbiamo iniziato a ricevere una risposta
complessa di un comando (tipo la lettura di un SMS che ᅵ formata da 3
messaggi su righe diverse, cosᅵ un SMS con il testo NO CARRIER non viene
interpretato come URC).