1
/* mustek.c - model specific routines for mustek UPS models
3
Based on blazer.c driver from nut 2.0.0.
5
Modified to work with Mustek PowerMust by Martin Hajduch (martin@hajduch.de).
6
If it does not work as expected, please send me a note.
7
Well, you can send me a note even if it works as expected ;-)
9
Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
10
2002 Phil Hutton <mustek-driver@hutton.sh>
11
2003 Arnaud Quette <arnaud.quette@free.fr>
12
2004 Martin Hajduch <martin@hajduch.de>
14
This program is free software; you can redistribute it and/or modify
15
it under the terms of the GNU General Public License as published by
16
the Free Software Foundation; either version 2 of the License, or
17
(at your option) any later version.
19
This program is distributed in the hope that it will be useful,
20
but WITHOUT ANY WARRANTY; without even the implied warranty of
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
GNU General Public License for more details.
24
You should have received a copy of the GNU General Public License
25
along with this program; if not, write to the Free Software
26
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32
#define DRV_VERSION "0.2"
34
#define ENDCHAR 13 /* replies end with CR */
37
#define SENDDELAY 100000 /* 100 ms delay between chars on transmit */
38
#define SER_WAIT_SEC 2 /* allow 3.0 sec for responses */
39
#define SER_WAIT_USEC 0
41
static float lowvolt = 0, highvolt = 0, voltrange = 0;
42
static int poll_failures = 0;
43
static int inverted_bypass_bit = 0;
46
static int instcmd(const char *cmdname, const char *extra)
48
/* Stop battery test */
49
if (!strcasecmp(cmdname, "test.battery.stop")) {
50
ser_send_pace(upsfd, SENDDELAY, "CT\r");
51
return STAT_INSTCMD_HANDLED;
54
/* Start battery test */
55
if (!strcasecmp(cmdname, "test.battery.start")) {
56
ser_send_pace(upsfd, SENDDELAY, "T\r");
57
return STAT_INSTCMD_HANDLED;
60
upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
61
return STAT_INSTCMD_UNKNOWN;
64
void upsdrv_initinfo(void)
66
dstate_setinfo("driver.version.internal", "%s", DRV_VERSION);
67
dstate_setinfo("ups.mfr", "Mustek");
68
dstate_setinfo("ups.model", "PowerMust");
70
dstate_addcmd("test.battery.start");
71
dstate_addcmd("test.battery.stop");
73
printf("Detected UPS on %s\n", device_path);
75
upsh.instcmd = instcmd;
77
/* paranoia - cancel any shutdown that might already be running */
78
ser_send_pace(upsfd, SENDDELAY, "C\r");
81
static void ups_sync(void)
86
printf("Syncing with UPS: ");
91
if (tries > MAXTRIES) {
92
fatalx("\nFailed - giving up...");
98
ret = ser_send_pace(upsfd, SENDDELAY, "F\r");
102
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
103
SER_WAIT_SEC, SER_WAIT_USEC);
104
if (buf[0]=='#' && strlen(buf)>1) {
105
/* F command successful ! */
106
ret = ser_send_pace(upsfd, SENDDELAY, "Q1\r");
110
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
111
SER_WAIT_SEC, SER_WAIT_USEC);
112
if (buf[0]=='(' && strlen(buf)>2) {
118
/* not successful ! */
128
void upsdrv_shutdown(void)
130
ser_send_pace(upsfd, SENDDELAY, "S01R0001\r");
133
static void ups_ident(void)
138
float ratevolt, ratefreq;
140
printf("Identifying UPS: ");
145
if (tries > MAXTRIES) {
146
upsdebugx(2, "Failed - giving up...");
152
ret = ser_send_pace(upsfd, SENDDELAY, "F\r");
156
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
157
SER_WAIT_SEC, SER_WAIT_USEC);
159
/* don't be so strict about the return,
160
it should look reasonable, though */
161
if ((ret > 0) && (buf[0] == '#') && (strlen(buf) > 15)) {
172
sscanf(buf, "%*c %f %d %*f %f", &ratevolt, &ratecurrent, &ratefreq);
173
upsdebugx(2, "UPS is rated at %.2fV, %dA, %.2fHz.\n",
174
ratevolt, ratecurrent, ratefreq);
176
/* Just some guess ... */
180
voltrange = highvolt - lowvolt;
183
static void pollfail(const char *why)
187
/* ignore the first few since these UPSes tend to drop characters */
188
if (poll_failures == 3) {
195
void upsdrv_updateinfo(void)
197
char utility[16], outvolt[16], loadpct[16], acfreq[16],
198
battvolt[16], upstemp[16], pstat[16], buf[256];
202
ret = ser_send_pace(upsfd, SENDDELAY, "Q1\r");
205
pollfail("Poll failed: send status request failed");
212
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, "",
213
SER_WAIT_SEC, SER_WAIT_USEC);
216
pollfail("Poll failed: read failed");
221
if (strlen(buf) < 40) {
222
pollfail("Poll failed: short read from UPS");
227
if (strlen(buf) > 50) {
228
pollfail("Poll failed: oversized read from UPS");
234
pollfail("Poll failed: invalid start character");
238
/* only say this if it got high enough to log a failure note */
239
if (poll_failures >= 3) {
245
sscanf(buf, "%*c%s %*s %s %s %s %s %s %s", utility, outvolt,
246
loadpct, acfreq, battvolt, upstemp, pstat);
248
bvoltp = ((atof (battvolt) - lowvolt) / voltrange) * 100.0;
250
if (bvoltp > 100.0) {
254
dstate_setinfo("input.voltage", "%s", utility);
255
dstate_setinfo("input.frequency", "%s", acfreq);
256
dstate_setinfo("output.voltage", "%s", outvolt);
257
dstate_setinfo("battery.charge", "%02.1f", bvoltp);
258
dstate_setinfo("battery.voltage", "%s", battvolt);
259
dstate_setinfo("ups.load", "%s", loadpct);
263
if (pstat[0] == '0') {
264
status_set("OL"); /* on line */
266
/* only allow these when OL since they're bogus when OB */
268
if (pstat[2] == (inverted_bypass_bit ? '0' : '1')) {
269
/* boost or trim in effect */
270
if (atof(utility) < atof(outvolt))
273
if (atof(utility) > atof(outvolt))
278
status_set("OB"); /* on battery */
281
if (pstat[1] == '1') {
282
status_set("LB"); /* low battery */
289
void upsdrv_help(void)
293
void upsdrv_makevartable(void)
297
void upsdrv_banner(void)
299
printf("Network UPS Tools - mustek UPS driver %s (%s)\n",
300
DRV_VERSION, UPS_VERSION);
303
void upsdrv_initups(void)
305
upsfd = ser_open(device_path);
306
ser_set_speed(upsfd, device_path, B2400);
312
void upsdrv_cleanup(void)
314
ser_close(upsfd, device_path);