Implemented Direwolf into Pecan

pull/1/head
Sven Steudte 2018-01-19 05:05:50 +01:00
rodzic c746b1297b
commit 041635bdd1
31 zmienionych plików z 4646 dodań i 221 usunięć

Wyświetl plik

@ -5,7 +5,7 @@
# Compiler options here.
ifeq ($(USE_OPT),)
USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
USE_OPT = -std=gnu99 -O2 -ggdb -fomit-frame-pointer -falign-functions=16
endif
# C specific options here (added to USE_OPT).
@ -128,8 +128,10 @@ CSRC = $(STARTUPSRC) \
threads/radio/modulation.c \
protocols/ssdv/ssdv.c \
protocols/ssdv/rs8.c \
protocols/aprs/aprs.c \
protocols/aprs/ax25.c \
protocols/aprs2/ax25_pad.c \
protocols/aprs2/dedupe.c \
protocols/aprs2/fcs_calc.c \
protocols/aprs2/aprs.c \
drivers/wrapper/pi2c.c \
drivers/wrapper/ei2c.c \
drivers/wrapper/padc.c \
@ -152,7 +154,7 @@ CSRC = $(STARTUPSRC) \
config.c \
watchdog.c \
usbcfg.c \
main.c
main.c \
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
# setting.
@ -236,13 +238,13 @@ CPPWARN = -Wall -Wextra -Wundef
#
# List all user C define here, like -D_DEBUG=1
UDEFS =
UDEFS = -D_GNU_SOURCE
# Define ASM defines here
UADEFS =
# List all user directories here
UINCDIR = threads/ drivers/ drivers/wrapper/ protocols/aprs \
UINCDIR = threads/ drivers/ drivers/wrapper/ protocols/aprs2 \
protocols/ssdv protocols/morse math/ drivers/flash/ \
fatfs/src/ threads/radio/

Wyświetl plik

@ -360,7 +360,7 @@
#include "chprintf.h"
// Global variables
systime_t track_cycle_time = S2ST(60); // Tracking cycle (all peripheral data [airpressure, GPS, temperature, ...] is collected each 60 seconds
systime_t track_cycle_time = S2ST(30); // Tracking cycle (all peripheral data [airpressure, GPS, temperature, ...] is collected each 60 seconds
bool keep_cam_switched_on = false; // Keep camera switched on and initialized, this makes image capturing faster but takes a lot of power over long time
uint16_t gps_on_vbat = 1000; // Battery voltage threshold at which GPS is switched on
uint16_t gps_off_vbat = 1000; // Battery voltage threshold at which GPS is switched off
@ -369,7 +369,7 @@ uint16_t gps_onper_vbat = 1000; // Battery voltage threshold at which GPS
module_conf_t config[7];
uint8_t ssdv_buffer[245*1024] __attribute__((aligned(32))); // Image buffer
uint8_t ssdv_buffer[128*1024] __attribute__((aligned(32))); // Image buffer
void start_user_modules(void)
{
@ -381,7 +381,7 @@ void start_user_modules(void)
// Module POSITION, APRS 2m AFSK
config[0].power = 127; // Transmission Power
config[0].protocol = PROT_APRS_AFSK; // Protocol APRS (AFSK)
config[0].modulation = MOD_AFSK; // Protocol APRS (AFSK)
config[0].frequency.type = FREQ_APRS_REGION; // Dynamic frequency allocation
config[0].frequency.hz = 144800000; // Default frequency 144.800 MHz
config[0].trigger.type = TRIG_NEW_POINT; // Transmit when tracking manager samples new tracking point
@ -392,14 +392,14 @@ void start_user_modules(void)
config[0].aprs_conf.preamble = 200; // APRS Preamble (200ms)
config[0].aprs_conf.tel_enc_cycle = 3600; // Transmit Telemetry encoding information every 3600sec
chsnprintf(config[0].aprs_conf.tel_comment, 64, "http://ssdv.habhub.org/DL7AD");// Telemetry comment
start_position_thread(&config[0]);
//start_position_thread(&config[0]);
/* ---------------------------------------------------- IMAGE TRANSMISSION --------------------------------------------------- */
// Module IMAGE, APRS 2m AFSK low-duty cycle
config[3].power = 127; // Transmission Power
config[3].protocol = PROT_APRS_AFSK; // Protocol APRS/SSDV (AFSK)
config[3].modulation = MOD_AFSK; // Protocol APRS/SSDV (AFSK)
config[3].frequency.type = FREQ_APRS_REGION; // Dynamic frequency allocation
config[3].frequency.hz = 144800000; // Transmission frequency 144.800 MHz
config[3].packet_spacing = 10000; // Packet spacing in ms
@ -416,7 +416,7 @@ void start_user_modules(void)
// Module IMAGE, APRS 2m 2FSK
config[4].power = 127; // Transmission Power
config[4].protocol = PROT_APRS_2FSK; // Protocol APRS/SSDV (2FSK)
config[4].modulation = MOD_2FSK; // Protocol APRS/SSDV (2FSK)
config[4].fsk_conf.speed = 9600; // 2FSK Speed
config[4].frequency.type = FREQ_STATIC; // Static frequency allocation
config[4].frequency.hz = 144860000; // Transmission frequency 144.860 MHz
@ -436,7 +436,7 @@ void start_user_modules(void)
// Module LOG, APRS 2m AFSK
config[6].power = 127; // Transmission Power
config[6].protocol = PROT_APRS_AFSK; // Protocol APRS (AFSK)
config[6].modulation = MOD_AFSK; // Protocol APRS (AFSK)
config[6].frequency.type = FREQ_APRS_REGION; // Dynamic frequency allocation
config[6].frequency.hz = 144800000; // Default frequency 144.800 MHz
config[6].init_delay = 5000; // Module startup delay (5 seconds)

Wyświetl plik

@ -6,7 +6,7 @@
#define LOG_SECTOR_SIZE 0x20000 /* Log flash memory size */
#define TRACE_TIME TRUE /* Enables time tracing on debugging port */
#define TRACE_FILE FALSE /* Enables file and line tracing on debugging port */
#define TRACE_FILE TRUE /* Enables file and line tracing on debugging port */
#define ACTIVATE_USB TRUE /* If set to true, the USB interface will be switched on. The tracker is also switched to
* 3V, because USB would not work at 1.8V. Note that the transmission power is increased

Wyświetl plik

@ -8,6 +8,7 @@
#include "pi2c.h"
#include "ov5640.h"
#include "geofence.h"
#include "aprs.h"
const SerialConfig uart_config =
{
@ -19,7 +20,7 @@ const SerialConfig uart_config =
mutex_t trace_mtx; // Used internal to synchronize multiple chprintf in debug.h
bool debug_on_usb = true;
bool debug_on_usb = false;
void debugOnUSB(BaseSequentialStream *chp, int argc, char *argv[])
{
@ -112,7 +113,7 @@ void printConfig(BaseSequentialStream *chp, int argc, char *argv[])
if(argc < 1)
{
chprintf(chp, "Argument missing!\r\n");
chprintf(chp, "Argument 1: Id of config!\r\n");
chprintf(chp, "Argument 1: Id of config\r\n");
return;
}
@ -132,7 +133,7 @@ void printConfig(BaseSequentialStream *chp, int argc, char *argv[])
chprintf(chp, "Frequency: APRS region dependent (currently %d.%03d MHz)\r\n", freq/1000000, (freq%1000000)/1000);
}
chprintf(chp, "Protocol: %d\r\n", config[id].protocol);
chprintf(chp, "Modulation: %d\r\n", config[id].modulation);
chprintf(chp, "Initial Delay: %d\r\n", config[id].init_delay);
chprintf(chp, "Packet Spacing: %d\r\n", config[id].packet_spacing);
chprintf(chp, "Sleep config: xx\r\n");
@ -145,9 +146,34 @@ void printConfig(BaseSequentialStream *chp, int argc, char *argv[])
chprintf(chp, "SSDV config: xx\r\n");
chprintf(chp, "Watchdog timeout: %d\r\n", config[id].wdg_timeout);
}
void send_aprs_message(BaseSequentialStream *chp, int argc, char *argv[])
{
aprs_conf_t aprs_conf;
chsnprintf(aprs_conf.callsign, 16, "DL7AD"); // APRS Callsign
aprs_conf.ssid = 14; // APRS SSID
chsnprintf(aprs_conf.path, 16, "WIDE1-1"); // APRS Path
aprs_conf.preamble = 200; // APRS Preamble (200ms)
freq_conf_t frequency;
frequency.type = FREQ_APRS_REGION; // Dynamic frequency allocation
frequency.hz = 144800000; // Default frequency 144.800 MHz
if(argc < 2)
{
chprintf(chp, "Argument missing!\r\n");
chprintf(chp, "Argument 1: Destination\r\n");
chprintf(chp, "Argument 2: Message\r\n");
return;
}
chprintf(chp, "Destination: %s\r\n", argv[0]);
chprintf(chp, "Message: %s\r\n", argv[1]);
packet_t packet = aprs_encode_message(&aprs_conf, argv[0], argv[1], false);
transmitOnRadio(packet, &frequency, 127, MOD_AFSK);
chprintf(chp, "Message sent!\r\n");
}

Wyświetl plik

@ -40,6 +40,7 @@ extern bool debug_on_usb;
chprintf((BaseSequentialStream*)&SDU1, " "); \
chprintf((BaseSequentialStream*)&SDU1, (format), ##args); \
chprintf((BaseSequentialStream*)&SDU1, "\r\n"); \
chThdSleepMilliseconds(10); \
} \
}
@ -84,6 +85,7 @@ void printConfig(BaseSequentialStream *chp, int argc, char *argv[]);
void printPicture(BaseSequentialStream *chp, int argc, char *argv[]);
void readLog(BaseSequentialStream *chp, int argc, char *argv[]);
void command2Camera(BaseSequentialStream *chp, int argc, char *argv[]);
void send_aprs_message(BaseSequentialStream *chp, int argc, char *argv[]);
#endif

Wyświetl plik

@ -13,6 +13,7 @@ static const ShellCommand commands[] = {
{"log", readLog},
{"config", printConfig},
{"command", command2Camera},
{"aprs_message", send_aprs_message},
{NULL, NULL}
};

Wyświetl plik

