Imported Upstream version 2.7.4
This commit is contained in:
parent
fd413a3168
commit
c9cb2187ee
290 changed files with 7473 additions and 2607 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue