js-aprs-fap
Version:
NodeJs library for parsing APRS packets.
203 lines • 8.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.KissUtil = void 0;
class KissUtil {
checkKissCallsign(callsign) {
const matches = callsign.match(/^([A-Z0-9]+)\s*(|-\d+)$/);
if (matches && matches.length > 0) {
if (matches[2] == undefined || matches[2] == null || matches[2].trim().length === 0) {
if (parseInt(matches[2]) < -15) {
return null;
}
}
return `${matches[1]}${matches[2]}`;
}
return null;
}
kissToTnc2(frame) {
let asciiFrame = "";
let dstCallsign = "";
let callsignTmp = "";
let digipeaterCount = 0;
frame = frame.replace(/\xDB\xDC\xC0\xDB\xDD\xDB/, '');
if (frame.length < 16) {
return null;
}
if (frame.charCodeAt(0) != 0) {
throw new Error(`not a kiss frame ${frame.charCodeAt(0)}.`);
}
let addressPart = 0;
let addressCount = 0;
do {
frame = frame.substring(1);
let charri = frame.substring(0, 1);
let charCode = frame.charCodeAt(0);
if (addressPart == 0) {
addressCount++;
if (charCode & 1) {
if (addressCount < 14 || (addressCount % 7) != 0) {
throw new Error("addresses ended too soon or in the wrong place in kiss frame.");
}
addressPart = 1;
}
if ((addressCount % 7) == 0) {
let ssid = (charCode >> 1) & 0xF;
if (ssid != 0) {
callsignTmp = `${callsignTmp}-${ssid}`;
}
let chkCall = this.checkKissCallsign(callsignTmp);
if (!chkCall || chkCall == null || chkCall == undefined) {
throw new Error("Invalid callsign in kiss frame, discarding.");
}
if (addressCount == 7) {
dstCallsign = chkCall;
callsignTmp = "";
continue;
}
else if (addressCount == 14) {
asciiFrame = `${chkCall}>${dstCallsign}`;
callsignTmp = "";
}
else if (addressCount > 14) {
asciiFrame = `${asciiFrame}${chkCall}`;
callsignTmp = "";
if (charCode & 0x80) {
asciiFrame = `${asciiFrame}*`;
}
digipeaterCount++;
}
else {
throw new Error("Internal error 1 in kiss_to_tnc2()");
}
if (addressPart == 0) {
if (digipeaterCount >= 8) {
throw new Error("Too many digipeaters in kiss packet, discarding.");
}
asciiFrame = `${asciiFrame},`;
}
else {
asciiFrame = `${asciiFrame}:`;
}
continue;
}
charCode = charCode >> 1;
callsignTmp = callsignTmp + String.fromCharCode(charCode);
}
else if (addressPart == 1) {
if (charCode != 3) {
}
addressPart = 2;
}
else if (addressPart == 2) {
if (charCode != 0xF0) {
throw new Error("PID not 0xF0, skipping.");
}
addressPart = 3;
}
else {
asciiFrame = `${asciiFrame}${charri}`;
}
} while (frame.length > 0);
return asciiFrame;
}
tnc2ToKiss(frame) {
let kissFrame = String.fromCharCode(parseInt("00", 16));
let body;
let header;
if (/^([A-Z0-9,*>-]+):(.+)$/.test(frame)) {
[, header, body] = frame.match(/^([A-Z0-9,*>-]+):(.+)$/);
}
else {
throw new Error("Separation into header and body failed.");
}
let sender;
let senderSsid;
let receiver;
let receiverSsid;
let digipeaters;
if (/^([A-Z0-9]{1,6})(-\d+|)>([A-Z0-9]{1,6})(-\d+|)(|,.*)$/.test(header)) {
[, sender, senderSsid, receiver, receiverSsid, digipeaters] = header.match(/^([A-Z0-9]{1,6})(-\d+|)>([A-Z0-9]{1,6})(-\d+|)(|,.*)$/);
}
else {
throw new Error("Separation of sender and receiver from header failed.");
}
if (senderSsid.length > 0) {
senderSsid = Number(senderSsid) * -1;
if (senderSsid > 15) {
throw new Error("Sender SSID ($sender_ssid) is over 15.");
}
}
else {
senderSsid = 0;
}
if (receiverSsid.length > 0) {
receiverSsid = Number(receiverSsid) * -1;
if (receiverSsid > 15) {
throw new Error("tnc2_to_kiss(): receiver SSID ($receiver_ssid) is over 15.");
}
}
else {
receiverSsid = 0;
}
sender = sender.padEnd(6, ' ');
receiver = receiver.padEnd(6, ' ');
kissFrame += this.encodeString(receiver);
kissFrame += String.fromCharCode(0xe0 | (receiverSsid << 1));
kissFrame += this.encodeString(sender);
if (digipeaters.length > 0) {
kissFrame += String.fromCharCode(0x60 | (senderSsid << 1));
}
else {
kissFrame += String.fromCharCode(0x61 | (senderSsid << 1));
}
if (digipeaters.length > 0) {
digipeaters = digipeaters.indexOf(',') == 0 ? digipeaters.substring(1) : digipeaters;
let digis = digipeaters.split(/,/);
if (digis.length > 8 || digis.length < 1) {
throw new Error(`Too many (or zero) digipeaters: ${digis.length}`);
}
for (let i = 0; i < digis.length; i++) {
let tmp;
if ((tmp = digis[i].match(/^([A-Z0-9]{1,6})(-\d+|)(\*|)$/))) {
let callsign = tmp[1].padEnd(6, ' ');
let ssid = 0;
let hbit = 0x00;
if (tmp[2].length > 0) {
ssid = Number(tmp[2]) * -1;
if (ssid > 15) {
throw new Error(`Digipeater nr. ${i} SSID ($ssid) invalid.`);
}
}
if (tmp[3] == '*') {
hbit = 0x80;
}
kissFrame += this.encodeString(callsign);
if (i + 1 < digis.length) {
kissFrame += String.fromCharCode(hbit | 0x60 | (ssid << 1));
}
else {
kissFrame += String.fromCharCode(hbit | 0x61 | (ssid << 1));
}
}
else {
throw new Error(`Digipeater nr. ${i} parsing failed.`);
}
}
}
kissFrame = `${kissFrame}${String.fromCharCode(0x03)}${String.fromCharCode(0xf0)}`;
kissFrame += body;
kissFrame = kissFrame.replace(/\xdb/, `${String.fromCharCode(0xdb)}${String.fromCharCode(0xdd)}`);
kissFrame = kissFrame.replace(/\xc0/, `${String.fromCharCode(0xdb)}${String.fromCharCode(0xdc)}`);
kissFrame = `${String.fromCharCode(parseInt("c0", 16))}${kissFrame}${String.fromCharCode(parseInt("c0", 16))}`;
return kissFrame;
}
encodeString(value) {
let retVal = "";
for (let i = 0; i < value.length; i++) {
retVal += String.fromCharCode(value.charCodeAt(i) << 1);
}
return retVal;
}
}
exports.KissUtil = KissUtil;
//# sourceMappingURL=KissUtil.js.map