2014-04-22 18:39:47 +00:00
/* nutdrv_qx_blazer-common.c - Common functions/settings for nutdrv_qx_{mecer,megatec,megatec-old,mustek,q1,voltronic-qs,zinto}.{c,h}
2013-11-24 15:00:12 +00:00
*
* Copyright ( C )
* 2013 Daniele Pezzini < hyouko @ gmail . com >
*
* 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 "main.h"
# include "nutdrv_qx.h"
# include "nutdrv_qx_blazer-common.h"
/* == Ranges == */
/* Range for ups.delay.start */
info_rw_t blazer_r_ondelay [ ] = {
{ " 0 " , 0 } ,
{ " 599940 " , 0 } ,
{ " " , 0 }
} ;
/* Range for ups.delay.shutdown */
info_rw_t blazer_r_offdelay [ ] = {
{ " 12 " , 0 } ,
{ " 600 " , 0 } ,
{ " " , 0 }
} ;
/* == Support functions == */
/* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0. */
2015-04-30 13:53:36 +00:00
int blazer_claim ( void )
{
2013-11-24 15:00:12 +00:00
/* To tell whether the UPS is supported or not, we'll check both status (Q1/QS/D) and vendor (I/FW?) - provided that we were not told not to do it with the ups.conf flag 'novendor'. */
item_t * item = find_nut_info ( " input.voltage " , 0 , 0 ) ;
/* Don't know what happened */
if ( ! item )
return 0 ;
/* No reply/Unable to get value */
if ( qx_process ( item , NULL ) )
return 0 ;
/* Unable to process value */
if ( ups_infoval_set ( item ) ! = 1 )
return 0 ;
if ( testvar ( " novendor " ) )
return 1 ;
/* Vendor */
item = find_nut_info ( " ups.firmware " , 0 , 0 ) ;
/* Don't know what happened */
if ( ! item ) {
dstate_delinfo ( " input.voltage " ) ;
return 0 ;
}
/* No reply/Unable to get value */
if ( qx_process ( item , NULL ) ) {
dstate_delinfo ( " input.voltage " ) ;
return 0 ;
}
/* Unable to process value */
if ( ups_infoval_set ( item ) ! = 1 ) {
dstate_delinfo ( " input.voltage " ) ;
return 0 ;
}
return 1 ;
}
2014-04-22 18:39:47 +00:00
/* This function allows the subdriver to "claim" a device: return 1 if the device is supported by this subdriver, else 0.
* NOTE : this ' light ' version only checks for status ( Q1 / QS / D / . . ) */
2015-04-30 13:53:36 +00:00
int blazer_claim_light ( void )
{
2014-04-22 18:39:47 +00:00
/* To tell whether the UPS is supported or not, we'll check just status (Q1/QS/D/..). */
item_t * item = find_nut_info ( " input.voltage " , 0 , 0 ) ;
/* Don't know what happened */
if ( ! item )
return 0 ;
/* No reply/Unable to get value */
if ( qx_process ( item , NULL ) )
return 0 ;
/* Unable to process value */
if ( ups_infoval_set ( item ) ! = 1 )
return 0 ;
return 1 ;
}
2013-11-24 15:00:12 +00:00
/* Subdriver-specific flags/vars */
void blazer_makevartable ( void )
{
addvar ( VAR_FLAG , " norating " , " Skip reading rating information from UPS " ) ;
addvar ( VAR_FLAG , " novendor " , " Skip reading vendor information from UPS " ) ;
2015-04-30 13:53:36 +00:00
blazer_makevartable_light ( ) ;
}
/* Subdriver-specific flags/vars
* NOTE : this ' light ' version only handles vars / flags related to UPS status query ( Q1 / QS / D / . . . ) */
void blazer_makevartable_light ( void )
{
addvar ( VAR_FLAG , " ignoresab " , " Ignore 'Shutdown Active' bit in UPS status " ) ;
2013-11-24 15:00:12 +00:00
}
/* Subdriver-specific initups */
void blazer_initups ( item_t * qx2nut )
{
2015-04-30 13:53:36 +00:00
int nr , nv , isb ;
2013-11-24 15:00:12 +00:00
item_t * item ;
nr = testvar ( " norating " ) ;
nv = testvar ( " novendor " ) ;
2015-04-30 13:53:36 +00:00
isb = testvar ( " ignoresab " ) ;
2013-11-24 15:00:12 +00:00
2015-04-30 13:53:36 +00:00
if ( ! nr & & ! nv & & ! isb )
2013-11-24 15:00:12 +00:00
return ;
for ( item = qx2nut ; item - > info_type ! = NULL ; item + + ) {
if ( ! item - > command )
continue ;
/* norating */
if ( nr & & ! strcasecmp ( item - > command , " F \r " ) ) {
upsdebugx ( 2 , " %s: skipping %s " , __func__ , item - > info_type ) ;
item - > qxflags | = QX_FLAG_SKIP ;
}
/* novendor */
if ( nv & & ( ! strcasecmp ( item - > command , " I \r " ) | | ! strcasecmp ( item - > command , " FW? \r " ) ) ) {
upsdebugx ( 2 , " %s: skipping %s " , __func__ , item - > info_type ) ;
item - > qxflags | = QX_FLAG_SKIP ;
}
2015-04-30 13:53:36 +00:00
/* ignoresab */
if ( isb & & ! strcasecmp ( item - > info_type , " ups.status " ) & & item - > from = = 44 & & item - > to = = 44 ) {
upsdebugx ( 2 , " %s: skipping %s ('Shutdown Active' bit) " , __func__ , item - > info_type ) ;
item - > qxflags | = QX_FLAG_SKIP ;
}
}
}
/* Subdriver-specific initups
* NOTE : this ' light ' version only checks for status ( Q1 / QS / D / . . ) related items */
void blazer_initups_light ( item_t * qx2nut )
{
item_t * item ;
if ( ! testvar ( " ignoresab " ) )
return ;
for ( item = qx2nut ; item - > info_type ! = NULL ; item + + ) {
if ( strcasecmp ( item - > info_type , " ups.status " ) | | item - > from ! = 44 | | item - > to ! = 44 )
continue ;
upsdebugx ( 2 , " %s: skipping %s ('Shutdown Active' bit) " , __func__ , item - > info_type ) ;
item - > qxflags | = QX_FLAG_SKIP ;
break ;
2013-11-24 15:00:12 +00:00
}
}
/* == Preprocess functions == */
/* Preprocess setvars */
2016-07-18 00:11:41 +00:00
int blazer_process_setvar ( item_t * item , char * value , const size_t valuelen )
2013-11-24 15:00:12 +00:00
{
if ( ! strlen ( value ) ) {
upsdebugx ( 2 , " %s: value not given for %s " , __func__ , item - > info_type ) ;
return - 1 ;
}
if ( ! strcasecmp ( item - > info_type , " ups.delay.start " ) ) {
2022-06-29 10:37:36 +00:00
long ondelay = strtol ( value , NULL , 10 ) ;
if ( ondelay < 0 ) {
upslogx ( LOG_ERR , " %s: ondelay '%ld' should not be negative " ,
item - > info_type , ondelay ) ;
return - 1 ;
}
2013-11-24 15:00:12 +00:00
/* Truncate to minute */
ondelay - = ( ondelay % 60 ) ;
2022-06-29 10:37:36 +00:00
snprintf ( value , valuelen , " %ld " , ondelay ) ;
2013-11-24 15:00:12 +00:00
} else if ( ! strcasecmp ( item - > info_type , " ups.delay.shutdown " ) ) {
2022-06-29 10:37:36 +00:00
long offdelay = strtol ( value , NULL , 10 ) ;
if ( offdelay < 0 ) {
upslogx ( LOG_ERR , " %s: offdelay '%ld' should not be negative " ,
item - > info_type , offdelay ) ;
return - 1 ;
}
2013-11-24 15:00:12 +00:00
/* Truncate to nearest settable value */
if ( offdelay < 60 ) {
offdelay - = ( offdelay % 6 ) ;
} else {
offdelay - = ( offdelay % 60 ) ;
}
2022-06-29 10:37:36 +00:00
snprintf ( value , valuelen , " %ld " , offdelay ) ;
2013-11-24 15:00:12 +00:00
} else {
/* Don't know what happened */
return - 1 ;
}
return 0 ;
}
/* Preprocess instant commands */
2016-07-18 00:11:41 +00:00
int blazer_process_command ( item_t * item , char * value , const size_t valuelen )
2013-11-24 15:00:12 +00:00
{
2022-06-29 10:37:36 +00:00
# ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
# pragma GCC diagnostic push
# endif
# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
# endif
# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY
# pragma GCC diagnostic ignored "-Wformat-security"
# endif
2013-11-24 15:00:12 +00:00
if ( ! strcasecmp ( item - > info_type , " shutdown.return " ) ) {
/* Sn: Shutdown after n minutes and then turn on when mains is back
* SnRm : Shutdown after n minutes and then turn on after m minutes
* Accepted values for n : .2 - > .9 , 01 - > 10
* Accepted values for m : 0001 - > 9999
* Note : " S01R0001 " and " S01R0002 " may not work on early ( GE ) firmware versions .
* The failure mode is that the UPS turns off and never returns .
* The fix is to push the return value up by 2 , i . e . S01R0003 , and it will return online properly .
* ( thus the default of ondelay = 3 mins ) */
2022-06-29 10:37:36 +00:00
long offdelay = strtol ( dstate_getinfo ( " ups.delay.shutdown " ) , NULL , 10 ) ,
ondelay = strtol ( dstate_getinfo ( " ups.delay.start " ) , NULL , 10 ) / 60 ;
2013-11-24 15:00:12 +00:00
char buf [ SMALLBUF ] = " " ;
2022-06-29 10:37:36 +00:00
if ( ondelay < = 0 ) {
if ( offdelay < 0 ) {
upslogx ( LOG_ERR , " %s: offdelay '%ld' should not be negative " ,
item - > info_type , offdelay ) ;
return - 1 ;
}
2013-11-24 15:00:12 +00:00
if ( offdelay < 60 ) {
2022-06-29 10:37:36 +00:00
snprintf ( buf , sizeof ( buf ) , " .%ld " , offdelay / 6 ) ;
2013-11-24 15:00:12 +00:00
} else {
2022-06-29 10:37:36 +00:00
snprintf ( buf , sizeof ( buf ) , " %02ld " , offdelay / 60 ) ;
2013-11-24 15:00:12 +00:00
}
} else if ( offdelay < 60 ) {
2022-06-29 10:37:36 +00:00
if ( offdelay < 0 ) {
upslogx ( LOG_ERR , " %s: offdelay '%ld' should not be negative " ,
item - > info_type , offdelay ) ;
return - 1 ;
}
snprintf ( buf , sizeof ( buf ) , " .%ldR%04ld " , offdelay / 6 , ondelay ) ;
2013-11-24 15:00:12 +00:00
} else {
2022-06-29 10:37:36 +00:00
if ( offdelay < 0 ) {
upslogx ( LOG_ERR , " %s: offdelay '%ld' should not be negative " ,
item - > info_type , offdelay ) ;
return - 1 ;
}
snprintf ( buf , sizeof ( buf ) , " %02ldR%04ld " , offdelay / 60 , ondelay ) ;
2013-11-24 15:00:12 +00:00
}
snprintf ( value , valuelen , item - > command , buf ) ;
} else if ( ! strcasecmp ( item - > info_type , " shutdown.stayoff " ) ) {
/* SnR0000
* Shutdown after n minutes and stay off
* Accepted values for n : .2 - > .9 , 01 - > 10 */
2022-06-29 10:37:36 +00:00
long offdelay = strtol ( dstate_getinfo ( " ups.delay.shutdown " ) , NULL , 10 ) ;
2013-11-24 15:00:12 +00:00
char buf [ SMALLBUF ] = " " ;
2022-06-29 10:37:36 +00:00
if ( offdelay < 0 ) {
upslogx ( LOG_ERR , " %s: offdelay '%ld' should not be negative " ,
item - > info_type , offdelay ) ;
return - 1 ;
}
2013-11-24 15:00:12 +00:00
if ( offdelay < 60 ) {
2022-06-29 10:37:36 +00:00
snprintf ( buf , sizeof ( buf ) , " .%ld " , offdelay / 6 ) ;
2013-11-24 15:00:12 +00:00
} else {
2022-06-29 10:37:36 +00:00
snprintf ( buf , sizeof ( buf ) , " %02ld " , offdelay / 60 ) ;
2013-11-24 15:00:12 +00:00
}
snprintf ( value , valuelen , item - > command , buf ) ;
} else if ( ! strcasecmp ( item - > info_type , " test.battery.start " ) ) {
2022-06-29 10:37:36 +00:00
long delay = strlen ( value ) > 0 ? strtol ( value , NULL , 10 ) : 600 ;
2013-11-24 15:00:12 +00:00
if ( ( delay < 60 ) | | ( delay > 5940 ) ) {
2022-06-29 10:37:36 +00:00
upslogx ( LOG_ERR , " %s: battery test time '%ld' out of range [60..5940] seconds " , item - > info_type , delay ) ;
2013-11-24 15:00:12 +00:00
return - 1 ;
}
delay = delay / 60 ;
snprintf ( value , valuelen , item - > command , delay ) ;
} else {
/* Don't know what happened */
return - 1 ;
}
2022-06-29 10:37:36 +00:00
# ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
# pragma GCC diagnostic pop
# endif
2013-11-24 15:00:12 +00:00
return 0 ;
}
/* Process status bits */
2016-07-18 00:11:41 +00:00
int blazer_process_status_bits ( item_t * item , char * value , const size_t valuelen )
2013-11-24 15:00:12 +00:00
{
char * val = " " ;
if ( strspn ( item - > value , " 01 " ) ! = 1 ) {
upsdebugx ( 3 , " %s: unexpected value %s@%d->%s " , __func__ , item - > value , item - > from , item - > value ) ;
return - 1 ;
}
switch ( item - > from )
{
case 38 : /* Utility Fail (Immediate) */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " !OL " ;
else
val = " OL " ;
break ;
case 39 : /* Battery Low */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " LB " ;
else
val = " !LB " ;
break ;
case 40 : /* Bypass/Boost or Buck Active */
if ( item - > value [ 0 ] = = ' 1 ' ) {
double vi , vo ;
vi = strtod ( dstate_getinfo ( " input.voltage " ) , NULL ) ;
vo = strtod ( dstate_getinfo ( " output.voltage " ) , NULL ) ;
if ( vo < 0.5 * vi ) {
upsdebugx ( 2 , " %s: output voltage too low " , __func__ ) ;
return - 1 ;
} else if ( vo < 0.95 * vi ) {
val = " TRIM " ;
} else if ( vo < 1.05 * vi ) {
val = " BYPASS " ;
} else if ( vo < 1.5 * vi ) {
val = " BOOST " ;
} else {
upsdebugx ( 2 , " %s: output voltage too high " , __func__ ) ;
return - 1 ;
}
}
break ;
case 41 : /* UPS Failed - ups.alarm */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " UPS selftest failed! " ;
break ;
case 42 : /* UPS Type - ups.type */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " offline / line interactive " ;
else
val = " online " ;
break ;
case 43 : /* Test in Progress */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " CAL " ;
else
val = " !CAL " ;
break ;
case 44 : /* Shutdown Active */
2015-04-30 13:53:36 +00:00
if ( item - > value [ 0 ] = = ' 1 ' )
val = " FSD " ;
else
2013-11-24 15:00:12 +00:00
val = " !FSD " ;
break ;
case 45 : /* Beeper status - ups.beeper.status */
if ( item - > value [ 0 ] = = ' 1 ' )
val = " enabled " ;
else
val = " disabled " ;
break ;
default :
/* Don't know what happened */
return - 1 ;
}
snprintf ( value , valuelen , " %s " , val ) ;
return 0 ;
}