diff --git a/README.md b/README.md
index 6debf2d..302461d 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ Supported modules:
* AV8BNA Harrier
* Ka-50 Blackshark
* AH-64D Apache (Pilot and CP/G)
+* OH-58D Kiowa Warrior
* Mirage F1EE
* UH-60L Blackhawk
* Hercules (Requires patch available at https://github.com/Summit60/DCS-Hercules-TheWay-patch)
diff --git a/electron/TCPSender.js b/electron/TCPSender.js
index fddc5a3..daea898 100644
--- a/electron/TCPSender.js
+++ b/electron/TCPSender.js
@@ -8,6 +8,7 @@ class TCPSender {
client
.connect(42070, "127.0.0.1", function () {
client.write(JSON.stringify(msg) + "\n");
+ client.end();
})
.on("error", (e) => {
console.log(e);
diff --git a/package-lock.json b/package-lock.json
index 7b2fe6f..27a1a4a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "theway",
- "version": "2.4.2",
+ "version": "2.5.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "theway",
- "version": "2.4.2",
+ "version": "2.5.0",
"dependencies": {
"electron-devtools-installer": "^3.2.0",
"electron-is-dev": "^2.0.0",
diff --git a/package.json b/package.json
index e06433a..d744cd2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "theway",
- "version": "2.4.2",
+ "version": "2.5.0",
"private": true,
"main": "electron/electron.js",
"dependencies": {
diff --git a/public/assets/moduleImages/OH58D.jpg b/public/assets/moduleImages/OH58D.jpg
new file mode 100644
index 0000000..2b60442
Binary files /dev/null and b/public/assets/moduleImages/OH58D.jpg differ
diff --git a/src/App.js b/src/App.js
index 2714598..017793e 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,7 +4,7 @@ import { useDispatch, useSelector } from "react-redux";
import ModalContainer from "react-modal-promise";
import SourceSelector from "./components/SourceSelector";
-import WaypointList from "./components/WaypointList";
+import WaypointList from "./components/waypoints/WaypointList";
import theWayTheme from "./theme/TheWayTheme";
import TransferControls from "./components/TransferControls";
import TitleBar from "./components/TitleBar";
diff --git a/src/components/WaypointItem.js b/src/components/WaypointItem.js
deleted file mode 100644
index d59db39..0000000
--- a/src/components/WaypointItem.js
+++ /dev/null
@@ -1,157 +0,0 @@
-import {
- Button,
- IconButton,
- ListItem,
- ListItemText,
- Stack,
- Grid,
- TextField,
- Input,
- Box,
- Tooltip,
- Typography,
- Collapse,
- Grow,
-} from "@mui/material";
-import {
- DragHandle,
- ArrowDropDown,
- ArrowDropUp,
- Delete,
-} from "@mui/icons-material";
-import { useSortable } from "@dnd-kit/sortable";
-import { CSS } from "@dnd-kit/utilities";
-
-import "./WaypointItem.css";
-
-const { ipcRenderer } = window.require("electron");
-
-const WaypointItem = (props) => {
- const { attributes, listeners, setNodeRef, transform, transition } =
- useSortable({ id: props.id });
- const style = {
- transform: CSS.Transform.toString(transform),
- transition,
- };
-
- const handleInputFocus = () => {
- ipcRenderer.send("focus");
- };
- const handleInputDefocus = (event) => {
- ipcRenderer.send("defocus");
- event.target.blur();
- };
- const handleInputFinished = (event) => {
- if (event.key === "Enter") {
- props.onExpand(props.id, !props.expanded);
- handleInputDefocus();
- }
- };
-
- return (
-
-
-
-
-
-
- {props.expanded ? (
- props.onRename(e, props.id)}
- onMouseEnter={handleInputFocus}
- onMouseLeave={handleInputDefocus}
- onKeyDown={handleInputFinished}
- onFocus={(e) => e.target.select()}
- />
- ) : (
- {props.name}
- )}
-
-
-
-
-
- LAT
-
-
-
-
-
-
-
-
-
-
- LONG
-
-
-
-
-
-
-
-
-
-
- ELEV
-
-
-
- props.onElevation(e, props.id)}
- onMouseEnter={handleInputFocus}
- onMouseLeave={handleInputDefocus}
- onKeyDown={handleInputFinished}
- >
-
-
-
-
-
-
-
- {props.pending ? (
-
-
-
-
-
- ) : (
-
- props.onDelete(e, props.id)}>
-
-
- props.onExpand(props.id, !props.expanded)}
- >
- {props.expanded ? : }
-
-
-
-
-
- )}
-
-
-
-
- );
-};
-
-export default WaypointItem;
diff --git a/src/components/waypoints/WaypointFieldsLatLong.js b/src/components/waypoints/WaypointFieldsLatLong.js
new file mode 100644
index 0000000..6873078
--- /dev/null
+++ b/src/components/waypoints/WaypointFieldsLatLong.js
@@ -0,0 +1,59 @@
+import { Box, Grid, Input, Typography } from "@mui/material";
+
+const WaypointFieldsLatLong = ({
+ id,
+ latHem,
+ longHem,
+ lat,
+ long,
+ elev,
+ onElevation,
+ handleInputFocus,
+ handleInputDefocus,
+ handleInputFinished,
+}) => {
+ return (
+
+
+
+
+ LAT
+
+
+
+
+
+
+
+
+
+
+ LONG
+
+
+
+
+
+
+
+
+
+
+ ELEV
+
+
+
+ onElevation(e, id)}
+ onMouseEnter={handleInputFocus}
+ onMouseLeave={handleInputDefocus}
+ onKeyDown={handleInputFinished}
+ >
+
+
+
+ );
+};
+
+export default WaypointFieldsLatLong;
diff --git a/src/components/waypoints/WaypointFieldsMGRS.js b/src/components/waypoints/WaypointFieldsMGRS.js
new file mode 100644
index 0000000..f08f6c1
--- /dev/null
+++ b/src/components/waypoints/WaypointFieldsMGRS.js
@@ -0,0 +1,45 @@
+import { Box, Grid, Input, Typography } from "@mui/material";
+
+const WaypointFieldsMGRS = ({
+ id,
+ mgrs,
+ elev,
+ onElevation,
+ handleInputFocus,
+ handleInputDefocus,
+ handleInputFinished,
+}) => {
+ return (
+
+
+
+
+ MGRS
+
+
+
+
+
+
+
+
+
+
+ ELEV
+
+
+
+ onElevation(e, id)}
+ onMouseEnter={handleInputFocus}
+ onMouseLeave={handleInputDefocus}
+ onKeyDown={handleInputFinished}
+ >
+
+
+
+ );
+};
+
+export default WaypointFieldsMGRS;
diff --git a/src/components/WaypointItem.css b/src/components/waypoints/WaypointItem.css
similarity index 100%
rename from src/components/WaypointItem.css
rename to src/components/waypoints/WaypointItem.css
diff --git a/src/components/waypoints/WaypointItem.js b/src/components/waypoints/WaypointItem.js
new file mode 100644
index 0000000..a0e1434
--- /dev/null
+++ b/src/components/waypoints/WaypointItem.js
@@ -0,0 +1,145 @@
+import {
+ Button,
+ IconButton,
+ ListItem,
+ ListItemText,
+ Stack,
+ Grid,
+ TextField,
+ Box,
+ Tooltip,
+ Collapse,
+ Grow,
+} from "@mui/material";
+import {
+ DragHandle,
+ ArrowDropDown,
+ ArrowDropUp,
+ Delete,
+} from "@mui/icons-material";
+import { useSortable } from "@dnd-kit/sortable";
+import { CSS } from "@dnd-kit/utilities";
+
+import "./WaypointItem.css";
+import WaypointFieldsMGRS from "./WaypointFieldsMGRS";
+import WaypointFieldsLatLong from "./WaypointFieldsLatLong";
+
+const { ipcRenderer } = window.require("electron");
+
+const WaypointItem = ({
+ wp,
+ pending,
+ onSave,
+ onDelete,
+ onRename,
+ expanded,
+ onExpand,
+ onElevation,
+}) => {
+ const { attributes, listeners, setNodeRef, transform, transition } =
+ useSortable({ id: wp?.id });
+ const style = {
+ transform: CSS.Transform.toString(transform),
+ transition,
+ };
+
+ const handleInputFocus = () => {
+ ipcRenderer.send("focus");
+ };
+ const handleInputDefocus = (event) => {
+ ipcRenderer.send("defocus");
+ event.target.blur();
+ };
+ const handleInputFinished = (event) => {
+ if (event.key === "Enter") {
+ onExpand(wp?.id, !expanded);
+ handleInputDefocus();
+ }
+ };
+
+ return (
+
+
+
+
+
+
+ {expanded ? (
+ onRename(e, wp?.id)}
+ onMouseEnter={handleInputFocus}
+ onMouseLeave={handleInputDefocus}
+ onKeyDown={handleInputFinished}
+ onFocus={(e) => e.target.select()}
+ />
+ ) : (
+ {wp?.name || "New Waypoint"}
+ )}
+
+ {wp?.MGRS ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {pending ? (
+
+
+
+
+
+ ) : (
+
+ onDelete(e, wp?.id)}>
+
+
+ onExpand(wp?.id, !expanded)}>
+ {expanded ? : }
+
+
+
+
+
+ )}
+
+
+
+
+ );
+};
+
+export default WaypointItem;
diff --git a/src/components/WaypointList.js b/src/components/waypoints/WaypointList.js
similarity index 82%
rename from src/components/WaypointList.js
rename to src/components/waypoints/WaypointList.js
index e13badd..56fd066 100644
--- a/src/components/WaypointList.js
+++ b/src/components/waypoints/WaypointList.js
@@ -1,8 +1,8 @@
import { Box, Button, Card, List, Typography } from "@mui/material";
import WaypointItem from "./WaypointItem";
import { useDispatch, useSelector } from "react-redux";
-import { waypointsActions } from "../store/waypoints";
-import Convertors from "../utils/Convertors";
+import { waypointsActions } from "../../store/waypoints";
+import Convertors from "../../utils/Convertors";
import { closestCenter, DndContext } from "@dnd-kit/core";
import {
restrictToVerticalAxis,
@@ -13,7 +13,7 @@ import {
SortableContext,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
-import ConvertModuleWaypoints from "../utils/ConvertModuleWaypoints";
+import ConvertModuleWaypoints from "../../utils/ConvertModuleWaypoints";
import { useEffect, useRef, useState } from "react";
const WaypointList = () => {
@@ -56,8 +56,11 @@ const WaypointList = () => {
};
const elevationHandler = (event, id) => {
- const elev = Convertors.fToM(event.target.value);
- dispatch(waypointsActions.changeElevation({ id, elev }));
+ const enteredValue = event.target.value;
+ if (!isNaN(enteredValue)) {
+ const elev = Convertors.fToM(event.target.value);
+ dispatch(waypointsActions.changeElevation({ id, elev }));
+ }
};
const expandHandler = (id, isExpanded) => {
@@ -103,14 +106,8 @@ const WaypointList = () => {
{moduleCoordinates.map((wp) => (
{
))}
{isPending && (
-
+
)}
>
) : (
diff --git a/src/moduleCommands/GetModuleCommands.js b/src/moduleCommands/GetModuleCommands.js
index 9848ca8..2d616e6 100644
--- a/src/moduleCommands/GetModuleCommands.js
+++ b/src/moduleCommands/GetModuleCommands.js
@@ -9,6 +9,7 @@ import ka50 from "./ka50";
import miragef1 from "./miragef1";
import uh60l from "./uh60l";
import hercules from "./Hercules";
+import oh58d from "./oh58d";
export default function getModuleCommands(module, waypoints, buttonExtraDelay) {
switch (module) {
@@ -77,6 +78,16 @@ export default function getModuleCommands(module, waypoints, buttonExtraDelay) {
hercules.extraDelay = buttonExtraDelay;
return hercules.createButtonCommands(waypoints);
}
+ case "OH58Dright-seat": {
+ oh58d.extraDelay = buttonExtraDelay;
+ oh58d.slotVariant = "OH58Dright-seat";
+ return oh58d.createButtonCommands(waypoints);
+ }
+ case "OH58Dleft-seat": {
+ oh58d.extraDelay = buttonExtraDelay;
+ oh58d.slotVariant = "OH58Dleft-seat";
+ return oh58d.createButtonCommands(waypoints);
+ }
default:
return [];
}
diff --git a/src/moduleCommands/askUserAboutSeat.js b/src/moduleCommands/askUserAboutSeat.js
index ad23eaa..1af3b6d 100644
--- a/src/moduleCommands/askUserAboutSeat.js
+++ b/src/moduleCommands/askUserAboutSeat.js
@@ -76,6 +76,20 @@ const askUserAboutSeat = async (module, userPreferences) => {
"Make sure you have downloaded the Patch for the Hercules module: https://github.com/Summit60/DCS-Hercules-TheWay-patch",
}).then(() => "Hercules");
}
+ } else if (module === "OH58D") {
+ if (moduleSpecificPreferences?.includes("Right Seat"))
+ return "OH58Dright-seat";
+ else if (moduleSpecificPreferences?.includes("Left Seat"))
+ return "OH58Dleft-seat";
+ else {
+ return TwoOptionsDialog({
+ title: "What seat are you in?",
+ op1: "Right Seat",
+ op2: "Left Seat",
+ }).then((option) =>
+ option === "Left Seat" ? "OH58Dleft-seat" : "OH58Dright-seat",
+ );
+ }
} else return module;
};
diff --git a/src/moduleCommands/oh58d.js b/src/moduleCommands/oh58d.js
new file mode 100644
index 0000000..81022f8
--- /dev/null
+++ b/src/moduleCommands/oh58d.js
@@ -0,0 +1,171 @@
+import createButtonPress from "../models/ButtonPress";
+
+class oh58d {
+ static extraDelay = 100;
+ static #delay100 = 100 + this.extraDelay;
+ static slotVariant = "";
+ static #oh58dkeycodes = {
+ // Keyboard keys (device 14)
+ a: 3063,
+ b: 3064,
+ c: 3065,
+ d: 3066,
+ e: 3067,
+ f: 3068,
+ g: 3069,
+ h: 3070,
+ i: 3071,
+ j: 3072,
+ k: 3073,
+ l: 3074,
+ m: 3075,
+ n: 3076,
+ o: 3077,
+ p: 3078,
+ q: 3079,
+ r: 3080,
+ s: 3081,
+ t: 3082,
+ u: 3083,
+ v: 3084,
+ w: 3085,
+ x: 3086,
+ y: 3087,
+ z: 3088,
+ // number keys
+ 0: 3062,
+ 1: 3053,
+ 2: 3054,
+ 3: 3055,
+ 4: 3056,
+ 5: 3057,
+ 6: 3058,
+ 7: 3059,
+ 8: 3060,
+ 9: 3061,
+ // special keys
+ " ": 3094,
+ ".": 3090,
+ "-": 3095,
+ enter: 3089,
+ clear: 3091,
+ // pilot MFD (device 11) copilot MFD (device 23)
+ vsd: 3008,
+ hsd: 3009,
+ l1: 3001,
+ l2: 3002,
+ l3: 3003,
+ l4: 3004,
+ l5: 3005,
+
+ r1: 3013,
+ r2: 3014,
+ r3: 3015,
+ r4: 3016,
+ r5: 3017,
+ };
+ static #codesPayload = [];
+
+ static #isPilot() {
+ return this.slotVariant === "OH58Dright-seat";
+ }
+
+ static createButtonCommands(waypoints) {
+ this.#codesPayload = [];
+ this.#codesPayload.push(
+ // enter nav setup on pilot MFD
+ createButtonPress(
+ this.#isPilot() ? 11 : 23,
+ this.#oh58dkeycodes["hsd"],
+ this.#delay100,
+ ),
+ createButtonPress(
+ this.#isPilot() ? 11 : 23,
+ this.#oh58dkeycodes["r2"],
+ this.#delay100,
+ ),
+ createButtonPress(
+ this.#isPilot() ? 11 : 23,
+ this.#oh58dkeycodes["l4"],
+ this.#delay100,
+ ),
+ );
+
+ for (const waypoint of waypoints) {
+ this.#codesPayload.push(
+ // enter waypoint
+ createButtonPress(
+ this.#isPilot() ? 11 : 23,
+ this.#oh58dkeycodes["l2"],
+ this.#delay100,
+ ),
+ createButtonPress(14, this.#oh58dkeycodes["clear"], this.#delay100),
+ );
+ const [zone, squareId, easting, northing] = waypoint.MGRS.split(" ");
+ let convertedWaypoint = `${zone} ${squareId} ${easting.slice(
+ 0,
+ 4,
+ )} ${northing.slice(0, 4)}`;
+ for (let i = 0; i < convertedWaypoint.length; i++) {
+ if (convertedWaypoint.charAt(i) !== " ") {
+ this.#codesPayload.push(
+ // enter each digit of MGRS into scratchpad
+ createButtonPress(
+ 14,
+ this.#oh58dkeycodes[convertedWaypoint.charAt(i).toLowerCase()],
+ this.#delay100,
+ ),
+ );
+ }
+ }
+ this.#codesPayload.push(
+ // enter MGRS into UFC
+ createButtonPress(14, this.#oh58dkeycodes["enter"], this.#delay100),
+ );
+
+ this.#codesPayload.push(
+ // select altitude on mfd
+ createButtonPress(
+ this.#isPilot() ? 11 : 23,
+ this.#oh58dkeycodes["l4"],
+ this.#delay100,
+ ),
+ createButtonPress(14, this.#oh58dkeycodes["clear"], this.#delay100), // clear current alt
+ );
+
+ for (let i = 0; i < waypoint.elev.length; i++) {
+ // enter in waypoint elevation
+ this.#codesPayload.push(
+ createButtonPress(
+ 14,
+ this.#oh58dkeycodes[waypoint.elev.charAt(i).toLowerCase()],
+ this.#delay100,
+ ),
+ );
+ }
+
+ this.#codesPayload.push(
+ // press enter on scratchpad
+ createButtonPress(14, this.#oh58dkeycodes["enter"], this.#delay100),
+ createButtonPress(
+ this.#isPilot() ? 11 : 23,
+ this.#oh58dkeycodes["r5"],
+ this.#delay100,
+ ),
+ );
+ }
+
+ this.#codesPayload.push(
+ // exit nav setup on pilot MFD
+ createButtonPress(
+ this.#isPilot() ? 11 : 23,
+ this.#oh58dkeycodes["vsd"],
+ this.#delay100,
+ ),
+ );
+
+ return this.#codesPayload;
+ }
+}
+
+export default oh58d;
diff --git a/src/utils/ConvertModuleWaypoints.js b/src/utils/ConvertModuleWaypoints.js
index 44cff80..08346dd 100644
--- a/src/utils/ConvertModuleWaypoints.js
+++ b/src/utils/ConvertModuleWaypoints.js
@@ -20,6 +20,7 @@ const convert = (dcsWaypoints, module) => {
//long 000.00.000
let waypoints = [];
for (const dcsWaypoint of dcsWaypoints) {
+
const name = dcsWaypoint.name;
const id = dcsWaypoint.id;
const dmmLat = Convertors.decimalToDMM(dcsWaypoint.lat);
@@ -190,6 +191,22 @@ const convert = (dcsWaypoints, module) => {
}
return waypoints;
}
+ case "OH58D": {
+ let waypoints = [];
+ for (const dcsWaypoint of dcsWaypoints) {
+ const name = dcsWaypoint.name;
+ const id = dcsWaypoint.id;
+ const MGRS = Convertors.decimalToMGRS(dcsWaypoint.lat, dcsWaypoint.long);
+ const elev = Math.trunc(Convertors.mToF(dcsWaypoint.elev)).toString();
+ waypoints.push({
+ name,
+ id,
+ MGRS,
+ elev,
+ });
+ }
+ return waypoints;
+ }
}
};
diff --git a/src/utils/Convertors.js b/src/utils/Convertors.js
index d46eece..a924578 100644
--- a/src/utils/Convertors.js
+++ b/src/utils/Convertors.js
@@ -21,6 +21,73 @@ class Convertors {
static fToM(f) {
return f / 3.280839895;
}
+
+ static decimalToMGRS(Lat, Long) {
+ // source: https://stackoverflow.com/questions/46728319/how-to-convert-between-lat-long-and-mgrs-using-javascript-without-dependence-on
+ if (Lat < -80) return "Too far South";
+ if (Lat > 84) return "Too far North";
+ const c = 1 + Math.floor((Long + 180) / 6);
+ const e = c * 6 - 183;
+ const k = (Lat * Math.PI) / 180;
+ const l = (Long * Math.PI) / 180;
+ const m = (e * Math.PI) / 180;
+ const n = Math.cos(k);
+ const o = 0.006739496819936062 * Math.pow(n, 2);
+ const p = 40680631590769 / (6356752.314 * Math.sqrt(1 + o));
+ const q = Math.tan(k);
+ const r = q * q;
+ const t = l - m;
+ const u = 1.0 - r + o;
+ const v = 5.0 - r + 9 * o + 4.0 * (o * o);
+ const w = 5.0 - 18.0 * r + r * r + 14.0 * o - 58.0 * r * o;
+ const x = 61.0 - 58.0 * r + r * r + 270.0 * o - 330.0 * r * o;
+ const y = 61.0 - 479.0 * r + 179.0 * (r * r) - r * r * r;
+ const z = 1385.0 - 3111.0 * r + 543.0 * (r * r) - r * r * r;
+ let aa =
+ p * n * t +
+ (p / 6.0) * Math.pow(n, 3) * u * Math.pow(t, 3) +
+ (p / 120.0) * Math.pow(n, 5) * w * Math.pow(t, 5) +
+ (p / 5040.0) * Math.pow(n, 7) * y * Math.pow(t, 7);
+ let ab =
+ 6367449.14570093 *
+ (k -
+ 0.00251882794504 * Math.sin(2 * k) +
+ 0.00000264354112 * Math.sin(4 * k) -
+ 0.00000000345262 * Math.sin(6 * k) +
+ 0.000000000004892 * Math.sin(8 * k)) +
+ (q / 2.0) * p * Math.pow(n, 2) * Math.pow(t, 2) +
+ (q / 24.0) * p * Math.pow(n, 4) * v * Math.pow(t, 4) +
+ (q / 720.0) * p * Math.pow(n, 6) * x * Math.pow(t, 6) +
+ (q / 40320.0) * p * Math.pow(n, 8) * z * Math.pow(t, 8);
+ aa = aa * 0.9996 + 500000.0;
+ ab = ab * 0.9996;
+ if (ab < 0.0) ab += 10000000.0;
+ const ad = "CDEFGHJKLMNPQRSTUVWXX".charAt(Math.floor(Lat / 8 + 10));
+ const ae = Math.floor(aa / 100000);
+ const af = ["ABCDEFGH", "JKLMNPQR", "STUVWXYZ"][(c - 1) % 3].charAt(ae - 1);
+ const ag = Math.floor(ab / 100000) % 20;
+ const ah = ["ABCDEFGHJKLMNPQRSTUV", "FGHJKLMNPQRSTUVABCDE"][
+ (c - 1) % 2
+ ].charAt(ag);
+
+ function pad(val) {
+ if (val < 10) {
+ val = "0000" + val;
+ } else if (val < 100) {
+ val = "000" + val;
+ } else if (val < 1000) {
+ val = "00" + val;
+ } else if (val < 10000) {
+ val = "0" + val;
+ }
+ return val;
+ }
+ aa = Math.floor(aa % 100000);
+ aa = pad(aa);
+ ab = Math.floor(ab % 100000);
+ ab = pad(ab);
+ return c + ad + " " + af + ah + " " + aa + " " + ab;
+ }
}
export default Convertors;
diff --git a/src/utils/constants.js b/src/utils/constants.js
index d64eaa3..cd9d5b3 100644
--- a/src/utils/constants.js
+++ b/src/utils/constants.js
@@ -25,4 +25,5 @@ export const supportedModules = [
"Mirage-F1EE",
"UH-60L",
"Hercules",
+ "OH58D",
];
diff --git a/testing/debuggingStateKiowa.json b/testing/debuggingStateKiowa.json
new file mode 100644
index 0000000..dc68098
--- /dev/null
+++ b/testing/debuggingStateKiowa.json
@@ -0,0 +1,3 @@
+{
+ "payload": "[{\"type\":\"dcsPoint/changeCoords\",\"payload\":{\"model\":\"OH58D\",\"coords\":{\"lat\":\"41.905925545347\",\"long\":\"43.783457188399\"},\"elev\":\"1677.6647949219\"}},{\"type\":\"waypoints/addDcsWaypoint\",\"payload\":{\"lat\":41.905925545347,\"long\":43.783457188399,\"elev\":1677.6647949219}},{\"type\":\"waypoints/addDcsWaypoint\",\"payload\":{\"lat\":41.905925545347,\"long\":43.783457188399,\"elev\":1677.6647949219}},{\"type\":\"waypoints/addDcsWaypoint\",\"payload\":{\"lat\":41.905925545347,\"long\":43.783457188399,\"elev\":1677.6647949219}}]"
+}