[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