Risponditore di query APRS#
Il componente query (components/query/) risponde alle query APRS definite
nel capitolo 15 di APRS101. Riconosce le query generali (broadcast) che
viaggiano nel normale traffico ricevuto e le query dirette inviate a questa
stazione come messaggi APRS, costruisce la risposta corrispondente e la consegna
alla stessa infrastruttura di TX RF/APRS-IS usata dal motore di messaggistica.
Tutto ciò che fa è condizionato da g_config.query_en e dal resto della pagina
Query dell’amministrazione web.
Due punti di ingresso#
query_process(tnc2Line, source)— riceve ogni riga TNC2 decodificata. Non fa nulla a meno chequery_ensia attivo, l’interruttore disourcesia acceso e il campo informativo inizi con?, che è ciò che rende una riga una query generale. Riconoscere la parola chiave, applicare la limitazione di frequenza e accodare la richiesta è tutto ciò che fa.query_process_directed(fromCall, toCall, text, tnc2Line, source)— chiamata dahandleIncomingAPRS()dimessage.cquando il testo di un messaggio indirizzato inizia con?, così l’analisi di:ADDRESSEE:non viene duplicata qui. Non fa nulla a meno chequery_enequery_directed_ensiano attivi, l’interruttore disourcesia acceso etoCallcorrisponda ag_config.aprs_mycall(nominativo base, senza distinguere l’SSID).
Sorgente e canale#
Entrambi i punti di ingresso sanno da dove è arrivata la query —
QUERY_SRC_RF per la radio, QUERY_SRC_INET per il flusso APRS-IS — e
quella sorgente decide due cose.
Decide se la query viene risposta: g_config.query_rf e query_inet
nominano una sorgente, non una destinazione. E decide dove va la risposta:
una domanda ascoltata in onda riceve risposta in onda, una domanda letta dal
flusso riceve risposta verso APRS-IS. Le risposte sono trasmesse tramite il
gestore installato con query_set_tx_handler() — aprs_service.c riusa
esattamente lo stesso messageTxHandler() che fornisce al motore di
messaggistica — e la maschera che riceve porta sempre esattamente uno fra
MSG_CHANNEL_RF / MSG_CHANNEL_INET, quello corrispondente alla sorgente.
Tenere insieme le due cose è ciò che tiene il flusso APRS-IS lontano dal
trasmettitore. ?APRS? è normale traffico di dorsale e un IGate ne vede un
flusso costante; con l’interruttore della sorgente APRS-IS spento — l’impostazione
di fabbrica — nulla di quel traffico raggiunge il risponditore, e con
l’interruttore acceso le risposte tornano verso APRS-IS invece di andare in onda.
Una risposta non viene costruita qui, e un’altra non è un singolo pacchetto, ma
nessuna delle due sfugge all’accoppiamento. ?APRSO riannuncia gli
Oggetti/Elementi originati da questa stazione: la gamba da cui è arrivata la
domanda viene consegnata al trasmettitore come limite superiore e lì
intersecata con la configurazione «invia via» di ogni elemento, così il giro può
togliere una gamba che l’elemento seleziona ma non aggiungerne mai una che non
seleziona. ?APRSM ritrasmette messaggi che questa stazione già deve
all’operatore che interroga — un numero limitato di essi, vedi la tabella più
sotto — instradati dagli indicatori «invia via» della pagina Message; quelle
trame sarebbero uscite comunque secondo la pianificazione dei ritentativi del
motore di messaggistica, quindi una query accelera la consegna di traffico che
la stazione già doveva invece di crearne di nuovo.
Il risultato è la proprietà che gli interruttori di sorgente promettono: con Rispondi alle query ascoltate in RF spento, nessuna sequenza di righe APRS-IS può far attivare il trasmettitore a questa stazione.
Dove viene costruita la risposta#
Nessuno dei due punti di ingresso costruisce o trasmette qualcosa. Entrambi
riconoscono la parola chiave, applicano la limitazione di frequenza e
registrano la richiesta: il suo tipo, la stazione che interroga e al massimo
un testo — il nominativo su cui chiede un ?APRSH, oppure il percorso da cui è
arrivata una ?APRST, letto lì per lì mentre la riga ricevuta è ancora a
disposizione. La risposta vera e propria viene costruita e messa in aria da
query_service(), che il task dello scheduler dei beacon chiama all’inizio
di ogni passata; accodare una richiesta chiama anche
beacon_scheduler_wake(), così quella passata avviene subito e non quando
scade il beacon successivo.
Il motivo è lo stack. Una risposta a ?APRS? è un beacon: esegue
beacon_build_igate_position_packet(), diversi snprintf() di newlib con
supporto in virgola mobile, aprs_coord_format(), il costruttore del path e poi
l’intera catena aprs_service_send_tnc2() → modem_send_tnc2() →
ax25_encode(), con ogni livello che impila il proprio buffer da 300–450 byte
— esattamente l’albero di chiamate per cui beacon_scheduler.c dimensiona il
suo stack da 14336 byte. Le query, però, arrivano su aprs_rx (RF) e
igate_task (APRS-IS), i cui stack sono una frazione di quello. Il lavoro gira
quindi sul task il cui budget lo copre e non su quello che ha ricevuto la
domanda, e i costruttori possono crescere senza obbligare a riverificare quei
due percorsi.
Da dove gira discendono due cose. Rispondere non occupa mai un task RX per la
durata di una raffica di trasmissione — la proprietà che ?APRSO ha sempre
avuto — e la risposta eredita il contesto beacon dello scheduler, quindi
aprs_service_send_tnc2() attende un istante se l’anello di TX RF è pieno
invece di scartare la risposta (vedi Beacon e il pianificatore).
La coda contiene QUERY_PENDING_MAX (8) richieste, servite dalla più vecchia.
Una richiesta identica a una già in attesa viene fusa con essa — ogni risposta
riporta lo stato vivo nel momento in cui viene inviata, quindi un duplicato
metterebbe in aria due volte la stessa informazione — e a coda piena le
richieste successive vengono scartate con un avviso anziché soppiantare una
risposta già dovuta a qualcuno.
Query generali#
Query |
Abilitazione |
Risposta |
|---|---|---|
|
|
Il rapporto di posizione della stazione, costruito con
|
|
|
L’ultimo Rapporto Meteo in cache, costruito con
|
|
|
La riga di Capacità di Stazione definita da APRS101,
|
|
|
L’appello di appartenenza al gruppo definito da APRS101 cap.15: un
pacchetto di stato che elenca ogni Oggetto/Item proprio che porta
un’etichetta QRU non vuota, come coppie |
Poiché le risposte di posizione, stato e meteo riusano i costruttori di beacon esistenti, una risposta non può mai divergere da ciò che trasmettono i beacon periodici.
Beacon periodico delle capacità#
Il capitolo 15 consente a una stazione di inviare la riga delle capacità in
qualsiasi momento, non solo quando viene interrogata, e molti gateway ne
trasmettono uno perché i vicini sappiano che il gateway esiste senza doverlo
chiedere. Invia le capacità periodicamente (query_cap_beacon_en) lo attiva;
è disattivato per impostazione predefinita, e la riga viene comunque inviata in
risposta a ?IGATE? in entrambi i casi.
Il beacon ha un intervallo proprio (query_cap_interval_sec, limitato
all’intervallo QUERY_CAP_INTERVAL_S_MIN..``QUERY_CAP_INTERVAL_S_MAX`` sia nel
gestore POST sia nel lettore JSON) e una propria selezione di canale
(query_cap_rf / query_cap_inet), invece di ereditare i due interruttori
di sorgente: quelli dicono dove viene ascoltata una domanda, mentre questo
attiva il trasmettitore con un temporizzatore proprio. Richiede inoltre
igate_en, perché la riga annuncia un gateway.
Elementi di capacità aggiuntivi (query_cap_extra) viene accodato ai due
obbligatori, perché l’elenco delle capacità è aperto. Al testo vengono tolti CR,
LF e i byte , e > che delimitano la riga stessa, nel gestore POST e di
nuovo alla lettura della configurazione salvata, così un elemento digitato nel
campo non può inventare un token né chiudere l’elenco in anticipo.
Viene costruito un pacchetto per ogni tratta abilitata, perché il percorso
differisce fra loro, ed entrambi provengono dallo stesso costruttore usato dalla
risposta a ?IGATE?. La trasmissione gira sul task dello scheduler dei beacon,
insieme agli altri originatori periodici.
Query dirette#
Risposte solo con query_directed_en attivo. ?APRSP e ?APRSS sono
sempre disponibili in quell’insieme; le restanti, di tipo elenco, richiedono
inoltre Query dirette estese (query_ext_en).
Query |
Risposta |
|---|---|
|
Rapporto di posizione (stesso costruttore di |
|
Rapporto di stato, byte per byte ciò che invia il beacon di stato dell’IGate sullo stesso canale — incluso il blocco del locatore Maidenhead quando quell’opzione della pagina Station è attiva. |
|
Le stazioni sentite dirette (non via digipeater), come messaggio di testo APRS di ritorno a chi ha chiesto. Vengono scartati nominativi interi anziché troncare quando l’elenco supererebbe la lunghezza del messaggio in onda. |
|
Il grafico di 18 ore di ascolto di una stazione: |
|
Reinvia i messaggi pendenti di questa stazione per l’operatore che
interroga, fino a |
|
Riannuncia gli Oggetti/Item originati qui. Chiama
|
|
Il percorso preso dalla query stessa, letto dalla riga TNC2 ricevuta al momento di accodare la richiesta. Senza riga disponibile risponde con percorso sconosciuto. |
Le risposte di tipo elenco escono come messaggi di testo APRS indirizzati alla
stazione che interroga, con il campo destinatario fisso di 9 caratteri riempito
di spazi e senza numero di messaggio — una risposta a query è informativa,
quindi non sollecita ack. Il nominativo di destinazione usato per il traffico di
query è APE32I, e il percorso è la maschera di percorso della pagina IGate.
Limitazione di frequenza#
Tre limitatori evitano che il risponditore diventi un problema di tempo in onda o metà di un anello di retroazione con un altro auto-risponditore:
Limitatore broadcast — per tipo di query e sorgente, al massimo una risposta ogni
g_config.query_min_interval_sec(30 s predefiniti; il minimo della pagina Query è 5 s). Essendo per tipo, un canale affollato che chiede?APRS?non può sopprimere una risposta a?WX?; essendo anche per sorgente, un flusso APRS-IS loquace non può consumare la quota che serve a una domanda ascoltata in onda.Limitatore delle dirette per nominativo — le query dirette saltano il limitatore broadcast (sono esplicitamente indirizzate a questa stazione) ma hanno un proprio limite, più stretto, di
QUERY_DIRECTED_MIN_INTERVAL_SEC(5 s) per nominativo che interroga, tracciato in una tabella fissa diQUERY_DIRECTED_TRACK_MAX(8) voci. Le query dirette sono traffico raro, quindi una tabella piena semplicemente ricicla la voce più vecchia.Tetto globale delle dirette — al massimo una risposta diretta per sorgente ogni
QUERY_DIRECTED_GLOBAL_MIN_INTERVAL_SEC(10 s), indipendentemente da quanti nominativi interroghino. La tabella per nominativo è un limite di equità e non può essere da sola un limite di tempo in onda: il nominativo su cui si indicizza è scelto da chi interroga e, sulla gamba APRS-IS, non è affatto autenticato, quindi ruotare più nominativi di quanti la tabella ne contenga riciclerebbe le voci e comprerebbe una quota nuova ogni volta. Questo tetto si indicizza su qualcosa che chi interroga non controlla, quindi ruotare i nominativi non compra nulla. Una raffica di N query dirette da N nominativi diversi produce dunque al massimo una risposta per intervallo.
I due limiti delle dirette vengono applicati in serie e una richiesta deve superarli entrambi. Il tetto viene controllato per primo e timbrato per ultimo, così una richiesta che la sorgente non può ancora soddisfare non consuma nemmeno la quota propria del nominativo che interroga.
I limitatori girano sul task che ha ricevuto la query, e sono due: il task del modem per RF e il task dell’IGate per APRS-IS. Le due tabelle di marche temporali sono indicizzate per sorgente, quindi ogni task raggiunge solo le proprie voci e non serve alcun lock. La tabella per nominativo è indicizzata solo sul nominativo che interroga, quindi entrambi i task raggiungono le stesse otto celle; viene presa sotto un proprio mutex per la durata della scansione, che sono poche comparazioni di stringhe senza I/O. Una query che non riesce a prendere quel lock è trattata come limitata in frequenza e resta senza risposta, il che sbaglia verso il non trasmettere.
Configurazione#
La pagina Query (page_query.c) espone, in ordine: Abilita,
Rispondere alle interrogazioni ricevute in RF, Rispondere alle
interrogazioni ricevute da APRS-IS, i tre interruttori di query generale (?APRS?,
?WX?, ?IGATE? — gli ultimi due appaiono solo nelle build che includono le
funzioni meteo e IGate), Abilita query dirette, Query dirette estese, e
l”Intervallo minimo di risposta in secondi.
Chiave JSON |
Predefinito |
Campo |
|---|---|---|
|
|
abilitazione principale (opt-in, come la messaggistica) |
|
|
quale sorgente viene risposta: query ascoltate in RF / lette dal flusso APRS-IS. La sorgente APRS-IS è spenta per impostazione predefinita, così il traffico di dorsale non può attivare il trasmettitore appena installato. |
|
|
abilitazioni per singola query generale |
|
|
insieme diretto / insieme diretto esteso |
|
|
limite di frequenza broadcast, in secondi |
L’intera pagina è condizionata dall’interruttore di compilazione ENABLE_QUERY.
Nota
query_init() deve essere eseguita dopo message_init()/igate_start()
e prima che aprs_service_start() finisca di cablare la catena di dispatch
RX, che è esattamente dove la chiama aprs_service.c.