kopia lustrzana https://github.com/DL7AD/pecanpico10
Implemented Direwolf into Pecan
rodzic
c746b1297b
commit
041635bdd1
|
@ -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/
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ static const ShellCommand commands[] = {
|
|||
{"log", readLog},
|
||||
{"config", printConfig},
|
||||
{"command", command2Camera},
|
||||
{"aprs_message", send_aprs_message},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
Plik diff jest za duży
Load Diff
|
@ -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 */
|
||||
|
||||
|
|
@ -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 */
|
|
@ -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
|
|
@ -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;
|
||||
}*/
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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.
|
@ -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 */
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Ładowanie…
Reference in New Issue