I am trying to Open a SerialPort in unity. It is working in editor and mono build. But when I build the game with iL2CPP scripting backend. It is throwing an exception with message The port \\.\COM3 does not exist.
Is this something related to Unity IL2CPP build?
Unity player settings:
Scripting Runtime Version: .Net 4.x Equivalent
API compatibility Level: .NET 4.x
public void OpenSerialPort()
{
try
{
string ComPort = #"\\.\COM3"; //I even tried "COM3"
int BaudRate = 9600;
// Initialise the serial port
SerialPort = new SerialPort(ComPort, BaudRate);
SerialPort.ReadTimeout = ReadTimeout;
SerialPort.WriteTimeout = WriteTimeout;
SerialPort.DtrEnable = true;
SerialPort.RtsEnable = true;
// Open the serial port
SerialPort.Open();
Debug.LogError("SerialPort successfully opened!");
}
catch (UnauthorizedAccessException ex)
{
// Failed to open com port or start serial thread
Debug.LogError("UnauthorizedAccessException: " + ex.Message.ToString());
}
catch (ArgumentOutOfRangeException ex)
{
// Failed to open com port or start serial thread
Debug.LogError("ArgumentOutOfRangeException: " + ex.Message.ToString());
}
catch (ArgumentException ex)
{
// Failed to open com port or start serial thread
Debug.LogError("ArgumentException : " + ex.Message.ToString());
}
catch (InvalidOperationException ex)
{
// Failed to open com port or start serial thread
Debug.LogError("ArgumentException : " + ex.Message.ToString());
}
catch (IOException ex)
{
// Failed to open com port or start serial thread
Debug.LogError("IOException : " + ex.Message.ToString());
}
}
Related
I'm studying network and Windows forms with C# these days.
I'm trying to build an async-socket network system, everything's working well.
codes for Connect and Connect Callback are below.
private void ClientConnect()
{
CheckForIllegalCrossThreadCalls = false;
try
{
socket.BeginConnect(endPoint, new AsyncCallback(ConnectCallback), socket);
connectDone.WaitOne();
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
Send(socket, textBox3.Text, 0);
connectDone.Set();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
But in disconnecting socket, there's a problem.
I make a button to disconnect socket, and codes for button-clicked event are below.
private void btnDisconnect_Click(object sender, EventArgs e)
{
try
{
socket.Shutdown(SocketShutdown.Both);
Application.DoEvents();
socket.Disconnect(true); //-> problem occurs.
}
catch
{
MessageBox.Show("Disconnect Error!");
}
if (socket.Connected)
MessageBox.Show("Disconnect Error!");
else
textBox1.AppendText("Disconnected! (" + DateTime.Now.ToString("h:mm:ss tt") + ")\n");
}
When I disconnect the socket, 2 minutes of waiting time occurs.
after 2 minute(I checked this with time-stamp), It shows 'Disconnected' message.
And I can re-connect with this socket.
I think it is not just waiting like sleep, something's processed in background.
(Because mouse cursor's changed and program's blocked)
I'm so wondering why this delay(?) happens.
Please let me know.
I've written this program to automatically gather the IP Addresses that allow me to connect to port 8888.
It works fine until the final loop. Whereby my for loop finishes. But my timer keeps going and outputting:
10.10.10.150 - No
10.10.10.150 - No
10.10.10.150 - No
10.10.10.150 - No
This is my code, after the for loop I try stop the timer, but it doesn't stop.
protected void PingPython(){
for (int i = 50; i <= 150; i++){
// Try Connect to Python
try{
ip = "10.10.10."+i.ToString();
// Set timer to break Client connection
tConnectTimeout = new System.Timers.Timer(100);
tConnectTimeout.Elapsed += new System.Timers.ElapsedEventHandler(tConnectTimeout_Elapsed);
tConnectTimeout.Start();
// Connect to Client
cli = new TcpClient();
cli.Connect(ip, 8888);
// If it connects, stop the thread
tConnectTimeout.Stop();
tConnectTimeout.Dispose();
Console.WriteLine(ip + " - Yes");
ipAddresses.Add(ip);
cli.Close();
} catch (ObjectDisposedException ex) {
} catch (SocketException ex) {
tConnectTimeout.Stop();
tConnectTimeout.Dispose();
Console.WriteLine(ip + " - No");
}
}
tConnectTimeout.Stop();
btnStart.Sensitive = true;
foreach(string ipa in ipAddresses){
cbAddresses.AppendText(ipa);
}
cbAddresses.Sensitive = true;
}
public void tConnectTimeout_Elapsed(object sender, System.Timers.ElapsedEventArgs e){
//Close the socket
cli.Close();
Console.WriteLine(ip + " - No");
//Stop and dispose timer
tConnectTimeout.Stop();
tConnectTimeout.Dispose();
}
try using a using statement to create the timer (and dispose of it no matter the excetion)
using (var timer = new system.timer)
{
}
instead of using an exception handler to do it.
Also why the empty exception handler around a huge scope? that is bad you want that removed or scoped to minimum possible..
what is happening is that something is going bang causing your for loop to exit in effect before the timer can be stopped so it keeps firing the event.
in response to jon edgerton the solution shuold be
protected void PingPython(){
for (int i = 50; i <= 150; i++){
// Try Connect to Python
try{
ip = "10.10.10."+i.ToString();
// Set timer to break Client connection
tConnectTimeout = new System.Timers.Timer(100);
tConnectTimeout.Elapsed += new System.Timers.ElapsedEventHandler(tConnectTimeout_Elapsed);
tConnectTimeout.Start();
// Connect to Client
cli = new TcpClient();
cli.Connect(ip, 8888);
Console.WriteLine(ip + " - Yes");
ipAddresses.Add(ip);
cli.Close();
} catch (ObjectDisposedException ex) {
} catch (SocketException ex) {
Console.WriteLine(ip + " - No");
}
finally
{
tConnectTimeout.Stop();
tConnectTimeout.Dispose();
}
}
tConnectTimeout.Stop();
btnStart.Sensitive = true;
foreach(string ipa in ipAddresses){
cbAddresses.AppendText(ipa);
}
cbAddresses.Sensitive = true;
}
or better yet
for (int i = 50; i <= 150; i++)
{
// Try Connect to Python
try
{
ip = "10.10.10."+i.ToString();
// Set timer to break Client connection
using( tConnectTimeout = new System.Timers.Timer(100))
{
tConnectTimeout.Elapsed += new System.Timers.ElapsedEventHandler(tConnectTimeout_Elapsed);
tConnectTimeout.Start();
// Connect to Client
using (cli = new TcpClient())
{
cli.Connect(ip, 8888);
tConnectTimeout.Stop()
Console.WriteLine(ip + " - Yes");
ipAddresses.Add(ip);
cli.Close();
}
}
}
catch (ObjectDisposedException ex)
{
}
catch (SocketException ex)
{
Console.WriteLine(ip + " - No");
}
}
From the OPs edits, the answer was to change the catch block to the following:
} catch (ObjectDisposedException ex) {
//HERE WAS THE PROBLEM. Added these two lines and now working.
tConnectTimeout.Stop();
tConnectTimeout.Dispose();
} catch (SocketException ex) {
tConnectTimeout.Stop();
tConnectTimeout.Dispose();
Console.WriteLine(ip + " - No");
}
(see here)
However I wouldn't recommend this fix over correct use of using to manage the timer.
I have a C# application that uses the CoreScanner.dll and SNAPI API. Everything works fine on my development computer but once I install the application on a client PC it gives a few errors.
Retrieving the COM class factory for component with CLSID {} failed due to the following error: 80080005 or Creating an instance of the COM component with CLSID {} from the IClassFactory failed due to the following error: 80010108.
And if I dont get either of those errors, I can back Object reference not set to an instance of an object when I call one of the scanner methods.
try
{
try
{
cCoreScanner = (CCoreScannerClass)Activator.CreateInstance(typeof(CCoreScannerClass));
}
catch (Exception e)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(e, "Setup Scanner - Splash Screen - Scanner Created");
}
}
short[] scannertTypes = new short[1];
scannertTypes[0] = 1;
short numberOfScannerTypes = 1;
int[] connectedScannerList = new int[255];
try
{
cCoreScanner.Open(0, scannertTypes, numberOfScannerTypes, out status);
}
catch (Exception e)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(e, "Setup Scanner - Splash Screen - Scanner Open " + status.ToString());
}
}
try
{
cCoreScanner.GetScanners(out numberOfScannerTypes, connectedScannerList, out outXML, out status);
}
catch (Exception e)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(e, "Setup Scanner - Splash Screen - Get Scanners " + status.ToString());
}
}
try
{
xmlDoc = new XmlDocument();
}
catch (Exception e)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(e, "Setup Scanner - Splash Screen - XML Create");
}
}
try
{
xmlDoc.LoadXml(outXML);
}
catch (Exception e)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(e, "Setup Scanner - Splash Screen - XML Load");
}
}
try
{
scannerID = xmlDoc.DocumentElement.GetElementsByTagName("scannerID").Item(0).InnerText;
}
catch (Exception e)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(e, "Setup Scanner - Splash Screen - Get ScannerID");
}
}
try
{
cCoreScanner.BarcodeEvent += new _ICoreScannerEvents_BarcodeEventEventHandler(onBarcodeScan);
inXML = "<inArgs>" +
"<scannerID>" + scannerID + "</scannerID>" +
"</inArgs>";
cCoreScanner.ExecCommand(2014, inXML, out outXML, out status);
opCode = 1001;
inXML = "<inArgs>" +
"<cmdArgs>" +
"<arg-int>1</arg-int>" + // Number of events you want to subscribe
"<arg-int>1</arg-int>" + // Comma separated event IDs
"</cmdArgs>" +
"</inArgs>";
cCoreScanner.ExecCommand(opCode, ref inXML, out outXML, out status);
}
catch (Exception e)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(e, "Setup Scanner - Splash Screen - Enable Scanner, Subscribe to barcode event");
}
}
}
catch (Exception ex)
{
using (LogManager lm = new LogManager())
{
lm.WriteErrorTextLog(ex, "Setup Scanner - Splash Screen");
}
}
I'm not sure where I am going wrong. I have the DLL registered, the SNAPI driver is installed on the client, and I've used the 123Scan utility to set the scanner up for SNAPI input. The client is a Win 7 64 bit, but I've also been testing on a Win XP and getting the same results. Developing on Win 7 32 bit, only difference is my computer as the SDK on it while the others don't.
Update: I finally found the CoreScanner driver on the Motorola website, however the 80010108 error will still happen, but if you restart the application, everything loads fine. Not 100% sure why its failing still but at least it works until the application closes.
Update 2: It seems only to fail after the application is re-installed. After that it will close / open just fine with no errors. Still have no clue has to why it doesn't work the 1st time but at least it works after that.
I am trying to send AT commands to COM ports, so I can find the GSM dongle. Below is the code
public bool findGsmModem()
{
bool sendStatus = false;
//Get all the available ports
string[] serialPorts = SerialPort.GetPortNames();
for (int i = 0; i < serialPorts.Length; i++)
{
Console.WriteLine(serialPorts[i]);
}
//Iterate through all the ports sending AT commands to find a modem
for (int i = 0; i < 1; i++)
{
try
{
//port.PortName = serialPorts[i].Trim();
port.PortName = "COM7";
openPort();
string res = ATCommandCaller("AT", 300,"Unable to connect to the phone"); //Connecting to the phone
//res = ATCommandCaller("AT+CMGF=1", 300); //Setting the message Format
sendStatus = true;
break;
}
catch (System.InvalidOperationException ex)
{
//port.PortName = null;
port.Close();
autoInitializer();
//port = new SerialPort();
continue;
//throw ex;
}
}
return sendStatus;
}
Here is how I call this method inside another class
if (sms.findGsmModem())
{
MessageBox.Show("Modem Found: " + sms.getPortName());
}
else
{
MessageBox.Show("No modem found");
}
OK, now in the findGsmModem() method if I use port.PortName = "COM5"; the above second code works successfully and display the message. That is because the Modem is actually in COM5 and the value is hard coded, so the statement do not reach the catch() block.
But, if I use port.PortName = serialPorts[i].Trim(); or port.PortName = serialPorts[i]; then it seems like nothing is happening instead of printing the port names (inside findGsmModem()). Following ports are being printed
COM1
COM2
COM8
COM9
COM5
COM4
COM3
As you can see, the COM5, the port where the gms modem actually exists is in the 5th element of the array, so findGsmModem() calls catch() part before it access the COM5.
I do believe I am not getting anything when port.PortName = serialPorts[i].Trim() is used because it goes to the catch() part and something terrible happens there.
Any idea?
Here is the openPort() method
public void openPort()
{
try
{
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
if (!port.IsOpen)
{
port.Open();
}
port.RtsEnable = true;
port.DtrEnable = true;
}
catch (Exception ex)
{
throw ex;
}
}
EDIT
Here is the most weirdest part. I just noticed the catch() block never get reached when the loop is called! I tried ex.Message to print the stack trace, and it didn't print anything!
catch (Exception ex)
This is the trouble with catch-em-all exception handling. You are getting an InvalidOperationException because you change the PortName property on a opened port. That's a bug in your code, nothing actually went wrong with the serial port.
You'll need to call the Close() method if you find out that it port is not connected to the GSM modem.
Then you can't call Open() again on that same SerialPort instance, it takes time for internal worker thread to shut down. Best thing to do is to create a new instance of SerialPort instead of trying to keep using the same one repeatedly.
I have a problem with a small C# application.
The application has to connect through a serial port to a bar code scanner which reads a Data Matrix code. The Data Matrix code represents an array of bytes which is a zip archive. I read a lot about the way SerialPort.DataReceived work but I can't find an elegant solution to my problem. And the application should work with different bar code scanners so i can't make it scanner specific. Here is some of my code:
using System;
using System.IO;
using System.IO.Ports;
using System.Windows.Forms;
using Ionic.Zip;
namespace SIUI_PE
{
public partial class Form1 : Form
{
SerialPort _serialPort;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
try
{
_serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.ToString());
return;
}
_serialPort.Handshake = Handshake.None;
_serialPort.ReadBufferSize = 10000;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
_serialPort.Open();
}
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[10000];
_serialPort.Read(data, 0, 10000);
File.WriteAllBytes(Directory.GetCurrentDirectory() + "/temp/fis.zip", data);
try
{
using (ZipFile zip = ZipFile.Read(Directory.GetCurrentDirectory() + "/temp/fis.zip"))
{
foreach (ZipEntry ZE in zip)
{
ZE.Extract(Directory.GetCurrentDirectory() + "/temp");
}
}
File.Delete(Directory.GetCurrentDirectory() + "/temp/fis.zip");
}
catch (Exception ex1)
{
MessageBox.Show("Corrupt Archive: " + ex1.ToString());
}
}
}
}
So my question is: How can I know that I read all the bytes the scanner sent?
The code I've got for reading barcode data, which has been working flawlessly in production for several years looks like this:
Note, my app has to read standard UPC barcodes as well as GS1 DataBar, so there's a bit of code you may not need...
The key line in this is:
string ScanData = ScannerPort.ReadExisting();
which is found in the DoScan section, and simply reads the scan data as a string. It bypasses the need to know how many bytes are sent, and makes the rest of the code easier to deal with.
// This snippet is in the Form_Load event, and it initializes teh scanner
InitializeScanner();
ScannerPort.ReadExisting();
System.Threading.Thread.Sleep(1000);
// ens snippet from Form_Load.
this.ScannerPort.DataReceived += new SerialDataReceivedEventHandler(ScannerPort_DataReceived);
delegate void DoScanCallback(); // used for updating the form UI
void DoScan()
{
if (this.txtCouponCount.InvokeRequired)
{
DoScanCallback d = new DoScanCallback(DoScan);
this.Invoke(d);
return;
}
System.Threading.Thread.Sleep(100);
string ScanData = ScannerPort.ReadExisting();
if (isInScanMode)
{
try
{
HandleScanData(ScanData);
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Invalid Scan");
}
}
}
void ScannerPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// this call to sleep allows the scanner to receive the entire scan.
// without this sleep, we've found that we get only a partial scan.
try
{
DoScan();
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Unable to handle scan event in ScannerPort_DataReceived." + System.Environment.NewLine + ex.ToString());
}
}
void Port_ErrorReceived(object sender, System.IO.Ports.SerialErrorReceivedEventArgs e)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show(e.EventType.ToString());
}
private void HandleScanData(string ScanData)
{
//MessageBox.Show(ScanData + System.Environment.NewLine + ScanData.Length.ToString());
//Determine which type of barcode has been scanned, and handle appropriately.
if (ScanData.StartsWith("A") && ScanData.Length == 14)
{
try
{
ProcessUpcCoupon(ScanData);
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Unable to process UPC coupon data" + System.Environment.NewLine + ex.ToString());
}
}
else if (ScanData.StartsWith("8110"))
{
try
{
ProcessDataBarCoupon(ScanData);
}
catch (Exception ex)
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Unable to process DataBar coupon data" + System.Environment.NewLine + ex.ToString());
}
}
else
{
System.Media.SystemSounds.Beep.Play();
MessageBox.Show("Invalid Scan" + System.Environment.NewLine + ScanData);
}
}
private void InitializeScanner()
{
try
{
ScannerPort.PortName = Properties.Settings.Default.ScannerPort;
ScannerPort.ReadBufferSize = Properties.Settings.Default.ScannerReadBufferSize;
ScannerPort.Open();
ScannerPort.BaudRate = Properties.Settings.Default.ScannerBaudRate;
ScannerPort.DataBits = Properties.Settings.Default.ScannerDataBit;
ScannerPort.StopBits = Properties.Settings.Default.ScannerStopBit;
ScannerPort.Parity = Properties.Settings.Default.ScannerParity;
ScannerPort.ReadTimeout = Properties.Settings.Default.ScannerReadTimeout;
ScannerPort.DtrEnable = Properties.Settings.Default.ScannerDtrEnable;
ScannerPort.RtsEnable = Properties.Settings.Default.ScannerRtsEnable;
}
catch (Exception ex)
{
MessageBox.Show("Unable to initialize scanner. The error message received will be shown next. You should close this program and try again. If the problem persists, please contact support.", "Error initializing scanner");
MessageBox.Show(ex.Message);
Application.Exit();
}
}
As stated in the doc for SerialPort.DataReceived, "Use the BytesToRead property to determine how much data is left to be read in the buffer."
here is the doc for SerialPort.BytesToRead
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.bytestoread.aspx