Add support for sendCOMM method
Credits go to user @angelsware, I just did a copy/paste from #120
This commit is contained in:
@@ -973,3 +973,40 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view)
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/**** End View functions ****/
|
/**** End View functions ****/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**** Comm functions ****/
|
||||||
|
/*****************************************************************************/
|
||||||
|
int sendCOMM(XPCSocket sock, const char* comm) {
|
||||||
|
// Setup command
|
||||||
|
// Max size is technically unlimited.
|
||||||
|
unsigned char buffer[65536] = "COMM";
|
||||||
|
int pos = 5;
|
||||||
|
|
||||||
|
int commLen = strnlen(comm, 256);
|
||||||
|
if (pos + commLen + 2 > 65536)
|
||||||
|
{
|
||||||
|
printError("sendCOMM", "About to overrun the send buffer!");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if (commLen > 255)
|
||||||
|
{
|
||||||
|
printError("sendCOMM", "comm is too long. Must be less than 256 characters.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Copy comm to buffer
|
||||||
|
buffer[pos++] = (unsigned char)commLen;
|
||||||
|
memcpy(buffer + pos, comm, commLen);
|
||||||
|
pos += commLen;
|
||||||
|
|
||||||
|
// Send command
|
||||||
|
if (sendUDP(sock, buffer, pos) < 0)
|
||||||
|
{
|
||||||
|
printError("setDREF", "Failed to send command");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**** End Comm functions ****/
|
||||||
|
/*****************************************************************************/
|
||||||
@@ -303,6 +303,13 @@ int sendVIEW(XPCSocket sock, VIEW_TYPE view);
|
|||||||
/// \returns 0 if successful, otherwise a negative value.
|
/// \returns 0 if successful, otherwise a negative value.
|
||||||
int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count);
|
int sendWYPT(XPCSocket sock, WYPT_OP op, float points[], int count);
|
||||||
|
|
||||||
|
/// Sends commands.
|
||||||
|
///
|
||||||
|
/// \param sock The socket to use to send the command.
|
||||||
|
/// \param comm The command string.
|
||||||
|
/// \returns 0 if successful, otherwise a negative value.
|
||||||
|
int sendCOMM(XPCSocket sock, const char* comm);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -889,6 +889,42 @@ public class XPlaneConnect implements AutoCloseable
|
|||||||
sendUDP(os.toByteArray());
|
sendUDP(os.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a command to X-Plane.
|
||||||
|
*
|
||||||
|
* @param comm The name of the X-Plane command to send.
|
||||||
|
* @throws IOException If the command cannot be sent.
|
||||||
|
*/
|
||||||
|
public void sendCOMM(String comm) throws IOException
|
||||||
|
{
|
||||||
|
//Preconditions
|
||||||
|
if(comm == null || comm.length() == 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(("comm must be non-empty."));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
os.write("COMM".getBytes(StandardCharsets.UTF_8));
|
||||||
|
os.write(0xFF); //Placeholder for message length
|
||||||
|
|
||||||
|
//Convert comm to bytes.
|
||||||
|
byte[] commBytes = comm.getBytes(StandardCharsets.UTF_8);
|
||||||
|
if (commBytes.length == 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("COMM is an empty string!");
|
||||||
|
}
|
||||||
|
if (commBytes.length > 255)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("comm must be less than 255 bytes in UTF-8. Are you sure this is a valid comm?");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Build and send message
|
||||||
|
os.write(commBytes.length);
|
||||||
|
os.write(commBytes);
|
||||||
|
sendUDP(os.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the port on which the client will receive data from X-Plane.
|
* Sets the port on which the client will receive data from X-Plane.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
|
|
||||||
class XPlaneConnect(object):
|
class XPlaneConnect(object):
|
||||||
'''XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin.'''
|
"""XPlaneConnect (XPC) facilitates communication to and from the XPCPlugin."""
|
||||||
|
|
||||||
socket = None
|
socket = None
|
||||||
|
|
||||||
# Basic Functions
|
# Basic Functions
|
||||||
def __init__(self, xpHost = 'localhost', xpPort = 49009, port = 0, timeout = 100):
|
def __init__(self, xpHost="localhost", xpPort=49009, port=0, timeout=100):
|
||||||
'''Sets up a new connection to an X-Plane Connect plugin running in X-Plane.
|
"""Sets up a new connection to an X-Plane Connect plugin running in X-Plane.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
xpHost: The hostname of the machine running X-Plane.
|
xpHost: The hostname of the machine running X-Plane.
|
||||||
xpPort: The port on which the XPC plugin is listening. Usually 49007.
|
xpPort: The port on which the XPC plugin is listening. Usually 49007.
|
||||||
port: The port which will be used to send and receive data.
|
port: The port which will be used to send and receive data.
|
||||||
timeout: The period (in milliseconds) after which read attempts will fail.
|
timeout: The period (in milliseconds) after which read attempts will fail.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
# Validate parameters
|
# Validate parameters
|
||||||
xpIP = None
|
xpIP = None
|
||||||
@@ -51,30 +53,30 @@ class XPlaneConnect(object):
|
|||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
'''Closes the specified connection and releases resources associated with it.'''
|
"""Closes the specified connection and releases resources associated with it."""
|
||||||
if self.socket is not None:
|
if self.socket is not None:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
self.socket = None
|
self.socket = None
|
||||||
|
|
||||||
def sendUDP(self, buffer):
|
def sendUDP(self, buffer):
|
||||||
'''Sends a message over the underlying UDP socket.'''
|
"""Sends a message over the underlying UDP socket."""
|
||||||
# Preconditions
|
# Preconditions
|
||||||
if(len(buffer) == 0):
|
if len(buffer) == 0:
|
||||||
raise ValueError("sendUDP: buffer is empty.")
|
raise ValueError("sendUDP: buffer is empty.")
|
||||||
|
|
||||||
self.socket.sendto(buffer, 0, self.xpDst)
|
self.socket.sendto(buffer, 0, self.xpDst)
|
||||||
|
|
||||||
def readUDP(self):
|
def readUDP(self):
|
||||||
'''Reads a message from the underlying UDP socket.'''
|
"""Reads a message from the underlying UDP socket."""
|
||||||
return self.socket.recv(16384)
|
return self.socket.recv(16384)
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
def setCONN(self, port):
|
def setCONN(self, port):
|
||||||
'''Sets the port on which the client sends and receives data.
|
"""Sets the port on which the client sends and receives data.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
port: The new port to use.
|
port: The new port to use.
|
||||||
'''
|
"""
|
||||||
# Validate parameters
|
# Validate parameters
|
||||||
if port < 0 or port > 65535:
|
if port < 0 or port > 65535:
|
||||||
raise ValueError("The specified port is not a valid port number.")
|
raise ValueError("The specified port is not a valid port number.")
|
||||||
@@ -85,8 +87,8 @@ class XPlaneConnect(object):
|
|||||||
|
|
||||||
# Rebind socket
|
# Rebind socket
|
||||||
clientAddr = ("0.0.0.0", port)
|
clientAddr = ("0.0.0.0", port)
|
||||||
timeout = self.socket.gettimeout();
|
timeout = self.socket.gettimeout()
|
||||||
self.socket.close();
|
self.socket.close()
|
||||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||||
self.socket.bind(clientAddr)
|
self.socket.bind(clientAddr)
|
||||||
self.socket.settimeout(timeout)
|
self.socket.settimeout(timeout)
|
||||||
@@ -95,13 +97,13 @@ class XPlaneConnect(object):
|
|||||||
buffer = self.socket.recv(1024)
|
buffer = self.socket.recv(1024)
|
||||||
|
|
||||||
def pauseSim(self, pause):
|
def pauseSim(self, pause):
|
||||||
'''Pauses or un-pauses the physics simulation engine in X-Plane.
|
"""Pauses or un-pauses the physics simulation engine in X-Plane.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
pause: True to pause the simulation for all a/c; False to resume for all a/c.
|
pause: True to pause the simulation for all a/c; False to resume for all a/c.
|
||||||
2 to switch the status for all a/c. 100:119 to pause a/c 0:19. 200:219 to
|
2 to switch the status for all a/c. 100:119 to pause a/c 0:19. 200:219 to
|
||||||
resume a/c 0:19
|
resume a/c 0:19
|
||||||
'''
|
"""
|
||||||
pause = int(pause)
|
pause = int(pause)
|
||||||
if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219:
|
if pause < 0 or (pause > 2 and pause < 100) or (pause > 119 and pause < 200) or pause > 219:
|
||||||
raise ValueError("Invalid argument for pause command.")
|
raise ValueError("Invalid argument for pause command.")
|
||||||
@@ -111,14 +113,14 @@ class XPlaneConnect(object):
|
|||||||
|
|
||||||
# X-Plane UDP Data
|
# X-Plane UDP Data
|
||||||
def readDATA(self):
|
def readDATA(self):
|
||||||
'''Reads X-Plane data.
|
"""Reads X-Plane data.
|
||||||
|
|
||||||
Returns: A 2 dimensional array containing 0 or more rows of data. Each array
|
Returns: A 2 dimensional array containing 0 or more rows of data. Each array
|
||||||
in the result will have 9 elements, the first of which is the row number which
|
in the result will have 9 elements, the first of which is the row number which
|
||||||
that array represents data for, and the rest of which are the data elements in
|
that array represents data for, and the rest of which are the data elements in
|
||||||
that row.
|
that row.
|
||||||
'''
|
"""
|
||||||
buffer = self.readUDP();
|
buffer = self.readUDP()
|
||||||
if len(buffer) < 6:
|
if len(buffer) < 6:
|
||||||
return None
|
return None
|
||||||
rows = (len(buffer) - 5) / 36
|
rows = (len(buffer) - 5) / 36
|
||||||
@@ -128,13 +130,13 @@ class XPlaneConnect(object):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def sendDATA(self, data):
|
def sendDATA(self, data):
|
||||||
'''Sends X-Plane data over the underlying UDP socket.
|
"""Sends X-Plane data over the underlying UDP socket.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data: An array of values representing data rows to be set. Each array in `data`
|
data: An array of values representing data rows to be set. Each array in `data`
|
||||||
should have 9 elements, the first of which is a row number in the range (0-134),
|
should have 9 elements, the first of which is a row number in the range (0-134),
|
||||||
and the rest of which are the values to set for that data row.
|
and the rest of which are the values to set for that data row.
|
||||||
'''
|
"""
|
||||||
if len(data) > 134:
|
if len(data) > 134:
|
||||||
raise ValueError("Too many rows in data.")
|
raise ValueError("Too many rows in data.")
|
||||||
|
|
||||||
@@ -147,11 +149,11 @@ class XPlaneConnect(object):
|
|||||||
|
|
||||||
# Position
|
# Position
|
||||||
def getPOSI(self, ac=0):
|
def getPOSI(self, ac=0):
|
||||||
'''Gets position information for the specified aircraft.
|
"""Gets position information for the specified aircraft.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||||
'''
|
"""
|
||||||
# Send request
|
# Send request
|
||||||
buffer = struct.pack("<4sxB", "GETP", ac)
|
buffer = struct.pack("<4sxB", "GETP", ac)
|
||||||
self.sendUDP(buffer)
|
self.sendUDP(buffer)
|
||||||
@@ -169,7 +171,7 @@ class XPlaneConnect(object):
|
|||||||
return result[2:]
|
return result[2:]
|
||||||
|
|
||||||
def sendPOSI(self, values, ac=0):
|
def sendPOSI(self, values, ac=0):
|
||||||
'''Sets position information on the specified aircraft.
|
"""Sets position information on the specified aircraft.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
values: The position values to set. `values` is a array containing up to
|
values: The position values to set. `values` is a array containing up to
|
||||||
@@ -184,7 +186,7 @@ class XPlaneConnect(object):
|
|||||||
* True Heading (deg)
|
* True Heading (deg)
|
||||||
* Gear (0=up, 1=down)
|
* Gear (0=up, 1=down)
|
||||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||||
'''
|
"""
|
||||||
# Preconditions
|
# Preconditions
|
||||||
if len(values) < 1 or len(values) > 7:
|
if len(values) < 1 or len(values) > 7:
|
||||||
raise ValueError("Must have between 0 and 7 items in values.")
|
raise ValueError("Must have between 0 and 7 items in values.")
|
||||||
@@ -205,11 +207,11 @@ class XPlaneConnect(object):
|
|||||||
|
|
||||||
# Controls
|
# Controls
|
||||||
def getCTRL(self, ac=0):
|
def getCTRL(self, ac=0):
|
||||||
'''Gets the control surface information for the specified aircraft.
|
"""Gets the control surface information for the specified aircraft.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||||
'''
|
"""
|
||||||
# Send request
|
# Send request
|
||||||
buffer = struct.pack("<4sxB", "GETC", ac)
|
buffer = struct.pack("<4sxB", "GETC", ac)
|
||||||
self.sendUDP(buffer)
|
self.sendUDP(buffer)
|
||||||
@@ -228,7 +230,7 @@ class XPlaneConnect(object):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def sendCTRL(self, values, ac=0):
|
def sendCTRL(self, values, ac=0):
|
||||||
'''Sets control surface information on the specified aircraft.
|
"""Sets control surface information on the specified aircraft.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
values: The control surface values to set. `values` is a array containing up to
|
values: The control surface values to set. `values` is a array containing up to
|
||||||
@@ -243,7 +245,7 @@ class XPlaneConnect(object):
|
|||||||
* Flaps [0, 1]
|
* Flaps [0, 1]
|
||||||
* Speedbrakes [-0.5, 1.5]
|
* Speedbrakes [-0.5, 1.5]
|
||||||
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
ac: The aircraft to set the control surfaces of. 0 is the main/player aircraft.
|
||||||
'''
|
"""
|
||||||
# Preconditions
|
# Preconditions
|
||||||
if len(values) < 1 or len(values) > 7:
|
if len(values) < 1 or len(values) > 7:
|
||||||
raise ValueError("Must have between 0 and 6 items in values.")
|
raise ValueError("Must have between 0 and 6 items in values.")
|
||||||
@@ -270,21 +272,21 @@ class XPlaneConnect(object):
|
|||||||
|
|
||||||
# DREF Manipulation
|
# DREF Manipulation
|
||||||
def sendDREF(self, dref, values):
|
def sendDREF(self, dref, values):
|
||||||
'''Sets the specified dataref to the specified value.
|
"""Sets the specified dataref to the specified value.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dref: The name of the datarefs to set.
|
dref: The name of the datarefs to set.
|
||||||
values: Either a scalar value or a sequence of values.
|
values: Either a scalar value or a sequence of values.
|
||||||
'''
|
"""
|
||||||
self.sendDREFs([dref], [values])
|
self.sendDREFs([dref], [values])
|
||||||
|
|
||||||
def sendDREFs(self, drefs, values):
|
def sendDREFs(self, drefs, values):
|
||||||
'''Sets the specified datarefs to the specified values.
|
"""Sets the specified datarefs to the specified values.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drefs: A list of names of the datarefs to set.
|
drefs: A list of names of the datarefs to set.
|
||||||
values: A list of scalar or vector values to set.
|
values: A list of scalar or vector values to set.
|
||||||
'''
|
"""
|
||||||
if len(drefs) != len(values):
|
if len(drefs) != len(values):
|
||||||
raise ValueError("drefs and values must have the same number of elements.")
|
raise ValueError("drefs and values must have the same number of elements.")
|
||||||
|
|
||||||
@@ -312,24 +314,24 @@ class XPlaneConnect(object):
|
|||||||
self.sendUDP(buffer)
|
self.sendUDP(buffer)
|
||||||
|
|
||||||
def getDREF(self, dref):
|
def getDREF(self, dref):
|
||||||
'''Gets the value of an X-Plane dataref.
|
"""Gets the value of an X-Plane dataref.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dref: The name of the dataref to get.
|
dref: The name of the dataref to get.
|
||||||
|
|
||||||
Returns: A sequence of data representing the values of the requested dataref.
|
Returns: A sequence of data representing the values of the requested dataref.
|
||||||
'''
|
"""
|
||||||
return self.getDREFs([dref])[0]
|
return self.getDREFs([dref])[0]
|
||||||
|
|
||||||
def getDREFs(self, drefs):
|
def getDREFs(self, drefs):
|
||||||
'''Gets the value of one or more X-Plane datarefs.
|
"""Gets the value of one or more X-Plane datarefs.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
drefs: The names of the datarefs to get.
|
drefs: The names of the datarefs to get.
|
||||||
|
|
||||||
Returns: A multidimensional sequence of data representing the values of the requested
|
Returns: A multidimensional sequence of data representing the values of the requested
|
||||||
datarefs.
|
datarefs.
|
||||||
'''
|
"""
|
||||||
# Send request
|
# Send request
|
||||||
buffer = struct.pack("<4sxB", "GETD", len(drefs))
|
buffer = struct.pack("<4sxB", "GETD", len(drefs))
|
||||||
for dref in drefs:
|
for dref in drefs:
|
||||||
@@ -353,7 +355,7 @@ class XPlaneConnect(object):
|
|||||||
|
|
||||||
# Drawing
|
# Drawing
|
||||||
def sendTEXT(self, msg, x=-1, y=-1):
|
def sendTEXT(self, msg, x=-1, y=-1):
|
||||||
'''Sets a message that X-Plane will display on the screen.
|
"""Sets a message that X-Plane will display on the screen.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
msg: The string to display on the screen
|
msg: The string to display on the screen
|
||||||
@@ -363,7 +365,7 @@ class XPlaneConnect(object):
|
|||||||
y: The distance in pixels from the bottom edge of the screen to display the
|
y: The distance in pixels from the bottom edge of the screen to display the
|
||||||
message. A value of -1 indicates that the default vertical position should be
|
message. A value of -1 indicates that the default vertical position should be
|
||||||
used.
|
used.
|
||||||
'''
|
"""
|
||||||
if y < -1:
|
if y < -1:
|
||||||
raise ValueError("y must be greater than or equal to -1.")
|
raise ValueError("y must be greater than or equal to -1.")
|
||||||
|
|
||||||
@@ -375,12 +377,12 @@ class XPlaneConnect(object):
|
|||||||
self.sendUDP(buffer)
|
self.sendUDP(buffer)
|
||||||
|
|
||||||
def sendVIEW(self, view):
|
def sendVIEW(self, view):
|
||||||
'''Sets the camera view in X-Plane
|
"""Sets the camera view in X-Plane
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
view: The view to use. The ViewType class provides named constants
|
view: The view to use. The ViewType class provides named constants
|
||||||
for known views.
|
for known views.
|
||||||
'''
|
"""
|
||||||
# Preconditions
|
# Preconditions
|
||||||
if view < ViewType.Forwards or view > ViewType.FullscreenNoHud:
|
if view < ViewType.Forwards or view > ViewType.FullscreenNoHud:
|
||||||
raise ValueError("Unknown view command.")
|
raise ValueError("Unknown view command.")
|
||||||
@@ -392,7 +394,7 @@ class XPlaneConnect(object):
|
|||||||
self.sendUDP(buffer)
|
self.sendUDP(buffer)
|
||||||
|
|
||||||
def sendWYPT(self, op, points):
|
def sendWYPT(self, op, points):
|
||||||
'''Adds, removes, or clears waypoints. Waypoints are three dimensional points on or
|
"""Adds, removes, or clears waypoints. Waypoints are three dimensional points on or
|
||||||
above the Earth's surface that are represented visually in the simulator. Each
|
above the Earth's surface that are represented visually in the simulator. Each
|
||||||
point consists of a latitude and longitude expressed in fractional degrees and
|
point consists of a latitude and longitude expressed in fractional degrees and
|
||||||
an altitude expressed as meters above sea level.
|
an altitude expressed as meters above sea level.
|
||||||
@@ -402,7 +404,7 @@ class XPlaneConnect(object):
|
|||||||
`2` to remove waypoints, and `3` to clear all waypoints.
|
`2` to remove waypoints, and `3` to clear all waypoints.
|
||||||
points: A sequence of floating point values representing latitude, longitude, and
|
points: A sequence of floating point values representing latitude, longitude, and
|
||||||
altitude triples. The length of this array should always be divisible by 3.
|
altitude triples. The length of this array should always be divisible by 3.
|
||||||
'''
|
"""
|
||||||
if op < 1 or op > 3:
|
if op < 1 or op > 3:
|
||||||
raise ValueError("Invalid operation specified.")
|
raise ValueError("Invalid operation specified.")
|
||||||
if len(points) % 3 != 0:
|
if len(points) % 3 != 0:
|
||||||
@@ -416,6 +418,27 @@ class XPlaneConnect(object):
|
|||||||
buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points)
|
buffer = struct.pack("<4sxBB" + str(len(points)) + "f", "WYPT", op, len(points), *points)
|
||||||
self.sendUDP(buffer)
|
self.sendUDP(buffer)
|
||||||
|
|
||||||
|
def sendCOMM(self, comm):
|
||||||
|
'''Sets the specified datarefs to the specified values.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
drefs: A list of names of the datarefs to set.
|
||||||
|
values: A list of scalar or vector values to set.
|
||||||
|
'''
|
||||||
|
if comm == None:
|
||||||
|
raise ValueError("comm must be non-empty.")
|
||||||
|
|
||||||
|
buffer = struct.pack("<4sx", "COMM")
|
||||||
|
if len(comm) == 0 or len(comm) > 255:
|
||||||
|
raise ValueError("comm must be a non-empty string less than 256 characters.")
|
||||||
|
|
||||||
|
# Pack message
|
||||||
|
fmt = "<B{0:d}s".format(len(comm))
|
||||||
|
buffer += struct.pack(fmt, len(comm), comm)
|
||||||
|
|
||||||
|
# Send
|
||||||
|
self.sendUDP(buffer)
|
||||||
|
|
||||||
class ViewType(object):
|
class ViewType(object):
|
||||||
Forwards = 73
|
Forwards = 73
|
||||||
Down = 74
|
Down = 74
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "XPLMDataAccess.h"
|
#include "XPLMDataAccess.h"
|
||||||
#include "XPLMGraphics.h"
|
#include "XPLMGraphics.h"
|
||||||
|
#include "XPLMUtilities.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@@ -791,6 +792,21 @@ namespace XPC
|
|||||||
Set(DREF_FlapActual, value);
|
Set(DREF_FlapActual, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataManager::Execute(const std::string& comm)
|
||||||
|
{
|
||||||
|
Log::FormatLine(LOG_INFO, "DMAN", "Executing command (value:%s)", comm.c_str());
|
||||||
|
|
||||||
|
XPLMCommandRef xcref = XPLMFindCommand(comm.c_str());
|
||||||
|
if (!xcref)
|
||||||
|
{
|
||||||
|
// COMM does not exist
|
||||||
|
Log::FormatLine(LOG_ERROR, "DMAN", "ERROR: invalid COMM %s", comm.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XPLMCommandOnce(xcref);
|
||||||
|
}
|
||||||
|
|
||||||
float DataManager::GetDefaultValue()
|
float DataManager::GetDefaultValue()
|
||||||
{
|
{
|
||||||
return -998.0F;
|
return -998.0F;
|
||||||
|
|||||||
@@ -410,6 +410,11 @@ namespace XPC
|
|||||||
/// \param value The flaps settings. Should be between 0.0 (no flaps) and 1.0 (full flaps).
|
/// \param value The flaps settings. Should be between 0.0 (no flaps) and 1.0 (full flaps).
|
||||||
static void SetFlaps(float value);
|
static void SetFlaps(float value);
|
||||||
|
|
||||||
|
/// Executes a command
|
||||||
|
///
|
||||||
|
/// \param comm The name of the command to execute.
|
||||||
|
static void Execute(const std::string& comm);
|
||||||
|
|
||||||
/// Gets a default value that indicates that a dataref should not be changed.
|
/// Gets a default value that indicates that a dataref should not be changed.
|
||||||
static float GetDefaultValue();
|
static float GetDefaultValue();
|
||||||
|
|
||||||
|
|||||||
@@ -176,6 +176,11 @@ namespace XPC
|
|||||||
ss << "Type:" << *((unsigned long*)(buffer + 5));
|
ss << "Type:" << *((unsigned long*)(buffer + 5));
|
||||||
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||||
}
|
}
|
||||||
|
else if (head == "COMM")
|
||||||
|
{
|
||||||
|
ss << "Type:" << *((unsigned long*)(buffer + 5));
|
||||||
|
Log::WriteLine(LOG_DEBUG, "DBUG", ss.str());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ss << " UNKNOWN HEADER ";
|
ss << " UNKNOWN HEADER ";
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ namespace XPC
|
|||||||
handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView));
|
handlers.insert(std::make_pair("VIEW", MessageHandlers::HandleView));
|
||||||
handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC));
|
handlers.insert(std::make_pair("GETC", MessageHandlers::HandleGetC));
|
||||||
handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP));
|
handlers.insert(std::make_pair("GETP", MessageHandlers::HandleGetP));
|
||||||
|
handlers.insert(std::make_pair("COMM", MessageHandlers::HandleComm));
|
||||||
handlers.insert(std::make_pair("GETT", MessageHandlers::HandleGetT));
|
handlers.insert(std::make_pair("GETT", MessageHandlers::HandleGetT));
|
||||||
// X-Plane data messages
|
// X-Plane data messages
|
||||||
handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData));
|
handlers.insert(std::make_pair("DSEL", MessageHandlers::HandleXPlaneData));
|
||||||
@@ -916,6 +917,31 @@ namespace XPC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageHandlers::HandleComm(const Message& msg)
|
||||||
|
{
|
||||||
|
Log::FormatLine(LOG_TRACE, "COMM", "Request to execute COMM command received (Conn %i)", connection.id);
|
||||||
|
const unsigned char* buffer = msg.GetBuffer();
|
||||||
|
std::size_t size = msg.GetSize();
|
||||||
|
std::size_t pos = 5;
|
||||||
|
while (pos < size)
|
||||||
|
{
|
||||||
|
unsigned char len = buffer[pos++];
|
||||||
|
if (pos + len > size)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::string comm = std::string((char*)buffer + pos, len);
|
||||||
|
pos += len;
|
||||||
|
|
||||||
|
DataManager::Execute(comm);
|
||||||
|
Log::FormatLine(LOG_DEBUG, "COMM", "Execute command %s", comm.c_str());
|
||||||
|
}
|
||||||
|
if (pos != size)
|
||||||
|
{
|
||||||
|
Log::WriteLine(LOG_ERROR, "COMM", "ERROR: Command did not terminate at the expected position.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageHandlers::HandleWypt(const Message& msg)
|
void MessageHandlers::HandleWypt(const Message& msg)
|
||||||
{
|
{
|
||||||
// Update Log
|
// Update Log
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ namespace XPC
|
|||||||
static void HandleText(const Message& msg);
|
static void HandleText(const Message& msg);
|
||||||
static void HandleWypt(const Message& msg);
|
static void HandleWypt(const Message& msg);
|
||||||
static void HandleView(const Message& msg);
|
static void HandleView(const Message& msg);
|
||||||
|
static void HandleComm(const Message& msg);
|
||||||
|
|
||||||
static void HandleXPlaneData(const Message& msg);
|
static void HandleXPlaneData(const Message& msg);
|
||||||
static void HandleUnknown(const Message& msg);
|
static void HandleUnknown(const Message& msg);
|
||||||
|
|||||||
@@ -221,6 +221,7 @@
|
|||||||
"APL=1",
|
"APL=1",
|
||||||
"IBM=0",
|
"IBM=0",
|
||||||
"LIN=0",
|
"LIN=0",
|
||||||
|
XPLM200,
|
||||||
);
|
);
|
||||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
||||||
GCC_VERSION = "";
|
GCC_VERSION = "";
|
||||||
@@ -274,6 +275,7 @@
|
|||||||
"APL=1",
|
"APL=1",
|
||||||
"IBM=0",
|
"IBM=0",
|
||||||
"LIN=0",
|
"LIN=0",
|
||||||
|
XPLM200,
|
||||||
);
|
);
|
||||||
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
|
||||||
GCC_VERSION = "";
|
GCC_VERSION = "";
|
||||||
|
|||||||
Reference in New Issue
Block a user