Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

10
voti

Eraserhead IV

Fuggi per salvare la tua vita! Non guardare indietro e non ti fermare in alcun luogo della pianura; salvati al monte che tu non abbia a perire!.( Genesi 19:17)

La scelta. Pillola rossa o pillola blu ? Tornare indietro o andare avanti seguendo la strada del bianconiglio ? Capire che ad un certo punto nella vita ci sono porte che si possono aprire solo in un verso non è difficile, il bello e che lo capisci solo quando la porta si è chiusa dietro di te.

Funzioni ad una incognita a due tre... e così via in un caotico crescendo. Poi per ogni incognita abbiamo bisogno di un’altra funzione e così il sistema aumenta di complessità esponenzialmente. Le strade che percorriamo si diramano in tante direzioni alcune sono larghe e spaziose altre tortuose e faticose. Quale percorso sceglieremo ? Forse siamo giovani e abbiamo paura. Forse siamo vecchi e non è cambiato nulla. Talvolta ti guardi indietro ed è come se fossi in una parete verticale di una montagna. Ti prendono le vertigini. Se sapevi che era così forse non l’avresti mai fatto. Ma una volta presa una strada perché tornare indietro ? Perché pensare continuamente e ossessivamente alla strada persa ? Guardare indietro significa solo finire fuori strada alla prossima curva....


Maledizione. Adesso devo risolvere il problema dell’SMS che non viene inviato. Così riprendo l’apparato ed eseguo la prova.Prendo un gsm della Cinterion perché quelli della Digicom mi fanno impazzire con i led, non capisco mai cosa vogliono dire..

Spedisco un sms e attendo la risposta.

Inesrisco il debugger sulla scheda, metto un break point all’uscita del riconoscimento sms e poi step by step, vado avanti. La macchina a stati, dopo aver riconosciuto l’sms, richiama lo stato di verifica della registrazione alla rete e poi subito dopo, costruisce il messaggio che viene inviato correttamente. Tutto ok, ma è solo un'illusione.

Ripeto la prova, senza debugger e niente da fare l’sms non viene inviato.

Bene, il problema è più difficile di quello che pensavo, non posso usare il debugger ( e nello stesso tempo interiorizzo qualche esotico impropero... ) ma almeno riesco a vedere il baco in laboratorio. Allora, per scrupolo, metto un messaggio di errore nella TraceError ( sistema di funzioni con coda di eventi errore del sistema ), proprio nello stato di verifica di registrazione della rete. Ripeto la prova.. una due tre quattro volte e santi numi tutte le volte fallisce. Visto che non posso debuggare, inserisco un codice di errore su tutta la sezione di invio del messaggio e alla fine, scopro che la macchina a stati fallisce perché il gsm gli dice che non è registrato alla rete. Pork ma se lo ha appena scaricato... Come è possibile che il gsm non sia registrato sulla rete, quando pochi secondi prima oltre ad essersi collegato alla rete ( e lo avevo verficato con il comando AT+CREG ) ne avevo anche scaricato il messaggio di test, inviato poco prima ?


Cerco su internet Telit sui siti ufficiali e trovo in un forum di cazzutissimi guru della telecomunicazione e in un post leggo questa serafica risposta. “Yes our Gsm can get dummy failed registration after any sms operation.... You need to check it after 10 seconds to avoid...”. Ovviamente questo “dummy failed registration” non era un problema generalizzato dei GSM, visto che il modulo mai modificato era stato testato con i gsm della Siemens e non aveva mai dato problemi..Modifico il firmware e aggiungo un retry, al comando di verifica della registrazione di 30 secondi non prima però di aver di nuovo interiorizzato ulteriori e non condivisibili improperi... Creo una nuova release e la salvo sul repository.

Riprovo il test e questa volta tutto quanto funziona correttamente. Aggiorno il binario della periferica remota e chiamo il tecnico della Wasserdome, per monitorare quell’impianto.

