COM port communication problems, Text To ASCII - c#

I'm making a simple program, to send information from PC to COM port. So far I have established a connection between the PC and the COM port and I can send information and see what the port received, but I have two problems, the first one is that when I send the info to an actual com port (COM port to USB cable made to echo the signal) the first time I all of the information is received. Then it becomes random, sometimes again, all of what I have written, sometimes only the first character. And sometimes nothing. My assumption is this happens because I haven't put any time-outs or anything at all. Help with this would be nice.
But the real problem that I have is that I want all of the information sent from the textbox to be sent in ASCII code since I'm making the program for communication with PLC.
Here is the code:
public Form1()
{
InitializeComponent();
}
//BTN new serial port creation - port taken from comport text box
private void button1_Click(object sender, EventArgs e)
{
System.IO.Ports.SerialPort sport = new System.IO.Ports.SerialPort(comport.Text, 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
//opening the com port and sending the information from textbox1
try
{
sport.Open();
sport.Write(textBox1.Text);
}
//if there is an error - show error message
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
//Adding timestamp to received info
DateTime dt = DateTime.Now;
String dtn = dt.ToShortTimeString();
//reading the information form the com port
textBox2.AppendText("[" + dtn + "] " + "Recieved: " + sport.ReadExisting() + "\n");
//closing the port
sport.Close();
}

The problem is, you are reading every time you click the button and may not have recieved everything. You should use the SerialPort class' DataReceived event to receive your data. The event fires every time data is received through your COM port, so you can press your button to write to the port then as the data comes in you should see the event fire with your data.
Microsoft has a good definition and example here.
The event is on a separate thread, so to write it to a textbox you may have to invoke it to display it on your gui. See the example code below:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string Data = serialPort1.ReadExisting();
this.Invoke((MethodInvoker)delegate
{
textBox2.AppendText(Data);
});
}

Related

c# with dotras - Status Box not updating automatically after dial connect/disconnect

Greeting,
OS: Windows 7 /64bit
Application: Visual Studio 2012 / C# and DotRas 1.3 Library
I am very new to c# or VS thing so please bear with me. After doing many hours R&D, I have finaly made a pppoe dialer program in C# / Dotras. This program have 3 main buttons
Create /Add PPPoE Internet Dialer Connection in network connections , working fine
Dial button, which connects the newly created dialer , working Fine
Disconnect working fine
I have added StatuBox where dialup events should appear as showed on dotras youtube video tutorial (which was for vpn, but my project is for pppoe dialer)
StatusBox Not updating the dialup events like connecting/password error/connected etc. This is the part where I am finally confused.
Following is my Code.
// Dial Button Action
private void button2_Click_1(object sender, EventArgs e)
{
using (RasDialer dialer = new RasDialer())
{
// I had to add below line to update statusTextBox Manualy , want to get rid of it by adding auto status update
this.StatusTextBox.AppendText(string.Format("{0}\r\n\r\n", "Connection in progress ...", "{0}\r\n\r\n"));
dialer.EntryName = ("pppoe2");
string username = textBox1.Text;
string passwd = textBox2.Text;
// If username is empty dont connect
if (string.IsNullOrWhiteSpace(textBox1.Text))
{
this.StatusTextBox.AppendText(string.Format("{0}\r\n", "Cancelled. Cannot continue with username/password.", "{0}\r\n"));
MessageBox.Show("Enter username.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
dialer.Credentials = new System.Net.NetworkCredential(textBox1.Text, textBox2.Text);
dialer.PhoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.User);
dialer.Timeout = 1000;
dialer.AllowUseStoredCredentials = true;
// start dialing,
dialer.Dial();
// If dialer connects successfully update StatuTextbox
this.StatusTextBox.AppendText(string.Format("{0}\r\n\r\n", "Connected."));
}
}
private void rasDialer1_StateChanged(object sender, StateChangedEventArgs e)
{
this.StatusTextBox.AppendText(string.Format("{0}\r\n", "Status Changed"));
}
private void rasDialer1_Error(object sender, System.IO.ErrorEventArgs e)
{
this.StatusTextBox.AppendText(string.Format("{0}\r\n", "STATUS UPDATE TEXT XYZ"));
}
private void rasDialer1_DialCompleted(object sender, DialCompletedEventArgs e)
{
this.StatusTextBox.AppendText(string.Format("{0}\r\n", "STATUS UPDATE TEXT XYZ"));
}
Any help would be highly appreciable.
Ok I have managed to enable status box text append work fine.
this.Invoke((MethodInvoker)delegate
{
this.StatusTextBox.AppendText(string.Format(e.State.ToString() + "\r\n"));
});
}
Depending on how you were using it, if the background thread from the OS isn’t marshaled back to the UI thread it won’t update. Similarly to what you had done, the SynchronizingObject property on the RasDialer can be set to your form and the thread synchronization will occur automatically.

