diff --git a/htdocs/lib/MessagePanel.js b/htdocs/lib/MessagePanel.js index 54fcee32..3ecca55e 100644 --- a/htdocs/lib/MessagePanel.js +++ b/htdocs/lib/MessagePanel.js @@ -64,7 +64,7 @@ function WsjtMessagePanel(el) { this.modes = [].concat(this.qsoModes, this.beaconModes); } -WsjtMessagePanel.prototype = new MessagePanel(); +WsjtMessagePanel.prototype = Object.create(MessagePanel.prototype); WsjtMessagePanel.prototype.supportsMessage = function(message) { return this.modes.indexOf(message['mode']) >= 0; @@ -133,7 +133,7 @@ function PacketMessagePanel(el) { this.initClearTimer(); } -PacketMessagePanel.prototype = new MessagePanel(); +PacketMessagePanel.prototype = Object.create(MessagePanel.prototype); PacketMessagePanel.prototype.supportsMessage = function(message) { return message['mode'] === 'APRS'; @@ -239,7 +239,7 @@ PocsagMessagePanel = function(el) { this.initClearTimer(); } -PocsagMessagePanel.prototype = new MessagePanel(); +PocsagMessagePanel.prototype = Object.create(MessagePanel.prototype); PocsagMessagePanel.prototype.supportsMessage = function(message) { return message['mode'] === 'Pocsag'; @@ -282,7 +282,7 @@ AdsbMessagePanel = function(el) { this.initClearTimer(); } -AdsbMessagePanel.prototype = new MessagePanel(); +AdsbMessagePanel.prototype = Object.create(MessagePanel.prototype); AdsbMessagePanel.prototype.supportsMessage = function(message) { return message["mode"] === "ADSB"; @@ -405,7 +405,7 @@ IsmMessagePanel = function(el) { this.initClearTimer(); }; -IsmMessagePanel.prototype = new MessagePanel(); +IsmMessagePanel.prototype = Object.create(MessagePanel.prototype); IsmMessagePanel.prototype.supportsMessage = function(message) { return message['mode'] === 'ISM'; @@ -462,12 +462,60 @@ $.fn.ismMessagePanel = function() { return this.data('panel'); }; -HfdlMessagePanel = function(el) { +AircraftMessagePanel = function(el) { MessagePanel.call(this, el); +} + +AircraftMessagePanel.prototype = Object.create(MessagePanel.prototype); + +AircraftMessagePanel.prototype.renderAcars = function(acars) { + var details = '

ACARS message

'; + if ('flight' in acars) { + details += '
Flight: ' + acars['flight'] + '
'; + } + details += '
Registration: ' + acars['reg'].replace(/^\.+/g, '') + '
'; + if ('media-adv' in acars) { + details += '
Media advisory
'; + if ('current_link' in acars) { + details += '
Current link: ' + acars['current_link']['descr']; + } + if ('links_avail' in acars) { + details += '
Available links: ' + acars['links_avail'].map(function (l) { + return l['descr']; + }).join(', ') + '
'; + } + } else if ('arinc622' in acars) { + var arinc622 = acars['arinc622']; + if ('adsc' in arinc622) { + var adsc = arinc622['adsc']; + if ('tags' in adsc) { + adsc['tags'].forEach(function(tag) { + if ('basic_report' in tag) { + var basic_report = tag['basic_report']; + details += '
Basic report
'; + details += '
Position: ' + basic_report['lat'] + ', ' + basic_report['lon'] + '
'; + details += '
Altitude: ' + basic_report['alt'] + '
'; + } else { + details += '
Unsupported tag
'; + } + }); + } else { + details += '
Other ADS-C data
'; + } + } + } else { + // plain text + details += '
' + acars['msg_text'] + '
'; + } + return details; +} + +HfdlMessagePanel = function(el) { + AircraftMessagePanel.call(this, el); this.initClearTimer(); } -HfdlMessagePanel.prototype = new MessagePanel(); +HfdlMessagePanel.prototype = Object.create(AircraftMessagePanel.prototype); HfdlMessagePanel.prototype.render = function() { $(this.el).append($( @@ -533,13 +581,7 @@ HfdlMessagePanel.prototype.pushMessage = function(message) { } else if (hfnpdu['type']['id'] === 255) { // enveloped data if ('acars' in hfnpdu) { - var acars = hfnpdu['acars']; - details = '

ACARS message

'; - if ('flight' in acars) { - details += '
Flight: ' + acars['flight'] + '
'; - } - details += '
Registration: ' + acars['reg'].replace(/^\.+/g, '') + '
'; - details += '
' + acars['msg_text'] + '
'; + details = this.renderAcars(hfnpdu['acars']); } } } else if (lpdu['type']['id'] === 47) { @@ -599,18 +641,20 @@ $.fn.hfdlMessagePanel = function() { }; Vdl2MessagePanel = function(el) { - MessagePanel.apply(this, el); + AircraftMessagePanel.call(this, el); this.initClearTimer(); } -Vdl2MessagePanel.prototype = new MessagePanel(); +Vdl2MessagePanel.prototype = Object.create(AircraftMessagePanel.prototype); Vdl2MessagePanel.prototype.render = function() { $(this.el).append($( '' + '' + - '' + - '' + + '' + + '' + + '' + + '' + '' + '
TODO
SourceDestinationDetails
' )); @@ -622,9 +666,77 @@ Vdl2MessagePanel.prototype.supportsMessage = function(message) { Vdl2MessagePanel.prototype.pushMessage = function(message) { var $b = $(this.el).find('tbody'); + var src = ''; + var dst = ''; + var details = JSON.stringify(message); + + var renderAddress = function(a) { + return '
' + a['addr'] + '
' + a['type'] + ( 'status' in a ? ' (' + a['status'] + ')' : '' ) + '
' + } + + // TODO remove safety net once parsing is complete + try { + var payload = message['vdl2']; + if ('avlc' in payload) { + var avlc = payload['avlc']; + src = renderAddress(avlc['src']); + dst = renderAddress(avlc['dst']); + + if (avlc['frame_type'] === 'S') { + details = '

Supervisory frame

'; + if (avlc['cmd'] === 'Receive Ready') { + details = '

Receive Ready

'; + } + } else if (avlc['frame_type'] === 'I') { + details = '

Information frame

'; + if ('acars' in avlc) { + details = this.renderAcars(avlc['acars']); + } else if ('x25' in avlc) { + var x25 = avlc['x25']; + if (!('reasm_status' in x25) || ['skipped', 'complete'].includes(x25['reasm_status'])) { + details = '

X.25 frame

'; + if ('clnp' in x25) { + var clnp = x25['clnp'] + if ('cotp' in clnp) { + var cotp = clnp['cotp']; + if ('cpdlc' in cotp) { + var cpdlc = cotp['cpdlc']; + details = '

CPDLC

'; + if ('atc_downlink_message' in cpdlc) { + var atc_downlink_message = cpdlc['atc_downlink_message']; + if ('msg_data' in atc_downlink_message) { + var msg_data = atc_downlink_message['msg_data']; + if ('msg_elements' in msg_data) { + details += '
' + msg_data['msg_elements'].map(function(e) { return e['msg_element']['choice_label']; }).join(', ') + '
'; + } + } else { + details += '
' + JSON.stringify(cpdlc) + '
'; + } + } + } + } + } + } else { + details = '

Partial X.25 frame

'; + } + } + } else if (avlc['frame_type'] === 'U') { + details = '

Unnumbered frame

'; + if ('xid' in avlc) { + var xid = avlc['xid']; + details = '

' + xid['type_descr'] + '

'; + } + } + } + } catch (e) { + console.error(e, e.stack); + } + $b.append($( '' + - '' + JSON.stringify(message) + '' + + '' + src + '' + + '' + dst + '' + + '' + details + '' + '' )); this.scrollToBottom();