--- drivers/belkin.c.2571 2010-10-15 14:35:04.000000000 +0000 +++ drivers/belkin.c 2010-12-06 15:06:58.000000000 +0000 @@ -21,6 +21,11 @@ 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 + + Author : Marcus Müller + Created On : + Last Modified By : John Bayly + Last Modified On : Monday December 06, 2010, 15:05 GMT */ #include "main.h" @@ -28,7 +33,7 @@ #include "belkin.h" #define DRIVER_NAME "Belkin Smart protocol driver" -#define DRIVER_VERSION "0.23" +#define DRIVER_VERSION "0.24" /* driver description structure */ upsdrv_info_t upsdrv_info = { @@ -39,8 +44,13 @@ { NULL } }; +/** the number of replies that have been missed */ +static int retry = 0; + static void send_belkin_command(char cmd, const char *subcmd, const char *data) { + upsdebugx(6, "Send Command: %s, %s", subcmd, data); + ser_flush_io(upsfd); ser_send(upsfd, "~00%c%03d%s%s", cmd, (int)strlen(data) + 3, subcmd, data); } @@ -96,53 +106,76 @@ return NULL; } -static int do_status(void) +static char *get_status() { char temp[SMALLBUF], st[SMALLBUF]; int res; + const char *status = NULL; send_belkin_command(STATUS,STAT_STATUS,""); res = get_belkin_reply(temp); - if (res == -1) { - dstate_datastale(); - return 0; - } - - status_init(); - + if (res < 1) + return NULL; + get_belkin_field(temp, st, sizeof(st), 6); if (*st == '1') { - status_set("OFF"); - - } else { /* (OFF) and (OB | OL) are mutually exclusive */ + status = "OFF"; + } else if (*st == '0') { /* (OFF) and (OB | OL) are mutually exclusive */ get_belkin_field(temp, st, sizeof(st), 2); if (*st == '1') { - status_set("OB"); + status = "OB"; /* on battery */ send_belkin_command(STATUS,STAT_BATTERY,""); res = get_belkin_reply(temp); - if (res == -1) { - dstate_datastale(); - return 0; + if (res < 1) { /* no battery info, so no reliable status */ + status = NULL; + + } else { + get_belkin_field(temp, st, sizeof(st), 10); + res = atoi(st); + get_belkin_field(temp, st, sizeof(st), 2); + + if (*st == '1' || res < LOW_BAT) + status = "LB"; /* low battery */ } - get_belkin_field(temp, st, sizeof(st), 10); - res = atoi(st); - get_belkin_field(temp, st, sizeof(st), 2); + } else if (*st == '0') { + status = "OL"; /* on line */ - if (*st == '1' || res < LOW_BAT) - status_set("LB"); /* low battery */ } - else - status_set("OL"); /* on line */ } - status_commit(); - dstate_dataok(); + return status; +} - return 1; +static int do_status(void) +{ + /* fetch the UPS status, or null if unavailable */ + const char *status = get_status(); + + if (status) { + if (retry) /* previous attempt had failed */ + upslogx(LOG_WARNING, "Communications with UPS re-established"); + + status_init(); + status_set(status); + status_commit(); + dstate_dataok(); + retry = 0; + return 1; + + } else { + if (retry < MAXTRIES) { + upslogx(LOG_WARNING, "Communications with UPS lost: status read failed!"); + retry++; + + } else { /* too many retries */ + dstate_datastale(); + } + return 0; + } } static int do_broken_rat(char *buf) @@ -326,6 +359,14 @@ break; } + + send_belkin_command(STATUS,STAT_STATUS, ""); + res = get_belkin_reply(temp); + if (res == -1) + return; + + get_belkin_field(temp, st, sizeof(st), 16); + dstate_setinfo("ups.beeper.status", "%s", (*st == '0' ? "disabled" : "enabled")); } static int get_belkin_reply(char *buf) @@ -335,7 +376,7 @@ usleep(25000); - /* pull first 7 bytes to get data length - like ~00S004 */ + /* pull first 7 bytes to get data length - like ~00D004 */ ret = ser_get_buf_len(upsfd, (unsigned char *)tmp, 7, 3, 0); if (ret != 7) { @@ -345,8 +386,13 @@ tmp[7] = 0; cnt = atoi(tmp + 4); + upsdebugx(6, "Received: %s", tmp); - if ((cnt < 1) || (cnt > 255)) + if (cnt == 0) { /* possible to have ~00R000, return empty response */ + buf[0] = 0; + return 0; + + } else if ((cnt < 1) || (cnt > 255)) return -1; /* give it time to respond to us */ @@ -355,6 +401,7 @@ ret = ser_get_buf_len(upsfd, (unsigned char *)buf, cnt, 3, 0); buf[cnt] = 0; + upsdebugx(6, "Received: %s", buf); if (ret != cnt) { ser_comm_fail("Second read returned %d bytes, expected %d",