Discussions related to Visual Prolog
B.Hooijenga
VIP Member
Posts: 57
Joined: 11 Jul 2002 23:01

closing the program after an unknown exception?

Unread post by B.Hooijenga »

Thomas,

Between my robot and laptop I use a bluetooth connection. In general it is working very nicely.
Sometimes during test-drives I get an unknown exception.
Mostly because my program can not deal with a real world situation..

My problem is that VIP always closes the application. I can not see the sensorreadings the robot has made so far .
I would very much have the (extra) possibilty like the exceptionhandling for internal exceptions.
There the program does not end. And then I can properly investigate the problem.

Can something be done?

Kind regards

Ben
Attachments
unknown exception.PNG
unknown exception.PNG (97.73 KiB) Viewed 13448 times
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

I am not sure I fully understand what happens. When does the program end?

Also, can you press "Copy" and then paste the exception so that I can see the entire text?

By the way, there is nothing "strange" about this exception. The exception is raised in Action here (in window):

Code: Select all

class predicates     timerProc_tick : gui_native::timerProc. clauses     timerProc_tick(Window, _Message, Timer, _Time) :-         timerAction(Action) = uncheckedConvert(timerAction, Timer),         try             Action()         catch TraceId do             _ = gui_native::killTimer(Window, Timer),             % The timer action is not retracted from the window             exception::continue_unknown(TraceId, "Exception in tickAction/delayCall")         end try.
The "difficult" thing about this exception is that it takes place in a timer actions, which mean that it runs "asynchronous" compared to your normal code. But timer actions don't happen by themselves someone/something starts them. It will be a delayCall or a tickAction as stated in the exception. Do you use any such calls yourself?

Otherwise they must have been stated indirectly by something else, you could put break points on timerAction and delayCall to see where they are called from.
Regards Thomas Linder Puls
PDC
B.Hooijenga
VIP Member
Posts: 57
Joined: 11 Jul 2002 23:01

Unread post by B.Hooijenga »

Thomas,

I will try to be more specific.

Let us suppose that there is an exception and VIP can handle it.
Then I get an exception dialog.
After I have pressed the copy-button I get a copy.
Then the exception dialog is closed but not the application.
That is important because I keep in control of the program.
I can for instance ask for sensorreadings, give a command, close a log-file and so on.
Such things are often possible because the wireless connection keeps mostly intact in spite of the exception.

Now for the case of an unknown exception.
I get also an exception dialog.
After I have pressed the copy-button I get a copy.
Then the exception dialog is closed but also the application.
I lose control and can take no actions anymore like described above. (apart from reading the copy).
That is a pity because I am pretty sure that the wireless connection is still there.

VIP will have good reasons for always closing the application after the handling of an unknown exception.
But I would be very pleased when I have a choice in this matter. As in the first situation.


As for your other questions:
I am using a timer event. At the moment with a tickduration of 700 millisconds. But that may change.
During this time laptop and robot are exchanging information. The time they need depends on the time
the Vipprogram uses to solve some questions and the time the robot needs for his actions. And there are
other factors. The tickduration is not so easy to predict, so I am experimenting.

And there are the real world problems: empty batteries, bumping to the wall, misreadings of a sensor.
Such things are unknown errors for VIP.

Kind regards

Ben
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

There is absolutely nothing special about "unknown exception".

The "unknown" comes from exception::continue_unknown in these lines of code:

Code: Select all

class predicates     timerProc_tick : gui_native::timerProc. clauses     timerProc_tick(Window, _Message, Timer, _Time) :-         timerAction(Action) = uncheckedConvert(timerAction, Timer),         try             Action()         catch TraceId do             _ = gui_native::killTimer(Window, Timer),             % The timer action is not retracted from the window             exception::continue_unknown(TraceId, "Exception in tickAction/delayCall")         end try.
If you create a new GUI project and update it like this:

Code: Select all

predicates     onShow : window::showListener. clauses     onShow(_, _CreationData) :-         _MessageForm = messageForm::display(This),         _ = tickAction(500, {  :- _ = inverse(0) }).   class predicates     inverse : (integer) -> integer. clauses     inverse(X) = 1 div X.
Then you will have a program that 500ms after it starts will perform a division by zero. It will give an exception dump similar to this:

<pre>----------------------------------------
An unknown exception has been trapped and continued

Arguments = Exception in tickAction/delayCall
unknown (exception) in window::timerProc_tick

----------------------------------------
System exception

error code = 1
ExtraInfo = Exception C0000094: Integral divide by zero
systemException (runtime_exception) in runtime_exception::runtimeExceptionRaiser

