Read data from serial port device in c# - c#

We need to weigh a bunch of products, and store their weight in a DB.
We have a scale that can be plugged through a serial port, and then we want to scan the product's barcode with a barcode scanner.
I need to write a program that will read the scale data. I have read and followed a bunch of articles on how to do it, but I can't seem to make it work.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace Weighting
{
public partial class Form1 : Form
{
SerialPort port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
public Form1()
{
this.InitializeComponent();
this.port.Open();
this.port.Encoding = Encoding.ASCII;
this.port.Handshake = Handshake.None;
this.port.RtsEnable = true;
this.port.ReceivedBytesThreshold = 1;
this.port.DataReceived += new SerialDataReceivedEventHandler(this.port_DataReceived);
}
~Form1()
{
this.port.Close();
this.port.Dispose();
}
private void button2_Click(object sender, EventArgs e)
{
try
{
char[] data = new char[] { 's', ' ', '\r', '\n' };
this.port.Write(data, 0, 1);
Thread.Sleep(500);
var InputData = this.port.ReadLine();
if (!string.IsNullOrEmpty(InputData))
{
MessageBox.Show(InputData);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var InputData = this.port.ReadLine();
this.BeginInvoke(new Action(() =>
{
MessageBox.Show(InputData);
}));
}
}
}
The DataReceived handler is never fired, and ReadLine() never returns anything.
The specs of the scale can be found here (chapter 10) : http://www.kern-sohn.com/manuals/files/English/FCB-BA-e-0911.pdf
Note that it's very possible that my serial port, or my cable don't work, or that the scale doesn't send data, or whatever (it's been about 15 years since I have used a serial port device). How can y test that everything works ?
Thank you!
Update
The connection parameters have been taken (and interpreted) from an old Excel macro:
With MSComm1
.CommPort = 1
.Handshaking = 0
.RThreshold = 1
.RTSEnable = True
.Settings = "9600,n,8,1"
.SThreshold = 1
.PortOpen = True
End With
This macro supposedly used to work a few years back, but I couldn't make it work myself (the MSComm1 object is not defined).

Your connection setup looks to match the documentation, but your code smells quite a bit (this is nothing against you, the .NET SerialPort is a nightmare to work with!).
You are not setting the SerialPort.NewLine property to Environment.NewLine (CRLF) and it is instead using the default value of \n (LF). This alone doesn't solve the problem, because you would just have a carriage return at end of the result of calling ReadLine().
The real issue is the DataReceived handler. A lot of people recommend using it but through my exhaustive testing it diminishes determinism of results greatly, particularly when communicating in a friendly encoding such as ASCII. Because you initiate the command by sending your s character, I would honestly get rid of it, and just call ReadLine() right after your Write. (You do not need to Thread.Sleep because ReadLine will simply block until the terminated string is read in or a timeout is reached).
Your ReceivedBytesThreshold is set to 1, and that specifies the buffer size to fill before raising DataReceived so you're trying to read a whole line for every byte received (give or take, DataReceived is very unpredictable).
Here's an example of how I would clean it up (in addition to removing the DataReceived handler). I can't be certain if this will clear your problem up, but making these corrections will lead to much easier debugging. As a temporary change to aid with debugging, you could bring your Sleep call back in and call ReadExisting instead of ReadLine and examine what it pulls (if anything) from the buffer.
private void button2_Click(object sender, EventArgs e)
{
try
{
this.port.Write("s");
var InputData = this.port.ReadLine();
if (!string.IsNullOrEmpty(InputData))
{
MessageBox.Show(InputData);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I've just finished writing a library to sit on top of the .NET SerialPort for my company and have run into the same sort of issues (plus a million more) as you. If you would like further clarification feel free to ask.

As pointed out by #user3894601, the problem was solved by using the original cable, and using a USB adapter.

Related

Read Pulse value from Coin selector using Rasbperry PI 4 in C# Console Application

Hello guy i have problem in my code it always says low even i already insert coin in Coin Selector
using System;
using System.Device.Gpio;
using System.Threading;
try
{
Thread.Sleep(1000);
int pin = 16;
using var controller = new GpioController();
controller.OpenPin(pin, PinMode.Input);
while (true)
{
String ButtonState = controller.Read(pin).ToString();
Console.WriteLine(ButtonState); //checking the state if the digital value is changing
Thread.Sleep(1000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Thread.Sleep(10000);
}
This is my current code and I already configure the coin selector.. How can i read the pulse value from the selector?
My wiring is the coin wire is connected to gpio pins (like gpio 16)
I already tried different types of wiring and code but still not working
I believe you are using the wrong pin. GPIO16 = pin36 and pin16 = GPIO23.
https://roboticsbackend.com/raspberry-pi-gpios-default-state/
Here is an picture of the pin layout.
There are multiple libraries that use different layouts so make sure you look at the documentation provided by these libraries.
Good luck!

C# and serial communication how to flush the device to read same data again?

Okay so I am stuck for almost 20 days now in the same problem of a serial communication device. I have a hardware sensor which read tags and returns the tag code number on every read through serial com port 1 or 3.Any of these I use doesn't matter. I am using a program I wrote in c# to play with the incoming data.
Now problem is that if forexample:
my sensor reads tag with code "e2 0 10 1 83 10 1 23 7 0 d0 c0 1 be"
It will not read this tag again unless I switch of the sensor and turn it on again (Power reset) . So I can't figure out how to make my sensor forget all the data it read till I closed the port. ANY ONE CAN HELP PLEASE I AM DESPERATE NOW
Some one told me that we need to write to device with some commands but he didn't know more than that.
Here is the current code:
void IntializeSensor()
{
try
{
if (mySerialPort==null)
{
mySerialPort = new SerialPort("COM3");
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.ReadTimeout = 2000;
mySerialPort.Handshake = Handshake.None;
LoglistBox.Items.Add("--Port Intilalized at COM1--");
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void OpenPort()
{
try
{
str = "";
if (mySerialPort.IsOpen)
{
ClosePort();
Thread.Sleep(6000);
}
mySerialPort.Open();
LoglistBox.Items.Add("--Port Opened at COM1 Success--");
}
catch (Exception ex)
{
LoglistBox.Items.Add("--Port Opened Failed--Error: "+ex.Message);
}
}
void ClosePort()
{
try
{
mySerialPort.Write("ABCABCABCABCABC");
mySerialPort.DiscardInBuffer();
mySerialPort.DiscardOutBuffer();
mySerialPort.Dispose();
mySerialPort.Close();
LoglistBox.Items.Add("--Port Closed at COM1 Success--");
}
catch (Exception ex)
{
LoglistBox.Items.Add("--Port Closed Failed--Error: " + ex.Message);
MessageBox.Show(ex.Message);
}
}
private void DataReceivedHandler(object sender,SerialDataReceivedEventArgs e)
{
try
{
if (e.EventType != SerialData.Chars) return;
SerialPort COMPort = (SerialPort)sender;
int bytes = COMPort.BytesToRead;
//create a byte array to hold the awaiting data
byte[] comBuffer = new byte[bytes];
//read the data and store it
COMPort.Read(comBuffer, 0, bytes);
// System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
str = ByteArrayToHexString(comBuffer);
holdfirstvalue += str;
//str = str +" "+ str;
//MessageBox.Show("after concat "+str);
if (str.Contains("FF") || str.Contains("F F") || str.Contains("F"))
{
SetText(holdfirstvalue.ToString());// ONE TAG CODE SENT TO BE SET IN LIST
str = "";
holdfirstvalue = "";
}
}
catch (Exception ex)
{
// LoglistBox.Items.Add("--Port Opened Failed--Error: " + ex.InnerException);
MessageBox.Show(ex.Message+" "+ex.InnerException);
}
}
As I understood from your comments, even the program that is shipped with it does not read the same bar-code twice in a row. Am I right?
To me it seems that "the tag reader manufacturer" may have put that mechanism intentionally to prevent user mistakenly scan an item twice at check-out. because it happens a lot that a same stays on the scanner or be crossed against the scanner couple of times when moving things around.
Unless you have access to the scanner Firmware and are able to make changes yourself, I'd say contact the manufacturer. I would contact the manufacturer and ask about this directly. There should be a command that tells the scanner to "Get out of lock mode and restart scanning again" for the special case of scanning a same item several times (e.g. buying multiple similar things.)
They should provide you with a manual with the list of all the commands you can send to your device and you use this commands to build up your system.
One more thing to try! can you scope out your serial port using "Real Term" or any other terminal monitoring application to see if the scanner sends the code to the PC after you scan the same item again or not? This helps you to isolate the problem to make sure if it is the Scanner Firmware or the desktop software. (it seems to me that it is the scanner Firmware ignoring the item because you say it works fine when you reset it)
edit: also I see you are reading your serial port based on DataREadyEvent, again, if it was me, I would add another thread with a very short delay say 20ms or 50ms to keep reading the serial port constantly. there are plenty of examples on how to implement this on the net, one simple and quick way of this is described here:
Read com ports using threading in c#
Hope it helps.
Ok so I finally found the code in hex which actually resets the sensor.
So to help anyone out there who bought Middle Range UHF RFID Reader or any type of this model.
What we did is we hacked into the wires of serial port by soldering copper wire on data pins. Then we attached the other end of those copper wires to my laptop and used the terminal reader "Putty" to see what is actually being sent by the PC to the Reader on RESET HEAD button click.
This way we found the hex code , converted it to byte array and here is the C# code to write it to reader device by serial port and resets the device:
{
mySerialPort.Open();
byte[] bytesToSend = StringToByteArray("A00265F9");// correct command to reset READER
mySerialPort.Write(bytesToSend, 0, 4);
}
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}

unity freezes due to use of system.IO.ports.serialport

I am using a c# script to send things over serial. Everything works out fine. The other end is getting all the right data. Problem is, it only works for about 110 to 30 seconds, then unity freezes. I know that this is better suited for the unity forums, but i dont seem to get any replies there, so i have come here.
code below:
using UnityEngine;
using System.Collections;
using System.IO.Ports;
public class NewBehaviourScript : MonoBehaviour {
byte[] StepperAngle = new byte[1];
short servoAngle = 0;
byte[] servoArray = new byte[2];
SerialPort sp = new SerialPort("COM4", 9600);
// Use this for initialization
void Start () {
sp.Open();
sp.ReadTimeout = 1;
}
// Update is called once per frame
void Update () {
StepperAngle[0] = (byte)(transform.localEulerAngles.y * 50/360);
servoAngle = (short)(transform.localEulerAngles.z* 10e8); // turn fl2oat into short. short is split right down center
servoArray[0] = (byte)(servoAngle/10e8);
servoArray[1] = (byte)(servoAngle % 10e8);
sp.Write(StepperAngle,0,1);
//try{
//print(StepperAngle[0]);
//}catch(System.Exception){
//print("stupid " + stepperAngle);
//}
}
}
and also, the culprit IS the line sp.Write(StepperAngle[0]); When commented out everything goes fine.
Yaay. It seems that the issue was not in fact the sp.Write(); call but in fact was the input buffer overflowing. It seems that the arduino code was writing and the unity code was not reading. This caused Unity to freeze up. How removing sp.Write(StepperAngle,0,1); fixed it I have no idea.

Cannot convert from SharpPcap.RawCapture to PacketDotNet.Packet

I've been following the guide over at http://www.codeproject.com/KB/IP/sharppcap.aspx for implementing a simple packet sniffer to automate authentications for me, I've managed to get to the Filtering section, and have had to make some adjustments to the tutorial code so far for it to work, but I am now stumped.
The error I am receiving is;
The best overloaded method match for 'PacketDotNet.TcpPacket.GetEncapsulated(PacketDotNet.Packet)' has some invalid arguments
Argument 1: cannot convert from 'SharpPcap.RawCapture' to 'PacketDotNet.Packet'
But I've yet to make any references to PacketDotNet my self (everything so far has been SharpPcap).
Entire code I have so far is included, the problem is in the device_OnPacketArrival() function.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PacketDotNet;
using SharpPcap;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string ver = SharpPcap.Version.VersionString;
Console.WriteLine("SharpPcap {0}, Example1.IfList.cs", ver);
// Retrieve the device list
CaptureDeviceList devices = CaptureDeviceList.Instance;
// If no devices were found print an error
if (devices.Count < 1)
{
Console.WriteLine("No devices were found on this machine");
return;
}
// Extract a device from the list
ICaptureDevice device = devices[0];
// Register our handler function to the
// 'packet arrival' event
device.OnPacketArrival +=
new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival);
// Open the device for capturing
int readTimeoutMilliseconds = 1000;
device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
// tcpdump filter to capture only TCP/IP packets
string filter = "ip and tcp";
device.Filter = filter;
Console.WriteLine();
Console.WriteLine("-- The following tcpdump filter will be applied: \"{0}\"",
filter);
Console.WriteLine("-- Listening on {0}, hit 'Enter' to stop...",
device.Description);
// Start capturing packets indefinitely
device.Capture();
// Close the pcap device
// (Note: this line will never be called since
// we're capturing indefinitely
device.Close();
}
private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
{
var tcp = TcpPacket.GetEncapsulated(e.Packet);
}
}
}
A SharpPcap.RawPacket is used to hold the raw data captured over the network adapter but PacketDotNet needs the packet parsed before the GetEncapsulated() methods will work. The step you need will look like:
var packet = PacketDotNet.Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data);
Then you can extract the encapsulated TcpPacket via the GetEncapsulated() method by passing it packet.
Example 12 in the SharpPcap source download at https://sourceforge.net/projects/sharppcap/ shows the syntax and how packets can be modified.
Keep in mind that PacketType.GetEncapsulated() is returning a reference to that portion of the packet so modifying it will alter the original packet.
As an update to Chris Morgan's answer (because I find myself doing this today), getEncapsulated() is now obsolete, instead you should use packet.Extract() to extract the encapsulated packet.
Alternatively, you can use Pcap.Net, which only has one Packet class that you can dynamically parse to get whatever it may contain without doing any packet cast.
You just get a Packet object and do (for example):
uint sequenceNumber = packet.Ethernet.IpV4.Tcp.SequenceNumber;
No need to cast it or know what kind of packet it is in advance, all parsing is done dynamically.

Serial Port - Open errors

When opening a serial port, the device I am trying to access may not have a baudrate of 9600 set so I will have to go thru each baudrate until the device opens correctly.
What error, ArgumentOutOfRangeException or an IOException or some other, should I look for after performing the Port.Open ? Or do I perform this check using the PortOpen statement ?
Sorry to have to ask all of these simple questions, but I am unsure how else to get the information ?
Is there any way that I can tell how to use the PortOpen procedures correctly, including the error handling too, so that I dont have to keep asking everyone ?
Thanks, George.
IOException
InvalidOperationException
is what You should receive in case of errors.
Here You have great example in C#:
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.open.aspx
You could find all exceptions explanation down there.
For more general advice, have a look at the System.IO.Ports namespace which has a more complete example. Personally I'd adapt what they have there to set your general port settings and then try a few different baud rates in debug mode (some bad, one known good). You'll very quickly see what a bad configuration gives vs a good one. I'm assuming you have access to test the device here?
It's worth noting that you won't see any problems with the call to open the port (just opening it will only test that you've set some parameters which the port supports). You'll start to see issues when you try and read/write to the device and it's there that you'll want to do the error checking for a valid baud rate.
[EDIT] Try something along these lines (NOTE: I've not tested this with any hardware but it at least compiles):
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO.Ports;
namespace SerialPortExperiments
{
class Program
{
public static void Main()
{
// Create a new SerialPort object with default settings.
SerialPort _serialPort = new SerialPort();
// Set some generic settings
SetBasicSettings(ref _serialPort);
// Try and find something valid
int baudRate = FindValidBaud(ref _serialPort);
if (baudRate > 0)
{
Console.WriteLine(String.Format("Found baudrate: {0}", baudRate));
}
else
{
Console.WriteLine("ERROR: Failed to identify baudrate");
}
}
public static void SetBasicSettings(ref SerialPort port)
{
port.PortName = "COM1";
port.Parity = Parity.None;
port.DataBits = 8;
port.StopBits = 0;
port.Handshake = Handshake.None;
port.ReadTimeout = 500;
port.WriteTimeout = 500;
}
public static int FindValidBaud(ref SerialPort port)
{
bool buadrateIdentified = false;
// Pick some baudrates to try
List<int> baudrates = new List<int>();
baudrates.Add(9600);
baudrates.Add(19200);
// Try and open the port at each baud rate in turn, trying one write/read to verify success
for (int i = 0; i < baudrates.Count; i++)
{
// Pick a baud rate
port.BaudRate = baudrates[i];
// Try opening a connection and exchanging some data
port.Open();
buadrateIdentified = AttemptValidExchange(ref port);
port.Close();
if (buadrateIdentified)
{
return port.BaudRate;
}
}
return -1;
}
public static bool AttemptValidExchange(ref SerialPort port)
{
try
{
// Send a test command
port.Write("SOME_TEST_COMMAND");
// Check to see what the device responded with
const int expectedReturnLength = 1024;
byte[] buffer = new byte[expectedReturnLength];
port.Read(buffer, 0, expectedReturnLength);
if (buffer.ToString().Equals("EXPECTED_RETURN_VALUE"))
{
return true;
}
}
catch (TimeoutException) // NOTE: You'll probably need to catch other exceptions like parity errors here
{
}
return false;
}
}
}

Categories

Resources