Copio la pagina e la includo nella documentazione del Telit, assieme all’email ricevuto poco tempo prima, con il segretissimo comando, non documentato, per la modifica dei guadagni di potenza della ricezione radio alle frequenze di trasmissione gsm ( 900 e 1800 Mhz )

AT#PCLMIN <900Mhz>,<1800Mhz>,<nc>


Ovviamente quelli della Telit mi hanno scongiurato di non dirlo a nessuno...


Ho risolto il baco del sms non inviato. Ora riprendiamo il problema dell’sms corrotto...


Quando abbiamo spiegato il processo di comunicazione abbiamo spiegato che questo processo sostanzialmente si suddivide in 4 parti

  • Trasmittente
  • Mezzo
  • Ricevente
  • Protocollo.


Abbiamo anche spiegato che il protocollo ha bisogno di una grammatica condivisa fra trasmittente e ricevente per garantire la finalità della trasmissione. La grammatica però non si occupa del significato del messaggio.

Noi possiamo benissimo scrivere, una frase grammaticalmente corretta ma assolutamente priva di senso. Questo è un po’ quello che è accaduto nel nostro caso, i messaggi che erano grammaticalmente corretti ma assolutamente privi di significato.


Pausa pranzo. Esco dal retro e passo davanti alla postazione montata dai tecnici del CNR. Abbiamo reso disponibile un po’ di spazio per un progetto internazionale, commissionato dalla comunità europea. Questo progetto è nato, quasi certamente, perché tutto il mondo accademico scientifico, si era impaurito dopo aver visto il terrificante cartone l’era glaciale. Il mese prima era arrivato questo apparato dagli Stati Uniti per la misura della gravità terrestre ( detto anche più comunemente gravimetro ). La nostra azienda, sarà utilizzata come postazione di riferimento nazionale per la ben più importante misura dell’altezza del mar mediterraneo. Sulla banchina di un porto nella vicina città marittima, avrebbero installato una postazione di misura. In pratica era un tubo vuoto lungo un paio di metri con sopra un sensore di prossimità ad ultrasuoni.

Dentro a questo gravimetro, dicono ci sia una molla fatta con materiale alieno e che vibra in continuazione. Solo il posizionamento ha richiesto l’intervento di un superspecialista con la chiave del dieci addetto alla rotazione dei bulloni nei supporti in lega di alluminio tornito. La cassa ,voci di corridoio, costa cento mila euro e io pagherei altrettanto per smontarla e vedere come salta quella molla sul pavimento....


Squilla il telefono. Era Bukovsky... un buon tecnico che chiamava solo quando c’erano problemi veri.

“ Si senti abbiamo notato che il problema non è solo nei messaggi ma anche durante lo scarico dei dati... sai mica darmi delle notizie... “

“ Tutto sotto controllo.. guarda.. un attimo solo, finisco le ultime verifiche e poi ti dico ”

“... noi qui siamo un po' preoccupati” -Figurati io-

“ma no... dai... non scherziamo nessun problema... fidati.. dovete aspettare solo un attimo...un giorno di prove ” ero proprio senza ritegno....


Specifica del protocollo
Convenzioni
In  tutti i casi in cui il protocollo prevede la trasmissione 
di un valore a  16 bit o di un valore espresso in 4 byte, devono 
essere trasmessi per  primi i byte meno significativi e 
successivamente i byte più  significativi. Per la “LUNGHEZZA DATI” 
e il “CAMPO DATI” devono essere trasmessi 7 bit per byte, con il 
bit 8 fisso a 1.
La Lunghezza Dati può essere quindi al massimo di 16384 e deve 
comprendere anche tutti i bit fissi a 1.
Quando la Lunghezza Dati = 0 il Campo Dati deve essere omesso.

Esempio di conversione Lunghezza = 80 (decimale) (0050 Hex)

Viene trasmessa in 2 byte con la parte meno significativa inviata prima


Dato hgfedcba h gfedcba xgfedcba Dato trasmesso
0x50 01010000 0 1010000 11010000 0xD0
ponmli ponmli xponmlih
0x00 000000 000000 10000000 0x80

