Using Threads in a C# function for Excel - c#

I am writing a ping function for Excel. This function suppose to take a column of IP address (about 200 address) and ping each one of them.
To avoid Excel getting stuck, I have decided to use a thread that will send the pings instead of the main thread. The problem is that the thread can't access the cell values and the Excel crashes.
I hope that someone could help me with this.
Here is the code :
private LinkedList<string> Iplist;
private Thread t;
public NetworkPing()
{
}
public int CalcPingColumn(Range IPcells, Range ANScells)
{
CreateIpList(IPcells);
this.t = new Thread(() => CalcPing_method(ANScells));
this.t.Start();
return 1;
}
//THE PROBLEM IS PREOBBLY HERE
private void CalcPing_method(Range ANScells)
{
foreach (Range ans in ANScells.Cells)
{
ans.Value2 = Ping(Iplist.Last.Value);
Iplist.RemoveLast();
Thread.Sleep(50);
}
}
private void CreateIpList(Range IPcells)
{
Iplist = new LinkedList<string>();
foreach (Range ip in IPcells.Cells)
{
Iplist.AddFirst(ip.Value2);
}
}

Try to use the BackgroundWorker-class instead of the regular Thread. It makes it more easy to "send" objects/instances between threads. From that you can also get progress: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx

why not one function?
public string PingIpadress(string ipadress)
{
var pingSender = new Ping();
var options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
PingReply reply = pingSender.Send(ipadress, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
return "alive " + reply.Options.Ttl;
}
return "no response";
}

Related

Error when trying to use Ping in Unity - C#

I am trying to ping one of my servers using C# Ping to see whether it is available or not, but I am receiving a weird error and I'm not sure what's causing it
On first execution of the code, it returns an error but states that the operation was completed successfully
System.Net.Sockets.SocketException (0x80004005): The operation completed successfully.\r\n\r\n at System.Net.Sockets.Socket..ctor (System.Net.Sockets.AddressFamily addressFamily, System.Net.Sockets.SocketType socketType, System.Net.Sockets.ProtocolType protocolType) [0x00069]
Each time the code is executed after the first, it will return a different error.
"An attempt was made to access a socket in a way forbidden by its access permissions."
System.Net.Sockets.SocketException (0x80004005)
The code I am using to ping is as follows which is pretty much pulled straight from MSDN. https://msdn.microsoft.com/en-us/library/system.net.networkinformation.pingreply(v=vs.110).aspx
public static bool pingHost(string nameOrAddress)
{
bool pingable = false;
if (nameOrAddress == "127.0.0.1")
{
return true;
}
try
{
System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 3;//3 seconds?
PingReply reply = pingSender.Send(nameOrAddress, timeout);
if (reply.Status == IPStatus.Success)
{
pingable = true;
} else
{
pingable = false;
}
}
catch (PingException e)
{
Debug.Log("Error pinging: " + e.Message + " - " + e.StackTrace);
// Discard PingExceptions and return false;
}
return pingable;
}
I am able to ping the server from my terminal on my machine, but not through code. Why am I receiving this error?
EDIT
I have tested the code in a standard C# application and it works fine. This issue must be something related to Unity.
Unity has its own Ping class but can't be called from outside the main thread. The code below tries to utilise this, but it always returns false and -1 for the time.
Ping should definitely complete within 3 seconds? I have tried increasing this time to 10 seconds but still returns false. The address is definitely pingable as I can ping it from the terminal.
IEnumerator ping()
{
while (true)
{
UnityEngine.Ping pinger = new UnityEngine.Ping("ADDRESS");
yield return new WaitForSeconds(3.0f);
Debug.Log("Ping finished? " + pinger.isDone + " - " + pinger.time);
yield return new WaitForSeconds(2.0f);
}
}
As this doesn't work, my next question is how does the Unity ping actually work? My servers are in a secure environment with only specific open ports. If it is doing something unexpected other than the standard ping, it may not be able to.
EDIT 2
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}
This code seems to work nicely, but only works from the main thread. I will need a solution that is able to be started from a separate task or thread.
This seems to work, but only from the main thread.
IEnumerator ping()
{
while (true)
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
PingFinished(p);
}
}
Here's a general idea of how to do it on/off the main thread:
(Caution: untested)
using System.Threading;
class Test : MonoBehaviour {
Ping result;
private object pingLock;
void Start() {
pingLock = new object();
new Thread(ThingRunningOffMainThread).Start();
StartCoroutine(DoPing());
}
IEnumerator DoPing()
{
WaitForSeconds f = new WaitForSeconds(0.05f);
Ping p = new Ping("ADDR");
while (!p.isDone)
{
yield return f;
}
Monitor.Enter(pingLock);
result = p;
Monitor.Pulse(pingLock);
Monitor.Exit(pingLock);
}
void ThingRunningOffMainThread() {
if (result == null) {
Monitor.Enter(pingLock);
while (result == null) {
Monitor.Wait(pingLock);
}
Monitor.Exit(pingLock);
}
PingFinished(pingLock);
}
}
To invoke from a background thread to the main thread, look at Main Thread Dispatchers, for example:
https://github.com/PimDeWitte/UnityMainThreadDispatcher/blob/master/UnityMainThreadDispatcher.cs

