Endless while loop while polling data out of received bytes - c#

I use some third party code from which i thought it worked...it is a loop which is polling some data out of the received Socket-bytes with a ByteBuffer and has to react to the timeout in case when the NetworkTpdu is null, but it doesn't! The while-loop is endless...Somebody an idea?
int start = Environment.TickCount;
int myTimeout = 5000;
while (NetworkTpdu.CreateFromBuffer(_receiveBuffer, false) == null && (!_masterMode || Environment.TickCount - start < myTimeout))
{
_receiveBuffer.WaitForByte(myTimeout, false);
}

it will probably be easier to find the problem if you split the method into separate statements. For example:
var sw = Stopwatch.StartNew();
var timeout = TimeSpan.FromSeconds(5);
while (true)
{
var buffer = NetworkTpdu.CreateFromBuffer(_receiveBuffer, false);
if (buffer != null)
{
Console.WriteLine("Buffer is not null");
return;
}
if (_masterMode)
{
if (sw.Elapsed > timeout)
{
Console.WriteLine("Timeout!");
return;
}
}
Console.WriteLine("Wait for byte: " + sw.ElapsedMilliseconds);
_receiveBuffer.WaitForByte(timeout.TotalMilliseconds, false);
// Check if WaitForByte succeeded or timed out, and handle the result
}
This should make it easy to find the problem:
Wait for Byte is not printed -> CreateFromBuffer never returns
Wait for Byte is only printed once -> WaitForByte never returns
Wait for Byte is printed with a value over 5000 -> _masterMode is false
Edit: As canton7 mentioned in the comments, you can do the same thing with a debugger by placing breakpoints or tracepoints at appropriate places. This is merely a way to make the execution order more apparent.

Related

COM: Device only sends data when things are changing. How to deal with that?