Ovviamente questa è solo una parte della specifica, io ho cercato di capire se chi ha partorito questo geniale protocollo si facesse quanto meno delle canne... ma non ci sono riuscito.

Comunque riflettevo sull’ultima telefonata di Bukovski. Ma certo era ancora la maledetta Ferroram, se la radio del gsm riesce a corrompere i dati dell'sms pdu figurati se non abbiamo gli stessi effetti malefici durante la connessione dati. Tutto torna, il baco è il solito e abbiamo scoperto semplicemente che era in più punti del codice. Ero sempre più convinto che bypassando la lettura della Ferroram si sarebbe risolto il problema.

Sul tavolo a fianco avevamo un pc fanless. Io e Cricket lo guardiamo con occhio assatanato e lo smontiamo in 40 secondi netti. Poi rimontiamo tutto prima che la direzione ci avvisi che deve essere testato, perchè fara parte del sistema di controllo di uno Yatch.

Guardiamo il connettore a vista che non è etichettato

“secondo te ?”

“Secondo me 230... il connettore non è polarizzato..”

“..E poi c’è uno scatolotto dentro... sembra un alimentatore....”

“ma si dai 230....”

“attacco ?”

“attacca...”

Pof ! Un lieve filo di fumo biancastro salì dall’alimentatore, dal colore e l’odore giurerei che è un condesatorino elettrolitico da 100 uF 16 V. Saltò, di seguito, tutta l’alimentazione sul piano e partirono i gruppi di continuità assieme ad una sequela di parolacce prevalentemente di origine toscana. Il loro eco rimbalzò per diversi minuti su tutta la ditta.

Squillò il telefono. La direzione.

“Pronto...Si anche a noi è saltata la corrente... ma non sappiamo.. adesso andiamo a vedere è un periodo che quelli dell’Enel fanno sempre casino... sono dei manari... si … mi dica….. il pc fanless ?... ecco si a proposito stavo per chiamare ecco ..guardi secondo noi è guasto.... non si accende.. va bene … provvederemo...” Rimetto il pc nella scatola, e mi riprendo dalla telefonata. Adesso il grosso problema era che bisognava intervenire all’interno del protocollo di comunicazione dati. Non ho ancora finito.


Il flusso del programma prevede due funzioni


WORD  Wass_Cmd_SET_REQMINM()

{

…..
…..
 for (i=0; i<Num; i++)
 {
   // Indirizzo del record nell'archivio circolare finito
   FAddr &= (MINUTE_LOG_SIZE-1);
   // Legge dall'archivio tutto il record dati al minuto
   FlashReadData(FA_MINLOG+FAddr, (BYTE*)&Minute, 16);
   // Converte in scala wass dati del canale selezionato
   Sample[0] = Scale_wlogTowass(Minute.Data[TLCh].Min, Scale);
   Sample[1] = Scale_wlogTowass(Minute.Data[TLCh].Med, Scale);
   Sample[2] = Scale_TlogTowass(Minute.Data[TLCh].Max, Scale);
   // - DEBUG - Invia timestamp invece dei dati
#ifdef __Wass_DEBUG__
   ts=SecondsToTs(Minute.TimeStamp);
   Sample[0]=(ts.anno*100)+(ts.mese);
   Sample[1]=(ts.giorno*100)+(ts.ora);
   Sample[2]=(ts.minuto*100)+(ts.secondo);
#endif
   // Memorizza il record nel buffer
   XWData(XAddr, (BYTE*)&Sample, 6); ⇐ punto dove viene salvato lo stream in ferroram
   // Avanza puntatori archivio e buffer
   FAddr+=16; XAddr+=6;
 }
 // Numero di bytes inviati = numero di campioni x 6 (max=240)
 return(Num*6);
}


