Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #439 Incorrect Output Voltage on CPS*EFPCLCD #1245

Merged
merged 17 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/apc-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,4 +507,5 @@ subdriver_t apc_subdriver = {
apc_format_model,
apc_format_mfr,
apc_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/arduino-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,5 @@ subdriver_t arduino_subdriver = {
arduino_format_model,
arduino_format_mfr,
arduino_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/belkin-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -641,4 +641,5 @@ subdriver_t belkin_subdriver = {
belkin_format_model,
belkin_format_mfr,
belkin_format_serial,
fix_report_desc,
};
74 changes: 74 additions & 0 deletions drivers/cps-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,79 @@ static int cps_claim(HIDDevice_t *hd) {
}
}

/* CPS Models like CP900EPFCLCD return a syntactically legal but incorrect
* Report Descriptor whereby the Input High Transfer Max/Min values are used
* for the Output Voltage Usage Item limits. This corrects them by finding and
* applying the Input Voltage limits as being more appropriate.
*/

HIDData_t *FindReport(HIDDesc_t *pDesc, uint8_t ReportID, HIDNode_t node)
{
size_t i;

for (i = 0; i < pDesc->nitems; i++) {
HIDData_t *pData = &pDesc->item[i];

if (pData->ReportID != ReportID) {
continue;
}

HIDPath_t * pPath = &pData->Path;
uint8_t size = pPath->Size;
if (size == 0 || pPath->Node[size-1] != node) {
continue;
}

return pData;
}

return NULL;
}

static int cps_fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc) {
HIDData_t *pData;

int vendorID = pDev->VendorID;
int productID = pDev->ProductID;
if (vendorID != CPS_VENDORID || productID != 0x0501) {
return 0;
}

upsdebugx(3, "Attempting Report Descriptor fix for UPS: Vendor:%04x, Product:%04x", vendorID, productID);

/* Apply the fix cautiously by looking for input voltage, high voltage transfer and output voltage report usages.
* If the output voltage log min/max equals high voltage transfer log min/max then the bug is present.
* To fix it copy the input voltage log min/max settings as reasonable values for the output voltage limits.
*/

if ((pData=FindReport(pDesc, 15, (PAGE_POWER_DEVICE<<16)+USAGE_VOLTAGE))) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I my opinion we should skip report 15 (0xe) and change output voltage:

  • LogMin to 0
  • LogMax leave as it is or even increase it (current value 270)

According to the specification for EU version of the UPS "Input Voltage Range" is "170 ~ 270".
which means that the input voltage up to 270 V can be accepted, before system will switch to a battery.
If UPS will switch to battery I'm not sure if it will report input voltage higher than 270V, I don't have equipment to verify it.

long input_logmin = pData->LogMin;
long input_logmax = pData->LogMax;
upsdebugx(4, "Fix Report Descriptor: input LogMin:%ld LogMax:%ld", input_logmin, input_logmax);

if ((pData=FindReport(pDesc, 16, (PAGE_POWER_DEVICE<<16)+USAGE_HIGHVOLTAGETRANSFER))) {
long hvt_logmin = pData->LogMin;
long hvt_logmax = pData->LogMax;
upsdebugx(4, "Fix Report Descriptor:hvt input LogMin:%ld LogMax:%ld", hvt_logmin, hvt_logmax);

if ((pData=FindReport(pDesc, 18, (PAGE_POWER_DEVICE<<16)+USAGE_VOLTAGE))) {
long output_logmin = pData->LogMin;
long output_logmax = pData->LogMax;
upsdebugx(4, "Fix Report Descriptor: output LogMin:%ld LogMax:%ld", output_logmin, output_logmax);

if (hvt_logmin == output_logmin && hvt_logmax == output_logmax) {
pData->LogMin = input_logmin;
pData->LogMax = input_logmax;
upsdebugx(3, "Fixing Report Descriptor. Set Output Voltage LogMin = %ld, LogMax = %ld",
input_logmin, input_logmax);
return 1;
}
}
}
}
return 0;
}

