1 /*
2  * riello_ser.c: support for Riello serial protocol based UPSes
3  *
4  * A document describing the protocol implemented by this driver can be
5  * found online at "http://www.networkupstools.org/ups-protocols/riello/PSGPSER-0104.pdf"
6  * and "http://www.networkupstools.org/ups-protocols/riello/PSSENTR-0100.pdf".
7  *
8  * Copyright (C) 2012 - Elio Parisi <e.parisi@riello-ups.com>
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  * Reference of the derivative work: blazer driver
25  */
26 
27 #include <string.h>
28 #include <stdint.h>
29 
30 #include "config.h"
31 #include "main.h"
32 #include "serial.h"
33 #include "timehead.h"
34 #include "hidparser.h"
35 #include "hidtypes.h"
36 #include "common.h" /* for upsdebugx() etc */
37 #include "riello.h"
38 
39 #define DRIVER_NAME	"Riello serial driver"
40 #define DRIVER_VERSION	"0.03"
41 
42 /* driver description structure */
43 upsdrv_info_t upsdrv_info = {
44 	DRIVER_NAME,
45 	DRIVER_VERSION,
46 	"Elio Parisi <e.parisi@riello-ups.com>",
47 	DRV_EXPERIMENTAL,
48 	{ NULL }
49 };
50 
51 uint8_t bufOut[BUFFER_SIZE];
52 uint8_t bufIn[BUFFER_SIZE];
53 
54 uint8_t gpser_error_control;
55 uint8_t typeRielloProtocol;
56 
57 uint8_t input_monophase;
58 uint8_t output_monophase;
59 
60 extern uint8_t commbyte;
61 extern uint8_t wait_packet;
62 extern uint8_t foundnak;
63 extern uint8_t foundbadcrc;
64 extern uint8_t buf_ptr_length;
65 extern uint8_t requestSENTR;
66 
67 TRielloData DevData;
68 
69 /**********************************************************************
70  * char_read (char *bytes, int size, int read_timeout)
71  *
72  * reads size bytes from the serial port
73  *
74  * bytes	  			- buffer to store the data
75  * size				- size of the data to get
76  * read_timeout 	- serial timeout (in milliseconds)
77  *
78  * return -1 on error, -2 on timeout, nb_bytes_readen on success
79  *
80  *********************************************************************/
char_read(char * bytes,int size,int read_timeout)81 static int char_read (char *bytes, int size, int read_timeout)
82 {
83 	struct timeval serial_timeout;
84 	fd_set readfs;
85 	int readen = 0;
86 	int rc = 0;
87 
88 	FD_ZERO (&readfs);
89 	FD_SET (upsfd, &readfs);
90 
91 	serial_timeout.tv_usec = (read_timeout % 1000) * 1000;
92 	serial_timeout.tv_sec = (read_timeout / 1000);
93 
94 	rc = select (upsfd + 1, &readfs, NULL, NULL, &serial_timeout);
95 	if (0 == rc)
96 		return -2;			/* timeout */
97 
98 	if (FD_ISSET (upsfd, &readfs)) {
99 		int now = read (upsfd, bytes, size - readen);
100 
101 		if (now < 0) {
102 			return -1;
103 		}
104 		else {
105 			bytes += now;
106 			readen += now;
107 		}
108 	}
109 	else {
110 		return -1;
111 	}
112 	return readen;
113 }
114 
115 /**********************************************************************
116  * serial_read (int read_timeout)
117  *
118  * return data one byte at a time
119  *
120  * read_timeout - serial timeout (in milliseconds)
121  *
122  * returns 0 on success, -1 on error, -2 on timeout
123  *
124  **********************************************************************/
serial_read(int read_timeout,u_char * readbuf)125 int serial_read (int read_timeout, u_char *readbuf)
126 {
127 	static u_char cache[512];
128 	static u_char *cachep = cache;
129 	static u_char *cachee = cache;
130 	int recv;
131 	*readbuf = '\0';
132 
133 	/* if still data in cache, get it */
134 	if (cachep < cachee) {
135 		*readbuf = *cachep++;
136 		return 0;
137 		/* return (int) *cachep++; */
138 	}
139 	recv = char_read ((char *)cache, 1, read_timeout);
140 
141 	if ((recv == -1) || (recv == -2))
142 		return recv;
143 
144 	cachep = cache;
145 	cachee = cache + recv;
146 	cachep = cache;
147 	cachee = cache + recv;
148 
149 	if (recv) {
150 		upsdebugx(5,"received: %02x", *cachep);
151 		*readbuf = *cachep++;
152 		return 0;
153 	}
154 	return -1;
155 }
156 
riello_serialcomm(uint8_t * bufIn,uint8_t typedev)157 void riello_serialcomm(uint8_t* bufIn, uint8_t typedev)
158 {
159 	time_t realt, nowt;
160 	uint8_t commb = 0;
161 
162 	realt = time(NULL);
163 	while (wait_packet) {
164 		serial_read(1000, &commb);
165 		nowt = time(NULL);
166 		commbyte = commb;
167 		riello_parse_serialport(typedev, bufIn, gpser_error_control);
168 
169 		if ((nowt - realt) > 4)
170 			break;
171 	}
172 }
173 
get_ups_nominal()174 int get_ups_nominal()
175 {
176 	uint8_t length;
177 
178 	riello_init_serial();
179 
180 	length = riello_prepare_gn(&bufOut[0], gpser_error_control);
181 
182 	if (ser_send_buf(upsfd, bufOut, length) == 0) {
183 		upsdebugx (3, "Communication error while writing to port");
184 		return -1;
185 	}
186 
187 	riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
188 
189 	if (!wait_packet && foundbadcrc) {
190 		upsdebugx (3, "Get nominal Ko: bad CRC or Checksum");
191 		return -1;
192 	}
193 
194 	/* mandatory */
195 	if (!wait_packet && foundnak) {
196 		upsdebugx (3, "Get nominal Ko: command not supported");
197 		return -1;
198 	}
199 
200 	upsdebugx (3, "Get nominal Ok: received byte %u", buf_ptr_length);
201 
202 	riello_parse_gn(&bufIn[0], &DevData);
203 
204 	return 0;
205 }
206 
get_ups_status()207 int get_ups_status()
208 {
209 	uint8_t numread, length;
210 
211 	riello_init_serial();
212 
213 	length = riello_prepare_rs(&bufOut[0], gpser_error_control);
214 
215 	if (ser_send_buf(upsfd, bufOut, length) == 0) {
216 		upsdebugx (3, "Communication error while writing to port");
217 		return -1;
218 	}
219 
220 	if (input_monophase)
221 		numread = LENGTH_RS_MM;
222 	else if (output_monophase)
223 		numread = LENGTH_RS_TM;
224 	else
225 		numread = LENGTH_RS_TT;
226 
227 	riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
228 
229 	if (!wait_packet && foundbadcrc) {
230 		upsdebugx (3, "Get status Ko: bad CRC or Checksum");
231 		return -1;
232 	}
233 
234 	/* mandatory */
235 	if (!wait_packet && foundnak) {
236 		upsdebugx (3, "Get status Ko: command not supported");
237 		return -1;
238 	}
239 
240 	upsdebugx (3, "Get status Ok: received byte %u", buf_ptr_length);
241 
242 	riello_parse_rs(&bufIn[0], &DevData, numread);
243 
244 	return 0;
245 }
246 
get_ups_extended()247 int get_ups_extended()
248 {
249 	uint8_t length;
250 
251 	riello_init_serial();
252 
253 	length = riello_prepare_re(&bufOut[0], gpser_error_control);
254 
255 	if (ser_send_buf(upsfd, bufOut, length) == 0) {
256 		upsdebugx (3, "Communication error while writing to port");
257 		return -1;
258 	}
259 
260 	riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
261 
262 	if (!wait_packet && foundbadcrc) {
263 		upsdebugx (3, "Get extended Ko: bad CRC or Checksum");
264 		return -1;
265 	}
266 
267 	/* optonal */
268 	if (!wait_packet && foundnak) {
269 		upsdebugx (3, "Get extended Ko: command not supported");
270 		return 0;
271 	}
272 
273 	upsdebugx (3, "Get extended Ok: received byte %u", buf_ptr_length);
274 
275 	riello_parse_re(&bufIn[0], &DevData);
276 
277 	return 0;
278 }
279 
get_ups_statuscode()280 int get_ups_statuscode()
281 {
282 	uint8_t length;
283 
284 	riello_init_serial();
285 
286 	length = riello_prepare_rc(&bufOut[0], gpser_error_control);
287 
288 	if (ser_send_buf(upsfd, bufOut, length) == 0) {
289 		upsdebugx (3, "Communication error while writing to port");
290 		return -1;
291 	}
292 
293 	riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
294 
295 	if (!wait_packet && foundbadcrc) {
296 		upsdebugx (3, "Get statuscode Ko: bad CRC or Checksum");
297 		return -1;
298 	}
299 
300 	/* optional */
301 	if (!wait_packet && foundnak) {
302 		upsdebugx (3, "Get statuscode Ko: command not supported");
303 		return 0;
304 	}
305 
306 	upsdebugx (3, "Get statuscode Ok: received byte %u", buf_ptr_length);
307 
308 	riello_parse_rc(&bufIn[0], &DevData);
309 
310 	return 0;
311 }
312 
get_ups_sentr()313 int get_ups_sentr()
314 {
315 	uint8_t length;
316 
317 	riello_init_serial();
318 
319 	bufOut[0] = requestSENTR;
320 
321 	if (requestSENTR == SENTR_EXT176) {
322 		bufOut[1] = 103;
323 		bufOut[2] = 1;
324 		bufOut[3] = 0;
325 		bufOut[4] = 24;
326 		length = 5;
327 	}
328 	else
329 		length = 1;
330 
331 	if (ser_send_buf(upsfd, bufOut, length) == 0) {
332 		upsdebugx (3, "Communication error while writing to port");
333 		return -1;
334 	}
335 
336 	riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY);
337 
338 	if (!wait_packet && foundbadcrc) {
339 		upsdebugx (3, "Get sentry Ko: bad CRC or Checksum");
340 		return -1;
341 	}
342 
343 	/* mandatory */
344 	if (!wait_packet && foundnak) {
345 		upsdebugx (3, "Get sentry Ko: command not supported");
346 		return -1;
347 	}
348 
349 	upsdebugx (3, "Get sentry Ok: received byte %u", buf_ptr_length);
350 
351 	riello_parse_sentr(&bufIn[0], &DevData);
352 
353 	return 0;
354 }
355 
riello_instcmd(const char * cmdname,const char * extra)356 int riello_instcmd(const char *cmdname, const char *extra)
357 {
358 	uint8_t length;
359 	uint16_t delay;
360 	const char	*delay_char;
361 
362 	if (!riello_test_bit(&DevData.StatusCode[0], 1)) {
363 		if (!strcasecmp(cmdname, "load.off")) {
364 			delay = 0;
365 			riello_init_serial();
366 
367 			if (typeRielloProtocol == DEV_RIELLOGPSER)
368 				length = riello_prepare_cs(bufOut, gpser_error_control, delay);
369 			else
370 				length = riello_prepare_shutsentr(bufOut, delay);
371 
372 			if (ser_send_buf(upsfd, bufOut, length) == 0) {
373 				upsdebugx (3, "Command load.off communication error");
374 				return STAT_INSTCMD_FAILED;
375 			}
376 
377 			riello_serialcomm(&bufIn[0], typeRielloProtocol);
378 			if (!wait_packet && foundbadcrc) {
379 				upsdebugx (3, "Command load.off Ko: bad CRC or Checksum");
380 				return STAT_INSTCMD_FAILED;
381 			}
382 
383 			if (!wait_packet && foundnak) {
384 				upsdebugx (3, "Command load.off Ko: command not supported");
385 				return STAT_INSTCMD_FAILED;
386 			}
387 
388 			upsdebugx (3, "Command load.off Ok");
389 			return STAT_INSTCMD_HANDLED;
390 		}
391 
392 		if (!strcasecmp(cmdname, "load.off.delay")) {
393 			delay_char = dstate_getinfo("ups.delay.shutdown");
394 			delay = atoi(delay_char);
395 			riello_init_serial();
396 
397 			if (typeRielloProtocol == DEV_RIELLOGPSER)
398 				length = riello_prepare_cs(bufOut, gpser_error_control, delay);
399 			else
400 				length = riello_prepare_shutsentr(bufOut, delay);
401 
402 			if (ser_send_buf(upsfd, bufOut, length) == 0) {
403 				upsdebugx (3, "Command load.off delay communication error");
404 				return STAT_INSTCMD_FAILED;
405 			}
406 
407 			riello_serialcomm(&bufIn[0], typeRielloProtocol);
408 			if (!wait_packet && foundbadcrc) {
409 				upsdebugx (3, "Command load.off.delay Ko: bad CRC or Checksum");
410 				return STAT_INSTCMD_FAILED;
411 			}
412 
413 			if (!wait_packet && foundnak) {
414 				upsdebugx (3, "Command load.off.delay Ko: command not supported");
415 				return STAT_INSTCMD_FAILED;
416 			}
417 
418 			upsdebugx (3, "Command load.off delay Ok");
419 			return STAT_INSTCMD_HANDLED;
420 		}
421 
422 		if (!strcasecmp(cmdname, "load.on")) {
423 			delay = 0;
424 			riello_init_serial();
425 
426 			if (typeRielloProtocol == DEV_RIELLOGPSER)
427 				length = riello_prepare_cr(bufOut, gpser_error_control, delay);
428 			else {
429 				length = riello_prepare_setrebsentr(bufOut, delay);
430 
431 				if (ser_send_buf(upsfd, bufOut, length) == 0) {
432 					upsdebugx (3, "Command load.on communication error");
433 					return STAT_INSTCMD_FAILED;
434 				}
435 
436 				riello_serialcomm(&bufIn[0], typeRielloProtocol);
437 				if (!wait_packet && foundbadcrc) {
438 					upsdebugx (3, "Command load.on Ko: bad CRC or Checksum");
439 					return STAT_INSTCMD_FAILED;
440 				}
441 
442 				if (!wait_packet && foundnak) {
443 					upsdebugx (3, "Command load.on Ko: command not supported");
444 					return STAT_INSTCMD_FAILED;
445 				}
446 
447 				length = riello_prepare_rebsentr(bufOut, delay);
448 			}
449 
450 			if (ser_send_buf(upsfd, bufOut, length) == 0) {
451 				upsdebugx (3, "Command load.on communication error");
452 				return STAT_INSTCMD_FAILED;
453 			}
454 
455 			riello_serialcomm(&bufIn[0], typeRielloProtocol);
456 			if (!wait_packet && foundbadcrc) {
457 				upsdebugx (3, "Command load.on Ko: bad CRC or Checksum");
458 				return STAT_INSTCMD_FAILED;
459 			}
460 
461 			if (!wait_packet && foundnak) {
462 				upsdebugx (3, "Command load.on Ko: command not supported");
463 				return STAT_INSTCMD_FAILED;
464 			}
465 
466 			upsdebugx (3, "Command load.on Ok");
467 			return STAT_INSTCMD_HANDLED;
468 		}
469 
470 		if (!strcasecmp(cmdname, "load.on.delay")) {
471 			delay_char = dstate_getinfo("ups.delay.reboot");
472 			delay = atoi(delay_char);
473 			riello_init_serial();
474 
475 			if (typeRielloProtocol == DEV_RIELLOGPSER)
476 				length = riello_prepare_cr(bufOut, gpser_error_control, delay);
477 			else {
478 				length = riello_prepare_setrebsentr(bufOut, delay);
479 
480 				if (ser_send_buf(upsfd, bufOut, length) == 0) {
481 					upsdebugx (3, "Command load.on delay communication error");
482 					return STAT_INSTCMD_FAILED;
483 				}
484 
485 				riello_serialcomm(&bufIn[0], typeRielloProtocol);
486 				if (!wait_packet && foundbadcrc) {
487 					upsdebugx (3, "Command load.on delay Ko: bad CRC or Checksum");
488 					return STAT_INSTCMD_FAILED;
489 				}
490 
491 				if (!wait_packet && foundnak) {
492 					upsdebugx (3, "Command load.on delay Ko: command not supported");
493 					return STAT_INSTCMD_FAILED;
494 				}
495 
496 				length = riello_prepare_rebsentr(bufOut, delay);
497 			}
498 
499 			if (ser_send_buf(upsfd, bufOut, length) == 0) {
500 				upsdebugx (3, "Command load.on delay communication error");
501 				return STAT_INSTCMD_FAILED;
502 			}
503 
504 			riello_serialcomm(&bufIn[0], typeRielloProtocol);
505 			if (!wait_packet && foundbadcrc) {
506 				upsdebugx (3, "Command load.on.delay Ko: bad CRC or Checksum");
507 				return STAT_INSTCMD_FAILED;
508 			}
509 
510 			if (!wait_packet && foundnak) {
511 				upsdebugx (3, "Command load.on.delay Ko: command not supported");
512 				return STAT_INSTCMD_FAILED;
513 			}
514 
515 			upsdebugx (3, "Command load.on delay Ok");
516 			return STAT_INSTCMD_HANDLED;
517 		}
518 	}
519 	else {
520 		if (!strcasecmp(cmdname, "shutdown.return")) {
521 			delay_char = dstate_getinfo("ups.delay.shutdown");
522 			delay = atoi(delay_char);
523 			riello_init_serial();
524 
525 			if (typeRielloProtocol == DEV_RIELLOGPSER)
526 				length = riello_prepare_cs(bufOut, gpser_error_control, delay);
527 			else
528 				length = riello_prepare_shutsentr(bufOut, delay);
529 
530 			if (ser_send_buf(upsfd, bufOut, length) == 0) {
531 				upsdebugx (3, "Command shutdown.return communication error");
532 				return STAT_INSTCMD_FAILED;
533 			}
534 
535 			riello_serialcomm(&bufIn[0], typeRielloProtocol);
536 			if (!wait_packet && foundbadcrc) {
537 				upsdebugx (3, "Command shutdown.return Ko: bad CRC or Checksum");
538 				return STAT_INSTCMD_FAILED;
539 			}
540 
541 			if (!wait_packet && foundnak) {
542 				upsdebugx (3, "Command shutdown.return Ko: command not supported");
543 				return STAT_INSTCMD_FAILED;
544 			}
545 
546 			upsdebugx (3, "Command shutdown.return Ok");
547 			return STAT_INSTCMD_HANDLED;
548 		}
549 	}
550 
551 	if (!strcasecmp(cmdname, "shutdown.stop")) {
552 		riello_init_serial();
553 
554 		if (typeRielloProtocol == DEV_RIELLOGPSER)
555 			length = riello_prepare_cd(bufOut, gpser_error_control);
556 		else
557 			length = riello_prepare_cancelsentr(bufOut);
558 
559 		if (ser_send_buf(upsfd, bufOut, length) == 0) {
560 			upsdebugx (3, "Command shutdown.stop communication error");
561 			return STAT_INSTCMD_FAILED;
562 		}
563 
564 		riello_serialcomm(&bufIn[0], typeRielloProtocol);
565 		if (!wait_packet && foundbadcrc) {
566 			upsdebugx (3, "Command shutdown.stop Ko: bad CRC or Checksum");
567 			return STAT_INSTCMD_FAILED;
568 		}
569 
570 		if (!wait_packet && foundnak) {
571 			upsdebugx (3, "Command shutdown.stop Ko: command not supported");
572 			return STAT_INSTCMD_FAILED;
573 		}
574 
575 		upsdebugx (3, "Command shutdown.stop Ok");
576 		return STAT_INSTCMD_HANDLED;
577 	}
578 
579 	if (!strcasecmp(cmdname, "test.panel.start")) {
580 		riello_init_serial();
581 		length = riello_prepare_tp(bufOut, gpser_error_control);
582 
583 		if (ser_send_buf(upsfd, bufOut, length) == 0) {
584 			upsdebugx (3, "Command test.panel.start communication error");
585 			return STAT_INSTCMD_FAILED;
586 		}
587 
588 		riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
589 		if (!wait_packet && foundbadcrc) {
590 			upsdebugx (3, "Command test.panel.start Ko: bad CRC or Checksum");
591 			return STAT_INSTCMD_FAILED;
592 		}
593 
594 		if (!wait_packet && foundnak) {
595 			upsdebugx (3, "Command test.panel.start Ko: command not supported");
596 			return STAT_INSTCMD_FAILED;
597 		}
598 
599 		upsdebugx (3, "Command test.panel.start Ok");
600 		return STAT_INSTCMD_HANDLED;
601 	}
602 
603 	if (!strcasecmp(cmdname, "test.battery.start")) {
604 		riello_init_serial();
605 		if (typeRielloProtocol == DEV_RIELLOGPSER)
606 			length = riello_prepare_tb(bufOut, gpser_error_control);
607 		else
608 			length = riello_prepare_tbsentr(bufOut);
609 
610 		if (ser_send_buf(upsfd, bufOut, length) == 0) {
611 			upsdebugx (3, "Command test.battery.start communication error");
612 			return STAT_INSTCMD_FAILED;
613 		}
614 
615 		riello_serialcomm(&bufIn[0], typeRielloProtocol);
616 		if (!wait_packet && foundbadcrc) {
617 			upsdebugx (3, "Command battery.start Ko: bad CRC or Checksum");
618 			return STAT_INSTCMD_FAILED;
619 		}
620 
621 		if (!wait_packet && foundnak) {
622 			upsdebugx (3, "Command battery.start Ko: command not supported");
623 			return STAT_INSTCMD_FAILED;
624 		}
625 
626 		upsdebugx (3, "Command test.battery.start Ok");
627 		return STAT_INSTCMD_HANDLED;
628 	}
629 
630 	upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
631 	return STAT_INSTCMD_UNKNOWN;
632 }
633 
start_ups_comm()634 int start_ups_comm()
635 {
636 	uint8_t length;
637 
638 	upsdebugx (2, "entering start_ups_comm()\n");
639 
640 	riello_init_serial();
641 
642 	if (typeRielloProtocol == DEV_RIELLOGPSER) {
643 		length = riello_prepare_gi(&bufOut[0]);
644 
645 		if (ser_send_buf(upsfd, bufOut, length) == 0) {
646 			upsdebugx (3, "Communication error while writing to port");
647 			return -1;
648 		}
649 
650 		riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
651 	}
652 	else {
653 		bufOut[0] = 192;
654 		length = 1;
655 
656 		if (ser_send_buf(upsfd, bufOut, length) == 0) {
657 			upsdebugx (3, "Communication error while writing to port");
658 			return -1;
659 		}
660 
661 		riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY);
662 	}
663 
664 	if (!wait_packet && foundbadcrc) {
665 		upsdebugx (3, "Get identif Ko: bad CRC or Checksum");
666 		return 1;
667 	}
668 
669 	if (!wait_packet && foundnak) {
670 		upsdebugx (3, "Get identif Ko: command not supported");
671 		return 1;
672 	}
673 
674 	upsdebugx (3, "Get identif Ok: received byte %u", buf_ptr_length);
675 	return 0;
676 
677 }
678 
upsdrv_initinfo(void)679 void upsdrv_initinfo(void)
680 {
681 	int ret;
682 
683 	ret = start_ups_comm();
684 
685 	if (ret < 0)
686 		fatalx(EXIT_FAILURE, "No communication with UPS");
687 	else if (ret > 0)
688 		fatalx(EXIT_FAILURE, "Bad checksum or NACK");
689 	else
690 		upsdebugx(2, "Communication with UPS established");
691 
692 	if (typeRielloProtocol == DEV_RIELLOGPSER)
693 		riello_parse_gi(&bufIn[0], &DevData);
694 	else
695 		riello_parse_sentr(&bufIn[0], &DevData);
696 
697 	gpser_error_control = DevData.Identif_bytes[4]-0x30;
698 	if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '2'))
699 		input_monophase = 1;
700 	else {
701 		input_monophase = 0;
702 		dstate_setinfo("input.phases", "%u", 3);
703 		dstate_setinfo("input.phases", "%u", 3);
704 		dstate_setinfo("input.bypass.phases", "%u", 3);
705 	}
706 	if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '3'))
707 		output_monophase = 1;
708 	else {
709 		output_monophase = 0;
710 		dstate_setinfo("output.phases", "%u", 3);
711 	}
712 
713 	dstate_setinfo("device.mfr", "RPS S.p.a.");
714 	dstate_setinfo("device.model", "%s", (unsigned char*) DevData.ModelStr);
715 	dstate_setinfo("device.serial", "%s", (unsigned char*) DevData.Identification);
716 	dstate_setinfo("device.type", "ups");
717 
718 	dstate_setinfo("ups.mfr", "RPS S.p.a.");
719 	dstate_setinfo("ups.model", "%s", (unsigned char*) DevData.ModelStr);
720 	dstate_setinfo("ups.serial", "%s", (unsigned char*) DevData.Identification);
721 	dstate_setinfo("ups.firmware", "%s", (unsigned char*) DevData.Version);
722 
723 	if (typeRielloProtocol == DEV_RIELLOGPSER) {
724 		if (get_ups_nominal() == 0) {
725 			dstate_setinfo("ups.realpower.nominal", "%u", DevData.NomPowerKW);
726 			dstate_setinfo("ups.power.nominal", "%u", DevData.NomPowerKVA);
727 			dstate_setinfo("output.voltage.nominal", "%u", DevData.NominalUout);
728 			dstate_setinfo("output.frequency.nominal", "%.1f", DevData.NomFout/10.0);
729 			dstate_setinfo("battery.voltage.nominal", "%u", DevData.NomUbat);
730 			dstate_setinfo("battery.capacity", "%u", DevData.NomBatCap);
731 		}
732 	}
733 	else {
734 		if (get_ups_sentr() == 0) {
735 			dstate_setinfo("ups.realpower.nominal", "%u", DevData.NomPowerKW);
736 			dstate_setinfo("ups.power.nominal", "%u", DevData.NomPowerKVA);
737 			dstate_setinfo("output.voltage.nominal", "%u", DevData.NominalUout);
738 			dstate_setinfo("output.frequency.nominal", "%.1f", DevData.NomFout/10.0);
739 			dstate_setinfo("battery.voltage.nominal", "%u", DevData.NomUbat);
740 			dstate_setinfo("battery.capacity", "%u", DevData.NomBatCap);
741 		}
742 	}
743 
744 
745 	/* commands ----------------------------------------------- */
746 	dstate_addcmd("load.off");
747 	dstate_addcmd("load.on");
748 	dstate_addcmd("load.off.delay");
749 	dstate_addcmd("load.on.delay");
750 	dstate_addcmd("shutdown.return");
751 	dstate_addcmd("shutdown.stop");
752 	dstate_addcmd("test.battery.start");
753 
754 	if (typeRielloProtocol == DEV_RIELLOGPSER)
755 		dstate_addcmd("test.panel.start");
756 
757 	/* install handlers */
758 /*	upsh.setvar = hid_set_value; setvar; */
759 	upsh.instcmd = riello_instcmd;
760 }
761 
upsdrv_updateinfo(void)762 void upsdrv_updateinfo(void)
763 {
764 	uint8_t getextendedOK;
765 	static int countlost = 0;
766 	int stat;
767 
768 	upsdebugx(1, "countlost %d",countlost);
769 
770 	if (countlost > 0){
771 		upsdebugx(1, "Communication with UPS is lost: status read failed!");
772 
773 		if (countlost == COUNTLOST) {
774 			dstate_datastale();
775 			upslogx(LOG_WARNING, "Communication with UPS is lost: status read failed!");
776 		}
777 	}
778 
779 	if (typeRielloProtocol == DEV_RIELLOGPSER)
780 		stat = get_ups_status();
781 	else
782 		stat = get_ups_sentr();
783 
784 	if (stat < 0) {
785 		if (countlost < COUNTLOST)
786 			countlost++;
787 		return;
788 	}
789 
790 	if (typeRielloProtocol == DEV_RIELLOGPSER) {
791 		if (get_ups_extended() == 0)
792 			getextendedOK = 1;
793 		else
794 			getextendedOK = 0;
795 	}
796 	else
797 		getextendedOK = 1;
798 
799 	if (countlost == COUNTLOST)
800 		upslogx(LOG_NOTICE, "Communication with UPS is re-established!");
801 
802 	dstate_setinfo("input.frequency", "%.2f", DevData.Finp/10.0);
803 	dstate_setinfo("input.bypass.frequency", "%.2f", DevData.Fbypass/10.0);
804 	dstate_setinfo("output.frequency", "%.2f", DevData.Fout/10.0);
805 	dstate_setinfo("battery.voltage", "%.1f", DevData.Ubat/10.0);
806 	dstate_setinfo("battery.charge", "%u", DevData.BatCap);
807 	dstate_setinfo("battery.runtime", "%u", DevData.BatTime*60);
808 	dstate_setinfo("ups.temperature", "%u", DevData.Tsystem);
809 
810 	if (input_monophase) {
811 		dstate_setinfo("input.voltage", "%u", DevData.Uinp1);
812 		dstate_setinfo("input.bypass.voltage", "%u", DevData.Ubypass1);
813 	}
814 	else {
815 		dstate_setinfo("input.L1-N.voltage", "%u", DevData.Uinp1);
816 		dstate_setinfo("input.L2-N.voltage", "%u", DevData.Uinp2);
817 		dstate_setinfo("input.L3-N.voltage", "%u", DevData.Uinp3);
818 		dstate_setinfo("input.bypass.L1-N.voltage", "%u", DevData.Ubypass1);
819 		dstate_setinfo("input.bypass.L2-N.voltage", "%u", DevData.Ubypass2);
820 		dstate_setinfo("input.bypass.L3-N.voltage", "%u", DevData.Ubypass3);
821 	}
822 
823 	if (output_monophase) {
824 		dstate_setinfo("output.voltage", "%u", DevData.Uout1);
825 		dstate_setinfo("output.power.percent", "%u", DevData.Pout1);
826 		dstate_setinfo("ups.load", "%u", DevData.Pout1);
827 	}
828 	else {
829 		dstate_setinfo("output.L1-N.voltage", "%u", DevData.Uout1);
830 		dstate_setinfo("output.L2-N.voltage", "%u", DevData.Uout2);
831 		dstate_setinfo("output.L3-N.voltage", "%u", DevData.Uout3);
832 		dstate_setinfo("output.L1.power.percent", "%u", DevData.Pout1);
833 		dstate_setinfo("output.L2.power.percent", "%u", DevData.Pout2);
834 		dstate_setinfo("output.L3.power.percent", "%u", DevData.Pout3);
835 		dstate_setinfo("ups.load", "%u", (DevData.Pout1+DevData.Pout2+DevData.Pout3)/3);
836 	}
837 
838 	status_init();
839 
840 	/* AC Fail */
841 	if (riello_test_bit(&DevData.StatusCode[0], 1))
842 		status_set("OB");
843 	else
844 		status_set("OL");
845 
846 	/* LowBatt */
847 	if ((riello_test_bit(&DevData.StatusCode[0], 1)) &&
848 		(riello_test_bit(&DevData.StatusCode[0], 0)))
849 		status_set("LB");
850 
851 	/* Standby */
852 	if (!riello_test_bit(&DevData.StatusCode[0], 3))
853 		status_set("OFF");
854 
855 	/* On Bypass */
856 	if (riello_test_bit(&DevData.StatusCode[1], 3))
857 		status_set("BYPASS");
858 
859 	/* Overload */
860 	if (riello_test_bit(&DevData.StatusCode[4], 2))
861 		status_set("OVER");
862 
863 	/* Buck */
864 	if (riello_test_bit(&DevData.StatusCode[1], 0))
865 		status_set("TRIM");
866 
867 	/* Boost */
868 	if (riello_test_bit(&DevData.StatusCode[1], 1))
869 		status_set("BOOST");
870 
871 	/* Replace battery */
872 	if (riello_test_bit(&DevData.StatusCode[2], 0))
873 		status_set("RB");
874 
875 	/* Charging battery */
876 	if (riello_test_bit(&DevData.StatusCode[2], 2))
877 		status_set("CHRG");
878 
879 	status_commit();
880 
881 	dstate_dataok();
882 
883 	if (getextendedOK) {
884 		dstate_setinfo("output.L1.power", "%u", DevData.Pout1VA);
885 		dstate_setinfo("output.L2.power", "%u", DevData.Pout2VA);
886 		dstate_setinfo("output.L3.power", "%u", DevData.Pout3VA);
887 		dstate_setinfo("output.L1.realpower", "%u", DevData.Pout1W);
888 		dstate_setinfo("output.L2.realpower", "%u", DevData.Pout2W);
889 		dstate_setinfo("output.L3.realpower", "%u", DevData.Pout3W);
890 		dstate_setinfo("output.L1.current", "%u", DevData.Iout1);
891 		dstate_setinfo("output.L2.current", "%u", DevData.Iout2);
892 		dstate_setinfo("output.L3.current", "%u", DevData.Iout3);
893 	}
894 
895 	poll_interval = 2;
896 
897 	countlost = 0;
898 /*	if (get_ups_statuscode() != 0)
899 		upsdebugx(2, "Communication is lost");
900 	else {
901 	}*/
902 
903 	/*
904 	 * poll_interval = 2;
905 	 */
906 }
907 
upsdrv_shutdown(void)908 void upsdrv_shutdown(void)
909 {
910 	/* tell the UPS to shut down, then return - DO NOT SLEEP HERE */
911 	int	retry;
912 
913 	/* maybe try to detect the UPS here, but try a shutdown even if
914 		it doesn't respond at first if possible */
915 
916 	/* replace with a proper shutdown function */
917 
918 
919 	/* you may have to check the line status since the commands
920 		for toggling power are frequently different for OL vs. OB */
921 
922 	/* OL: this must power cycle the load if possible */
923 
924 	/* OB: the load must remain off until the power returns */
925 	upsdebugx(2, "upsdrv Shutdown execute");
926 
927 	for (retry = 1; retry <= MAXTRIES; retry++) {
928 
929 		if (riello_instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) {
930 			continue;
931 		}
932 
933 		if (riello_instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) {
934 			continue;
935 		}
936 
937 		fatalx(EXIT_SUCCESS, "Shutting down");
938 	}
939 
940 	fatalx(EXIT_FAILURE, "Shutdown failed!");
941 }
942 
943 
944 /*
945 static int setvar(const char *varname, const char *val)
946 {
947 	if (!strcasecmp(varname, "ups.test.interval")) {
948 		ser_send_buf(upsfd, ...);
949 		return STAT_SET_HANDLED;
950 	}
951 
952 	upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname);
953 	return STAT_SET_UNKNOWN;
954 }
955 */
956 
upsdrv_help(void)957 void upsdrv_help(void)
958 {
959 }
960 
961 /* list flags and values that you want to receive via -x */
upsdrv_makevartable(void)962 void upsdrv_makevartable(void)
963 {
964 	/* allow '-x xyzzy' */
965 	/* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */
966 
967 	/* allow '-x foo=<some value>' */
968 	/* addvar(VAR_VALUE, "foo", "Override foo setting"); */
969 }
970 
upsdrv_initups(void)971 void upsdrv_initups(void)
972 {
973 	upsdebugx(2, "entering upsdrv_initups()");
974 
975 	upsfd = ser_open(device_path);
976 
977 	riello_comm_setup(device_path);
978 
979 	/* probe ups type */
980 
981 	/* to get variables and flags from the command line, use this:
982 	 *
983 	 * first populate with upsdrv_buildvartable above, then...
984 	 *
985 	 *	  				set flag foo : /bin/driver -x foo
986 	 * set variable 'cable' to '1234' : /bin/driver -x cable=1234
987 	 *
988 	 * to test flag foo in your code:
989 	 *
990 	 * 	if (testvar("foo"))
991 	 * 		do_something();
992 	 *
993 	 * to show the value of cable:
994 	 *
995 	 *	if ((cable = getval("cable")))
996 	 *		printf("cable is set to %s\n", cable);
997 	 *	else
998 	 *		printf("cable is not set!\n");
999 	 *
1000 	 * don't use NULL pointers - test the return result first!
1001 	 */
1002 
1003 	/* the upsh handlers can't be done here, as they get initialized
1004 	 * shortly after upsdrv_initups returns to main.
1005 	 */
1006 
1007 	/* don't try to detect the UPS here */
1008 
1009 	/* initialise communication */
1010 }
1011 
upsdrv_cleanup(void)1012 void upsdrv_cleanup(void)
1013 {
1014 	/* free(dynamic_mem); */
1015 	ser_close(upsfd, device_path);
1016 }
1017 
riello_comm_setup(const char * port)1018 void riello_comm_setup(const char *port)
1019 {
1020 	uint8_t length;
1021 
1022 	upsdebugx(2, "set baudrate 9600");
1023 	ser_set_speed(upsfd, device_path, B9600);
1024 
1025 	upsdebugx(2, "try to detect SENTR");
1026 	riello_init_serial();
1027 	bufOut[0] = 192;
1028 	ser_send_buf(upsfd, bufOut, 1);
1029 
1030 	riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY);
1031 
1032 	if (buf_ptr_length == 103) {
1033 		typeRielloProtocol = DEV_RIELLOSENTRY;
1034 		upslogx(LOG_INFO, "Connected to UPS SENTR on %s with baudrate %d", port, 9600);
1035 		return;
1036 	}
1037 
1038 	upsdebugx(2, "try to detect GPSER");
1039 	riello_init_serial();
1040 	length = riello_prepare_gi(&bufOut[0]);
1041 
1042 	ser_send_buf(upsfd, bufOut, length);
1043 
1044 	riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
1045 
1046 	if (!wait_packet && !foundbadcrc && !foundnak) {
1047 		typeRielloProtocol = DEV_RIELLOGPSER;
1048 		upslogx(LOG_INFO, "Connected to UPS GPSER on %s with baudrate %d", port, 9600);
1049 		return;
1050 	}
1051 
1052 	upsdebugx(2, "set baudrate 1200");
1053 	ser_set_speed(upsfd, device_path, B1200);
1054 
1055 	upsdebugx(2, "try to detect SENTR");
1056 	riello_init_serial();
1057 	bufOut[0] = 192;
1058 	ser_send_buf(upsfd, bufOut, 1);
1059 
1060 	riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY);
1061 
1062 	if (buf_ptr_length == 103) {
1063 		typeRielloProtocol = DEV_RIELLOSENTRY;
1064 		upslogx(LOG_INFO, "Connected to UPS SENTR on %s with baudrate %d", port, 1200);
1065 		return;
1066 	}
1067 
1068 	upsdebugx(2, "try to detect GPSER");
1069 	riello_init_serial();
1070 	length = riello_prepare_gi(&bufOut[0]);
1071 
1072 	ser_send_buf(upsfd, bufOut, length);
1073 
1074 	riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER);
1075 
1076 	if (!wait_packet && !foundbadcrc && !foundnak) {
1077 		typeRielloProtocol = DEV_RIELLOGPSER;
1078 		upslogx(LOG_INFO, "Connected to UPS GPSER on %s with baudrate %d", port, 1200);
1079 		return;
1080 	}
1081 
1082 	fatalx(EXIT_FAILURE, "Can't connect to the UPS on port %s!\n", port);
1083 }
1084 
1085