Wass_Tx(WORD Len8)
{
…..
…..
while (OutPos<Len7)
{
// Ogni 8 dati usciti lo shift-register deve essere caricato con 7 bytes
if ((OutPos & 0x0007)==0)
   {
     // Azzera tutto lo shift-register
     sr=0;
     // Calcola in numero di bytes ancora da spedire, massimo 7
     RLen=Len8-InPos; if (RLen>7) RLen=7;
     // Copia i dati da spedire dal buffer allo shift-register
     XRData(_P.BufAddr+InPos, (BYTE*)(&sr), RLen); <= punto dove viene letto lo stream in ferroram
     // Incrementa numero di bytes prelevati dal buffer
     InPos+=RLen;
   }
   // Preleva un dato da spedire (bit8 settato) e slitta sr
   Out = (sr & 0xff) | 0x80; sr >>= 7;
   // Spedisce il dato
   Wass_SendAndCrc(Out);
   // Incrementa numero di bytes(7 bit) inviati
   OutPos++;
 }
 // Invia ETX e i due bytes del crc calcolato
 Wass_SendAndCrc(ETX);
 ChannelTxData(_P.Uart, (_P.Crc & 0xff));
 ChannelTxData(_P.Uart, (_P.Crc >> 8));
}


La prima funzione, prevede di preparare il messaggi,o creando un primo stream di dati con le misure lette dalla Flash. La seconda prepara il buffer con la conversione dello stream da 8 a 7 bit così come descritto nella specifica precedente.Penso di entrare dentro la funzione Wass_Tx e di leggere la flash. Ma la cosa non è così semplice perché da una parte ho un ciclo a 6 byte e dall’altra ho un ciclo a 8 byte.


Squilla il telefono, il mosfet di un controllo lineare, per un apparato medicale di un vecchio progetto, era di nuovo saltato. Il controllo lineare era a drain in comune e il mosfet utilizzato un IRF9540. Depletion layer, body effect, junction leakage ... Lo studio di un mosfet direi che è un po’ la base per chi ha intenzione di avviarsi a questo mestiere. C’è tutto quello che serve per diventare un buon elettronico. I mosfet si rompevano in continuazione. Avevo scoperto che la mica, usata come isolante, veniva bucata dalle bavette di alluminio che rimanevano come residuo della lavorazione, del buco passante, effettuato col trapano sul dissipatore. Il buco doveva fare da guida alla vite di fissaggio del mosfet; così, per evitare problemi meccanici, abbiamo pensato di rovesciare il mosfet e di montarlo su un circuito stampato. Ma il problema era evidentemente un altro, quando da un certo punto in poi mi accorsi che i mosfet si innescavano spontaneamente, ma in questo momento ho altro a cui pensare....

Ritorniamo alla nostra storia…Il vero problema di questa modifica firmware non è la sua farraginosa implementazione. Il vero dramma è che la modifica sarà cieca perché non potrò provarla, un po’ come dire ad un equilibrista di eseguire il suo percorso con gli occhi bendati... o al buio. Per testare il firmware bisognerà infatti avviare una procedura speciale di richiesta dello scarico dei dati con il centro nazionale della Wasserdome, che ci dirà poi se è stato effettuato correttamente o meno. Ovviamente questa situazione che mi costringe a confidare nell’avvallo del cliente è una cosa pericolosissima, così cerco di ingraziarmi qualche personaggio del CED per seguire meglio la fase di verifica. Solo la richiesta, mi creava uno stato d’ansia ma non mi venivano in mente altri modi per venirne fuori. L’unico modo era quello che semplicemente la modifica non doveva avere bachi.

La cosa migliore sarebbe quella di implementare un’interfaccia su pc che contenga il cervellotico protocollo, ma il tempo mi era tiranno ( e lo è ancora.. e lo sarà sempre ). Allora rompo gli indugi e la scrivo di getto... è tutta nella testa... deve funzionare.
La funzione, di creazione dello stream, descritta precedentemente deve leggere i dati non più dalla ferroram ma dalla flash. La funzione che fa questo era la Wass_Cmd_SET_REQMINM che però scritta così è inutilizzabile. La modifico in modo che abbia un parametro di ritorno, letto dalla flash, così la utilizzo come fosse una ferroram, tanto in lettura la risposta è più praticamente identica.