subdriver_t cps_subdriver = {
CPS_HID_VERSION,
cps_claim,
Expand All @@ -270,4 +343,5 @@ subdriver_t cps_subdriver = {
cps_format_model,
cps_format_mfr,
cps_format_serial,
cps_fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/delta_ups-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,5 @@ subdriver_t delta_ups_subdriver = {
delta_ups_format_model,
delta_ups_format_mfr,
delta_ups_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/explore-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,5 @@ subdriver_t explore_subdriver = {
explore_format_model,
explore_format_mfr,
explore_format_serial,
fix_report_desc,
};
6 changes: 6 additions & 0 deletions drivers/hidtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ extern "C" {
#define ATTR_DATA_CST 0x01
#define ATTR_NVOL_VOL 0x80

/* Usage Pages */
#define PAGE_POWER_DEVICE 0x84

/* Usages */
#define USAGE_HIGHVOLTAGETRANSFER 0x54
#define USAGE_VOLTAGE 0x30
/*
* HIDNode_t struct
*
Expand Down
1 change: 1 addition & 0 deletions drivers/idowell-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,5 @@ subdriver_t idowell_subdriver = {
idowell_format_model,
idowell_format_mfr,
idowell_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/liebert-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,5 @@ subdriver_t liebert_subdriver = {
liebert_format_model,
liebert_format_mfr,
liebert_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/mge-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1591,4 +1591,5 @@ subdriver_t mge_subdriver = {
mge_format_model,
mge_format_mfr,
mge_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/openups-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,4 +393,5 @@ subdriver_t openups_subdriver = {
openups_format_model,
openups_format_mfr,
openups_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/powercom-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,4 +550,5 @@ subdriver_t powercom_subdriver = {
powercom_format_model,
powercom_format_mfr,
powercom_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/powervar-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,5 @@ subdriver_t powervar_subdriver = {
powervar_format_model,
powervar_format_mfr,
powervar_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/salicru-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,5 @@ subdriver_t salicru_subdriver = {
salicru_format_model,
salicru_format_mfr,
salicru_format_serial,
fix_report_desc,
};
1 change: 1 addition & 0 deletions drivers/tripplite-hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,4 +562,5 @@ subdriver_t tripplite_subdriver = {
tripplite_format_model,
tripplite_format_mfr,
tripplite_format_serial,
fix_report_desc,
};
9 changes: 9 additions & 0 deletions drivers/usbhid-ups.c
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,9 @@ static int callback(hid_dev_handle_t argudev, HIDDevice_t *arghd, unsigned char

upslogx(2, "Using subdriver: %s", subdriver->name);

if (subdriver->fix_report_desc(arghd, pDesc)) {
upsdebugx(2, "Report Descriptor Fixed");
}
HIDDumpTree(udev, subdriver->utab);

#ifndef SHUT_MODE
Expand Down Expand Up @@ -1242,6 +1245,12 @@ static double interval(void)
}
#endif

/* default subdriver function which doesnt attempt to fix any issues in the parsed HID Report Descriptor */
int fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc) {
return 0;
}


/* walk ups variables and set elements of the info array. */
static bool_t hid_ups_walk(walkmode_t mode)
{
Expand Down
2 changes: 2 additions & 0 deletions drivers/usbhid-ups.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ typedef struct {
const char *(*format_model)(HIDDevice_t *hd); /* driver-specific methods */
const char *(*format_mfr)(HIDDevice_t *hd); /* for preparing human- */
const char *(*format_serial)(HIDDevice_t *hd); /* readable information */
int (*fix_report_desc)(HIDDevice_t *pDev, HIDDesc_t *pDesc); /* Function called to potentially remedy defects in the parsed Report Descriptor caused by buggy HID contents*/
} subdriver_t;

/* the following functions are exported for the benefit of subdrivers */
Expand All @@ -216,4 +217,5 @@ int setvar(const char *varname, const char *val);

void possibly_supported(const char *mfr, HIDDevice_t *hd);

int fix_report_desc(HIDDevice_t *pDev, HIDDesc_t *pDesc);
#endif /* USBHID_UPS_H */