1 /*
2  * al175.c - NUT support for Eltek AL175 alarm module.
3  *           AL175 shall be in COMLI mode.
4  *
5  * Copyright (C) 2004-2013 Marine & Bridge Navigation Systems <http://mns.spb.ru>
6  * Author: Kirill Smelkov <kirr@mns.spb.ru>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */
22 
23 
24 /*
25  * - NOTE the following document is referenced in this driver:
26  *
27  *	TE-36862-B4 "COMLI COMMUNICATION PROTOCOL IMPLEMENTED IN PRS SYSTEMS",
28  *	by Eltek A/S
29  *
30  *
31  * - AL175 debug levels:
32  *
33  *	1 user-level trace (status, instcmd, etc...)
34  * 	2 status decode errors
35  * 	3 COMLI proto handling errors
36  * 	4 raw IO trace
37  *
38  */
39 
40 #include "main.h"
41 #include "serial.h"
42 #include "timehead.h"
43 
44 #include <stddef.h>
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 
50 
51 #include "nut_stdint.h"
52 typedef	uint8_t byte_t;
53 
54 
55 #define DRIVER_NAME	"Eltek AL175/COMLI driver"
56 #define DRIVER_VERSION	"0.12"
57 
58 /* driver description structure */
59 upsdrv_info_t upsdrv_info = {
60 	DRIVER_NAME,
61 	DRIVER_VERSION,
62 	"Kirill Smelkov <kirr@mns.spb.ru>\n" \
63 	"Marine & Bridge Navigation Systems <http://mns.spb.ru>",
64 	DRV_EXPERIMENTAL,
65 	{ NULL }
66 };
67 
68 
69 #define	STX	0x02
70 #define	ETX	0x03
71 #define	ACK	0x06
72 
73 
74 /************
75  * RAW DATA *
76  ************/
77 
78 /**
79  * raw_data buffer representation
80  */
81 typedef struct {
82 	byte_t     *buf;	/*!< the whole buffer address	*/
83 	unsigned    buf_size;	/*!< the whole buffer size	*/
84 
85 	byte_t     *begin;	/*!< begin of content		*/
86 	byte_t     *end;	/*!< one-past-end of content	*/
87 } raw_data_t;
88 
89 
90 /**
91  * pseudo-alloca raw_data buffer  (alloca is not in POSIX)
92  * @param  varp		ptr-to local raw_data_t variable to which to alloca
93  * @param  buf_array	array allocated on stack which will be used as storage
94  *			(must be auto-variable)
95  * @return alloca'ed memory as raw_data
96  *
97  * Example:
98  *
99  *	raw_data_t ack;
100  *	byte_t     ack_buf[8];
101  *
102  *	raw_alloc_onstack(&ack, ack_buf);
103  */
104 #define raw_alloc_onstack(varp, buf_array) do {		\
105 	(varp)->buf		= &(buf_array)[0];	\
106 	(varp)->buf_size	= sizeof(buf_array);	\
107 							\
108 	(varp)->begin		= (varp)->buf;		\
109 	(varp)->end		= (varp)->buf;		\
110 } while (0)
111 
112 
113 /**
114  * xmalloc raw buffer
115  * @param  size	size in bytes
116  * @return xmalloc'ed memory as raw_data
117  */
raw_xmalloc(size_t size)118 raw_data_t raw_xmalloc(size_t size)
119 {
120 	raw_data_t data;
121 
122 	data.buf	= xmalloc(size);
123 	data.buf_size	= size;
124 
125 	data.begin	= data.buf;
126 	data.end	= data.buf;
127 
128 	return data;
129 }
130 
131 /**
132  * free raw_data buffer
133  * @param  buf	raw_data buffer to free
134  */
raw_free(raw_data_t * buf)135 void raw_free(raw_data_t *buf)
136 {
137 	free(buf->buf);
138 
139 	buf->buf      = NULL;
140 	buf->buf_size = 0;
141 	buf->begin    = NULL;
142 	buf->end      = NULL;
143 }
144 
145 
146 /***************************************************************************/
147 
148 /***************
149  * COMLI types *
150  ***************/
151 
152 /**
153  * COMLI message header info
154  * @see 1. INTRODUCTION
155  */
156 typedef struct {
157 	int  id;	/*!< Id[1:2]		*/
158 	int  stamp;	/*!< Stamp[3]		*/
159 	int  type;	/*!< Mess Type[4]	*/
160 } msg_head_t;
161 
162 /**
163  * COMLI IO header info
164  * @see 1. INTRODUCTION
165  */
166 typedef struct {
167 	unsigned  addr;	/*!< Addr[5:8]		*/
168 	unsigned  len;	/*!< NOB[9:10]		*/
169 } io_head_t;
170 
171 /**
172  * maximum allowed io.len value
173  */
174 #define	IO_LEN_MAX	0xff
175 
176 /**
177  * COMLI header info
178  * @see 1. INTRODUCTION
179  */
180 typedef struct {
181 	msg_head_t  msg;	/*!< message header [1:4]	*/
182 	io_head_t   io;		/*!< io header [5:10]		*/
183 } comli_head_t;
184 
185 
186 
187 /******************
188  * MISC UTILITIES *
189  ******************/
190 
191 /**
192  * convert hex string to int
193  * @param  head  input string
194  * @param  count string length
195  * @return parsed value (>=0) if success, -1 on error
196  */
from_hex(const byte_t * head,unsigned len)197 static long from_hex(const byte_t *head, unsigned len)
198 {
199 	long val=0;
200 
201 	while (len-- != 0) {
202 		int ch = *head;
203 
204 		if (!isxdigit(ch))
205 			return -1;	/* wrong character	*/
206 
207 		val *= 0x10;
208 
209 		if (isdigit(ch)) {
210 			val += (ch-'0');
211 		}
212 		else {
213 			/* ch = toupper(ch)  without locale-related problems */
214 			if (ch < 'A')
215 				ch += 'A' - 'a';
216 
217 			val += 0x0A + (ch-'A');
218 		}
219 
220 		++head;
221 	}
222 
223 	return val;
224 }
225 
226 /**
227  * compute checksum of a buffer
228  * @see 10. CHECKSUM BCC
229  * @param   buf     buffer address
230  * @param   count   no. of bytes in the buffer
231  * @return  computed checksum
232  */
compute_bcc(const byte_t * buf,size_t count)233 static byte_t compute_bcc(const byte_t *buf, size_t count)
234 {
235 	byte_t bcc=0;
236 	unsigned i;
237 
238 	for (i=0; i<count; ++i)
239 		bcc ^= buf[i];
240 
241 	return bcc;
242 }
243 
244 
245 /**
246  * reverse bits in a buffer bytes from right to left
247  * @see 6. CODING AND DECODING OF REGISTER VALUES
248  * @param   buf     buffer address
249  * @param   count   no. of bytes in the buffer
250  */
reverse_bits(byte_t * buf,size_t count)251 static void reverse_bits(byte_t *buf, size_t count)
252 {
253 	byte_t x;
254 
255 	while (count!=0) {
256 		x = *buf;
257 		x = ( (x & 0x80) >> 7 )  |
258 		    ( (x & 0x40) >> 5 )  |
259 		    ( (x & 0x20) >> 3 )  |
260 		    ( (x & 0x10) >> 1 )  |
261 		    ( (x & 0x08) << 1 )  |
262 		    ( (x & 0x04) << 3 )  |
263 		    ( (x & 0x02) << 5 )  |
264 		    ( (x & 0x01) << 7 );
265 		*buf = x;
266 
267 		++buf;
268 		--count;
269 	}
270 }
271 
272 
273 /********************************************************************/
274 
275 /*
276  * communication basics
277  *
278  * ME	(Monitor Equipment)
279  * PRS	(Power Rectifier System)  /think of it as of UPS in common speak/
280  *
281  * there are 2 types of transactions:
282  *
283  * 'ACTIVATE COMMAND'
284  *	ME -> PRS		(al_prep_activate)
285  *	ME <- PRS [ack]		(al_check_ack)
286  *
287  *
288  * 'READ REGISTER'
289  *	ME -> PRS		(al_prep_read_req)
290  *	ME <- PRS [data]	(al_parse_reply)
291  *
292  */
293 
294 /********************
295  * COMLI primitives *
296  ********************/
297 
298 
299 /************************
300  * COMLI: OUTPUT FRAMES *
301  ************************/
302 
303 /**
304  * prepare COMLI sentence
305  * @see 1. INTRODUCTION
306  * @param   dest    [out] where to put the result
307  * @param   h       COMLI header info
308  * @param   buf     data part of the sentence
309  * @param   count   amount of data bytes in the sentence
310  *
311  * @note: the data are copied into the sentence "as-is", there is no conversion is done.
312  *  if the caller wants to reverse bits it is necessary to call reverse_bits(...) prior
313  *  to comli_prepare.
314  */
comli_prepare(raw_data_t * dest,const comli_head_t * h,const void * buf,size_t count)315 static void comli_prepare(raw_data_t *dest, const comli_head_t *h, const void *buf, size_t count)
316 {
317 /*
318  *    0     1   2      3       4     5     6     7     8       9    10    11 - - -     N-1    N
319  * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+
320  * | STX | IDh IDl | Stamp | type | addr1 addr2 addr3 addr4 | NOBh NOBl | ...data... | ETX | BCC |
321  * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+
322  *
323  * ^                                                                                             ^
324  * |                                                                                             |
325  *begin                                                                                         end
326  */
327 	byte_t *out = dest->begin;
328 
329 
330 	/* it's caller responsibility to allocate enough space.
331 	   else it is a bug in the program */
332 	if ( (out+11+count+2) > (dest->buf + dest->buf_size) )
333 		fatalx(EXIT_FAILURE, "too small dest in comli_prepare\n");
334 
335 	out[0] = STX;
336 	snprintf((char *)out+1, 10+1, "%02X%1i%1i%04X%02X", h->msg.id, h->msg.stamp, h->msg.type, h->io.addr, h->io.len);
337 
338 	memcpy(out+11, buf, count);
339 	reverse_bits(out+11, count);
340 
341 
342 	out[11+count] = ETX;
343 	out[12+count] = compute_bcc(out+1, 10+count+1);
344 
345 	dest->end = dest->begin + (11+count+2);
346 }
347 
348 
349 
350 
351 /**
352  * prepare AL175 read data request
353  * @see 2. MESSAGE TYPE 2 (COMMAND SENT FROM MONITORING EQUIPMENT)
354  * @param   dest    [out] where to put the result
355  * @param   addr    start address of requested area
356  * @param   count   no. of requested bytes
357  */
al_prep_read_req(raw_data_t * dest,unsigned addr,size_t count)358 static void al_prep_read_req(raw_data_t *dest, unsigned addr, size_t count)
359 {
360 	comli_head_t h;
361 
362 	h.msg.id	= 0x14;
363 	h.msg.stamp	= 1;
364 	h.msg.type	= 2;
365 
366 	h.io.addr	= addr;
367 	h.io.len	= count;
368 
369 	comli_prepare(dest, &h, NULL, 0);
370 }
371 
372 
373 /**
374  * prepare AL175 activate command
375  * @see 4. MESSAGE TYPE 0 (ACTIVATE COMMAND)
376  * @param   dest    [out] where to put the result
377  * @param   cmd     command type        [11]
378  * @param   subcmd  command subtype     [12]
379  * @param   pr1     first parameter     [13:14]
380  * @param   pr2     second parameter    [15:16]
381  * @param   pr3     third parameter     [17:18]
382  */
al_prep_activate(raw_data_t * dest,byte_t cmd,byte_t subcmd,uint16_t pr1,uint16_t pr2,uint16_t pr3)383 static void al_prep_activate(raw_data_t *dest, byte_t cmd, byte_t subcmd, uint16_t pr1, uint16_t pr2, uint16_t pr3)
384 {
385 	comli_head_t h;
386 	char data[8+1];
387 
388 	h.msg.id	= 0x14;
389 	h.msg.stamp	= 1;
390 	h.msg.type	= 0;
391 
392 	h.io.addr	= 0x4500;
393 	h.io.len	= 8;
394 
395 	/* NOTE: doc says we should use ASCII coding here, but the actual
396 	 *       values are > 0x80, so we use binary coding	*/
397 	data[0] = cmd;
398 	data[1] = subcmd;
399 
400 	snprintf(data+2, 6+1, "%2X%2X%2X", pr1, pr2, pr3);
401 
402 	comli_prepare(dest, &h, data, 8);
403 }
404 
405 /***********************
406  * COMLI: INPUT FRAMES *
407  ***********************/
408 
409 /**
410  * check COMLI frame for correct layout and bcc
411  * @param  f	frame to check
412  *
413  * @return 0 (ok)  -1 (error)
414  */
comli_check_frame(raw_data_t f)415 static int comli_check_frame(/*const*/ raw_data_t f)
416 {
417 	int bcc;
418 	byte_t *tail;
419 
420 	if (*f.begin!=STX)
421 		return -1;
422 
423 	tail = f.end - 2;
424 	if (tail <= f.begin)
425 		return -1;
426 
427 	if (tail[0]!=ETX)
428 		return -1;
429 
430 	bcc = compute_bcc(f.begin+1, (f.end - f.begin) - 2/*STX & BCC*/);
431 	if (bcc!= tail[1])
432 		return -1;
433 
434 	return 0;
435 }
436 
437 
438 /**
439  * parse reply header from PRS
440  * @see 3. MESSAGE TYPE 0 (REPLY FROM PRS ON MESSAGE TYPE 2)
441  *
442  * @param  io			[out] parsed io_header
443  * @param  raw_reply_head	[in] raw reply header from PRS
444  * @return 0 (ok),  -1 (error)
445  *
446  * @see al_parse_reply
447  */
al_parse_reply_head(io_head_t * io,const raw_data_t raw_reply_head)448 static int al_parse_reply_head(io_head_t *io, const raw_data_t raw_reply_head)
449 {
450 /*
451  *    0     1   2      3       4     5     6     7     8       9    10
452  * +-----+---------+-------+------+-------------------------+-----------+-----------+
453  * | STX | IDh IDl | Stamp | type | addr1 addr2 addr3 addr4 | NOBh NOBl | ......... |
454  * +-----+---------+-------+------+-------------------------+-----------+-----------+
455  *
456  *       ^                                                              ^
457  *       |                                                              |
458  *     begin							       end
459  */
460 
461 	unsigned long io_addr, io_len;
462 	const byte_t *reply_head = raw_reply_head.begin - 1;
463 
464 	if ( (raw_reply_head.end - raw_reply_head.begin) != 10)  {
465 		upsdebugx(3, "%s: wrong size\t(%i != 10)", __func__, (int)(raw_reply_head.end - raw_reply_head.begin));
466 		return -1;		/* wrong size	*/
467 	}
468 
469 	if (reply_head[1]!='0' || reply_head[2]!='0')  {
470 		upsdebugx(3, "%s: wrong id\t('%c%c' != '00')", __func__, reply_head[1], reply_head[2]);
471 		return -1;		/* wrong id	*/
472 	}
473 
474 	if (reply_head[3]!='1')  {
475 		upsdebugx(3, "%s: wrong stamp\t('%c' != '1')", __func__, reply_head[3]);
476 		return -1;		/* wrong stamp	*/
477 	}
478 
479 	if (reply_head[4]!='0')  {
480 		upsdebugx(3, "%s: wrong type\t('%c' != '0')", __func__, reply_head[4]);
481 		return -1;		/* wrong type	*/
482 	}
483 
484 	io_addr = from_hex(&reply_head[5], 4);
485 	if (io_addr==-1UL)  {
486 		upsdebugx(3, "%s: invalid addr\t('%c%c%c%c')", __func__, reply_head[5],reply_head[6],reply_head[7],reply_head[8]);
487 		return -1;		/* wrong addr	*/
488 	}
489 
490 	io_len = from_hex(&reply_head[9], 2);
491 	if (io_len==-1UL)   {
492 		upsdebugx(3, "%s: invalid nob\t('%c%c')", __func__, reply_head[9],reply_head[10]);
493 		return -1;		/* wrong NOB	*/
494 	}
495 
496 	if (io_len > IO_LEN_MAX) {
497 		upsdebugx(3, "nob too big\t(%lu > %i)", io_len, IO_LEN_MAX);
498 		return -1;		/* too much data claimed */
499 	}
500 
501 	io->addr = io_addr;
502 	io->len  = io_len;
503 
504 
505 	return 0;
506 }
507 
508 
509 /**
510  * parse reply from PRS
511  * @see 3. MESSAGE TYPE 0 (REPLY FROM PRS ON MESSAGE TYPE 2)
512  * @param  io_head	[out] parsed io_header
513  * @param  io_buf	[in] [out] raw_data where to place incoming data (see ...data... below)
514  * @param  raw_reply	raw reply from PRS to check
515  * @return  0 (ok), -1 (error)
516  *
517  * @see al_parse_reply_head
518  */
al_parse_reply(io_head_t * io_head,raw_data_t * io_buf,raw_data_t raw_reply)519 static int al_parse_reply(io_head_t *io_head, raw_data_t *io_buf, /*const*/ raw_data_t raw_reply)
520 {
521 /*
522  *    0     1   2      3       4     5     6     7     8       9    10    11 - - -     N-1    N
523  * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+
524  * | STX | IDh IDl | Stamp | type | addr1 addr2 addr3 addr4 | NOBh NOBl | ...data... | ETX | BCC |
525  * +-----+---------+-------+------+-------------------------+-----------+------------+-----+-----+
526  *
527  *       ^                                                                           ^
528  *       |                                                                           |
529  *     begin                                                                        end
530  */
531 
532 	int err;
533 	unsigned i;
534 	const byte_t *reply = raw_reply.begin - 1;
535 
536 	/* 1: extract header and parse it */
537 	/*const*/ raw_data_t raw_reply_head = raw_reply;
538 
539 	if (raw_reply_head.begin + 10 <= raw_reply_head.end)
540 		raw_reply_head.end = raw_reply_head.begin + 10;
541 
542 	err = al_parse_reply_head(io_head, raw_reply_head);
543 	if (err==-1)
544 		return -1;
545 
546 
547 	/* 2: process data */
548 	reply = raw_reply.begin - 1;
549 
550 	if ( (raw_reply.end - raw_reply.begin) != (ptrdiff_t)(10 + io_head->len))  {
551 		upsdebugx(3, "%s: corrupt sentence\t(%i != %i)",
552 				__func__, (int)(raw_reply.end - raw_reply.begin), 10 + io_head->len);
553 		return -1;		/* corrupt sentence	*/
554 	}
555 
556 
557 	/* extract the data */
558 	if (io_buf->buf_size < io_head->len)	{
559 		upsdebugx(3, "%s: too much data to fit in io_buf\t(%u > %u)",
560 				__func__, io_head->len, io_buf->buf_size);
561 		return -1;		/* too much data to fit in io_buf	*/
562 	}
563 
564 	io_buf->begin = io_buf->buf;
565 	io_buf->end   = io_buf->begin;
566 
567 	for (i=0; i<io_head->len; ++i)
568 		*(io_buf->end++) = reply[11+i];
569 
570 	reverse_bits(io_buf->begin, (io_buf->end - io_buf->begin) );
571 
572 	upsdebug_hex(3, "\t\t--> payload", io_buf->begin, (io_buf->end - io_buf->begin));
573 
574 	return 0;	/* all ok */
575 }
576 
577 
578 /**
579  * check acknowledge from PRS
580  * @see 5. ACKNOWLEDGE FROM PRS
581  * @param   raw_ack  raw acknowledge from PRS to check
582  * @return  0 on success, -1 on error
583  */
al_check_ack(raw_data_t raw_ack)584 static int al_check_ack(/*const*/ raw_data_t raw_ack)
585 {
586 /*
587  *    0     1   2      3       4     5     6     7
588  * +-----+---------+-------+------+-----+-----+-----+
589  * | STX | IDh IDl | Stamp | type | ACK | ETX | BCC |
590  * +-----+---------+-------+------+-----+-----+-----+
591  *
592  *       ^                              ^
593  *       |                              |
594  *     begin                           end
595  */
596 
597 	const byte_t *ack = raw_ack.begin - 1;
598 
599 	if ( (raw_ack.end - raw_ack.begin) !=5)  {
600 		upsdebugx(3, "%s: wrong size\t(%i != 5)", __func__, (int)(raw_ack.end - raw_ack.begin));
601 		return -1;		/* wrong size	*/
602 	}
603 
604 	if (ack[1]!='0' || ack[2]!='0')  {
605 		upsdebugx(3, "%s: wrong id\t('%c%c' != '00')", __func__, ack[1], ack[2]);
606 		return -1;		/* wrong id	*/
607 	}
608 
609 	/* the following in not mandated. it is just said it will be
610 	 * "same as one received". but we always send '1' (0x31) as stamp
611 	 * (see 4. MESSAGE TYPE 0 (ACTIVATE COMMAND). Hence, stamp checking
612 	 * is hardcoded here.
613 	 */
614 	if (ack[3]!='1')  {
615 		upsdebugx(3, "%s: wrong stamp\t('%c' != '1')", __func__, ack[3]);
616 		return -1;		/* wrong stamp	*/
617 	}
618 
619 	if (ack[4]!='1')  {
620 		upsdebugx(3, "%s: wrong type\t('%c' != '1')", __func__, ack[4]);
621 		return -1;		/* wrong type	*/
622 	}
623 
624 	if (ack[5]!=ACK)  {
625 		upsdebugx(3, "%s: wrong ack\t(0x%02X != 0x%02X)", __func__, ack[5], ACK);
626 		return -1;		/* wrong ack	*/
627 	}
628 
629 
630 	return 0;
631 }
632 
633 
634 
635 
636 
637 /******************************************************************/
638 
639 
640 /**********
641  * SERIAL *
642  **********/
643 
644 /* clear any flow control (copy from powercom.c) */
ser_disable_flow_control(void)645 static void ser_disable_flow_control (void)
646 {
647 	struct termios tio;
648 
649 	tcgetattr (upsfd, &tio);
650 
651 	tio.c_iflag &= ~ (IXON | IXOFF);
652 	tio.c_cc[VSTART] = _POSIX_VDISABLE;
653 	tio.c_cc[VSTOP] = _POSIX_VDISABLE;
654 
655 	upsdebugx(4, "Flow control disable");
656 
657 	/* disable any flow control */
658 	tcsetattr(upsfd, TCSANOW, &tio);
659 }
660 
flush_rx_queue()661 static void flush_rx_queue()
662 {
663 	ser_flush_in(upsfd, "", /*verbose=*/nut_debug_level);
664 }
665 
666 /**
667  * transmit frame to PRS
668  *
669  * @param  dmsg   debug message prefix
670  * @param  frame  the frame to tansmit
671  * @return 0 (ok) -1 (error)
672  */
tx(const char * dmsg,raw_data_t frame)673 static int tx(const char *dmsg, /*const*/ raw_data_t frame)
674 {
675 	int err;
676 
677 	upsdebug_ascii(3, dmsg, frame.begin, (frame.end - frame.begin));
678 
679 	err = ser_send_buf(upsfd, frame.begin, (frame.end - frame.begin) );
680 	if (err==-1) {
681 		upslogx(LOG_ERR, "failed to send frame to PRS: %s", strerror(errno));
682 		return -1;
683 	}
684 
685 	if (err != (frame.end - frame.begin)) {
686 		upslogx(LOG_ERR, "sent incomplete frame to PRS");
687 		return -1;
688 	}
689 
690 	return 0;
691 }
692 
693 /***********
694  * CHATTER *
695  ***********/
696 
697 static time_t T_io_begin;	/* start of current I/O transaction */
698 static int    T_io_timeout;	/* in seconds */
699 
700 /* start new I/O transaction with maximum time limit */
io_new_transaction(int timeout)701 static void io_new_transaction(int timeout)
702 {
703 	T_io_begin = time(NULL);
704 	T_io_timeout = timeout;
705 }
706 
707 /**
708  * get next character from input stream
709  *
710  * @param  ch   ptr-to where store result
711  *
712  * @return -1 (error)  0 (timeout)  >0 (got it)
713  *
714  */
get_char(char * ch)715 static int get_char(char *ch)
716 {
717 	time_t now = time(NULL);
718 	long rx_timeout;
719 
720 	rx_timeout = T_io_timeout - (now - T_io_begin);
721 	/* negative rx_timeout -> time already out */
722 	if (rx_timeout < 0)
723 		return 0;
724 	return ser_get_char(upsfd, ch, rx_timeout, 0);
725 }
726 
727 
728 /**
729  * get next characters from input stream
730  *
731  * @param   buf ptr-to output buffer
732  * @param   len buffer length
733  *
734  * @return -1 (error)  0 (timeout)  >0 (no. of characters actually read)
735  *
736  */
get_buf(byte_t * buf,size_t len)737 static int get_buf(byte_t *buf, size_t len)
738 {
739 	time_t now = time(NULL);
740 	long rx_timeout;
741 
742 	rx_timeout = T_io_timeout - (now - T_io_begin);
743 	/* negative rx_timeout -> time already out */
744 	if (rx_timeout < 0)
745 		return 0;
746 	return ser_get_buf_len(upsfd, buf, len, rx_timeout, 0);
747 }
748 
749 /**
750  * scan incoming bytes for specific character
751  *
752  * @return 0 (got it) -1 (error)
753  */
scan_for(char c)754 static int scan_for(char c)
755 {
756 	char in;
757 	int  err;
758 
759 	while (1) {
760 		err = get_char(&in);
761 		if (err==-1 || err==0 /*timeout*/)
762 			return -1;
763 
764 		if (in==c)
765 			break;
766 	}
767 
768 	return 0;
769 }
770 
771 
772 /**
773  * receive 'activate command' ACK from PRS
774  *
775  * @return 0 (ok) -1 (error)
776  */
recv_command_ack()777 static int recv_command_ack()
778 {
779 	int err;
780 	raw_data_t ack;
781 	byte_t     ack_buf[8];
782 
783 	/* 1:  STX  */
784 	err = scan_for(STX);
785 	if (err==-1)
786 		return -1;
787 
788 
789 	raw_alloc_onstack(&ack, ack_buf);
790 	*(ack.end++) = STX;
791 
792 
793 	/* 2:  ID1 ID2 STAMP MSG_TYPE ACK ETX BCC */
794 	err = get_buf(ack.end, 7);
795 	if (err!=7)
796 		return -1;
797 
798 	ack.end += 7;
799 
800 	/* frame constructed - let's verify it */
801 	upsdebug_ascii(3, "rx (ack):\t\t", ack.begin, (ack.end - ack.begin));
802 
803 	/* generic layout */
804 	err = comli_check_frame(ack);
805 	if (err==-1)
806 		return -1;
807 
808 	/* shrink frame */
809 	ack.begin += 1;
810 	ack.end   -= 2;
811 
812 	return al_check_ack(ack);
813 }
814 
815 /**
816  * receive 'read register' data from PRS
817  * @param  io		[out] io header of received data
818  * @param  io_buf	[in] [out] where to place incoming data
819  *
820  * @return 0 (ok) -1 (error)
821  */
recv_register_data(io_head_t * io,raw_data_t * io_buf)822 static int recv_register_data(io_head_t *io, raw_data_t *io_buf)
823 {
824 	int err, ret;
825 	raw_data_t reply_head;
826 	raw_data_t reply;
827 
828 	byte_t	   reply_head_buf[11];
829 
830 	/* 1:  STX  */
831 	err = scan_for(STX);
832 	if (err==-1)
833 		return -1;
834 
835 	raw_alloc_onstack(&reply_head, reply_head_buf);
836 	*(reply_head.end++) = STX;
837 
838 
839 	/* 2:  ID1 ID2 STAMP MSG_TYPE ADDR1 ADDR2 ADDR3 ADDR4 LEN1 LEN2 */
840 	err = get_buf(reply_head.end, 10);
841 	if (err!=10)
842 		return -1;
843 
844 	reply_head.end += 10;
845 
846 	upsdebug_ascii(3, "rx (head):\t", reply_head.begin, (reply_head.end - reply_head.begin));
847 
848 
849 	/* 3:  check header, extract IO info */
850 	reply_head.begin += 1;	/* temporarily strip STX */
851 
852 	err = al_parse_reply_head(io, reply_head);
853 	if (err==-1)
854 		return -1;
855 
856 	reply_head.begin -= 1;  /* restore STX */
857 
858 	upsdebugx(4, "\t\t--> addr: 0x%x  len: 0x%x", io->addr, io->len);
859 
860 	/* 4:  allocate space for full reply and copy header there */
861 	reply = raw_xmalloc(11/*head*/ + io->len/*data*/ + 2/*ETX BCC*/);
862 
863 	memcpy(reply.end, reply_head.begin, (reply_head.end - reply_head.begin));
864 	reply.end += (reply_head.end - reply_head.begin);
865 
866 	/* 5:  receive tail of the frame */
867 	err = get_buf(reply.end, io->len + 2);
868 	if (err!=(int)(io->len+2)) {
869 		upsdebugx(4, "rx_tail failed, err=%i (!= %i)", err, io->len+2);
870 		ret = -1; goto out;
871 	}
872 
873 	reply.end += io->len + 2;
874 
875 
876 	/* frame constructed, let's verify it */
877 	upsdebug_ascii(3, "rx (head+data):\t", reply.begin, (reply.end - reply.begin));
878 
879 	/* generic layout */
880 	err = comli_check_frame(reply);
881 	if (err==-1) {
882 		upsdebugx(3, "%s: corrupt frame", __func__);
883 		ret = -1; goto out;
884 	}
885 
886 	/* shrink frame */
887 	reply.begin += 1;
888 	reply.end   -= 2;
889 
890 
891 	/* XXX: a bit of processing duplication here	*/
892 	ret = al_parse_reply(io, io_buf, reply);
893 
894 out:
895 	raw_free(&reply);
896 	return ret;
897 }
898 
899 
900 /*****************************************************************/
901 
902 /*********************
903  * AL175: DO COMMAND *
904  *********************/
905 
906 /**
907  * do 'ACTIVATE COMMAND'
908  *
909  * @return 0 (ok)  -1 (error)
910  */
al175_do(byte_t cmd,byte_t subcmd,uint16_t pr1,uint16_t pr2,uint16_t pr3)911 static int al175_do(byte_t cmd, byte_t subcmd, uint16_t pr1, uint16_t pr2, uint16_t pr3)
912 {
913 	int err;
914 	raw_data_t CTRL_frame;
915 	byte_t	   CTRL_frame_buf[512];
916 
917 	raw_alloc_onstack(&CTRL_frame, CTRL_frame_buf);
918 	al_prep_activate(&CTRL_frame, cmd, subcmd, pr1, pr2, pr3);
919 
920 	flush_rx_queue();		        /*  DROP  */
921 
922 	err = tx("tx (ctrl):\t", CTRL_frame);	/*  TX    */
923 	if (err==-1)
924 		return -1;
925 
926 
927 	return recv_command_ack();	        /*  RX    */
928 }
929 
930 
931 /**
932  * 'READ REGISTER'
933  *
934  */
al175_read(byte_t * dst,unsigned addr,size_t count)935 static int al175_read(byte_t *dst, unsigned addr, size_t count)
936 {
937 	int err;
938 	raw_data_t REQ_frame;
939 	raw_data_t rx_data;
940 	io_head_t io;
941 
942 	byte_t	REQ_frame_buf[512];
943 
944 	raw_alloc_onstack(&REQ_frame, REQ_frame_buf);
945 	al_prep_read_req(&REQ_frame, addr, count);
946 
947 	flush_rx_queue();			/*  DROP  */
948 
949 	err = tx("tx (req):\t", REQ_frame);	/*  TX    */
950 	if (err==-1)
951 		return -1;
952 
953 
954 	rx_data.buf	 = dst;
955 	rx_data.buf_size = count;
956 	rx_data.begin	 = dst;
957 	rx_data.end	 = dst;
958 
959 	err = recv_register_data(&io, &rx_data);
960 	if (err==-1)
961 		return -1;
962 
963 	if ((rx_data.end - rx_data.begin) != (int)count)
964 		return -1;
965 
966 	if ( (io.addr != addr) || (io.len != count) ) {
967 		upsdebugx(3, "%s: io_head mismatch\t(%x,%x != %x,%x)",
968 				__func__, io.addr, io.len, addr,
969 				(unsigned int)count);
970 		return -1;
971 	}
972 
973 
974 	return 0;
975 }
976 
977 /*************
978  * NUT STUFF *
979  *************/
980 
981 /****************************
982  * ACTIVATE COMMANDS table
983  *
984  * see 8. ACTIVATE COMMANDS
985  */
986 
987 typedef int mm_t;	/* minutes */
988 typedef int VV_t;	/* voltage */
989 
990 #define	Z1  , 0
991 #define Z2  , 0, 0
992 #define	Z3  , 0, 0, 0
993 
994 #define	ACT int
995 
TOGGLE_PRS_ONOFF()996 ACT	TOGGLE_PRS_ONOFF	()		{ return al175_do(0x81, 0x80			Z3);	}
CANCEL_BOOST()997 ACT	CANCEL_BOOST		()		{ return al175_do(0x82, 0x80			Z3);	}
STOP_BATTERY_TEST()998 ACT	STOP_BATTERY_TEST	()		{ return al175_do(0x83, 0x80			Z3);	}
START_BATTERY_TEST(VV_t EndVolt,unsigned Minutes)999 ACT	START_BATTERY_TEST	(VV_t EndVolt, unsigned Minutes)
1000 						{ return al175_do(0x83, 0x81, EndVolt, Minutes	Z1);	}
1001 
SET_FLOAT_VOLTAGE(VV_t v)1002 ACT	SET_FLOAT_VOLTAGE	(VV_t v)	{ return al175_do(0x87, 0x80, v			Z2);	}
SET_BOOST_VOLTAGE(VV_t v)1003 ACT	SET_BOOST_VOLTAGE	(VV_t v)	{ return al175_do(0x87, 0x81, v			Z2);	}
SET_HIGH_BATTERY_LIMIT(VV_t Vhigh)1004 ACT	SET_HIGH_BATTERY_LIMIT	(VV_t Vhigh)	{ return al175_do(0x87, 0x82, Vhigh		Z2);	}
SET_LOW_BATTERY_LIMIT(VV_t Vlow)1005 ACT	SET_LOW_BATTERY_LIMIT	(VV_t Vlow)	{ return al175_do(0x87, 0x83, Vlow		Z2);	}
1006 
SET_DISCONNECT_LEVEL_AND_DELAY(VV_t level,mm_t delay)1007 ACT	SET_DISCONNECT_LEVEL_AND_DELAY
1008 				(VV_t level, mm_t delay)
1009 						{ return al175_do(0x87, 0x84, level, delay	Z1);	}
1010 
RESET_ALARMS()1011 ACT	RESET_ALARMS		()		{ return al175_do(0x88, 0x80			Z3);	}
CHANGE_COMM_PROTOCOL()1012 ACT	CHANGE_COMM_PROTOCOL	()		{ return al175_do(0x89, 0x80			Z3);	}
SET_VOLTAGE_AT_ZERO_T(VV_t v)1013 ACT	SET_VOLTAGE_AT_ZERO_T	(VV_t v)	{ return al175_do(0x8a, 0x80, v			Z2);	}
SET_SLOPE_AT_ZERO_T(VV_t mv_per_degree)1014 ACT	SET_SLOPE_AT_ZERO_T	(VV_t mv_per_degree)
1015 						{ return al175_do(0x8a, 0x81, mv_per_degree	Z2);	}
1016 
SET_MAX_TCOMP_VOLTAGE(VV_t v)1017 ACT	SET_MAX_TCOMP_VOLTAGE	(VV_t v)	{ return al175_do(0x8a, 0x82, v			Z2);	}
SET_MIN_TCOMP_VOLTAGE(VV_t v)1018 ACT	SET_MIN_TCOMP_VOLTAGE	(VV_t v)	{ return al175_do(0x8a, 0x83, v			Z2);	}
SWITCH_TEMP_COMP(int on)1019 ACT	SWITCH_TEMP_COMP	(int on)	{ return al175_do(0x8b, 0x80, on		Z2);	}
1020 
SWITCH_SYM_ALARM()1021 ACT	SWITCH_SYM_ALARM	()		{ return al175_do(0x8c, 0x80			Z3);	}
1022 
1023 
1024 /**
1025  * extract double value from a word
1026  */
d16(byte_t data[2])1027 static double d16(byte_t data[2])
1028 {
1029 	return (data[1] + 0x100*data[0]) / 100.0;
1030 }
1031 
upsdrv_updateinfo(void)1032 void upsdrv_updateinfo(void)
1033 {
1034 	/* int flags; */
1035 
1036 	byte_t x4000[9];		/* registers from 0x4000 to 0x4040 inclusive */
1037 	byte_t x4048[2];		/* 0x4048 - 0x4050	*/
1038 	byte_t x4100[8];		/* 0x4100 - 0x4138	*/
1039 	byte_t x4180[8];		/* 0x4180 - 0x41b8	*/
1040 	byte_t x4300[2];		/* 0x4300 - 0x4308	*/
1041 	int err;
1042 
1043 	double batt_current = 0.0;
1044 
1045 
1046 	upsdebugx(4, " ");
1047 	upsdebugx(4, "UPDATEINFO");
1048 	upsdebugx(4, "----------");
1049 	io_new_transaction(/*timeout=*/3);
1050 
1051 #define	RECV(reg) do { \
1052 	err = al175_read(x ## reg, 0x ## reg, sizeof(x ## reg));	\
1053 	if (err==-1) {							\
1054 		dstate_datastale();					\
1055 		return;							\
1056 	}								\
1057 } while (0)
1058 
1059 	RECV(4000);
1060 	RECV(4048);
1061 	RECV(4100);
1062 	RECV(4180);
1063 	RECV(4300);
1064 
1065 
1066 	status_init();
1067 
1068 	/* XXX non conformant with NUT naming & not well understood what they mean */
1069 #if 0
1070 				/* 0x4000   DIGITAL INPUT 1-8	*/
1071 	dstate_setinfo("load.fuse",		(x4000[0] & 0x80) ? "OK" : "BLOWN");
1072 	dstate_setinfo("battery.fuse",		(x4000[0] & 0x40) ? "OK" : "BLOWN");
1073 	dstate_setinfo("symalarm.fuse",		(x4000[0] & 0x20) ? "OK" : "BLOWN");
1074 
1075 				/* 0x4008   BATTERY INFORMATION	*/
1076 	dstate_setinfo("battery.contactor",	(x4000[1] & 0x80) ? "XX" : "YY");	/* FIXME */
1077 	dstate_setinfo("load.contactor",	(x4000[1] & 0x40) ? "XX" : "YY");	/* FIXME */
1078 	dstate_setinfo("lvd.contactor",		(x4000[1] & 0x20) ? "XX" : "YY");	/* FIXME */
1079 #endif
1080 	if (x4000[0] & 0x40){
1081 		dstate_setinfo("battery.fuse",	"FAIL");
1082 		status_set("RB");
1083 	}else{
1084 		dstate_setinfo("battery.fuse",	"OK");
1085 	}
1086 
1087 	if (x4000[0] & 0x20){
1088 		dstate_setinfo("battery.symmetry",	"FAIL");
1089 		status_set("RB");
1090 	}else{
1091 		dstate_setinfo("battery.symmetry",	"OK");
1092 	}
1093 
1094 	if (x4000[1] & 0x01)	/* battery test running	*/
1095 		status_set("TEST");
1096 
1097 	/* TODO: others from 0x4008 */
1098 
1099 				/* 0x4010   NOT USED	*/
1100 				/* 0x4018   NOT USED	*/
1101 
1102 	switch (x4000[4]) {	/* 0x4020   MAINS VOLTAGE STATUS	*/
1103 		case 0:     status_set("OL");   break;
1104 		case 1:     status_set("OB");   break;
1105 
1106 		case 2:     /* doc: "not applicable" */
1107 		default:
1108 			upsdebugx(2, "%s: invalid mains voltage status\t(%i)", __func__, x4000[4]);
1109 	}
1110 
1111 				/* 0x4028   SYSTEM ON OFF STATUS	*/
1112 	switch (x4000[5]) {
1113 		case 0: /* system on */     break;
1114 		case 1:	status_set("OFF");  break;
1115 
1116 		default:
1117 			upsdebugx(2, "%s: invalid system on/off status\t(%i)", __func__, x4000[5]);
1118 	}
1119 
1120 	switch (x4000[6]) {	/* 0x4030   BATTERY TEST FAIL	*/
1121 		case 0:     dstate_setinfo("ups.test.result", "OK");
1122 			break;
1123 
1124 		case 1:     status_set("RB");
1125 			dstate_setinfo("ups.test.result", "FAIL");
1126 			break;
1127 
1128 		default:
1129 			upsdebugx(2, "%s: invalid battery test fail\t(%i)", __func__, x4000[6]);
1130 	}
1131 	switch (x4000[7]) {	/* 0x4038   BATTERY VOLTAGE STATUS	*/
1132 		case 0:     /* normal */	break;
1133 		case 1:     status_set("LB");	break;
1134 		case 2:     status_set("HB");   break;
1135 
1136 		default:
1137 			upsdebugx(2, "%s: invalid battery voltage status\t(%i)", __func__, x4000[7]);
1138 	}
1139 	switch (x4000[8]) {	/* 0x4040   POS./NEG. BATT. CURRENT	*/
1140 		case 0:	batt_current = +1.0;	break;	/* positive	*/
1141 		case 1:	batt_current = -1.0;	break;	/* negative	*/
1142 
1143 		default:
1144 			upsdebugx(2, "%s: invalid pos/neg battery current\t(%i)", __func__, x4000[8]);
1145 	}
1146 
1147 	switch (x4048[0]) {	/* 0x4048   BOOST STATUS	*/
1148 		case 0:	/* no boost */;		break;
1149 		case 1:	status_set("BOOST");	break;
1150 
1151 		default:
1152 			upsdebugx(2, "%s: invalid boost status\t(%i)", __func__, x4048[0]);
1153 	}
1154 
1155 	{
1156 		const char *v=NULL;
1157 
1158 		switch (x4048[1]) {	/* 0x4050   SYSTEM VOLTAGE STAT.	*/
1159 			case 0:	v = "48";	break;
1160 			case 1: v = "24";	break;
1161 			case 2: v = "12";	break;
1162 			case 3: v = "26";	break;
1163 			case 4: v = "60";	break;
1164 
1165 			default:
1166 				upsdebugx(2, "%s: invalid system voltage status\t(%i)", __func__, x4048[1]);
1167 		}
1168 
1169 		if (v)
1170 			dstate_setinfo("output.voltage.nominal",    "%s", v);
1171 	}
1172 
1173 
1174 				/* 0x4100   BATTERY VOLTAGE REF	*/
1175 	dstate_setinfo("battery.voltage.nominal",	"%.2f", d16(x4100+0));
1176 
1177 				/* 0x4110   BOOST VOLTAGE REF	*/
1178 	dstate_setinfo("input.transfer.boost.low",	"%.2f", d16(x4100+2));	/* XXX: boost.high ?	*/
1179 
1180 				/* 0x4120   HIGH BATT VOLT REF		XXX	*/
1181 				/* 0x4130   LOW  BATT VOLT REF		XXX	*/
1182 
1183 				/* 0x4180   FLOAT VOLTAGE		XXX	*/
1184 				/* 0x4190   BATT CURRENT			*/
1185 	batt_current *= d16(x4180+2);
1186 	dstate_setinfo("battery.current",		"%.2f", batt_current);
1187 
1188 				/* 0x41b0   LOAD CURRENT (output.current in NUT)	*/
1189 	dstate_setinfo("output.current",		"%.2f", d16(x4180+6));
1190 
1191 				/* 0x4300   BATTERY TEMPERATURE	*/
1192 	dstate_setinfo("battery.temperature",		"%.2f", d16(x4300+0));
1193 
1194 
1195 	status_commit();
1196 
1197 	upsdebugx(1, "STATUS: %s", dstate_getinfo("ups.status"));
1198 	dstate_dataok();
1199 
1200 
1201 	/* out: */
1202 	return;
1203 
1204 }
1205 
upsdrv_shutdown(void)1206 void upsdrv_shutdown(void)
1207 {
1208 	/* TODO use TOGGLE_PRS_ONOFF for shutdown */
1209 
1210 	/* tell the UPS to shut down, then return - DO NOT SLEEP HERE */
1211 
1212 	/* maybe try to detect the UPS here, but try a shutdown even if
1213 	   it doesn't respond at first if possible */
1214 
1215 	/* replace with a proper shutdown function */
1216 	fatalx(EXIT_FAILURE, "shutdown not supported");
1217 
1218 	/* you may have to check the line status since the commands
1219 	   for toggling power are frequently different for OL vs. OB */
1220 
1221 	/* OL: this must power cycle the load if possible */
1222 
1223 	/* OB: the load must remain off until the power returns */
1224 }
1225 
1226 
instcmd(const char * cmdname,const char * extra)1227 static int instcmd(const char *cmdname, const char *extra)
1228 {
1229 	int err;
1230 
1231 	upsdebugx(1, "INSTCMD: %s", cmdname);
1232 
1233 	io_new_transaction(/*timeout=*/5);
1234 
1235 	/*
1236 	 * test.battery.start
1237 	 * test.battery.stop
1238 	 */
1239 
1240 	if (!strcasecmp(cmdname, "test.battery.start")) {
1241 		err = START_BATTERY_TEST(24, 1);
1242 		return (!err ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_FAILED);
1243 	}
1244 
1245 	if (!strcasecmp(cmdname, "test.battery.stop")) {
1246 		err = STOP_BATTERY_TEST();
1247 		return (!err ? STAT_INSTCMD_HANDLED : STAT_INSTCMD_FAILED);
1248 	}
1249 
1250 	upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
1251 	return STAT_INSTCMD_UNKNOWN;
1252 }
1253 
1254 /* no help */
upsdrv_help(void)1255 void upsdrv_help(void)
1256 {
1257 }
1258 
1259 /* no -x flags */
upsdrv_makevartable(void)1260 void upsdrv_makevartable(void)
1261 {
1262 }
1263 
upsdrv_initups(void)1264 void upsdrv_initups(void)
1265 {
1266 	upsfd = ser_open(device_path);
1267 	ser_set_speed(upsfd, device_path, B9600);
1268 
1269 	ser_disable_flow_control();
1270 }
1271 
upsdrv_cleanup(void)1272 void upsdrv_cleanup(void)
1273 {
1274 	ser_close(upsfd, device_path);
1275 }
1276 
1277 
upsdrv_initinfo(void)1278 void upsdrv_initinfo(void)
1279 {
1280 	/* TODO issue short io with UPS to detect it's presence */
1281 	/* try to detect the UPS here - call fatal_with_errno(EXIT_FAILURE, ) if it fails */
1282 
1283 	dstate_setinfo("ups.mfr", "Eltek");
1284 	dstate_setinfo("ups.model", "AL175");
1285 	/* ... */
1286 
1287 	/* instant commands */
1288 	dstate_addcmd ("test.battery.start");
1289 	dstate_addcmd ("test.battery.stop");
1290 	/* TODO rest instcmd(s) */
1291 
1292 	upsh.instcmd = instcmd;
1293 }
1294