----------------------------------------
taskwindow\taskwindow.pro(24)
C:\v\user\Thomas_Linder_Puls\_vip\timerException\Exe\vipKernel.dll (0x140085D6)
C:\v\user\Thomas_Linder_Puls\_vip\timerException\Exe\vipKernel.dll (0x14006244)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x776EB652)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x776EB624)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x776D8E7F)
taskwindow\taskwindow.pro(19)
c:\v\_vp\_vip6\prodir\pfc\gui\window.pro(1016)
...</pre>

You will notice that the first entry is an "unknown exception" coming from the mentioned line, but the next entry is a "division by zero".

If you run the program you will also notice that it does not terminate after you press copy.

So there must be another reason why your program terminates.

From what I can see in your image both the first and the second entry comes from the mentioned exception::continue_unknown (which is quite strange), but the "root" of the exception is in the other end of the dump. That is where I would start the examination.
Regards Thomas Linder Puls
PDC
B.Hooijenga
VIP Member
Posts: 57
Joined: 11 Jul 2002 23:01

Unread post by B.Hooijenga »

Thomas,

Thank you.
If you run the program you will also notice that it does not terminate after you press copy.
I regret to say, but I do not follow you here.
Your suggestion terminates as well.

I made the program and included the zip-file.
If you would be so kind and have a look at it

In taskwindow.pro you find a fact readings which is just a string containing data the laptop and robot has send to eachother during a testdrive.
I put it there just for demonstration it has no further importance here. Do not waste your time with it.

Code: Select all

clauses     onShow(_, _CreationData) :-         _MessageForm = messageForm::display(This),           _ = tickAction(500, {  :- _ = inverse(0) }), %       _ = binary::getIndexed_unsigned8($[],0),         stdio::write(readings).
After an unknown exception you can only see a part of this data.
The buttons for hide details, close application, copy and ok are are all closing the application and one can not reach the data the testdrive has left behind.

Now have a look at this, please.

Code: Select all

clauses     onShow(_, _CreationData) :-         _MessageForm = messageForm::display(This), %          _ = tickAction(500, {  :- _ = inverse(0) }),        _ = binary::getIndexed_unsigned8($[],0),         stdio::write(readings).
Now the buttons for hide details, copy and ok perform there action and then we return to the taskwindow.
If you do menu/file/open you get all the data the testdrive has left behind.

It is this behaviour I would like see in the case of an unexpected exception.

Kind regards

Ben
Attachments
testUnknownException.zip
(18.48 KiB) Downloaded 429 times
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

I am sorry, that I actually didn't run my test it Vip 7.5, but in our current version. You are right it does close in Vip 7.5.

Still it doesn't have any thing to do with the unknown exception, the problem is that it happens on a timer event. I am afraid that timer events works in that way in Vip 7.5.

However the problem is that your timed predicate terminates with an exception. You still haven't shown the exception dump you get, so it is difficult to assist with that part.

You can of course make sure that you timed predicate does not terminates with an exception by wrapping it with a try-catch construction.

Have you read the Exception Handling tutorial?
Regards Thomas Linder Puls
PDC
B.Hooijenga
VIP Member
Posts: 57
Joined: 11 Jul 2002 23:01

Unread post by B.Hooijenga »

Thomas,
....but in our current version
May I conclude that in the next VIP-version, the closing problem does not exist anymore?
Still it doesn't have any thing to do with the unknown exception, the problem is that it happens on a timer event
You are absolutely right, but it was the closing problem that makes things difficult in the first place.

Anyway, I started two months ago with using the timer, after reading your tutorials on delaycall and exceptions.
I was fully aware of the problems I could expect with tickaction/delaycall in the timer event.
For the simple reason that there are a lot of uncertainties.

The interaction between two bluetooth devices is a mystery
There are RS232 timing events in windows,
There is the general eventhandling in windows which has influence on timing
The solutions/algortihms I use in my program are using time.
There are events in the c-code on the robot
There is the length of the messages laptop and robot are sending to each other.
There are sensorproperties on the robot.

Well, I am experimenting with the timer, gathering results to see if it is workable. If not, I have to look for another approach.

Here is the code I use for starting up and using the timer.

Code: Select all

