Hello all, I have been stymied by this problem for way too long and need to resolve it or abandon the platform. I am going to be very verbose in this post so if you are not up for the ride…
The problem I am experiencing happens on a Cerberus, Hydra and Spyder. I have them all using 4.2.
I have an application that is reading a serial port using the rs232 module. The messages are 8 bytes long and they come every 200 ms.
I have an object that aggregates those messages and generates an XML string out of the messages.
I have a timer that every second calls for the XML and writes it to a socket connection.
The program runs for some random amount of time @ 1 or 2 hours and then just stops in the middle of writing the xml to the socket, and by that I mean a random length fragment of the xml document was received by the client. There are no errors, there are no trappable exceptions. The entire thing is hung until I reset. I cannot connect with mfDeploy, I cannot reconnect a new socket, and I cannot try to deploy/debug without a hard (push the button) reset.
I have isolated and run the rs232 module reading the data for 24 hours and it did not fail.
I have Isolated the xml generation code and ran it for 48 hours and it did not fail.
I have isolated the Socket and sent data over it for 24 hours and it did not fail.
When I combine the RS232 and the Socket I get a failure after @ 4 hours.
things I have tried with no effect:
[ul]multiple timers (function specific)
a single timer (and counted ticks for longer things)
multiple threads with while/sleep combinations
a single thread with a while/sleep combination[/ul]
I have thinned the code down to a single page that still fails. I have removed all of the code that handles anything extraneous (heartbeat, socket state etc.). I do not know what else to isolate nor do I know what else to try.
Here is the code:
using System;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Net.NetworkInformation;
using GT = Gadgeteer;
using Serial = Gadgeteer.Interfaces.Serial;
using Gadgeteer.Modules.GHIElectronics;
namespace NetworkAppliance.Hardware.Cerberus
{
public partial class Program
{
private static RS232 _rs232;
private int _byteIndex;
private byte[] _currentMessage;
private readonly NetworkInterface _networkInterface = NetworkInterface.GetAllNetworkInterfaces()[0];
private readonly Gadgeteer.Timer _shortTimer = new GT.Timer(1000);
private Socket _hostSocket;
private Socket _clientSocket;
private Thread _listener;
void ProgramStarted()
{
Debug.Print("Program Started");
_rs232 = new RS232(2);
_rs232.Initialize(19200, Serial.SerialParity.None, Serial.SerialStopBits.None, 8, Serial.HardwareFlowControl.NotRequired);
_rs232.serialPort.Open();
_rs232.serialPort.DataReceived += new Serial.DataReceivedEventHandler(SerialPort_DataReceived);
_networkInterface.EnableDhcp();
while (_networkInterface.IPAddress == "0.0.0.0")
{
Debug.Print("Awaiting IP Address");
Thread.Sleep(1000);
}
Debug.Print(
"DCHP - IP Address = " + _networkInterface.IPAddress + " ... Net Mask = " +
_networkInterface.SubnetMask + " ... Gateway = " + _networkInterface.GatewayAddress);
var localEndPoint = new IPEndPoint(IPAddress.Any, 60504);
_hostSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_hostSocket.Bind(localEndPoint);
_hostSocket.Listen(1);
_listener = new Thread(ListenerLoop);
_listener.Start();
_shortTimer.Tick+=new GT.Timer.TickEventHandler(ShortTimer_Tick);
}
#region Timer Loop
private void ShortTimer_Tick(GT.Timer timer)
{
Debug.Print("Tick: " + DateTime.Now.ToString("%h:mm:ss.fff"));
OneSecondTick();
}
private void OneSecondTick()
{
try
{
if (_clientSocket != null)
{
Debug.Print("Calling Socket Send: " + DateTime.Now.ToString("%h:mm:ss.fff"));
//this string is representative of the xml that is being generated
var message = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<AccutechMessaging xmlns=\"http://www.Accutech.com\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" MessageTime=\"2011-06-01T00:25:48\">\r\n <SecurityEvents>\r\n <TagEvents>\r\n <TagEvent>\r\n <Tag>\r\n <TagId>12</TagId>\r\n <BatteryStrength>LowBatteryStrength</BatteryStrength>\r\n </Tag>\r\n <Zone>\r\n <ZoneId>4</ZoneId>\r\n </Zone>\r\n <EventTypes>\r\n <EventType>ExitPointAlarm</EventType>\r\n <EventType>Loiter</EventType>\r\n </EventTypes>\r\n </TagEvent>\r\n <TagEvent>\r\n <Tag>\r\n <TagId>2</TagId>\r\n <BatteryStrength>LowBatteryStrength</BatteryStrength>\r\n </Tag>\r\n <Zone>\r\n <ZoneId>13</ZoneId>\r\n </Zone>\r\n <EventTypes>\r\n <EventType>ExitPointAlarm</EventType>\r\n <EventType>Loiter</EventType>\r\n </EventTypes>\r\n </TagEvent>\r\n </TagEvents>\r\n <ZoneEvents>\r\n <ZoneEvent>\r\n <Zone>\r\n <ZoneId>4</ZoneId>\r\n </Zone>\r\n <EventTypes>\r\n <EventType>DoorAjar</EventType>\r\n </EventTypes>\r\n </ZoneEvent>\r\n <ZoneEvent>\r\n <Zone>\r\n <ZoneId>13</ZoneId>\r\n </Zone>\r\n <EventTypes>\r\n <EventType>DoorAjar</EventType>\r\n </EventTypes>\r\n </ZoneEvent>\r\n </ZoneEvents>\r\n </SecurityEvents>\r\n</AccutechMessaging>\r\n\r\n";
//******************fails in the middle of the next call****************************
_clientSocket.Send(Encoding.UTF8.GetBytes(message));
Debug.Print("Completed Socket Send: " + DateTime.Now.ToString("%h:mm:ss.fff"));
}
}
catch (Exception ex) // this never gets called even in failure
{
Debug.Print(ex.Message);
throw;
}
}
#endregion
#region Socket Methods
private void ListenerLoop()
{
while (_clientSocket == null) // exit method after socket is found
{
Debug.Print("listening...");
_clientSocket = _hostSocket.Accept();
Debug.Print("Accepted Port 60504 connection from " + _clientSocket.RemoteEndPoint);
_shortTimer.Start();
}
}
#endregion
#region SerialPort Methods
void SerialPort_DataReceived(Serial sender, SerialData data)
{
var bytesToReceive = sender.BytesToRead;
var bytes = new byte[bytesToReceive];
sender.Read(bytes, 0, bytesToReceive);
ProcessByte(bytes);
}
private void ProcessByte(byte[] data)
{
foreach (var currentByte in data)
{
if (currentByte == 0X0A) // dump any in flight message and start new
{
_byteIndex = 0;
_currentMessage = new byte[32];
}
if (_currentMessage != null)
{
_currentMessage[_byteIndex] = currentByte;
_byteIndex++;
if (currentByte == 0X0D)
{
var passingMessage = new byte[_byteIndex];
Array.Copy(_currentMessage, passingMessage, _byteIndex);
HandleMessage(passingMessage, DateTime.Now);
_currentMessage = null;
}
}
}
}
private static void HandleMessage(byte[] bytes, DateTime expireTime)
{
// do nothing -- this would be a call to put the bytes into an object that converts and aggregates them into an xml stream.
}
#endregion
}
}
Any help would be greatly appreciated
Tal