Alexey Loukianov
2010-Jan-06 15:56 UTC
[Nut-upsdev] blazer_usb: compatibility with Ippon BackPro UPSes (Phoenix Power Co., Ltd usb-to-serial controller)
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Good day to all. In one of the offices I'm administering there are about 15 UPS marked with the brand "Ippon BackPro". This brand is widely popular in Russian Federation, while by itself is a 'Made in PRC' megatec clone. Depending on the model this UPSes have got either one standard serial RS-232C interface (cheaper models like Ippon BackPro 400 and Ippon BackPro 600/700 that were manufactured back in about year 2005 or earlier) or dual-port control interface: one serial and one USB. Ippon UPSes are by default shipped with Winpower java-based monitoring and controlling solution which is said to be compatible with windows of any kind, MacOS X and Linux. On workstations I used to use this software and it proved to work quiet reliable under Windows XP while still require some additional configuration to power the workstations down correctly before LowBattery condition arises. It was always a big problem to run this software on server in that office because of the server hardware that is available there. So-called "server" is in reality an older workstation with the Celeron 2Ghz CPU and 128Mb RAM acting as an office router and local mail server running CentOS4. So it was almost impossible to run Winpower on this box due to Java memory requirements. The only serial port available on this "server" box is occuped by local-specific hardware (PBX logs control), so the only choice to connect UPSes to this server was to use USB. Back in 2007 I've been trying to configure NUT to use megatec_usb driver, but that attempts were totally unsuccessful: driver was showing up "no response" from UPS. Recently I've been able to do "upgrade" of a server adding additional 256Mb of RAM and it allowed me to install and run linux version of Winpower. It was a big surprise for me that Winpower on linux successfully detects and controls UPS connected through USB interface but there were some caveats including huge CPU usage by Winpower main java process and tonns on "Process java(1234) uses usb device without first claming it" showing up in dmesg. So I have decided to give NUT one more chance. Prebuilt binary RPM available for CentOS4 (nut-2.2.0-4.el4) ships with older megatec_usb driver that still don't work with Ippon UPSes connected through USB. So I have fetched latest revision of NUT from SVN and tried both megatec protocol usb drivers from it: megatec_usb and blazer_usb. megatec_usb driver in debug mode showed up that there's some king of connection with UPS but correct status readings were obtained once in a 5-10 tries. blazer_usb showed up no connections with UPS at all. As Winpower on the same linux box was working perfectly my decision was to try to figure out what are the differences in the way the USB UPS communication happens between the Winpower, megatec_usb and blazer_usb. My best friends in this process were DJ Java Decompiller 3.10 and IDA Pro 4. Decompilation of Winpower java modules showed up that it uses native system binary libraries to handle actual accesses to USB bus (System.loadLibrary), which is called jusbMaxOSX/jusbMaxOSXi386 on MacOS X, jusb.dll on windows and libusbLinux/libusbLinuxamd on i686/x86-64 linux. Communication with UPS happens using megatec protocol through the single function OrderUPS with C-style prototype: int OrderUPS(char* cmd, char* return_buf, int return_buf_size, int timeout); This prototype is perfectly self-describing, so I went on to IDA Pro and opened up libusbLinux.so in it. Quick examination of this library showed up that this is a PIC-enabled lib and is in fact a mix of libusb-0.1.x with some Winpower-related funtions including OrderUPS. I'm not sure about the legal status of this as AFAIR libusb-0.1.x is GNU GPL licensed so Winpower creators should release full source of modified libusb they have used in their product. Well, this might be just another GNU GPL violation example, but let me continue to the interesting part. Disassembly of OrderUPS functions showed up that the base algorithm of communications with USB UPS is as following: 1. Explore usbfs, find first device with ID 06da:0003 (Phoenixtec Power Co., Ltd). 2. Try to open this device using libusb. 3. In case of failure try to detach kernel driver from this device using libusb and retry to open it. 4. If the device was opened up correctly set the configuration to 1 on it using: usb_set_configuration(devfd, 0x1); 5. Send command to device using usb_control_msg function in 8-bytes chunks as following: - ------------------- cut -------------------------------------- int index = 0; int count = strlen(cmd); while(index < count) { int tosend = ((count - index) > 8) ? 8 : (count - index); char tmp[8]; memset(tmp, 0, sizeof(tmp)); memcpy(tmp, &cmd[index], tosend); int ret = usb_control_message(devfd, 0x21, 0x9, 0x2, 0, tmp, tosend, 1000); if((ret <= 0) || (ret != tosend)) { return_buf[0] = 0; return -1; } index += tosend; } - ------------------- cut -------------------------------------- 6. Read back return string from UPS in one chunk using usb_interrupt_read: - ------------------- cut -------------------------------------- char tmp[256]; memset(tmp, 0, sizeof(tmp)); int ret = usb_interrupt_read(devfd, 0x81, tmp, max_return_size, timeout); if(ret <= 0) { return_buf[0] = 0; return -1; } int max = (max_return_size > 256) ? 256 : max_return_size; memcpy(return_buf, tmp, max); return_buf[max] = 0; usb_close(devfd); return max; - ------------------- cut -------------------------------------- The differences between the way Winpower works with UPS and NUT works with UPS are as follows: 1. megatec_usb and blazer_usb both read up data in 8-byte chunks. Winpower do it in one large chunk. 2. blazer_usb tries to flush read buffer of controller before sending a command. 3. Both megatec_usb and blazer_usb use different USB message value in usb_control_message call (Winpower uses 0x2, while blazer_usb uses 0x200 and megatec_usb uses "ReportId+(0x03<<8)"). So I've changed blazer_usb.c to read up data in one large chunk instead of 8-byte chunks, to pass 0x2 instead of 0x200 in the usb_control_message call and removed buffer-flushing code completely. At first glance blazer_usb still wasn't working after this change but experiments showed up that this usb-to-serial implementation hangs when max_return_size is set larger that 64 bytes. Limiting return buffer size to 64 bytes in usb_interrupt_read call made blazer_usb to work perfectly with Ippon UPS. As for hangs: there are several ways to un-hang hanged UPS. You may replug USB cable, you may reboot the server and you may use appropriate ioctl on usbfs node to do a port-reset (libusb usb_reset also will do). Side note: the device is not working with Winpower after it was hanged by blazer_usb or megatec_usb. In the end I've got working blazer_usb on CentOS4 with stock libusb (0.1.8). Key point was to read up data in one 64 byte chunk. It is still unclear why does the data got corrupted in megatec_usb when read up in 8-bytes chunks, and why does the device hang when using original blazer_usb with buffer-flush and 8-byte chunks read. To try to make things more clear I had reverted blazer_usb.c back to SVN HEAD and removed from the code the part that flushes the device buffer before reading up a command. The result was the device returned back one correct reply on Q1 query but then hanged. Running blazer_usb under ltrace showed that there were some additional characters left in device buffer after the '\r', so I had added buffer flush code back but placed it after the buffer read. Nothing changed, device still locked up after returning one correct answer on "Q1\r" query. Next proposal was that libusb version shipped with RHEL4/CentOS4 is a bit outdated and might be somewhat buggy. So I had downloaded libusb-0.1.12 SRPMS from CentOS5, built binary RPM and installed it. After that the modified blazer_usb with buffer flush taking place after the reading of reply no longer made the device hang. I had reverted blazer_usb back to SVN HEAD once again and it also started to work normally. However megatec_usb data corruption on receive wasn't cured by libusb update. So, the conclusion is as following: 1. blazer_usb driver from SVN HEAD works correctly with USB Ippon UPSes on CentOS4, but require libusb version update. Version 0.1.12 from CentOS5 will do. 2. megatec_usb driver somehow fails to read up correct data from USB device. The cause of data corruption is unclear for me as it seems that the steps megatec_usb driver takes to read up data are almost the same as blazer_usb take. 3. It is possible to make blazer_usb work with RHEL4 version of libusb (0.1.8), but it require modifications to the way it work. The patch that works on my setup is attached to this message. Hope this info will help people to get Ippon UPSes with USB connection to a server work normally in conjunction with RHEL4/CentOS4. - -- Best regards, Alexey Loukianov mailto:mooroon2 at mail.ru System Engineer, Mob.:+7(926)218-1320 *nix Specialist -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iQEcBAEBAgAGBQJLRLLIAAoJEPB9BOdTkBUL0P0H/2rkUW5lKPR3whE5OKhMdyOh XrrEh7gJjeIYUUjj+hPWgEdCBgwp7D/o3YpAh7PaCtysodqMVtgrPgt7pmOoRkQR RAFNarQnmx+ctRffbd/+wTpHWglGJtsmuRw1Ontj9G57117F2k4hDphOsjJPWGNw VTwKfQi8yXqqCK8wKSH7xj5iMmbbgHso+Tde5nue0kHdEEkSqkW54ZGAwtInoMMs P2q2qfxyKC/hDJkGIVmTC74BtGVmSUQntwbKQ+VCKMGR0NYV0T/tTKNcoRQeJRMz UILdWrfDZc8h4MBl7eh15TU5A8gPZX6asPIEx0qPSUX0c39fqIv0D53uZYK9T5o=iJR2 -----END PGP SIGNATURE----- -------------- next part -------------- A non-text attachment was scrubbed... Name: blazer_usb.c.patch Type: text/x-patch Size: 2586 bytes Desc: not available URL: <http://lists.alioth.debian.org/pipermail/nut-upsdev/attachments/20100106/f46cbbfe/attachment.bin>
Arjen de Korte
2010-Jan-06 20:04 UTC
[Nut-upsdev] blazer_usb: compatibility with Ippon BackPro UPSes (Phoenix Power Co., Ltd usb-to-serial controller)
Citeren Alexey Loukianov <mooroon2 op mail.ru>:> 1. megatec_usb and blazer_usb both read up data in 8-byte chunks. > Winpower do it in one large chunk.This depends on what the interrupt endpoint supports. Both megatec_usb and blazer_usb can be used for widely different UPS makes and models. Not all support reading more than 8 bytes at a time (in fact, most don't). See the output of 'lsusb -vvv' for your UPS and lookup the following: Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes The collection of data when reading from the interrupt endpoint is possibly dealt with through some libusb implementations, but it is safer to do this in the driver itself.> 2. blazer_usb tries to flush read buffer of controller before > sending a command.This is needed by some devices supported through this driver.> In the end I've got working blazer_usb on CentOS4 with stock libusb > (0.1.8). Key > point was to read up data in one 64 byte chunk. It is still unclear > why does the > data got corrupted in megatec_usb when read up in 8-bytes chunks, > and why does > the device hang when using original blazer_usb with buffer-flush and 8-byte > chunks read.Most likely, the interrupt endpoint stalls. Since the flushing so far didn't clear stall conditions, it may hang. Improved now, thanks for the hint.> 1. blazer_usb driver from SVN HEAD works correctly with USB Ippon UPSes on > CentOS4, but require libusb version update. Version 0.1.12 from > CentOS5 will do.Good. Thanks for the report.> 2. megatec_usb driver somehow fails to read up correct data from USB > device. The > cause of data corruption is unclear for me as it seems that the steps > megatec_usb driver takes to read up data are almost the same as > blazer_usb take.There is an error in the way how the megatec_usb driver deals with replies shorter than the 8 bytes it asks for.> 3. It is possible to make blazer_usb work with RHEL4 version of > libusb (0.1.8), > but it require modifications to the way it work. The patch that works on my > setup is attached to this message.Thanks for the patch, but that will badly break other devices with the same VID:PID combination. Therefor, this is not an option. Best regards, Arjen -- Please keep list traffic on the list
Seemingly Similar Threads
- megatec_usb: Ippon BackComfoPro (06da:0003 Phoenixtec Power)
- Problem with nut 2.4.1 & Ippon 2000 Smart power on FreeBSD
- blazer_usb vs. Ippon Smart Power Pro 1400
- Question about nut 2.4.1 and Ippon smart power pro 2000
- Fwd: Re: megatec_usb: Ippon BackComfoPro (06da:0003 Phoenixtec Power)