APRS fields implementation.

pull/5/head
sq2ips 2025-10-19 00:08:55 +02:00
rodzic 7fb9757665
commit cdc34b404c
5 zmienionych plików z 97 dodań i 16 usunięć

Wyświetl plik

@ -5,13 +5,20 @@
#define APRS_CONTROL_FIELD 0x03
#define APRS_PROTOCOL_ID 0xf0
#define APRS_SPACE_SYMBOL 0x20
#define APRS_MAX_INFO_LEN 61
typedef struct TAPRSPacket {
uint8_t Hours;
uint8_t Minutes;
uint8_t Seconds;
float Lat;
float Lon;
uint16_t Alt;
uint8_t Speed;
} APRSPacket;
uint16_t encode_APRS_packet(APRSPacket Packet, uint8_t *buff);
uint8_t encode_APRS_packet(APRSPacket Packet, uint8_t *buff);
#endif

Wyświetl plik

@ -31,15 +31,17 @@ const static float QRG_FSK4[] = {435100000}; // Transmitted frequencies array, s
#define LED_PERIOD 5 // time between LED lighting
#define LED_DISABLE_ALT 1000 // disable led when certain altitude is reached, 0 for always enable
#define APRS_D_CALL "APRS\x20\x20"
#define APRS_D_CALL "APRS"
#define APRS_D_CALL_SSID 0
#define APRS_S_CALL "SQ2IPS"
#define APRS_S_CALL_SSID 1
#define APRS_PATH "WIDE1\x20"
#define APRS_PATH "WIDE1"
#define APRS_PATH_SSID 1
#define APRS_SYMBOL "/O" // baloon symbol, all symbols: https://www.aprs.org/symbols.html
/*-----------------------------------------------------------------*/
// the rest of parameters should not be changed normally

Wyświetl plik

@ -56,9 +56,9 @@ volatile static uint16_t phase_inc = PHASE_INC_MARC; // current phase increase v
volatile static uint16_t phase = 0; // Current phase value, fixed point 9.7
volatile static uint16_t sample_in_baud = 0;
volatile static uint16_t bit_pos = 0;
volatile static uint8_t stuffing_cnt = 0;
volatile static bool stuff = false;
static uint16_t bit_pos = 0;
static uint8_t stuffing_cnt = 0;
static bool stuff = false;
bool AFSK_Active = false; // Activity flag

Wyświetl plik