How to store data through web service when data coming to my serial port will be asynchronous?

I have one device "installed" on a users desk (a desk is nothing but a chair or table on which user will sit), and I will be supporting thousands of desks.
A user will have one "chip" and the user will scan this chip on the device which is installed on their desk.
The device will read the data off the chip and will send it to my laptop which will also have one of the devices installed, except this device is the main device responsible for collecting all user scan chip data.
All the data will be routed to my device via a wifi router and I will listen to this from my Main device and read data from this device from my laptop via serial port connection.
This data sending will happen as each user number scans his/her chip.
I have created a windows form application which will continuously run in the background on my laptop, and will be listening to my serial port on which main device is connected.
This is my code taken from here: Source Code Reference:
public partial class MainUI : Form
{
SerialPortManager _spManager;
public MainUI()
{
InitializeComponent();
UserInitialization();
}
}
private void UserInitialization()
{
_spManager = new SerialPortManager();
_spManager.NewSerialDataRecieved += new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved);
this.FormClosing += new FormClosingEventHandler(MainUI_FormClosing);
}
private void MainUI_Load(object sender, EventArgs e)
{
_spManager.StartListening()
}
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to whom ever interested
if (NewSerialDataRecieved != null)
{
NewSerialDataRecieved(this, new SerialDataEventArgs(data));
}
}
void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
{
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port, and BeginInvoke is good practice anyway.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender, e });
return;
}
//data is converted to text
string str = Encoding.ASCII.GetString(e.Data);
if (!string.IsNullOrEmpty(str))
{
//Here i will store that data in to my database through web service.
//What i should use whether WCF service or Web Api because data will be continuos like at a
//time more than 10 or 100 user can scan data at the same time so this event will be fired continuously.
//I am using entity framework to store data in to my database and how to ansynchornously call web service to store my data
//so that my call doesnt block incoming data to serial port
}
}
My main concern is I will have numerous users who will scan data at the same time and how I will handle when more than 10 or 100 user scan the data at the same time.
How can I mitigate this potential issue?
Ok, if i got the question right you need to do something like this ...
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int dataLength = _serialPort.BytesToRead;
byte[] data = new byte[dataLength];
int nbrDataRead = _serialPort.Read(data, 0, dataLength);
if (nbrDataRead == 0)
return;
// Send data to api
string str = Encoding.ASCII.GetString(e.Data);
if (!string.IsNullOrEmpty(str))
{
var api = new HttpClient();
api.BaseUrl("http://somewhere.com");
api.PostAsJsonAsync("api/Something", str)
}
if (this.InvokeRequired)
{
// Using this.Invoke causes deadlock when closing serial port,
// and BeginInvoke is good practice anyway.
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(
_spManager_NewSerialDataRecieved), new object[] { sender, e
});
return;
}
}
// i think this can go completely ...
void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
That posts the data to webapi but whilst that post is taking place on another thread the serial port can carry on receiving data
close your serial port and load every some-amount-of-time. After that some-amount-of-time open the port and scan all devices, then close it again.
public void MainUI.Load(Object sender, Eventargs e)
{
if (_spmanager != null && !_spManager.IsOpen)
//*write the code here where it opens and starts listening
_spmanager.StartListening();
//*write the code here where it waits a little bit then
_spmanager.Close();
}
Therefore everytime it loads it starts when the port is closed, it opens for a little bit, scans whatever values are true and then closes again.
I am not very sure about this but it is just an idea of how to handle it. The code might not be accurate or currect I just wrote it quickly. Take the idea from this

How to make caller id in c#.net

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.

Checking device status, while receiving data from serial port c#

