Merge pull request #46 from jason-watkins/feature/print-to-screen

Add the ability to print messages on screen
This commit is contained in:
Christopher Teubert
2015-04-08 09:26:50 -07:00
19 changed files with 316 additions and 12 deletions

View File

@@ -155,6 +155,13 @@ BASIC FUNCTIONS
char DREFArray[][100] = {"sim/cockpit/switches/gear_handle_status"};
requestDREF(theSocket, IP, 49009, DREFArray, strlen(DREFArray[0]),1);
10. sendTEXT write some text to the screen.
INPUT:
outSocket (xpcSocket): Socket to use to send the command
message (char*): The string to be wrote to the screen
x (int): The x position where the text will be written. Set to -1 to use default position.
y (int): The y position where the text will be written. Set to -1 to use default position.
-----------------------------------
ADVANCED FUNCTIONS (These are mostly used by the xpcPlugin to read requests)
1. sendUDP
@@ -179,9 +186,6 @@ PLANNED FUNCTIONS
5. parseWYPT
6. readWYPT
7. selectDATA
8. sendTEXT
9. readTEXT
10. parseTEXT
-----------------------------------
CONTACT

View File

@@ -419,6 +419,21 @@ short sendpCTRL(struct xpcSocket recfd, short numArgs, float valueArray[], char
return 0;
}
short sendTEXT(struct xpcSocket sendfd, char* msg, int x, int y)
{
char buf[269] = { 0 };
size_t msgLen = strnlen(msg, 255);
size_t len = 14 + msgLen;
strcpy(buf, "TEXT");
memcpy(buf + 5, &x, sizeof(int));
memcpy(buf + 9, &y, sizeof(int));
buf[13] = msgLen;
strncpy(buf + 14, msg, msgLen);
sendUDP(sendfd, buf, len);
return 0;
}
//READ
//----------------------------------------
short readUDP(struct xpcSocket recfd, char *dataRef, struct sockaddr *recvaddr)

View File

@@ -81,7 +81,11 @@
short requestDREF(struct xpcSocket sendfd, struct xpcSocket recfd, char DREFArray[][100], short DREFSizes[], short listLength, float *resultArray[], short arraySizes[]);
int parseGETD(const char my_message[], char *DREFArray[], int DREFSizes[]);
short parseRequest(const char my_message[], float *resultArray[], short arraySizes[]);
short readRequest(struct xpcSocket recfd, float *dataRef[], short arraySizes[], struct sockaddr *recvaddr);
short readRequest(struct xpcSocket recfd, float *dataRef[], short arraySizes[], struct sockaddr *recvaddr);
// Screen Text
short sendTEXT(struct xpcSocket sendfd, char* msg, int x, int y);
#endif //ifdef _h

View File

