Imported Upstream version 2.7.4

This commit is contained in:
Laurent Bigonville 2016-07-18 02:11:41 +02:00
parent fd413a3168
commit c9cb2187ee
290 changed files with 7473 additions and 2607 deletions

View file

@ -33,7 +33,7 @@
*
*/
#define DRIVER_VERSION "0.17"
#define DRIVER_VERSION "0.28"
#include "main.h"
@ -475,6 +475,75 @@ static int cypress_command(const char *cmd, char *buf, size_t buflen)
return i;
}
/* SGS communication subdriver */
static int sgs_command(const char *cmd, char *buf, size_t buflen)
{
char tmp[SMALLBUF];
int ret;
size_t cmdlen, i;
/* Send command */
cmdlen = strlen(cmd);
for (i = 0; i < cmdlen; i += ret) {
memset(tmp, 0, sizeof(tmp));
ret = (cmdlen - i) < 7 ? (cmdlen - i) : 7;
tmp[0] = ret;
memcpy(&tmp[1], &cmd[i], ret);
/* Write data in 8-byte chunks */
ret = usb_control_msg(udev, USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0x09, 0x200, 0, tmp, 8, 5000);
if (ret <= 0) {
upsdebugx(3, "send: %s (%d)", ret ? usb_strerror() : "timeout", ret);
return ret;
}
ret--;
}
upsdebugx(3, "send: %.*s", (int)strcspn(cmd, "\r"), cmd);
/* Read reply */
memset(buf, 0, buflen);
for (i = 0; i <= buflen - 8; i += ret) {
memset(tmp, 0, sizeof(tmp));
/* Read data in 8-byte chunks */
ret = usb_interrupt_read(udev, 0x81, tmp, 8, 1000);
/* No error!!! */
if (ret == -110)
break;
/* Any errors here mean that we are unable to read a reply (which will happen after successfully writing a command to the UPS) */
if (ret <= 0) {
upsdebugx(3, "read: %s (%d)", ret ? usb_strerror() : "timeout", ret);
return ret;
}
/* Every call to read returns 8 bytes
* -> actually returned bytes: */
ret = tmp[0] <= 7 ? tmp[0] : 7;
if (ret > 0)
memcpy(&buf[i], &tmp[1], ret);
snprintf(tmp, sizeof(tmp), "read [% 3d]", (int)i);
upsdebug_hex(5, tmp, &buf[i], ret);
}
upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf);
return i;
}
/* Phoenix communication subdriver */
static int phoenix_command(const char *cmd, char *buf, size_t buflen)
{
@ -693,7 +762,10 @@ static int krauler_command(const char *cmd, char *buf, size_t buflen)
}
/* "UPS No Ack" has a special meaning */
if (!strcasecmp(buf, "UPS No Ack")) {
if (
strcspn(buf, "\r") == 10 &&
!strncasecmp(buf, "UPS No Ack", 10)
) {
upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf);
continue;
}
@ -799,9 +871,14 @@ static int fabula_command(const char *cmd, char *buf, size_t buflen)
upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf);
/* The UPS always replies "UPS No Ack" when a supported command is issued (either if it fails or if it succeeds).. */
if (!strcasecmp(buf, "UPS No Ack"))
/* ..because of that, always return 0 (as if it was a timeout): queries will see it as a failure, instant commands ('megatec' protocol) as a success */
if (
strcspn(buf, "\r") == 10 &&
!strncasecmp(buf, "UPS No Ack", 10)
) {
/* ..because of that, always return 0 (with buf empty, as if it was a timeout): queries will see it as a failure, instant commands ('megatec' protocol) as a success */
memset(buf, 0, buflen);
return 0;
}
return ret;
}
@ -936,6 +1013,12 @@ static void *cypress_subdriver(USBDevice_t *device)
return NULL;
}
static void *sgs_subdriver(USBDevice_t *device)
{
subdriver_command = &sgs_command;
return NULL;
}
static void *ippon_subdriver(USBDevice_t *device)
{
subdriver_command = &ippon_command;
@ -988,6 +1071,7 @@ static qx_usb_device_id_t qx_usb_id[] = {
{ USB_DEVICE(0x06da, 0x0601), NULL, NULL, &phoenix_subdriver }, /* Online Zinto A */
{ USB_DEVICE(0x0f03, 0x0001), NULL, NULL, &cypress_subdriver }, /* Unitek Alpha 1200Sx */
{ USB_DEVICE(0x14f0, 0x00c9), NULL, NULL, &phoenix_subdriver }, /* GE EP series */
{ USB_DEVICE(0x0483, 0x0035), NULL, NULL, &sgs_subdriver }, /* TS Shara UPSes */
{ USB_DEVICE(0x0001, 0x0000), "MEC", "MEC0003", &fabula_subdriver }, /* Fideltronik/MEC LUPUS 500 USB */
{ USB_DEVICE(0x0001, 0x0000), "ATCL FOR UPS", "ATCL FOR UPS", &fuji_subdriver }, /* Fuji UPSes */
{ USB_DEVICE(0x0001, 0x0000), NULL, NULL, &krauler_subdriver }, /* Krauler UP-M500VA */
@ -1056,7 +1140,7 @@ static USBDeviceMatcher_t device_matcher = {
/* == Driver functions implementations == */
/* Process instant command and take action. */
/* See header file for details. */
int instcmd(const char *cmdname, const char *extradata)
{
item_t *item;
@ -1136,7 +1220,7 @@ int instcmd(const char *cmdname, const char *extradata)
return STAT_INSTCMD_INVALID;
}
/* If extradata is empty, use the default value from the QX to NUT table */
/* If extradata is empty, use the default value from the QX to NUT table, if any */
extradata = extradata ? extradata : item->dfl;
snprintf(value, sizeof(value), "%s", extradata ? extradata : "");
@ -1180,7 +1264,7 @@ int instcmd(const char *cmdname, const char *extradata)
return STAT_INSTCMD_HANDLED;
}
/* Set r/w variable to a value. */
/* See header file for details. */
int setvar(const char *varname, const char *val)
{
item_t *item;
@ -1840,6 +1924,7 @@ void upsdrv_initups(void)
{ "krauler", &krauler_command },
{ "fabula", &fabula_command },
{ "fuji", &fuji_command },
{ "sgs", &sgs_command },
{ NULL }
};
@ -2168,7 +2253,7 @@ static int qx_command(const char *cmd, char *buf, size_t buflen)
#endif /* TESTING */
}
/* Update ups_status to remember this status item.
/* See header file for details.
* Interpretation is done in ups_status_set(). */
void update_status(const char *value)
{
@ -2600,9 +2685,7 @@ static void ups_status_set(void)
}
}
/* Find element definition in qx2nut array by NUT varname optionally filtered by its qxflags:
* - '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
* - '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 */
/* See header file for details. */
item_t *find_nut_info(const char *varname, const unsigned long flag, const unsigned long noflag)
{
item_t *item;
@ -2647,6 +2730,12 @@ static int qx_process_answer(item_t *item, const int len)
return -1;
}
/* Check boundaries */
if (item->to && item->to < item->from) {
upsdebugx(1, "%s: in %s, starting char's position (%d) follows ending char's one (%d)", __func__, item->info_type, item->from, item->to);
return -1;
}
/* Get value */
if (strlen(item->answer)) {
snprintf(item->value, sizeof(item->value), "%.*s", item->to ? 1 + item->to - item->from : (int)strcspn(item->answer, "\r") - item->from, item->answer + item->from);
@ -2657,23 +2746,39 @@ static int qx_process_answer(item_t *item, const int len)
return 0;
}
/* Send the command to the UPS and process the reply.
* Return -1 on errors, 0 on success */
/* See header file for details. */
int qx_process(item_t *item, const char *command)
{
char buf[SMALLBUF] = "";
char buf[sizeof(item->answer) - 1] = "",
cmd[command ? (strlen(command) >= SMALLBUF ? strlen(command) + 1 : SMALLBUF) : (item->command && strlen(item->command) >= SMALLBUF ? strlen(item->command) + 1 : SMALLBUF)];
int len;
/* Prepare the command to be used */
memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd), "%s", command ? command : item->command);
/* Preprocess the command */
if (
item->preprocess_command != NULL &&
item->preprocess_command(item, cmd, sizeof(cmd)) == -1
) {
upsdebugx(4, "%s: failed to preprocess command [%s]", __func__, item->info_type);
return -1;
}
/* Send the command */
int len = qx_command(command ? command : item->command, buf, sizeof(buf));
len = qx_command(cmd, buf, sizeof(buf));
memset(item->answer, 0, sizeof(item->answer));
memcpy(item->answer, buf, sizeof(item->answer) <= sizeof(buf) ? sizeof(item->answer) - 1 : sizeof(buf));
memcpy(item->answer, buf, sizeof(buf));
/* Preprocess the answer */
if (item->preprocess_answer != NULL) {
len = item->preprocess_answer(item, len);
if (len == -1) {
upsdebugx(4, "%s: failed to preprocess answer [%s]", __func__, item->info_type);
/* Clear answer, preventing it from being reused by next items with same command */
memset(item->answer, 0, sizeof(item->answer));
return -1;
}
}
@ -2682,10 +2787,7 @@ int qx_process(item_t *item, const char *command)
return qx_process_answer(item, len);
}
/* Process the value we got back (set status bits and set the value of other parameters) and execute:
* - item-specific preprocessing, if any, otherwise
* - the standard preprocessing (including trimming if QX_FLAG_TRIM is set).
* Return -1 on failure, 0 for a status update and 1 in all other cases */
/* See header file for details. */
int ups_infoval_set(item_t *item)
{
char value[SMALLBUF] = "";
@ -2719,7 +2821,7 @@ int ups_infoval_set(item_t *item)
/* Cover most of the cases: either left/right filled with hashes, spaces or a mix of both */
if (item->qxflags & QX_FLAG_TRIM)
rtrim_m(ltrim_m(value, "# "), "# ");
str_trim_m(value, "# ");
if (strcasecmp(item->dfl, "%s")) {
@ -2754,7 +2856,7 @@ int ups_infoval_set(item_t *item)
return 1;
}
/* Return actual status */
/* See header file for details. */
int qx_status(void)
{
return ups_status;