/* * Based loosly on code from: * ups.c Copyright (c) 1999-2000 Vojtech Pavlik * NUT 0.44-3 nutusb.c Copyright (C) 2001 Russell Kroll * includes battery date function from apcupsd * Copyright (c) 2001 Vojtech Pavlik * Copyright (c) 2001 Paul Stewart * * and a small amount of original code from Rob Crittenden Copyright (c) 2002 */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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 * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ #include #include #include #include #include #include #include #include #include #include #include "linux/hiddev.h" /* power device page: x84 */ #define UPS_USAGE 0x840004 #define UPS_BATTVOLT 0x840030 /* voltage * 100 */ #define UPS_LOADPCT 0x840035 /* load percentage */ #define UPS_BELOW_RCL 0x840042 /* below remaining cap limit */ #define UPS_CHARGING 0x840044 /* 0 = no longer charging */ #define UPS_SHUTDOWN_IMMINENT 0x840069 /* 1 = low battery */ #define UPS_MFR 0x8400FD /* manufacturer */ #define UPS_IPRODUCT 0x8400FE /* model name */ #define UPS_ISERIAL 0x8400FF /* serial number */ /* battery system page: x85 */ #define BATT_CHARGING 0x850044 /* 1 = charging, 0 = charged */ #define BATT_DISCHARGING 0x850045 /* 1 = on battery */ #define BATT_REMAINING_CAPACITY 0x850066 /* battery percentage */ #define BATT_RUNTIME_TO_EMPTY 0x850068 /* minutes */ #define BATT_MFRDATE 0x850085 /* manufacturer date */ #define BATT_ICHEMISTRY 0x850089 /* battery type */ #define BATT_AC_PRESENT 0x8500d0 /* 1 = on line */ #define BATT_IOEMINFORMATION 0x85008f /* battery OEM description */ static char *getstring(int fd, int type) { struct hiddev_usage_ref uref; struct hiddev_string_descriptor sdesc; static char str[256]; /* TODO: build a report table so we don't need HID_REPORT_ID_UNKNOWN */ memset(&uref, 0, sizeof(uref)); memset(&sdesc, 0, sizeof(sdesc)); uref.report_type = HID_REPORT_TYPE_FEATURE; uref.report_id = HID_REPORT_ID_UNKNOWN; uref.usage_code = type; snprintf(str, sizeof(str), "Unknown"); if (ioctl(fd, HIDIOCGUSAGE, &uref) == 0) { sdesc.index = uref.value; if (ioctl(fd, HIDIOCGSTRING, &sdesc) > 0) snprintf(str, sizeof(str), "%s", sdesc.value); else perror("ioctl HIDIOCGSTRING"); } return str; } int getval(int fd, int type) { struct hiddev_usage_ref uref; /* TODO: build a report table so we don't need HID_REPORT_ID_UNKNOWN */ memset(&uref, 0, sizeof(uref)); uref.report_type = HID_REPORT_TYPE_FEATURE; uref.report_id = HID_REPORT_ID_UNKNOWN; uref.field_index = 0; uref.usage_index = 0; uref.usage_code = type; uref.value = 0; if (ioctl(fd, HIDIOCGUSAGE, &uref) == 0) return uref.value; else return -1; } static inline int find_application(int fd, unsigned usage) { int i = 0, ret; while ((ret = ioctl(fd, HIDIOCAPPLICATION, i)) > 0 && ret != usage) i++; return (ret == usage); } int main (int argc, char **argv) { int fd = -1, i; char name[256] = "Unknown"; int battdate = 0; if (argc < 2) { char evdev[20]; for (i = 0; i < 4; i++) { sprintf(evdev, "/dev/usb/hid/hiddev%d", i); if ((fd = open(evdev, O_RDONLY)) >= 0) { if (find_application(fd, UPS_USAGE)) break; close(fd); } } if (i >= 4) { fprintf(stderr, "Couldn't find UPS device.\n"); exit(1); } printf("Found UPS at %s\n", evdev); } else { if ((fd = open(argv[argc - 1], O_RDONLY)) < 0) { perror("hiddev open"); exit(1); } if (!find_application(fd, UPS_USAGE)) { fprintf(stderr, "%s is not a UPS\n", argv[argc - 1]); exit(1); } } ioctl(fd, HIDIOCINITREPORT, 0); printf("Manufacturer: %s\n", getstring(fd, UPS_MFR)); printf("Model: %s\n", getstring(fd, UPS_IPRODUCT)); printf("Serial #: %s\n", getstring(fd, UPS_ISERIAL), 0, 0); printf("Battery Manufacture date: "); battdate = getval(fd, BATT_MFRDATE); printf("%4d-%02d-%02d (%d)\n", (battdate >> 9) + 1980, (battdate >> 5) & 0xF, battdate & 0x1F, battdate); printf("Battery Capacity: %d%%\n", getval(fd, BATT_REMAINING_CAPACITY)); printf("Battery Runtime: %d\n", getval(fd, BATT_RUNTIME_TO_EMPTY)); printf("Battery Voltage: %2.1f\n", (getval(fd, UPS_BATTVOLT) / 100.0)); printf("UPS State: "); switch(getval(fd, BATT_AC_PRESENT)) { case 0: printf("On battery\n"); break; case 1: printf("On line\n"); break; default: printf("Unknown battery status\n"); break; } }