How to return to function from event time

So, I have a readSensor function that you guessed it .. reads the sensor.

But the sensors usually take about 100 ms to respond. So in the readSensor function, I just start the timer.

At a point in time, I read serialport and got my answer.

However, this means that my answer is in onTimedEvent when I want it to be in the readSensor function.

Mostly from the main form, I want to be able to do this.

value = readSensor ()

when for a minute all I can do is readSensor (), and then I see that the response is returned, showing it in the message box after the timedEvent has been triggered.

here is my code. (I missed a lot of serialport settings and stuff, but hope you can see the problem I'm in)

I do not want to just wait in a function for 100 ms, although polling a timer, as this will make my program slow.

I want to somehow return the response to the readSensor function, and then return to the form.

using System; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; using System.Timers; namespace readSensor { public partial class readSens : UserControl { public readSens() { InitializeComponent(); } private System.Timers.Timer rTimer; SerialPort sp = new SerialPort(); private void setupTimer() { // Create a timer with a 100ms response. rTimer = new System.Timers.Timer(100); rTimer.SynchronizingObject = this; // Hook up the Elapsed event for the timer. rTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); } private void OnTimedEvent(object source, ElapsedEventArgs e) { string response = getResponse(); } public string getResponse() { string status = ""; byte[] readBuffer = new byte[255]; if (sp.IsOpen) { if (sp.BytesToRead > 0) //there is data to read { int length = sp.BytesToRead; for (int i = 0; i < length; i++) { readBuffer[i] = (byte)sp.ReadByte(); status = "pass"; return status; } } } public void readSensor(byte addr) { if (!sp.IsOpen) { openPort(); readSensor(addr); // calls itself again once port is opened } else if (sp.IsOpen) { rTimer.Start(); } else { MessageBox.Show("Port not opened yet"); } } } } 

In basic form, I basically just say

 setupTimer(); readSensor(); 

at the touch of a button.

+4
source share
3 answers

Start a separate stream, then from this stream, queue the results back to the main stream.

 class Game1 { //We declare a queue, which is like an array that we can extract and enter data easily in a FIFO (first in, first out) style list. Queue<string> q = new Queue<string>(); public void threadStart(object obj) { //We get the result of your function, while our main function is still looping and waiting. string result = readInput() //We tell C# that the parameter we passed in, is in fact the Game1 class passed from "t.Start" Game1 game = (Game1)obj; //This puts our "result" into the queue. game.q.Enqueue(result); } public void start() { //Declares a new thread, which will run "threadStart" function. System.Threading.Thread t = new System.Threading.Thread(threadStart); //We start the other thread (that will run in parallel) and pass "this" as the parameter. t.Start(this); //We loop over and over, sleeping, whilst the other function runs at the same time. This is called "multi- threading" while (q.Count == 0) { System.Threading.Thread.Sleep(10); } //This gets the last-entered (oldest) value from the queue q. string result = q.Deque(); } } 

So, this sets the thread to get the result, and then in my version polling the queue for some time until the results return, but in yours you could collect a bunch of things if you check each queue from time to time for new data .

Edit: Commenting has been added, hopefully alleviating some of your questions.

+1
source

I don't think you can do this without any callback mechanism. You could implement a while loop, but it’s not as if it led to a rotation.

My advice is to implement the correct asynchronization pattern or something simple:

 ReadSensor(addr, DoSomethingWithResult); public void DoSomethingWithResult(string result) { Console.WriteLine (result); } public partial class ReadSens : UserControl { private Action<string> _responseCallback; public void ReadSensor(byte addr, Action<string> responseCallback) { _responseCallback = responseCallback; // initiate timer } private void OnTimedEvent(object source, ElapsedEventArgs e) { string response = getResponse(); _responseCallback(response); } } 
+2
source

Is this approach possible for you? I think you are using Timer to wait for serialPort to open, but it can be self-managed with event-by-event.

 public class SensorReader { private Sensor sensor; private string lastResponse; public SensorReader(SerialPort serialPort) { this.serialPort = aSerialPort. this.sensor = new Sensor(serialPort); this.sensor.PortOpen += PortOpenEventHandler(OnPortOpen); } private void OnPortOpen() { this.ReadPort(); } public string ReadPort(byte address) { if (!this.sensor.IsOpen) { this.sensor.OpenPort(); this.lastResponse = "The serial port doesn't respond... yet!"; } else { // Read response at this point. this.lastResponse = this.GetResponse(); } return this.lastResponse; } } public class Sensor { private SerialPort serialPort; public Sensor(SerialPort aSerialPort) { this.serialPort = aSerialPort; } public bool IsOpen { get { return this.serialPort.IsOpen; } } public delegate void PortOpenEventHandler(object sender, EventArgs e); public event PortOpenEventHandler PortOpen; public void OpenPort() { // Open port here... // ... and throw the PortOpen event. if (this.PortOpen != null) { this.PortOpen(this, EventArgs.Empty); } } } 
+1
source

Source: https://habr.com/ru/post/1490670/


All Articles