Tecniche per osservare lo stato di runtime in C

0

Quali sono le tecniche per i programmi C che consentono di ispezionare facilmente lo stato del dispositivo incorporato, attraverso un collegamento di comunicazione?

Ad esempio, per un dispositivo microcontrollore che comunica con altri dispositivi, un dispositivo esterno potrebbe voler eseguire query simili a:

  1. Qual è il livello della batteria di questo dispositivo?
  2. Quando è stato spento questo dispositivo?
  3. Gli altri dispositivi sono collegati a questo dispositivo?
  4. Di quali indirizzi IP si connettono questi dispositivi?
  5. ecc.

Ci sono modi in cui di solito lo facciamo nei nostri progetti che riguardano:

  1. Rendere condiviso un sacco di stati (ad es. globale). Il modulo di comunicazione che riceve queste richieste accede allo stato globale per trasmetterlo.

  2. Definizione dei parser delle richieste e dei serializzatori di risposta per i dati coinvolti. Questi progetti legacy hanno spesso molti cookie diversi, ognuno dei quali rappresenta un certo messaggio di richiesta, e quindi alcuni dati vengono rispediti, solitamente serializzati al volo secondo un formato (o protocollo) di messaggio concordato.

Esistono alcuni modi per implementare questa funzionalità comune in modo che:

  1. Possiamo prevenire l'interruzione dell'incapsulamento esponendo lo stato e
  2. Rimuovi la quantità di codice per ogni nuova richiesta?
posta Lou 13.08.2017 - 00:30
fonte

2 risposte

2

Puoi avere una tabella dei simboli, o un file di mappe, un sistema di query basato su un meccanismo di query generico che richiede i dati in una posizione specifica e con una dimensione specifica, quindi decodifica la risposta ricevuta.

Ovviamente il tuo software di interrogazione dovrà conoscere la versione esatta del target interrogato e avere la mappa per ogni versione supportata, di solito viene gestita avendo una posizione fissa per le informazioni sulla versione.

L'altro problema è che non sarai in grado di accedere ad alcuna posizione di dati allocata dinamicamente, (ad esempio malloc creata), a meno che tu non abbia un processo in due fasi, (richiedi la posizione della memoria quindi richiedi la dati da quella posizione), - tuttavia l'uso di malloc non è generalmente considerato la best practice nel mondo embedded ed è spesso vietato dagli standard di codifica se si sta facendo un lavoro altamente affidabile o di sicurezza.

Se hai solo bisogno di fornire questo durante lo sviluppo di un test, l'uso di uno strumento come il debugger remoto gdb è il modo più usuale per andare.

    
risposta data 13.08.2017 - 06:57
fonte
1

Una risposta alla prima preoccupazione è l'inversione del controllo. Al posto del modulo di comunicazione cerca per lo stato pertinente, gli altri moduli possono semplicemente informare il modulo di comunicazione quando lo stato cambia. Questo aggiunge alcuni costi generali. Innanzitutto, il modulo di comunicazione avrà quindi essenzialmente una copia dello stato interrogabile, tuttavia, a seconda dei problemi di concorrenza, avere un puntatore a più parti di stato andrebbe bene. Ciò aggiunge anche un sovraccarico quando si aggiorna lo stato (ad esempio una chiamata di funzione), sebbene nei casi in cui questo sia un problema, può essere corretto comunicare solo il modulo di comunicazione di alcuni aggiornamenti (ad esempio 1 su 1000). Ovviamente, questo significherà che il risultato potrebbe essere stantio. Ciò significa anche che la creazione di un nuovo stato interrogabile richiede la modifica del modulo responsabile per la notifica al modulo di comunicazione. Detto questo, un tale cambiamento sarebbe probabilmente comunque necessario, a meno che tutti del tuo stato fossero globali.

I vantaggi di questo approccio sono i primi, l'incapsulamento che significa che se un modulo cambia il modo in cui rappresenta il suo stato, non sono necessarie modifiche altrove nel sistema. Inoltre, mentre l'approccio che descrivo consente a più moduli di sovrascrivere lo stato di altri moduli nel modulo di comunicazione, ciò influisce solo sui risultati della query e non sul funzionamento di altri moduli. Anche in questo caso però non è molto probabile. In secondo luogo, il modulo di comunicazione può memorizzare il suo stato in modo conveniente per l'elaborazione generica. Concettualmente, è solo un negozio di valori chiave (dattilografato). Anche la creazione di query di metadati, come la restituzione dell'elenco di chiavi supportate, diventa semplice da fare in modo generico. La rappresentazione effettiva può essere una normale tabella hash o una matrice per tipo di dati (ad esempio interi o sequenze di byte) indicizzati da chiavi allocate sequenzialmente e manualmente. A seconda della situazione di concorrenza, questo può anche fornire uno snapshot più coerente in quanto altri moduli possono notificare il modulo di comunicazione delle modifiche quando il suo stato è consistente, piuttosto che il modulo di comunicazione potenzialmente in grado di leggere lo stato nel mezzo di essere modificato.

Passando alla seconda preoccupazione, dovrebbe essere chiaro come è possibile creare un semplice protocollo per interrogare questi dati. È molto probabile che tu possa utilizzare un protocollo "standard" per questo scopo. Tuttavia, sospetto che tu debba gestire protocolli preesistenti che sono idiosincratici, vale a dire che ogni richiesta ha il suo formato e si aspetta la risposta in un formato specifico della richiesta. È probabile che vi sia una certa sistematizzazione che è possibile sfruttare, ma alla fine, finché è necessario supportare tali richieste, non c'è niente da fare se non scrivere un sacco di codice di casi speciali. È possibile creare o utilizzare librerie e strumenti che possono semplificarlo. Ciò che puoi fare, però, è potenzialmente centralizzare questo codice in un proxy o almeno un livello davanti al modello di comunicazione scrivendo codice per convertire i formati del protocollo legacy in un formato più generico.

Se l'approccio di cui sopra sembra avere troppi sovraccarichi di runtime, ci sono cose che possono essere fatte per mitigarlo (ad esempio, impacchettare lo stato di un intero componente in una struct o collezione di array e passare solo un puntatore ad esso al modulo di comunicazione). Questi probabilmente porteranno indietro alcuni dei lati negativi e / o aggiungeranno complessità. Se i tuoi vincoli sono così stretti, potresti trovare ispirazione dalla lingua di Virgil (code ).

    
risposta data 13.08.2017 - 07:57
fonte

Leggi altre domande sui tag