let handlers = { contexts: { }, sessions: { } }; function getSystemTime(time, reference) { if (time == 0) return '-'; return new Date((time + reference) * 1000).toLocaleString(); } function formatInterval(value) { if (value < 60) return Math.floor(value * 100) / 100; value = Math.floor(value); let minutes = Math.floor(value / 60); let seconds = Math.floor(value % 60); return minutes + ':' + (seconds < 10 ? '0' : '') + seconds; } handlers.contexts.DummyLink = (data, reference, order) => { let getSlotUsate = (carrier, usage) => { let result = ''; for (let slot = 31; slot >= 0; slot --) { if (~(carrier >> (slot / 4)) & 1) { result += 'o'; continue; } if (~(usage >> slot ) & 1) { result += 'x'; continue; } result += 'X'; } return result; } let result = [ ]; let topology = (data[5] ^ data[7]) & data[5]; result.push('MNI ' + (data[1] >> 14) + ' ' + (data[1] & 0x03fff)); if (data[3] & 0x01) result.push('E1 established'); if (topology & 0x0001) result.push('BS-1: ' + getSystemTime(data[ 8], reference - data[6])); if (topology & 0x0002) result.push('BS-2: ' + getSystemTime(data[ 9], reference - data[6])); if (topology & 0x0004) result.push('BS-3: ' + getSystemTime(data[10], reference - data[6])); if (topology & 0x0008) result.push('BS-4: ' + getSystemTime(data[11], reference - data[6])); if (topology & 0x0010) result.push('BS-5: ' + getSystemTime(data[12], reference - data[6])); if (topology & 0x0020) result.push('BS-6: ' + getSystemTime(data[13], reference - data[6])); if (topology & 0x0040) result.push('BS-7: ' + getSystemTime(data[14], reference - data[6])); if (topology & 0x0080) result.push('BS-8: ' + getSystemTime(data[15], reference - data[6])); if (topology & 0x8000) result.push('GWPC: ' + getSystemTime(data[23], reference - data[6])); if (data[0] & 0x01) result.push('Emulated BS-' + (data[2] + 1) + ' use: ' + getSlotUsate(data[4], data[16])); if (data[0] & 0x02) result.push('Emulated GWPC use: ' + getSlotUsate(data[4] >> 16, data[18])); if (data[22]) result.push('Ping ' + data[22] + ' ms'); return result; } handlers.contexts.SidecarLink = (data, reference, order) => { let result = [ ]; let statuses = [ 'DOWN', 'LINKING', 'GRANT', 'ACTIVE', 'STANDBY' ]; let list = [ ]; let buildStatusList = (status, number) => { while (status != 0n) { if (status == -1n) status = 1n; if (status & 1n) list.push(number); status = status >> 1n; number ++; } } buildStatusList(BigInt(data[3]), 1); buildStatusList(BigInt(data[4]), 65); result.push('Zone ' + ((data[0] >> 16) + 1)); result.push('Emulated Site ' + ((data[0] & 0xff) + 1)); result.push('LAI ' + (BigInt(data[1]) >> 30n) + ' ' + ((data[1] >> 16) & 0x03fff) + ' ' + (data[1] & 0xffff)); result.push('WAN1: ' + statuses[(data[2] >> 0) & 0x07]); result.push('WAN2: ' + statuses[(data[2] >> 4) & 0x07]); result.push('SDR configured: ' + data[6]); result.push('User cache size: ' + data[61]); result.push('List cache size: ' + data[62]); if (data[2] & 0x200) result.push('Zone Controller configured'); if (data[62]) result.push('Fake GSSI ' + data[48] + ' +' + data[49]); if (data[63]) result.push('Ping ' + data[63] + ' ms'); if (list.length > 0) result.push('Sites online: ' + list.join(' ')); if (data[7]) { list = [ ]; list.push(statuses[data[7] & 0x07]); if (data[7] & 0x010) list.push('QSIG1'); if (data[7] & 0x020) list.push('QSIG2'); if (data[7] & 0x100) list.push('SNMP'); if (data[7] & 0x200) list.push('ICI'); if (data[7] & 0x400) list.push('DTMF'); result.push('TIG: ' + list.join('/')); } return result; } handlers.contexts.DockStation = (data, reference, order) => { return [ 'GSSI ' + data[0] ]; } handlers.contexts.QuickRapid = (data, reference, order) => { let result = [ ]; if (data[0]) result.push('Connected'); if (data[2]) result.push('Ping ' + data[2] + ' ms'); return result; } handlers.contexts.DataBridge = (data, reference, order) => { let result = [ ]; if (data[2] & 0x01) result.push('IPv4 enabled'); if (data[2] & 0x02) result.push('IPv6 enabled'); if (data[0] || data[1]) result.push('IPv6 network configured'); return result; } handlers.sessions.DummyLink = (type, point, data, reference, order) => { return [ 'Channel ' + data[5].toString(16) ]; } handlers.sessions.SidecarLink = (type, point, data, reference, order) => { let result = [ ]; if ((point == 0) && (type <= 2)) { result.push('number: 0x' + data[0].toString(16)); result.push('mode: 0x' + data[4].toString(16)); result.push('status: 0x' + data[5].toString(16)); result.push('flag: 0x' + data[6].toString(16)); result.push('options: ' + ((data[7] >> 15) & 1) + ' ' + ((data[7] >> 14) & 1) + ' ' + ((data[7] >> 13) & 1) + ' ' + ((data[7] >> 12) & 1) + ' ' + ((data[7] >> 11) & 1) + ' ' + ((data[7] >> 10) & 1) + ' ' + ((data[7] >> 9) & 1) + ' ' + ((data[7] >> 8) & 1) + ' - ' + ((data[7] >> 7) & 1) + ' ' + ((data[7] >> 6) & 1) + ' ' + ((data[7] >> 3) & 7) + ' ' + ((data[7] >> 0) & 7)); } return result; } handlers.sessions.GroupSpread = (type, point, data, reference, order) => { let states = [ 'Queued', 'Transmitting' ]; return (point == 1) ? [ states[data[0]], data[1] + ' routes' ] : [ ]; } handlers.sessions.DetroitBridge = (type, point, data, reference, order) => { let states = [ 'Idle', 'DMR -> TETRA', 'TETRA -> DMR' ]; return (data[0] || data[1]) ? [ states[data[3]] ] : [ ]; } handlers.sessions.DataBridge = (type, point, data, reference, order) => { return [ 'Bytes in: ' + data[0], 'Packets in: ' + data[1], 'Bytes out: ' + data[2], 'Packets out: ' + data[3], 'Errors out: ' + data[4] ]; } function getContextDetailString(entry, reference, order) { return (typeof handlers.contexts[entry.link] == 'function') ? handlers.contexts[entry.link](entry.values, reference, order).join(', ') : ''; } function getSessionDetailString(point, entry, reference, order) { let names = [ 'source', 'destination' ]; let link = entry.points[names[point]] ? entry.points[names[point]].link : ''; return (typeof handlers.sessions[link] == 'function') ? handlers.sessions[link](entry.type & 0xff, point, entry.values[point], reference, order).join(', ') : ''; }