How to implement a loop to check for data recieved Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
jaxsin
Earned a small fee
Earned a small fee
Posts: 18
Joined: Fri Feb 27, 2015 10:37 pm

How to implement a loop to check for data recieved

Post by jaxsin »

I am trying to find the best way to implement a "loop" where I check to see if data has arrived and if so I want to update a wxTextCtrl with the data received.

I wrote a serial class that essentially checks the com port for data that has arrived. I read the data one byte at a time and add it to an internal buffer.

Code: Select all

// Get the Bytes in queue
do
{
	byte szBuf;
	if (ReadFile(cThis->m_hSerial, &szBuf, 1, NULL, &ovRead))
		{
			GetOverlappedResult(cThis->m_hSerial, &ovRead, &dwBytesRead, FALSE);
			cThis->m_Buffer.AddData(szBuf);
		}
		else
		{
			DWORD err = GetLastError();
			(void)err;
		}
} while (dwBytesRead > 0);

Code: Select all

void Buffer::AddData(byte c)
{
	LockBuf();
	m_byteArray.push_back(c);
	m_bytesAvailable = true;
	UnLockBuf();
}
I want a way to check if m_bytesAvailable = true and then update the TextCtrl. I am not sure how exactly is the best way to implement this in wxwidgets. I was thinking I could override the wxapp::MainLoop() or OnRun() function, but after doing some research I am not sure that is the best way to do it. In fact I have come to the conclusion that maybe using idle events to check if data is available on the internal buffer would be better, or even a timer. Any advice or some simple code to point me in the right direction would be appreciated.

according to this page https://wiki.wxwidgets.org/Making_a_render_loop I was thinking of doing something like this

Code: Select all

bool AppMain::OnInit() 
{
   receive_data_loop_on = false;
	//put construction and showing of top-level window here (by using new statement)
	Layout * layout = new Layout(wxT("Yapper"));
	layout->Show(true);
   activateReceiveDataLoop(true);
	return true;
}

void AppMain::activateReceiveDataLoop(bool on)
{
    if(on && !receive_data_loop_on)
    {
        Connect( wxID_ANY, wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle) );
        receive_data_loop_on = true;
    }
    else if(!on && receive_data_loop_on)
    {
        Disconnect( wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle) );
        receive_data_loop_on = false;
    }
}
void AppMain::onIdle(wxIdleEvent& evt)
{
    if(render_loop_on)
    {
        // code to update the wxTextCtrl here
        evt.RequestMore(); // Receive continuously, not only once on idle as long as com is connected
    }
}

DenDev
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 231
Joined: Mon Jan 19, 2015 1:45 pm

Re: How to implement a loop to check for data recieved

Post by DenDev »

You will not get anything but trouble from using wxIdleEvent::RequestMore() - do not venture into this! I would personally prefer to create a derived thread for the job since it is a non-visual task, but if you are not familiar with multi-threading this might end up giving you a headache. The wxTimer is ideal for you since it is very simple to implement and it offers you what you need :-)
I have a bad habbit of not testing the code I post :D
jaxsin
Earned a small fee
Earned a small fee
Posts: 18
Joined: Fri Feb 27, 2015 10:37 pm

Re: How to implement a loop to check for data recieved

Post by jaxsin »

Now a question about threads, I was under the impression that you should avoid polling and idling in a loop, see the reference below under
How to Pause a Thread or Wait for an External Condition - If a thread needs to wait for something to happen, you should avoid both polling and idling in a loop that keeps the processor busy doing nothing ("busy waiting").
http://flylib.com/books/en/3.138.1.144/1/

It's not that I am scared of threads to not use them or at the very least learn them so I can understand them. I was just under the impression that this type of threading where I poll do nothing, poll some more till I find something is not correct. Am I misunderstanding how one would implement a thread to handle this sort of problem? I am always willing to learn and never want to accept the easy way out. I will certainly write a wxTimer and get it working.
DenDev
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 231
Joined: Mon Jan 19, 2015 1:45 pm

Re: How to implement a loop to check for data recieved

Post by DenDev »

A thread is ideal for non-visual, continous tasks like reading data from pipes, sockets and alike, because it does not block the main UI thread. A typical thread loop would look something like this:

Code: Select all

//Initialize loop here

while (ThreadIsAlive())
{

  if (ReadData(..))
  {
    LockGlobalDataWithMutex();
    AddReadDataToGlobalData();
    UnlockGlobalData();
    SendEventToInformAboutAvailableData();
  }

  else
  {
    SleepAWhile();
  }

}