@@ -457,7 +457,7 @@ public class XPlaneConnect implements AutoCloseable
cur += 4;
}
}
bb.put(cur, (byte)aircraft);
bb.put(cur, (byte) aircraft);
//Build and send message
ByteArrayOutputStream os = new ByteArrayOutputStream();
@@ -586,6 +586,55 @@ public class XPlaneConnect implements AutoCloseable
sendUDP(os.toByteArray());
}
/**
* Sets a message to be displayed on the screen in X-Plane at the default screen location.
*
* @param msg The message to display. Should not contain any newline characters.
* @throws IOException If the command cannot be sent.
*/
public void sendTEXT(String msg) throws IOException
{
sendTEXT(msg, -1, -1);
}
/**
* Sets a message to be displayed on the screen in X-Plane at the specified coordinates.
*
* @param msg The message to display. Should not contain any newline characters.
* @param x The number of pixels from the right edge of the screen to display the text.
* @param y The number of pixels from the bottom edge of the screen to display the text.
* @throws IOException If the command cannot be sent.
*/
public void sendTEXT(String msg, int x, int y) throws IOException
{
//Preconditions
if(msg == null)
{
msg = "";
}
//Convert drefs to bytes.
byte[] msgBytes = msg.getBytes(StandardCharsets.UTF_8);
if(msgBytes.length > 255)
{
throw new IllegalArgumentException("msg must be less than 255 bytes in UTF-8.");
}
ByteBuffer bb = ByteBuffer.allocate(8);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.putInt(0, x);
bb.putInt(4, y);
//Build and send message
ByteArrayOutputStream os = new ByteArrayOutputStream();
os.write("TEXT".getBytes(StandardCharsets.UTF_8));
os.write(0xFF); //Placeholder for message length
os.write(bb.array());
os.write(msgBytes.length);
os.write(msgBytes);
sendUDP(os.toByteArray());
}
/**
* Sets the port on which the client will receive data from X-Plane.
*

View File

@@ -0,0 +1,47 @@
function [ status ] = sendTEXT( msg, varargin )
% sendTEXT Sends a string to be displayed in X-Plane.
%
% Inputs
% msg: The string to be displayed
% x (optional): The distance from the left edge of the screen to display the message.
% y (optional): The distance from the bottom edge of the screen to display the message.
% IP Address (optional): IP Address of the machine that will receive the data as a character array. Default is '127.0.0.1' (local machine)
% port (optional): Port on the receiving machine where the data will be sent. Default is 49009 (XPlaneConnect). In general use 49009 to send to the plugin and 49005 to send to the x-plane udp
%
% Outputs
% status: 0 if successful, otherwise a negative value.
%
% Use
% 1. import XPlaneConnect.*;
% 2. #Set a message to be displayed near the top middle of the screen.
% 3. status = sendTEXT('Some text', 512, 600);
%
% Contributors
% Jason Watkins
% jason.w.watkins@nasa.gov
%
% To Do
%
% BEGIN CODE
import XPlaneConnect.*
%% Handle Input
p = inputParser;
addRequired(p,'msg');
addOptional(p,'x',-1,@isnumeric);
addOptional(p,'y',-1,@isnumeric);
addOptional(p,'IP','127.0.0.1',@ischar);
addOptional(p,'port',49009,@isnumeric);
parse(p,msg,varargin{:});
%% Body
header = ['TEXT'-0,0];
dataStream = [header,...
typecast(uint32(p.Results.x), 'uint8'),...
typecast(uint32(p.Results.y), 'uint8'),...
uint8(length(msg)), msg-0];
% Send TEXT
status = sendUDP(dataStream, p.Results.IP, p.Results.port);
end

View File

@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include "xplaneconnect.h"
@@ -84,6 +85,25 @@ short sendReadTest() // send/read Test
return 0;
}
short sendTEXTTest()
{
printf("sendTEXT - ");
// Setup
struct xpcSocket sendPort = openUDP(49064, "127.0.0.1", 49009);
int x = 100;
int y = 700;
char* msg = "XPlaneConnect test message. Now with 100% fewer new lines!";
// Test
sendTEXT(sendPort, msg, x, y);
// NOTE: Manually verify that msg appears on the screen in X-Plane!
// Cleanup
closeUDP(sendPort);
return 0;
}
short requestDREFTest() // Request DREF Test (Required for next tests)
{
printf("requestDREF - ");
@@ -542,15 +562,16 @@ int main(int argc, const char * argv[])
runTest(openTest);
runTest(closeTest);
runTest(sendReadTest);
runTest(sendReadTest);
runTest(sendTEXTTest);
runTest(requestDREFTest);
runTest(sendDREFTest);
runTest(sendDATATest);
runTest(sendCTRLTest);
runTest(sendpCTRLTest);
runTest(sendPOSITest);
runTest(pauseTest);
runTest(connTest);
runTest(pauseTest);
runTest(connTest);
printf( "----------------\nTest Summary\n\tFailed: %i\n\tPassed: %i\n", testFailed, testPassed );

View File

@@ -217,6 +217,36 @@ public class XPlaneConnectTest
}
}
@Test
public void testSendTEXT() throws IOException
{
String msg = "XPlaneConnect Java message test.";
try(XPlaneConnect xpc = new XPlaneConnect())
{
xpc.sendTEXT(msg, 200, 400);
}
}
@Test
public void testSendTEXT_Multiline() throws IOException
{
String msg = "XPlaneConnect Java message test.\nNow with new lines!\rAnd another...\r\nAnd now a double.";
try(XPlaneConnect xpc = new XPlaneConnect())
{
xpc.sendTEXT(msg, 200, 400);
}
}
@Test
public void testSendTEXT_Long() throws IOException
{
String msg = "XPlaneConnect Java message test.\nNow with new lines!\rAnd another...\r\nAnd now a double\nAnd finally a really long line because that seemed to break things.";
try(XPlaneConnect xpc = new XPlaneConnect())
{
xpc.sendTEXT(msg, 200, 400);
}
}
@Test
public void testSendDREF() throws IOException
{

View File

@@ -0,0 +1,11 @@
function sendTEXTTest()
%% Setup
addpath('../../MATLAB')
import XPlaneConnect.*
%% Test
sendTEXT('sendTEXT test message M', 200, 400);
end

View File

@@ -12,6 +12,7 @@ disp(['XPC Tests-MATLAB (', os, ')']);
theTests = {{@openCloseTest, 'Open/Close Test', 0},...
{@sendReadTest,'Send/Read Test', 0},...
{@sendTEXTTest,'TEXT Test', 0},...
{@requestDREFTest,'Request DREF Test', 0},...
{@sendDREFTest,'Send DREF Test', 0},...
{@DATATest,'DATA Test', 0},...

View File

@@ -68,6 +68,7 @@
//#include "XPLMPlanes.h"
#include "XPLMProcessing.h"
#include "XPLMGraphics.h"
#include "xpcDrawing.h"
#include "xpcPluginTools.h"
#ifdef _WIN32 /* WIN32 SYSTEM */
@@ -124,6 +125,7 @@ int handleGETD(char *buf);
int handleDREF(char *buf);
int handleVIEW();
int handleDATA(char *buf, int buflen);
int handleTEXT(char *buf, int len);
short handleInput(struct XPCMessage * theMessage);
char setPOSI(short aircraft, float pos[3]);
@@ -189,6 +191,8 @@ PLUGIN_API void XPluginDisable(void)
closeUDP(recSocket);
closeUDP(sendSocket);
updateLog(logmsg,strlen(logmsg));
XPCClearMessage();
}
PLUGIN_API int XPluginEnable(void)
@@ -369,6 +373,10 @@ short handleInput(struct XPCMessage * theMessage)
{
handleDATA(theMessage->msg, theMessage->msglen);
}
else if (strncmp(theMessage->head, "TEXT", 4) == 0) // Header = TEXT (Screen message)
{
handleTEXT(theMessage->msg, theMessage->msglen);
}
else if ((strncmp(theMessage->head,"DSEL",4)==0) || (strncmp(theMessage->head,"USEL",4)==0)) // Header = DSEL/USEL (Select UDP Send)
{
sendBUF(theMessage->msg,theMessage->msglen); // Send to UDP
@@ -409,13 +417,13 @@ short handleInput(struct XPCMessage * theMessage)
{
sendBUF(theMessage->msg,theMessage->msglen); // Send to UDP
}
else if (strncmp(theMessage->head,"BOAT",4)==0)
else if (strncmp(theMessage->head, "BOAT", 4) == 0)
{
sendBUF(theMessage->msg,theMessage->msglen); // Send to UDP
sendBUF(theMessage->msg, theMessage->msglen); // Send to UDP
}
else
{ //unrecognized header
sprintf(logmsg,"[EXEC] ERROR: Command %s not recognised",theMessage->head);
sprintf(logmsg,"[EXEC] ERROR: Command %s not recognized",theMessage->head);
updateLog(logmsg, strlen(logmsg));
}
current_connection = -1;
@@ -491,6 +499,31 @@ int handleSIMU(char buf[])
return 0;
}
int handleTEXT(char *buf, int len)
{
char msg[256] = { 0 };
if (len < 14)
{
updateLog("[TEXT] ERROR: Length less than 14 bytes", 39);
return -1;
}
size_t msgLen = (unsigned char)buf[13];
if (msgLen == 0)
{
XPCClearMessage();
updateLog("[TEXT] Text cleared", 19);
}
else
{
int x = *((int*)(buf + 5));
int y = *((int*)(buf + 9));
strncpy(msg, buf + 14, msgLen);
XPCSetMessage(x, y, msg);
updateLog("[TEXT] Text set", 15);
}
return 0;
}
char setDREF(XPLMDataRef theDREF, float floatarray[], short arrayStart, short arraySize)
{
XPLMDataTypeID dataType;

Binary file not shown.

Binary file not shown.

Binary file not shown.

67
xpcPlugin/xpcDrawing.cpp Normal file
View File

@@ -0,0 +1,67 @@
#include "xpcDrawing.h"
#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include <stdlib.h>
#include <string.h>
//Internal Memory
static bool msgEnabled = false;
static int msgX = -1;
static int msgY = -1;
static char msgVal[256] = { 0 };
static size_t newLineCount = 0;
static size_t newLines[64] = { 0 };
static float rgb[3] = { 0.25F, 1.0F, 0.25F };
//Internal Functions
static int MessageDrawCallback(XPLMDrawingPhase inPhase, int inIsBefore, void * inRefcon)
{
XPLMDrawString(rgb, msgX, msgY, msgVal, NULL, xplmFont_Basic);
int y = msgY - 16;
for (size_t i = 0; i < newLineCount; ++i)
{
XPLMDrawString(rgb, msgX, y, msgVal + newLines[i], NULL, xplmFont_Basic);
y -= 16;
}
return 1;
}
//Public Functions
void XPCClearMessage()
{
XPLMUnregisterDrawCallback(MessageDrawCallback, xplm_Phase_Window, 0, NULL);
msgEnabled = false;
}
void XPCSetMessage(int x, int y, char* msg)
{
//Determine size of message and clear instead if the message string
//is empty.
size_t len = strnlen(msg, 255);
if (len == 0)
{
XPCClearMessage();
return;
}
//Set the message, location, and mark new lines.
strncpy(msgVal, msg, len);
newLineCount = 0;
for (size_t i = 0; i < len && newLineCount < 64; ++i)
{
if (msgVal[i] == '\n' || msgVal[i] == '\r')
{
msgVal[i] = 0;
newLines[newLineCount++] = i + 1;
}
}
msgX = x < 0 ? 10 : x;
msgY = y < 0 ? 600 : y;
//Enable drawing if necessary
if (!msgEnabled)
{
XPLMRegisterDrawCallback(MessageDrawCallback, xplm_Phase_LastCockpit, 0, NULL);
msgEnabled = true;
}
}

8
xpcPlugin/xpcDrawing.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef xpcDrawing_h
#define xpcDrawing_h
void XPCClearMessage();
void XPCSetMessage(int x, int y, char* msg);
#endif

View File

@@ -11,6 +11,7 @@
BE5F2FF118FCA1D500AFCD17 /* xpcPluginTools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5F2FF018FCA1D500AFCD17 /* xpcPluginTools.cpp */; };
BE8361EF18C5591C00E9C923 /* mac.xpl in CopyFiles */ = {isa = PBXBuildFile; fileRef = D607B19909A556E400699BC3 /* mac.xpl */; };
BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */ = {isa = PBXBuildFile; fileRef = BEDC620218EDF1A7005DB364 /* xplaneConnect.c */; };
BEFBC0CB1AD4A0290025705B /* xpcDrawing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEFBC0C91AD4A0290025705B /* xpcDrawing.cpp */; };
D6A7BDAA16A1DEA200D1426A /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A7BDA916A1DEA200D1426A /* OpenGL.framework */; };
D6A7BDC116A1DEC000D1426A /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A7BDC016A1DEC000D1426A /* CoreFoundation.framework */; };
D6A7BDF116A1DED200D1426A /* XPLM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6A7BDF016A1DED200D1426A /* XPLM.framework */; };
@@ -37,6 +38,8 @@
BE5F2FF018FCA1D500AFCD17 /* xpcPluginTools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xpcPluginTools.cpp; sourceTree = "<group>"; };
BEDC620218EDF1A7005DB364 /* xplaneConnect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xplaneConnect.c; path = ../C/src/xplaneConnect.c; sourceTree = "<group>"; };
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xplaneConnect.h; path = ../C/src/xplaneConnect.h; sourceTree = "<group>"; };
BEFBC0C91AD4A0290025705B /* xpcDrawing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xpcDrawing.cpp; sourceTree = "<group>"; };
BEFBC0CA1AD4A0290025705B /* xpcDrawing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xpcDrawing.h; sourceTree = "<group>"; };
D607B19909A556E400699BC3 /* mac.xpl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = mac.xpl; sourceTree = BUILT_PRODUCTS_DIR; };
D6A7BDA916A1DEA200D1426A /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
D6A7BDC016A1DEC000D1426A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
@@ -67,6 +70,8 @@
BEDC620318EDF1A7005DB364 /* xplaneConnect.h */,
BE5F2FF018FCA1D500AFCD17 /* xpcPluginTools.cpp */,
BE5F2FEF18FCA13700AFCD17 /* xpcPluginTools.h */,
BEFBC0C91AD4A0290025705B /* xpcDrawing.cpp */,
BEFBC0CA1AD4A0290025705B /* xpcDrawing.h */,
);
name = "C Source";
sourceTree = "<group>";
@@ -155,6 +160,7 @@
files = (
BEDC620418EDF1A7005DB364 /* xplaneConnect.c in Sources */,
BE37D960187C8B0F0033B082 /* XPCPlugin.cpp in Sources */,
BEFBC0CB1AD4A0290025705B /* xpcDrawing.cpp in Sources */,
BE5F2FF118FCA1D500AFCD17 /* xpcPluginTools.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@@ -97,10 +97,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\C\src\xplaneConnect.h" />
<ClInclude Include="..\xpcDrawing.h" />
<ClInclude Include="..\xpcPluginTools.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\C\src\xplaneConnect.c" />
<ClCompile Include="..\xpcDrawing.cpp" />
<ClCompile Include="..\XPCPlugin.cpp" />
<ClCompile Include="..\xpcPluginTools.cpp" />
</ItemGroup>

View File

@@ -21,6 +21,9 @@
<ClInclude Include="..\xpcPluginTools.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\xpcDrawing.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\C\src\xplaneConnect.c">
@@ -32,6 +35,9 @@
<ClCompile Include="..\xpcPluginTools.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\xpcDrawing.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Library Include="..\SDK\Libraries\Win\XPLM.lib">

View File

@@ -380,7 +380,7 @@ int printBufferToLog(struct XPCMessage & msg)
{// Header = CTRL (Control)
xpcCtrl ctrl = parseCTRL(msg.msg);
sprintf(logmsg,"%s (%f %f %f) %f %hi %f",logmsg, ctrl.pitch, ctrl.roll, ctrl.yaw, ctrl.throttle, ctrl.gear, ctrl.flaps);
sprintf(logmsg,"%s (%f %f %f) %f %hhi %f",logmsg, ctrl.pitch, ctrl.roll, ctrl.yaw, ctrl.throttle, ctrl.gear, ctrl.flaps);
updateLog(logmsg,strlen(logmsg));