1 /* nutdrv_qx.h - Driver for USB and serial UPS units with Q* protocols
2  *
3  * Copyright (C)
4  *   2013 Daniele Pezzini <hyouko@gmail.com>
5  * Based on usbhid-ups.h - Copyright (C)
6  *   2003-2009 Arnaud Quette <http://arnaud.quette.free.fr/contact.html>
7  *   2005-2006 Peter Selinger <selinger@users.sourceforge.net>
8  *   2007-2009 Arjen de Korte <adkorte-guest@alioth.debian.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  */
25 
26 #ifndef NUTDRV_QX_H
27 #define NUTDRV_QX_H
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include "config.h"
34 
35 /* For testing purposes */
36 /*#define TESTING*/
37 
38 /* Driver's parameters */
39 #define QX_VAR_ONDELAY	"ondelay"
40 #define QX_VAR_OFFDELAY	"offdelay"
41 #define QX_VAR_POLLFREQ	"pollfreq"
42 
43 /* Parameters default values */
44 #define DEFAULT_ONDELAY		"180"	/* Delay between return of utility power and powering up of load, in seconds */
45 #define DEFAULT_OFFDELAY	"30"	/* Delay before power off, in seconds */
46 #define DEFAULT_POLLFREQ	30	/* Polling interval between full updates, in seconds; the driver will do quick polls in the meantime */
47 
48 #ifndef TRUE
49 typedef enum { FALSE, TRUE } bool_t;
50 #else
51 typedef int bool_t;
52 #endif
53 
54 /* Structure for rw vars */
55 typedef struct {
56 	char	value[SMALLBUF];				/* Value for enum/range, or length for ST_FLAG_STRING */
57 	int	(*preprocess)(char *value, const size_t len);	/* Optional function to preprocess range/enum value.
58 								 * This function will be given value and its size_t and must return either 0 if value is supported or -1 if not supported. */
59 } info_rw_t;
60 
61 /* Structure containing information about how to get/set data from/to the UPS and convert these to/from NUT standard */
62 typedef struct item_t {
63 	const char	*info_type;		/* NUT variable name
64 						 * If QX_FLAG_NONUT is set, name to print to the logs
65 						 * If both QX_FLAG_NONUT and QX_FLAG_SETVAR are set, name of the var to retrieve from ups.conf */
66 	const int	info_flags;		/* NUT flags (ST_FLAG_* values to set in dstate_addinfo) */
67 	info_rw_t	*info_rw;		/* An array of info_rw_t to handle r/w variables:
68 						 * If ST_FLAG_STRING is set: length of the string (dstate_setaux)
69 						 * If QX_FLAG_ENUM is set: enumerated values (dstate_addenum)
70 						 * If QX_FLAG_RANGE is set: range boundaries (dstate_addrange)
71 						 * If QX_FLAG_SETVAR is set the value given by the user will be checked against these infos. */
72 	const char	*command;		/* Command sent to the UPS to get answer/to execute an instant command/to set a variable */
73 
74 	char		answer[SMALLBUF];	/* Answer from the UPS, filled at runtime.
75 						 * If you expect a nonvalid C string (e.g.: inner '\0's) or need to perform actions before the answer is used (and treated as a null-terminated string), you should set a preprocess_answer() function */
76 	const size_t	answer_len;		/* Expected min length of the answer. Set it to 0 if there's no minimum length to look after. */
77 	const char	leading;		/* Expected leading character of the answer (optional) */
78 
79 	char		value[SMALLBUF];	/* Value from the answer, filled at runtime (i.e. answer between from and to) */
80 	const int	from;			/* Position of the starting character of the info (i.e. 'value') we're after in the answer */
81 	const int	to;			/* Position of the ending character of the info (i.e. 'value') we're after in the answer: use 0 if all the remaining of the line is needed */
82 
83 	const char	*dfl;			/* Format to store value from the UPS in NUT variables. Not used by the driver for QX_FLAG_{CMD,SETVAR} items.
84 						 * If there's no preprocess function, set it either to %s for strings or to a floating point specifier (e.g. %.1f) for numbers.
85 						 * Otherwise:
86 						 * If QX_FLAG_ABSENT: default value
87 						 * If QX_FLAG_CMD: default command value */
88 
89 	unsigned long	qxflags;		/* Driver's own flags */
90 
91 	int		(*preprocess_command)(struct item_t *item, char *command, const size_t commandlen);
92 						/* Last chance to preprocess the command to be sent to the UPS (e.g. to add CRC, ...).
93 						 * This function is given the currently processed item (item), the command to be sent to the UPS (command) and its size_t (commandlen).
94 						 * Return -1 in case of errors, else 0.
95 						 * command must be filled with the actual command to be sent to the UPS. */
96 
97 	int		(*preprocess_answer)(struct item_t *item, const int len);
98 						/* Function to preprocess the answer we got from the UPS before we do anything else (e.g. for CRC, decoding, ...).
99 						 * This function is given the currently processed item (item) with the answer we got from the UPS unmolested and already stored in item->answer and the length of that answer (len).
100 						 * Return -1 in case of errors, else the length of the newly allocated item->answer (from now on, treated as a null-terminated string). */
101 
102 	int		(*preprocess)(struct item_t *item, char *value, const size_t valuelen);
103 						/* Function to preprocess the data from/to the UPS
104 						 * This function is given the currently processed item (item), a char array (value) and its size_t (valuelen).
105 						 * Return -1 in case of errors, else 0.
106 						 * If QX_FLAG_SETVAR/QX_FLAG_CMD -> process command before it is sent: value must be filled with the command to be sent to the UPS.
107 						 * Otherwise -> process value we got from answer before it gets stored in a NUT variable: value must be filled with the processed value already compliant to NUT standards. */
108 } item_t;
109 
110 /* Driver's own flags */
111 #define QX_FLAG_STATIC		2UL	/* Retrieve info only once. */
112 #define QX_FLAG_SEMI_STATIC	4UL	/* Retrieve info smartly, i.e. only when a command/setvar is executed and we expect that data could have been changed. */
113 #define QX_FLAG_ABSENT		8UL	/* Data is absent in the device, use default value. */
114 #define QX_FLAG_QUICK_POLL	16UL	/* Mandatory vars, polled also in QX_WALKMODE_QUICK_UPDATE.
115 					 * If there's a problem with a var not flagged as QX_FLAG_QUICK_POLL in QX_WALKMODE_INIT, the driver will automagically set QX_FLAG_SKIP on it and then it'll skip that item in QX_WALKMODE_{QUICK,FULL}_UPDATE.
116 					 * Otherwise, if the item has the flag QX_FLAG_QUICK_POLL set, in case of errors in QX_WALKMODE_INIT the driver will set datastale. */
117 #define QX_FLAG_CMD		32UL	/* Instant command. */
118 #define QX_FLAG_SETVAR		64UL	/* The var is settable and the actual item stores info on how to set it. */
119 #define QX_FLAG_TRIM		128UL	/* This var's value need to be trimmed of leading/trailing spaces/hashes. */
120 #define QX_FLAG_ENUM		256UL	/* Enum values exist and are stored in info_rw. */
121 #define QX_FLAG_RANGE		512UL	/* Ranges for this var available and are stored in info_rw. */
122 #define QX_FLAG_NONUT		1024UL	/* This var doesn't have a corresponding var in NUT. */
123 #define QX_FLAG_SKIP		2048UL	/* Skip this var: this item won't be processed. */
124 
125 #define MAXTRIES		3	/* Max number of retries */
126 
127 #ifdef TESTING
128 /* Testing struct */
129 typedef struct {
130 	const char	*cmd;			/* Command to match */
131 	const char	answer[SMALLBUF];	/* Answer for that command.
132 						 * Note: if 'answer' contains inner '\0's, in order to preserve them, 'answer_len' as well as an item_t->preprocess_answer() function must be set */
133 	const int	answer_len;		/* Answer length:
134 						 * - if set to -1 -> auto calculate answer length (treat 'answer' as a null-terminated string)
135 						 * - otherwise -> use the provided length (if reasonable) and preserve inner '\0's (treat 'answer' as a sequence of bytes till the item_t->preprocess_answer() function gets called) */
136 } testing_t;
137 #endif	/* TESTING */
138 
139 /* Subdriver interface */
140 typedef struct {
141 	const char	*name;			/* Name of this subdriver, i.e. name (must be equal to the protocol name) + space + version */
142 	int		(*claim)(void);		/* Function that allows the subdriver to "claim" a device: return 1 if device is covered by this subdriver, else 0 */
143 	item_t		*qx2nut;		/* Main table of vars and instcmds */
144 	void		(*initups)(void);	/* Subdriver specific upsdrv_initups. Called at the end of nutdrv_qx's own upsdrv_initups */
145 	void		(*initinfo)(void);	/* Subdriver specific upsdrv_initinfo. Called at the end of nutdrv_qx's own upsdrv_initinfo */
146 	void		(*makevartable)(void);	/* Subdriver specific ups.conf flags/vars */
147 	const char	*accepted;		/* String to match if the driver is expecting a reply from the UPS on instcmd/setvar.
148 						 * This comparison is done after the answer we got back from the UPS has been processed to get the value we are searching:
149 						 *  - you don't have to include the trailing carriage return (\r)
150 						 *  - you can decide at which index of the answer the value should start or end setting the appropriate from and to in the item_t */
151 	const char	*rejected;		/* String to match if the driver is expecting a reply from the UPS in case of error.
152 						 * This comparison is done on the answer we got back from the UPS before it has been processed:
153 						 *  - include also the trailing carriage return (\r) and whatever character is expected */
154 #ifdef TESTING
155 	testing_t	*testing;		/* Testing table: commands and the replies used for testing the subdriver */
156 #endif	/* TESTING */
157 } subdriver_t;
158 
159 /* The following functions are exported for the benefit of subdrivers */
160 	/* Execute an instant command. In detail:
161 	 * - look up the given 'cmdname' in the qx2nut data structure (if not found, try to fallback to commonly known commands);
162 	 * - if 'cmdname' is found, call its preprocess function, passing to it 'extradata', if any, otherwise its dfl value, if any;
163 	 * - send the command to the device and check the reply.
164 	 * Return STAT_INSTCMD_INVALID if the command is invalid, STAT_INSTCMD_FAILED if it failed, STAT_INSTCMD_HANDLED on success. */
165 int	instcmd(const char *cmdname, const char *extradata);
166 	/* Set r/w variable to a value after it has been checked against its info_rw structure. Return STAT_SET_HANDLED on success, otherwise STAT_SET_UNKNOWN. */
167 int	setvar(const char *varname, const char *val);
168 	/* Find an item of item_t type in qx2nut data structure by its info_type, optionally filtered by its qxflags, and return it if found, otherwise return NULL.
169 	 *  - 'flag': flags that have to be set in the item, i.e. if one of the flags is absent in the item it won't be returned
170 	 *  - 'noflag': flags that have to be absent in the item, i.e. if at least one of the flags is set in the item it won't be returned */
171 item_t	*find_nut_info(const char *varname, const unsigned long flag, const unsigned long noflag);
172 	/* Send 'command' (a null-terminated byte string) or, if it is NULL, send the command stored in the item to the UPS and process the reply, saving it in item->answer. Return -1 on errors, 0 on success. */
173 int	qx_process(item_t *item, const char *command);
174 	/* Process the value we got back from the UPS (set status bits and set the value of other parameters), calling the item-specific preprocess function, if any, otherwise executing the standard preprocessing (including trimming if QX_FLAG_TRIM is set).
175 	 * Return -1 on failure, 0 for a status update and 1 in all other cases. */
176 int	ups_infoval_set(item_t *item);
177 	/* Return the currently processed status so that it can be checked with one of the status_bit_t passed to the STATUS() macro. */
178 unsigned int	qx_status(void);
179 	/* Edit the current status: it takes one of the NUT status (all but OB are supported, simply set it as not OL), eventually preceded with an exclamation mark to clear it from the status (e.g. !OL). */
180 void	update_status(const char *nutvalue);
181 
182 /* Data for processing status values */
183 #define	STATUS(x)	((unsigned int)1U<<x)
184 
185 typedef enum {
186 	OL = 0,		/* On line */
187 	LB,		/* Low battery */
188 	RB,		/* Replace battery */
189 	CHRG,		/* Charging */
190 	DISCHRG,	/* Discharging */
191 	BYPASS,		/* On bypass */
192 	CAL,		/* Calibration */
193 	OFF,		/* UPS is off */
194 	OVER,		/* Overload */
195 	TRIM,		/* SmartTrim */
196 	BOOST,		/* SmartBoost */
197 	FSD 		/* Shutdown imminent */
198 } status_bit_t;
199 
200 #endif	/* NUTDRV_QX_H */
201