views:

597

answers:

3

Hi, I'm trying to write a small application that simply reads data from a socket, extracts some information (two integers) from the data and sends the extracted information off on a serial port.

The idea is that it should start and just keep going. In short, it works, but not for long. After a consistently short period I start to receive IOExceptions and socket receive buffer is swamped.

The thread framework has been taken from the MSDN serial port example.

The delay in send(), readThread.Join(), is an effort to delay read() in order to allow serial port interrupt processing a chance to occur, but I think I've misinterpreted the join function. I either need to sync the processes more effectively or throw some data away as it comes in off the socket, which would be fine. The integer data is controlling a pan tilt unit and I'm sure four times a second would be acceptable, but not sure on how to best acheive either, any ideas would be greatly appreciated, cheers.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;


namespace ConsoleApplication1
{
    class Program
    {
        static bool _continue;
        static SerialPort _serialPort;
        static Thread readThread;
        static Thread sendThread;
        static String sendString;
        static Socket s;
        static int byteCount;
        static Byte[] bytesReceived;

        // synchronise send and receive threads
        static bool dataReceived;

        const int FIONREAD = 0x4004667F;

        static void Main(string[] args)
        {
            dataReceived = false;
            readThread = new Thread(Read);
            sendThread = new Thread(Send);

            bytesReceived = new Byte[16384];

            // Create a new SerialPort object with default settings.
            _serialPort = new SerialPort("COM4", 38400, Parity.None, 8, StopBits.One);

            // Set the read/write timeouts
            _serialPort.WriteTimeout = 500;

            _serialPort.Open();
            string moveMode = "CV ";
            _serialPort.WriteLine(moveMode);

            s = null;
            IPHostEntry hostEntry = Dns.GetHostEntry("localhost");
            foreach (IPAddress address in hostEntry.AddressList)
            {
                IPEndPoint ipe = new IPEndPoint(address, 10001);
                Socket tempSocket =
                    new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                tempSocket.Connect(ipe);

                if (tempSocket.Connected)
                {
                    s = tempSocket;
                    s.ReceiveBufferSize = 16384;
                    break;
                }
                else
                {
                    continue;
                }
            }

            readThread.Start();
            sendThread.Start();

            while (_continue)
            {
                Thread.Sleep(10);
                ;// Console.WriteLine("main...");
            }

            readThread.Join();
            _serialPort.Close();
            s.Close();
        }

        public static void Read()
        {
            while (_continue)
            {
                try
                {
                    //Console.WriteLine("Read");
                    if (!dataReceived)
                    {
                        byte[] outValue = BitConverter.GetBytes(0);
                        // Check how many bytes have been received.
                        s.IOControl(FIONREAD, null, outValue);
                        uint bytesAvailable = BitConverter.ToUInt32(outValue, 0);

                        if (bytesAvailable > 0)
                        {
                            Console.WriteLine("Read thread..." + bytesAvailable);
                            byteCount = s.Receive(bytesReceived);
                            string str = Encoding.ASCII.GetString(bytesReceived);
                            //str = Encoding::UTF8->GetString( bytesReceived );
                            string[] split = str.Split(new Char[] { '\t', '\r', '\n' });

                            string filteredX = (split.GetValue(7)).ToString();
                            string filteredY = (split.GetValue(8)).ToString();

                            string[] AzSplit = filteredX.Split(new Char[] { '.' });
                            filteredX = (AzSplit.GetValue(0)).ToString();
                            string[] ElSplit = filteredY.Split(new Char[] { '.' });
                            filteredY = (ElSplit.GetValue(0)).ToString();

                            // scale values 
                            int x = (int)(Convert.ToInt32(filteredX) * 1.9);
                            string scaledAz = x.ToString();
                            int y = (int)(Convert.ToInt32(filteredY) * 1.9);
                            string scaledEl = y.ToString();

                            String moveAz = "PS" + scaledAz + " ";
                            String moveEl = "TS" + scaledEl + " ";

                            sendString = moveAz + moveEl;
                            dataReceived = true;
                        }
                    }
                }
                catch (TimeoutException) {Console.WriteLine("timeout exception");}
                catch (NullReferenceException) {Console.WriteLine("Read NULL reference  exception");}
            }
        }

        public static void Send()
        {
            while (_continue)
            {
                try
                {
                    if (dataReceived)
                    {
                        // sleep Read() thread to allow serial port interrupt     processing 
                        readThread.Join(100);
                        // send command to PTU
      dataReceived = false;
                        Console.WriteLine(sendString);
                        _serialPort.WriteLine(sendString);
                    }
                }
                catch (TimeoutException) { Console.WriteLine("Timeout exception"); }
                catch (IOException) { Console.WriteLine("IOException exception"); }
                catch (NullReferenceException) { Console.WriteLine("Send NULL reference exception"); }
            }
        }
    }
}
+1  A: 

It looks like what you're trying to do is send some data, then wait for a response, then repeat. You're using two threads for this and trying to sync them. I think you only need one thread. First send, then wait for a response, then repeat. This will eliminate your thread sync problems.

Jon B
A: 

Heading ##Am now on a Different PC so this looks like an answer whereas is further clarification.

Thanks for the response Jon.

What I'm attempting to do is poll a socket for data, if its there process it and send it to the serial port, else keep polling the socket , repeating this whole process ad nauseum.

My initial attempt used a single thread and I was getting the same problem, which led me to believe that I need to give the serial port some more time to allow it to send the data before giving it more data on the next loop, because once I've sent data to the serial port I'm back polling the socket very hard. Having said that IOExceptions occur after approximately 30 seconds of operation, possibly with what I'm saying is I should see IOExceptions immediately?

My interpretation of the join function, I think, is incorrect, ideally calling readThread.Join from send() would allow read() to sleep while still pumping the COM port, but where I have it seems to put the send() to sleep, which I guess is the calling function?? and not producing the desired result.

Any suggestions would be appreciated. Cheers.

+1  A: 

I've encountered this problem recently as well (and a lot of others have too) - and it's basically a problem with Microsoft's serial port initialization code. I've written a very detailed explanation here if you wish to find out more. I've also suggested a workaround. Hopefully there's enough fuss about this issue such that Microsoft would take notice and fix it asap - perhaps a .NET 4.0 hotfix. This issue has been going on long enough starting .NET 2.0 (first time System.IO.Ports namespace was introduced).

Zach Saw