@ -133,7 +133,7 @@ size_t basE91_encode_end(base91_t *b, void *o)
return n;
}
void base91_encode(const uint8_t *in, uint8_t *out, uint16_t input_length) {
size_t base91_encode(const uint8_t *in, uint8_t *out, uint16_t input_length) {
base91_t handle;
uint32_t ototal = 0;
@ -143,5 +143,6 @@ void base91_encode(const uint8_t *in, uint8_t *out, uint16_t input_length) {
basE91_init(&handle);
ototal += basE91_encode(&handle, in, input_length, out);
ototal += basE91_encode_end(&handle, out + ototal);
return ototal;
}

Wyświetl plik

@ -9,6 +9,6 @@
#define BASE91LEN(in) ((((in)*16)+26) / 13)
void base64_encode(const uint8_t *in, uint8_t *out, uint16_t input_length);
void base91_encode(const uint8_t *in, uint8_t *out, uint16_t input_length);
size_t base91_encode(const uint8_t *in, uint8_t *out, uint16_t input_length);
#endif

Wyświetl plik

@ -0,0 +1,40 @@
CC := gcc
CFLAGS += -O2
LDFLAGS +=
# ---------------------------------------- Other utilities included ------------------------------
# Provide our own copy of strlcpy and strlcat because they are not included with Linux.
# We don't need the others in that same directory.
misc.a : strlcpy.o strlcat.o
ar -cr $@ $^
strlcpy.o : strlcpy.c
$(CC) $(CFLAGS) -I. -c -o $@ $^
strlcat.o : strlcat.c
$(CC) $(CFLAGS) -I. -c -o $@ $^
# ---------------------------------- Application --------------------------------
.PHONY : dtest
dtest : digipeater.c dedupe.c ax25_pad.o fcs_calc.o misc.a
$(CC) $(CFLAGS) -DDIGITEST -o $@ $^ $(LDFLAGS)
# ./dtest
# rm dtest
.PHONY: clean
clean :
rm -f dtest *.o

Wyświetl plik

@ -0,0 +1,155 @@
/* trackuino copyright (C) 2010 EA5HAV Javi
*
* 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
* of the License, 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "aprs.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "debug.h"
#include "base91.h"
#define METER_TO_FEET(m) (((m)*26876) / 8192)
static uint16_t msg_id;
/**
* Transmit APRS position packet. The comments are filled with:
* - Static comment (can be set in config.h)
* - Battery voltage in mV
* - Solar voltage in mW (if tracker is solar-enabled)
* - Temperature in Celcius
* - Air pressure in Pascal
* - Number of satellites being used
* - Number of cycles where GPS has been lost (if applicable in cycle)
*/
packet_t aprs_encode_position(const aprs_conf_t *config, trackPoint_t *trackPoint)
{
// Latitude
uint32_t y = 380926 * (90 - trackPoint->gps_lat/10000000.0);
uint32_t y3 = y / 753571;
uint32_t y3r = y % 753571;
uint32_t y2 = y3r / 8281;
uint32_t y2r = y3r % 8281;
uint32_t y1 = y2r / 91;
uint32_t y1r = y2r % 91;
// Longitude
uint32_t x = 190463 * (180 + trackPoint->gps_lon/10000000.0);
uint32_t x3 = x / 753571;
uint32_t x3r = x % 753571;
uint32_t x2 = x3r / 8281;
uint32_t x2r = x3r % 8281;
uint32_t x1 = x2r / 91;
uint32_t x1r = x2r % 91;
// Altitude
uint32_t a = logf(METER_TO_FEET(trackPoint->gps_alt)) / logf(1.002f);
uint32_t a1 = a / 91;
uint32_t a1r = a % 91;
uint8_t gpsFix = trackPoint->gps_lock == GPS_LOCKED1 || trackPoint->gps_lock == GPS_LOCKED2 ? GSP_FIX_CURRENT : GSP_FIX_OLD;
uint8_t src = NMEA_SRC_GGA;
uint8_t origin = ORIGIN_PICO;
char xmit[256];
uint32_t len = chsnprintf(xmit, sizeof(xmit), "%s-%d>%s,%s:!", config->callsign, config->ssid, APRS_DEST_CALLSIGN, config->path);
xmit[len+0] = (config->symbol >> 8) & 0xFF;
xmit[len+1] = y3+33;
xmit[len+2] = y2+33;
xmit[len+3] = y1+33;
xmit[len+4] = y1r+33;
xmit[len+5] = x3+33;
xmit[len+6] = x2+33;
xmit[len+7] = x1+33;
xmit[len+8] = x1r+33;
xmit[len+9] = config->symbol & 0xFF;
xmit[len+10] = a1+33;
xmit[len+11] = a1r+33;
xmit[len+12] = ((gpsFix << 5) | (src << 3) | origin) + 33;
// Comments
uint32_t len2 = base91_encode((uint8_t*)trackPoint, (uint8_t*)&xmit[len+13], sizeof(trackPoint_t));
xmit[len+len2+13] = '|';
// Sequence ID
uint32_t t = trackPoint->id & 0x1FFF;
xmit[len+len2+14] = t/91 + 33;
xmit[len+len2+15] = t%91 + 33;
// Telemetry parameter
for(uint8_t i=0; i<5; i++) {
switch(i) {
case 0: t = trackPoint->adc_vbat; break;
case 1: t = trackPoint->adc_vsol; break;
case 2: t = trackPoint->pac_pbat+4096; break;
case 3: t = trackPoint->sen_i1_temp/10 + 1000; break;
case 4: t = trackPoint->sen_i1_press/125 - 40; break;
}
xmit[len+len2+16+i*2] = t/91 + 33;
xmit[len+len2+16+i*2+1] = t%91 + 33;
}
xmit[len+len2+26] = '|';
xmit[len+len2+27] = 0;
TRACE_DEBUG("aprs_encode_position() => %s", xmit);
return ax25_from_text(xmit, 1);
}
packet_t aprs_encode_data_packet(char packetType, const aprs_conf_t *config, uint8_t *data)
{
char xmit[256];
chsnprintf(xmit, sizeof(xmit), "%s-%d>%s,%s:{{%c%s", config->callsign, config->ssid, APRS_DEST_CALLSIGN, config->path, packetType, data);
TRACE_DEBUG("aprs_encode_data_packet() => %s", xmit);
return ax25_from_text(xmit, 1);
}
/**
* Transmit message packet
*/
packet_t aprs_encode_message(const aprs_conf_t *config, const char *receiver, const char *text, const bool noCounter)
{
char xmit[256];
if(noCounter)
chsnprintf(xmit, sizeof(xmit), "%s-%d>%s,%s::%-9s:%s", config->callsign, config->ssid, APRS_DEST_CALLSIGN, config->path, receiver, text);
else
chsnprintf(xmit, sizeof(xmit), "%s-%d>%s,%s::%-9s:%s{%d", config->callsign, config->ssid, APRS_DEST_CALLSIGN, config->path, receiver, text, ++msg_id);
TRACE_DEBUG("aprs_encode_message() => %s", xmit);
return ax25_from_text(xmit, 1);
}
/**
* Transmit APRS telemetry configuration
*/
packet_t aprs_encode_telemetry_configuration(const aprs_conf_t *config, uint8_t type)
{
char dest[16];
chsnprintf(dest, sizeof(dest), "%s-%d", config->callsign, config->ssid);
switch(type)
{
case 0: return aprs_encode_message(config, dest, "PARM.Vbat,Vsol,Pbat,Temperature,Airpressure", true);
case 1: return aprs_encode_message(config, dest, "UNIT.V,V,W,degC,Pa", true);
case 2: return aprs_encode_message(config, dest, "EQNS.0,.001,0,0,.001,0,0,.001,-4.096,0,.1,-100,0,12.5,500", true);
case 3: return aprs_encode_message(config, dest, "BITS.11111111,", true);
}
}

Wyświetl plik

@ -0,0 +1,58 @@
/* trackuino copyright (C) 2010 EA5HAV Javi
*
* 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
* of the License, 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; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __APRS_H__
#define __APRS_H__
#include "config.h"
#include "si4464.h"
#include "ax25_pad.h"
#include "tracking.h"
#define GSP_FIX_OLD 0x0
#define GSP_FIX_CURRENT 0x1
#define NMEA_SRC_OTHER 0x0
#define NMEA_SRC_GLL 0x1
#define NMEA_SRC_GGA 0x2
#define NMEA_SRC_RMC 0x3
#define ORIGIN_COMPRESSED 0x0
#define ORIGIN_TNC_BTEXT 0x1
#define ORIGIN_SOFTWARE 0x2
#define ORIGIN_RESERVED 0x3
#define ORIGIN_KPC3 0x4
#define ORIGIN_PICO 0x5
#define ORIGIN_OTHER_TRACKER 0x6
#define ORIGIN_DIGIPEATER_CONVERSION 0x7
#define APRS_DEST_CALLSIGN "APECAN" // APExxx = Pecan device
#define APRS_DEST_SSID 0
#define SYM_BALLOON 0x2F4F
#define SYM_SMALLAIRCRAFT 0x2F27
#define SYM_SATELLITE 0x5C53
#define SYM_CAR 0x2F3E
#define SYM_SHIP 0x2F73
packet_t aprs_encode_position(const aprs_conf_t *config, trackPoint_t *trackPoint);
packet_t aprs_encode_telemetry_configuration(const aprs_conf_t *config, uint8_t type);
packet_t aprs_encode_message(const aprs_conf_t *config, const char *receiver, const char *text, const bool noCounter);
packet_t aprs_encode_data_packet(char packetType, const aprs_conf_t *config, uint8_t *data);
#endif

Wyświetl plik

@ -0,0 +1,415 @@
/*-------------------------------------------------------------------
*
* Name: ax25_pad.h
*
* Purpose: Header file for using ax25_pad.c
*
*------------------------------------------------------------------*/
#ifndef AX25_PAD_H
#define AX25_PAD_H 1
#define DEBUGX 0
#define DEBUG 0
#define DEBUG14H 0
#define AXTEST 0
#define AX25_MAX_REPEATERS 8
#define AX25_MIN_ADDRS 2 /* Destinatin & Source. */
#define AX25_MAX_ADDRS 10 /* Destination, Source, 8 digipeaters. */
#define AX25_DESTINATION 0 /* Address positions in frame. */
#define AX25_SOURCE 1
#define AX25_REPEATER_1 2
#define AX25_REPEATER_2 3
#define AX25_REPEATER_3 4
#define AX25_REPEATER_4 5
#define AX25_REPEATER_5 6
#define AX25_REPEATER_6 7
#define AX25_REPEATER_7 8
#define AX25_REPEATER_8 9
#define AX25_MAX_ADDR_LEN 12 /* In theory, you would expect the maximum length */
/* to be 6 letters, dash, 2 digits, and nul for a */
/* total of 10. However, object labels can be 10 */
/* characters so throw in a couple extra bytes */
/* to be safe. */
#define AX25_MIN_INFO_LEN 0 /* Previously 1 when considering only APRS. */
#define AX25_MAX_INFO_LEN 2048 /* Maximum size for APRS. */
/* AX.25 starts out with 256 as the default max */
/* length but the end stations can negotiate */
/* something different. */
/* version 0.8: Change from 256 to 2028 to */
/* handle the larger paclen for Linux AX25. */
/* These don't include the 2 bytes for the */
/* HDLC frame FCS. */
/*
* Previously, for APRS only.
* #define AX25_MIN_PACKET_LEN ( 2 * 7 + 2 + AX25_MIN_INFO_LEN)
* #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN)
*/
/* The more general case. */
/* An AX.25 frame can have a control byte and no protocol. */
#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 )
#define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + 3 + AX25_MAX_INFO_LEN)
/*
* packet_t is a pointer to a packet object.
*
* The actual implementation is not visible outside ax25_pad.c.
*/
#define AX25_UI_FRAME 3 /* Control field value. */
#define AX25_PID_NO_LAYER_3 0xf0 /* protocol ID used for APRS */
#define AX25_PID_SEGMENTATION_FRAGMENT 0x08
#define AX25_PID_ESCAPE_CHARACTER 0xff
struct packet_s {
int magic1; /* for error checking. */
int seq; /* unique sequence number for debugging. */
double release_time; /* Time stamp in format returned by dtime_now(). */
/* When to release from the SATgate mode delay queue. */
#define MAGIC 0x41583235
struct packet_s *nextp; /* Pointer to next in queue. */
int num_addr; /* Number of addresses in frame. */
/* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */
/* It will be 0 if it doesn't look like AX.25. */
/* -1 is used temporarily at allocation to mean */
/* not determined yet. */
/*
* The 7th octet of each address contains:
*
* Bits: H R R SSID 0
*
* H for digipeaters set to 0 intially.
* Changed to 1 when position has been used.
*
* for source & destination it is called
* command/response. Normally both 1 for APRS.
* They should be opposites for connected mode.
*
* R R Reserved. Normally set to 1 1.
*
* SSID Substation ID. Range of 0 - 15.
*
* 0 Usually 0 but 1 for last address.
*/
#define SSID_H_MASK 0x80
#define SSID_H_SHIFT 7
#define SSID_RR_MASK 0x60
#define SSID_RR_SHIFT 5
#define SSID_SSID_MASK 0x1e
#define SSID_SSID_SHIFT 1
#define SSID_LAST_MASK 0x01
int frame_len; /* Frame length without CRC. */
int modulo; /* I & S frames have sequence numbers of either 3 bits (modulo 8) */
/* or 7 bits (modulo 128). This is conveyed by either 1 or 2 */
/* control bytes. Unfortunately, we can't determine this by looking */
/* at an isolated frame. We need to know about the context. If we */
/* are part of the conversation, we would know. But if we are */
/* just listening to others, this would be more difficult to determine. */
/* For U frames: set to 0 - not applicable */
/* For I & S frames: 8 or 128 if known. 0 if unknown. */
unsigned char frame_data[AX25_MAX_PACKET_LEN+1];
/* Raw frame contents, without the CRC. */
int magic2; /* Will get stomped on if above overflows. */
};
typedef struct packet_s *packet_t;
typedef enum cmdres_e { cr_00 = 2, cr_cmd = 1, cr_res = 0, cr_11 = 3 } cmdres_t;
extern packet_t ax25_new (void);
/*
* APRS always has one control octet of 0x03 but the more
* general AX.25 case is one or two control bytes depending on
* whether "modulo 128 operation" is in effect.
*/
//#define DEBUGX 1
static inline int ax25_get_control_offset (packet_t this_p)
{
return (this_p->num_addr*7);
}
static inline int ax25_get_num_control (packet_t this_p)
{
int c;
c = this_p->frame_data[ax25_get_control_offset(this_p)];
if ( (c & 0x01) == 0 ) { /* I xxxx xxx0 */
#if DEBUGX
TRACE_DEBUG ("ax25_get_num_control, %02x is I frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1);
#endif
return ((this_p->modulo == 128) ? 2 : 1);
}
if ( (c & 0x03) == 1 ) { /* S xxxx xx01 */
#if DEBUGX
TRACE_DEBUG ("ax25_get_num_control, %02x is S frame, returns %d\n", c, (this_p->modulo == 128) ? 2 : 1);
#endif
return ((this_p->modulo == 128) ? 2 : 1);
}
#if DEBUGX
TRACE_DEBUG ("ax25_get_num_control, %02x is U frame, always returns 1.\n", c);
#endif
return (1); /* U xxxx xx11 */
}
/*
* APRS always has one protocol octet of 0xF0 meaning no level 3
* protocol but the more general case is 0, 1 or 2 protocol ID octets.
*/
static inline int ax25_get_pid_offset (packet_t this_p)
{
return (ax25_get_control_offset (this_p) + ax25_get_num_control(this_p));
}
static int ax25_get_num_pid (packet_t this_p)
{
int c;
int pid;
c = this_p->frame_data[ax25_get_control_offset(this_p)];
if ( (c & 0x01) == 0 || /* I xxxx xxx0 */
c == 0x03 || c == 0x13) { /* UI 000x 0011 */
pid = this_p->frame_data[ax25_get_pid_offset(this_p)];
#if DEBUGX
TRACE_DEBUG ("ax25_get_num_pid, %02x is I or UI frame, pid = %02x, returns %d\n", c, pid, (pid==AX25_PID_ESCAPE_CHARACTER) ? 2 : 1);
#endif
if (pid == AX25_PID_ESCAPE_CHARACTER) {
return (2); /* pid 1111 1111 means another follows. */
}
return (1);
}
#if DEBUGX
TRACE_DEBUG ("ax25_get_num_pid, %02x is neither I nor UI frame, returns 0\n", c);
#endif
return (0);
}
/*
* AX.25 has info field for 5 frame types depending on the control field.
*
* xxxx xxx0 I
* 000x 0011 UI (which includes APRS)
* 101x 1111 XID
* 111x 0011 TEST
* 100x 0111 FRMR
*
* APRS always has an Information field with at least one octet for the Data Type Indicator.
*/
static inline int ax25_get_info_offset (packet_t this_p)
{
int offset = ax25_get_control_offset (this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p);
#if DEBUGX
TRACE_DEBUG ("ax25_get_info_offset, returns %d\n", offset);
#endif
return (offset);
}
static inline int ax25_get_num_info (packet_t this_p)
{
int len;
/* assuming AX.25 frame. */
len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p);
if (len < 0) {
len = 0; /* print error? */
}
return (len);
}
typedef enum ax25_modulo_e { modulo_unknown = 0, modulo_8 = 8, modulo_128 = 128 } ax25_modulo_t;
typedef enum ax25_frame_type_e {
frame_type_I = 0, // Information
frame_type_S_RR, // Receive Ready - System Ready To Receive
frame_type_S_RNR, // Receive Not Ready - TNC Buffer Full
frame_type_S_REJ, // Reject Frame - Out of Sequence or Duplicate
frame_type_S_SREJ, // Selective Reject - Request single frame repeat
frame_type_U_SABME, // Set Async Balanced Mode, Extended
frame_type_U_SABM, // Set Async Balanced Mode
frame_type_U_DISC, // Disconnect
frame_type_U_DM, // Disconnect Mode
frame_type_U_UA, // Unnumbered Acknowledge
frame_type_U_FRMR, // Frame Reject
frame_type_U_UI, // Unnumbered Information
frame_type_U_XID, // Exchange Identification
frame_type_U_TEST, // Test
frame_type_U, // other Unnumbered, not used by AX.25.
frame_not_AX25 // Could not get control byte from frame.
// This must be last because value plus 1 is
// for the size of an array.
} ax25_frame_type_t;
#ifndef AXTEST
// TODO: remove this?
#define AX25MEMDEBUG 1
#else
#define AX25MEMDEBUG 0
#endif
#if AX25MEMDEBUG // to investigate a memory leak problem
extern void ax25memdebug_set(void);
extern int ax25memdebug_get (void);
extern int ax25memdebug_seq (packet_t this_p);
extern packet_t ax25_from_text_debug (char *monitor, int strict, char *src_file, int src_line);
#define ax25_from_text(m,s) ax25_from_text_debug(m,s,__FILE__,__LINE__)
extern packet_t ax25_from_frame_debug (unsigned char *data, int len, char *src_file, int src_line);
#define ax25_from_frame(d,l,a) ax25_from_frame_debug(d,l,a,__FILE__,__LINE__);
extern packet_t ax25_dup_debug (packet_t copy_from, char *src_file, int src_line);
#define ax25_dup(p) ax25_dup_debug(p,__FILE__,__LINE__);
extern void ax25_delete_debug (packet_t pp, char *src_file, int src_line);
#define ax25_delete(p) ax25_delete_debug(p,__FILE__,__LINE__);
#else
extern packet_t ax25_from_text (char *monitor, int strict);
extern packet_t ax25_from_frame (unsigned char *data, int len);
extern packet_t ax25_dup (packet_t copy_from);
extern void ax25_delete (packet_t pp);
#endif
extern int ax25_parse_addr (int position, char *in_addr, int strict, char *out_addr, int *out_ssid, int *out_heard);
extern int ax25_check_addresses (packet_t pp);
extern packet_t ax25_unwrap_third_party (packet_t from_pp);
extern void ax25_set_addr (packet_t pp, int, char *);
extern void ax25_insert_addr (packet_t this_p, int n, char *ad);
extern void ax25_remove_addr (packet_t this_p, int n);
extern int ax25_get_num_addr (packet_t pp);
extern int ax25_get_num_repeaters (packet_t this_p);
extern void ax25_get_addr_with_ssid (packet_t pp, int n, char *station);
extern void ax25_get_addr_no_ssid (packet_t pp, int n, char *station);
extern int ax25_get_ssid (packet_t pp, int n);
extern void ax25_set_ssid (packet_t this_p, int n, int ssid);
extern int ax25_get_h (packet_t pp, int n);
extern void ax25_set_h (packet_t pp, int n);
extern int ax25_get_heard(packet_t this_p);
extern int ax25_get_first_not_repeated(packet_t pp);
extern int ax25_get_rr (packet_t this_p, int n);
extern int ax25_get_info (packet_t pp, unsigned char **paddr);
extern int ax25_cut_at_crlf (packet_t this_p);
extern void ax25_set_nextp (packet_t this_p, packet_t next_p);
extern int ax25_get_dti (packet_t this_p);
extern packet_t ax25_get_nextp (packet_t this_p);
extern void ax25_set_release_time (packet_t this_p, double release_time);
extern double ax25_get_release_time (packet_t this_p);
extern void ax25_set_modulo (packet_t this_p, int modulo);
extern void ax25_format_addrs (packet_t pp, char *);
extern void ax25_format_via_path (packet_t this_p, char *result, size_t result_size);
extern int ax25_pack (packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]);
extern ax25_frame_type_t ax25_frame_type (packet_t this_p, cmdres_t *cr, char *desc, int *pf, int *nr, int *ns);
extern void ax25_hex_dump (packet_t this_p);
extern int ax25_is_aprs (packet_t pp);
extern int ax25_is_null_frame (packet_t this_p);
extern int ax25_get_control (packet_t this_p);
extern int ax25_get_c2 (packet_t this_p);
extern int ax25_get_pid (packet_t this_p);
extern unsigned short ax25_dedupe_crc (packet_t pp);
extern unsigned short ax25_m_m_crc (packet_t pp);
extern void ax25_safe_print (char *, int, int ascii_only);
#endif /* AX25_PAD_H */
/* end ax25_pad.h */

Wyświetl plik

@ -0,0 +1,244 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2013 John Langner, WB2OSZ
//
// 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 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
//
/*------------------------------------------------------------------
*
* Name: dedupe.c
*
* Purpose: Avoid transmitting duplicate packets which are too
* close together.
*
*
* Description: We want to avoid digipeating duplicate packets to
* to help reduce radio channel congestion with
* redundant information.
* Duplicate packets can occur in several ways:
*
* (1) A digipeated packet can loop between 2 or more
* digipeaters. For example:
*
* W1ABC>APRS,WIDE3-3
* W1ABC>APRS,mycall*,WIDE3-2
* W1ABC>APRS,mycall,RPT1*,WIDE3-1
* W1ABC>APRS,mycall,RPT1,mycall*
*
* (2) We could hear our own original transmission
* repeated by someone else. Example:
*
* mycall>APRS,WIDE3-3
* mycall>APRS,RPT1*,WIDE3-2
* mycall>APRS,RPT1*,mycall*,WIDE3-1
*
* (3) We could hear the same packet from multiple
* digipeaters (with or without the original).
*
* W1ABC>APRS,WIDE3-2
* W1ABC>APRS,RPT1*,WIDE3-2
* W1ABC>APRS,RPT2*,WIDE3-2
* W1ABC>APRS,RPT3*,WIDE3-2
*
* (4) Someone could be sending the same thing over and
* over with very little delay in between.
*
* W1ABC>APRS,WIDE3-3
* W1ABC>APRS,WIDE3-3
* W1ABC>APRS,WIDE3-3
*
* We can catch the first two by looking for 'mycall' in
* the source or digipeater fields.
*
* The other two cases require us to keep a record of what
* we transmitted recently and test for duplicates that
* should be dropped.
*
* Once we have the solution to catch cases (3) and (4)
* there is no reason for the special case of looking for
* mycall. The same technique catches all four situations.
*
* For detecting duplicates, we need to look
* + source station
* + destination
* + information field
* but NOT the changing list of digipeaters.
*
* Typically, only a checksum is kept to reduce memory
* requirements and amount of compution for comparisons.
* There is a very very small probability that two unrelated
* packets will result in the same checksum, and the
* undesired dropping of the packet.
*
* References: Original APRS specification:
*
* TBD...
*
* "The New n-N Paradigm"
*
* http://www.aprs.org/fix14439.html
*
*------------------------------------------------------------------*/
#define DEDUPE_C
#include "ch.h"
#include "hal.h"
#include <stdlib.h>
#include <string.h>
#include "ax25_pad.h"
#include "dedupe.h"
#include "fcs_calc.h"
/*------------------------------------------------------------------------------
*
* Name: dedupe_init
*
* Purpose: Initialize the duplicate detection subsystem.
*
* Input: ttl - Number of seconds to retain information
* about recent transmissions.
*
*
* Returns: None
*
* Description: This should be called at application startup.
*
*
*------------------------------------------------------------------------------*/
static systime_t history_time = 30; /* Number of seconds to keep information */
/* about recent transmissions. */
#define HISTORY_MAX 25 /* Maximum number of transmission */
/* records to keep. If we run out of */
/* room the oldest ones are overwritten */
/* before they expire. */
static int insert_next; /* Index, in array below, where next */
/* item should be stored. */
static struct {
systime_t time_stamp; /* When the packet was transmitted. */
unsigned short checksum; /* Some sort of checksum for the */
/* source, destination, and information. */
/* is is not used anywhere else. */
short xmit_channel; /* Radio channel number. */
} history[HISTORY_MAX];
void dedupe_init (systime_t ttl)
{
history_time = ttl;
insert_next = 0;
memset (history, 0, sizeof(history));
}
/*------------------------------------------------------------------------------
*
* Name: dedupe_remember
*
* Purpose: Save information about a packet being transmitted so we
* can detect, and avoid, duplicates later.
*
* Input: pp - Pointer to packet object.
*
* chan - Radio channel for transmission.
*
* Returns: None
*
* Rambling: At one time, my thinking is that we want to keep track of
* ALL transmitted packets regardless of origin or type.
*
* + my beacons
* + anything from a connected application
* + anything digipeated
*
* The easiest way to catch all cases is to call dedup_remember()
* from inside tq_append().
*
* But I don't think that is the right approach.
* When acting as a KISS TNC, we should just shovel everything
* through and not question what the application is doing.
* If the connected application has a digipeating function,
* it's responsible for those decisions.
*
* My current thinking is that dedupe_remember() should be
* called BEFORE tq_append() in the digipeater case.
*
* We should also capture our own beacon transmissions.
*
*------------------------------------------------------------------------------*/
void dedupe_remember (packet_t pp, int chan)
{
history[insert_next].time_stamp = chVTGetSystemTimeX();
history[insert_next].checksum = ax25_dedupe_crc(pp);
history[insert_next].xmit_channel = chan;
insert_next++;
if (insert_next >= HISTORY_MAX) {
insert_next = 0;
}
/* If we send something by digipeater, we don't */
/* want to do it again if it comes from APRS-IS. */
/* Not sure about the other way around. */
}
/*------------------------------------------------------------------------------
*
* Name: dedupe_check
*
* Purpose: Check whether this is a duplicate of another sent recently.
*
* Input: pp - Pointer to packet object.
*
* chan - Radio channel for transmission.
*
* Returns: True if it is a duplicate.
*
*
*------------------------------------------------------------------------------*/
int dedupe_check (packet_t pp, int chan)
{
unsigned short crc = ax25_dedupe_crc(pp);
time_t now = time(NULL);
int j;
for (j=0; j<HISTORY_MAX; j++) {
if (history[j].time_stamp >= now - history_time &&
history[j].checksum == crc &&
history[j].xmit_channel == chan) {
return 1;
}
}
return 0;
}
/* end dedupe.c */

Wyświetl plik

@ -0,0 +1,12 @@
#ifndef __DEDUPE_H__
#define __DEDUPE_H__
#include "ch.h"
#include "hal.h"
void dedupe_init(systime_t ttl);
void dedupe_remember(packet_t pp, int chan);
int dedupe_check(packet_t pp, int chan);
#endif

Wyświetl plik

@ -0,0 +1,538 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011, 2013, 2014, 2015 John Langner, WB2OSZ
//
// 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 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
//
/*------------------------------------------------------------------
*
* Name: digipeater.c
*
* Purpose: Act as an APRS digital repeater.
* Similar cdigipeater.c is for connected mode.
*
*
* Description: Decide whether the specified packet should
* be digipeated and make necessary modifications.
*
*
* References: APRS Protocol Reference, document version 1.0.1
*
* http://www.aprs.org/doc/APRS101.PDF
*
* APRS SPEC Addendum 1.1
*
* http://www.aprs.org/aprs11.html
*
* APRS SPEC Addendum 1.2
*
* http://www.aprs.org/aprs12.html
*
* "The New n-N Paradigm"
*
* http://www.aprs.org/fix14439.html
*
* Preemptive Digipeating (new in version 0.8)
*
* http://www.aprs.org/aprs12/preemptive-digipeating.txt
*
*------------------------------------------------------------------*/
#define DIGIPEATER_C
#include "ch.h"
#include "hal.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h> /* for isdigit, isupper */
#include "regex.h"
#include "ax25_pad.h"
#include "digipeater.h"
#include "dedupe.h"
#include "fcs_calc.h"
uint8_t data[] = ":2000000082A0AEAE6260E0AC96648A90A21B7EAC9664829AAEE2AE92888A64406303F040E6\n";
/*------------------------------------------------------------------------------
*
* Name: digipeat_match
*
* Purpose: A simple digipeater for APRS.
*
* Input: pp - Pointer to a packet object.
*
* mycall_rec - Call of my station, with optional SSID,
* associated with the radio channel where the
* packet was received.
*
* mycall_xmit - Call of my station, with optional SSID,
* associated with the radio channel where the
* packet is to be transmitted. Could be the same as
* mycall_rec or different.
*
* alias - Compiled pattern for my station aliases or
* "trapping" (repeating only once).
*
* wide - Compiled pattern for normal WIDEn-n digipeating.
*
* to_chan - Channel number that we are transmitting to.
* This is needed to maintain a history for
* removing duplicates during specified time period.
*
* preempt - Option for "preemptive" digipeating.
*
* filter_str - Filter expression string or NULL.
*
* Returns: Packet object for transmission or NULL.
* The original packet is not modified. (with one exception, probably obsolete)
* We make a copy and return that modified copy!
* This is very important because we could digipeat from one channel to many.
*
* Description: The packet will be digipeated if the next unused digipeater
* field matches one of the following:
*
* - mycall_rec
* - udigi list (only once)
* - wide list (usual wideN-N rules)
*
*------------------------------------------------------------------------------*/
static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, char *mycall_xmit,
regex_t *alias, regex_t *wide, int to_chan, enum preempt_e preempt, char *filter_str)
{
(void)from_chan;
(void)filter_str;
char source[AX25_MAX_ADDR_LEN];
int ssid;
int r;
char repeater[AX25_MAX_ADDR_LEN];
int err;
char err_msg[100];
/*
* Find the first repeater station which doesn't have "has been repeated" set.
*
* r = index of the address position in the frame.
*/
r = ax25_get_first_not_repeated(pp);
if (r < AX25_REPEATER_1) {
return (NULL);
}
ax25_get_addr_with_ssid(pp, r, repeater);
ssid = ax25_get_ssid(pp, r);
/*
* First check for explicit use of my call, including SSID.
* Someone might explicitly specify a particular path for testing purposes.
* This will bypass the usual checks for duplicates and my call in the source.
*
* In this case, we don't check the history so it would be possible
* to have a loop (of limited size) if someone constructed the digipeater paths
* correctly. I would expect it only for testing purposes.
*/
if (strcmp(repeater, mycall_rec) == 0) {
packet_t result;
result = ax25_dup (pp);
(result == NULL)
return NULL;
/* If using multiple radio channels, they */
/* could have different calls. */
ax25_set_addr (result, r, mycall_xmit);
ax25_set_h (result, r);
return (result);
}
/*
* Don't digipeat my own. Fixed in 1.4 dev H.
* Alternatively we might feed everything transmitted into
* dedupe_remember rather than only frames out of digipeater.
*/
ax25_get_addr_with_ssid(pp, AX25_SOURCE, source);
if (strcmp(source, mycall_rec) == 0) {
return (NULL);
}
/*
* Next try to avoid retransmitting redundant information.
* Duplicates are detected by comparing only:
* - source
* - destination
* - info part
* - but not the via path. (digipeater addresses)
* A history is kept for some amount of time, typically 30 seconds.
* For efficiency, only a checksum, rather than the complete fields
* might be kept but the result is the same.
* Packets transmitted recently will not be transmitted again during
* the specified time period.
*
*/
if (dedupe_check(pp, to_chan)) {
//#if DEBUG
/* Might be useful if people are wondering why */
/* some are not repeated. Might also cause confusion. */
TRACE_DEBUG("Digipeater: Drop redundant packet to channel %d.\n", to_chan);
//#endif
return NULL;
}
/*
* For the alias pattern, we unconditionally digipeat it once.
* i.e. Just replace it with MYCALL.
*
* My call should be an implied member of this set.
* In this implementation, we already caught it further up.
*/
err = regexec(alias,repeater,0,NULL,0);
if (err == 0) {
packet_t result;
result = ax25_dup (pp);
if(result == NULL)
return NULL;
ax25_set_addr (result, r, mycall_xmit);
ax25_set_h (result, r);
return (result);
}
else if (err != REG_NOMATCH) {
regerror(err, alias, err_msg, sizeof(err_msg));
TRACE_ERROR("%s\n", err_msg);
}
/*
* If preemptive digipeating is enabled, try matching my call
* and aliases against all remaining unused digipeaters.
*/
if (preempt != PREEMPT_OFF) {
int r2;
for (r2 = r+1; r2 < ax25_get_num_addr(pp); r2++) {
char repeater2[AX25_MAX_ADDR_LEN];
ax25_get_addr_with_ssid(pp, r2, repeater2);
if (strcmp(repeater2, mycall_rec) == 0 ||
regexec(alias,repeater2,0,NULL,0) == 0) {
packet_t result;
result = ax25_dup (pp);
if(result == NULL)
return NULL;
ax25_set_addr (result, r2, mycall_xmit);
ax25_set_h (result, r2);
switch (preempt) {
case PREEMPT_DROP: /* remove all prior */
while (r2 > AX25_REPEATER_1) {
ax25_remove_addr (result, r2-1);
r2--;
}
break;
case PREEMPT_MARK:
r2--;
while (r2 >= AX25_REPEATER_1 && ax25_get_h(result,r2) == 0) {
ax25_set_h (result, r2);
r2--;
}
break;
case PREEMPT_TRACE: /* remove prior unused */
default:
while (r2 > AX25_REPEATER_1 && ax25_get_h(result,r2-1) == 0) {
ax25_remove_addr (result, r2-1);
r2--;
}
break;
}
return (result);
}
}
}
/*
* For the wide pattern, we check the ssid and decrement it.
*/
err = regexec(wide,repeater,0,NULL,0);
if (err == 0) {
/*
* If ssid == 1, we simply replace the repeater with my call and
* mark it as being used.
*
* Otherwise, if ssid in range of 2 to 7,
* Decrement y and don't mark repeater as being used.
* Insert own call ahead of this one for tracing if we don't already have the
* maximum number of repeaters.
*/
if (ssid == 1) {
packet_t result;
result = ax25_dup (pp);
if(result == NULL)
return NULL;
ax25_set_addr (result, r, mycall_xmit);
ax25_set_h (result, r);
return (result);
}
if (ssid >= 2 && ssid <= 7) {
packet_t result;
result = ax25_dup (pp);
if(result == NULL)
return NULL;
ax25_set_ssid(result, r, ssid-1); // should be at least 1
if (ax25_get_num_repeaters(pp) < AX25_MAX_REPEATERS) {
ax25_insert_addr (result, r, mycall_xmit);
ax25_set_h (result, r);
}
return (result);
}
}
else if (err != REG_NOMATCH) {
regerror(err, wide, err_msg, sizeof(err_msg));
TRACE_ERROR("%s\n", err_msg);
}
/*
* Don't repeat it if we get here.
*/
return (NULL);
}
/*-------------------------------------------------------------------------
*
* Name: main
*
* Purpose: Standalone test case for this funtionality.
*
* Usage: make -f Makefile.<platform> dtest
* ./dtest
*
*------------------------------------------------------------------------*/
static char mycall[] = "DL7AD-12";
static regex_t alias_re;
static regex_t wide_re;
static enum preempt_e preempt = PREEMPT_OFF;
static bool try_digipeat(unsigned char *frame_in, int frame_in_len, unsigned char *frame_out, int *frame_out_len)
{
if(frame_in_len > 768) // Frame is too long and would cause a buffer overflow
return false;
packet_t pp, result;
char rec[1024];
char xmit[1024];
unsigned char *pinfo;
int info_len;
pp = ax25_from_frame(frame_in, frame_in_len);
if(result == NULL)
return false;
ax25_format_addrs (pp, rec);
info_len = ax25_get_info (pp, &pinfo);
(void)info_len;
strlcat (rec, (char*)pinfo, sizeof(rec));
result = digipeat_match (0, pp, mycall, mycall, &alias_re, &wide_re, 0, preempt, NULL);
ax25_delete (pp);
if (result != NULL) {
dedupe_remember(result, 0);
ax25_format_addrs(result, xmit);
info_len = ax25_get_info(result, &pinfo);
strlcat(xmit, (char*)pinfo, sizeof(xmit));
*frame_out_len = ax25_pack(result, frame_out);
ax25_delete(result);
TRACE_DEBUG("Digipeat\n");
TRACE_DEBUG("Rec\t%s\n", rec);
TRACE_DEBUG("Xmit\t%s\n", xmit);
return true;
} else {
TRACE_DEBUG("No Digipeat\n");
TRACE_DEBUG("Rec\t%s\n", rec);
strlcpy (xmit, "", sizeof(xmit));
return false;
}
}
uint8_t intelbuffer[1024];
uint8_t out[1024];
uint8_t last;
void clearBuffer(void) {
for(uint32_t i=0; i<sizeof(intelbuffer); i++)
{
intelbuffer[i] = 0;
out[i] = 0;
}
}
void processIntelHex(uint8_t *buffer, uint32_t n) {
// Parse IntelHex data
uint8_t buffer2[n/2];
for(uint8_t count = 0; count < n/2; count++) {
sscanf((char*)&buffer[count*2], "%2hhx", &buffer2[count]);
}
// Extract data from IntelHex format
uint8_t i_len = buffer2[0];
uint16_t i_addr = (buffer2[1] << 8) | buffer2[2];
uint8_t i_type = buffer2[3];
uint8_t* i_data = &buffer2[4];
if(i_type == 1) { // Found EOF
// Check AX.25 CRC
unsigned short actual_fcs = (intelbuffer[last-1] << 8) | intelbuffer[last-2];
unsigned short expected_fcs = fcs_calc(intelbuffer, last-2);
TRACE_DEBUG("Binary[IN]: ");
for(uint32_t i=0; i<last; i++) {
TRACE_DEBUG("%02x ", intelbuffer[i]);
}
int out_len = 0;
if(actual_fcs == expected_fcs) {
try_digipeat(intelbuffer, last-2, out, &out_len);
} else {
TRACE_DEBUG("Bad CRC\n");
}
TRACE_DEBUG("Binary[OUT]: ");
for(int32_t i=0; i<out_len; i++) {
TRACE_DEBUG("%02x ", out[i]);
}
TRACE_DEBUG("---------------------------------------------------------\n");
clearBuffer();
} else if(i_type == 0) { // Found Data
memcpy(&intelbuffer[i_addr], i_data, i_len);
last = i_addr+i_len;
}
}
/*int main(int argc, char *argv[])
{
int e;
char message[256];
dedupe_init(S2ST(4));
e = regcomp(&alias_re, "^WIDE[4-7]-[1-7]|CITYD$", REG_EXTENDED|REG_NOSUB);
if(e != 0) {
regerror(e, &alias_re, message, sizeof(message));
TRACE_DEBUG("\n%s\n\n", message);
return 1;
}
e = regcomp(&wide_re, "^WIDE[1-7]-[1-7]$|^TRACE[1-7]-[1-7]$|^MA[1-7]-[1-7]$", REG_EXTENDED|REG_NOSUB);
if(e != 0) {
regerror(e, &wide_re, message, sizeof(message));
TRACE_DEBUG("\n%s\n\n", message);
return 1;
}
uint8_t buffer[1024];
uint32_t n;
uint32_t j = 0;
clearBuffer();
for(uint32_t i=0; i<sizeof(data); i++)
{
switch(j)
{
case 0: // Looking for start of frame
if(data[i] == ':') { // Found start of frame
j = 1;
n = 0;
}
break;
case 1: // capturing frame
if(data[i] == '\n' || i+1 == n) { // Found end of frame OR end of input buffer
buffer[n] = 0;
processIntelHex(buffer, n);
j = 0;
} else {
buffer[n++] = data[i];
}
break;
}
}
return 0;
}*/

