Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 176 additions & 10 deletions LibAPRS/LibAPRS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,17 @@ AX25Call dst;
AX25Call path1;
AX25Call path2;

char CALL[7] = "NOCALL";
#define MAX_CALL_LENGTH 7
char CALL[MAX_CALL_LENGTH] = "NOCALL";
int CALL_SSID = 0;
char DST[7] = "APZMDM";
char DST[MAX_CALL_LENGTH] = "APZMDM";
int DST_SSID = 0;
char PATH1[7] = "WIDE1";
char PATH1[MAX_CALL_LENGTH] = "WIDE1";
int PATH1_SSID = 1;
char PATH2[7] = "WIDE2";
char PATH2[MAX_CALL_LENGTH] = "WIDE2";
int PATH2_SSID = 2;
uint8_t MICE_MSG;
uint8_t MICE_SSID;

AX25Call path[4];

Expand All @@ -39,6 +42,8 @@ uint8_t power = 10;
uint8_t height = 10;
uint8_t gain = 10;
uint8_t directivity = 10;
uint16_t speed;
uint16_t course;
/////////////////////////

// Message packet assembly fields
Expand All @@ -64,7 +69,7 @@ void APRS_poll(void) {
}

void APRS_setCallsign(char *call, int ssid) {
memset(CALL, 0, 7);
memset(CALL, 0, MAX_CALL_LENGTH);
int i = 0;
while (i < 6 && call[i] != 0) {
CALL[i] = call[i];
Expand All @@ -74,7 +79,7 @@ void APRS_setCallsign(char *call, int ssid) {
}

void APRS_setDestination(char *call, int ssid) {
memset(DST, 0, 7);
memset(DST, 0, MAX_CALL_LENGTH);
int i = 0;
while (i < 6 && call[i] != 0) {
DST[i] = call[i];
Expand All @@ -84,7 +89,7 @@ void APRS_setDestination(char *call, int ssid) {
}

void APRS_setPath1(char *call, int ssid) {
memset(PATH1, 0, 7);
memset(PATH1, 0, MAX_CALL_LENGTH);
int i = 0;
while (i < 6 && call[i] != 0) {
PATH1[i] = call[i];
Expand All @@ -94,7 +99,7 @@ void APRS_setPath1(char *call, int ssid) {
}

void APRS_setPath2(char *call, int ssid) {
memset(PATH2, 0, 7);
memset(PATH2, 0, MAX_CALL_LENGTH);
int i = 0;
while (i < 6 && call[i] != 0) {
PATH2[i] = call[i];
Expand All @@ -104,7 +109,7 @@ void APRS_setPath2(char *call, int ssid) {
}

void APRS_setMessageDestination(char *call, int ssid) {
memset(message_recip, 0, 7);
memset(message_recip, 0, 6);
int i = 0;
while (i < 6 && call[i] != 0) {
message_recip[i] = call[i];
Expand Down Expand Up @@ -175,6 +180,24 @@ void APRS_setDirectivity(int s) {
}
}

// Set the speed in knots. Valid speeds are 0-799 knots
void APRS_setSpeed(int s) {
if (s >= 0 && s < 800) {
speed = s;
} else {
speed = 0;
}
}

// Set the course, valid courses are 0-360 where 0 is unknown and 360 is due north
void APRS_setCourse(int c) {
if (c >= 0 && c <= 360) {
course = c;
} else {
course = 0;
}
}

void APRS_printSettings() {
Serial.println(F("LibAPRS Settings:"));
Serial.print(F("Callsign: ")); Serial.print(CALL); Serial.print(F("-")); Serial.println(CALL_SSID);
Expand Down Expand Up @@ -218,6 +241,149 @@ void APRS_sendPkt(void *_buffer, size_t length) {
ax25_sendVia(&AX25, path, countof(path), buffer, length);
}

// 3 bits of MIC-E message. Bit A is the most significant bit.
// If custom is set then we use the custom message bits when encoding
// Standard messages Custom Messages
// 0x07: M0: Off Duty C0: Custom-0
// 0x06: M1: En route C1: Custom-1
// 0x05: M2: In service C2: Custom-2
// 0x04: M3: Returning C3: Custom-3
// 0x03: M4: Committed C4: Custom-4
// 0x02: M5: Special C5: Custom-5
// 0x01: M6: Priority C6: Custom-6
// 0x00: Emergency Emergency
void APRS_set_mice_msg(uint8_t msg, bool custom) {
MICE_MSG = msg & 0x07;
// If custom message bits, store the custom flag in bit 7 of the MICE_MSG
if (custom) {
MICE_MSG |= 0x80;
}
}

void APRS_set_mice_ssid(uint8_t ssid) {
MICE_SSID = ssid & 0x0F;
}

uint8_t APRS_sendLoc_mice(void *_buffer, size_t length) {
uint8_t path_len;
uint8_t payloadLength = 9 + length;
uint8_t *packet = (uint8_t*)malloc(payloadLength);
// Sanity check the latitude and longtitude
if (latitude[7] != 'N' && latitude[7] != 'S') {
return 1;
}
if (longtitude[8] != 'E' && longtitude[8] != 'W') {
return 1;
}
// Build the Destination callsign with the latitude information
DST[0] = (latitude[0] & 0x0F) | 0x30;
if (MICE_MSG & 0x04) {
if (MICE_MSG & 0x80) {
DST[0] += 0x17; // Custom message bit
} else {
DST[0] += 0x20; // Standard message bit
}
}
DST[1] = (latitude[1] & 0x0F) | 0x30;
if (MICE_MSG & 0x02) {
if (MICE_MSG & 0x80) {
DST[1] += 0x17; // Custom message bit
} else {
DST[1] += 0x20; // Standard message bit
}
}
DST[2] = (latitude[2] & 0x0F) | 0x30;
if (MICE_MSG & 0x01) {
if (MICE_MSG & 0x80) {
DST[2] += 0x17; // Custom message bit
} else {
DST[2] += 0x20; // Standard message bit
}
}
DST[3] = (latitude[3] & 0x0F) | 0x30;
if (latitude[7] == 'N') { // North/South Latitude Indicator
DST[3] += 0x20;
}
DST[4] = (latitude[5] & 0x0F) | 0x30; // Use latitude[5] becuase latitude[4] is a .
// if (longtitude[0] == '1') { // If the longtitude is > 100, set this bit
// DST[4] += 0x20;
// }
DST[5] = (latitude[6] & 0x0F) | 0x30;
if (longtitude[8] == 'W') { // If the longtitude is > 100, set this bit
DST[4] += 0x20;
}

packet[0] = 0x60; // The ` character indicating valid GPS data
// Degrees. If longtitude > 100 the +100 longtitude bit is set in the Destination field, but only in
// certain circumstances, see http://www.aprs.org/doc/APRS101.PDF page 47
uint8_t lon_deg = ((longtitude[0] & 0x0F) * 100 + (longtitude[1] & 0x0F) * 10 + (longtitude[2] & 0x0F));
if (lon_deg < 10) {
packet[1] = 118 + lon_deg;
DST[4] += 0x20;
} else if (lon_deg < 100) {
packet[1] = 38 + lon_deg - 10;
} else if (lon_deg < 110) {
packet[1] = 108 + (lon_deg - 100);
DST[4] += 0x20;
} else {
packet[1] = 38 + (lon_deg - 110);
DST[4] += 0x20;
}

uint8_t lon_min = ((longtitude[3] & 0x0F) * 10) + (longtitude[4] & 0x0F);
if (lon_min < 10) {
packet[2] = 88 + lon_min;
} else {
packet[2] = 38 + lon_min - 10;
}
packet[3] = ((longtitude[6] & 0x0F) * 10) + (longtitude[7] & 0x0F) + 28;

// bytes 4, 5 and 6 encode the speed and course
// Page 50 of the APRS spec
packet[4] = (speed / 10) + 28; // 100's an 10's of knots
packet[5] = (speed % 10) * 10 + 32; // 1's of knots
if (course > 299) {
packet[5] += 3;
} else if (course > 199) {
packet[5] += 2;
} else if (course > 99) {
packet[5] += 1;
}
packet[6] = (course % 100) + 28;
packet[7] = (uint8_t)symbol;
packet[8] = (uint8_t)symbolTable;

if (MICE_SSID != 0) {
path_len = 0;
} else {
path_len = 4;
}

memcpy(dst.call, DST, 6);
dst.ssid = DST_SSID;

memcpy(src.call, CALL, 6);
src.ssid = CALL_SSID;

memcpy(path1.call, PATH1, 6);
path1.ssid = PATH1_SSID;

memcpy(path2.call, PATH2, 6);
path2.ssid = PATH2_SSID;

path[0] = dst;
path[1] = src;
path[2] = path1;
path[3] = path2;
if (length > 0) {
uint8_t *buffer = (uint8_t *)_buffer;
memcpy(&packet[9], buffer, length);
}
ax25_sendVia(&AX25, path, path_len, packet, payloadLength);
free(packet);
return 0;
}

// Dynamic RAM usage of this function is 30 bytes
void APRS_sendLoc(void *_buffer, size_t length) {
size_t payloadLength = 20+length;
Expand Down Expand Up @@ -303,7 +469,7 @@ void APRS_sendMsg(void *_buffer, size_t length) {
packet[12+length] = h+48;
packet[13+length] = d+48;
packet[14+length] = n+48;

APRS_sendPkt(packet, payloadLength);
free(packet);
}
Expand Down
15 changes: 15 additions & 0 deletions LibAPRS/LibAPRS.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
#include "AFSK.h"
#include "AX25.h"

#define MICE_STD_MSG_OFF_DUTY 0x07
#define MICE_STD_MSG_EN_ROUTE 0x06
#define MICE_STD_MSG_IN_SERVICE 0x05
#define MICE_STD_MSG_RETURNING 0x04
#define MICE_STD_MSG_COMMITTED 0x03
#define MICE_STD_MSG_SPECIAL 0x02
#define MICE_STD_MSG_PRIORITY 0x01
#define MICE_STD_MSG_EMERGENCY 0x00

void APRS_init(int reference, bool open_squelch);
void APRS_poll(void);

Expand All @@ -28,11 +37,17 @@ void APRS_setPower(int s);
void APRS_setHeight(int s);
void APRS_setGain(int s);
void APRS_setDirectivity(int s);
void APRS_setSpeed(int s);
void APRS_setCourse(int c);

void APRS_sendPkt(void *_buffer, size_t length);
void APRS_sendLoc(void *_buffer, size_t length);
void APRS_sendMsg(void *_buffer, size_t length);
void APRS_msgRetry();
uint8_t APRS_sendLoc_mice(void *_buffer, size_t length);
void APRS_set_mice_ssid(uint8_t ssid);
void APRS_set_mice_msg(uint8_t msg, bool custom);


void APRS_printSettings();

Expand Down