3

After much research I am still stumped. I have a serial port object which is reading data continuously. What I am able to do it generate the dataReceived event, communicate with the port, and output the received values to the debug window. So, I'm pretty sure it's all working physically. The problem is when I try to pass the serial port output to my original thread I get an error. It says I can't have thread cross talk (or something to that effect). I've been trying to use a backgroundWorker but I'm not sure that is the solution I want plus with my novice skills it's a little over my head. And I tried to use invoke but the method doesn't seem to be available. (I might be calling from the wrong object?) Anyway section is below.

namespace Photometer
{
    class csRadiometerILT1700
    {
        //manufacturer specs for baud rate, databits, and stop bits
        static string portName="COM1";
        static int baudRate = 1200;
        static int dataBits = 8;
        //instantialize a serial port object for the Radiometer
        private SerialPort RadiometerSerial = new SerialPort(portName, baudRate, Parity.None, dataBits, StopBits.One);


        //constructor
        //public csRadiometerILT1700(Form ParentForm, Chart outputChart)
        public csRadiometerILT1700()
        {


            //two handshaking properties of the ILT1700. Handshaking is enabled and 
            //http://stackoverflow.com/questions/6277619/problem-reading-serial-port-c-net-2-0-to-get-weighing-machine-output
            RadiometerSerial.Handshake= Handshake.RequestToSend;
            RadiometerSerial.DtrEnable = true;

            RadiometerSerial.DataReceived += new SerialDataReceivedEventHandler(RadiometerSerial_DataReceived);

        }

        public void openPort()
        {
            if (!RadiometerSerial.IsOpen)
            {
               RadiometerSerial.Open(); 
            }

        }
        public void closePort()
        {
            RadiometerSerial.Close();
        }

        string RadiometerVoltageReadingString;
        int RadiometerVoltageReadingInt;
        private void RadiometerSerial_DataReceived(object sender, SerialDataReceivedEventArgs e) 
        {
            //It's here that this.invoke()... cannot be called.

            RadiometerVoltageReadingString= (RadiometerSerial.ReadExisting().ToString());    //y-value
            Debug.Print(RadiometerVoltageReadingString.ToString());

            makeRadioReadingDouble(RadiometerVoltageReadingString);

        }

        private void makeRadioReadingDouble(string inputVoltageString)
        {

            List<double> outputVoltageDouble=new List<double>(2);


            if (!(inputVoltageString == "\r\n" || inputVoltageString == ""))
            {
                string[] voltageValAndExpo = inputVoltageString.Split(new string[] { "e", "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

                for (int inCounter = 0; inCounter < voltageValAndExpo.Count(); inCounter=inCounter+2)
                {
                    double voltageVal = Convert.ToDouble(voltageValAndExpo[inCounter]);
                    double voltageExpo = Convert.ToDouble(voltageValAndExpo[inCounter + 1]);

                    outputVoltageDouble.Add(Math.Pow(voltageVal, voltageExpo));
                }
            }
        }

    }
}

This is all called when I form loads with the code

            csRadiometerILT1700 Radiometer;

            ...

            Radiometer = new csRadiometerILT1700();
            Radiometer.openPort();

Any insight is appreciated.

EDIT: I altered my csRadiometerILT1700 constructor to

   public csRadiometerILT1700(Form inputForm)
    {

        //inputForm.Invoke(
        //two handshaking properties of the ILT1700. Handshaking is enabled and 
        //http://stackoverflow.com/questions/6277619/problem-reading-serial-port-c-net-2-0-to-get-weighing-machine-output
        RadiometerSerial.Handshake= Handshake.RequestToSend;
        RadiometerSerial.DtrEnable = true;

        RadiometerSerial.DataReceived += new SerialDataReceivedEventHandler(RadiometerSerial_DataReceived);
        inputForm.Invoke(DataReceived);
    }

and declare

public event Delegate DataReceived;

in the csRadiometerILT1700 class. But this gives me the error of "Datareceived must be of a delegate type." How do I resolve this now? Am I on the right track?

Brad
  • 11,934
  • 4
  • 45
  • 73
  • Don't Invoke from the ctor. Here is a link for setting up an event:http://stackoverflow.com/questions/2448487/how-to-dispatch-events-in-c/2448530#2448530 – H H Jul 18 '11 at 23:01
  • Your class should raise its event when meaningful data is received. Pack it into an EventArgs-derive class. The form subscribes (+=) and Invokes in its handler. – H H Jul 18 '11 at 23:03

5 Answers5

2
  1. Your RadiometerILT1700 class needs an event to report it's received (and processed) data.
  2. Your Form subscribes to that event
  3. The Forms eventhandler uses this.Invoke() to overcome the cross-threading issue.
H H
  • 263,252
  • 30
  • 330
  • 514
  • 1. Would this even be triggered within the DataReceived event? Once I'm done processing X amount of serial data I flag the event? 2. How do I go about subscribing to it from the calling form? 3. Does this mean that I put the "subscription" within the Invoke()? – Brad Jul 15 '11 at 16:44
  • 1) Yes, 2) with `+=`, like with the other event, 3) No, you Invoke form the subscribed Form method. To another or the same method. – H H Jul 15 '11 at 18:05
  • I'm sorry, I'm still lost. I might need a little more hand holding. could you use more words to describe the actions associate with 2). – Brad Jul 15 '11 at 18:56
1

Invoke is a method on a Delegate or a Form or Control, since csRadiometerILT1700 is none of these it is not inheriting an Invoke implemenation from those classes.

You will need to raise another event to the caller of csRadiometerILT1700 and hadle that on you GUI somewhere (along with any cross thread issues.) Alternatively, you could provide csRadiometerILT1700 with a delegate it could use to callback, kind of like a hand rolled event.

Once you have the data in your Form you can use Control.InokeRequired to detect a cross thread situation and Control.Invoke to make the cross thread call.

Jodrell
  • 34,946
  • 5
  • 87
  • 124
  • I think I'm confused about the delegate syntax. What parts go in the calling form and what parts go in the class where the event is handled? – Brad Jul 15 '11 at 17:31
  • A `delegate` is a definition of a function signature. A `Delegate` or `MultiCastDelegate` is the class that represents an instance of a `delegate`. An `event` is a `MulticastDelegate` of a specified `delegate` with a shortcut for "raising" or "invoking" the call. – Jodrell Jul 18 '11 at 08:18
  • The `delegate` can be declared anywhere, the `event` should be on the class that wants to raise it. A function that matches and is used to subscribe to the events `MulticastDelegate` should be on the class that wants to handle the event. – Jodrell Jul 18 '11 at 08:26
  • I've ended up just making a 500 ms timer and doing a readLine() on the serial port. This is about as frequently as it can send them without stalling out. I'll save the events and interrupts for another day. Thanks for the help. – Brad Jul 19 '11 at 13:44
0

anytime you try to post to the main thread from a different thread you'll get this error. You need to use a delegate and Invoke on the control you want to call from the thread that isn't the main form thread.

Mark W
  • 3,879
  • 2
  • 37
  • 53
0

Assuming the error is actually:

Control control name accessed from a thread other than the thread it was created on.

The problem is you can't affect your GUI from another thread. You need to invoke the form or control to pass control so it can be modified. You should be able to interact with most other elements, but not a form.

Tremmors
  • 2,906
  • 17
  • 13
0

You should not call this.Invoke there, the way you are doing it is like trying to sync your own thread with your own instead with the UI. you should call formhandle.Invoke, or inside form class register for the event and then you can use this.invoke

Djole
  • 1,145
  • 5
  • 10