On Thu, 29 Dec 2011, Charles Lepple wrote:
On Dec 28, 2011, at 9:16 AM, Ariel wrote:
On Wed, 28 Dec 2011, Charles Lepple wrote:
Is it possible that UPS.PowerSummary.Voltage is really an output
voltage divided by 10? (This has happened on other devices.)
Well, I have two 12 volt batteries, so 24 volts makes sense, 240 doesn't.
I meant AC output voltage, not DC.
No, I'm in the US, so 120 volts.
I agree - I think the scaling should be configured in ups.conf, and be
general for any field. To make it very easy support +-*/ without
precedence - operations are done strictly left to right. Perhaps 3
fields: operation, min, max (min/max are applied after scaling, not
before).
We will need to think about this a bit more to bound the scaling/offset
problem.
In case you wish to do it, I wrote some functions to parse and execute a
scale/offset/min/max calculation.
The code pre-parses a text specification, then there is a function to run
the calculation on a specific value.
I did not try to integrate it into the code since I'm not very familiar
with it, but I would expect that instead of things like:
{ "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%s", 0,
cps_battvolt },
You would have:
{ "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%s", 0, "* 0.667"
},
i.e. just a textual specification of the scaling/offset, and the driver
could read in user specified options that would override the default
(either on the command line or in ups.conf).
Or the divide_by_10_conversion_fun() function would be replaced by a
default scaling (that can be overridden by the user - which is the main
point of doing it in text), and then just a single generic output
function.
I attached the files with the code.
An example of usage:
#include <stdio.h>
#include "str_math.h"
int main(void) {
struct str_math spec;
/* minus 6 times 3 divide by 8, min value 1, max 20 */
printf(init_str_math(&spec, " - 6 * 3 / 8, 1, 20") ? "valid spec\n" : "invalid
spec\n");
printf("%f\n", str_math(&spec, 500));
free_str_math(&spec);
return 0;
}
-Ariel/* str_math - Parse and calculate an offset/scale text specification with min and max
Copyright (C) 2011 Ariel Shkedi <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
struct str_math {
double min;
double max;
int count;
struct str_math_op *ops;
};
void free_str_math(struct str_math *str_math);
int init_str_math(struct str_math *str_math, char *str);
double str_math(struct str_math *str_math, double val);
/* str_math - Parse and calculate an offset/scale text specification with min and max
Copyright (C) 2011 Ariel Shkedi <[email protected]>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <math.h>
#include <float.h>
#include "str_math.h"
struct str_math_op {
enum op {ADD, MUL} op;
double val;
};
/* frees data in an str_math struct that was created by init_str_math */
void free_str_math(struct str_math *str_math) {
free(str_math->ops);
str_math->ops = NULL;
str_math->count = 0;
}
/* Pass it a pointer to an str_math struct, and a string with the scale/offset specification
Returns 1 for a valid string, 0 for an invalid string (error)
This function initializes the structure to prepare for calculation.
To actually do a calculation call str_math()
format is:
scale/offset, min, max
all fields are optional and can be left blank (and commas can be omitted if at the end)
eg: just a max of 10: ,,10
eg: just a scale of 2 plus an offset of 3: *2 +3
the scale/offset calculates in order, and does not have any precedence rules
pass it any number of <operator value> pairs (operator is + - * /)
*/
int init_str_math(struct str_math *str_math, char *str) {
char op;
char *ptr;
str_math->count = 0;
str_math->ops = NULL;
str--;
while(isspace(*++str));
while(*str != '\0' && *str != ',') {
str_math->ops = realloc(str_math->ops, sizeof(struct str_math_op) * ++str_math->count);
op = *str++;
errno = 0;
str_math->ops[str_math->count-1].val = strtod(str, &ptr);
if(errno) {
/* underflow or overflow */
free_str_math(str_math);
return 0;
}
if (str == ptr) {
/* invalid digits */
free_str_math(str_math);
return 0;
}
str = ptr;
switch(op) {
case '-':
str_math->ops[str_math->count-1].val *= -1;
case '+':
str_math->ops[str_math->count-1].op = ADD;
break;
case '/':
str_math->ops[str_math->count-1].val = 1/str_math->ops[str_math->count-1].val;
case '*':
str_math->ops[str_math->count-1].op = MUL;
break;
default:
/* not a valid operator */
free_str_math(str_math);
return 0;
}
str--;
while(isspace(*++str));
}
if(*str != '\0') str++;
str_math->min = strtod(str, &ptr);
if(errno || str == ptr) {
/* underflow, overflow, invalid or blank */
str_math->min = -DBL_MAX;
}
str = ptr-1;
while(isspace(*++str));
if(*str != '\0' && *str != ',') { /* invalid specification */
free_str_math(str_math);
return 0;
}
if(*str != '\0') str++;
str_math->max = strtod(str, &ptr);
if(errno || str == ptr) {
/* underflow, overflow, invalid or blank */
str_math->max = DBL_MAX;
}
str = ptr-1;
while(isspace(*++str));
if(*str != '\0' && *str != ',') { /* invalid specification */
free_str_math(str_math);
return 0;
}
return 1;
}
/* runs the calculation in str_math */
double str_math(struct str_math *str_math, double val) {
int i;
for(i = 0; i < str_math->count; i++) {
switch(str_math->ops[i].op) {
case ADD:
val += str_math->ops[i].val;
break;
case MUL:
val *= str_math->ops[i].val;
break;
}
}
if(val > str_math->max) val = str_math->max;
if(val < str_math->min) val = str_math->min;
return val;
}
_______________________________________________
Nut-upsdev mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/nut-upsdev