Shutdown interception

Hello ! who know how I can intercept myrobolab shutdown action ( from python or java ) , if possible.

Want to launch some actions before, like disable servo / shutdown neopixel ...

thanks !

calamity's picture

Hi Moz4r I don't know how to

Hi Moz4r

I don't know how to intecept shutdown action, but there is already a code stub to  do what you want

 

The idea is if MRL shutdown or the USB cable plug out, breaking the bidirectionnal communication between MrlComm  and MRL, MRLComm will react by shuting down or react to the lost of communication.

So when MRLComm detect a disconnection, it will call the method onDisconnect() of each devices. I have made some test with the Neopixel (showing an animation to warn about the disconnection) but that still mostly a code stub that need to be implemented

 

GroG's picture

Not sure I know what your

Not sure I know what your looking for moz4r.

Runtime will send an onReleased(Service) envent for any service being shutdown - The GUI's use these to tear down the ui appropriately - but this is after the service is dead

I've just added code to support a shutdown similar to Linux ...
Runtime.shutdown(seconds)

It broadcasts a onShutdown(seconds)
event - and in x seconds - shutsdown ..

I saw a little cleanup in SwingGui service - where it was directly terminating instead of calling the Runtime.shutdown ... this has been corrected.

I've used this event (or one like it in the past) - to give perhaps time for some unfinished business ...  Like warning the user to save their files - or auto-saving them  etc.. 

moz4r's picture

thank a lot guys !! I will

thank a lot guys !! I will play with it and tell you results

 

Mats's picture

Runtime.shutdown(seconds)

I tried to

subscribe(Runtime.getInstance().getName(), "shutdown", this.getName(), "onShutdown");

in Adafruit16CServoDriver to be able to send a last shutdown message to stop the pwm generation.

But the

Runtime.shutdown(2) command fails before the shutdown method is invoked, and a "normal" shutdown of MRL thru the GUI stops MRL without any grace period. 

http://myrobotlab.org/content/mrl-servo-control#comment-8978

How can I ensure that I can send a last i2c message before all services are stopped ?

/Mats

GroG's picture

Not sure if adding

Not sure if adding Runtime.shutdown(n) was a good idea.
This is really for the whole mrl process (all services) and not just a specific service.

The (n) seconds in Linux and Mrl shutdown is used to notify the "user" - so they can finish their activities or prepare, and should not be used to hook "system" activities.

When the Mrl Process is shutdown, the Runtime tells each and every Service to shutdown.

Each Service's "stopService()"  method is called.

This should be the area where a Service "cleans up or does its very last things"

If a Servo should detach before being released then it should be in Servo.stopService().

If there Service.stopService() is not being called before Mrl shutdown - then it is a bug and needs to be fixed.
If there is not enough time between what stopService is doing and the actual shutdown. 

For example, if there is an asynchronous I2C message being sent, then the particular stopService should block for the appropriate time.

void stopService() {
      super.stopService(); // stop inbox and outbox
      i2cSend(0,35); // stop pwm
      sleep(1000); // block for a second
}

Mats's picture

stopService not being called

That's where I started, but it seems like the stopService method isn't called for each service before MRL shuts down. 

GroG's picture

Shutting down on Windows

Shutting down on Windows using the SwingGui top right X

  • calls -> SwingGui.windowClosing() --> 
  • calls -> Runtime.shutdown(closeTimeout) -->
  • since closeTimeout == 0 -> calls Runtime.shutdown() -->
  • calls Runtime. releaseAll();

     which iterates through all services - calling stopService()  on every service.

This would work the same if a python script or cli called Runtime.shutdown()

Just tested it.

I assume your shutting it down a different way ?  Maybe the code path you took to shutdown is different ?  Also there is absolutely no way to take action if the operating system simply terminates the process .. e.g. equivalent to kill -9 pid

GroG's picture

The send message in I2C is

The send message in I2C is asynchronous at some point - perhaps all of mrl is terminating too quickly for the message to process completely.

I'd set a breakpoint in the stopService and step through the last message request.

If it works when you step through, you might require a sleep to that your service is completely stopped

moz4r's picture

Hi mats , you can override a

Hi mats , you can override a grace period of shutdown, so you have time to parse the published event

Before the subscribe method :

SwingGui.closeTimeout=8 ( seconds )

GroG's picture

If its time that a "specific"

If its time that a "specific" service needs in order to shutdown properly ONLY that service should have a sleep.

IMHO SwingGui does not need this timeout, the timeout is necessary in Adafruit16CServoDriver only.

So within Adafruit16CServoDriver's stopService :

  • override stopService in Adafruit16CServoDriver
  • iterate through all attached servos - detach them
  • send messages to each to stop pwm via I2C
  • sleep here until all messages have processed
  • done...

If you add sleep to SwingGui or are telling the Runtime to delay shutting down, you are affecting services which do not need to pause in order to shutdown.

 

Mats's picture

Shutdown sequence

Seems like the services are shutdown in the order they were started, so when stopService in Adafruit16CServoDriver is executed, the necessary low level services are already shutdown.

I.e both Arduino and Serial services are gone before I can send the message.

I see that there has been an idea of a prepareForRelease method to be executed once for each service, before executing the stopService.

It would be nice to have that, so that each service can do some preparation for shutdown, before all other services are gone.

The sequence in releaseAll would then be 

execute the prepareForRelease once for each service ( this is the method I would use to send the i2c message )

execute the stop Service once for each service ( as it is today )

I think this would make it possible to have a good shutdown sequence. It won't solve the kill -9 issue, but at least it would work when closing the GUI the normal way.

GroG's picture

Is there a 3 way dependency

Is there a 3 way dependency ?

Is this how it looks ?

Servo <--> Adafruit16CServoDriver <--> Arduino

And currently shutting it all down is dependent on the order they are shutdown ?

Can you call detach from within stopService ?

Detach is supposed to detach self as much as possible, then call detach on the other service(s).  This could have a cascade effect where a detach in the Servo propegates to Arduino, before it is released.  It potentially breaks the order dependency, because the detaching thread will process detaching in other services to the completion, before any service is released.

Mats's picture

calling detach from stopService

Perhaps I'm missundestanding your suggestion.

Do you suggest that I should call a parameterless detach() in the stopService in /myrobotlab/src/org/myrobotlab/framework/Service.java 

so that it happens in every service ?

---------------------------------------------

What I want to do is an orderly shutdown of the PCA9685 ( Adafruit16CServoDriver ).

This is what the documentation says:

Two methods can be used to do an orderly shutdown. The fastest is to write a logic 1 to bit 4 in register ALL_LED_OFF_H. The other method is to write logic 1 to bit 4 in each active PWM channel LEDn_OFF_H register.

So, since there is a very simple and fast way to turn off pwm generation for all 16 ports in a single command, that's what I want to use at shutdown. 

My suggestion is to add a method ( prepareForRelease ) in Service that gets called from Runtime in a seperate loop for each service, just before the loop that executes the stopService() here:

https://github.com/MyRobotLab/myrobotlab/blob/develop/src/org/myrobotlab...

I would like to add a loop, that iterates over each local service and calls a prepareForRelease method. At this point all services will still be active so that I can send the command. 

In Service I would add an empty prepareForRelease method so that any service can override it. 

In Adafruit16CServoDriver I would create a prepareForRelease that would send the small "pwm shutdown" i2c command. 

The important thing is that I have somewhere that I can execute it while the other services are still alive.

------------------------------

Could you please describe your suggestion in more detail. In what services should detach() be implemented, and what should it do in each service. 

------------------------------