Wyświetl plik

@ -0,0 +1,13 @@
#ifndef DIGIPEATER_H
#define DIGIPEATER_H 1
#include "regex.h"
#include "ax25_pad.h" /* for packet_t */
enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE };
#endif

Wyświetl plik

@ -0,0 +1,105 @@
//
// This file is part of Dire Wolf, an amateur radio packet TNC.
//
// Copyright (C) 2011 John Langner, WB2OSZ
//
// 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 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
//
/*
* Calculate the FCS for an AX.25 frame.
*/
#include "fcs_calc.h"
static const unsigned short ccitt_table[256] = {
// from http://www.ietf.org/rfc/rfc1549.txt
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
/*
* Use this for an AX.25 frame.
*/
unsigned short fcs_calc (unsigned char *data, int len)
{
unsigned short crc = 0xffff;
int j;
for (j=0; j<len; j++) {
crc = ((crc) >> 8) ^ ccitt_table[((crc) ^ data[j]) & 0xff];
}
return ( crc ^ 0xffff );
}
/*
* This can be used when we want to calculate a single CRC over disjoint data.
*
* crc = crc16 (region1, sizeof(region1), 0xffff);
* crc = crc16 (region2, sizeof(region2), crc);
* crc = crc16 (region3, sizeof(region3), crc);
*/
unsigned short crc16 (unsigned char *data, int len, unsigned short seed)
{
unsigned short crc = seed;
int j;
for (j=0; j<len; j++) {
crc = ((crc) >> 8) ^ ccitt_table[((crc) ^ data[j]) & 0xff];
}
return ( crc ^ 0xffff );
}

Wyświetl plik

@ -0,0 +1,11 @@
/* fcs_calc.h */
unsigned short fcs_calc (unsigned char *data, int len);
unsigned short crc16 (unsigned char *data, int len, unsigned short seed);
/* end fcs_calc.h */

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -0,0 +1,18 @@
/* direwolf.h - Common stuff used many places. */
#ifndef DIREWOLF_H
#define DIREWOLF_H 1
#include <stddef.h>
#define DEBUG_STRL 1
//#define strlcpy(dst,src,siz) strlcpy_debug(dst,src,siz,__FILE__,__func__,__LINE__)
//#define strlcat(dst,src,siz) strlcat_debug(dst,src,siz,__FILE__,__func__,__LINE__)
//size_t strlcpy_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz, const char *file, const char *func, int line);
//size_t strlcat_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz, const char *file, const char *func, int line);
#endif /* ifndef DIREWOLF_H */

Wyświetl plik

@ -0,0 +1,123 @@
/*------------------------------------------------------------------
*
* Module: strlcat.c
*
* Purpose: Safe string functions to guard against buffer overflow.
*
* Description: The size of character strings, especially when coming from the
* outside, can sometimes exceed a fixed size storage area.
*
* There was one case where a MIC-E format packet had an enormous
* comment that exceeded an internal buffer of 256 characters,
* resulting in a crash.
*
* We are not always meticulous about checking sizes to avoid overflow.
* Use of these functions, instead of strcpy and strcat, should
* help avoid issues.
*
* Orgin: From OpenBSD as the copyright notice indicates.
* The GNU folks didn't think it was appropriate for inclusion
* in glibc. https://lwn.net/Articles/507319/
*
* Modifications: Added extra debug output when strings are truncated.
* Not sure if I will leave this in the release version
* or just let it happen silently.
*
*---------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "direwolf.h"
/* $NetBSD: strlcat.c,v 1.5 2014/10/31 18:59:32 spz Exp $ */
/* from NetBSD: strlcat.c,v 1.16 2003/10/27 00:12:42 lukem Exp */
/* from OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
#if DEBUG_STRL
size_t strlcat_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz, const char *file, const char *func, int line)
#else
size_t strlcat_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz)
#endif
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
size_t retval;
#if DEBUG_STRL
if (dst == NULL) {
printf ("ERROR: strlcat dst is NULL. (%s %s %d)\n", file, func, line);
return (0);
}
if (src == NULL) {
printf ("ERROR: strlcat src is NULL. (%s %s %d)\n", file, func, line);
return (0);
}
if (siz == 1 || siz == 4) {
printf ("Suspicious strlcat siz. Is it using sizeof a pointer variable? (%s %s %d)\n", file, func, line);
}
#endif
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0) {
retval = dlen + strlen(s);
goto the_end;
}
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
retval = dlen + (s - src); /* count does not include NUL */
the_end:
#if DEBUG_STRL
if (retval >= siz) {
printf ("WARNING: strlcat result length %d exceeds maximum length %d. (%s %s %d)\n",
(int)retval, (int)(siz-1), file, func, line);
}
#endif
return (retval);
}

