Skip to content

Commit

Permalink
fix(atsu): fix message interpretation (#7065)
Browse files Browse the repository at this point in the history
* fix message interpretation errors

* add a missing message

* remove a debugging log

* remove old code

* overwrite the response type, if needed

* allow the change of responses, if needed

* avoid double-creation

* use correct abbreviations

* fix DCDU visualization highlights

* export the hoppie connector

* add a function to deactivate hoppie

* update the hoppie connection after weather source changes

* fix an interval crash after the network connection is lost
  • Loading branch information
svengcz authored Apr 20, 2022
1 parent 56c798e commit 9a253b6
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,6 @@ class CDUAtcDepartReq {
["<RETURN"]
]);

// define the template
mcdu.setTemplate(addionalLineTemplate);

mcdu.leftInputDelay[5] = () => {
return mcdu.getDelaySwitchPage();
};
Expand Down
7 changes: 5 additions & 2 deletions src/atsu/src/ATC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,15 @@ export class Atc {
public sendResponse(uid: number, response: number): void {
const message = this.messageQueue.find((element) => element.UniqueMessageID === uid);
if (message !== undefined) {
const responseMsg = this.createCpdlcResponse(message, response);

// avoid double-sents
if (message.Response !== undefined && (message.Response.ComStatus === AtsuMessageComStatus.Sending || message.Response.ComStatus === AtsuMessageComStatus.Sent)) {
if (message.Response !== undefined && message.Response.Content.TypeId === responseMsg.Content.TypeId
&& (message.Response.ComStatus === AtsuMessageComStatus.Sending || message.Response.ComStatus === AtsuMessageComStatus.Sent)) {
return;
}

message.Response = this.createCpdlcResponse(message, response);
message.Response = responseMsg;
message.Response.ComStatus = AtsuMessageComStatus.Sending;
this.dcduLink.update(message);

Expand Down
154 changes: 86 additions & 68 deletions src/atsu/src/com/webinterfaces/HoppieConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Hoppie } from '@flybywiresim/api-client';
import { AtsuStatusCodes } from '../../AtsuStatusCodes';
import { AtsuMessage, AtsuMessageNetwork, AtsuMessageDirection, AtsuMessageComStatus, AtsuMessageSerializationFormat } from '../../messages/AtsuMessage';
import { CpdlcMessage } from '../../messages/CpdlcMessage';
import { CpdlcMessagesUplink, CpdlcMessageElement, CpdlcMessageContent } from '../../messages/CpdlcMessageElements';
import { CpdlcMessagesUplink, CpdlcMessageElement, CpdlcMessageContent, CpdlcMessageExpectedResponseType } from '../../messages/CpdlcMessageElements';
import { FreetextMessage } from '../../messages/FreetextMessage';
import { FansMode } from '../FutureAirNavigationSystem';

Expand Down Expand Up @@ -56,6 +56,10 @@ export class HoppieConnector {
});
}

public static deactivateHoppie(): void {
SimVar.SetSimVarValue('L:A32NX_HOPPIE_ACTIVE', 'number', 0);
}

public static async connect(flightNo: string): Promise<AtsuStatusCodes> {
if (SimVar.GetSimVarValue('L:A32NX_HOPPIE_ACTIVE', 'number') !== 1) {
HoppieConnector.flightNumber = flightNo;
Expand Down Expand Up @@ -174,13 +178,16 @@ export class HoppieConnector {
}

private static levenshteinDistance(template: string, message: string, content: CpdlcMessageContent[]): number {
const elements = message.split(' ');
let elements = message.split(' ');
let validContent = true;

// try to match the content
content.forEach((entry) => {
if (!entry.validateAndReplaceContent(elements)) {
const result = entry.validateAndReplaceContent(elements);
if (!result.matched) {
validContent = false;
} else {
elements = result.remaining;
}
});
if (!validContent) return 100000;
Expand Down Expand Up @@ -271,11 +278,14 @@ export class HoppieConnector {

// create a deep-copy of the message
const retval: CpdlcMessageElement = CpdlcMessagesUplink[matches[0]][1].deepCopy();
const elements = message.split(' ');
let elements = message.split(' ');
console.log(`Selected UM-ID: ${matches[0]}`);

// parse the content and store it in the deep copy
retval.Content.forEach((entry) => entry.validateAndReplaceContent(elements));
retval.Content.forEach((entry) => {
const result = entry.validateAndReplaceContent(elements);
elements = result.remaining;
});

return retval;
}
Expand All @@ -287,73 +297,81 @@ export class HoppieConnector {
return [AtsuStatusCodes.NoHoppieConnection, retval];
}

const body = {
logon: NXDataStore.get('CONFIG_HOPPIE_USERID', ''),
from: HoppieConnector.flightNumber,
to: HoppieConnector.flightNumber,
type: 'poll',
};
const text = await Hoppie.sendRequest(body).then((resp) => resp.response).catch(() => 'proxy');

// proxy error during request
if (text === 'proxy') {
return [AtsuStatusCodes.ProxyError, retval];
}
try {
const body = {
logon: NXDataStore.get('CONFIG_HOPPIE_USERID', ''),
from: HoppieConnector.flightNumber,
to: HoppieConnector.flightNumber,
type: 'poll',
};
const text = await Hoppie.sendRequest(body).then((resp) => resp.response).catch(() => 'proxy');

// proxy error during request
if (text === 'proxy') {
return [AtsuStatusCodes.ProxyError, retval];
}

// something went wrong
if (!text.startsWith('ok')) {
return [AtsuStatusCodes.ComFailed, retval];
}
// something went wrong
if (!text.startsWith('ok')) {
return [AtsuStatusCodes.ComFailed, retval];
}

// split up the received data into multiple messages
let messages = text.split(/({.*?})/gm);
messages = messages.filter((elem) => elem !== 'ok' && elem !== 'ok ' && elem !== '} ' && elem !== '}' && elem !== '');

// create the messages
messages.forEach((element) => {
// get the single entries of the message
// example: [CALLSIGN telex, {Hello world!}]
const entries = element.substring(1).split(/({.*?})/gm);

// get all relevant information
const metadata = entries[0].split(' ');
const sender = metadata[0].toUpperCase();
const type = metadata[1].toLowerCase();
const content = entries[1].replace(/{/, '').replace(/}/, '').toUpperCase();

switch (type) {
case 'telex':
const freetext = new FreetextMessage();
freetext.Network = AtsuMessageNetwork.Hoppie;
freetext.Station = sender;
freetext.Direction = AtsuMessageDirection.Uplink;
freetext.ComStatus = AtsuMessageComStatus.Received;
freetext.Message = content.replace(/\n/i, ' ');
retval.push(freetext);
break;
case 'cpdlc':
const cpdlc = new CpdlcMessage();
cpdlc.Station = sender;
cpdlc.Direction = AtsuMessageDirection.Uplink;
cpdlc.ComStatus = AtsuMessageComStatus.Received;

// split up the data
const elements = content.split('/');
cpdlc.CurrentTransmissionId = parseInt(elements[2]);
if (elements[3] !== '') {
cpdlc.PreviousTransmissionId = parseInt(elements[3]);
// split up the received data into multiple messages
let messages = text.split(/({.*?})/gm);
messages = messages.filter((elem) => elem !== 'ok' && elem !== 'ok ' && elem !== '} ' && elem !== '}' && elem !== '');

// create the messages
messages.forEach((element) => {
// get the single entries of the message
// example: [CALLSIGN telex, {Hello world!}]
const entries = element.substring(1).split(/({.*?})/gm);

// get all relevant information
const metadata = entries[0].split(' ');
const sender = metadata[0].toUpperCase();
const type = metadata[1].toLowerCase();
const content = entries[1].replace(/{/, '').replace(/}/, '').toUpperCase();

switch (type) {
case 'telex':
const freetext = new FreetextMessage();
freetext.Network = AtsuMessageNetwork.Hoppie;
freetext.Station = sender;
freetext.Direction = AtsuMessageDirection.Uplink;
freetext.ComStatus = AtsuMessageComStatus.Received;
freetext.Message = content.replace(/\n/i, ' ');
retval.push(freetext);
break;
case 'cpdlc':
const cpdlc = new CpdlcMessage();
cpdlc.Station = sender;
cpdlc.Direction = AtsuMessageDirection.Uplink;
cpdlc.ComStatus = AtsuMessageComStatus.Received;

// split up the data
const elements = content.split('/');
cpdlc.CurrentTransmissionId = parseInt(elements[2]);
if (elements[3] !== '') {
cpdlc.PreviousTransmissionId = parseInt(elements[3]);
}
cpdlc.Content = HoppieConnector.cpdlcMessageClassification(elements[5]);
if ((elements[4] as CpdlcMessageExpectedResponseType) !== cpdlc.Content.ExpectedResponse) {
cpdlc.Content.ExpectedResponse = (elements[4] as CpdlcMessageExpectedResponseType);
}
cpdlc.Message = elements[5];

retval.push(cpdlc);
break;
default:
break;
}
cpdlc.Content = HoppieConnector.cpdlcMessageClassification(elements[5]);
cpdlc.Message = elements[5];
});

retval.push(cpdlc);
break;
default:
break;
}
});

return [AtsuStatusCodes.Ok, retval];
return [AtsuStatusCodes.Ok, retval];
} catch (_err) {
console.log('ERROR IN POLL');
return [AtsuStatusCodes.NoHoppieConnection, []];
}
}

public static pollInterval(): number {
Expand Down
2 changes: 2 additions & 0 deletions src/atsu/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { DclMessage } from './messages/DclMessage';
import { OclMessage } from './messages/OclMessage';
import { InputValidation, InputWaypointType } from './InputValidation';
import { FansMode } from './com/FutureAirNavigationSystem';
import { HoppieConnector } from './com/webinterfaces/HoppieConnector';

export {
AtsuStatusCodes,
Expand Down Expand Up @@ -46,4 +47,5 @@ export {
RequestMessage,
InputValidation,
InputWaypointType,
HoppieConnector,
};
2 changes: 1 addition & 1 deletion src/atsu/src/messages/CpdlcMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class CpdlcMessage extends AtsuMessage {
content = template;
element.Content.forEach((entry) => {
const idx = content.indexOf('%s');
content = `${content.substring(0, idx)}${entry.Value}${content.substring(idx + 2)}`;
content = `${content.substring(0, idx)}@${entry.Value}@${content.substring(idx + 2)}`;
});

return content;
Expand Down
Loading

0 comments on commit 9a253b6

Please sign in to comment.