[Nut-upsdev] [RFC apcsmart V3 10/18] drivers/apcsmart.c: add sdcmd_*() sdok()
Michal Soltys
soltys at ziu.info
Sat Mar 5 10:38:27 UTC 2011
Add functions that will be used for improved shutdown controls in next
patches.
Signed-off-by: Michal Soltys <soltys at ziu.info>
---
drivers/apcsmart.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 132 insertions(+), 0 deletions(-)
diff --git a/drivers/apcsmart.c b/drivers/apcsmart.c
index bb8d394..eb261d9 100644
--- a/drivers/apcsmart.c
+++ b/drivers/apcsmart.c
@@ -826,6 +826,138 @@ static int smartmode(void)
return 0; /* failure */
}
+/*
+ * all shutdown commands should respond with 'OK' or '*'
+ */
+static int sdok(void)
+{
+ char temp[16];
+
+ ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
+ upsdebugx(4, "sdok: got \"%s\"", temp);
+
+ if (!strcmp(temp, "*") || !strcmp(temp, "OK")) {
+ upsdebugx(4, "Last issued shutdown command succeeded");
+ return 1;
+ }
+
+ upsdebugx(1, "Last issued shutdown command failed");
+ return 0;
+}
+
+/* soft hibernate: S - working only when OB, otherwise ignored */
+static int sdcmd_S(int dummy)
+{
+ ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+
+ upsdebugx(1, "Issuing soft hibernate");
+ ser_send_char(upsfd, APC_CMD_SOFTDOWN);
+
+ return sdok();
+}
+
+/* soft hibernate, hack version for CS 350 */
+static int sdcmd_CS(int tval)
+{
+ upsdebugx(1, "Using CS 350 'force OB' shutdown method");
+ if (tval & APC_STAT_OL) {
+ upsdebugx(1, "On-line - forcing OB temporarily");
+ ser_send_char(upsfd, 'U');
+ usleep(UPSDELAY);
+ }
+ return sdcmd_S(tval);
+}
+
+/*
+ * hard hibernate: @nnn / @nn
+ * note: works differently for older and new models, see help function for
+ * detailed info
+ */
+static int sdcmd_ATn(int cnt)
+{
+ int n = 0, mmax, ret;
+ const char *strval;
+ char timer[4];
+
+ mmax = cnt == 2 ? 99 : 999;
+
+ if ((strval = getval("wugrace"))) {
+ errno = 0;
+ n = strtol(strval, NULL, 10);
+ if (errno || n < 0 || n > mmax)
+ n = 0;
+ }
+
+ snprintf(timer, sizeof(timer), "%.*d", cnt, n);
+
+ ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsdebugx(1, "Issuing hard hibernate with %d minutes additional wakeup delay", n*6);
+
+ ser_send_char(upsfd, APC_CMD_GRACEDOWN);
+ usleep(CMDLONGDELAY);
+ ser_send_pace(upsfd, UPSDELAY, timer);
+
+ ret = sdok();
+ if (ret || cnt == 3)
+ return ret;
+
+ /*
+ * "tricky" part - we tried @nn variation and it (unsurprisingly)
+ * failed; we have to abort the sequence with something bogus to have
+ * the clean state; newer upses will respond with 'NO', older will be
+ * silent (YMMV);
+ */
+ ser_send_char(upsfd, APC_CMD_GRACEDOWN);
+ usleep(UPSDELAY);
+ ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+
+ return 0;
+}
+
+/* shutdown: K - delayed poweroff */
+static int sdcmd_K(int dummy)
+{
+ ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsdebugx(1, "Issuing delayed poweroff");
+
+ ser_send_char(upsfd, APC_CMD_SHUTDOWN);
+ usleep(CMDLONGDELAY);
+ ser_send_char(upsfd, APC_CMD_SHUTDOWN);
+
+ return sdok();
+}
+
+/* shutdown: Z - immediate poweroff */
+static int sdcmd_Z(int dummy)
+{
+ ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
+ upsdebugx(1, "Issuing immediate poweroff");
+
+ ser_send_char(upsfd, APC_CMD_OFF);
+ usleep(CMDLONGDELAY);
+ ser_send_char(upsfd, APC_CMD_OFF);
+
+ return sdok();
+}
+
+static int (*sdlist[])(int) = {
+ sdcmd_S,
+ sdcmd_ATn, /* for @nnn version */
+ sdcmd_K,
+ sdcmd_Z,
+ sdcmd_CS,
+ sdcmd_ATn, /* for @nn version */
+};
+
+#define SDIDX_S 0
+#define SDIDX_AT3N 1
+#define SDIDX_K 2
+#define SDIDX_Z 3
+#define SDIDX_CS 4
+#define SDIDX_AT2N 5
+
+#define SDCNT 6
+
/* power down the attached load immediately */
void upsdrv_shutdown(void)
{
--
1.7.2.1
More information about the Nut-upsdev
mailing list