Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 25, 2023 2:56:01 GMT -5
There's no need to update in real time. Data only needs to be there when operator comes along. There's an "Update" button for that purpose. In operator's absence, data still needs to come in regularly. Currently that happens once a minute. Logging in a file is actually a good idea. That way we can keep a record on meaningful events. I'll discuss it all later on. Haven't lost hope in L.B. yet.
|
|
|
Post by Rod on Apr 25, 2023 7:30:21 GMT -5
As Anatoly says logging to a file once a minute then drawing all on demand is an obvious solution. We were trying to hold our record on screen which was the blind alley. So it is very doable. This demo is less relevant now, it is the fastest way to draw and present continuous data. but we dont really need it now. ' open our window and graphicsbox and set options and event labels nomainwin WindowWidth = 600 WindowHeight = 600 UpperLeftX = (DisplayWidth-WindowWidth)/2 UpperLeftY = (DisplayHeight-WindowHeight)/2 graphicbox #1.g, 50,80,500,300 open "Graph" for graphics_nf_nsb as #1 print #1, "trapclose [quit]"
' set up our bitmaps, open device contexts and store our bitmaps in them
' gDC is our graphics screen print #1, "down ; fill buttonface" print #1.g, "down"
' fancy shaded graphics you could equally down ; fill black
for shade= 300 to 0 step -2 print #1.g, "color ";shade/2+100;" ";shade/2+100;" ";shade/2+100 print #1.g, "line 0 ";shade;" ";"500 ";shade print #1.g, "line 0 ";shade-1;" ";"500 ";shade-1 next shade print #1.g, "color yellow" print #1.g, "line 0 150 500 150" print #1.g, "flush" print #1.g, "getbmp bmp 0 0 500 300"
gDC=GetDC(hwnd(#1.g))
' mDC is a copy of the screen in memory used as a buffer to draw graphics to
mDC=CreateCompatibleDC(gDC) hBitmap=hbmp("bmp") oldBmp=SelectObject(mDC,hBitmap)
' variables
X=496 Y=150 degree=0 degree1=270 increment=4 '360/(samplesPerSecond/hertz) volume=.5 ' .01 - 1.0
' Start a repeating timer call to [graphit] ' for really fast graphics just loop [graphit]
' set the rgb color to plot red=255 ' 0-255 green=0 ' 0-255 blue=0 ' 0-255 rgb1=red+(green*256)+(blue*256*256)
red=0 ' 0-255 green=255 ' 0-255 blue=0 ' 0-255 rgb2=red+(green*256)+(blue*256*256)
[graphit]
scan
' flip the buffer to the screen so that it is visible and stable for as long as possible
call StretchBlt,gDC,0,0,500,300,mDC,0,0,500,300
' now start to redraw everything on the buffer ' first slip the graphics a little to the left
call StretchBlt,mDC,-1,0,498,300,mDC,0,0,498,300
' calculate and plot/draw new point
degree=degree+increment if degree>359 then degree=0 Y=Int((sin(degree/57.29577951)*128*volume)+150)
degree1=degree1+increment if degree1>359 then degree1=0 Y1=Int((sin(degree1/57.29577951)*128*volume)+150)
color=SetPixel(mDC,X,Y,rgb1) color=SetPixel(mDC,X,Y1,rgb2)
goto [graphit]
[quit] timer 0 unloadbmp "bmp" call ReleaseDC hwnd(#1), gDC call DeleteDC mDC close #1
end
'=============================Window and DC functions================================= Function GetDC(hWnd) CallDLL #user32, "GetDC",_ hWnd As Ulong,_ 'window or control handle GetDC As Ulong 'returns device context End Function
Sub ReleaseDC hWnd, hDC CallDLL#user32,"ReleaseDC",_ hWnd As Ulong,_ 'window or control handle hDC As Ulong,_ 'handle of DC to delete result As Long End Sub
Function CreateCompatibleDC(hDC) CallDLL #gdi32,"CreateCompatibleDC",_ hDC As Ulong,_ 'window DC CreateCompatibleDC As Ulong 'memory DC End Function
Sub DeleteDC hDC CallDLL #gdi32, "DeleteDC",_ hDC As Ulong,_ 'memory DC to delete result As Boolean End Sub
Sub StretchBlt hDCdest,x,y,w,h,hDCsrc,x2,y2,w2,h2 CallDLL #gdi32, "SetStretchBltMode",_ hDCdest As Ulong,_ 'device context _COLORONCOLOR As Long,_ 'color reduction mode result As Long CallDLL #gdi32, "StretchBlt",_ hDCdest As Ulong,_ 'destination x As Long,_ 'destination x pos y As Long,_ 'destination y pos w As Long,_ 'destination width desired h As Long,_ 'destination height desired hDCsrc As Ulong,_ 'source x2 As Long,_ 'x location to start from source y2 As Long,_ 'y location to start from source w2 As Long,_ 'width desired from source h2 As Long,_ 'height desired from source _SRCCOPY As Ulong,_ 'dwRasterOperation result As Boolean End Sub
Function SelectObject(hDC,hObject) CallDLL #gdi32,"SelectObject",_ hDC As Ulong,_ 'memory device context hObject As Ulong,_ 'handle of object SelectObject As Ulong 'returns previously selected object End Function
Function SetPixel(hdc,x,y,rgbColor) CallDll #gdi32, "SetPixel",_ hdc as Ulong,_ 'the handle of the Device context from GetDC x as long,_ 'the x coordinate to draw the pixel y as long,_ 'the y coordinate to draw the pixel rgbColor as long,_ SetPixel as long End Function
This is what we are drawing.
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 25, 2023 11:00:53 GMT -5
Here's a screenshot with one of the actual things. Notice the moment the COM port stops working. Later, after an update, it restarted.
This issue was discused this afternoon with management. It was decided to go the logging way. However, the PC will not be the one making the log, for practical reasons. That would imply a computer turned on 24/7. There would be no point in making this logging without it being 24/7. A separate, specialized unit (Arduino thingy), will be recording data.
What this means for our program is that I'm free of screen restrictions. Draw, redraw, and the like can now be done at any time, as all data is recorded
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 25, 2023 11:47:46 GMT -5
"This demo is less relevant now, it is the fastest way to draw and present continuous data. but we dont really need it now."
Thank you for it Rod, will keep a copy just in case
|
|
|
Post by Rod on Apr 25, 2023 12:18:59 GMT -5
Ok, we are several posts down the line and we are still blaming drawing. Eliminate all drawing just read and print. Does it keep going like the clock program or is there an actual program flow fault that is nothing to do with drawing.
I do differentiate between storing the data on screen with flush which is never going to work. And this problem of the program stalling.
Does it keep going without any drawing, did you code in the timer tip to encase it in a sub.
We need to stop chasing our tails. Let’s get the program cycling first. So no drawing.
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 25, 2023 13:08:33 GMT -5
Do not worry about drawing Rod. That screenshot is the old version, were even the timings were wrong. I though it would be interesting to post it here. Currently, I'll make a short brake to handle the Arduino logger, fast&easy for me. After that, this program code will undergo a major redo to handle the logged data. The screen data retention went to the bin for good.
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 25, 2023 14:30:16 GMT -5
did you code in the timer tip to encase it in a sub. With that timer in the main loop, that makes L.B. wait for next clock flag, instead of just cycling around 320000 times a min., L.B. is actually at the timer routine almost all the time. Since labels outside the sub are not recognised by that sub, this means any keyboard, or mouse, presses will give an error of unrecognised label. Have rewritten the timer exactly as in your sub, but at 3 different locations in the main code. A sub wouldn't work
|
|
|
Post by Rod on Apr 26, 2023 6:10:44 GMT -5
The timer sub will have problems if you mix subs and branch label code. Usually best to keep all subs or all [labels]. But they can co exist. This code shows keyboard and mouse tracking while using the sub timer. It works because the code is in the other subs for a tiny amount of time and they make no attempt to branch anywhere, so the program flow comes back to the timer sub to branch. But stick with what you know.
I have been experimenting with the chart and graphing the data. You are going to need a drawing strategy, a simple strategy wont work since we are charting 6 locations, 5 datasets each? over 1440 24hr timescale That's coming out at 43200 points. Drawing the background as a .bmp or segment takes no time but charting those points is taking 1856ms on my fast machine. Even the redraw segment takes 212ms. So I suspect we will be exploring the blitter or some sort of getbmp shift left and draw the last set of points.
Anyway, for now this shows the timer sub reading keys and mouse, but its a simple program. larger code that introduces delays would probably need something different.
nomainwin open "graphics" for graphics as #g #g "trapclose closedown" #g "when characterInput key" #g "when leftButtonDown mouse" #g "setfocus"
while 1 call waitMilliseconds 500 #g "place 50 50" #g "\";time$("ms") 'check devices and read data wend
sub key h$,c$ #g "place 100 100 ;\key :";c$;" " end sub
sub mouse h$,x,y #g "place ";x;" ";y;" ;\Mouse!" end sub
sub waitMilliseconds ms timer ms, [stopWaiting] wait [stopWaiting] timer 0 end sub
sub closedown h$ timer 0 close #g end end sub
|
|
|
Post by Rod on Apr 26, 2023 8:41:32 GMT -5
This is a blitter solution. Simplest I can think of. We step outside Liberty's flush and segment system and draw directly to a DC buffer. We need to use API for this. So this code takes a large background bmp and loads that to the buffer. We then cycle at 500ms and draw new points to the buffer then flip it to the screen. You can minimise and cover the chart and it will repaint at the 500ms point. So really no need for flush or segment at all. See how this code runs for you over time. You will need to supply a 1920x1080 background bmp.
If the program is closed you would need to find a way to redraw all points again. But that was a problem that existed before. So this is more about drawing the points and having the image persist over time. You will still need log. But given the 2000ms redraw time this is a practical way to present your data,
' open our window and graphicsbox and set options and event labels nomainwin WindowWidth = 1920 WindowHeight = 1080 open "Graph" for graphics_nf_nsb as #1 #1 "trapclose [quit]"
' set up our bitmaps, open device contexts and store our bitmaps in them loadbmp "bak","bak.bmp"
' gDC is our graphics screen #1 "down ; fill black" #1 "getbmp bmp 0 0 1920 1080" gDC=GetDC(hwnd(#1))
' mDC is a copy of the screen in memory used as a buffer to draw graphics to ' we load our background graphic into it mDC=CreateCompatibleDC(gDC) hBitmap=hbmp("bak") oldBmp=SelectObject(mDC,hBitmap)
' some dummy data to plot
' set the rgb long value color to plot ' we are drawing outside Liberty's segment system directly to a buffer ' the buffer persists over time and will be repainted at cycle time ' if you cycle at 500 ms there is really no need for any flushing or segments red=255 ' 0-255 green=0 ' 0-255 blue=0 ' 0-255 rgb1=red+(green*256)+(blue*256*256) red=0 ' 0-255 green=255 ' 0-255 blue=0 ' 0-255 rgb2=red+(green*256)+(blue*256*256) red=0 ' 0-255 green=255 ' 0-255 blue=0 ' 0-255 rgb3=red+(green*256)+(blue*256*256) red=255 ' 0-255 green=255 ' 0-255 blue=0 ' 0-255 rgb4=red+(green*256)+(blue*256*256) red=0 ' 0-255 green=255 ' 0-255 blue=255 ' 0-255 rgb5=red+(green*256)+(blue*256*256) red=64 ' 0-255 green=255 ' 0-255 blue=128 ' 0-255 rgb6=red+(green*256)+(blue*256*256)
X=40
timer 500,[graphit] wait
[graphit]
' flip the buffer to the screen so that it is visible and stable for as long as possible call StretchBlt,gDC,0,0,1920,1080,mDC,0,0,1920,1080
' calculate and plot/draw new point to buffer ' ie read and plot our device info for Y=220 to 920 step 140 YY=int(sin(a/57.29577951)*15) color=SetPixel(mDC,X,YY+Y,rgb1) color=SetPixel(mDC,X,YY+Y+5,rgb2) color=SetPixel(mDC,X,YY+Y+10,rgb3) color=SetPixel(mDC,X,YY+Y+15,rgb4) color=SetPixel(mDC,X,YY+Y+20,rgb5) color=SetPixel(mDC,X,YY+Y+25,rgb6) next X=X+1 a=a+1 mod 360 wait
[quit] timer 0 unloadbmp "bak" call ReleaseDC hwnd(#1), gDC call DeleteDC mDC close #1
end
'=============================Window and DC functions================================= Function GetDC(hWnd) CallDLL #user32, "GetDC",_ hWnd As Ulong,_ 'window or control handle GetDC As Ulong 'returns device context End Function
Sub ReleaseDC hWnd, hDC CallDLL#user32,"ReleaseDC",_ hWnd As Ulong,_ 'window or control handle hDC As Ulong,_ 'handle of DC to delete result As Long End Sub
Function CreateCompatibleDC(hDC) CallDLL #gdi32,"CreateCompatibleDC",_ hDC As Ulong,_ 'window DC CreateCompatibleDC As Ulong 'memory DC End Function
Sub DeleteDC hDC CallDLL #gdi32, "DeleteDC",_ hDC As Ulong,_ 'memory DC to delete result As Boolean End Sub
Sub StretchBlt hDCdest,x,y,w,h,hDCsrc,x2,y2,w2,h2 CallDLL #gdi32, "SetStretchBltMode",_ hDCdest As Ulong,_ 'device context _COLORONCOLOR As Long,_ 'color reduction mode result As Long CallDLL #gdi32, "StretchBlt",_ hDCdest As Ulong,_ 'destination x As Long,_ 'destination x pos y As Long,_ 'destination y pos w As Long,_ 'destination width desired h As Long,_ 'destination height desired hDCsrc As Ulong,_ 'source x2 As Long,_ 'x location to start from source y2 As Long,_ 'y location to start from source w2 As Long,_ 'width desired from source h2 As Long,_ 'height desired from source _SRCCOPY As Ulong,_ 'dwRasterOperation result As Boolean End Sub
Function SelectObject(hDC,hObject) CallDLL #gdi32,"SelectObject",_ hDC As Ulong,_ 'memory device context hObject As Ulong,_ 'handle of object SelectObject As Ulong 'returns previously selected object End Function
Function SetPixel(hdc,x,y,rgbColor) CallDll #gdi32, "SetPixel",_ hdc as Ulong,_ 'the handle of the Device context from GetDC x as long,_ 'the x coordinate to draw the pixel y as long,_ 'the y coordinate to draw the pixel rgbColor as long,_ SetPixel as long End Function
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 26, 2023 11:52:09 GMT -5
The timer sub will have problems if you mix subs and branch label code. Usually best to keep all subs or all [labels]. But they can co exist. This code shows keyboard and mouse tracking while using the sub timer. It works because the code is in the other subs for a tiny amount of time and they make no attempt to branch anywhere, so the program flow comes back to the timer sub to branch. But stick with what you know. I have been experimenting with the chart and graphing the data. You are going to need a drawing strategy, a simple strategy wont work since we are charting 6 locations, 5 datasets each? over 1440 24hr timescale That's coming out at 43200 points. Drawing the background as a .bmp or segment takes no time but charting those points is taking 1856ms on my fast machine. Even the redraw segment takes 212ms. So I suspect we will be exploring the blitter or some sort of getbmp shift left and draw the last set of points. Anyway, for now this shows the timer sub reading keys and mouse, but its a simple program. larger code that introduces delays would probably need something different. nomainwin open "graphics" for graphics as #g #g "trapclose closedown" #g "when characterInput key" #g "when leftButtonDown mouse" #g "setfocus"
while 1 call waitMilliseconds 500 #g "place 50 50" #g "\";time$("ms") 'check devices and read data wend
sub key h$,c$ #g "place 100 100 ;\key :";c$;" " end sub
sub mouse h$,x,y #g "place ";x;" ";y;" ;\Mouse!" end sub
sub waitMilliseconds ms timer ms, [stopWaiting] wait [stopWaiting] timer 0 end sub
sub closedown h$ timer 0 close #g end end sub
With the exception of the "closedown" sub routine, I use a branch label, everything else is has in your example. Still have the problem of errors of non found labels. Timer routines only happen 3 times. And they are really small. I prefer to write it 3 times than having to debug, yet, another problem
Drawing speed is no longer a problem. since we (will) have all data recorded at very precise intervals. L.B. will only need to read that data and plot it on screen. Takes almost 2 seconds? I really don't care... data is not meant to be processed in real time. But does need to be acquired within precise timeframes. We are a UK temperature calibration lab. Environment of same must be well controlled, and always within a certain margin. Facilities the size of a small house don't change temperature that much that fast.
When I was aiming at having the data plotted on screen only, the goal was to check if lab temperature was drifting, or having deviations from room to room, that could cause calibration errors.
The whole point of these charts is to assess the behaviour of our lab in terms of temperature control. Waiting 2 seconds + reading time, to see the data, is not an issue.
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 26, 2023 12:02:13 GMT -5
This is a blitter solution. Simplest I can think of. We step outside Liberty's flush and segment system and draw directly to a DC buffer. We need to use API for this. So this code takes a large background bmp and loads that to the buffer. We then cycle at 500ms and draw new points to the buffer then flip it to the screen. You can minimise and cover the chart and it will repaint at the 500ms point. So really no need for flush or segment at all. See how this code runs for you over time. You will need to supply a 1920x1080 background bmp. If the program is closed you would need to find a way to redraw all points again. But that was a problem that existed before. So this is more about drawing the points and having the image persist over time. You will still need log. But given the 2000ms redraw time this is a practical way to present your data, ' open our window and graphicsbox and set options and event labels nomainwin WindowWidth = 1920 WindowHeight = 1080 open "Graph" for graphics_nf_nsb as #1 #1 "trapclose [quit]"
' set up our bitmaps, open device contexts and store our bitmaps in them loadbmp "bak","bak.bmp"
' gDC is our graphics screen #1 "down ; fill black" #1 "getbmp bmp 0 0 1920 1080" gDC=GetDC(hwnd(#1))
' mDC is a copy of the screen in memory used as a buffer to draw graphics to ' we load our background graphic into it mDC=CreateCompatibleDC(gDC) hBitmap=hbmp("bak") oldBmp=SelectObject(mDC,hBitmap)
' some dummy data to plot
' set the rgb long value color to plot ' we are drawing outside Liberty's segment system directly to a buffer ' the buffer persists over time and will be repainted at cycle time ' if you cycle at 500 ms there is really no need for any flushing or segments red=255 ' 0-255 green=0 ' 0-255 blue=0 ' 0-255 rgb1=red+(green*256)+(blue*256*256) red=0 ' 0-255 green=255 ' 0-255 blue=0 ' 0-255 rgb2=red+(green*256)+(blue*256*256) red=0 ' 0-255 green=255 ' 0-255 blue=0 ' 0-255 rgb3=red+(green*256)+(blue*256*256) red=255 ' 0-255 green=255 ' 0-255 blue=0 ' 0-255 rgb4=red+(green*256)+(blue*256*256) red=0 ' 0-255 green=255 ' 0-255 blue=255 ' 0-255 rgb5=red+(green*256)+(blue*256*256) red=64 ' 0-255 green=255 ' 0-255 blue=128 ' 0-255 rgb6=red+(green*256)+(blue*256*256)
X=40
timer 500,[graphit] wait
[graphit]
' flip the buffer to the screen so that it is visible and stable for as long as possible call StretchBlt,gDC,0,0,1920,1080,mDC,0,0,1920,1080
' calculate and plot/draw new point to buffer ' ie read and plot our device info for Y=220 to 920 step 140 YY=int(sin(a/57.29577951)*15) color=SetPixel(mDC,X,YY+Y,rgb1) color=SetPixel(mDC,X,YY+Y+5,rgb2) color=SetPixel(mDC,X,YY+Y+10,rgb3) color=SetPixel(mDC,X,YY+Y+15,rgb4) color=SetPixel(mDC,X,YY+Y+20,rgb5) color=SetPixel(mDC,X,YY+Y+25,rgb6) next X=X+1 a=a+1 mod 360 wait
[quit] timer 0 unloadbmp "bak" call ReleaseDC hwnd(#1), gDC call DeleteDC mDC close #1
end
'=============================Window and DC functions================================= Function GetDC(hWnd) CallDLL #user32, "GetDC",_ hWnd As Ulong,_ 'window or control handle GetDC As Ulong 'returns device context End Function
Sub ReleaseDC hWnd, hDC CallDLL#user32,"ReleaseDC",_ hWnd As Ulong,_ 'window or control handle hDC As Ulong,_ 'handle of DC to delete result As Long End Sub
Function CreateCompatibleDC(hDC) CallDLL #gdi32,"CreateCompatibleDC",_ hDC As Ulong,_ 'window DC CreateCompatibleDC As Ulong 'memory DC End Function
Sub DeleteDC hDC CallDLL #gdi32, "DeleteDC",_ hDC As Ulong,_ 'memory DC to delete result As Boolean End Sub
Sub StretchBlt hDCdest,x,y,w,h,hDCsrc,x2,y2,w2,h2 CallDLL #gdi32, "SetStretchBltMode",_ hDCdest As Ulong,_ 'device context _COLORONCOLOR As Long,_ 'color reduction mode result As Long CallDLL #gdi32, "StretchBlt",_ hDCdest As Ulong,_ 'destination x As Long,_ 'destination x pos y As Long,_ 'destination y pos w As Long,_ 'destination width desired h As Long,_ 'destination height desired hDCsrc As Ulong,_ 'source x2 As Long,_ 'x location to start from source y2 As Long,_ 'y location to start from source w2 As Long,_ 'width desired from source h2 As Long,_ 'height desired from source _SRCCOPY As Ulong,_ 'dwRasterOperation result As Boolean End Sub
Function SelectObject(hDC,hObject) CallDLL #gdi32,"SelectObject",_ hDC As Ulong,_ 'memory device context hObject As Ulong,_ 'handle of object SelectObject As Ulong 'returns previously selected object End Function
Function SetPixel(hdc,x,y,rgbColor) CallDll #gdi32, "SetPixel",_ hdc as Ulong,_ 'the handle of the Device context from GetDC x as long,_ 'the x coordinate to draw the pixel y as long,_ 'the y coordinate to draw the pixel rgbColor as long,_ SetPixel as long End Function
Thank you Rod. Will certainly look into it when the Arduino is up and running
|
|
|
Post by held12345 on May 1, 2023 14:53:08 GMT -5
a question from me to rod. how can i actually draw a picture from the gdc #1.g, 0,0,128,128
on the normal screen as a graphic in graphicbox #2.g, 50,80,500,300
can you please make an example?
thanks greeting
|
|
|
Post by Rod on May 2, 2023 2:00:22 GMT -5
Too much to guess about there. There is no #2.g or indeed #1.g there is #1 a graphics window and two DC’s gDC the DC of the graphics window and mDC a copy of the first DC.
There are several articles on the LBPE that will give you a better start into blitting. Unavoidable read.
|
|