Se avessi dovuto effettuare la scrittura allora sì che avrei dovuto tenere conto dei tempi, ma così non è stato.

Il ciclo poi doveva prevedere la gestione differenziata del comando di risposta così come richiedeva il protocollo. La modifica diventerà così di questo tipo...


WORD  Wass_Cmd_SET_REQMINM()
…..
…..
// Converte in scala Wass i dati del canale selezionato
   switch(ucStatus_REQMINM)
   {
       case 0:
           if ( byInit == 2 )
               ucStatus_REQMINM++;
           if(Ch==1)
               Sample = Scale_wlogToWasst(Minute.Data[TLCh].Min, Scale, cShunt_Status);
           else
              Sample = Scale_wlogToWass(Minute.Data[TLCh].Min, Scale, 0);
       break;
       case 1:
           if ( byInit == 2 )
               ucStatus_REQMINM++;
           if(Ch==1)
               Sample = Scale_wlogToWass(Minute.Data[TLCh].Med, Scale, cShunt_Status);
           else
               Sample = Scale_wlogToWass(Minute.Data[TLCh].Med, Scale,0);
       break;
       case 2:        
           if(Ch==1)
               Sample = Scale_wlogToWass(Minute.Data[TLCh].Max, Scale, cShunt_Status);
           else
               Sample = Scale_wlogToWass(Minute.Data[TLCh].Max, Scale,0);
           // Avanza puntatori archivio e buffer
           if ( byInit == 2 )
           {
               ucStatus_REQMINM=0;
               lFAddr+=16;
           }
       break;
   }
   // Numero di bytes inviati = numero di campioni x 6 (max=240)
   return(Sample);
}

Come si può notare adesso la funzione ha una macchina a stati interna con l’incremento automatico dell’indirizzo puntato nella flash. Il parametro in ingresso servirà per il controllo dell’indice e che verrà settato dalla funzione chiamante nel giusto momento.


