3030#include <timehead.h>
3131
3232#define DRIVER_NAME "NUT ADELSYSTEM DC-UPS CB/CBI driver"
33- #define DRIVER_VERSION "0.03 "
33+ #define DRIVER_VERSION "0.04 "
3434
3535/* variables */
3636static modbus_t * mbctx = NULL ; /* modbus memory context */
@@ -49,7 +49,6 @@ static uint32_t mod_resp_to_us = MODRESP_TIMEOUT_us; /* set the modbus response
4949static uint32_t mod_byte_to_s = MODBYTE_TIMEOUT_s ; /* set the modbus byte time out (us) */
5050static uint32_t mod_byte_to_us = MODBYTE_TIMEOUT_us ; /* set the modbus byte time out (us) */
5151
52-
5352/* initialize alarm structs */
5453void alrminit (void );
5554
@@ -193,6 +192,11 @@ void upsdrv_initinfo(void)
193192 /* register instant commands */
194193 dstate_addcmd ("load.off" );
195194
195+ /* FIXME: Check with the device what this instcmd
196+ * (nee upsdrv_shutdown() contents) actually does!
197+ */
198+ dstate_addcmd ("shutdown.stayoff" );
199+
196200 /* set callback for instant commands */
197201 upsh .instcmd = upscmd ;
198202}
@@ -464,33 +468,24 @@ void upsdrv_updateinfo(void)
464468/* shutdown UPS */
465469void upsdrv_shutdown (void )
466470{
467- int rval ;
468- int cnt = FSD_REPEAT_CNT ; /* shutdown repeat counter */
469- struct timeval start ;
470- long etime ;
471-
472- /* retry sending shutdown command on error */
473- while ((rval = upscmd ("load.off" , NULL )) != STAT_INSTCMD_HANDLED && cnt > 0 ) {
474- rval = gettimeofday (& start , NULL );
475- if (rval < 0 ) {
476- upslog_with_errno (LOG_ERR , "upscmd: gettimeofday" );
477- }
471+ /* Only implement "shutdown.default"; do not invoke
472+ * general handling of other `sdcommands` here */
478473
479- /* wait for an increasing time interval before sending shutdown command */
480- while (( etime = time_elapsed ( & start )) < ( FSD_REPEAT_INTRV / cnt ));
481- upsdebugx ( 2 , "ERROR: load.off failed, wait for %lims, retries left: %d\n" , etime , cnt - 1 );
482- cnt -- ;
483- }
484- switch ( rval ) {
485- case STAT_INSTCMD_FAILED :
486- case STAT_INSTCMD_INVALID :
487- fatalx ( EXIT_FAILURE , "shutdown failed" );
488- case STAT_INSTCMD_UNKNOWN :
489- fatalx ( EXIT_FAILURE , "shutdown not supported" );
490- default :
491- break ;
492- }
493- upslogx ( LOG_INFO , "shutdown command executed" );
474+ /*
475+ * WARNING: When using RTU TCP, this driver will probably
476+ * never support shutdowns properly, except on some systems:
477+ * In order to be of any use, the driver should be called
478+ * near the end of the system halt script (or a service
479+ * management framework's equivalent, if any). By that
480+ * time we, in all likelyhood, won't have basic network
481+ * capabilities anymore, so we could never send this
482+ * command to the UPS. This is not an error, but rather
483+ * a limitation (on some platforms) of the interface/media
484+ * used for these devices.
485+ */
486+ int ret = do_loop_shutdown_commands ( "shutdown.stayoff" , NULL ) ;
487+ if ( handling_upsdrv_shutdown > 0 )
488+ set_exit_flag ( ret == STAT_INSTCMD_HANDLED ? EF_EXIT_SUCCESS : EF_EXIT_FAILURE );
494489}
495490
496491/* print driver usage info */
@@ -832,6 +827,43 @@ int upscmd(const char *cmd, const char *arg)
832827 upsdebugx (2 , "load.off: addr: 0x%x, data: %d" , regs [FSD ].xaddr , data );
833828 rval = STAT_INSTCMD_HANDLED ;
834829 }
830+ } else if (!strcasecmp (cmd , "shutdown.stayoff" )) {
831+ /* FIXME: Which one is this actually -
832+ * "shutdown.stayoff" or "shutdown.return"? */
833+ int cnt = FSD_REPEAT_CNT ; /* shutdown repeat counter */
834+ struct timeval start ;
835+ long etime ;
836+
837+ /* retry sending shutdown command on error */
838+ while ((rval = upscmd ("load.off" , NULL )) != STAT_INSTCMD_HANDLED && cnt > 0 ) {
839+ rval = gettimeofday (& start , NULL );
840+ if (rval < 0 ) {
841+ upslog_with_errno (LOG_ERR , "upscmd: gettimeofday" );
842+ }
843+
844+ /* wait for an increasing time interval before sending shutdown command */
845+ while ((etime = time_elapsed (& start )) < ( FSD_REPEAT_INTRV / cnt ));
846+ upsdebugx (2 , "ERROR: load.off failed, wait for %lims, retries left: %d\n" , etime , cnt - 1 );
847+ cnt -- ;
848+ }
849+ switch (rval ) {
850+ case STAT_INSTCMD_FAILED :
851+ case STAT_INSTCMD_INVALID :
852+ upslog_with_errno (LOG_ERR , "instcmd: %s failed" , cmd );
853+ if (handling_upsdrv_shutdown > 0 )
854+ set_exit_flag (EF_EXIT_FAILURE );
855+ break ;
856+ case STAT_INSTCMD_UNKNOWN :
857+ upslog_with_errno (LOG_ERR , "instcmd: %s not supported" , cmd );
858+ if (handling_upsdrv_shutdown > 0 )
859+ set_exit_flag (EF_EXIT_FAILURE );
860+ break ;
861+ default :
862+ upslogx (LOG_INFO , "shutdown command executed" );
863+ if (handling_upsdrv_shutdown > 0 )
864+ set_exit_flag (EF_EXIT_SUCCESS );
865+ break ;
866+ }
835867 } else {
836868 upslogx (LOG_NOTICE , "instcmd: unknown command [%s] [%s]" , cmd , arg );
837869 rval = STAT_INSTCMD_UNKNOWN ;
0 commit comments