UNPKG

js-aprs-fap

Version:

NodeJs library for parsing APRS packets.

203 lines 8.1 kB
"use strict"; 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