this is my first question on here, since I couldn't find it answered anywhere.
I am not particularly new to WPF and C#, but I've never read SerialData with it before, and I'm having rudimentary problems I'm sure.
Setup:
Arduino clone (SparkFun Pro Micro) sending "Hello!" + a number to the USB serial port (COM5) once every second:
String hello = "hello!";
Serial.println(hello + i);
i++;
delay(1000);
And trying to receive it in WPF, with a simple button that refreshes the data to a TextBlock (tbData).
SerialPort sp = null;
String str = null;
int i = 0;
public MainWindow()
{
InitializeComponent();
sp = new SerialPort("COM5", 9600);
sp.DataReceived += new SerialDataReceivedEventHandler(ReceiveData);
sp.Open();
}
void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
str = sp.ReadLine();
}
private void Refresh_Click(object sender, RoutedEventArgs e)
{
tbData.Text = str;
}
But nothing happens, I seem to be getting an empty string, since the TextBlock doesn't show anything when I press the Refresh_Click button.
I can get it to work with a new Thread, but it keeps timeouting, and I read on here (Timeouts in C# serial port) that the best (and simplest it seems) method is using a SerialDataReceived event.
t = new Thread(() =>
{
int i = 0;
while (run)
{
SerialString = sp.ReadLine();
Thread.Sleep(1000);
}
sp.Close();
});
What I am missing must be something along the lines of changing the size of the buffer? Or something similar?
It seems I've found the answer!
I am pretty clueless about Serial communications, but today I came across the MODE cmd function:
C:\Users\Username>mode
Status for device COM5:
-----------------------
Baud: 9600
Parity: None
Data Bits: 8
Stop Bits: 1
Timeout: ON
XON/XOFF: OFF
CTS handshaking: OFF
DSR handshaking: OFF
DSR sensitivity: OFF
DTR circuit: OFF
RTS circuit: OFF
And I noticed that it changed whenever I had the Arduino IDE report the data to me - which it would always do successfully! - and whenever I tried to make WPF do the same.
Above is the MODE return after I tried to run my own code, and:
Status for device COM5:
-----------------------
Baud: 9600
Parity: None
Data Bits: 8
Stop Bits: 1
Timeout: OFF
XON/XOFF: OFF
CTS handshaking: OFF
DSR handshaking: OFF
DSR sensitivity: OFF
DTR circuit: ON
RTS circuit: ON
this is what it showed after opening Tools>Serial monitor in the Arduino IDE, and closing it again immediately.
I changed my WPF code from:
sp = new SerialPort("COM5", 9600);
sp.Open();
to:
sp = new SerialPort("COM5", 9600);
//sp.ReadTimeout = 200;
sp.DtrEnable = true;
sp.RtsEnable = true;
sp.DataBits = 8;
sp.StopBits = StopBits.One;
sp.Open();
And now both the threading example and the SerialDataReceived event runs smoothly (well, except I can't update a UI thread within a SerialDataReceived thread).
I hope someone out there finds this useful.
Related
For some research of network activity on my private network, I came across NightHawk. So after downloading and testing, I tried to print out some Tcp packets when "sniffing". This worked for me very fine.
But when clicking the "stop button", the sniff function pauses for around 3 seconds and resumes sniffing to the network and printing arriving packets.
After searching for the missing -= of a "sniffing to the network" event handler, I found one and fixed it. BUT the problem is still active.
So for some reason - I can't find out - the OnPacketArrival event is still "alive" AND called from somewhere, even though I stopped capturing AND removed the event handler.
Edit:
As requested, here is some code:
// start listening on a device (combobox index)
public void StartDevice(int deviceIndex)
{
Started = true;
DeviceInfo = DeviceInfoList[deviceIndex];
Device = WinPcapDeviceList.Instance[deviceIndex];
Sniffer = new Sniffer(DeviceInfo);
ARPTools = new ARPTools(DeviceInfo);
NDTools = new NDTools(DeviceInfo);
SSLStrip = new SSLStrip();
Scanner = new Scanner(DeviceInfo);
Sniffer.SnifferResult += new SnifferResultHandler(sniffer_OnSnifferResult);
SSLStrip.SSLStripped += new SSLStripHandler(SSLStrip_OnSSLStripped);
Scanner.ScannerResponse += new ScannerResponseReceived(scanner_OnResponse);
Scanner.ScanComplete += new ScannerEventHandler(scanner_OnScanComplete);
Scanner.HostnameResolved += new ScannerHostnameResolvedHandler(scanner_HostnameResolved);
// open device, set filters & events, start capturing
Device.Open(DeviceMode.Promiscuous, 1);
Device.Filter = "(arp || ip || ip6)";
Device.OnPacketArrival += device_OnPacketArrival; // Subscribe the event for arriving packets
Device.StartCapture();
}
// stop listening on a device
public void StopDevice()
{
Started = false;
if (Device == null) return;
Device.StopCaptureTimeout = TimeSpan.FromMilliseconds(200);
Device.StopCapture();
Device.OnPacketArrival -= device_OnPacketArrival; // This is to unsubscribe the event. This was coded by me
Device.Close();
}
So has someone an explanation for this?
Thanks in advance!
I'm trying to create a Serial Communication tool on MSVS using C#. it communicates with the Photon MCU and a bluetooth dongle.
When the "start" button is pressed, the UI sends a "1" to the Photon which it first sends the current time stamp and starts streaming data from the function generator. When the "stop" button is pressed, It first sends 10 "2"s (due to the timer issue on the photon's end) which the when the Photon receives, it stops transmitting the function generator's data. Then it sleeps for a second and sends a "3" which it sends another current time stamp. Then the UI discards data in the InBuffer and stops reading data.
connectBT is connected with the start button and the disconnectBT is connected with the stop button.
This is the code that I have right now:
SerialPort serial = new SerialPort();
string recieved_data;
int startBuffer = 0;
private void connectBT(object sender, RoutedEventArgs e)
{
startBuffer++; // keep track of BT open counter
if (serial.IsOpen) Debug.WriteLine("BT Open");
// first time BT is open and BT is not open
if (!serial.IsOpen)
{
if (startBuffer == 1)
{
// COM port properties
serial.PortName = "COM7";
serial.BaudRate = 38400;
serial.Handshake = Handshake.None;
serial.Parity = Parity.None;
serial.DataBits = 8;
serial.StopBits = StopBits.One;
serial.ReadTimeout = 200;
serial.WriteTimeout = 50;
serial.Open();
}
startButton.Content = "Recording";
Send_Data("1"); // tell Photon to start sending data
serial.DiscardInBuffer(); // discard whatever is in inbuffer
serial.DataReceived += new SerialDataReceivedEventHandler(Recieve); // start receiving data
}
// after BT has been opened and start button has been pressed again
else if (serial.IsOpen && startBuffer > 1)
{
startButton.Content = "Recording";
Send_Data("1");
serial.DiscardInBuffer();
serial.DataReceived += new SerialDataReceivedEventHandler(Recieve);
}
}
// stop button is pressed
private void disconnectBT(object sender, RoutedEventArgs e)
{
// send "2" ten times to tell photon to stop transmitting function generator data
int i = 0;
while (i < 10)
{
Send_Data("2");
Thread.Sleep(1);
i++;
}
Thread.Sleep(1000);
Send_Data("3"); // send a 3 to tell photon to send the last time stamp
Thread.Sleep(1000);
serial.DiscardInBuffer(); // discard in buffer
serial.DataReceived -= Recieve; // stop receiving data
//serial.Close(); // close BT
startButton.Content = "Start";
}
private void Recieve(object sender, SerialDataReceivedEventArgs e)
{
recieved_data = serial.ReadLine();
Debug.WriteLine(recieved_data);
}
I'm running into an issue where when I press the "stop" button, the last chunk of data that was sent from the bluetooth is lost. I never receive the last time stamp that I'm supposed to have received when the stop button is pressed. According to our math, we're supposed to be receiving 500 points per second (500Hz) but I only receive about 100 of them.
My theory is that the UI is receiving data at a slower (or a delayed) rate and the serial.DiscardInBuffer discard the received data even before that the data can be printed to the Debug output. I know for a fact that all the data between the first and last I receive are all there because of counter values associated with the data packets. Basically if I were to receive 1~500 data points, I only receive 1~100. I've also tried it with just termite with sending 1,2, and 3 as the UI is supposed to be and I get all the data as I need them. I don't close BT on purpose.
What can I do to prevent this data loss? What am I doing wrong in my code that I shouldn't be doing or be doing for the correct bluetooth protocol? This is my first time writing bluetooth code so I'm fairly unfamiliar with it.
Not sure if that's the cause of your problem, but your Receive has a very big pitfall.
You only read one line per Receive event, and on one event there can be more than one line to read, then they are being accumulated and discarded at the end.
ReadLine is meant to be used in a synchronous way like an stream where you read one line, process it then you write, not to be used with the DataReceived event.
You have two options: spin a new thread in a continuous loop reading with serial.ReadLine() (it will block until a new line is available) or the better approach, read the serial buffer on each Receive event.
To do it like that you can do smething like this:
List<byte> tmpBuffer = new List<byte>();
static byte newLineB = Encoding.ASCII.GetBytes("\n")[0];
void Receive(object sender, SerialDataReceivedEventArgs e)
{
lock (tmpBuffer)
{
while (serial.BytesToRead > 0)
{
byte[] segment = new byte[serial.BytesToRead];
serial.Read(segment, 0, segment.Length);
tmpBuffer.AddRange(segment);
ProcessBuffer();
}
}
}
private void ProcessBuffer()
{
int index = 0;
while ((index = tmpBuffer.IndexOf(newLineB)) > -1)
{
string line = Encoding.ASCII.GetString(tmpBuffer.Take(index + 1).ToArray());
//Do whatever you need to do with the line data
Debug.WriteLine(line);
tmpBuffer.RemoveRange(0, index + 1);
}
}
As you can see, the received data is being stored on a temporal list used as a buffer (yes, an array and using Buffer functions would be faster, but for small messages and for simplicity a list is enough for most cases), then the received data is added to the buffer and when there are no more bytes left the list is processed in search of string lines.
Also note the read is in a loop, I have run in cases where there were data received while the function was being executed and no receive event was fired, so the better for this is to create a loop to read while there is still data.
Thank you all for your response, they all helped me reaching the solution for my issue, but in the end what fixed it was delaying the time between sending the "3" and discarding my inBuffer and closing the Receive connection.
async Task DelayBT()
{
await Task.Delay(100);
}
Thread.Sleep() didn't work because of its nature disabling all action within the thread (which I still needed) so this method worked like a charm. I just called await DelayBT where I needed the delay.
Hope this helps anyone running into the same issue as me.
I know this is answered question however I want to know hardware required and how to setup.
I am trying to build a take-out's delivery system wherein users call and their phone number gets captured on a WINFORM.
I googled and it says I need to use TAPI API. That's fine but do I need to connect anything to the PC or will just using TAPI work?
This Link explains it in VB.net. I am looking for it in c#.net.
I have also gone through the links provided here.
But nowhere does it explain the setup. So please help.
First thing
See if your hardware supports caller ID
Add the serial port control, set it to whatever comm port your modem is on and watch for the CALLER ID number, then react
To see if your modem supports Caller ID open a serial port terminal (I like putty) and set it to the com port of your modem then call the phone number attached to that that modem, you should see something like RING 5555555555 (where 5555555555 is the phone number of the person calling you)
You may have to turn caller id on for that modem (if so)
1) Open the "Phone And Modem Options" control panel
2) Click the "Modems" tab
3) Select your modem in the list (if it is not already selected)
4) Click the "Properties" button
5) Click the "Advanced" tab
6) Type "#CID=1" into the "Extra initialization commands" edit box
Note: replace "#CID=1" with the command to enable caller id on your modem
Do not include the "AT" part of the command
Do not include the quotes
7) Click OK
8) Click OK
9) restart the computer
Here is some code for interacting with a serial port in c# (incase you need that)
public SerialPort sp;
string dataReceived = string.Empty;
private delegate void SetTextDeleg(string text);
private void FormLoad()
{
sp = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
this.sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sp.Open();
}
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
Thread.Sleep(500);
string x = sp.ReadLine(); // will read to the first carriage return
this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { x });
}
catch
{ }
}
private void si_DataReceived(string data)
{
dataReceived = data.Trim();
// Do whatever with the data that is coming in.
}
Also I just searched amazon for "Caller ID Modem" and there seem to be alot for between 10 and 20 dollars (US) that support this exact use. I would recommend the Trendnet TFM-561U
If you are using a phone and fax modem, just plug-in your telephone line into the modem.
Next on your windows form drag-n-drop a SerialPort control and initialize it.
this.serialPort1.PortName = "COM3";
this.serialPort1.BaudRate = 9600;
this.serialPort1.DataBits = 8;
this.serialPort1.RtsEnable = true;
this.serialPort1.DataReceived += serialPort1_DataReceived;
this.serialPort1.Open();
Pass the following command to modem in order to activate Caller-ID
this.serialPort1.WriteLine("AT#cid=1" + System.Environment.NewLine);
Handle its DataReceived event and display the received data
void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
richTextBox1.Text += this.serialPort1.ReadLine();
}
Output:
RING //On 1st Ring
DATE = xxxxx //On 2nd Ring
TIME = xxxx
NMBR = xxxxxxxxx
RING //On 3rd Ring
RING //On 4th Ring
P.S. If the telephone line sends DTMF tones as Caller-ID then you need DTMF to FSK converter to detect the number, or else you will receive the rings but not the number.
We are developing WinCE SerialPort Application on .net compact framework 3.5.
In The serialPort Class we have DataReceived event, un fortunately it is firing only once.
Our serialport settings are below:
_com = new SerialPort();
_com.PortName = str_comport;
_com.BaudRate = pBaudRate;
_com.ReadTimeout = 1000 * 10 * 1;
_com.WriteTimeout = 1000 * 10 * 1;
_com.Handshake = Handshake.None;
_com.ReceivedBytesThreshold = 1;
_com.RtsEnable = true;
_com.DtrEnable = true;
_com.Parity = pParity;
_com.DataBits = pDataBits;
_com.StopBits = pStopBits;
_com.DataReceived += new SerialDataReceivedEventHandler(this.Receive);
_com.Open();
....
private void Receive(object sender, SerialDataReceivedEventArgs e)
{
_receivedString = _port.ReadExisting();
_log.WriteFile("RX : " + _receivedString);
}
We have tried opening port first and attaching data received Event also but of no use.
and the same code works fine on Windows XP/Windows 7 Machine.What could be the possible reason.
We need to know more about what your expectation and the data coming in looks like. What does your Receive method look like?
The ReceivedBytesThreshold can be thought of as a trigger point on the input buffer. When the buffer size goes past that, only in a forward direction, you get an event. In this case it means when the receive buffer size goes from 0 to 1 byte, you'll get an event. You won't get one from, say 200 to 201. You don't get an event for every byte either.
So to make this effective, when you receive the event, you need to read all data from the buffer, bringing its size back to zero and effectively "resetting" the event trigger.
I've coin machine acceptor set and I wanna connect this machine using serialport. My main problem is, I did try almost every setting to connect that machine. The pin numbers are written on the cable as 3th and 7th. So I try
private void Form1_Load(object sender, EventArgs e)
{
// SerialPort paraPort defined at designer's generated code
paraport = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
//I wanna access to windows controls from the thread
System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false;
}
private void button2_Click(object sender, EventArgs e)
{
//paraPort is the name of serialport class
paraPort.ReadBufferSize = 1024;
paraPort.WriteBufferSize = 1024;
paraPort.ReadTimeout = 1000;
paraPort.WriteTimeout = 1000;
paraPort.NewLine = "\n";
//Because 7th pin is for RTS which means request 2 send
paraPort.Handshake = Handshake.RequestToSend;
//Data Terminal Ready Enable
paraPort.DtrEnable = true;
paraPort.RtsEnable = true;
paraPort.Open();
//Then Thread check the procedure inside of try - catch block
try{
// Thread money defined at designer's generated code
money = new Thread(new ThreadStart(CheckTheMachineState));
money.Start();
}catch(Exception e){
MessageBox.Show("thread cannot be created"+e.Message);
}
}
private void CheckTheMachineState()
{
richTextBox1.AppendText("Thread is running\n");
//I wanna get the value of IOCTL_SERIAL_WAIT_ON_MASK
//But I still don't know how
}
}
The machine is working well. But when I use paraPort.ReadBufferSize property, it gives me 0 when the coin accept :S. When I use the paraPort.Read method it throws an timeout exception :\
So What can I do for this stuff ? I'm using portmon tools to catch the coin machine signal.
IOCTL_SERIAL_WAIT_ON_MASK value is changed as SUCESS when I put the coin. How can I catch this value ?
After several days of work, I have figured out how to connect a coin acceptor/validator machine to a PC via serial port using VB6, such that every coin inserted in the slot will trigger a signal that will be caught by the PC.