Wyświetl plik

@ -0,0 +1,115 @@
/*------------------------------------------------------------------
*
* Module: strlcpy.c
*
* Purpose: Safe string functions to guard against buffer overflow.
*
* Description: The size of character strings, especially when coming from the
* outside, can sometimes exceed a fixed size storage area.
*
* There was one case where a MIC-E format packet had an enormous
* comment that exceeded an internal buffer of 256 characters,
* resulting in a crash.
*
* We are not always meticulous about checking sizes to avoid overflow.
* Use of these functions, instead of strcpy and strcat, should
* help avoid issues.
*
* Orgin: From OpenBSD as the copyright notice indicates.
* The GNU folks didn't think it was appropriate for inclusion
* in glibc. https://lwn.net/Articles/507319/
*
* Modifications: Added extra debug output when strings are truncated.
* Not sure if I will leave this in the release version
* or just let it happen silently.
*
*---------------------------------------------------------------*/
/* $NetBSD: strlcpy.c,v 1.5 2014/10/31 18:59:32 spz Exp $ */
/* from NetBSD: strlcpy.c,v 1.14 2003/10/27 00:12:42 lukem Exp */
/* from OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "direwolf.h"
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
#if DEBUG_STRL
size_t strlcpy_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz, const char *file, const char *func, int line)
#else
size_t strlcpy_debug(char *__restrict__ dst, const char *__restrict__ src, size_t siz)
#endif
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t retval;
#if DEBUG_STRL
if (dst == NULL) {
printf ("ERROR: strlcpy dst is NULL. (%s %s %d)\n", file, func, line);
return (0);
}
if (src == NULL) {
printf ("ERROR: strlcpy src is NULL. (%s %s %d)\n", file, func, line);
return (0);
}
if (siz == 1 || siz == 4) {
printf ("Suspicious strlcpy siz. Is it using sizeof a pointer variable? (%s %s %d)\n", file, func, line);
}
#endif
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
retval = s - src - 1; /* count does not include NUL */
#if DEBUG_STRL
if (retval >= siz) {
printf ("WARNING: strlcpy result length %d exceeds maximum length %d. (%s %s %d)\n",
(int)retval, (int)(siz-1), file, func, line);
}
#endif
return (retval);
}

