public delegate void LineReceivedEvent(string sentence);
//serial port receive in its own thread
private void sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (sp.IsOpen)
{
string sentence = sp.ReadLine();
this.BeginInvoke(new LineReceivedEvent(LineReceived), sentence);
}
}
private void LineReceived(string sentence)
{
textBoxRcv.AppendText(sentence);
textBoxRcv.AppendText("\n");
}
I have this SerialPort code that works perfectly in a Windows.Form but not in XNA. I am reading gps data from a serial port, a single sentence, then want to use that data in the XNA game to plot a 3D path.
The error is BeginInvoke does not exist in the current context. I can of course get around this by using a ReadExisting in the update part of XNA without events or threaded but would really prefer the serial reading done in its own thread.
I made sure all references and "using's" were the same as the Windows.Form application.
I am using a Forms.Panel in the XNA window for buttons and the textbox. Everything works fine as long as i don't use BeginInvoke and the Serial Data Event.
Any suggestions?
Here is the code in its entirety:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using ButtonState = Microsoft.Xna.Framework.Input.ButtonState;
using Point = System.Drawing.Point;
using System.IO.Ports;
//using System.Threading;
namespace gpsPlot
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class GPSMain : Microsoft.Xna.Framework.Game
{
//Global Properties
GraphicsDeviceManager graphics;
Viewport vp;
SpriteBatch spriteBatch;
private Texture2D img;
//panel objects and controls
Panel pnl;
Button btnExit;
Button btnOpenSerial;
Button btnCloseSerial;
ComboBox cboxPort;
ComboBox cboxBaud;
TextBox textBoxRcv;
//serial related
static string portName = "COM7";
static int baudRate = 4800;
SerialPort sp = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
public delegate void LineReceivedEvent(string sentence);
//serial port receive in its own thread
private void sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (sp.IsOpen)
{
try
{
string sentence = sp.ReadLine();
this.BeginInvoke(new LineReceivedEvent(LineReceived), sentence);
}
//this is bad programming, it just ignores errors until its hooked up again.
catch (Exception) { }
}
}
private void btnOpenSerial_Click(object sender, EventArgs e)
{
if (!sp.IsOpen)
{
sp.PortName = portName;
sp.BaudRate = baudRate;
sp.DataReceived += sp_DataReceived;
}
try { sp.Open(); }
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Not Connected to GPS");
}
if (sp.IsOpen)
{
//sp.ReadTimeout = 200;
btnOpenSerial.Enabled = true;
btnCloseSerial.Enabled = true;
//update port status labels
//this.labelPortStatus.Text = "Open";
//this.labelPortName.Text = portName;
//this.labelBaudRate.Text = Convert.ToString(baudRate);
//discard any stuff in the buffers
sp.DiscardOutBuffer();
sp.DiscardInBuffer();
if (!sp.IsOpen) return;
}
}
private void btnCloseSerial_Click(object sender, EventArgs e)
{
try { sp.Close(); }
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Connection already terminated. Unplugged or shut off?");
}
btnOpenSerial.Enabled = true;
btnCloseSerial.Enabled = false;
//this.labelPortStatus.Text = "Closed";
//this.labelPortName.Text = "-";
//this.labelBaudRate.Text = "-";
//Application.Exit();
}
private void LineReceived(string sentence)
{
//no matter what the line is, display it
textBoxRcv.AppendText(sentence);
textBoxRcv.AppendText("\n");
}
private void cboxPort_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void cboxBaud_SelectedIndexChanged(object sender, EventArgs e)
{
}
public GPSMain()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1400;
graphics.PreferredBackBufferHeight = 768;
Content.RootDirectory = "Content";
// allow the mouse to remain visible and allow user resizing ofthe window
this.IsMouseVisible = true;
this.Window.AllowUserResizing = true;
// create and setup the winform controls on the game window
this.CreateControls();
// hook into the client size change event so we can update the win form
// controls and update the viewport on the graphics device
this.Window.ClientSizeChanged += this.Window_ClientSizeChanged;
//add available ports in port name combobox
foreach (String s in System.IO.Ports.SerialPort.GetPortNames())
{
cboxPort.Items.Add(s);
}
}
private void CreateControls()
{
// get game window as a win form Form class
Form frm = Control.FromHandle(this.Window.Handle) as Form;
// setup the panel control---------------------------------
this.pnl = new Panel();
this.pnl.Dock = DockStyle.Right;
this.pnl.Width = 250;
//Exit button-----------------------------------------------
this.btnExit = new Button();
this.btnExit.Location = new System.Drawing.Point(12, 12);
this.btnExit.Name = "btnExit";
this.btnExit.Size = new System.Drawing.Size(75, 23);
this.btnExit.TabIndex = 0;
this.btnExit.Text = "Exit";
this.btnExit.UseVisualStyleBackColor = true;
this.btnExit.Click += new System.EventHandler(this.btnExit_Click);
this.pnl.Controls.Add(btnExit);// add the button to the panel
//Open Serial button----------------------------------------
this.btnOpenSerial = new Button();
this.btnOpenSerial.Location = new System.Drawing.Point(122, 146);
this.btnOpenSerial.Name = "btnOpenSerial";
this.btnOpenSerial.Size = new System.Drawing.Size(75, 23);
this.btnOpenSerial.TabIndex = 0;
this.btnOpenSerial.Text = "Open Port";
this.btnOpenSerial.UseVisualStyleBackColor = true;
this.btnOpenSerial.Click += new System.EventHandler(this.btnOpenSerial_Click);
this.pnl.Controls.Add(btnOpenSerial);
//
// btnCloseSerial--------------------------------------------------
//
this.btnCloseSerial = new Button();
this.btnCloseSerial.Location = new System.Drawing.Point(122, 185);
this.btnCloseSerial.Name = "btnCloseSerial";
this.btnCloseSerial.Size = new System.Drawing.Size(75, 23);
this.btnCloseSerial.TabIndex = 1;
this.btnCloseSerial.Text = "Close Serial";
this.btnCloseSerial.UseVisualStyleBackColor = true;
this.btnCloseSerial.Click += new System.EventHandler(this.btnCloseSerial_Click);
this.pnl.Controls.Add(btnCloseSerial);
// cboxPort---------------------------------------------------------
//
this.cboxPort = new ComboBox();
this.cboxPort.FormattingEnabled = true;
this.cboxPort.Location = new System.Drawing.Point(16, 146);
this.cboxPort.Name = "cboxPort";
this.cboxPort.Size = new System.Drawing.Size(71, 21);
this.cboxPort.TabIndex = 3;
this.cboxPort.Text = "Port";
this.cboxPort.SelectedIndexChanged += new System.EventHandler(this.cboxPort_SelectedIndexChanged);
this.pnl.Controls.Add(cboxPort);
//
// cboxBaud------------------------------------------------------------
//
this.cboxBaud = new ComboBox();
this.cboxBaud.FormattingEnabled = true;
this.cboxBaud.Items.AddRange(new object[] {
"4800",
"9600",
"19200",
"38400",
"57600",
"115200"});
this.cboxBaud.Location = new System.Drawing.Point(17, 185);
this.cboxBaud.Name = "cboxBaud";
this.cboxBaud.Size = new System.Drawing.Size(70, 21);
this.cboxBaud.TabIndex = 4;
this.cboxBaud.Text = "Baud";
this.pnl.Controls.Add(cboxBaud);
this.cboxBaud.SelectedIndexChanged += new System.EventHandler(this.cboxBaud_SelectedIndexChanged);
// textBoxRcv---------------------------------------------------------------
//
this.textBoxRcv = new TextBox();
this.textBoxRcv.BackColor = System.Drawing.SystemColors.ButtonHighlight;
this.textBoxRcv.Location = new System.Drawing.Point(3, 43);
this.textBoxRcv.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
this.textBoxRcv.Multiline = true;
this.textBoxRcv.Name = "textBoxRcv";
this.textBoxRcv.ReadOnly = true;
this.textBoxRcv.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.textBoxRcv.Size = new System.Drawing.Size(230, 95);
this.textBoxRcv.TabIndex = 17;
this.pnl.Controls.Add(textBoxRcv);
//add the panel to the game window form
frm.Controls.Add(this.pnl);
}
//Event Handlers
private void btnExit_Click(object sender, EventArgs e)
{
this.Exit();
}
void Window_ClientSizeChanged(object sender, EventArgs e)
{
// get the viewport from the graphics device
vp = this.GraphicsDevice.Viewport;
// change the viewport dimensions so that it is not drawn under any of our winform controls
vp.Width = this.Window.ClientBounds.Width - pnl.Width;
vp.Height = this.Window.ClientBounds.Height;
// set the viewport back onto the graphics device
this.GraphicsDevice.Viewport = vp;
// update the label to display the rectangle info
Rectangle rect = new Rectangle(vp.X, vp.Y, vp.Width, vp.Height);
//lbl.Text = "Client: " + this.Window.ClientBounds.ToString() + "\r\n" +
// "Viewport: " + rect.ToString();
this.Window.Title = "GPS Plotter";
}
protected override void Initialize()
{
this.Window_ClientSizeChanged(this, EventArgs.Empty);
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// load a sample image that will be drawn the size of the viewport
this.img = this.Content.Load<Texture2D>("Map2");
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// draw the image the same size of the viewport
this.spriteBatch.Begin();
//var vp = this.GraphicsDevice.Viewport;
Rectangle rect = new Rectangle(vp.X, vp.Y, vp.Width, vp.Height);
Rectangle srcrect = new Rectangle(0, 0, this.img.Width, this.img.Height);
this.spriteBatch.Draw(this.img, rect, srcrect, Color.White);
this.spriteBatch.End();
base.Draw(gameTime);
}
}
}