Files
mayhem-firmware/firmware/application/external/kiss_tnc/main.cpp
T
Sarah Rose bf5ea0a004 Add KISS TNC external app for APRS RX/TX over USB serial (#3078)
* Add KISS TNC external app for APRS RX/TX over USB serial

Adds a KISS TNC (Terminal Node Controller) app that bridges APRS
packets between the HackRF radio and a connected PC over USB CDC
serial using the KISS protocol.

Features:
- APRS receive at 144.390 MHz (configurable), decoding packets via
  the existing APRS RX baseband (PAPR.bin)
- Received AX.25 frames forwarded to host as KISS-framed data over
  USB serial
- KISS frames received from host transmitted as AFSK audio using the
  existing AFSK TX baseband (PAFT.bin)
- Clean RX->TX->RX baseband switching with proper timing delays
- USB connection status indicator with periodic refresh
- Compatible with standard KISS TNC clients (Xastir, APRSISCE/32,
  Dire Wolf, etc.)

Firmware changes required to support the external app:
- baseband_api.cpp: mark set_aprs() __attribute__((used)) so it is
  retained by the linker for external app use
- protocols/ax25: add make_frame_from_raw() to build NRZI bitstream
  from raw AX.25 bytes, marked __attribute__((used))
- usb_serial_host_to_device: add kiss_raw_handler hook to route
  incoming USB bytes directly to a registered callback, bypassing
  the shell; marked __attribute__((used))
- baseband/proc_aprsrx: add constructor that auto-configures at
  1200 baud so external apps do not need to call set_aprs() at init

* Address PR review: generic RAII USB handler, fix TX cutoff and buffer overflow

- Replace KISS-specific set_kiss_raw_handler() in shared USB code with a
  generic UsbSerialInputHandler RAII class; any app can now register a
  handler via the ctor and it auto-clears in the dtor — no app-specific
  'if' checks in shared code, no __attribute__((used)) needed
- Remove __attribute__((used)) from set_aprs() — it is referenced directly
  by ui_aprs_rx.cpp so it will never be dead-stripped
- Fix send_kiss_frame() buffer overflow: per-byte bounds check prevents
  2-byte escape sequences from writing past the end of the output buffer
- Replace fillOBuffer(TIME_INFINITE) with chOQWriteTimeout(TIME_IMMEDIATE)
  to drop bytes instead of blocking the event loop
- Remove chThdSleepMilliseconds() calls from start_tx() and finish_tx()
- Fix TX cutoff bug: call start_tx() directly from process_kiss_frame()
  instead of deferring via tx_pending_ flag (deferral caused kiss_idx_
  to be 0 by the time start_tx() fired, producing an empty frame)

* Move USB write into UsbSerialInputHandler class

Add a write() method to UsbSerialInputHandler so all USB I/O
(both input callback and output) is encapsulated in the class.
KISS TNC now uses usb_input_handler_->write() instead of calling
chOQWriteTimeout(&SUSBD1.oqueue, ...) directly, keeping raw USB
details out of app code.

* Address PR review: remove auto-configure from APRSRxProcessor, add timeout param to write()

- Remove default_config from APRSRxProcessor() constructor; baseband should
  start unconfigured and wait for APRSRxConfigureMessage from the app side
  (already sent via baseband::set_aprs() in KISS TNC and APRS RX app)
- Remove stray #include "stdio.h" from proc_aprsrx.cpp
- Add systime_t timeout parameter with default TIME_IMMEDIATE to
  UsbSerialInputHandler::write() so callers can choose blocking behaviour
2026-03-10 10:40:27 +01:00

85 lines
2.2 KiB
C++

/*
* Copyright (C) 2024 Sarah Rose
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui.hpp"
#include "ui_kiss_tnc.hpp"
#include "ui_navigation.hpp"
#include "external_app.hpp"
namespace ui::external_app::kiss_tnc {
void initialize_app(ui::NavigationView& nav) {
nav.push<KissTncView>();
}
} // namespace ui::external_app::kiss_tnc
extern "C" {
__attribute__((section(".external_app.app_kiss_tnc.application_information"), used)) application_information_t _application_information_kiss_tnc = {
/*.memory_location = */ (uint8_t*)0x00000000,
/*.externalAppEntry = */ ui::external_app::kiss_tnc::initialize_app,
/*.header_version = */ CURRENT_HEADER_VERSION,
/*.app_version = */ VERSION_MD5,
/*.app_name = */ "KISS TNC",
/*.bitmap_data = */ {
// 16x16 icon - radio tower / TNC
0x00,
0x00,
0x08,
0x00,
0x14,
0x00,
0x22,
0x00,
0x08,
0x00,
0x08,
0x00,
0x08,
0x00,
0x3E,
0x00,
0x22,
0x00,
0x22,
0x00,
0x22,
0x00,
0x22,
0x00,
0x3E,
0x00,
0x1C,
0x00,
0x08,
0x00,
0x00,
0x00,
},
/*.icon_color = */ ui::Color::green().v,
/*.menu_location = */ app_location_t::TRX,
/*.desired_menu_position = */ -1,
/*.m4_app_tag = portapack::spi_flash::image_tag_aprs_rx */ {'P', 'A', 'P', 'R'},
/*.m4_app_offset = */ 0x00000000,
};
}