Wyświetl plik

@ -280,20 +280,10 @@ uint32_t gimage_id; // Global image ID (for all image threads)
mutex_t camera_mtx;
bool camera_mtx_init = false;
/**
* At EOI or if picture is cut prematurely, when buffer has to be flushed
* so all packets are transmitted.
*/
static void flush_ssdv_buffer(prot_t protocol, ax25_t *ax25_handle, radioMSG_t *msg)
{
if(isAPRS(protocol)) {
msg->bin_len = aprs_encode_finalize(ax25_handle);
transmitOnRadio(msg);
}
}
void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf, uint8_t image_id, bool redudantTx)
{
(void)redudantTx;
ssdv_t ssdv;
uint8_t pkt[SSDV_PKT_SIZE];
uint8_t pkt_base91[256];
@ -307,23 +297,6 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf,
ssdv_enc_init(&ssdv, SSDV_TYPE_PADDING, conf->ssdv_conf.callsign, image_id, conf->ssdv_conf.quality);
ssdv_enc_set_buffer(&ssdv, pkt);
// Init transmission packet
radioMSG_t msg;
uint8_t buffer[conf->packet_spacing ? 2048 : 8192];
msg.buffer = buffer;
msg.bin_len = 0;
msg.freq = &conf->frequency;
msg.power = conf->power;
ax25_t ax25_handle;
if(conf->protocol == PROT_APRS_2FSK || conf->protocol == PROT_APRS_AFSK)
{
msg.mod = conf->protocol == PROT_APRS_AFSK ? MOD_AFSK : MOD_2FSK;
msg.afsk_conf = &(conf->afsk_conf);
msg.fsk_conf = &(conf->fsk_conf);
aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod);
}
while(true)
{
conf->wdg_timeout = chVTGetSystemTimeX() + S2ST(600); // TODO: Implement more sophisticated method
@ -337,7 +310,6 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf,
if(r <= 0)
{
TRACE_ERROR("SSDV > Premature end of file");
flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
break;
}
ssdv_enc_feed(&ssdv, b, r);
@ -346,40 +318,20 @@ void encode_ssdv(const uint8_t *image, uint32_t image_len, module_conf_t* conf,
if(c == SSDV_EOI)
{
TRACE_INFO("SSDV > ssdv_enc_get_packet said EOI");
flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
break;
} else if(c != SSDV_OK) {
TRACE_ERROR("SSDV > ssdv_enc_get_packet failed: %i", c);
flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
return;
}
if(isAPRS(conf->protocol)) {
// Encode packet
TRACE_INFO("IMG > Encode APRS/SSDV packet");
// Encode packet
TRACE_INFO("IMG > Encode APRS/SSDV packet");
// Sync byte, CRC and FEC of SSDV not transmitted (because its not neccessary inside an APRS packet)
base91_encode(&pkt[6], pkt_base91, 174);
// Sync byte, CRC and FEC of SSDV not transmitted (because its not neccessary inside an APRS packet)
base91_encode(&pkt[6], pkt_base91, 174);
aprs_encode_data_packet(&ax25_handle, 'I', &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91));
if(redudantTx)
aprs_encode_data_packet(&ax25_handle, 'I', &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91));
// Transmit if buffer is almost full or if single packet transmission is activated (packet_spacing != 0)
// or if AFSK is selected (because the encoding takes a lot of buffer)
if(ax25_handle.size >= 58000 || conf->packet_spacing || conf->protocol == PROT_APRS_AFSK)
{
// Transmit packets
flush_ssdv_buffer(conf->protocol, &ax25_handle, &msg);
// Initialize new packet buffer
aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod);
}
} else {
TRACE_ERROR("IMG > Unsupported protocol selected for module IMAGE");
}
packet_t packet = aprs_encode_data_packet('I', &conf->aprs_conf, pkt_base91);
transmitOnRadio(packet, &conf->frequency, conf->power, conf->modulation);
chThdSleepMilliseconds(100); // Leave other threads some time

