diff --git a/htdocs/css/openwebrx.css b/htdocs/css/openwebrx.css
index aaf85759..1cc73c47 100644
--- a/htdocs/css/openwebrx.css
+++ b/htdocs/css/openwebrx.css
@@ -1122,6 +1122,15 @@ img.openwebrx-mirror-img
background-color: #575757;
}
+.openwebrx-message-panel h4 {
+ margin: .25em 0;
+}
+
+.openwebrx-message-panel .acars-message {
+ white-space: pre;
+ font-family: roboto-mono, monospace;
+}
+
#openwebrx-panel-wsjt-message .message {
width: 380px;
}
diff --git a/htdocs/lib/MessagePanel.js b/htdocs/lib/MessagePanel.js
index f9023d29..40f7f606 100644
--- a/htdocs/lib/MessagePanel.js
+++ b/htdocs/lib/MessagePanel.js
@@ -473,7 +473,9 @@ HfdlMessagePanel.prototype.render = function() {
$(this.el).append($(
'
' +
'' +
- '| TODO | ' +
+ 'Source | ' +
+ 'Destination | ' +
+ 'Details | ' +
'
' +
'' +
'
'
@@ -486,11 +488,105 @@ HfdlMessagePanel.prototype.supportsMessage = function(message) {
HfdlMessagePanel.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['id'];
+ }
+
+ // TODO remove safety net once parsing is complete
+ try {
+ var payload = message['hfdl'];
+ if ('spdu' in payload) {
+ var spdu = payload['spdu'];
+ src = renderAddress(spdu['src']);
+ details = 'HFDL Squitter message
'
+ details += 'Systable version: ' + spdu['systable_version'] + '
';
+
+ if ('gs_status' in spdu) {
+ details += spdu['gs_status'].map(function(gs){
+ return 'Ground station ' + gs['gs']['id'] + ' is operating on frequency ids ' + gs['freqs'].map(function(f) {return f['id']; }).join(', ') + '
';
+ }).join('')
+ }
+ } else if ('lpdu' in payload) {
+ var lpdu = payload['lpdu'];
+ src = renderAddress(lpdu['src']);
+ dst = renderAddress(lpdu['dst']);
+ if (lpdu['type']['id'] === 13 || lpdu['type']['id'] === 29) {
+ // unnumbered data
+ var hfnpdu = lpdu['hfnpdu'];
+ if (hfnpdu['type']['id'] === 209) {
+ // performance data
+ details = 'Performance data
';
+ details += 'Flight: ' + hfnpdu['flight_id'] + '
';
+ if ('pos' in hfnpdu) {
+ var pos = hfnpdu['pos'];
+ var lat = pos['lat'] || 180;
+ var lon = pos['lon'] || 180;
+ if (Math.abs(lat) <= 90 && Math.abs(lon) <= 180) {
+ details += 'Position: ' + pos['lat'] + ', ' + pos['lon'] + '
';
+ }
+ }
+ } else if (hfnpdu['type']['id'] === 255) {
+ // enveloped data
+ if ('acars' in hfnpdu) {
+ var acars = hfnpdu['acars'];
+ details = 'ACARS message
';
+ details += 'Flight: ' + acars['flight'] + '
';
+ details += 'Registration: ' + acars['reg'] + '
';
+ details += '' + acars['msg_text'] + '
';
+ }
+ }
+ } else if (lpdu['type']['id'] === 47) {
+ // logon denied
+ details = 'Logon denied
';
+ } else if (lpdu['type']['id'] === 63) {
+ details = 'Logoff request
';
+ if (lpdu['ac_info'] && lpdu['ac_info']['icao']) {
+ details += 'ICAO: ' + lpdu['ac_info']['icao'];
+ }
+ } else if (lpdu['type']['id'] === 79) {
+ details = '
Logon resume
';
+ if (lpdu['ac_info'] && lpdu['ac_info']['icao']) {
+ details += '
ICAO: ' + lpdu['ac_info']['icao'];
+ }
+ } else if (lpdu['type']['id'] === 95) {
+ details = '
Logon resume confirmation
';
+ } else if (lpdu['type']['id'] === 143) {
+ details = '
Logon request
';
+ if (lpdu['ac_info'] && lpdu['ac_info']['icao']) {
+ details += '
ICAO: ' + lpdu['ac_info']['icao'];
+ }
+ } else if (lpdu['type']['id'] === 159) {
+ details = '
Logon confirmation
';
+ if (lpdu['ac_info'] && lpdu['ac_info']['icao']) {
+ details += '
ICAO: ' + lpdu['ac_info']['icao'];
+ }
+ if (lpdu['assigned_ac_id']) {
+ details += '
Assigned aircraft ID: ' + lpdu['assigned_ac_id'] + '
';
+ }
+ } else if (lpdu['type']['id'] === 191) {
+ details = '
Logon request (DLS)
';
+ if (lpdu['ac_info'] && lpdu['ac_info']['icao']) {
+ details += '
ICAO: ' + lpdu['ac_info']['icao'];
+ }
+ }
+ }
+ } catch (e) {
+ console.error(e, e.stack);
+ }
+
$b.append($(
'
' +
- '| ' + JSON.stringify(message) + ' | ' +
+ '' + src + ' | ' +
+ '' + dst + ' | ' +
+ '' + details + ' | ' +
'
'
));
+ this.scrollToBottom();
};
$.fn.hfdlMessagePanel = function() {