Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 16, 2023 10:35:58 GMT -5
Hello all,
Just run across an issue with Liberty Basic when some other Windows program is brought forward, and L.B. stays running in the background. My L.B. program has a visible clock in it. displayed by reading system clock through time$(). It happens that if L.B. is not in Windows foreground, the clock stops running. When brought forward again, the clock starts running really fast until it catches up with system clock. Weird, but would not be a major issue if the following didn't happen: The purpose of the displayed clock, is for the operator to know when a new COM port reading will take place. As such readings should happen at precise intervals. As soon as the L.B. program windows goes into Windows background mode, these timed readings stop happening. No COM port activity can be seen.
More: Once L.B. is brought to Windows Foreground again, and the clock starts running really fast until it catches up. No further COM port readings take place. Even waiting a while after the clocks is running normally again, COM port readings no longer happen. Everything else in my program, keystrokes, mouse clicks, works ok. Just no further COM activity after this. Only by exiting the program and start again, will the COM port show activity.
Has anyone expirienced this before? I'm I missing something in my code/doing it wrong that causes this? Any ideas?
Thank you
|
|
|
Post by Rod on Apr 16, 2023 11:43:00 GMT -5
When the window is in the background the drawing actions are stored in a segment and then redrawn when windows decided the screen should be repainted. The program still runs and should be handling the com port.
So you need a different strategy for drawing that does not store everything in the segment, or you need to put the clock screen on top and constantly in view.
For a better answer post example code so that we can show alternatives. Try and rem out the com code and just show us the timed drawing of your clock.
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 16, 2023 12:30:56 GMT -5
Hi Rod, This is what I call "the main loop" Program is basically cycling around until the time calculations trigger an event. Then there's a much larger loop that encompases this one, all the COM stuff, calculus and associated drawings. The lack of, or delayed, drawing may be annoying, but is not a major issue. The clock doesn't necessarily need to be in view all the time, but the COM read timing MUST happen
The fact that COM transmissions cease is my problem. The 2 CALL functions don't jump anywhere else. Always come back to the call point. There's keyboard and mouse handling sub routines that are triggered by event. However, the described issue still happens even if no key/mouse button is pressed do reading=0 #graph, "place 1585 40" call calcweek week call printweek week #graph, "|";date$() #graph, "|";time$() if settfile(1)>0 then #graph, "place 1290 90" #graph, "| ";autorltmr;" min. " end if timestamp=val(mid$(time$(),1,2))*60+val(mid$(time$(),4,2)) if timestamp<>autorl then autorl=timestamp reading=1 if settfile(1)>0 then autorltmr=autorltmr-1 if autorltmr=0 then key$="r" end if end if end if scan loop until key$="x" or key$="r" or reading=1 Thank you ************************************** EDIT ********************************* Just noticed that if I do the switching back and forth between the L.B. window, and some other Windows window, The "racing" of the clock always starts at the same original point when the first switching to background occurred. Gives me the impresson there's some sort of "cache" memory that needs "dumping" in order for the new one to go in?
|
|
|
Post by tsh73 on Apr 16, 2023 14:17:29 GMT -5
Yes That's graphic segments memory All you draw is stored, and on window opening is replayed back (what you see as time "fast forward")
try #graph "discard" before updating #graph This way it will not be stored at all (but then you can get empty window if drawing will not happen soon)
or "#flush someSegmentName" after drawing - this way only last update will be saved. sorry could not make some working example.
*(probably using some text control just to show text will be easier way out)
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 16, 2023 15:07:09 GMT -5
I see...
Window drawing will be "freezed" while in background. Once back in foreground, everything that the code sent for drawing, will be drawed as fast as possible. Is there a way for the code to know when it's window is active or freezed?
Still doesn't explain why COM port stops working. Any hints?
Thanks
|
|
|
Post by Rod on Apr 17, 2023 3:42:39 GMT -5
Look at the clock demo that ships with Liberty. If you work it through you will see that there is only ever two segments. If you don't manage the segments correctly you can build up thousands of segments to redraw. While Windows is busy doing that nothing else gets done. So I added a counter to clock.bas. You will see that even minimised it still keeps counting /calling com read even though the clock ticks and count increase are not displayed. So it continues to run in the background.
We would really need to see the rest of the code to give specific advice.
'clock2.bas - a clock program for Just BASIC v1.0
WindowWidth = 120 WindowHeight = 144 nomainwin open "Clock" for graphics_nsb_nf as #clock print #clock, "trapclose [exit]"
print #clock, "fill white" for angle = 0 to 330 step 30 print #clock, "up ; home ; north ; turn "; angle print #clock, "go 40 ; down ; go 5" next angle
print #clock, "flush"
timer 1000, [display] wait
[display] ' call this only when seconds has changed
'call our com read count=count+1 time$ = time$() hours = val(time$) if hours > 12 then hours = hours - 12 minutes = val(mid$(time$, 4, 2)) seconds = val(right$(time$, 2))
' delete the last drawn segment, if there is one if segId > 2 then print #clock, "delsegment "; segId - 1
' center the turtle print #clock, "up ; home ; down ; north" #clock "place 20 20 ;\";count
' erase each hand if its position has changed if oldHours <> hours then print #clock, "size 2 ; color white ; turn "; oldHours * 30 + int(oldMinutes/2) ; " ; go 19 ; home ; color black ; north" : oldHours = hours if oldMinutes <> minutes then print #clock, "size 2 ; color white ; turn "; oldMinutes * 6 ; " ; go 38 ; home ; color black ; north" : oldMinutes = minutes if oldSeconds <> seconds then print #clock, "size 1 ; color white ; turn "; oldSeconds * 6 ; " ; go 38 ; home ; color black ; north" : oldSeconds = seconds
' redraw all three hands, second hand first print #clock, "size 1 ; turn "; seconds * 6 ; " ; go 38" print #clock, "size 2 ; home ; north ; turn "; hours * 30 + int(minutes/2); " ; go 19" print #clock, "home ; north ; turn "; minutes * 6 ; " ; go 38"
' flush to end segment, then get the next segment id # print #clock, "flush" print #clock, "segment" input #clock, segId
wait
[exit]
timer 0 'prevent timer ticks from building up confirm "Quit Clock?"; q$ if q$ = "yes" then close #clock else timer 1000, [display] wait end if
end
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 17, 2023 10:00:34 GMT -5
I think I got your point Rod.
My code draws many stuff continuously, regardless if it needs to be drawn or not. It's a cycle that repeats itself without looking at anything else. I had no previous knowledge of that "build up" once in background.
Your code draws stuff ONLY WHEN REQUIRED. This certainly reduces the issue to a minimum.
Just guessing here: If my code generates that much commands in the background, maybe there's no time do to anything else, including the COM port commands? Will try to rewrite it in such a way that will mimic yours in terms of amount of commands.
My full program is pretty big already. The .BAS file is nearly 35k. Don't mind posting it here, but is this ok?
|
|
|
Post by Rod on Apr 17, 2023 10:48:13 GMT -5
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 17, 2023 11:42:30 GMT -5
These simple changes in my main cycle were enough. Anything that doesn't have to be continuously drawn is now outside the main cycle. It will still be redrawn every minute or so, in the outside bigger loop. But not continuosly. #graph, "place 1585 40" call calcweek week call printweek week #graph, "|";date$() do #graph "discard" reading=0 #graph, "place 1585 78" #graph, "|";time$() if settfile(1)>0 then #graph, "place 1290 90" #graph, "| ";autorltmr;" min. " end if timestamp=val(mid$(time$(),1,2))*60+val(mid$(time$(),4,2)) if timestamp<>autorl then autorl=timestamp reading=1 if settfile(1)>0 then autorltmr=autorltmr-1 if autorltmr=0 then key$="u" end if end if end if scan loop until key$="x" or key$="u" or reading=1 time$() is still redrawn in a continuous fashion, instead of just every second. Guess that just including the command tsh73 suggested, "discard" would have done it. In any case, COM port is now operational all the time, and does what is supposed to do. When I come back to L.B. window, no clock fast forward happens. Still reading the tutorials in the links, Rod. Will not rest until i find out why the COM port stopped in those conditions. Thank you Rod and tsh73
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 19, 2023 12:43:29 GMT -5
Hello again. Still strugling with the inactive COM issue. There's no fast forward time anymore. Clock always in sync with system clock. However, if L.B. is left long enough in the background, the issue of the COM port becoming inactive still exists.
This is my main loop inserted in the bigger outside loop. As can be seen, the main loop only draws what is stricly necessary when necessary. There's a "discard" command executed everytime something new needs to de drawn.
pvafrx=(val(mid$(time$(),1,2))*60+val(mid$(time$(),4,2)))*timediv+46 autorl=val(mid$(time$(),1,2))*60+val(mid$(time$(),4,2)) autorltmr=settfile(1) do <-- OUTSIDE LOOP HERE for maincyc=1 to 6 if housediv(maincyc,1)<2 then ' Relay and process values reading modbuspacket(1,1)=maincyc ' Device modbuspacket(2,1)=3 ' Command modbuspacket(3,1)=0 modbuspacket(4,1)=1 ' First address to read modbuspacket(5,1)=0 modbuspacket(6,1)=3 ' Amount of addresses call sendpacket 6, errortype if errortype=0 then housediv(maincyc,1)=modbuspacket(5,2) housediv(maincyc,2)=modbuspacket(6,2)*256+modbuspacket(7,2) if housediv(maincyc,2)=350 then housediv(maincyc,2)=0 end if housediv(maincyc,3)=modbuspacket(8,2)*256+modbuspacket(9,2) #graph, "size 1" curafrx=(val(mid$(time$(),1,2))*60+val(mid$(time$(),4,2)))*timediv+46 #graph, "color red" curafry=vdiv*maincyc+130-60*housediv(maincyc,1) #graph, "line ";pvafrx;" ";housediv(maincyc,12);" ";curafrx;" ";curafry housediv(maincyc,12)=curafry #graph, "color green" curafry=vdiv*maincyc+130-2*(housediv(maincyc,3)/10-5) #graph, "line ";pvafrx;" ";housediv(maincyc,11);" ";curafrx;" ";curafry housediv(maincyc,11)=curafry #graph, "color yellow" curafry=vdiv*maincyc+130-2*(housediv(maincyc,2)/10-5) #graph, "line ";pvafrx;" ";housediv(maincyc,10);" ";curafrx;" ";curafry housediv(maincyc,10)=curafry pvafrx=curafrx else housediv(maincyc,1)=2 end if end if call redraw maincyc next maincyc #graph, "place 1585 40" call calcweek week call printweek week #graph, "|";date$() if settfile(1)>0 then #graph, "place 1290 90" #graph, "| ";autorltmr;" min. " end if #graph, "flush" #graph, "place 1585 78" #graph, "|";time$() prevsec=val(mid$(time$(),7,8)) do <-- MAIN LOOP HERE reading=0 cursec=val(mid$(time$(),7,8)) if cursec<>prevsec then prevsec=cursec #graph, "discard" #graph, "place 1585 78" #graph, "|";time$() timestamp=val(mid$(time$(),1,2))*60+val(mid$(time$(),4,2)) if timestamp<>autorl then autorl=timestamp reading=1 if settfile(1)>0 then autorltmr=autorltmr-1 if autorltmr=0 then key$="u" end if end if end if end if scan loop until key$="x" or key$="u" or reading=1 loop until key$="x" or key$="u"
The "call sendpacket" routine is what actually sends and receives data through the COM port
sub sendpacket nbytes, byref errortype #graph, "size 5" #graph, "color yellow" 'Tx #graph, "line 255 ";vdiv*modbuspacket(1,1)+21;" 265 ";vdiv*modbuspacket(1,1)+21 errortype=255 ' 255=No communication call crc16, crclo, crchi, 1, nbytes '1=output, 2=input arrays modbuspacket(nbytes+1,1)=crclo 'Order that should be used modbuspacket(nbytes+2,1)=crchi 'Low first, High last for tx=1 to nbytes+2 #comm, chr$(modbuspacket(tx,1)); next tx timeout=0 timer 200, clocktick ' Wait for response. 56 is probably enough do scan loop until timeout=1 dataread$="" if lof(#comm) then timer 0 dataread$ = input$(#comm, lof(#comm)) for rx=1 to len(dataread$) modbuspacket(rx,2)=asc(mid$(dataread$,rx,1)) next rx call crc16, crclo, crchi, 2, len(dataread$)-2 if crclo=modbuspacket(len(dataread$)-1,2) and crchi=modbuspacket(len(dataread$),2) then errortype=0 ' No error else errortype=1 ' Wrong CRC16. =18 (error) to be implemented #graph, "color red" #graph, "line 207 ";vdiv*modbuspacket(1,1)+21;" 218 ";vdiv*modbuspacket(1,1)+21 end if end if #graph, "color black" #graph, "line 255 ";vdiv*modbuspacket(1,1)+21;" 265 ";vdiv*modbuspacket(1,1)+21 if errortype=0 or errortype=255 then #graph, "line 207 ";vdiv*modbuspacket(1,1)+21;" 218 ";vdiv*modbuspacket(1,1)+21 end if timeout=0 timer 50, clocktick ' Wait time until another transmission can start do scan loop until timeout=1 end sub
The rest of the program is pretty much inactive most of the time and doesn't handle any timings Any ideas of what might be happening? Thank you
|
|
|
Post by Rod on Apr 20, 2023 1:53:25 GMT -5
Leave aside the com port for now. Write a simple clock print program. Does it keep running. If not you need to use windows help to look and see what you power saving options have been set to. I suspect your pc is stopping.
If not then we need to look see what the com port buffer is doing, it may be filling up and not getting emptied fast enough. But it is probably your power settings.
I have still to look at the code, will do so later today.
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 20, 2023 2:19:24 GMT -5
Hi Rod,
A simple clock always keeps running. No issues here. I've used my "main cycle", stripped of everything else for this test.
I can assure you that both the pc, and windows, never go into sleep or stanby. Such options are turned off. There's always something happening in the background. Or a user is actually using it.
A windows driver issue maybe? It is the latest I could find. The port itself is implemented with a USB converter.
The wait time between transmissions was determined by a logic analyser. 150ms more were added to this as a precaution. Will try to modify the buffer size, see if that helps.
Thanks
|
|
|
Post by Rod on Apr 20, 2023 3:20:24 GMT -5
Ok, there are a few things in the code. First is just reading the com port without checking the length. That can get garbled messages. Next is the timer routines coupled with the scan command inside a sub. Timer routines are best encased entirely within a sub. But without the whole code it is hard to be specific.
The first thing to do is to put some logging code in, keep the mainwin open and simply print where you are, especially when you start a loop. Print the loop name as soon as you enter the loop. Now run the code and see if you are stuck in a non productive loop somewhere, you will at least see where you were when it stops.
I dont think it is much to do with drawing, more likely program flow.
|
|
Nuno
Junior Member
Posts: 64
|
Post by Nuno on Apr 20, 2023 5:34:26 GMT -5
just reading the com port without checking the length. That can get garbled messages. I agree that such is not a good practice. But the received messages are MODBUS packets. This means that there will be 2 Cyclic Redundancy Check bytes at the end of the message. If the message is too short, too long, or contains incorrect bytes, it will not be accepted by the CRC verification. Checking for correct lenght before reading becomes a bit redundant. In any case, I have no issues whatsoever with received messages. Problem is the transmission that stops entirely if L.B. is in the background for too long.
"Next is the timer routines coupled with the scan command inside a sub. Timer routines are best encased entirely within a sub."
Ok, will take a closer look at that. Any practical suggestions?
"But without the whole code it is hard to be specific."
As already mentioned, the whole code is about 35k long. I don't mind posting/sharing it here. but would you like to receive it in some more practical way?
"The first thing to do is to put some logging code in, keep the mainwin open and simply print where you are, especially when you start a loop. Print the loop name as soon as you enter the loop. Now run the code and see if you are stuck in a non productive loop somewhere, you will at least see where you were when it stops."
Can do that. But as it is, nothing wrong happens, no errors or freezing loops, if L.B. window is in the foreground all the time. I think that would only tell me what loops do I have that are wasting a lot of time doing nothing/useless code.
Thank you
|
|
|
Post by Brandon Parker on Apr 20, 2023 10:45:44 GMT -5
When this happens, have you gone into the Device Manager and checked that the port is still active or looked at a logic analyzer prior to bringing the window back into the foreground or otherwise activating it in any other way?
{:0)
Brandon Parker
|
|