predicates     onTimeronButton_ctl : button::clickResponder. clauses     onTimeronButton_ctl(_Source) = button::defaultAction :-     %    projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),         projectptr:to_commands(edit_ctl,message_ctl,toterm("10000"),toterm(wait_ctl:getText())),         not (timer1:isRunning()), % zet timer aan         edit_ctl:setText("adcl\nadc\nadcr"), % geef opdracht(en)           timer1:setTickDuration(700), % tijdsduur         timer1:start, % beginnen         !.     onTimeronButton_ctl(_Source) = button::defaultAction.     predicates     onTimer : window::timerListener. % lees sensorwaarden in % haal actie op % clauses     onTimer(_Source, _Timer) :-       if driving = false()         then             edit_ctl:setText("adcl\nadc\nadcr") ,             projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),             Command = projectptr:action(),             _ = vpi::processEvents(),             edit_ctl:setText(Command), % geef opdracht(en)             driving := true()         else             projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),             driving := false()      end if,   %    projectptr:to_commands(edit_ctl,message_ctl,toterm(readbytes_ctl:getText()),toterm(wait_ctl:getText())),    %   edit_ctl:setText("adcl\nadc\nadcr"). % geef opdracht(en)       !.     onTimer(_Source, _Timer).
By changing the tickduration to 400 milliseconds I could force the program to give an unknown exception.

The robot is reading three sensors and sends information back.
We are lucky and can just read some output.
On the screendump we see an empty tail. (left under).
I also can see (OE) in the header that this happens during the last command (adcr).
Apparently the RS232 buffer is empty: nothing to read. 400 millisecond is not enough.

Here is the full text:


========================================
Dump: 2016-08-26 12:51:56
----------------------------------------
Exception: unknown (exception)

An unknown exception has been trapped and continued

Predicate name = timerProc_tick
Arguments = Exception in tickAction/delayCall

continued 2016-08-26 12:39:45
ThreadId: 7028
Class name: window
Predicate name: timerProc_tick



----------------------------------------
Exception: indexOutOfRange (binary_exception)

Index out of binary limits

Predicate name = checkOffsetForSetGetValue
SourceCursor = pfc\binary\binary.pro(606,13)
Index = 0
binary size = 4
element size = 1

raised 2016-08-26 12:39:45
ThreadId: 7028
Class name: binary
Predicate name: checkOffsetForSetGetValue


c:\program files (x86)\visual prolog 7.5\pfc\exception\exception.pro(198)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipKernel.dll (0x140083A5)
c:\program files (x86)\visual prolog 7.5\pfc\exception\exception.pro(198)
c:\program files (x86)\visual prolog 7.5\pfc\exception\exception.pro(182)
c:\program files (x86)\visual prolog 7.5\pfc\binary\binary_exception.pro(18)
c:\program files (x86)\visual prolog 7.5\pfc\binary\binary.pro(607)
c:\program files (x86)\visual prolog 7.5\pfc\binary\binary.pro(237)
boards\boardsupport.pro(394)
boards\boardsupport.pro(332)
boards\boardsupport.pro(253)
boards\boardsupport.pro(221)
boards\boardsupport.pro(92)
testing\userinterfacers232.pro(509)
c:\program files (x86)\visual prolog 7.5\pfc\gui\window.pro(1062)
c:\program files (x86)\visual prolog 7.5\pfc\gui\window.pro(1000)
C:\WINDOWS\System32\USER32.dll (0x7795D273)
C:\WINDOWS\System32\USER32.dll (0x7793EF95)
C:\WINDOWS\System32\USER32.dll (0x7793E283)
C:\WINDOWS\System32\USER32.dll (0x7794C521)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipVpi.dll (0x1531A4EF)
c:\program files (x86)\visual prolog 7.5\pfc\vpi\vpi.pro(21)
c:\program files (x86)\visual prolog 7.5\pfc\windowsapi\exe_api\exe_api.pro(63)
c:\program files (x86)\visual prolog 7.5\pfc\application\exe\mainexe.pro(21)
main.pro(26)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipKernel.dll (0x1400884B)
C:\Users\Ben\Documents\RS232_Messages\Exe\vipKernel.dll (0x14008B0B)
C:\Users\Ben\Documents\RS232_Messages\Exe\RS232_Messages.exe (0x00548F67)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x77B50609)
C:\WINDOWS\SYSTEM32\ntdll.dll (0x77B505D4)

----------------------------------------
OS information:

Windows 8 64-bit (Build 9200)
Number Of Processors: 4 PageSize: 4096 Processor: 8664 level: 6 revision: 17665
ProcessorNameString: Intel(R) Core(TM) i5-4200U CPU @ 1.60GHz
VendorIdentifier: GenuineIntel
Identifier: Intel64 Family 6 Model 69 Stepping 1
~MHz: 2295

The code where the predicate gets an empty binary is here.

Code: Select all