Wyświetl plik

@ -148,42 +148,17 @@ THD_FUNCTION(logThread, arg)
{
// Get log from memory
trackPoint_t log;
getNextLogTrackPoint(&log);
// Encode radio message
radioMSG_t msg;
uint8_t buffer[512];
msg.buffer = buffer;
msg.freq = &conf->frequency;
msg.power = conf->power;
// Encode Base91
uint8_t pkt_base91[BASE91LEN(sizeof(log))];
base91_encode((uint8_t*)&log, pkt_base91, sizeof(log));
if(isAPRS(conf->protocol)) {
// Encode and transmit log packet
packet_t packet = aprs_encode_data_packet('L', &conf->aprs_conf, pkt_base91); // Encode packet
msg.mod = conf->protocol == PROT_APRS_AFSK ? MOD_AFSK : MOD_2FSK;
msg.afsk_conf = &(conf->afsk_conf);
msg.fsk_conf = &(conf->fsk_conf);
// Encode Base91
uint8_t pkt_base91[BASE91LEN(sizeof(log))];
// Encode and transmit log packet
ax25_t ax25_handle;
aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod);
for(uint8_t i=0; i<2; i++) { // Transmit two log packets
getNextLogTrackPoint(&log);
base91_encode((uint8_t*)&log, pkt_base91, sizeof(log));
aprs_encode_data_packet(&ax25_handle, 'L', &conf->aprs_conf, pkt_base91, strlen((char*)pkt_base91)); // Encode packet
}
msg.bin_len = aprs_encode_finalize(&ax25_handle);
// Transmit packet
transmitOnRadio(&msg);
if(conf->redundantTx) transmitOnRadio(&msg);
} else {
TRACE_ERROR("LOG > Unsupported protocol selected for module LOG");
}
// Transmit packet
transmitOnRadio(packet, &conf->frequency, conf->power, conf->modulation);
}
time = waitForTrigger(time, &conf->trigger);

