Recent

Author Topic: Real time charting  (Read 18007 times)

ahmadian

  • New Member
  • *
  • Posts: 35
Real time charting
« on: April 26, 2014, 11:35:13 pm »
I have a worker thread that read an integer value  from spi port every 10ms.
The hardware is Raspberry Pi and the worker thread works nice. It contains a sleep(10) for timing.
When thread read 100 numbers from poet, main thread must plot this values on a LineSeries.
But during LineSeries1.EndUpdate, the worker thread stops and my data is lost.
How can I write a thread that not interrupted by GUI?
Lazarus1.2 + FPC2.6.2 on Raspberry Pi ( installed from Jessie Repo) + LazReport Package

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Real time charting
« Reply #1 on: April 27, 2014, 12:58:51 am »
But during LineSeries1.EndUpdate, the worker thread stops and my data is lost.
How can I write a thread that not interrupted by GUI?
Maybe your data should not be part of the worker thread, or may be you should *not* use FreeOnTerminate := True.

ahmadian

  • New Member
  • *
  • Posts: 35
Re: Real time charting
« Reply #2 on: April 27, 2014, 07:35:17 pm »
Thanks engkin
The FreeOnTerminate didn't solve problem.
You can see two simple procedure of code:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
begin
  LineSeries1.BeginUpdate;
  LineSeries1.Clear;
  for i:= 1 to 10000 do LineSeries1.AddXY(i,i);
  test_flag:= false;
  LineSeries1.EndUpdate;
  if test_flag then Form1.Caption:= 'Worker Thread was alive';
end;

procedure TMyThread.Execute;
var
  dt: real;
  Present, Last: TdateTime;
begin
  Last:= Now;
  while true do
  begin
    Repeat
      Present:= Now;
      dt:= (Present - Last) * 86400; //sec
    until dt >= 0.01;
    Last:= Present;
    test_flag:= true;
    sleep(10);
  end;
end;
The 'test_flag' is set to false before EndUpdate.
If TMyThread works between EndUpdate execution, 'test_flag' must be true after EndUpdate. But it was not true;
Lazarus1.2 + FPC2.6.2 on Raspberry Pi ( installed from Jessie Repo) + LazReport Package

engkin

  • Hero Member
  • *****
  • Posts: 2513
Re: Real time charting
« Reply #3 on: April 27, 2014, 10:12:41 pm »
The 'test_flag' is set to false before EndUpdate.
If TMyThread works between EndUpdate execution, 'test_flag' must be true after EndUpdate. But it was not true;
Maybe because EndUpdate takes a very small amount of time before execution gets transferred to TMyThread. Which means, if true, that it does *not* block your thread.

wp

  • Hero Member
  • *****
  • Posts: 6468
Re: Real time charting
« Reply #4 on: April 28, 2014, 12:29:25 am »
Sorry, maybe my stupidity, but I don't understand your code:
- How does the while-loop in the thread terminate? Normally there is a "while not Terminated...".
- Why do you need that "sleep"? Can't you just loop until a value is available, use "synchronize" to pass the value to the series? The timing to catch values that come 10 ms apart by using a sleep value of 10 ms seems to be very tight to me. But maybe I don't understand your code at all.
- Can you simulate the issue on a little demo which runs on a PC? I don't have a Raspberry Pi, but would like to help debugging.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

ahmadian

  • New Member
  • *
  • Posts: 35
Re: Real time charting
« Reply #5 on: April 28, 2014, 01:55:11 pm »
Thanks engkin and wp
My story is:
I make circuit boards for Tensile Tester Machines.
Up to now i used Delphi and Cport component. The board send 8byte to PC every 10ms.
Serial port of PC has large buffer (over 4096 bytes) and the software has many free  time for charting and etc.
TeeChart component of Delphi is very fast too (1ms for each point of FastLine).
6 month ago, I decided to replace Raspberry Pi with PC. Best choose was Lazarus.
I change my PCB and Remove MCU of the circuit, because Raspberry Pi has GPIO.
I was successful and all works fine.
But there is no any buffer on GPIO and my software must read(non stop) every 10ms.
I measured charting speed of TAchart on Raspberry Pi.
It take 25ms fo revery  point  of LineSeries that is slow and i need below 10ms.
But when using BeginUpdate/EndUpdate, it draw 100 point in 50ms, that is fast.
I decided to write a thread to buffer every 100 points that take 1 second and draw these 100 points simultaneously with BeginUpdate/EndUpdate. But The tread is stopped on running EndUpdate and some data is lost.
I need a thread that works non stop within another procedure. Same as kernel drivers that stop any work for reading hardwares (mouse , keyboard , ...).