So I want to connect to a device via Serial that only sends data when things are changing with the settings on the device (a measuring device).
I use C# and .Net's SerialPort.
I am able to read data and it looks kind of good. But there are a few problems I encountered.
I realized my reading- method (ReadExistingData()) so that it will constantly use the SerialDataReceivedEventHandler when there's new data.
Unfortunately, when I read it like that (probably because of varying package sizes) it will read very chaotically and thus I need to "catch" the first initiating byte (here it's 0xA5).
That means, I always check whether the byte I just received is a 0xA5 and if it is, I read the rest.
But I feel like that way I am missing some commands my device sends me and thats why I cant display the data consistently right, only from time to time.
On a side note: The device sends the device time and a value. The value is delayed and kind of unaccurate, but the time is always right on spot. The other parameters it sends are always weirded out and dont seem to be recognized and thus changed at all.
To display data I use the console for testing purposes, and the whole construct seems to be very reactive to Console outputs.
Here's a little code snippet:
class Device
{
private int stdMessageLengthInBytes = 5;
public DeviceData processedData;
byte[] dataBuffer;
int receivedMessages = 0;
public Device()
{
// Initialize BaseClass (SerialPort derivative)
this.port = new System.IO.Ports.SerialPort();
// Initialize Device
this.data = new byte[stdMessageLengthInBytes];
this.processedData = new P8005_Data();
dataBuffer = new byte[stdMessageLengthInBytes];
}
// Is supposed to read the data from serial port
protected override void ReadExistingData()
{
// Check whether buffer is empty -> Try to catch a 0xA5
if (dataBuffer[0] == 0x00)
{
port.Read(dataBuffer, 0, 1);
}
// If no 0xA5 was catched, restart
if (dataBuffer[0] != 0xA5)
{
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
return;
}
// Read next byte -> Command byte
port.Read(dataBuffer, 1, 1);
// If command was empty, restart
if (dataBuffer[1] == 0x00)
{
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
return;
}
// If its time that is communicated: Read 3 bytes
if (dataBuffer[1] == 0x06)
{
// 4 ms delay seems to be needed otherwise it wont function correctly somehow
System.Threading.Thread.Sleep(5);
port.Read(dataBuffer, 2, 3);
// Write buffer to actual raw data byte array
this.data = dataBuffer;
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
}
// Otherwise: Just read 2 bytes
System.Threading.Thread.Sleep(5); // Needed delay
port.Read(dataBuffer, 2, 2);
// Write buffer to actual raw data byte array
this.data = dataBuffer;
dataBuffer = new byte[stdMessageLengthInBytes]; // Reset buffer
}
// Method called by SerialDataReceivedEventHandler
protected override void DataReceivedOnComPort(object sender, SerialDataReceivedEventArgs e)
{
bool valid = false;
ReadExistingData(); // Read data from COM- Port
lock (processedData)
{
switch (data[1]) // Check command byte
{
// Time (3 btyes)
case (0x06):
processedData.currentTime = String.Format("{0:D2}:{1:D2}:{2:D2}", DecodeBcd(data[2]), DecodeBcd(data[3]), DecodeBcd(data[4]));
valid = true;
receivedMessages++;
break;
// Value (2 bytes)
case (0x0D):
double val = 0;
val += DecodeBcd(data[2]) * 100;
val += DecodeBcd(data[3]);
val /= 10;
processedData.currentValue = val;
valid = true;
receivedMessages++;
break;
// ... here are various other hex- code that represent a command from the device (2 btyes)
default:
valid = false;
break;
}
}
// only to check when
if (valid)
{
Console.WriteLine("Received Valid Messages: {0}", receivedMessages);
ConsoleOutput();
}
}
}
On a note: The initialization of the port happens in another method from the base class and works fine.
Is there anything I am missing? How to deal with something like that? Are there any improvements that would help improving my performance? I thought about threading with locks, but I dont think that is the solution somehow... Or maybe everything is just a console problem?
EDIT:
I know changed my code (as #jdweng suggested) so that I put everything in a buffer (basically List<byte> mainBuffer. Then, I take all bytes in the buffer whenever its possbile and work with them, skimming it for 0xA5. When one is found, I read the command and determine how long the "message" has to be according to it (Time -> +3 bytes, Data -> +2 bytes, Other -> +1 byte). Then I can work off those messages (I put them into a List<byte[]>) and determine my output to my screen.
However, even after outsourcing the chopping up into messages and processing the messages, I still seem to either miss some messages, since some action are just not registered and have a big delay, or my processing is wrong. What I can think of is that because I lock my mainBuffer maybe some data isnt written to it.
Is this really this time critical? There is a software that comes with the device and it doesnt seem to have such big problems with delay and slightly wrong values...
Since you don't have the exact specs and/or an unreliable connection (which with serial data has to be expected) you need to sync to the 0xa5 at every message. I would just run every single byte you receive through a parser while keeping the state of the currently received message.
Make sure you validate your input since there are a bunch of things that can go wrong if you get messed up serial data. For example if there is an 0xa5 in the other message types, you might miss your next message. To prevent that I strongly recommend to either get to the specs if possible or code more logic based on data observations.
private const int MESSAGE_LENGTH = 5;
private const int VALUE_COMMAND = 0x0D;
private const int VALUE_SIZE = 4;
private const int TIME_COMMAND = 0x06;
private const int TIME_SIZE = 5;
private byte[] _message = new byte[MESSAGE_LENGTH];
private int _messagePos = 0;
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var data = new byte[_serialPort.BytesToRead];
_serialPort.Read(data, 0, data.Length);
foreach (var b in data)
{
_message[_messagePos] = b;
if (_messagePos == 0 && b != 0xa5)
continue;
++_messagePos;
if (_messagePos > 2) // if command byte present, process command of any size
ProcessCommand(_message[1]);
}
}
private void ProcessCommand(byte command)
{
if (_messagePos == VALUE_SIZE && command == VALUE_COMMAND)
{
// parse value...
_messagePos = 0;
}
else if (_messagePos == TIME_SIZE && _message[1] == TIME_COMMAND)
{
// parse time...
_messagePos = 0;
}
}

C# Async Array.Copy throwing access violations intermittently

I have a high performance server receiving raw data that needs processing. The following code, which destructs the packet, throws an AccessViolation once every few thousand times it runs. I can't find any others with the same problem. The rest of the time it works fine. But the access violation is fatal and causes this service to be unstable.
Does any one have any idea why the "Array.Copy" line would be throwing an access violation every so often? The fixed keyword should stop the GC from getting rid of the memory?
async public static Task<AsyncProcessWebFrameResult> ProcessWebFrame(SocketAsyncEventArgs SocketEvent, byte[] Packet, int BytesCnt)
{
AsyncProcessWebFrameResult Result = new AsyncProcessWebFrameResult() { BytesProcessed = 0, Result = ProcessResults.Failed };
ProtocolCommands? CommandType = null;
int WebFrameSize = Marshal.SizeOf(typeof(WebFrameStruct));
//do we at least a enough bytes for a frame?
if (BytesCnt < WebFrameSize)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: Invalid length.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = BytesCnt;
return Result;
}
int StartIdx = 0;
//frame start with SOD?
int BytesToCheck = Math.Min(BytesCnt+2, Packet.Length);
while (StartIdx < BytesToCheck && Packet[StartIdx] != 0xA5)
StartIdx++;
if (StartIdx > 0 && StartIdx < BytesCnt - 1)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: Does not start with SOD. Discarding " + StartIdx +" bytes");
Result = await ProcessWebFrame(SocketEvent, Packet.Skip(StartIdx).ToArray(), BytesCnt - StartIdx);
Result.BytesProcessed += StartIdx;
return Result;
}
else if (StartIdx == BytesCnt-1)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: SOD not found discarding all.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = BytesCnt;
return Result;
}
else if (StartIdx != 0)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: SOD not found discarding all.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = BytesCnt;
return Result;
}
byte[] Payload = new byte[0];
try
{
unsafe
{
fixed (byte* pFirstByte = &(Packet[0]))
{
WebFrameStruct* pFrame = (WebFrameStruct*)pFirstByte;
//Have we received the whole packet?
if (BytesCnt < WebFrameSize + pFrame->Size)
{
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Packet: Packet incomplete. Expected: {0}, Received {1}", pFrame->Size + WebFrameSize, BytesCnt));
Result.Result = ProcessResults.AwaitingMoreData;
return Result;
}
//recognised protocol version?
if (((pFrame->Flags >> 4) & 0xF) != PROTO_VER)
{
DebugUtils.ConsoleWriteLine(SocketEvent, "Packet: Invalid protocol version.");
Result.Result = ProcessResults.ProtocolError;
Result.BytesProcessed = 1; //false start of frame, discard SOD
return Result;
}
//We have a valid packet so we can mark the bytes as processed so they get discarded, regardless of the result below.
Result.BytesProcessed = WebFrameSize + (int)pFrame->Size;
//do we have a registered controller for the command type
if (CommandControllers.ContainsKey((ProtocolCommands)pFrame->Type))
{
CommandType = (ProtocolCommands)pFrame->Type;
Array.Resize(ref Payload, (int)pFrame->Size);
if (Payload.Length != (int)pFrame->Size)
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Array size incorrect. Is: {0} Should be {1}", Payload.Length, pFrame->Size));
================================================
Array.Copy(Packet, WebFrameSize, Payload, 0, (int)pFrame->Size); <---- this line throws the exception
=================================================
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Packet is {0} -> sending to controller ", (ProtocolCommands)pFrame->Type));
}
else
{
DebugUtils.ConsoleWriteLine(SocketEvent, string.Format("Packet: No registered controller for Job {0}.", (ProtocolCommands)pFrame->Type));
Result.Result = ProcessResults.NoController;
return Result;
}
}
}
}
catch (AccessViolationException E)
{
Program.HandleFatalExceptions("", E);
}
return Result;
}
The above method is called as follows
await ProcessWebFrame(SocketEvent, RxBuffer.Skip(Offset).ToArray(), RXBufferUsed - Offset);
OK, so I managed to track down the error causing the access violation. It was not in the end Array.Copy it self, but rather the attempt to access pFrame->Size.
I managed to break and debug this and for some (still unknown to me) reason pFrame and pFirstByte pointers no longer point at Packet. Accessing Packet is still possible and all its elements are still correct, but for some reason it appears Packet has been moved. Now I thought this was not possible because of the fixed keyword (I tried all sort of variations) but to no avail.
In the end I decided something was not working with the pointers and the fixed statement, so as a alternative solution I decided to pin and copy the data out of Packet in one statement without using "unsafe", "fixed" and pointers.
I now achieve this using
WebFrameStruct Frame;
GCHandle handle = GCHandle.Alloc(Packet, GCHandleType.Pinned);
Frame = Marshal.PtrToStructure<WebFrameStruct>(handle.AddrOfPinnedObject());
handle.Free();
I decided to do it the managed and "safe" way. No need for unsafe code. Previously it died every 10-50k connections. But I have now run it up to 4.5M connections with no errors. So I will be using this as my solution. Thanks to all for the comments.
This post made me think of using this instead... and I liked it as it avoided the use of "unsafe" code... Reading a C/C++ data structure in C# from a byte array

