Let's start off with that I have no idea what I'm doing. I've done some fancy C# stuff, but with the arduino I'm clueless. Luckily this is the last assignment I have to do with the arduino, so after this I'm done with it.
I have a Adafruit RFID/NFC shield, to, well, read RFIC/NFC tags. This works perfectly with the Adafruit examples. Now I have it logging the ID of the tag to the serial, and I want my C# program to react to it.
I've looked around on the web for examples, but there isn't really much useful stuff to find about this specific piece. Hence why I'm posting a question here. So far I've tried using the DataReceivedHandler, as well as some other solutions (port.ReadByte();, what is described here and here).
But none of it seems to be working correctly. None of the solutions pick up anything the arduino is returning. I'm using Visual Studio 2015 for both the C# and the Arduino. Fist of all, I can run the C# while another instance of VS is keeping the serial console occupied. It didn't result in an error of any kind, which it apparently should have. Yes, the COM port is the correct one (3 on this computer) and yes, the cable works perfectly.
For the arduino I use the following code:
#include <Wire.h>
#include <Adafruit_PN532.h>
#define IRQ (2)
#define RESET (3) // Not connected by default on the NFC Shield
int ledPin = 11;
uint8_t code[] = { 153, 220, 181, 78, 0, 0, 0 };
boolean firstTime = true;
boolean correct = true;
Adafruit_PN532 nfc(IRQ, RESET);
void setup(void) {
Serial.begin(115200);
Serial.println("Hello!");
pinMode(ledPin, OUTPUT);
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// Set the max number of retry attempts to read from a card
// This prevents us from waiting forever for a card, which is
// the default behaviour of the PN532.
nfc.setPassiveActivationRetries(0xFF);
// configure board to read RFID tags
nfc.SAMConfig();
Serial.println("Waiting for an ISO14443A card");
}
void loop(void) {
boolean success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
// 'uid' will be populated with the UID, and uidLength will indicate
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
if (success) {
if (firstTime) { Serial.println("First time. Writing shit"); }
Serial.println("Found a card!");
Serial.print("UID Length: ");Serial.print(uidLength, DEC);Serial.println(" bytes");
Serial.print("UID Value: ");
for (uint8_t i=0; i < uidLength; i++)
{
Serial.print(" 0x");Serial.print(uid[i], HEX);
if (firstTime) {
//code[i] = uid[i], HEX;
};
}
/*Serial.println("");
for (uint8_t i = 0; i < uidLength; i++) {
Serial.println(uid[i], HEX);
uint8_t temp = uid[i], HEX;
String temp = "0x" + uid[i];
}-*/
firstTime = false;
Serial.println("");
Serial.println("Let's check it: ");
digitalWrite(ledPin, HIGH);
for (uint8_t i = 0; i < uidLength; i++) {
//Serial.print("Looking for: "); Serial.println(code[i], HEX);
Serial.print("Found: "); Serial.println(uid[i], HEX);
if (code[i] == uid[i]) {
Serial.println("Found match!");
correct = true;
}
else {
Serial.print("Wanted: "); Serial.println(code[i], HEX);
correct = false;
}
}
if (correct) {
Serial.println("Complete code is correct!");
}
// Wait 1 second before continuing
delay(1000);
}
else
{
// PN532 probably timed out waiting for a card
Serial.println("Timed out waiting for a card");
}
}
Yes, this is nearly identical to the adafruit test programs, and no, that doesn't matter. I just need to get this working before Tuesday. I still need to change that the arduino only passes the ID to the serial monitor, but that is something to do when it can communicate with the C#. It needs to communicate in both ways:
The ID needs to be picked up by the C#
The C# will return a bool, and the arduino needs to act based on that bool
But I can't get the C# to work with the SerialPort. Can someone help me with how I should approach the serial communication from both ends?
A friend just worked this out for me. It's dirty, but it gets the job done.
SerialPort serial;
public Form1()
{
InitializeComponent();
serial = new SerialPort();
serial.PortName = "COM4";
serial.BaudRate = 9600;
serial.DtrEnable = true;
serial.Open();
Timer timer = new Timer();
timer.Interval = 1000;
timer.Tick += new System.EventHandler(timer_Tick);
timer.Start();
}
private void timer_Tick(object sender, EventArgs e)
{
String dataFromArduino = serial.ReadLine().ToString();
}
Thanks for the -1 again :p
Related
I grew up with C in the 80's but a complete beginner in c# and object oriented programming so some of you may have a good laugh at this.
I am trying to write a simple application to decode telemetry data from a lab instrument. I plan to write the final code using Windows Forms for look and feel but I made an experimental implementation of the core mechanics as a console app.
The data stream contain 72 byte messages starting with 0x55 0x2f 0x48, then contains payload data and ends with a checksum. I want to "catch" these messages, discard those with bad checksums and decode parts of the payload for display.
The test app work well but simply prints the incoming data. (Although because of its primitive design it does of course take 0x55 in the payload as the start of a new message)
What would be the best practice here? Should I put a state machine into the event handler for the serial port or have a timer that periodically checks the input buffer? I am actually not even sure how to access to the incoming data "outside" the event handler. Any help or pointers would be much appreciated.
The code of my experimental app is this:
using System;
using System.IO.Ports;
namespace Serial_port_experiment_console
{
class Program
{
static void Main(string[] args)
{
var enable_telemetry = new byte[] { 0x55, 0x92, 4, 0x15 };
var disable_telemetry = new byte[] { 0x55, 0x91, 4, 0x16 };
SerialPort sp = new SerialPort("COM12", 9600, Parity.None, 8, StopBits.One);
sp.Open();
sp.Write(enable_telemetry, 0, enable_telemetry.Length); // Start telemetry
sp.DataReceived += port_OnReceiveData;
Console.ReadLine(); // Wait for keyboard RETURN before closing program
sp.Write(disable_telemetry, 0, disable_telemetry.Length); // Stop telemetry
sp.Close();
}
private static void port_OnReceiveData(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spL = (SerialPort)sender;
byte[] buf = new byte[spL.BytesToRead];
spL.Read(buf, 0, buf.Length);
foreach (Byte b in buf)
{
if (b == 0x55) { Console.WriteLine(); } // Start of a new report
Console.Write(b.ToString("X")); // Write the hex code
}
}
}
}
Some encapsulation would help you - I would separate the logic of the reading from the port from the actual line processing into a couple of classes. Something like this:
static void Main(string[] args)
{
Console.WriteLine("Starting reading data");
var reader = new LinesReader();
Console.WriteLine("Reading data...");
try
{
reader.Start();
Console.ReadKey();
}
finally
{
reader.Stop();
}
foreach (var line in reader.ValidLines)
{
line.DoSomethingWithBytes();
}
Console.ReadKey();
}
internal sealed class LinesReader
{
private static readonly byte[] EnableCode = new byte[] { 0x55, 0x92, 4, 0x15 };
private static readonly byte[] DisableCode = new byte[] { 0x55, 0x91, 4, 0x16 };
private readonly SerialPort sp;
private readonly List<LineInput> lines = new List<LineInput>();
public LinesReader()
{
sp = new SerialPort("COM12", 9600, Parity.None, 8, StopBits.One);
lines.Add(new LineInput());
}
public void Start()
{
sp.DataReceived += DataReceived;
sp.Open();
// Start telemetry
sp.Write(EnableCode, 0, EnableCode.Length);
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
LineInput current;
byte[] buf = new byte[sp.BytesToRead];
sp.Read(buf, 0, buf.Length);
for (int offset = 0; offset < buf.Length; )
{
current = GetCurrentLine();
offset = current.AddBytes(offset, buf);
}
}
private LineInput GetCurrentLine()
{
if (lines.Count == 0 || lines[lines.Count - 1].IsComplete)
{
var ret = new LineInput();
lines.Add(ret);
Console.WriteLine($"Starting line {lines.Count}");
return ret;
}
return lines[lines.Count - 1];
}
public IEnumerable<LineInput> ValidLines => lines.Where(e => e.IsValid);
public void Stop()
{
// Stop telemetry
sp.Write(DisableCode, 0, DisableCode.Length);
sp.DataReceived -= DataReceived;
sp.Close();
}
}
internal sealed class LineInput
{
private readonly List<byte> bytesInLine = new List<byte>();
public static byte StartCode { get; } = 0x55;
public bool IsComplete { get; private set; }
public void DoSomethingWithBytes()
{
//Here I'm just printing the line.
Console.WriteLine(bytesInLine);
}
public bool IsValid
{
get
{
if (!IsComplete) return false;
//TODO - checksum (return true if checksum correct)
return true;
}
}
/// <summary>
/// Adds bytes until the end of the array or a 0x55 code is read
/// </summary>
/// <param name="bytes"></param>
/// <returns>The new offset to start the next segment at.</returns>
public int AddBytes(int offset, byte[] bytes)
{
int bytePosition = offset;
while (bytePosition < bytes.Length)
{
var currentByte = bytes[bytePosition];
if (currentByte == StartCode)
{
IsComplete = true;
break;
}
bytesInLine.Add(currentByte);
bytePosition++;
}
return bytePosition;
}
}
It probably isn't best practice to put all the logic in the event handler. I would suggest that port_OnReceiveData should only be concerned with extracting the 72 byte message. Then you might have another method (or possibly another class) which accepts this message and parses it and extracts whatever data it contains and then in turn may pass that data to another method or class for further processing or saving to a database etc.
I would start by developing port_OnReceiveData to reliably capture the incoming messages. I think you should check for sequence 0x55 0x2f 0x48 rather than just 0x55. Presumably 0x55 could also appear anywhere in the payload, not just the start. Can you contact the manufacturer of the device (or check their website) for details of the message protocol?
A serial port is a difficult thing to test so the idea would be to limit the amount of code dependent on the SerialPort logic so that you can test the actual code you care about (i.e. the processing of the message) in isolation. For instance, once you have captured a few of the 72 byte messages you can keep them and use them to develop your unit tests and logic for the code that will parse these messages without your PC or Laptop having to be physically connected to the lab device.
Another thing you can do if you really want to test your logic is to create a virtual serial port and transmit known data. This technique can be used to ensure your logic is capturing the message correctly. For instance, I once had to read data from a variety of medical devices including a heart rate monitor. I then had to plot this data on a graph. It is obviously crucial that this be correct. I created a test app that generated known wave patterns: a sin wave, saw tooth wave, flat line etc all of known amplitudes and frequencies. I created a virtual com port pair and my test app sent this test wave form data into the com port using the same serial port message format as the real device and I was able to validate that the data I captured and output on the screen was identical to my known wave forms.
I found the question interesting, so whipped up a quick example of what I'd (somewhat naively, without too much planning) do in this case.
Pretty idiomatic C#. Something (MySerialMessageReader) is responsible for reading the data, and fires off an event with a nicely parsed message for the consumer to react to.
Hope that helps?
public static class Program
{
public static void Main(string[] args)
{
using (var reader = new MySerialMessageReader())
{
reader.MessageReaceived += (s, e) =>
{
// TODO: Process message / react to it. Probably put it in a queue to be processed
Console.WriteLine("Received a new message: " + Encoding.UTF8.GetString(e.Message.Data));
};
Console.WriteLine("Waiting for data from serial port...");
Console.ReadLine();
}
}
}
class MySerialMessageReader : IDisposable
{
private byte[] mBuffer = new byte[72];
private int mReceivedCount = 0;
private bool mIsReadingMessage;
SerialPort mPort = new SerialPort("COM12", 9600, Parity.None);
public event EventHandler<MessageEventArgs> MessageReaceived;
public MySerialMessageReader()
{
}
public void Start()
{
mPort.DataReceived += Port_DataReceived;
mPort.Open();
}
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (e.EventType == SerialData.Eof)
{
if (mIsReadingMessage && mReceivedCount < Message.MESSAGE_LENGTH)
{
Debug.Fail("Received EOF before an entire message was read.");
return;
}
}
// Put the read buffer into our cached buffer
int n = 0;
while (n < mPort.BytesToRead)
{
var readByte = (byte)mPort.ReadByte();
if (!mIsReadingMessage && readByte == 0x55)
{
mIsReadingMessage = true; // New start of message
}
if (mIsReadingMessage)
{
// We're reading a message, put the message into a temporary buffer
// whilst we read(/wait for) the rest of the message
mBuffer[mReceivedCount++] = (byte)mPort.ReadByte();
}
if (mReceivedCount == Message.MESSAGE_LENGTH)
{
// We've got enough to construct a message
Message m = null;
if (Message.TryParse(mBuffer, ref m))
{
if (this.MessageReaceived != null)
this.MessageReaceived(this, new MessageEventArgs(m));
}
else
{
Console.WriteLine("Invalid message received. Checksum error?");
}
mReceivedCount = 0;
Array.Clear(mBuffer, 0, 72);
}
}
}
public void Dispose()
{
if (mPort != null)
{
mPort.DataReceived -= Port_DataReceived;
mPort.Dispose();
}
}
}
class Message
{
private const int CHECKSUM_LENGTH = 3;
private const int START_INDICATOR_LENGTH = 3;
public const int MESSAGE_LENGTH = 72;
public byte[] Data;
public byte[] Checksum;
private Message(byte[] data, byte[] checkSum)
{
this.Data = data;
this.Checksum = checkSum;
}
public static bool TryParse(byte[] data, ref Message message)
{
if (data.Length != MESSAGE_LENGTH)
return false; // Unexpected message length
if (data[0] != 0x55 || data[1] != 0x2F || data[2] != 0x48)
return false; // Invalid message start
var withotStartIndicator = data.Skip(START_INDICATOR_LENGTH);
var justData = withotStartIndicator.Take(MESSAGE_LENGTH - START_INDICATOR_LENGTH - CHECKSUM_LENGTH).ToArray();
var justChecksum = withotStartIndicator.Skip(justData.Length).ToArray();
// TODO: Insert checksum verification of justChecksum here
// TODO: parse justData into whatever your message look like
message = new Message(justData, justChecksum);
return true;
}
}
class MessageEventArgs : EventArgs
{
public Message Message { get; set; }
public MessageEventArgs(Message m)
{
this.Message = m;
}
}
Edit: You can obviously take this as far as you'd like, with async, queues, and whatever have you. But if you're not reading too much data, it's not such a bad thing to do it all in the event handler (in my opinion).
I need to replicate/port the settings for interfacing with a piece of hardware from an example in C++ to C# using its SerialPort class. Since I am not very familiar with the details of COM-port settings, my question is how to map these settings to those of the SerialPort class:
HANDLE OpenRS232(const char* ComName, DWORD BaudRate)
{
HANDLE ComHandle;
DCB CommDCB;
COMMTIMEOUTS CommTimeouts;
ComHandle=CreateFile(ComName, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(GetLastError()!=ERROR_SUCCESS) return INVALID_HANDLE_VALUE;
else
{
GetCommState(ComHandle, &CommDCB);
CommDCB.BaudRate=BaudRate;
CommDCB.Parity=NOPARITY;
CommDCB.StopBits=ONESTOPBIT;
CommDCB.ByteSize=8;
CommDCB.fBinary=1; //Binary Mode only
CommDCB.fParity=0;
CommDCB.fOutxCtsFlow=0;
CommDCB.fOutxDsrFlow=0;
CommDCB.fDtrControl=0;
CommDCB.fDsrSensitivity=0;
CommDCB.fTXContinueOnXoff=0;
CommDCB.fOutX=0;
CommDCB.fInX=0;
CommDCB.fErrorChar=0;
CommDCB.fNull=0;
CommDCB.fRtsControl=RTS_CONTROL_TOGGLE;
CommDCB.fAbortOnError=0;
SetCommState(ComHandle, &CommDCB);
//Set buffer size
SetupComm(ComHandle, 100, 100);
//Set up timeout values (very important, as otherwise the program will be very slow)
GetCommTimeouts(ComHandle, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout=MAXDWORD;
CommTimeouts.ReadTotalTimeoutMultiplier=0;
CommTimeouts.ReadTotalTimeoutConstant=0;
SetCommTimeouts(ComHandle, &CommTimeouts);
return ComHandle;
}
}
Currently, what I have works for communication, but it is running unstable and the communication with the hardware stalls in long-time endurance/stability tests. Here is the excerpt from the hardware controller factory that sets up the serial port:
private static SerialPort _serialPort = new SerialPort();
private string portName = "COM23";
private int baudRate = 9600;
private Parity portParity = Parity.None;
private int dataBits = 8;
private StopBits stopBits = StopBits.One;
int serialPortReceiveTimeout = 30000;
static private int TxRxBufferLength = 9;
public ControllerFactory()
{
_serialPort = new SerialPort();
_serialPort.PortName = portName;
_serialPort.BaudRate = baudRate;
_serialPort.Parity = portParity;
_serialPort.DataBits = dataBits;
_serialPort.StopBits = stopBits;
_serialPort.ReadTimeout = serialPortReceiveTimeout;
_serialPort.ReceivedBytesThreshold = TxRxBufferLength;
try
{
_serialPort.Open();
_serialPort.DiscardOutBuffer();
_serialPort.DiscardInBuffer();
Controller = new Controller(_serialPort, Address, TxRxBufferLength, ControllerClockFrequency);
} catch { }
UPDATE:
I thought I was going to try and keep the type of controller obscure, but there really isn't any reason to:
It is a TMCM-3110 from Trinamics and you can find the firmware manual here. Furthermore the code example is here, which is linked from the code examples here. I have not yet contacted Trinamics support, as I have only realized that the stability issues that I am having are likely caused by the incorrect COM-settings.
Regarding these stability issues:
By stalling I meant that the software crashes due to some of the data bytes not being received correctly. This causes problems with the checksum value being incorrect (see the example code for details on its calculation) and also leads to serial-port timeout, which eventually causes the process to crash. Unfortunately I have not yet been able to really identify, where the problem stems from, but I suspect it is the wrong serial-port settings.
Here is my C# code that I am using for handling the communication with the TMCM controller. As you can see it is more or less a 1-to-1 port from the C++ code:
static readonly object locker = new object();
private int sendCmdAndCheckResult(byte Address, byte Command, byte CommandType, byte MotorNr, int Value)
{
lock (locker) // this part needs to finish with out another thread interrupting, so that the sent value and the return value belong to the same command from the same thread. See firmware manual.
{
sendCmd(Address, Command, CommandType, MotorNr, Value);
readReturnMessageToBuffer();
checkReturnedStatus();
Thread.Sleep(10);
return getReturnedValue();
}
}
private void sendCmd(byte Address, byte Command, byte CommandType, byte MotorNr, int Value)
{
TxBuffer[0] = Address;
TxBuffer[1] = (byte)Command;
TxBuffer[2] = (byte)CommandType;
TxBuffer[3] = (byte)MotorNr;
TxBuffer[4] = (byte)(Value >> 24);
TxBuffer[5] = (byte)(Value >> 16);
TxBuffer[6] = (byte)(Value >> 8);
TxBuffer[7] = (byte)(Value & 0xff);
TxBuffer[8] = 0;
for (int i = 0; i < 8; i++)
TxBuffer[8] += TxBuffer[i];
Log($"TmclController: Sending COM-Port Buffer: {ByteArrayToString(TxBuffer)}");
if (ComPort.IsOpen)
ComPort.Write(TxBuffer, 0, TxRxBufferLength);
}
private void readReturnMessageToBuffer()
{
byte Checksum = 0;
for (int i = 0; i < TxRxBufferLength; i++)
{
if(ComPort.IsOpen)
RxBuffer[i] = (byte) ComPort.ReadByte(); // read byte for byte synchronously; ReadByte() is block and returns only, when it has read a byte; this method is inefficient, but the easiest way to achieve a blocking read of the returned message; a better way would be to use asychronous reading of serial ports using e.g. the SerialPort.ReceivedBytesThreshold Property and SerialPort.DataReceived Event
}
for (int i = 0; i < 8; i++)
Checksum += RxBuffer[i];
Log($"TmclController: Received COM-Port Buffer: {ByteArrayToString(RxBuffer)}");
if (Checksum != RxBuffer[8])
{
InvalidOperationException er = new InvalidOperationException("Returned Checksum from TMCL controller is incorrect.");
throw er;
}
}
private int getReturnedValue()
{
return (int)((RxBuffer[4] << 24) | (RxBuffer[5] << 16) | (RxBuffer[6] << 8) | RxBuffer[7]);
}
I am a beginner in C# but wrote some code using serial ports (for example an oscilloscope application communicating over the VCP). Unfortunately the easy way (DataReceived event ...) does not work. To make it work you need to write your own background worker getting the data from the stream or just reading the data from the serial port as they arrive. Even the second approach works - I have tested on windows 8M data rate for about two weeks without any problems.
So my Arduino is taking almost 200ms processing a total of 128 bytes. The whole process without writing over the serial port is only taking 25ms.
Why is my Arduino bottlenecking so much?
Arduino
setColor is simply setting the color of the ledstrip using the FastLED library.
void loop() {
if(Serial.available() == 4){
int led = Serial.read();
int r = Serial.read();
int g = Serial.read();
int b = Serial.read();
setColor(led, r, g, b);
Serial.write(1);
if(Serial.available() > 0) Serial.read();
}
}
C#
In a loop I am doing the following to write the data:
attempt:
if (Port.isReady) {
strip.Send(new byte[] { id, c.R, c.G, c.B });
Port.isReady = false;
} else {
goto attempt;
}
public void Send(byte[] bytes) {
port.Write(bytes, 0, bytes.Length);
}
And I read the Arduino response using:
private const int DONE = 1;
public void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e) {
Console.WriteLine("- Serial port data received -");
Console.WriteLine("Nr. of bytes: {0}", port.BytesToRead);
if (port.ReadByte() == DONE) {
isReady = true;
}
port.DiscardInBuffer();
}
Well it all depends on your baudrate. If your baudrate are 9600 you can receive 9600 bit per second, thats 1200 bytes.
So 128/1200 = 0.1066 = 107 ms spend on receiving 128 bytes.
Higher baudrates will give shorter readtime.
Well why is it then taking 200ms you then ask?
My guess is that it is because of the many calls to setColor()
You are calling that once for every 4 bytes so that is 32 times.
I don't know the execution time on that function, but if it's something like 2-3ms you'r hitting that 200ms fast.
Just to explain, I have a dev board that is, on command, shooting out 4 chars (Bytes). The terminal program (RealTerm) i'm using to debug this sees all 4 bytes. I've now moved on to writing the desktop software, and my program is only paying attention to 1 out of 4 bytes sent. TO clarify, i don't know which 1 of 4 bytes (first , last, middle two) but i can find out if its really necessary.
At first I thought the SerialPort.DataReceived event would fire for each byte that was received. This isn't true, I don't know what causes it to fire but its not the receiving of a singular Byte.
So I tried looping over SerialPort.BytesToRead, but this also only gets the first byte, even though it recognizes there are 3 bytes to read (why not 4??)
Its not essential for me to receive this data at the exact time it hits the port, but obviously I dot want to be loosing 3/4 of my data. However it wont always be 4 bytes, that's just what its doing now. I just want to get all bytes that are ready to be read.
Event Handler:
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (comPort.BytesToRead > 0)
{
RxString = comPort.ReadExisting();
RxByte = comPort.ReadByte();
byte[] myByte = new byte[6];
for (int i = 0; i < 6; i++)
{
myByte[i] = 0000000;
}
comPort.Read(myByte, 0, comPort.BytesToRead);
for (int i=0;i<6;i++)
{
if (myByte[i] != null)
{
thisBytes.Add(myByte[i]);
}
}
RxString = RxByte + "";
try
{
this.Invoke(new EventHandler(dealWithByte));
}
catch
{
}
}
}
private void dealWithByte(object sender, EventArgs e)
{
foreach (byte item in thisBytes)
{
RxByte = Convert.ToInt16(item);
string binary = Convert.ToString(RxByte, 2).PadLeft(8, '0');
//processTime(binary);
}
}
I am not a C# person but the code is pretty simple, pseudo code
numBytes As Int = SerialPort1.BytesToRead 'get # of bytes available
buf(numBytes - 1) As Byte 'allocate a buffer
br As Int = SerialPort1.Read(buf, 0, numBytes) 'read the bytes
If br <> numBytes {
Resize(buf, br) 'resize the buffer
}
at this point store the bytes into a list. This list can then be processed for messages.
I am trying to write data to serialport and then wait for the acknowledgement. After ack is received, I write the next set of data.
Please suggest a way of doing this. I tried the below code but before receiving the ack, the writing fires and completes execution.
When I run it in debug mode, it works fine, but when run without breakpoints, it doesnot run properly.
// some data for writing
byte[] data = "xxx";
byte[] data1 = "yyy";
byte[] data2 = "zzz";
// loop to write the above 5 times
int times = 1;
for (int i = 0; i < 20; i++)
{
if (Flag == true)
{
Flag = false;
if (times <= 5)
{
serialPort.Write(data, 0, data.Length);
serialPort.Write(data1, 0, data1.Length);
serialPort.Write(data2, 0, data2.Length);
times = times + 1;
}
}
else
{
MessageBox.Show("Some problem in ack...");
}
}
Flag = true;
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//char[] buffer = new char[4];
//serialPort.Read(buffer, 0, 4);
Flag = true;
}
Are you trying to use Flag as the ack? The logic doesn't make sense. Don't you need to do something like
while (Flag == false)
; //wait for flag to become true after previous write
...write...
Flag = false;
You need a state machine pattern, or at least some way of storing state. By "State" I mean where you are in the process of reading/writing. State machines are a basic design pattern commonly used for communications (or any event driven programs), read up on them a bit:
http://www.codeproject.com/KB/architecture/statepatterncsharp.aspx
http://www.dofactory.com/Patterns/PatternState.aspx
http://en.wikipedia.org/wiki/State_pattern (I don't like the sample they chose here)
Somehow this has worked out,
byte[] data = "Your message to be sent on serial port";
serialPort.Write(data, 0, data.Length);
byte[] buffer = new byte[16];
int vintctr = 0;
while (vintctr < 16)
vintctr += serialPort.Read(buffer, 0, 16);
Debug this and you you can get the reply from the port.