Life status of device connected via serial port.
Hello everyone.
How can I check if the device responds to the request? I'm googling this for couple days and tried lot of solutions also from SO, but nothing gave me results that I've expected. After lot of tries I'm in point described below. I think I'm very close but now I need little help, so thanks for every answer in advance.
The current situation
What am I doing right now is very simple. First of all I'm opening serial port serialPort.Open() at very beggining of app (data is receiving almost all the application running time).
As this is just an example in my form is only one label called labelStatus and labelStatus.Text = "Not connected"
Next I'm adding a timer and it's tick method, that contains execute of serialPort.Write(). Timer Interval is set to 100 if that matters.
private void timer_Tick(object sender, EventArgs e)
{
if (serialPort.IsOpen)
{
serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
}
}
Next step is create DataReceived event like below (very simplified version, in my app received data is parsing to floats and storing in array, but it's just to show the problem)
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
One last thing is create ErrorReceived method.
private void serialPort_ErrorReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Not connected"));
}
Untill now everything works brilliant. Sending data works. DataReceived event is executig each 100 miliseconds when data is send. My data is received properly with no problems. When I start application labelStatus text is "Not connected" (device cable is not plugged in). When I plugged in device labelStatus text changing to "Connected". But now when I plugged of cable ErrorReceived event is not executing and labelStatus text is still "Connected". So as I've asked before: How can I check is device still connected to computer? (Or maybe: how to execute ErrorReceived event, when data is not receiving?).
Note: Serial port ReadTimeout is set to 300 miliseconds.
What have I tried
I've tried lot of things but this one in my head seems to should work but doesn't.
I've modified DataReceived event and I've put serialPort.ReadLine() into try/catch block with TimeoutException where I've tried to manually execute ErrorReceived method like below
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
try
{
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
catch (TimeoutException)
{
serialPort_ErrorReceived(null, null);
}
}
I was hoping that will work like I want.
BTW. Sorry for my English. It's not perfect, but I do my best. Cheers!
Listen to the WM_DEVICECHANGE event that will be fired when a device is removed or inserted.
Here is an example of a implementation and some more information:
Detect serial port insertion/removal
http://www.codemiles.com/download/file.php?id=719 (USB Sample)
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx
This is solution in my case
Regarding to Martjin's answer i need to further explain my situation. First of all I want to say that I'm not installing any hardware into my computer, so in my opinion WM_DEVICECHANGE event was not what i need (but of course thanks for information, I've learned something new). Application is reading data from scale. Scale after plug into com port is not sending any data and actually there's no communication between it and computer at all. The only way to read data is to send request to scale, so I have to rely on that.
First try
The plan:
Add two static int fields (flags) checkOld and checkNew,
increment checkNew in DataReceived, check in timer Tick method
is checkOld is equal to checkNew. If true that means checkNew
was not increment, and that means DataReceived was not executed.
`
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
checkNew++;
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
private void timer_Tick(object sender, EventArgs e)
{
if (serialPort.IsOpen)
{
serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
}
if (checkOld == checkNew)
{
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Not connected"));
}
}
`
The plan was good but when I've tested it result was not even good. What happened? Actually device status was blinking connected-not connected-connected-not connected etc. I've wrote some data to output and get answer. The timer was looping so fast that DataReceived event could not always increment checkNew value.
Final solution
Based on what I had at the moment I've decided to add some little changes. Instead of comparing two integers values try to collect couple last values ad check if all were the sem or not.
The plan:
Add three static fields: first six elements array of integers
statusArray, second integer index with value equals to 6 (last
element of array + 1), third integer checkNew,
increment checkNew in
DataReceived event,
in timer Tick event fill array to index,
decrement index value untill whole array is filled, and if index == 0 reset index value to
6,
and last check if last six values of checkNew, stored in
statusArray are the same. If true that means DataReceived did not
executed six times in a row, and now I can be sure that connection is
lost.
`
static int index = 6;
static int checkNew = 0;
static int[] statusArray = {0,0,0,0,0,0};
private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
checkNew++;
string someVariable = serialPort.ReadLine();
labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
//If i received something that means the device is plugged in and connection is correct (still very simplified)
}
private void timer_Tick(object sender, EventArgs e)
{
if (serialPort.IsOpen)
{
serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
}
if (index == 0)
index = 6;
index--;
int value = statusArray[index] = checkNew;
}
`

serialport connection for unknown device

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.

Categories

Resources