UNPKG

ais-web

Version:

Compact AIS decoder in TypeScript for browser and web apps

94 lines (93 loc) 4.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.encodePositionMessage = encodePositionMessage; exports.encodeStaticMessage = encodeStaticMessage; /** * AIS Encoder: Generates AIVDM sentences for AIS Message Types 1 and 5 * Complies with ITU-R M.1371 */ const bitUtils_1 = require("./bitUtils"); function encodePositionMessage(msg) { var _a, _b, _c, _d, _e; const repeat = (_a = msg.repeat) !== null && _a !== void 0 ? _a : 0; const specialManoeuvre = (_b = msg.specialManoeuvre) !== null && _b !== void 0 ? _b : 0; const raim = (_c = msg.raim) !== null && _c !== void 0 ? _c : false; const radio = (_d = msg.radio) !== null && _d !== void 0 ? _d : 0; const channel = (_e = msg.channel) !== null && _e !== void 0 ? _e : 'A'; const accuracy = msg.accuracy ? 1 : 0; const bits = (0, bitUtils_1.encodeBitField)([ { value: 1, length: 6 }, // message type 1 { value: repeat, length: 2 }, // repeat indicator { value: msg.mmsi, length: 30 }, { value: msg.navStatus, length: 4 }, { value: msg.rateOfTurn, length: 8, signed: true }, { value: Math.floor(msg.sog * 10), length: 10 }, { value: accuracy, length: 1 }, { value: Math.floor(msg.lon * 600000), length: 28, signed: true }, { value: Math.floor(msg.lat * 600000), length: 27, signed: true }, { value: Math.floor(msg.cog * 10), length: 12 }, { value: msg.heading, length: 9 }, { value: msg.timestamp, length: 6 }, { value: specialManoeuvre, length: 2 }, { value: raim ? 1 : 0, length: 1 }, { value: radio, length: 19 }, ]); return encodePayload(bits, 1, channel); } function encodeStaticMessage(msg) { var _a, _b, _c, _d; const repeat = (_a = msg.repeat) !== null && _a !== void 0 ? _a : 0; const aisVersion = (_b = msg.aisVersion) !== null && _b !== void 0 ? _b : 0; const epfd = (_c = msg.epfd) !== null && _c !== void 0 ? _c : 0; // dteAvailable: true means available = 0, false means not available = 1 (inverted for AIS) const dteAvailable = msg.dteAvailable === false ? 1 : 0; const channel = (_d = msg.channel) !== null && _d !== void 0 ? _d : 'A'; const bits = (0, bitUtils_1.encodeBitField)([ { value: 5, length: 6 }, // message type 5 { value: repeat, length: 2 }, { value: msg.mmsi, length: 30 }, { value: aisVersion, length: 2 }, { value: msg.imo, length: 30 }, { value: msg.callsign, length: 42, ascii: true }, { value: msg.name, length: 120, ascii: true }, { value: msg.shipType, length: 8 }, { value: msg.dimensionToBow, length: 9 }, { value: msg.dimensionToStern, length: 9 }, { value: msg.dimensionToPort, length: 6 }, { value: msg.dimensionToStarboard, length: 6 }, { value: epfd, length: 4 }, { value: msg.etaMonth, length: 4 }, { value: msg.etaDay, length: 5 }, { value: msg.etaHour, length: 5 }, { value: msg.etaMinute, length: 6 }, { value: Math.floor(msg.draught * 10), length: 8 }, { value: msg.destination, length: 120, ascii: true }, { value: dteAvailable, length: 1 }, { value: 0, length: 1 }, // spare ]); return encodePayload(bits, 5, channel); } function encodePayload(bits, messageType, channel) { const payload = (0, bitUtils_1.to6BitAscii)(bits); const maxPayload = 60; const sentences = []; const total = Math.ceil(payload.length / maxPayload); const seqId = Math.floor(Math.random() * 9) + 1; for (let i = 0; i < total; i++) { const part = payload.slice(i * maxPayload, (i + 1) * maxPayload); const totalBits = part.length * 6; const fillBits = (8 - (totalBits % 8)) % 8; const line = `!AIVDM,${total},${i + 1},${seqId},${channel},${part},${fillBits}`; sentences.push(`${line}*${checksum(line)}`); } return sentences; } function checksum(sentence) { let chk = 0; for (let i = 1; i < sentence.length; i++) { if (sentence[i] === '*') break; chk ^= sentence.charCodeAt(i); } return chk.toString(16).toUpperCase().padStart(2, '0'); }