7
7
* This model is based on PowerCom (www.powercom.com) models.
8
8
* -Socomec Sicon Egys 420
10
* Read docs/powercom.txt for other models and manufactures
12
* $Id: - will be filled in on next CVS add/update $
15
* 20011022/Revision 0.1 - Peter Bieringer <pb@bieringer.de>
16
* - porting done, looks like working
17
* 20011208/Revision 0.2 - Peter Bieringer <pb@bieringer.de>
18
* - add some debug code
19
* - add new option "subtype"
20
* - add support for a 16 byte sending UPS (KP625AP)
21
* - shutdown function checked, but 'Trust' wakes up after a few seconds...
22
* 20020629/Revision 0.3 - Simon Rozman <simon@rozman.net>
23
* - add different serial port init. for each subtype
24
* - add support for Socomec Sycon Egys 420
25
* - add support for different calculation parameters for each subtype
26
* - add support for output voltage and output frequency monitoring
27
* 20020701/Revision 0.4 - Simon Rozman <simon@rozman.net>,
28
* proposed by Shaul Karl
29
* - subtypes specific info moved to struct subtype
30
* 20030506/Revision 0.5 - Shaul Karl <shaulka@bezeqint.net>
31
* - converted to dstate
32
* - modify the validation code
33
* - replace subtype with type
10
* $Id: powercom.c,v 1.1.1.1 2005/01/27 14:33:20 aquette Exp $
36
13
* (C) 2002 Simon Rozman <simon@rozman.net>
37
* Added support for Egys
39
* (C) 2001 Peter Bieringer <pb@bieringer.de>
40
* Porting old style "powercom" to new style "newpowercom"
42
* (C) 2000 Shaul Karl <shaulk@israsrv.net.il>
43
* Creating old style "powercom"
45
* ups-trust425+625.c - model specific routines for Trust UPS 425/625
46
* Copyright (C) 1999 Peter Bieringer <pb@bieringer.de>
14
* (C) 1999 Peter Bieringer <pb@bieringer.de>
48
16
* This program is free software; you can redistribute it and/or modify
49
17
* it under the terms of the GNU General Public License as published by
65
34
#include "powercom.h"
67
#define POWERCOM_DRIVER_VERSION "$Revision: 0.5 $"
36
#define POWERCOM_DRIVER_VERSION "$ Revision: 0.5 $"
68
37
#define NUM_OF_SUBTYPES (sizeof (types) / sizeof (*types))
70
39
/* variables used by module */
71
static unsigned char powercom_raw_data[MAX_NUM_OF_BYTES_FROM_UPS]; /* raw data reveived from UPS */
72
static unsigned int powercom_linevoltage = 230U; /* line voltage, can be defined via command line option */
73
static char *powercom_manufacturer = "PowerCom";
74
static char *powercom_modelname = "Unknown";
75
static char *powercom_serialnumber = "Unknown";
76
static char *powercom_type_name = "Trust";
77
static unsigned int type_index = 0;
40
static unsigned char raw_data[MAX_NUM_OF_BYTES_FROM_UPS]; /* raw data reveived from UPS */
41
static unsigned int linevoltage = 230U; /* line voltage, can be defined via command line option */
42
static const char *manufacturer = "PowerCom";
43
static const char *modelname = "Unknown";
44
static const char *serialnumber = "Unknown";
45
static unsigned int type = 0;
79
47
/* forward declaration of functions used to setup flow control */
80
static void dtr0rts1 ();
81
static void no_flow_control ();
48
static void dtr0rts1 (void);
49
static void dtr1 (void);
50
static void no_flow_control (void);
83
52
/* struct defining types */
84
53
static struct type types[] = {
89
{ { 5, 0 }, { 7, 0 }, { 8, 0 } },
57
{ "dtr0rts1", dtr0rts1 },
58
{ { 5U, 0U }, { 7U, 0U }, { 8U, 0U } },
90
60
{ 0.00020997, 0.00020928 },
91
61
{ 6.1343, -0.3808, 4.3110, 0.1811 },
92
62
{ 5.0000, 0.3268, -825.00, 4.5639, -835.82 },
119
{ { 5, 0x80 }, { 7, 0 }, { 8, 0 } },
90
{ "no_flow_control", no_flow_control },
91
{ { 5U, 0x80U }, { 7U, 0U }, { 8U, 0U } },
120
93
{ 0.00020997, 0.00020928 },
121
94
{ 6.1343, -0.3808, 1.3333, 0.6667 },
122
95
{ 5.0000, 0.3268, -825.00, 2.2105, -355.37 },
123
96
{ 1.9216, -0.0977, 0.9545, 0.0000 },
102
{ { 5U, 0x80U }, { 7U, 0U }, { 8U, 0U } },
103
{ { 0U, 10U }, 'y' },
104
{ 0.00020997, 0.00020928 },
105
{ 6.1343, -0.3808, 4.3110, 0.1811 },
106
{ 5.0000, 0.3268, -825.00, 4.5639, -835.82 },
107
{ 1.9216, -0.0977, 0.9545, 0.0000 },
112
{ "no_flow_control", no_flow_control },
113
{ { 7U, 0U }, { 8U, 0U }, { 8U, 0U } },
114
{ { 0U, 10U }, 'n' },
116
{ 6.1343, -0.3808, 1.075, 0.1811 },
117
{ 5.0000, 0.3268, -825.00, 0.46511, 0 },
118
{ 1.9216, -0.0977, 0.82857, 0.0000 },
128
/* used external variables */
129
extern int sddelay; /* shutdown delay, set by "-d $delay" in main.c */
130
extern int do_forceshutdown; /* shutdown delay, set by "-k" in main.c */
134
124
* local used functions
137
static void powercom_shutdown(void)
127
static void shutdown(void)
139
129
printf ("Initiating UPS shutdown!\n");
141
upssendchar (SHUTDOWN);
142
upssendchar (SEC_FOR_POWERKILL);
131
ser_send_char (upsfd, SHUTDOWN);
132
if (types[type].shutdown_arguments.minutesShouldBeUsed != 'n')
133
ser_send_char (upsfd, types[type].shutdown_arguments.delay[0]);
134
ser_send_char (upsfd, types[type].shutdown_arguments.delay[1]);
148
139
/* registered instant commands */
149
140
static int instcmd (const char *cmdname, const char *extra)
151
142
if (!strcasecmp(cmdname, "test.battery.start")) {
152
upssendchar (BATTERY_TEST);
143
ser_send_char (upsfd, BATTERY_TEST);
153
144
return STAT_INSTCMD_HANDLED;
290
259
/* input.frequency */
291
260
upsdebugx(3, "input.frequency (raw data): [raw: %u]",
292
powercom_raw_data[INPUT_FREQUENCY]);
261
raw_data[INPUT_FREQUENCY]);
293
262
dstate_setinfo("input.frequency", "%02.2f",
294
powercom_raw_data[INPUT_FREQUENCY] ?
295
1.0 / (types[type_index].freq[0] *
296
powercom_raw_data[INPUT_FREQUENCY] +
297
types[type_index].freq[1]) : 0);
263
raw_data[INPUT_FREQUENCY] ?
264
1.0 / (types[type].freq[0] *
265
raw_data[INPUT_FREQUENCY] +
266
types[type].freq[1]) : 0);
298
267
upsdebugx(2, "input.frequency: %s", dstate_getinfo("input.frequency"));
300
269
/* output.frequency */
301
270
upsdebugx(3, "output.frequency (raw data): [raw: %u]",
302
powercom_raw_data[OUTPUT_FREQUENCY]);
271
raw_data[OUTPUT_FREQUENCY]);
303
272
dstate_setinfo("output.frequency", "%02.2f",
304
powercom_raw_data[OUTPUT_FREQUENCY] ?
305
1.0 / (types[type_index].freq[0] *
306
powercom_raw_data[OUTPUT_FREQUENCY] +
307
types[type_index].freq[1]) : 0);
273
raw_data[OUTPUT_FREQUENCY] ?
274
1.0 / (types[type].freq[0] *
275
raw_data[OUTPUT_FREQUENCY] +
276
types[type].freq[1]) : 0);
308
277
upsdebugx(2, "output.frequency: %s", dstate_getinfo("output.frequency"));
311
280
upsdebugx(3, "ups.load (raw data): [raw: %u]",
312
powercom_raw_data[UPS_LOAD]);
313
282
dstate_setinfo("ups.load", "%03.1f",
314
tmp = powercom_raw_data[STATUS_A] & MAINS_FAILURE ?
315
types[type_index].loadpct[0] *
316
powercom_raw_data[UPS_LOAD] +
317
types[type_index].loadpct[1] :
318
types[type_index].loadpct[2] *
319
powercom_raw_data[UPS_LOAD] +
320
types[type_index].loadpct[3]);
283
tmp = raw_data[STATUS_A] & MAINS_FAILURE ?
284
types[type].loadpct[0] * raw_data[UPS_LOAD] +
285
types[type].loadpct[1] :
286
types[type].loadpct[2] * raw_data[UPS_LOAD] +
287
types[type].loadpct[3]);
321
288
upsdebugx(2, "ups.load: %s", dstate_getinfo("ups.load"));
323
290
/* battery.charge */
324
291
upsdebugx(3, "battery.charge (raw data): [raw: %u]",
325
powercom_raw_data[BATTERY_CHARGE]);
292
raw_data[BATTERY_CHARGE]);
326
293
dstate_setinfo("battery.charge", "%03.1f",
327
powercom_raw_data[STATUS_A] & MAINS_FAILURE ?
328
types[type_index].battpct[0] *
329
powercom_raw_data[BATTERY_CHARGE] +
330
types[type_index].battpct[1] * tmp +
331
types[type_index].battpct[2] :
332
types[type_index].battpct[3] *
333
powercom_raw_data[BATTERY_CHARGE] +
334
types[type_index].battpct[4]);
294
raw_data[STATUS_A] & MAINS_FAILURE ?
295
types[type].battpct[0] * raw_data[BATTERY_CHARGE] +
296
types[type].battpct[1] * tmp + types[type].battpct[2] :
297
types[type].battpct[3] * raw_data[BATTERY_CHARGE] +
298
types[type].battpct[4]);
335
299
upsdebugx(2, "battery.charge: %s", dstate_getinfo("battery_charge"));
337
301
/* input.voltage */
338
302
upsdebugx(3, "input.voltage (raw data): [raw: %u]",
339
powercom_raw_data[INPUT_VOLTAGE]);
303
raw_data[INPUT_VOLTAGE]);
340
304
dstate_setinfo("input.voltage", "%03.1f",
341
tmp = powercom_linevoltage >= 220 ?
342
types[type_index].voltage[0] *
343
powercom_raw_data[INPUT_VOLTAGE] +
344
types[type_index].voltage[1] :
345
types[type_index].voltage[2] *
346
powercom_raw_data[INPUT_VOLTAGE] +
347
types[type_index].voltage[3]);
305
tmp = linevoltage >= 220 ?
306
types[type].voltage[0] * raw_data[INPUT_VOLTAGE] +
307
types[type].voltage[1] :
308
types[type].voltage[2] * raw_data[INPUT_VOLTAGE] +
309
types[type].voltage[3]);
348
310
upsdebugx(2, "input.voltage: %s", dstate_getinfo("input.voltage"));
350
312
/* output.voltage */
351
313
upsdebugx(3, "input.voltage (raw data): [raw: %u]",
352
powercom_raw_data[OUTPUT_VOLTAGE]);
314
raw_data[OUTPUT_VOLTAGE]);
353
315
dstate_setinfo("output.voltage", "%03.1f",
354
powercom_linevoltage >= 220 ?
355
types[type_index].voltage[0] *
356
powercom_raw_data[OUTPUT_VOLTAGE] +
357
types[type_index].voltage[1] :
358
types[type_index].voltage[2] *
359
powercom_raw_data[OUTPUT_VOLTAGE] +
360
types[type_index].voltage[3]);
317
types[type].voltage[0] * raw_data[OUTPUT_VOLTAGE] +
318
types[type].voltage[1] :
319
types[type].voltage[2] * raw_data[OUTPUT_VOLTAGE] +
320
types[type].voltage[3]);
361
321
upsdebugx(2, "output.voltage: %s", dstate_getinfo("output.voltage"));
366
if (!(powercom_raw_data[STATUS_A] & MAINS_FAILURE)) {
367
!(powercom_raw_data[STATUS_A] & OFF) ?
326
if (!(raw_data[STATUS_A] & MAINS_FAILURE)) {
327
!(raw_data[STATUS_A] & OFF) ?
368
328
status_set("OL") : status_set("OFF");
370
330
status_set("OB");
373
if (powercom_raw_data[STATUS_A] & LOW_BAT) status_set("LB");
333
if (raw_data[STATUS_A] & LOW_BAT) status_set("LB");
375
if (powercom_raw_data[STATUS_A] & AVR_ON) {
376
tmp < powercom_linevoltage ?
335
if (raw_data[STATUS_A] & AVR_ON) {
377
337
status_set("BOOST") : status_set("TRIM");
380
if (powercom_raw_data[STATUS_A] & OVERLOAD) status_set("OVER");
382
if (powercom_raw_data[STATUS_B] & BAD_BAT) status_set("RB");
384
if (powercom_raw_data[STATUS_B] & TEST) status_set("TEST");
340
if (raw_data[STATUS_A] & OVERLOAD) status_set("OVER");
342
if (raw_data[STATUS_B] & BAD_BAT) status_set("RB");
344
if (raw_data[STATUS_B] & TEST) status_set("TEST");
393
352
/* shutdown UPS */
394
353
void upsdrv_shutdown(void)
396
if (do_forceshutdown == 1) {
397
/* power down the attached load immediately */
398
printf("Forced UPS shutdown triggered, do it...\n");
401
/* power down the attached load after the given delay */
402
printf("UPS shutdown with '%d' seconds delay triggered, wait now...\n", sddelay);
355
/* power down the attached load immediately */
356
printf("Forced UPS shutdown triggered, do it...\n");
409
360
/* initialize UPS */
410
361
void upsdrv_initups(void)
414
366
/* check manufacturer name from arguments */
415
if (getval("manufacturer") != NULL) {
416
powercom_manufacturer = getval("manufacturer");
367
if (getval("manufacturer") != NULL)
368
manufacturer = getval("manufacturer");
419
370
/* check model name from arguments */
420
if (getval("modelname") != NULL) {
421
powercom_modelname = getval("modelname");
371
if (getval("modelname") != NULL)
372
modelname = getval("modelname");
424
374
/* check serial number from arguments */
425
if (getval("serialnumber") != NULL) {
426
powercom_serialnumber = getval("serialnumber");
375
if (getval("serialnumber") != NULL)
376
serialnumber = getval("serialnumber");
429
378
/* get and check type */
430
379
if (getval("type") != NULL) {
431
powercom_type_name = getval("type");
432
for (i = 0; i < NUM_OF_SUBTYPES; i++) {
433
if (strcmp(types[i].name, powercom_type_name) == 0)
436
if (i < NUM_OF_SUBTYPES) {
437
/* we found a type */
440
/* no such type exists */
441
printf("Given UPS type '%s' isn't valid!\n", powercom_type_name);
381
i < NUM_OF_SUBTYPES && strcmp(types[i].name, getval("type"));
383
if (i >= NUM_OF_SUBTYPES) {
384
printf("Given UPS type '%s' isn't valid!\n", getval("type"));
446
390
/* check line voltage from arguments */
450
394
printf("Given line voltage '%d' is out of range (110-120 or 220-240 V)\n", tmp);
453
powercom_linevoltage = (unsigned int) tmp;
397
linevoltage = (unsigned int) tmp;
400
if (getval("numOfBytesFromUPS") != NULL) {
401
tmp = atoi(getval("numOfBytesFromUPS"));
402
if (! (tmp > 0 && tmp <= MAX_NUM_OF_BYTES_FROM_UPS) ) {
403
printf("Given numOfBytesFromUPS '%d' is out of range (1 to %d)\n",
404
tmp, MAX_NUM_OF_BYTES_FROM_UPS);
407
types[type].num_of_bytes_from_ups = (unsigned char) tmp;
410
if (getval("methodOfFlowControl") != NULL) {
412
i < NUM_OF_SUBTYPES &&
413
strcmp(types[i].flowControl.name,
414
getval("methodOfFlowControl"));
416
if (i >= NUM_OF_SUBTYPES) {
417
printf("Given methodOfFlowControl '%s' isn't valid!\n",
418
getval("methodOfFlowControl"));
421
types[type].flowControl = types[i].flowControl;
424
if (getval("validationSequence") &&
425
sscanf(getval("validationSequence"),
426
"{{%u,%x},{%u,%x},{%u,%x}}",
427
&types[type].validation[0].index_of_byte,
428
&types[type].validation[0].required_value,
429
&types[type].validation[1].index_of_byte,
430
&types[type].validation[1].required_value,
431
&types[type].validation[2].index_of_byte,
432
&types[type].validation[2].required_value
435
printf("Given validationSequence '%s' isn't valid!\n",
436
getval("validationSequence"));
440
if (getval("shutdownArguments") &&
441
sscanf(getval("shutdownArguments"), "{{%u,%u},%c}",
442
&types[type].shutdown_arguments.delay[0],
443
&types[type].shutdown_arguments.delay[1],
444
&types[type].shutdown_arguments.minutesShouldBeUsed
447
printf("Given shutdownArguments '%s' isn't valid!\n",
448
getval("shutdownArguments"));
452
if (getval("frequency") &&
453
sscanf(getval("frequency"), "{%f,%f}",
454
&types[type].freq[0], &types[type].freq[1]
457
printf("Given frequency '%s' isn't valid!\n",
458
getval("frequency"));
462
if (getval("loadPercentage") &&
463
sscanf(getval("loadPercentage"), "{%f,%f,%f,%f}",
464
&types[type].loadpct[0], &types[type].loadpct[1],
465
&types[type].loadpct[2], &types[type].loadpct[3]
468
printf("Given loadPercentage '%s' isn't valid!\n",
469
getval("loadPercentage"));
473
if (getval("batteryPercentage") &&
474
sscanf(getval("batteryPercentage"), "{%f,%f,%f,%f,%f}",
475
&types[type].battpct[0], &types[type].battpct[1],
476
&types[type].battpct[2], &types[type].battpct[3],
477
&types[type].battpct[4]
480
printf("Given batteryPercentage '%s' isn't valid!\n",
481
getval("batteryPercentage"));
485
if (getval("voltage") &&
486
sscanf(getval("voltage"), "{%f,%f,%f,%f}",
487
&types[type].voltage[0], &types[type].voltage[1],
488
&types[type].voltage[2], &types[type].voltage[3]
491
printf("Given voltage '%s' isn't valid!\n", getval("voltage"));
456
495
upsdebugx(1, "Values of arguments:");
457
upsdebugx(1, " manufacturer : '%s'", powercom_manufacturer);
458
upsdebugx(1, " model name : '%s'", powercom_modelname);
459
upsdebugx(1, " serial number: '%s'", powercom_serialnumber);
460
upsdebugx(1, " line voltage : '%u'", powercom_linevoltage);
461
upsdebugx(1, " type : '%s'", powercom_type_name);
496
upsdebugx(1, " manufacturer : '%s'", manufacturer);
497
upsdebugx(1, " model name : '%s'", modelname);
498
upsdebugx(1, " serial number : '%s'", serialnumber);
499
upsdebugx(1, " line voltage : '%u'", linevoltage);
500
upsdebugx(1, " type : '%s'", types[type].name);
501
upsdebugx(1, " number of bytes from UPS: '%u'",
502
types[type].num_of_bytes_from_ups);
503
upsdebugx(1, " method of flow control : '%s'",
504
types[type].flowControl.name);
505
upsdebugx(1, " validation sequence: '{{%u,%#x},{%u,%#x},{%u,%#x}}'",
506
types[type].validation[0].index_of_byte,
507
types[type].validation[0].required_value,
508
types[type].validation[1].index_of_byte,
509
types[type].validation[1].required_value,
510
types[type].validation[2].index_of_byte,
511
types[type].validation[2].required_value);
512
upsdebugx(1, " shutdown arguments: '{{%u,%u},%c}'",
513
types[type].shutdown_arguments.delay[0],
514
types[type].shutdown_arguments.delay[1],
515
types[type].shutdown_arguments.minutesShouldBeUsed);
516
upsdebugx(1, " frequency calculation coefficients: '{%f,%f}'",
517
types[type].freq[0], types[type].freq[1]);
518
upsdebugx(1, " load percentage calculation coefficients: "
520
types[type].loadpct[0], types[type].loadpct[1],
521
types[type].loadpct[2], types[type].loadpct[3]);
522
upsdebugx(1, " battery percentage calculation coefficients: "
523
"'{%f,%f,%f,%f,%f}'",
524
types[type].battpct[0], types[type].battpct[1],
525
types[type].battpct[2], types[type].battpct[3],
526
types[type].battpct[4]);
527
upsdebugx(1, " voltage calculation coefficients: '{%f,%f}'",
528
types[type].voltage[2], types[type].voltage[3]);
463
530
/* open serial port */
464
open_serial (device_path, B1200);
531
upsfd = ser_open(device_path);
532
ser_set_speed(upsfd, device_path, B1200);
466
534
/* setup flow control */
467
types[type_index].setup_flow_control();
535
types[type].flowControl.setup_flow_control();
471
538
/* display help */
472
539
void upsdrv_help(void)
479
545
/* display banner */
480
546
void upsdrv_banner(void)
482
printf ("Network UPS Tools (version %s) - PowerCom and similars protocol driver\n",
484
printf ("\tDriver %s\n",
485
POWERCOM_DRIVER_VERSION);
548
printf("Network UPS Tools - PowerCom and similars protocol UPS driver %s (%s)\n\n",
549
POWERCOM_DRIVER_VERSION, UPS_VERSION);
489
552
/* initialize information */
490
553
void upsdrv_initinfo(void)
492
555
/* write constant data for this model */
493
dstate_setinfo ("ups.mfr", "%s", powercom_manufacturer);
494
dstate_setinfo ("ups.model", "%s", powercom_modelname);
495
dstate_setinfo ("ups.serial", "%s", powercom_serialnumber);
496
dstate_setinfo ("ups.model.type", "%s", powercom_type_name);
497
dstate_setinfo ("input.voltage.nominal", "%u", powercom_linevoltage);
556
dstate_setinfo("driver.version.internal", "%s", POWERCOM_DRIVER_VERSION);
557
dstate_setinfo ("ups.mfr", "%s", manufacturer);
558
dstate_setinfo ("ups.model", "%s", modelname);
559
dstate_setinfo ("ups.serial", "%s", serialnumber);
560
dstate_setinfo ("ups.model.type", "%s", types[type].name);
561
dstate_setinfo ("input.voltage.nominal", "%u", linevoltage);
499
563
/* now add the instant commands */
500
564
dstate_addcmd ("test.battery.start");
501
upsh.new_instcmd = instcmd;
565
upsh.instcmd = instcmd;
505
568
/* define possible arguments */
506
569
void upsdrv_makevartable(void)
509
572
addvar(VAR_VALUE, "linevoltage", "Specify line voltage (110-120 or 220-240 V), because it cannot detect automagically (default: 230 V)");
510
573
addvar(VAR_VALUE, "modelname", "Specify model name, because it cannot detect automagically (default: Unknown)");
511
574
addvar(VAR_VALUE, "serialnumber", "Specify serial number, because it cannot detect automagically (default: Unknown)");
512
addvar(VAR_VALUE, "type", "Type of UPS like 'Trust', 'KP625AP', 'KIN2200AP' or 'Egys' (default: 'Trust')");
575
addvar(VAR_VALUE, "type", "Type of UPS like 'Trust', 'KP625AP', 'KIN2200AP', 'Egys', 'KIN525AP' or 'KIN1500AP' (default: 'Trust')");
576
addvar(VAR_VALUE, "numOfBytesFromUPS", "The number of bytes in a UPS frame");
577
addvar(VAR_VALUE, "voltage", "A quad to convert the raw data to human readable voltage");
578
addvar(VAR_VALUE, "methodOfFlowControl", "The flow control method engaged by the UPS");
579
addvar(VAR_VALUE, "frequency", "A pair to convert the raw data to human readable freqency");
580
addvar(VAR_VALUE, "batteryPercentage", "A 5 tuple to convert the raw data to human readable battery percentage");
581
addvar(VAR_VALUE, "loadPercentage", "A quad to convert the raw data to human readable load percentage");
582
addvar(VAR_VALUE, "validationSequence", "3 pairs to be used for validating the UPS");
583
addvar(VAR_VALUE, "shutdownArguments", "The number of delay arguments and their values for the shutdown operation");
517
586
void upsdrv_cleanup(void)
588
ser_close(upsfd, device_path);