'Ex me for my poor English'

« Last Edit: April 28, 2014, 11:33:00 pm by ahmadian »
Lazarus1.2 + FPC2.6.2 on Raspberry Pi ( installed from Jessie Repo) + LazReport Package

taazz

  • Hero Member
  • *****
  • Posts: 5363
Re: Real time charting
« Reply #6 on: April 28, 2014, 02:23:51 pm »
thats an interesting background but still with out any code to look at it is improbable that someone will come up with the solution to a problem he has not seen or know what it is. Calling endupdate should not have that effect on the thread or any thread for that matter what happens if instead of reading from the com port as you do now you use a file of previously recorded values and send them to the main thread add some more threads one to read from the com one or more to read from a file and report back one on 100 values the other on 1000 etc or any number of values you see that it will create a more random effect. now when endupdate is called are all the threads stopped? only the one that it communicated with the main thread last or only one specific thread? IT would be easier though if you could create a demo application using the file approach I described above to show us the problem and we could have something to look at and grin our teeth at.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ahmadian

  • New Member
  • *
  • Posts: 35
Re: Real time charting
« Reply #7 on: April 28, 2014, 11:27:44 pm »
Thanks taazz
I write a simple code that you can see on the top of topic. If this code work on Windows PC, I can move it raspberry PI and complete my software.
In that code I define a simple flag to check thread status when EndUpdate is working.
I am Hardware engineer and my main experiences is Assembly programming. I cant understand threading without interrupts!
I doubt thread Preempt method in Lazarus!
Any help or example that show a thread can run when EndUpdate is running, will be appropriated :-)
Simply, the thread must work like hardware interrupt.
Regards


Lazarus1.2 + FPC2.6.2 on Raspberry Pi ( installed from Jessie Repo) + LazReport Package

taazz

  • Hero Member
  • *****
  • Posts: 5363
Re: Real time charting
« Reply #8 on: April 29, 2014, 01:48:06 am »
OK lets go with the code provided, the main problem I see is that you make assumptions on the synchronization of the thread and the main thread execution time. You say that it should be true after the call to end update but I do not see anywhere code that makes sure that the thread had enough time to reach and execute the code <test_flag:= true;> at all, depending on the number of tests you might have different results each time why not introduce a sleep(X) before checking the test_flag where X must be equal to the total time required to execute a single iteration inside the while loop.

Still the code you provide is not enough for example how is the test_flag declared is it var or threadvar? inside the form or global to the unit/application, as you can see there are a number of reasons that your test fails and the thread is still executing behind your back so a complete demo that shows the problem with everything visible would be better for us to test.
« Last Edit: April 29, 2014, 01:58:10 am by taazz »
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

CaptBill

  • Sr. Member
  • ****
  • Posts: 435
Re: Real time charting
« Reply #9 on: April 29, 2014, 01:55:26 am »
Since you are already dealing with GPIO pins you could simply pass the data to a micro controller for buffering and timing. There is no need for 'Preempting', 'blocking', 'locks','priorities' etc. etc. Those are all 'contentious' types of coding where you are fighting the system for powers that aren't normally allowed. Those are all 'work arounds' to a problem that even the little Rasberry Pi OS has: poor 'real-time' skills. Micro controllers don't have those problems.

ahmadian

  • New Member
  • *
  • Posts: 35
Re: Real time charting
« Reply #10 on: April 29, 2014, 11:23:21 am »
OK lets go with the code provided, the main problem I see is that you make assumptions on the synchronization of the thread and the main thread execution time. You say that it should be true after the call to end update but I do not see anywhere code that makes sure that the thread had enough time to reach and execute the code <test_flag:= true;> at all, depending on the number of tests you might have different results each time why not introduce a sleep(X) before checking the test_flag where X must be equal to the total time required to execute a single iteration inside the while loop.