Why is the Windows Forms UI blocked when executing Task with ContinueWith?

I spent a couple of days searching in Google and trying to understand why in my case Windows Forms UI is blocked when executing pings in Tasks.
I saw a lot of similar cases, but none of them explains my specific case.
Issue description:
I have an application which sends pings asynchronously. Each ping is send inside of a Task. I use .ContinueWith to receive result of a ping and print it to textbox without blocking UI thread. It works OK if I launch all pings once. If I add a while {run} loop to make them run forever my UI becomes unresponsive and blocked, and none of the results are printed to the textbox.
Problematic Code:
Action action2 = () => {
for (int i = 0; i < ipquantity; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true) // Variable helps to check if ping reply was received and printed
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
Thread.Sleep(1000);
}
Questions:
Why is the UI blocked with a while loop and why is it not blocked without it?
How can I modify my code to be still able to use Tasks for pings without blocking the UI?
Is there a better way to launch endless pings to several IP addresses simultaneously?
Complete code:
private async void buttonStart_Click(object sender, EventArgs e)
{
run = true;
int count = listView1.Items.Count;
task = new Task<string>[count];
result1 = new string[count];
finished = new bool[count];
continutask = new Task[count];
for (int i = 0; i < count; i++)
{
finished[i] = true;
}
Action action2 = () =>
{
for (int i = 0; i < count; i++)
{
int temp1 = i;
string ip = listView1.Items[temp1].SubItems[1].Text;
if (finished[temp1] == true)
continutask[temp1] = Task<string>.Run(() => PingStart(ip, temp1)).ContinueWith(antecedent => PrintResult(antecedent.Result, temp1));
}
};
while (run)
{
action2();
//await Task.Delay;
//Thread.Sleep(1000);
}
}
public void PrintResult(string message, int seqnum)
{
Action action = () =>
{
textBox1.AppendText(message);
textBox1.AppendText(Environment.NewLine);
textBox1.AppendText("");
textBox1.AppendText(Environment.NewLine);
};
if (InvokeRequired)
Invoke(action);
else
action();
finished[seqnum] = true;
}
public string PingStart(string ip, int seqnum)
{
finished[seqnum] = false;
Ping isPing = new Ping();
PingReply reply;
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
options.DontFragment = false;
reply = isPing.Send(ip, timeout, buffer, options);
string rtt = (reply.RoundtripTime.ToString());
string success = "N/A";
if (reply.Status == IPStatus.Success)
{
success = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else if (reply.Status != IPStatus.Success)
{
success = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
return success;
}
Since you already create (and save) your tasks, the easiest fix would be to await them for each iteration of your while loop:
while (run)
{
action2();
foreach (Task t in continutask)
await t;
}
That way, when all pings completed (successful or not) you start the entire process again - without delay.
One more thing: You could add a textBox1.ScrollToEnd(); to PrintResult
Since there is a lot of room for improvement, below is a rewritten and simplified example. I've removed a lot of unused variables (e.g. seqnum) and made the PingStart method completely asynchronous. I also replaced your ListBox with a TextBox for easier testing, so you might want to revert that in your code.
This still isn't the cleanest of all possible implementations (mainly because of the global run) but it should show you how to do things "more async" :)
private async void buttonStart_Click(object sender, EventArgs e)
{
// If the ping loops are already running, don't start them again
if (run)
return;
run = true;
// Get all IPs (in my case from a TextBox instead of a ListBox
string[] ips = txtIPs.Text.Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries);
// Create an array to store all Tasks
Task[] pingTasks = new Task[ips.Length];
// Loop through all IPs
for(int i = 0; i < ips.Length; i++)
{
string ip = ips[i];
// Launch and store a task for each IP
pingTasks[i] = Task.Run(async () =>
{
// while run is true, ping over and over again
while (run)
{
// Ping IP and wait for result (instead of storing it an a global array)
var result = await PingStart(ip);
// Print the result (here I removed seqnum)
PrintResult(result.Item2);
// This line is optional.
// If you want to blast pings without delay,
// you can remove it
await Task.Delay(1000);
}
}
);
}
// Wait for all loops to end after setting run = false.
// You could add a mechanism to call isPing.SendAsyncCancel() instead of waiting after setting run = false
foreach (Task pingTask in pingTasks)
await pingTask;
}
// (very) simplified explanation of changes:
// async = this method is async (and therefore awaitable)
// Task<> = This async method returns a result of type ...
// Tuple<bool, string> = A generic combination of a bool and a string
// (-)int seqnum = wasn't used so I removed it
private async Task<Tuple<bool, string>> PingStart(string ip)
{
Ping isPing = new Ping();
const int timeout = 2000;
const string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
var buffer = Encoding.ASCII.GetBytes(data);
PingOptions options = new PingOptions {DontFragment = false};
// await SendPingAsync = Ping and wait without blocking
PingReply reply = await isPing.SendPingAsync(ip, timeout, buffer, options);
string rtt = reply.RoundtripTime.ToString();
bool success = reply.Status == IPStatus.Success;
string text;
if (success)
{
text = $"{ip}" + " Success!" + $" rtt: [{rtt}]" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
else
{
text = $"{ip}" + $" Not Successful! Status: {reply.Status}" + $"Thread: {Thread.CurrentThread.GetHashCode()} Is pool thread: {Thread.CurrentThread.IsThreadPoolThread}";
}
// return if the ping was successful and the status message
return new Tuple<bool, string>(success, text);
}
This way you will have a loop for each IP that will continue independently of each other until run is set to false.
Thread.Sleep(n) blocks the current thread for n milliseconds. If I understand the code correctly it executes action2 then suspends the calling thread for one second. If that thread is the main (UI) thread, your UI will be blocked.
Maybe moving the while loop to yet another thread would fix the problem.

Stream for sending byte-arrays and strings (for network)

I'm searching for a Streamclass which contains:
- a method for sending/receiving a byte-array
- a method for sending/receiving a string
The only Class I've found was NetworkStream. But the disadvantage with the NetworkStream-Class is, that if i want sending a string, i must befor convert this string into a byte-array and send this byte-array, because there is no method for sending strings directly.
And on the other side classes like Streamwriter have methods for sending/receiving strings, but there have no methods for sending/receiving a byte-array.
And if i try to combine these two Streamclasses like this:
TcpClient clientConnection = new TcpClient();
NetworkStream nws = clientConnection.GetStream();
StreamWriter sw = new StreamWriter(nws);
sw.writeLine("ABC");
sw.Flush();
nws.Write(byteArray, 0, lengthToSend);
i get a lot of strange errors (like byteArray will not receive on the other side completly), because i'm using here the same one stream in two different ways.
So, must i used NetworkStream-Class for my plan or exists there a better way?
I had the same problem,and the point is that the other side doesnt know what you are sending byte array or string so what i did is putting a header for each msg specially when dealing with serious server/client application coz you will have multiple data (user info, requesting info,replying info .. etc)
i am using streamwriter to send and streamreader to receive but i am also using threads
the connection remains open as long as the client is connected so i declare them once
here is a full example of my codes
public class Client
{
private StreamWriter swSender;
private StreamReader srReceiver;
private TcpClient tcpServer;
private Thread thrMessaging;
private string UserName = "UK";
private byte Tries = 0;
private bool Connected = false;
public void Connect()
{
if (!Connected)
{
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
string User = localIPs[0].ToString();
string ServIP = "127.0.0.1";//change this to your server ip
InitializeConnection(ServIP, User);
}
else
{
CloseConnection("Disconnected at user's request.");
}
}
private void InitializeConnection(string ServIp, string User)
{
IPAddress ipAddr = IPAddress.Parse(ServIp);
tcpServer = new TcpClient();
try
{
tcpServer.Connect(ipAddr, 1986);//change that 1986 to your server port
}
catch
{
if (Connected) CloseConnection("");
MessageBox.Show("Connecteing to " + ServIp + "\r\nServer is Down ... Try nomber " + Tries); return;
}
Connected = true;
UserName = User;
swSender = new StreamWriter(tcpServer.GetStream());
swSender.WriteLine(User);
swSender.Flush();
thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
thrMessaging.Start();
}
private void ReceiveMessages()
{
srReceiver = new StreamReader(tcpServer.GetStream());
string ConResponse = srReceiver.ReadLine();
if (ConResponse[0] == '1')
{
}
else
{
string Reason = "Not Connected: ";
Reason += ConResponse.Substring(2, ConResponse.Length - 2);
return;
}
while (Connected)
{
try
{
string NewMsg = srReceiver.ReadLine();
if (NewMsg != null && NewMsg != "")
PacketHandler.HandlePacket(NewMsg, this);
}
catch { }
}
}
public void CloseConnection(string Reason)
{
try
{
Connected = false;
swSender.Close();
srReceiver.Close();
tcpServer.Close();
}
catch { }
}
public void SendMessage(string Msg)
{
if (Msg.Length >= 1)
{
try
{
Tries++;
swSender.WriteLine(Msg);
swSender.Flush();
Tries = 0;
}
catch
{
if (Tries < 5)
{
try
{
CloseConnection("No connection made");
Connect();
}
catch { }
SendMessage(Msg);
}
else { MessageBox.Show("Connecting to server faild for 5 tries"); Tries = 0; }
}
}
}
then at the packet handler i do my handling to check what kind of data the client received
something like this
public static void HandlePacket(string MsgRec, Client Client)
{
string[] Info = MsgRec.Split('|');
string Type = Info[0];
if (Type == "")
{
return;
}
string subtype = Info[1];
int TLen = Type.Length + subtype.Length + 2;
string Data = MsgRec.Remove(0, TLen);//this is the main data the server sent
ushort PacketType = ushort.Parse(Type);
ushort SubType = ushort.Parse(subtype);
switch ((Structs.PacketType)PacketType)
{
case Structs.PacketType.Login:
{
//do your stuff here
break
}
case Structs.PacketType.Image:
{
//convert the Data back to byte array then get the image out from it
break
}
case Structs.PacketType.ByteArray:
{
//convert the Data back to byte array
break
}
}
}
i know its kinda messy and not the perfect way to do it , but it works for me
and remember that at the other side when sending something you need to add the packet type and subtype , or just any header with any splitter if u doin something simple
Finally : i think using Sockets and packets would be much easier if u are sending small packets length

The fastest way to ping a large list of IP adresses?

I have a large list of IP addresses in a datatable and i have to ping them so quickly,
I used this code :
public bool PingIP(string IP)
{
bool result = false;
try
{
Ping ping = new Ping();
PingReply pingReply = ping.Send(IP);
if (pingReply.Status == IPStatus.Success)
result = true;
}
catch
{
result = false;
}
return result;
}
then i call it in while loop :
private void CheckNetworkState()
{
while (rowindexping > -1)
{
if (rowindexping == tbl_ClientInfo.Rows.Count)
{
rowindexping = -1;
return;
}
string ip = tbl_ClientInfo.Rows[rowindexping]["clientip"].ToString();
if (!PingIP(ip))
{
do something
}
rowindexping++;
Thread.Sleep(100);
}
}
Since i want to do this work at the background of my project i call the class in a thread:
threadping = new Thread(CheckNetworkState);
threadping.IsBackground = true;
threadping.Start();
my problem is that it takes so many time and does not work at the background. i mean the system is busy till all ip addresses in tbl_clientinfo go through the ping class.
i want that system check all rows since i'm working with other part of my project.
Did i do correctly?
Your code is running all the code on a single thread; you're not using multiple threads. Also, why do you have a Thread.Sleep in there?
Try the following:
Query the database and get all the IPs
In a loop, spin up a new thread that will run PingIP for each IP address
Note: You can also spin up a new thread every time you get a new row from the database
Sample:
static void Main(string[] args)
{
// get the IPs from the database so you can iterate over them
List<string> ips = new List<string>()
{
"google.com",
"127.0.0.1",
"stackoverflow.com"
};
foreach (var ip in ips)
{
// See http://stackoverflow.com/questions/4744630/unexpected-behaviour-for-threadpool-queueuserworkitem
// for reason to use another variable in the loop
string loopIp = ip;
WaitCallback func = delegate(object state)
{
if (PingIP(loopIp))
{
Console.WriteLine("Ping Success");
}
else
{
Console.WriteLine("Ping Failed");
}
};
ThreadPool.QueueUserWorkItem(func);
}
Console.ReadLine();
}
public static bool PingIP(string IP)
{
bool result = false;
try
{
Ping ping = new Ping();
PingReply pingReply = ping.Send(IP);
if (pingReply.Status == IPStatus.Success)
result = true;
}
catch
{
result = false;
}
return result;
}
What I would do is have a separate multi-threaded daemon running in the background, doing the pings, and putting the results in a database. Have a page that loads results via AJAX later.
Consider making a system call to the fping utility. Granted, it's not managed code, but fping is very well optimized for your specific task and would simplify your problem down to a single call followed by the processing of a text-based list of results.
you can use powershell
private string resultat(string s)
{
Runspace space = RunspaceFactory.CreateRunspace();
space.Open();
Pipeline pipeline = space.CreatePipeline();
pipeline.Commands.AddScript(s);
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
and then use resultat("ping -l 10 -n 2 " + your_ip);

problem with two .NET threads and hardware access

I'm creating an application which communicates with the device via FT2232H USB/RS232 converter. For communication I'm using FTD2XX_NET.dll library from FTDI website.
I'm using two threads:
first thread continuously reads data from the device
the second thread is the main thread of the Windows Form Application
I've got a problem when I'm trying to write any data to the device while the receiver's thread is running. The main thread simply hangs up on ftdiDevice.Write function.
I tried to synchronize both threads so that only one thread can use Read/Write function at the same time, but it didn't help.
Below code responsible for the communication. Note that following functions are methods of FtdiPort class.
Receiver's thread
private void receiverLoop()
{
if (this.DataReceivedHandler == null)
{
throw new BackendException("dataReceived delegate is not set");
}
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
byte[] readBytes = new byte[this.ReadBufferSize];
while (true)
{
lock (FtdiPort.threadLocker)
{
UInt32 numBytesRead = 0;
ftStatus = ftdiDevice.Read(readBytes, this.ReadBufferSize, ref numBytesRead);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
this.DataReceivedHandler(readBytes, numBytesRead);
}
else
{
Trace.WriteLine(String.Format("Couldn't read data from ftdi: status {0}", ftStatus));
Thread.Sleep(10);
}
}
Thread.Sleep(this.RXThreadDelay);
}
}
Write function called from main thread
public void Write(byte[] data, int length)
{
if (this.IsOpened)
{
uint i = 0;
lock (FtdiPort.threadLocker)
{
this.ftdiDevice.Write(data, length, ref i);
}
Thread.Sleep(1);
if (i != (int)length)
{
throw new BackendException("Couldnt send all data");
}
}
else
{
throw new BackendException("Port is closed");
}
}
Object used to synchronize two threads
static Object threadLocker = new Object();
Method that starts the receiver's thread
private void startReceiver()
{
if (this.DataReceivedHandler == null)
{
return;
}
if (this.IsOpened == false)
{
throw new BackendException("Trying to start listening for raw data while disconnected");
}
this.receiverThread = new Thread(this.receiverLoop);
//this.receiverThread.Name = "protocolListener";
this.receiverThread.IsBackground = true;
this.receiverThread.Start();
}
The ftdiDevice.Write function doesn't hang up if I comment following line:
ftStatus = ftdiDevice.Read(readBytes, this.ReadBufferSize, ref numBytesRead);
An alternative is to use the event notification mechanism from FTDI, this way you don't need a blocking thread to read out data:
public FTDISample()
{
private AutoResetEvent receivedDataEvent;
private BackgroundWorker dataReceivedHandler;
private FTDI ftdi;
public FTDISample(string serialNumber){
ftdi = new FTDI();
FTDI.FT_STATUS status = ftdi.OpenBySerialNumber(serialNumber);
receivedDataEvent = new AutoResetEvent(false);
status = mFTDI.SetEventNotification(FTDI.FT_EVENTS.FT_EVENT_RXCHAR, receivedDataEvent);
dataReceivedHandler = new BackgroundWorker();
dataReceivedHandler.DoWork += ReadData;
if (!dataReceivedHandler.IsBusy)
{
dataReceivedHandler.RunWorkerAsync();
}
}
private void ReadData(object pSender, DoWorkEventArgs pEventArgs)
{
UInt32 nrOfBytesAvailable = 0;
while (true)
{
// wait until event is fired
this.receivedDataEvent.WaitOne();
// try to recieve data now
FTDI.FT_STATUS status = ftdi.GetRxBytesAvailable(ref nrOfBytesAvailable);
if (status != FTDI.FT_STATUS.FT_OK)
{
break;
}
if (nrOfBytesAvailable > 0)
{
byte[] readData = new byte[nrOfBytesAvailable];
UInt32 numBytesRead = 0;
status = mFTDI.Read(readData, nrOfBytesAvailable, ref numBytesRead);
// invoke your own event handler for data received...
//InvokeCharacterReceivedEvent(fParsedData);
}
}
}
public bool Write(string data)
{
UInt32 numBytesWritten = 0;
ASCIIEncoding enconding = new ASCIIEncoding();
byte[] bytes = enconding.GetBytes(data);
FTDI.FT_STATUS status = ftdi.Write(bytes, bytes.Length, ref numBytesWritten);
if (status != FTDI.FT_STATUS.FT_OK)
{
Debug.WriteLine("FTDI Write Status ERROR: " + status);
return false;
}
if (numBytesWritten < data.Length)
{
Debug.WriteLine("FTDI Write Length ERROR: " + status + " length " + data.Length +
" written " + numBytesWritten);
return false;
}
return true;
}
A few things:
Check to see if your Read call is blocking. If so, you might not be able to call Write while the Read is blocking waiting for a response. Your API documentation may have more details on this.
Some APIs do not support multiple threads very well, even when synchronizing access. If that's the case here, you can use a design where you delegate your Write commands to your comm thread. When I've used this pattern in the past, I typically queue up some sort of Command class containing the information I wish to write, and either use a threading Signal class to allow my calling 'command' methods to block or provide some sort of asynchronous notification.
I've found more detailed API documentation. Indeed the ftdiDevice.read function is blocking unless you set the readTimeout value other then 0. Setting this timeout value solved the problem.
Thanks for your quick response.
Regards
Checking out the API, it looks to me that the driver is capable of emulating a COM port. I see the GetComPort() method returning a "COMx" string. That makes it pretty likely that you can use the System.IO.Ports.SerialPort class. Which already does what your wrapper is trying to do, it supports a DataReceived event. Worth a shot.

Categories