predicates     tailCheck:(binary) -> boolean. clauses     tailCheck(Tail) = true() :-         Length = binary::getSize(Tail),         etx = binary::getIndexed_unsigned8(Tail,uncheckedConvert(core::positive,Length-1)), % Index starts at 0         message:write("EndOfText = Ok\n"),         !.    tailCheck(Tail) = false() :-         Length = binary::getSize(Tail),         message:write("EndOfText must be ",etx," instead of ",binary::getIndexed_unsigned8(Tail,uncheckedConvert(core::positive,Length)),"\n"),         !.

Thanks for all your suggestions
Kind regards

Ben
Attachments
unknown_exception_400millisec.PNG
unknown_exception_400millisec.PNG (237.37 KiB) Viewed 13394 times
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

Yes, the mentioned problem does not exist in the next version.

You can easily make it disappear in your version also; simply by catching all exceptions in your times predicate:

Code: Select all

predicates     onTimer_safe : window::timerListener. clauses     onTimer_safe(Source, Timer) :-         try             onTimer(Source, Timer)         catch TraceId do             errorPresentationDialog::present(TraceId)         end try.
Regards Thomas Linder Puls
PDC
B.Hooijenga
VIP Member
Posts: 57
Joined: 11 Jul 2002 23:01

Unread post by B.Hooijenga »

Thomas,

I tried your suggestion, again with forcing an unknown exception with 400 milliseconds time duration instead of 700.
But no result: it does not work: my program hangs, the robot goes wild and bluetooth is not happy either.
No harm done.

Then I tried this:

Code: Select all

predicates     onShow : window::showListener. clauses     onShow(_, _CreationData) :-         _MessageForm = messageForm::display(This),          try          _ = tickAction(500, {  :- _ = inverse(0) })         catch TraceId do             errorPresentationDialog::present(TraceId)         end try.   class predicates     inverse : (integer) -> integer. clauses     inverse(X) = 1 div X.
No effect. The program just closes on all buttons.

So, I am afraid I have to wait until the new VIP version arrives.
In the meantime I try to investigate my program further. There is always room for improvement!

Kind regards

Ben
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

That is the wrong place you catch the exception.

It is the code that is exceuted in the timer call that must catch the exception:

Code: Select all

predicates     onShow : window::showListener. clauses     onShow(_, _CreationData) :-         _MessageForm = messageForm::display(This),         delayCall(500, {  :- _ = inverse_safe(0) }).   class predicates     inverse_safe : (integer) -> integer. clauses     inverse_safe(X) = R :-          try             R = inverse(X)         catch TraceId do             errorPresentationDialog::present(TraceId),             R = 0         end try.   class predicates     inverse : (integer) -> integer. clauses     inverse(X) = 1 div X.
I have changed the tickAction to a delayCall because otherwise you will get an exception each 500 ms and that will give quite a lot of dialogs. But the principle is the same: the timer action should never exit with an exception.
Regards Thomas Linder Puls
PDC
B.Hooijenga
VIP Member
Posts: 57
Joined: 11 Jul 2002 23:01

Unread post by B.Hooijenga »

Thomas

Because I am using a timerevent in my robotprogram I was a little bit confused about the delaycall.
This is the solution I eventually use.
The trick is to stop the timer in case of an systemerror.
It seems to work well.
I did not see the term unknownexception anymore by driving the robot.

Code: Select all

facts     timer1 : timerControl := erroneous.   predicates     onShow : window::showListener. clauses     onShow(_Source, _Data) :-         timer1:= timerControl::new(This),         stdio::write("tickduration = ",timer1 :getTickDuration(),"\n"),         timer1:start.   predicates     onTimer : window::timerListener. clauses     onTimer(_Source, _Timer) :-     %    delayCall(1, {  :- _ = inverse_safe(4) }).         _ = inverse_safe(0).     predicates     inverse_safe : (integer) -> integer. clauses     inverse_safe(X) = R :-          try             R = inverse(X),             stdio::write(R,"\n")         catch TraceId do             timer1:stop,             errorPresentationDialog::present(TraceId),             R = 0         end try.   class predicates     inverse : (integer) -> integer. clauses     inverse(X) = 1 div X.  
Thanks very much for your help.

Kind regards

Ben
User avatar
Thomas Linder Puls
VIP Member
Posts: 1398
Joined: 28 Feb 2000 0:01

Unread post by Thomas Linder Puls »

I think you should drop using the timerControl it is an "outdated" thing. Instead you should either use:
  • delayCall for one "shots"
  • tickAction for repeated "shots"
Basically the tickAction does the same as the timerControl just without an extra control.
Regards Thomas Linder Puls
PDC
Post Reply