Wass_Tx(WORD Len8)
{
…..
…..
         Wass_Cmd_SET_REQMINM_Buffer(1);
            // Ciclo di invio del campo dati
            while (OutPos<Len7)
           {
               // Ogni 14 dati usciti gli shift-register deve essere caricato con 7 bytes
               // ciascuno....
               // if ((OutPos % 0x00E)==0)
               // Ogni 16 byte usciti gli shift-register deve essere caricato con 7 bytes
               // ciascuno....( 14 byte in totale )
               if ((OutPos & 0x00F)==0)
               {
                   // Azzera tutto lo shift-register
                   sr1=0;
                   sr2=0;
                   pWsr =(WORD*) &sr1;
                   // Calcola in numero di bytes ancora da spedire, massimo 7
                   RLen=Len8-InPos; if (RLen>7) RLen=7;
                   // Copia i dati da spedire dal buffer allo shift-register
                   // XRData(_P.BufAddr+InPos, (BYTE*)(&sr), RLen);  <= Vecchia lettura della ferroram
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(2);
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(2);
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(2);
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(0);
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(2);
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(2) ;
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(2);
                   *pWsr++ = Wass_Cmd_SET_REQMINM_Buffer(2);
                   sr2>>=8;
                   // Incrementa numero di bytes prelevati dal buffer
                   InPos+=RLen;
                   iIdx_Byte=0;
               }
               // Preleva un dato da spedire (bit8 settato) e slitta sr
               if( iIdx_Byte < 8 )
                   {Out = (sr1 & 0xff) | 0x80; sr1 >>= 7;}
               else
                   {Out = (sr2 & 0xff) | 0x80; sr2 >>= 7;}
               // Spedisce il dato
               wass_SendAndCrc(Out);
               // Incrementa numero di bytes(7 bit) inviati
               OutPos++;
}


Lo shift register ( fatto a mano ovviamente ) è composto dai due registri sr1 e sr2 dichiarati long long ( tanto per dire un intero mooolto lungo ) e quindi a 8 byte.

Non c’è uniformità nella lunghezza dei tipi di variabile fra i sistemi embedded e il PC. Una variabile di tipo int per il compilatore dello IAR del MSP430 è a due byte mentre ad esempio per il compilatore c++ della microsoft è a 4 byte. Tipicamente i protocolli sviluppadondoli in C puro riesco a riciclarli passandoli dal sistema embedded al programma di interfaccia su PC. La duplice implementazione mi permette di differenziare i test e provare il modulo in modo consistente.

Il ciclo modificato funziona su un volo un po’ pindarico del puntatore pWsr che attraversa i due registri passando da uno all’altro confidando che la dichiarazione contigua obblighi il compilatore a metterli in fila... ma non sempre è così. Sarebbe meglio fissare i registri di memoria ad indirizzi fisici... ma temo che sia ancora più pericoloso... Guardo le dichiarazioni e provo il codice simulato.. tutto ok.

La nuova dichiarazione di Wass_Cmd_SET_REQMINM_Buffer con il nuovo parametro ha mantenuto le stesse caratteristiche del ciclo mantenendo la poetica ed efficace conversione a 7 bit. Mezza giornata per buttarla giù e l’altra mezza per provare le funzionalità operative sono le 8 di sera creo la release che carico sulla macchina. Preparo il generatore di funzioni e sugli ingressi degli analogici carico un'onda triangolare con periodo 15 minuti offeset a 0 Volt e span da 0 a 9 volt. Metto su una SIM e accendo la macchina. Carico la configurazione con l’impostazione dell’sms da spedire domattina. Il giorno dopo fu una giornata un po' anomala. Ci venne a trovare Burton un vecchio dipendente che è riuscito ad arrivare alla pensione e passamo il tempo raccontandoci vecchi anedotti.

Squillò il telefono era la Wasserdome con il responso dei dati.

Mi faccio spedre l’sms ricevuto dal centro operativo ed estrapolo i dati con excel. Visualizzo il grafico e come per miracolo compare la stessa l’onda triangolare che avevo impostato col generatore di funzioni. La modifica aveva funzionato. Da lì cercai in tutti i modi di rallentare le esigenze della produzione e riuscii in qualche modo a frizzarla sino a quando le periferiche non furono provate per almeno una settimana. Furono così un paio di settimane passate al telefono con il ced, visualizzando grafici e scandagliando migliaia di dati giornalieri, in una decina di macchine in prova. Quella sera tornai a casa con il pezzo The Pretender dei Foo Fighters e per poco non divelgo il parabrezza dai colpi di cassa.

Fiat lux.... e lux fu...

6

Commenti e note

Inserisci un commento

di ,

lieto di servirti Oberon... ;-)

Rispondi

di ,

Grazie Kirkegaard!

Rispondi

di ,

Ciao Paolo Nel dettaglio diciamo che più o meno da quando c'è stata la prima segnalazione a quando è stata emessa la release definitiva sono passati 3 mesi. Per questo racconto ho avuto qualche problemino perchè le cose nella realtà erano molto più complicate e non risucivo a descriverle bene. Considerando che i racconti non sono leggibilissimi ho preferito tagliare. Non dimenticare però che la realtà presentata è sempre romanzata. Le storie sono vere ma sono anche manipolate... ;-)

Rispondi

di ,

Bene, un lieto fine è quello che ci vuole. Solo una curiosità: oltre alle due/tre settimane conclusive, quanto tempo hai impiegato complessivamente per risolvere il problema? È solo una mera curiosità! Comunque, complimenti! Ciao. Paolo.

Rispondi

di ,

si ( finalmente anche per me... ) ho faticato un po' questa volta è stato un parto difficile spero qualcosina sia venuta fuori...

Rispondi

di ,

Grazie Kirkegaard, ne parlavo proprio oggi con Paolino ed eravamo in attesa del sequel ... ora è arrivato. Ancora complimenti, -carlo.

Rispondi

Inserisci un commento

Per inserire commenti è necessario iscriversi ad ElectroYou. Se sei già iscritto, effettua il login.