@ -6,6 +6,7 @@
#include "aprs.h"
#include "config.h"
#include "utils.h"
#include <string.h>
@ -27,26 +28,32 @@ static uint16_t calculateFcs(uint8_t *input_data, uint16_t len) {
return (~crc);
}
static uint16_t generate_ax25_frame(uint8_t *info_field, uint8_t info_field_size, uint8_t *buff){
volatile uint16_t pos = 0;
static uint8_t generate_ax25_frame(uint8_t *info_field, uint8_t info_field_size, uint8_t *buff){
uint8_t pos = 0;
uint8_t d_pos = 0;
memset(buff, 0, sizeof(250));
for(; pos<6; pos++){ // Destination adress
buff[pos] = APRS_D_CALL[pos]<<1;
if(pos >= sizeof(APRS_D_CALL)-1){
buff[pos] = APRS_SPACE_SYMBOL<<1;
}else buff[pos] = APRS_D_CALL[pos]<<1;
}
buff[pos++] = (APRS_D_CALL_SSID<<1) | 0b11100000; // Destination adress SSID
d_pos = pos;
for(; pos-d_pos<6; pos++){ // Source adress
buff[pos] = APRS_S_CALL[pos-d_pos]<<1;
if(pos-d_pos >= sizeof(APRS_S_CALL)-1){
buff[pos] = APRS_SPACE_SYMBOL<<1;
}else buff[pos] = APRS_S_CALL[pos-d_pos]<<1;
}
buff[pos++] = (APRS_S_CALL_SSID<<1) | 0b11100000; // Source adress SSID
d_pos = pos;
for(; pos-d_pos<6; pos++){ // Path
buff[pos] = APRS_PATH[pos-d_pos]<<1;
if(pos-d_pos >= sizeof(APRS_PATH)-1){
buff[pos] = APRS_SPACE_SYMBOL<<1;
}else buff[pos] = APRS_PATH[pos-d_pos]<<1;
}
buff[pos++] = (APRS_PATH_SSID<<1) | 0b11100001; // Path SSID (1 at end as last adress)
@ -64,7 +71,66 @@ static uint16_t generate_ax25_frame(uint8_t *info_field, uint8_t info_field_size
return pos;
}
uint16_t encode_APRS_packet(APRSPacket Packet, uint8_t *buff){
uint8_t info[] = "@092345z/:*E\";qZ=OMRC/A=088132Hello World!";
return generate_ax25_frame(info, sizeof(info)-1, buff);
static uint8_t compress_pos(float lat, float lon, uint8_t *buff){
uint32_t lat_base10 = Round(380926 * (90-lat));
uint8_t cnt = 0;
buff[cnt++] = (lat_base10 / 753571) + 33;
buff[cnt++] = ((lat_base10 % 753571) / 8281) + 33;
buff[cnt++] = ((lat_base10 % 753571) % 8281) / 91 + 33;
buff[cnt++] = ((lat_base10 % 753571) % 8281) % 91 + 33;
uint32_t lon_base10 = Round(190463 * (180+lat));
buff[cnt++] = (lon_base10 / 753571) + 33;
buff[cnt++] = ((lon_base10 % 753571) / 8281) + 33;
buff[cnt++] = ((lon_base10 % 753571) % 8281) / 91 + 33;
buff[cnt++] = ((lon_base10 % 753571) % 8281) % 91 + 33;
return cnt;
}
uint8_t encode_APRS_packet(APRSPacket Packet, uint8_t *buff){
uint8_t info_field[APRS_MAX_INFO_LEN];
uint8_t pos = 0;
info_field[pos++] = '@';
info_field[pos++] = Packet.Hours%10+'0';
info_field[pos++] = Packet.Hours/10+'0';
info_field[pos++] = Packet.Minutes%10+'0';
info_field[pos++] = Packet.Minutes/10+'0';
info_field[pos++] = Packet.Seconds%10+'0';
info_field[pos++] = Packet.Seconds/10+'0';
info_field[pos++] = 'z';
info_field[pos++] = APRS_SYMBOL[0];
pos += compress_pos(Packet.Lat, Packet.Lon, info_field+pos);
info_field[pos++] = APRS_SYMBOL[1];
info_field[pos++] = 33; // no course data
info_field[pos++] = Round((Log(Packet.Speed*0.5399565f+1)/Log(1.08f)))+33;
info_field[pos++] = 67;
info_field[pos++] = '/';
info_field[pos++] = 'A';
info_field[pos++] = '=';
uint32_t alt_ft = (uint32_t)(Packet.Alt*3.28084f);
uint32_t a = 1000000;
for(uint8_t i = 0; i<6; i++){
info_field[pos++] = (alt_ft%(a*10))/a;
a/=10;
}
memcpy(info_field+pos, "test", 4);
pos+=4;
return generate_ax25_frame(info_field, pos, buff);
}

Wyświetl plik

@ -61,8 +61,6 @@ const static uint8_t GPS_airborne[44] = {
XMDATA GpsData;
#endif
static uint8_t afsk_buff[] = {0x82, 0xa0, 0xa4, 0xa6, 0x40, 0x40, 0xe0, 0x9c, 0x9e, 0x86, 0x82, 0x98, 0x98, 0xe2, 0xae, 0x92, 0x88, 0x8a, 0x62, 0x40, 0xe3, 0x03, 0xf0, 0x40, 0x30, 0x39, 0x32, 0x33, 0x34, 0x35, 0x7a, 0x2f, 0x3a, 0x2a, 0x45, 0x22, 0x3b, 0x71, 0x5a, 0x3d, 0x4f, 0x4d, 0x52, 0x43, 0x2f, 0x41, 0x3d, 0x30, 0x38, 0x38, 0x31, 0x33, 0x32, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0xa2, 0x48};
#ifdef GPS_WATCHDOG
struct GpsWatchdogStruct {
bool PreviousFix;
@ -454,6 +452,14 @@ int main(void)
* TIM6 - LED timer: 3
* SysTick: 4
*/
AprsPacket.Alt = 18523;
AprsPacket.Lat = 54.123;
AprsPacket.Lon = 18.456;
AprsPacket.Hours = 12;
AprsPacket.Minutes = 34;
AprsPacket.Seconds = 56;
AprsPacket.Speed = 123;
/* USER CODE END 2 */
/* Infinite loop */