//Finalize loop here
Another reccomendation is not to use a one-byte buffer, because it is highliy inefficient and you buffer should at least be 1KiB (1024 bytes).
I have a bad habbit of not testing the code I post :D
jaxsin
Earned a small fee
Earned a small fee
Posts: 18
Joined: Fri Feb 27, 2015 10:37 pm

Re: How to implement a loop to check for data recieved

Post by jaxsin »

ok I am not sure we are on the same page here. I have a serial class that does asynchronous IO (using threads) and a buffer class that stores data and allows read/writes but only one at a time.
The above codes seems to work fine in a c++ console app. This was all before I decided to add in a gui. At first I was thinking about win api, but I soon realized that it was a mess. I wanted something that was easier to use to design GUI's and I was hoping that would be wxWidgets.

This is where my current problem lies, Without specifically designing the serial class to send an event to wxWdigets to tell it when something is on the buffer I need a way to check so see if bytesAvailable == true.

so to clear up my confusion,
I am already using a thread to receive data that shows up on the serial port when an event is fired.

The reason why I don't want to hardcode the serial class to fire an event for a specific GUI framework is in case I want to say design a QT gui while using the same serial class. Does that makes sense or is my newbieness wearing off again? :D
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to implement a loop to check for data recieved

Post by doublemax »

This is what i would do:

- in the thread, read from the serial port and append all received data to a buffer

- in a timer event (10 times per second should be enough), read all data out of the buffer and append it to the text control

Access to the buffer must be protected with a mutex.
Use the source, Luke!
DenDev
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 231
Joined: Mon Jan 19, 2015 1:45 pm

Re: How to implement a loop to check for data recieved

Post by DenDev »

You do not have to bind you code to a specific platform or GUI. You can get about this with conditional compiling:

Code: Select all

SendEventToInformAboutAvailableData()
{
#ifdef __WXWINDOWS__

  //Send event using wxWidgets

#elif QT_DEBUG || QT_NO_DEBUG

  //Send event using QT

#else

  //Send event using neither wx nor qt

#endif
}
This would make the method achieve the same goal but on different GUI's and/or systems. Code is not testet, btw! ;-)
I have a bad habbit of not testing the code I post :D
jaxsin
Earned a small fee
Earned a small fee
Posts: 18
Joined: Fri Feb 27, 2015 10:37 pm

Re: How to implement a loop to check for data recieved

Post by jaxsin »

DenDev, on another note you said
Another recommendation is not to use a one-byte buffer, because it is highly inefficient and your buffer should at least be 1KiB (1024 bytes).
are you talking about the ReadFile call I make where I grab 1 byte at a time in the do while loop? Or are you talking about something else? The reason I am reading 1 byte at a time is two reasons, Serial communication is rather slow, I will never receive more then I can read in a 100 byte array, let alone 1KB. Secondly, is it not more inefficient to remove the '\r' carriage returns 1 byte at a time like I am or reading in a 1KB possible c-string and parse it to remove the carriage returns before copying it over to the internal buffer?

Remember my other problem where I was having issues with broken \r\n causing random newlines in my TextCtrl. What would you recommend in this circumstance?
DenDev
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 231
Joined: Mon Jan 19, 2015 1:45 pm

Re: How to implement a loop to check for data recieved

Post by DenDev »

If you read a buffer from the port you will only have to make sure that the last character read is not a carriage return:

Code: Select all

char buf[101]; //need space for a NULL char
int read = ReadSerial(buf, 100);
if (read > 0)
{
  if (buf[read-1] == '\r')) read--; //Prevent last character from being carriage return
  //if (read == 0) we should exit here
  #ifdef _USE_NULL_TERMINATED_C_STRING_ //Conditional compiling, pick your choice
  buf[read] = '\0'; //Set NULL termination, less work than ZeroMemory the whole buffer
  ProcessCString(buf);
  #else
  ProcessBuffer(buf, read);
  #endif
}
I do not know how slow serial is, but reading it byte by byte is not going to make it faster :-)
I have a bad habbit of not testing the code I post :D
jaxsin
Earned a small fee
Earned a small fee
Posts: 18
Joined: Fri Feb 27, 2015 10:37 pm

Re: How to implement a loop to check for data recieved

Post by jaxsin »

I appreciate the help DenDev, Got me sorted and everything is working now. You are right, reading one byte at a time surely isn't going to speed up the reading speed.
Post Reply