Mensajería APRS#
El componente message (components/message/) implementa la mensajería
APRS con acuse de recibo y reintento, y enrutamiento por RF y/o APRS-IS. La
administración web expone dos páginas distintas: la página Message
configura el motor (habilitación RF/INET, reintento, GPIO de alarma),
mientras que la página Snd/Rcv Msg (/msgchat) es la propia interfaz de
bandeja/redacción.
El motor de mensajes#
Cola en RAM.
s_queue[]guarda hastaMSG_QUEUE_SIZE(10) entradas, compartidas por los mensajes recibidos y salientes por igual — cada entrada lleva una banderarxtxque dice cuál es. La cola es la conversación: un mensaje enviado y uno recibido ocupan cada uno una ranura propia y la conservan hasta que tráfico más nuevo los desplaza, y una vez ocupadas las diez ranuras, guardar el siguiente mensaje descarta la entrada más antigua del hilo, sea RX o TX.MSG_TEXT_MAX(200) es el tope de almacenamiento en memoria del texto de una entrada; el límite de protocolo al aire es elAPRS_MSG_TEXT_STD_MAX(67 caracteres) aparte, que es contra el que validan el cuadro de composición y el respondedor de consultas, de modo que un campo de información":ADDRESSEE:texto{id"completo queda dentro del presupuesto TNC2 clásico de 256 bytes.Orden de la conversación. Cada mensaje guardado lleva un contador de inserción (
msg_entry_t::seq) que se asigna una sola vez y no cambia, y es ese contador — no el reloj de pared — el que ordena el hilo y elige la entrada a descartar. Así, un mensaje saliente conserva el lugar en que se escribió mientras se lo reintenta (last_txlleva la agenda de reintentos ytimesigue siendo el momento de creación), y el orden sobrevive a un salto del reloj del sistema, como la primera sincronización NTP tras el arranque.Enviar / ack / reintento.
sendAPRSMessage()encola un mensaje,sendAPRSAck()responde a uno recibido, ysendAPRSMessageRetry()— invocada a 1 Hz por la tarea de tick del servicio APRS — reenvía cualquier mensaje cuyo acuse aún no ha llegado, hastamsg_retryveces cadamsg_intervalsegundos.Respuesta a ``?APRSM``.
message_send_pending_to()reenvía lo que esta estación tiene retenido para el operador que consulta, sin gastar ninguno de los reintentos propios del mensaje ni mover su próximo reintento, y se detiene trasMSG_QUERY_BURST_MAX(3) tramas: una consulta dirigida vale un puñado de tramas, no una cola entera con el transmisor activo. Lo que el tope deja fuera sigue pendiente, así que la pasada de reintentos de arriba lo entrega separado unmsg_interval.Análisis de entrantes.
handleIncomingAPRS()analiza cualquier línea TNC2 — de RF o de APRS-IS. Un mensaje se reconoce a partir del campo de información de la línea, todo lo que sigue al primer:(ninguna dirección de un encabezado TNC2 puede contener uno), que debe llevar completo el encuadre":DESTINATARIO:"del capítulo 14: el identificador de tipo de dato:, un destinatario de nueve caracteres y un:de cierre. Es la misma prueba que aplica el clasificador de paquetes, así que un texto libre que apenas parece un mensaje — dentro de un reporte de estado, un comentario de posición o un objeto — queda donde corresponde, y ninguna trama que nunca estuvo dirigida aquí puede disparar la Alarma de Mensaje ni una transmisión de ack. De una línea que sí pasa, reconoce los mensajes dirigidos a esta estación o a un grupo de mensajes que ella lee, responde con un ack cuando es un mensaje directo, y reconoce los acks entrantes (ackNNN) para limpiar el mensaje encolado correspondiente. Cada mensaje aceptado es una línea nueva de la conversación y recibe su propia ranura, incluidos los que no traen ningún{idy los que repiten un número que la estación remitente ya había usado (la numeración se reinicia cuando esa estación se reinicia). La única línea que no ocupa ranura es una retransmisión que la cola ya tiene — mismo remitente, mismo número de mensaje, texto idéntico, mismo carácter directo/grupal —, que se responde con un ack nuevo cuando era un mensaje directo, porque un repetido significa que el remitente nunca escuchó el primero, sin aparecer dos veces en el historial. Los indicativos de origen se normalizan a mayúsculas al analizarlos, de modo que una estación ocupa un solo nombre en el hilo y un ack se empareja con el mensaje saliente que reconoce.
Grupos de mensajes#
Según el capítulo 14 de APRS101, «Message Groups», una estación receptora lee
todo mensaje dirigido a ALL, QST o CQ — el conjunto de grupos
incorporado — además de a su propio indicativo, más cualquier nombre de grupo
configurado localmente, como el destinatario que usa un net o una ronda APRS en
lugar del indicativo propio de cada participante. ALL, QST y CQ no
requieren configuración y se leen siempre; hasta MSG_USER_GROUPS (3)
nombres definidos por el operador se configuran en el bloque «Message Groups»
de la página Message, un campo de texto por ranura, el mismo patrón de
ranuras repetidas que usa la página de Boletines. Un nombre de grupo se compara
completo y sin distinguir mayúsculas/minúsculas, sin recorte de -SSID (un
grupo no es un indicativo).
Se lee, nunca se confirma. Un mensaje dirigido a un grupo se guarda en la cola y se muestra en el panel
/msgchatigual que un mensaje directo. Sin embargo, nunca se confirma, nunca se retransmite y nunca recibe una respuesta automática, lleve o no un sufijo{id: un grupo no tiene un único dueño que devuelva unackNN, y cada miembro que lo lea le respondería al remitente al mismo tiempo.handleIncomingAPRS()decide cada «enviar un ack» / «recordar un Reply-ACK adeudado» / «activar la Alarma de Mensaje» según si el destinatario coincidió exactamente con el indicativo propio de esta estación, nunca solo por haber sido aceptado — una líneaack/rejdirigida a un grupo también se ignora, ya que esta estación nunca envía un mensaje saliente a un grupo para que algo lo confirme.Ranuras de historial separadas. Un mensaje de grupo y uno directo se mantienen separados en la cola aun cuando compartan el mismo remitente y el mismo número de mensaje APRS: la detección de duplicados y el almacenamiento usan el indicativo del remitente y el número de mensaje junto con el carácter directo/grupal, de modo que los dos nunca chocan en una sola ranura ni se sobrescriben entre sí.
Enrutamiento#
Cada mensaje se enruta por una máscara de bits de canal vía un manejador de TX registrado:
MSG_CHANNEL_RF(1 << 0) →aprs_service_send_tnc2()(pata de RF).MSG_CHANNEL_INET(1 << 1) →igate_send_raw()(pata de APRS-IS).
g_config.msg_rf y g_config.msg_inet deciden qué patas están activas.
Hay una tercera pata opcional que no llega a ninguna radio: con el interruptor
«Reenviar mensajes de la estacion» de la página Telegram encendido, un
mensaje dirigido a un indicativo listado allí se entrega además al chat de
Telegram de ese usuario, sea recibido de la red o enviado desde la página
/msgchat. Ver Bot de Telegram.
La interfaz de chat de mensajes (/msgchat)#
La página /msgchat presenta un panel desplazable de mensajes enviados y
recibidos por esta estación, un campo de indicativo de destino, un cuadro de
texto de mensaje (limitado a la longitud de mensaje APRS) y un botón de envío.
Refresca su lista de mensajes vía /msgchat/list (un fragmento JSON), que
devuelve el hilo guardado completo, del más antiguo al más nuevo. Está
condicionada por el interruptor de compilación ENABLE_MSG_CHAT.
El panel se lee como una sola conversación, con los mensajes enviados y
recibidos intercalados en el orden en que ocurrieron y el más nuevo abajo. Su
script mide las burbujas de mensaje una vez maquetadas y dimensiona el panel a
las MSGCHAT_VISIBLE_MESSAGES (5) más nuevas, así se ven cinco mensajes sin
desplazar y el resto del hilo guardado — hasta MSG_QUEUE_SIZE (10) mensajes
— queda a un desplazamiento de distancia. La medición se repite al cambiar el
tamaño de la ventana, porque un texto más angosto se reparte en más líneas y
hace más altas las burbujas. El desplazamiento sigue a la conversación solo
mientras el operador ya está al final de ella, de modo que un mensaje que llega
nunca arranca el panel de las líneas viejas que se están leyendo.
Ambos números son constantes de compilación: MSGCHAT_VISIBLE_MESSAGES en
page_msgchat.c decide únicamente qué tan alto es el panel, mientras que
MSG_QUEUE_SIZE en message.h decide cuánta conversación guarda el
firmware.
Ver también
Respondedor de consultas APRS — el respondedor de consultas comparte el manejador de TX de
este componente y se alcanza desde handleIncomingAPRS() cuando el texto de
un mensaje dirigido empieza con ?.
GPIO de alarma de mensaje#
Opcionalmente (msg_alarm_enable), un mensaje entrante puede accionar un GPIO
(msg_alarm_gpio; -1 = deshabilitado), validado por
message_alarm_gpio_is_valid() — útil para encender un LED o hacer sonar un
zumbador al recibir un mensaje.