diff --git a/docs/man/apcsmart.txt b/docs/man/apcsmart.txt index 6a474c73dc..0e00e7e643 100644 --- a/docs/man/apcsmart.txt +++ b/docs/man/apcsmart.txt @@ -146,6 +146,10 @@ behaviour quite a bit, depending on the model. Immediately before issuing *S*, "simulate power failure" is issued. The remaining behaviour is as in *S* case. + +There's a delay between "simulate power failure" and *S* - by default set to +3.5s. You can control it through *cshdelay* option (allowed values are from 0 +to 9.9). ++ The name came from APC CS models, where such trick was used to power down UPSes in consistent fashion using only *S*. It\'s better to use *@nnn* command if your UPS supports it (and is not too old, see below). diff --git a/drivers/apcsmart.c b/drivers/apcsmart.c index d437467846..3417479f72 100644 --- a/drivers/apcsmart.c +++ b/drivers/apcsmart.c @@ -1441,10 +1441,14 @@ static int sdcmd_S(const void *foo) /* soft hibernate, hack version for CS 350 & co. */ static int sdcmd_CS(const void *foo) { - int ret; + int ret, cshd = 3500000; char temp[APC_SBUF]; + const char *val; + + if ((val = getval("cshdelay"))) + cshd = (int)(strtod(val, NULL) * 1000000); - debx(1, "issuing CS 'hack' [%s+%s]", prtchr(APC_CMD_SIMPWF), prtchr(APC_CMD_SOFTDOWN)); + debx(1, "issuing CS 'hack' [%s+%s] with %2.1f sec delay", prtchr(APC_CMD_SIMPWF), prtchr(APC_CMD_SOFTDOWN), (double)cshd / 1000000); if (ups_status & APC_STAT_OL) { apc_flush(0); debx(1, "issuing [%s]", prtchr(APC_CMD_SIMPWF)); @@ -1457,6 +1461,7 @@ static int sdcmd_CS(const void *foo) if (ret < 0) { return STAT_INSTCMD_FAILED; } + usleep(cshd); } /* continue with regular soft hibernate */ return sdcmd_S((void *)1); @@ -2000,6 +2005,7 @@ void upsdrv_makevartable(void) addvar(VAR_VALUE, "awd", "hard hibernate's additional wakeup delay"); addvar(VAR_VALUE, "sdtype", "simple shutdown method"); addvar(VAR_VALUE, "advorder", "advanced shutdown control"); + addvar(VAR_VALUE, "cshdelay", "CS hack delay"); } void upsdrv_help(void) @@ -2031,6 +2037,11 @@ void upsdrv_initups(void) fatalx(EXIT_FAILURE, "invalid value (%s) for option 'advorder'", val); } + /* sanitize cshdelay */ + if ((val = getval("cshdelay")) && !rexhlp(APC_CSHDFMT, val)) { + fatalx(EXIT_FAILURE, "invalid value (%s) for option 'cshdelay'", val); + } + upsfd = extrafd = ser_open(device_path); apc_ser_set(); diff --git a/drivers/apcsmart.h b/drivers/apcsmart.h index 8bfc914f91..601d4fedec 100644 --- a/drivers/apcsmart.h +++ b/drivers/apcsmart.h @@ -161,6 +161,9 @@ /* advorder method regex format*/ #define APC_ADVFMT "^([0-4]{1,5}|[Nn][Oo])$" +/* cshdelay format */ +#define APC_CSHDFMT "^([0-9]\\.?|[0-9]?\\.[0-9])$" + /* error logging/debug related macros */ #define fatx(fmt, ...) fatalx(EXIT_FAILURE, "%s: " fmt, __func__ , ## __VA_ARGS__)