Wyświetl plik

@ -26,7 +26,7 @@ THD_FUNCTION(posThread, arg)
TRACE_INFO("POS > Startup position thread");
// Set telemetry configuration transmission variables
systime_t last_conf_transmission = chVTGetSystemTimeX();
systime_t last_conf_transmission = chVTGetSystemTimeX() - S2ST(conf->aprs_conf.tel_enc_cycle);
systime_t time = chVTGetSystemTimeX();
while(true)
@ -39,50 +39,27 @@ THD_FUNCTION(posThread, arg)
if(!p_sleep(&conf->sleep_conf))
{
TRACE_INFO("POS > Transmit position");
radioMSG_t msg;
uint8_t buffer[512];
msg.buffer = buffer;
msg.freq = &conf->frequency;
msg.power = conf->power;
// Encode and transmit position packet
packet_t packet = aprs_encode_position(&(conf->aprs_conf), trackPoint); // Encode packet
transmitOnRadio(packet, &conf->frequency, conf->power, conf->modulation);
if(isAPRS(conf->protocol)) {
// Telemetry encoding parameter transmission
if(conf->aprs_conf.tel_enc_cycle != 0 && last_conf_transmission + S2ST(conf->aprs_conf.tel_enc_cycle) < chVTGetSystemTimeX())
{
chThdSleepMilliseconds(5000); // Take a litte break between the packet transmissions
// Position transmission
msg.mod = conf->protocol == PROT_APRS_AFSK ? MOD_AFSK : MOD_2FSK;
msg.fsk_conf = &(conf->fsk_conf);
msg.afsk_conf = &(conf->afsk_conf);
TRACE_INFO("POS > Transmit telemetry configuration");
ax25_t ax25_handle;
// Encode and transmit position packet
aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod);
aprs_encode_position(&ax25_handle, &(conf->aprs_conf), trackPoint); // Encode packet
msg.bin_len = aprs_encode_finalize(&ax25_handle);
transmitOnRadio(&msg);
if(conf->redundantTx) transmitOnRadio(&msg);
// Telemetry encoding parameter transmission
if(conf->aprs_conf.tel_enc_cycle != 0 && last_conf_transmission + S2ST(conf->aprs_conf.tel_enc_cycle) < chVTGetSystemTimeX())
// Encode and transmit telemetry config packet
for(uint8_t type=0; type<5; type++)
{
chThdSleepMilliseconds(5000); // Take a litte break between the packet transmissions
TRACE_INFO("POS > Transmit telemetry configuration");
// Encode and transmit telemetry config packet
aprs_encode_init(&ax25_handle, buffer, sizeof(buffer), msg.mod);
aprs_encode_telemetry_configuration(&ax25_handle, &conf->aprs_conf);
msg.bin_len = aprs_encode_finalize(&ax25_handle);
transmitOnRadio(&msg);
if(conf->redundantTx) transmitOnRadio(&msg);
packet = aprs_encode_telemetry_configuration(&conf->aprs_conf, type);
transmitOnRadio(packet, &conf->frequency, conf->power, conf->modulation);
}
} else {
TRACE_ERROR("POS > Unsupported modulation/protocol selected for module POSITION");
last_conf_transmission += S2ST(conf->aprs_conf.tel_enc_cycle);
}
}
@ -93,7 +70,7 @@ THD_FUNCTION(posThread, arg)
void start_position_thread(module_conf_t *conf)
{
chsnprintf(conf->name, sizeof(conf->name), "POS");
thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(5*1024), "POS", NORMALPRIO, posThread, conf);
thread_t *th = chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(20*1024), "POS", NORMALPRIO, posThread, conf);
if(!th) {
// Print startup error, do not start watchdog for this thread
TRACE_ERROR("POS > Could not startup thread (not enough memory available)");

Wyświetl plik

@ -4,6 +4,8 @@
#include "si4464.h"
#include "debug.h"
#include <string.h>
#include "ax25_pad.h"
#include "fcs_calc.h"
// AFSK
#define PLAYBACK_RATE 13200
@ -17,10 +19,11 @@ static uint32_t phase; // Fixed point 9.7 (2PI = TABLE_SIZE)
static uint32_t packet_pos; // Next bit to be sent out
static uint32_t current_sample_in_baud; // 1 bit = SAMPLES_PER_BAUD samples
static uint8_t current_byte;
static uint8_t ctone = 0;
// Thread
static thread_t* feeder_thd = NULL;
static THD_WORKING_AREA(si_fifo_feeder_wa, 1024);
static THD_WORKING_AREA(si_fifo_feeder_wa, 4096);
// Mutex
static mutex_t radio_mtx; // Radio mutex
@ -29,8 +32,9 @@ static bool radio_mtx_init = false;
// Modulation and buffer
static mod_t active_mod = MOD_NOT_SET;
static radioMSG_t radio_msg;
static uint8_t radio_buffer[8192];
static packet_t radio_packet;
static uint32_t radio_freq;
static uint8_t radio_pwr;
void shutdownRadio(void)
{
@ -49,14 +53,6 @@ static uint8_t radio_buffer[8192];
}
}
static void copyBuffer(radioMSG_t* msg)
{
// Copy data
memcpy(&radio_msg, msg, sizeof(radioMSG_t));
memcpy(&radio_buffer, msg->buffer, sizeof(radio_buffer));
radio_msg.buffer = radio_buffer;
}
/* ======================================================================== Locking ========================================================================= */
void lockRadio(void)
@ -98,9 +94,7 @@ void unlockRadio(void)
/* ========================================================================== AFSK ========================================================================== */
void initAFSK(radioMSG_t* msg) {
copyBuffer(msg);
void initAFSK(void) {
if(active_mod == MOD_AFSK)
return;
@ -110,9 +104,91 @@ void initAFSK(radioMSG_t* msg) {
active_mod = MOD_AFSK;
}
static uint8_t getAFSKbyte(void)
static bool encode_nrzi(bool bit)
{
if(packet_pos == radio_msg.bin_len) // Packet transmission finished
if((bit & 0x1) == 0)
ctone = !ctone;
return ctone;
}
static uint32_t afsk_pack(packet_t pp, uint8_t* buf, uint32_t buf_len)
{
memset(buf, 0, buf_len); // Clear buffer
uint32_t blen = 0;
// Preamble
for(uint8_t i=0; i<30; i++) {
for(uint8_t j=0; j<8; j++) {
if(blen >> 3 >= buf_len) { // Buffer overflow
TRACE_ERROR("Packet too long");
return blen;
}
buf[blen >> 3] |= encode_nrzi((0x7E >> j) & 0x1) << (blen % 8);
blen++;
}
}
// Insert CRC to buffer
uint16_t crc = fcs_calc(pp->frame_data, pp->frame_len);
pp->frame_data[pp->frame_len++] = crc & 0xFF;
pp->frame_data[pp->frame_len++] = crc >> 8;
uint32_t pos = 0;
uint8_t bitstuff_cntr = 0;
while(pos < (uint32_t)pp->frame_len*8)
{
if(blen >> 3 >= buf_len) { // Buffer overflow
TRACE_ERROR("Packet too long");
return blen;
}
bool bit;
if(bitstuff_cntr < 5) { // Normale bit
bit = (pp->frame_data[pos >> 3] >> (pos%8)) & 0x1;
if(bit == 1) {
bitstuff_cntr++;
} else {
bitstuff_cntr = 0;
}
pos++;
} else { // Fill stuffing bit
bit = 0;
bitstuff_cntr = 0;
}
// NRZ-I encode bit
bool nrzi = encode_nrzi(bit);
buf[blen >> 3] |= nrzi << (blen % 8);
blen++;
}
// Final flag
for(uint8_t i=0; i<10; i++)
for(uint8_t j=0; j<8; j++) {
if(blen >> 3 >= buf_len) { // Buffer overflow
TRACE_ERROR("Packet too long");
return blen;
}
buf[blen >> 3] |= encode_nrzi((0x7E >> j) & 0x1) << (blen % 8);
blen++;
}
return blen;
}
static uint8_t getAFSKbyte(uint8_t* buf, uint32_t blen)
{
if(packet_pos == blen) // Packet transmission finished
return false;
uint8_t b = 0;
@ -120,7 +196,7 @@ static uint8_t getAFSKbyte(void)
{
if(current_sample_in_baud == 0) {
if((packet_pos & 7) == 0) { // Load up next byte
current_byte = radio_msg.buffer[packet_pos >> 3];
current_byte = buf[packet_pos >> 3];
} else { // Load up next bit
current_byte = current_byte / 2;
}
@ -143,10 +219,22 @@ static uint8_t getAFSKbyte(void)
return b;
}
THD_FUNCTION(si_fifo_feeder_afsk, frequency)
THD_FUNCTION(si_fifo_feeder_afsk, arg)
{
(void)arg;
chRegSetThreadName("radio_afsk_feeder");
TRACE_DEBUG("frame=%s", radio_packet->frame_data);
uint8_t layer0[3072];
uint32_t layer0_blen = afsk_pack(radio_packet, layer0, sizeof(layer0));
TRACE_DEBUG("frame_layer0=%s", layer0);
// Initialize variables for timer
phase_delta = PHASE_DELTA_1200;
phase = 0;
@ -155,15 +243,15 @@ THD_FUNCTION(si_fifo_feeder_afsk, frequency)
current_byte = 0;
uint8_t localBuffer[129];
uint16_t c = 129;
uint16_t all = (radio_msg.bin_len*SAMPLES_PER_BAUD+7)/8;
uint16_t all = (layer0_blen*SAMPLES_PER_BAUD+7)/8;
// Initial FIFO fill
for(uint16_t i=0; i<c; i++)
localBuffer[i] = getAFSKbyte();
localBuffer[i] = getAFSKbyte(layer0, layer0_blen);
Si4464_writeFIFO(localBuffer, c);
// Start transmission
radioTune((uint32_t)frequency, 0, radio_msg.power, all);
radioTune(radio_freq, 0, radio_pwr, all);
while(c < all) { // Do while bytes not written into FIFO completely
// Determine free memory in Si4464-FIFO
@ -174,7 +262,7 @@ THD_FUNCTION(si_fifo_feeder_afsk, frequency)
}
for(uint16_t i=0; i<more; i++)
localBuffer[i] = getAFSKbyte();
localBuffer[i] = getAFSKbyte(layer0, layer0_blen);
Si4464_writeFIFO(localBuffer, more); // Write into FIFO
c += more;
@ -183,12 +271,23 @@ THD_FUNCTION(si_fifo_feeder_afsk, frequency)
// Shutdown radio (and wait for Si4464 to finish transmission)
shutdownRadio();
// Delete packet
ax25_delete(radio_packet);
chThdExit(MSG_OK);
}
void sendAFSK(uint32_t frequency) {
void sendAFSK(packet_t packet, uint32_t freq, uint8_t pwr) {
// Set pointers for feeder
radio_packet = packet;
radio_freq = freq;
radio_pwr = pwr;
// Start/re-start FIFO feeder
feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_afsk, (void*)frequency);
feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_afsk, NULL);
// Wait for the transmitter to start (because it is used as mutex)
while(Si4464_getState() != SI4464_STATE_TX)
@ -197,24 +296,28 @@ void sendAFSK(uint32_t frequency) {
/* ========================================================================== 2FSK ========================================================================== */
void init2FSK(radioMSG_t* msg) {
copyBuffer(msg);
void init2FSK(void) {
if(active_mod == MOD_2FSK)
return;
// Initialize radio
Si4464_Init();
setModem2FSK(radio_msg.fsk_conf);
fsk_conf_t conf = {9600};
setModem2FSK(&conf);
active_mod = MOD_2FSK;
}
THD_FUNCTION(si_fifo_feeder_fsk, frequency)
THD_FUNCTION(si_fifo_feeder_fsk, arg)
{
uint16_t c = 129;
(void)arg;
chRegSetThreadName("radio_2fsk_feeder");
//uint8_t *frame = radio_packet->frame_data;
//uint32_t len = radio_packet->frame_len;
/*uint16_t c = 129;
uint16_t all = (radio_msg.bin_len+7)/8;
chRegSetThreadName("radio_2fsk_feeder");
// Initial FIFO fill
Si4464_writeFIFO(radio_msg.buffer, c);
@ -231,7 +334,7 @@ THD_FUNCTION(si_fifo_feeder_fsk, frequency)
Si4464_writeFIFO(&radio_msg.buffer[c], more); // Write into FIFO
c += more;
chThdSleepMilliseconds(15); // That value is ok up to 96k
}
}*/
// Shutdown radio (and wait for Si4464 to finish transmission)
shutdownRadio();
@ -239,9 +342,14 @@ THD_FUNCTION(si_fifo_feeder_fsk, frequency)
chThdExit(MSG_OK);
}
void send2FSK(uint32_t frequency) {
void send2FSK(packet_t packet, uint32_t freq, uint8_t pwr) {
// Set pointers for feeder
radio_packet = packet;
radio_freq = freq;
radio_pwr = pwr;
// Start/re-start FIFO feeder
feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_fsk, (void*)frequency);
feeder_thd = chThdCreateStatic(si_fifo_feeder_wa, sizeof(si_fifo_feeder_wa), HIGHPRIO+1, si_fifo_feeder_fsk, NULL);
// Wait for the transmitter to start (because it is used as mutex)
while(Si4464_getState() != SI4464_STATE_TX)

Wyświetl plik

@ -3,15 +3,16 @@
#include "ch.h"
#include "hal.h"
#include "ax25_pad.h"
void lockRadio(void);
void lockRadioByCamera(void);
void unlockRadio(void);
void initAFSK(radioMSG_t* msg);
void sendAFSK(uint32_t frequency);
void init2FSK(radioMSG_t* msg);
void send2FSK(uint32_t frequency);
void initAFSK(void);
void sendAFSK(packet_t packet, uint32_t freq, uint8_t pwr);
void init2FSK(void);
void send2FSK(packet_t packet, uint32_t freq, uint8_t pwr);
#endif

Wyświetl plik

@ -9,35 +9,37 @@
// Thread
static thread_t* si4464_rx_thd = NULL;
static THD_WORKING_AREA(si4464_rx_wa, 16*1024);
static THD_WORKING_AREA(si4464_rx_wa, 32*1024);
static const char *getModulation(uint8_t key) {
const char *val[] = {"unknown", "2FSK", "AFSK"};
return val[key];
};
bool transmitOnRadio(radioMSG_t *msg)
bool transmitOnRadio(packet_t packet, freq_conf_t *freq_conf, uint8_t pwr, mod_t mod)
{
uint32_t freq = getFrequency(msg->freq); // Get transmission frequency
uint32_t freq = getFrequency(freq_conf); // Get transmission frequency
uint8_t *c;
uint32_t len = ax25_get_info(packet, &c);
if(msg->bin_len > 0) // Message length is not zero
if(len) // Message length is not zero
{
lockRadio(); // Lock radio
TRACE_INFO( "RAD > Transmit %d.%03d MHz, Pwr %d, %s, %d bits",
freq/1000000, (freq%1000000)/1000, msg->power,
getModulation(msg->mod), msg->bin_len
TRACE_INFO( "RAD > Transmit %d.%03d MHz, Pwr %d, %s, %d byte",
freq/1000000, (freq%1000000)/1000, pwr,
getModulation(mod), len
);
switch(msg->mod)
switch(mod)
{
case MOD_2FSK:
init2FSK(msg);
send2FSK(freq);
init2FSK();
send2FSK(packet, freq, pwr);
break;
case MOD_AFSK:
initAFSK(msg);
sendAFSK(freq);
initAFSK();
sendAFSK(packet, freq, pwr);
break;
case MOD_NOT_SET:
TRACE_ERROR("RAD > Modulation not set");
@ -48,8 +50,8 @@ bool transmitOnRadio(radioMSG_t *msg)
} else {
TRACE_ERROR("RAD > It is nonsense to transmit 0 bits, %d.%03d MHz, Pwr dBm, %s, %d bits",
freq/1000000, (freq%1000000)/1000, msg->power, getModulation(msg->mod), msg->bin_len
TRACE_ERROR("RAD > It is nonsense to transmit 0 bits, %d.%03d MHz, Pwr dBm, %s, %d byte",
freq/1000000, (freq%1000000)/1000, pwr, getModulation(mod), len
);
}

Wyświetl plik

@ -4,6 +4,7 @@
#include "ch.h"
#include "hal.h"
#include "config.h"
#include "ax25_pad.h"
// APRS region frequencies
#define APRS_FREQ_OTHER 144800000
@ -17,7 +18,7 @@
#define APRS_FREQ_ARGENTINA 144930000
#define APRS_FREQ_BRAZIL 145575000
bool transmitOnRadio(radioMSG_t *msg);
bool transmitOnRadio(packet_t packet, freq_conf_t *freq_conf, uint8_t pwr, mod_t mod);
void lockRadio(void);
void lockRadioByCamera(void);
void unlockRadio(void);

Wyświetl plik

@ -7,22 +7,6 @@ typedef enum { // Modulation type
MOD_AFSK
} mod_t;
// Protocol type
typedef enum {
PROT_NOT_SET,
PROT_APRS_AFSK,
PROT_APRS_2FSK
} prot_t;
#define isAPRS(x) ((x) == PROT_APRS_AFSK || (x) == PROT_APRS_2FSK)
typedef enum {
CONF_PARM,
CONF_UNIT,
CONF_EQNS,
CONF_BITS
} telemetry_conf_t;
typedef struct {
char callsign[16]; // APRS callsign
uint8_t ssid; // APRS SSID
@ -70,7 +54,7 @@ typedef struct {
typedef struct { // Radio message type
uint8_t* buffer; // Message (data)
uint32_t bin_len; // Binary length (it bits)
int8_t power; // Power in dBm
uint8_t power; // Power in dBm
mod_t mod; // Modulation
freq_conf_t* freq; // Frequency
@ -116,7 +100,7 @@ typedef struct {
// Radio
int8_t power;
freq_conf_t frequency;
prot_t protocol;
mod_t modulation;
// Timing
uint32_t init_delay;