Still the code you provide is not enough for example how is the test_flag declared is it var or threadvar? inside the form or global to the unit/application, as you can see there are a number of reasons that your test fails and the thread is still executing behind your back so a complete demo that shows the problem with everything visible would be better for us to test.
Thanks taazz
The test_flag is a global variable, not a thread var. I hered somewhere that boolean vars don't need to be defines in 'Critical Section'.
I can't add a Sleep(x) to main thread, because this don't change EndUpdate problem!
I attached the my test code. I am waiting any suggestion.

Thanks CaptBill (Great man of TinyCore)
Quote
Since you are already dealing with GPIO pins you could simply pass the data to a micro controller for buffering and timing. There is no need for 'Preempting', 'blocking', 'locks','priorities' etc. etc. Those are all 'contentious' types of coding where you are fighting the system for powers that aren't normally allowed. Those are all 'work arounds' to a problem that even the little Rasberry Pi OS has: poor 'real-time' skills. Micro controllers don't have those problems.
Yes, Doing this job with MCUs is 'ULTRA SIMPLE'. But I come from there to use a 1GHz CPU!!!
Recent years, I made many boards with AVR + WIN PC + Wireless dongle (that i made by NRF24L01+). Everything works OK.
I removed AVR, Wirless Link and  connect all ICs directly to GPIO of  Raspberry Pi. This Reduces the board size and eliminate an expensive Windows PC.
I expect the 1GHz CPU works better than a 20MHz AVR!
Linux has many advantages over Windows but I disappointed, If i can't have a simple interrupt (or fixed time thread) :(
My last solution is to:
1- Add an AVR to the board and buffer 100 samples
2- Add a 1 Sec timer in Lazarus Program
3- In the on timer event handler, simultaneously read all 100 samples from SPI and add them to LineSeries of chart.
This is very simple, but was not my first goal :)
Regards





Lazarus1.2 + FPC2.6.2 on Raspberry Pi ( installed from Jessie Repo) + LazReport Package

taazz

  • Hero Member
  • *****
  • Posts: 5363
Re: Real time charting
« Reply #11 on: April 29, 2014, 11:52:34 am »
well the attached project will show you that I was right, the problem is simple one of synchronization between main thread and your thread run it and see for your self the callback counter I added on the status bar.
« Last Edit: April 29, 2014, 12:04:15 pm by taazz »
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ahmadian

  • New Member
  • *
  • Posts: 35
Re: Real time charting
« Reply #12 on: April 29, 2014, 02:13:07 pm »
You are great taazz ...  :o
It Works OK and the AsyncCall is strange.  :D
Lazarus1.2 + FPC2.6.2 on Raspberry Pi ( installed from Jessie Repo) + LazReport Package

taazz

  • Hero Member
  • *****
  • Posts: 5363
Re: Real time charting
« Reply #13 on: April 29, 2014, 02:26:03 pm »
QueueAsyncCall is a method of TApplication it has been written with multi threading in mind so it is safe to call it from multiple threads at the same time. What I did was to instract the application that when all the messages (this is a windows behavior where event generates a message that is send to active windows) have finished processing and the application is about to enter its idle state then run the method I provided that is why I used a TForm1 method instead of a TMyThread Method since the calling thread will be the main thread this way I keep the thread free of synchronization code.

It is a quick way to check various things and probably to implement a limited information wake up calls eg percentage completed of a file decoding in the background but it is not to be used for more complicated data exchange with out proper data protection.
« Last Edit: April 29, 2014, 02:38:17 pm by taazz »
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

ahmadian

  • New Member
  • *
  • Posts: 35
Re: Real time charting
« Reply #14 on: April 29, 2014, 03:04:40 pm »
Thanks a lot taazz.
This is new highway for me and my hardwares.
But I have another problem. My data is an array and must be plotted on chart.
I changed the code to make an example array. I use the dt time for data for test and evaluation of thread timing.
But I don't know how to send this array asynchronously to chart.
I attached the new code.
Regards.
Lazarus1.2 + FPC2.6.2 on Raspberry Pi ( installed from Jessie Repo) + LazReport Package