How to validate the message that is receive in socket in C#

First 4 characters represent the length of message.
I want to validate by getting first 4 bit of the received message to find its length and verify whether it matches with the first 4 bit.
For example
First four bit give me 45 and message length is 49 then this is true (45 body + first 4 bit length)
else first four bit give 45 but message length 35 . drop this message. This where the problem is.
Class:
internal static void BeginReceive(this Client client)
{
client.outBuffer.Clear();
client.KindOfMessage = KindMessage.Unknown;
client.MessageLength = int.MaxValue;
using (client.mreBeginReceive = new ManualResetEvent(false))
{
try
{
while (!client.closed)
{
client.mreBeginReceive.Reset();
client.socket.BeginReceive(client.socketBuffer, 0, Const.BufferSize, SocketFlags.None, EndReceive, client);
client.mreInit.SetIfNotNull();
client.mreBeginReceive.WaitOne();
client.mreIsConnected.WaitOne();
}
}
catch (Exception e)
{
client.HandleError(e);
}
}
}
private static void EndReceive(IAsyncResult result)
{
var client = (Client)result.AsyncState;
if (client.closed)
{
return;
}
try
{
var receive = client.socket.EndReceive(result);
if (receive == 0)
{
client.Disconnect();
return;
}
client.ProcessNewData(receive);
}
catch (Exception e)
{
client.HandleError(e);
}
client.mreBeginReceive.SetIfNotNull();
}
internal static void ProcessNewData(this Client client, int receive)
{
lock (client.outBuffer)
{
client.outBuffer.AddRange(client.socketBuffer.Take(receive));
do
{
client.EnvelopeRead();
if (client.outBuffer.Count >= client.MessageLength)
{
var msg = client.outBuffer.GetRange(0, client.MessageLength).ToArray();
client.outBuffer.RemoveRange(0, client.MessageLength);
client.RaiseMessageReceived(msg, client.KindOfMessage);
client.KindOfMessage = KindMessage.Unknown;
client.MessageLength = client.outBuffer.Count >= Const.TotalSizeOfEnvelope ? 0 : int.MaxValue;
}
} while (client.outBuffer.Count >= client.MessageLength);
}
}
and process data as following
internal static void ProcessNewData(this Client client, int receive)
{
lock (client.outBuffer)
{
client.outBuffer.AddRange(client.socketBuffer.Take(receive));
do
{
client.EnvelopeRead();
if (client.outBuffer.Count >= client.MessageLength)
{
var msg = client.outBuffer.GetRange(0, client.MessageLength).ToArray();
client.outBuffer.RemoveRange(0, client.MessageLength);
client.RaiseMessageReceived(msg, client.KindOfMessage);
client.KindOfMessage = KindMessage.Unknown;
client.MessageLength = client.outBuffer.Count >= Const.TotalSizeOfEnvelope ? 0 : int.MaxValue;
}
} while (client.outBuffer.Count >= client.MessageLength);
}
**i change it as **
internal static void ProcessNewData(this Client client, int receive)
{
lock (client.outBuffer)
{
client.outBuffer.AddRange(client.socketBuffer.Take(receive));
List<Byte> a = new List<byte>();
a.AddRange(client.socketBuffer.Take(receive));
totmsglen2 = ((int.Parse(a.GetRange(0, 2)[0].ToString()) * 256) + int.Parse(a.GetRange(0, 2)[1].ToString()) + 2);
if (a.Count != totmsglen2)
{
// this is not valid messge discared it
a.RemoveRange(0,totmsglen2);
}
else
{// valid message process it
client.outBuffer.AddRange(a.GetRange(0,totmsglen2));
a.RemoveRange(0,totmsglen2);
}
do
{
client.EnvelopeRead();
if (client.outBuffer.Count >= client.MessageLength)
{
var msg = client.outBuffer.GetRange(0, client.MessageLength).ToArray();
client.outBuffer.RemoveRange(0, client.MessageLength);
client.RaiseMessageReceived(msg, client.KindOfMessage);
client.KindOfMessage = KindMessage.Unknown;
client.MessageLength = client.outBuffer.Count >= Const.TotalSizeOfEnvelope ? 0 : int.MaxValue;
}
} while (client.outBuffer.Count >= client.MessageLength);
}
}
The code works only for one message and not when continuous messages are received.
Cases:
0010aaaaaaaaa valid
0007asd invalid
0005iiiii valid
For example First four bit give me 45 and message length is 49 then this is true (45 body + first 4 bit length) else first four bit give 45 but message length 35 . drop this message.
The first 4 bytes are the "message length". There's no other way for a server to know when a message completes. So it's not possible to detect a mismatch.
it also not secure for examples if they send the length 500 and message is 200 long then it fail, in this situation
Your protocol will just be waiting for the completion of that message. This is not a failure; it is by design. For example, if a client sends a length of 500 and a message that is 500, but if the packets got broken up, your sever could get a length of 500 with a message that is 200... and then seconds later get the other 300 of the message. That's the way TCP/IP works.
However:
it also not secure
This is true. By following this simple approach, you allow two trivial denial-of-service attacks:
The client sends some huge message length, causing your server to allocate a huge buffer expecting some huge message.
The client only sends a partial message, causing your server to keep that buffer and socket allocated. A distributed attack can successfully consume a lot of your server resources.
To mitigate these attacks, you should do two things:
Have a reasonable maximum message size, and reject any client that tries to send a larger one.
Add an "idle timer" to each socket. Each time you receive data, reset the timer. When the timer goes off, kill the connection. Also, if the client is not sending enough data (i.e., the rate of data is too low for a period of time), then kill the connection.
A simple approach would be to make sure that the receiving logic only passes full messages back. Also you cannot assume that a full message (or even size info) is received always. So you would do something like:
Beginreceive(4 bytes length info) to start things off, then loop through EndReceive and new BeginReceives as long as the 4 bytes are not in.
Then BeginReceive(number of bytes expected) and again loop through EndReceive/BeginReceieve until you have all bytes in. That would be the moment to pass on the message to the decoding logic.

Increasing a timer everytime an evaluation is false

I'm measuring the amount of time certain actions in Internet Explorer take. One of the actions I'm measuring is launching another application via a link in IE. To measure how long this application takes to launch I start a timer after the link has been clicked in IE and I had planned on stopping it once the application had fully loaded. The problem there was that my application would go to execute the next line since the evaluation would always be false as there wasn't enough time between lines for the external app to load.
try
{
Process[] externApp = Process.GetProcessesByName("External");
System.Timers.Timer runningWindow = new System.Timers.Timer(1000);
runningWindow.Start();
while (runningWindow.Enabled)
{
if (externApp[0].Responding)
{
timer.Stop();
output[2] = timer.Elapsed.Seconds.ToString();
runningWindow.Stop();
}
runningWindow.Interval += 100;
}
externApp[0].Kill();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
Above is how I'm currently trying to get my application to hang while I wait for the other application to respond.
Since I wasn't sure how to wait for another application to load I decided to use a timer to postpone the execution of the next line after I check if the other application is running. If the application wasn't running I would increase the timer by a tenth of a second then check again. However the problem I was running into here is that I don't think I'm increasing the timer as my time measurement is always 0 for this step.
So how do I increase my timer if my external application isn't responding?
Albeit unreliable for the reasons explained above in comments you can still use the Process.WaitForInputIdle to get an approximate evaluation of the startup time required by your app
// Launch the external app...
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = #"D:\temp\MyExternalApp.exe";
psi.WorkingDirectory = #"D:\temp";
// Init measure
Stopwatch sw = StopWatch.StartNew();
Process.Start(psi);
Process[] externApp = null;
int cnt = 0;
bool ready = false;
while (externApp == null || externApp.Length == 0 || cnt == 600)
{
// Loop until the process appears in the process list.
// This is taxing for the performances. Heisenberg here
externApp = Process.GetProcessesByName("MyExternalApp");
Thread.Sleep(100);
cnt++;
}
if(cnt >= 600)
MessageBox.Show("Something has gone terribly wrong launching the external app");
else
ready = externApp[0].WaitForInputIdle(30000);
sw.Stop();
if(!ready)
MessageBox.Show("Not ready after:" + sw.ElapsedMilliseconds + " ms");
else
MessageBox.Show("Ready after:" + sw.ElapsedMilliseconds + " ms");
Another approch could be used (still with WaitForInputIdle) if you cannot start a Stopwatch the exact instant in which your external process has been started (like it seems with your comment about starting the ExternalApp through a browseer) In this case we could try to get the start time using the same named property in the Process class
Process[] externApp = null;
int cnt = 0;
bool ready = false;
while (externApp == null || externApp.Length == 0 || cnt == 600)
{
// Again we are waiting to see the process in the list of processes
externApp = Process.GetProcessesByName("MyExternalApp");
Thread.Sleep(100);
cnt++;
}
if(cnt >= 600)
MessageBox.Show("Something has gone terribly wrong launching the external app");
else
{
ready = externApp[0].WaitForInputIdle(30000);
DateTime readyAt = DateTime.Now;
TimeSpan ts = readyAt - externApp[0].StartTime;
MessageBox.Show("Ready after:" + ts.TotalMilliseconds + " ms");
}
You can simply get the Current time before starting IE:
DateTime start = DateTime.Now;
And in the end subtract it from the finish time like:
double SecondsElapsed = (DateTime.Now-start).TotalSeconds;

Reading and writing to arduino at the same time

I have a situation where I read values from sensors (attached to an arduino) which gets stored in a mysql database, which is then displayed on a webpage. At the same time relay values are read from a webpage, stored on mysql and then written to the arduino. I can do each separately but not at the same time. I've attached some code to show what Im trying to accomplish. I think it has something to do with Serial availability
/*----( SETUP: RUNS ONCE )----*/
void setup() {
Serial.begin(115200);
sensors.begin(); //Get DS18B20 temperatures
sensors.setResolution(probe1, 10); //set resolution to 10bit
sensors.setResolution(probe2, 10); //set resolution to 10bit
Wire.begin(); // Start the Wire (I2C communications)
RTC.begin(); // Start the RTC Chip
digitalWrite(Relay_1, RELAY_OFF); //Relays
digitalWrite(Relay_2, RELAY_OFF);
pinMode(Relay_1, OUTPUT); //Set relays as outputs
pinMode(Relay_2, OUTPUT);
}
/*--(end setup )---*/
/****** LOOP: RUNS CONSTANTLY ******/
void loop() {
ReadSensors();
delay(1000);
ReadRelays();
}
/****** Read Sensors ******/
void ReadSensors()
{
DateTime now = RTC.now(); //Get time from RTC
photolevel = analogRead(photopin); //Read light level
sensors.requestTemperatures();
dallas1 = sensors.getTempC(probe1);
dallas2 = sensors.getTempC(probe2);
dtostrf(photolevel, 1, 0, photo1);
dtostrf(dallas1, 1, 2, temp1);
dtostrf(dallas2, 1, 2, temp2);
String tempAsString1 = String(photo1);
String tempAsString2 = String(temp1);
String tempAsString3 = String(temp2);
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(" ");
Serial.println(tempAsString1 + " " + tempAsString2 + " " + tempAsString3);
Serial.flush();
}
void ReadRelays()
{
Serial.flush();
// Read all serial data available, as fast as possible
while(Serial.available() > 0)
{
char inChar = Serial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 79)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
if(started && ended)
{
// The end of packet marker arrived. Process the packet
if (strlen(inData) > 0)
{
char *token = strtok(inData, ",");
if(token)
{
index = 0;
array[index] = atoi(token);
while (token = strtok(NULL, ","))
{
array[index++] = atoi(token);
}
}
}
Serial.println(array[0]);
Serial.println(array[1]);
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
Any suggestions would be well appreciated??
The key to do several things "at the same time" is to understand that the Arduino has only one core. Thus it will process stuff only one step after the other. Now suppose you want to perform three functions "action1()", "action2()" and "action3()" at "the same time. In order to achieve this you must ensure that
all actions can be performed as fast as possible, preferably sub milliseconds
none of them "blocks"
Then the desired effect is achieved by just putting them into succession like so
void loop() {
action1();
action2();
action3();
}
This is the basic idea of "cooperative multitasking". It follows that none of the actions must utilize delay() or blocking waits. For example
while(Serial.available() == 0);
is a blocking wait and must be avoided. Things get more complicated if any of the actions is a set of lengthy and involved computations. Say action1() takes 1s to process. Then action1() must be split into pieces that execute fast enough. The pieces can still be kept in action1() with the help of a "state machine". For example
void action1() {
static uint8_t state = 0;
switch (state) {
case 1: sub_action1_1(); break;
case 2: sub_action1_2(); break;
case 3: sub_action1_2(); break;
default: state = 0; return;
}
++state;
}
Of course the sub actions must perform fast enough. Another frequently encountered issue is how to wait without blocking. This is achieved by storing the required delay. E.g. like this
void action1() {
static uint8_t state = 0;
static unsigned long start_millis = 0;
switch (state) {
case 1: sub_action(); break;
case 2: // this starts the delay
start_millis = millis();
break;
case 3: // this checks if the delay has elapsed
if (millis() - start_millis < 1000) {
// if it did not yet elapse ensure that the state will not progress to the next step
return;
}
// if the delay has elapsed proceed to next state
break;
case 4: next_sub_action(); break;
default: state = 0; return;
}
++state;
}
Of course this is only the basic principle. In "real" implementations you may vary this as needed.
Another often needed thing is to have a main loop that does some stuff and a higher frequency "loop" that does some other stuff. This is usually performed with so called timer interrupts. This is more advanced but usually more efficient also. The tricky thing with interrupts is that they tend to be somewhat harder to debug. I have some documented examples for this in my blog.
blinking several LEDs with different frequencies.
VU Meter experiment (scroll down!)

Categories