URL
https://opencores.org/ocsvn/usb_fpga_2_14/usb_fpga_2_14/trunk
Subversion Repositories usb_fpga_2_14
[/] [usb_fpga_2_14/] [trunk/] [java/] [ztex/] [Ztex1.java] - Rev 2
Compare with Previous | Blame | View Log
/*% Java host software API of ZTEX SDK Copyright (C) 2009-2017 ZTEX GmbH. http://www.ztex.de This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. Alternatively, the contents of this file may be used under the terms of the GNU General Public License Version 3, as described below: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. 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, see http://www.gnu.org/licenses/. %*/ /* Functions for USB devices with ZTEX descriptor 1 */ package ztex; import java.io.*; import java.util.*; import java.nio.*; import org.usb4java.*; /** * This class implements the interface-independent part of the communication protocol for the interaction with the ZTEX firmware.<p> * All firmware implementations that provide the ZTEX descriptor 1 are supported. * A description of this descriptor can be found in {@link ZtexDevice1}. * <p> * The most important features of this class are the functions for uploading the firmware * and the renumeration management. * <p> * The interface dependent part of the communication protocol (currently only one is supported) * can be found in {@link Ztex1v1}. * @see ZtexDevice1 * @see Ztex1v1 */ public class Ztex1 { private DeviceHandle handle = null; private ZtexDevice1 dev = null; private Vector<String> oldDevices = new Vector<String>(); private String oldDev = null; private boolean[] interfaceClaimed = new boolean[256]; private boolean configurationSet = false; /** * The timeout for control messages in ms. */ public int controlMsgTimeout = 2000; // in ms private long lastVendorCommandT = 0; // ******* Ztex1 *************************************************************** /** * Constructs an instance from a given device. * @param pDev The given device. * @throws UsbException if an communication error occurred. */ public Ztex1 ( ZtexDevice1 pDev ) throws UsbException { dev = pDev; init(); dev.ref(); } // ******* init **************************************************************** /** * Initializates the class. * @throws UsbException if an communication error occurred. */ protected synchronized void init () throws UsbException { for (int i=0; i<256; i++) interfaceClaimed[i] = false; handle = new DeviceHandle(); int result = LibUsb.open(dev.dev(), handle); if (result != LibUsb.SUCCESS) throw new UsbException(dev.dev(), "Unable to open USB device", result); } // ******* dispose ************************************************************* /** * This should be called if the class is not used anymore. * It closes the USB connection and releases all resources */ public synchronized void dispose () { if ( handle != null ) { for (int i=0; i<256; i++) if ( interfaceClaimed[i] ) LibUsb.releaseInterface(handle, i); LibUsb.close(handle); handle = null; } if ( dev != null ) { dev.unref(); dev = null; } } // ******* finalize ************************************************************ /** * Releases all resources. */ protected void finalize() throws Throwable { dispose(); } // ******* handle ************************************************************** /** Returns the USB file handle. * @return the USB file handle. */ public synchronized final DeviceHandle handle() { return handle; } // ******* dev ***************************************************************** /** * Returns the corresponding {@link ZtexDevice1}. * @return the corresponding {@link ZtexDevice1}. */ public synchronized final ZtexDevice1 dev() { return dev; } // ******* valid *************************************************************** /** * Returns true if ZTEX descriptor 1 is available. * @return true if ZTEX descriptor 1 is available. */ public synchronized boolean valid ( ) { return dev.valid(); } // ******* checkValid ********************************************************** /** * Checks whether ZTEX descriptor 1 is available. * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available. */ public synchronized void checkValid () throws InvalidFirmwareException { if ( ! dev.valid() ) throw new InvalidFirmwareException(this, "Can't read ZTEX descriptor 1"); } // ******* vendorCommand ******************************************************* /** * Sends a vendor command to Endpoint 0 of the EZ-USB device. * The command may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The command number (0..255). * @param func The name of the command. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param buf The payload data buffer. The full buffer is sent, i.e. transfer size is equal to buffer capacity. * @return the number of bytes sent. * @throws UsbException if a communication error occurs. */ public synchronized int vendorCommand (int cmd, String func, int value, int index, ByteBuffer buf) throws UsbException { long t0 = new Date().getTime()-100; int trynum = 0; int i = -1; if ( controlMsgTimeout < 400 ) controlMsgTimeout = 400; while ( i<=0 && new Date().getTime()-t0<controlMsgTimeout ) { // repeat the message until the timeout has reached i = LibUsb.controlTransfer(handle, (byte)0x40, (byte)(cmd & 255), (short)(value & 0xffff), (short)(index & 0xffff), buf, controlMsgTimeout>>2); lastVendorCommandT = new Date().getTime(); if ( i < 0 ) { System.err.println("Warning (try " + (trynum+1) + "): " + LibUsb.strError(i) ); try { Thread.sleep( 1 << trynum ); } catch ( InterruptedException e ) { } trynum++; } } if ( i < 0 ) throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + LibUsb.strError(i)); return i; } /** * Sends a vendor command to Endpoint 0 of the EZ-USB device. * The command may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The command number (0..255). * @param func The name of the command. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param length The size of the payload data (0..65535), i.e. bytes 6 and 7 of the setup data. * @param buf The payload data buffer. * @return the number of bytes sent. * @throws UsbException if a communication error occurs. */ public synchronized int vendorCommand (int cmd, String func, int value, int index, byte[] buf, int length) throws UsbException { ByteBuffer buffer = BufferUtils.allocateByteBuffer(length); buffer.put(buf,0,length); return vendorCommand(cmd, func, value, index, buffer); } /** * Sends a vendor command with no payload data to Endpoint 0 of the EZ-USB device. * The command may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The command number (0..255). * @param func The name of the command. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @return the number of bytes sent. * @throws UsbException if a communication error occurs. */ public int vendorCommand (int cmd, String func, int value, int index) throws UsbException { return vendorCommand (cmd, func, value, index, ByteBuffer.allocateDirect(0)); } /** * Sends a vendor command with no payload data and no setup data to Endpoint 0 of the EZ-USB device. * The command may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The command number (0..255). * @param func The name of the command. This string is used for the generation of error messages. * @return the number of bytes sent. * @throws UsbException if a communication error occurs. */ public int vendorCommand (int cmd, String func) throws UsbException { byte[] buf = { 0 }; return vendorCommand (cmd, func, 0, 0, ByteBuffer.allocateDirect(0)); } // ******* vendorRequest ******************************************************* /** * Sends a vendor request to Endpoint 0 of the EZ-USB device. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param buf The payload data buffer. Buffer capacity determines the length of the transfer. * @return the number of bytes received. * @throws UsbException if a communication error occurs. */ public synchronized int vendorRequest (int cmd, String func, int value, int index, ByteBuffer buf) throws UsbException { long t0 = new Date().getTime()-100; int trynum = 0; int i = -1; if ( controlMsgTimeout < 400 ) controlMsgTimeout = 400; while ( i<=0 && new Date().getTime()-t0<controlMsgTimeout ) { // we repeat the message until the timeout has reached // Wait at least 1ms after the last command has been send long ms = new Date().getTime() - lastVendorCommandT; if ( ms < 2 ) { try { Thread.sleep(1); } catch ( InterruptedException e ) { } } i = LibUsb.controlTransfer(handle, (byte)(0xc0 & 255), (byte)(cmd & 255), (short)(value & 0xffff), (short)(index & 0xffff), buf, controlMsgTimeout>>2); if ( i < 0 ) { System.err.println("Warning (try " + (trynum+1) + "): " + LibUsb.strError(i) ); try { Thread.sleep( 1 << trynum ); } catch ( InterruptedException e ) { } trynum++; } } if ( i < 0 ) throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + LibUsb.strError(i)); return i; } /** * Sends a vendor request to Endpoint 0 of the EZ-USB device. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data. * @param buf The payload data buffer. * @return the number of bytes received. * @throws UsbException if a communication error occurs. */ public synchronized int vendorRequest (int cmd, String func, int value, int index, byte[] buf, int maxlen) throws UsbException { ByteBuffer buffer = BufferUtils.allocateByteBuffer(maxlen); int i = vendorRequest(cmd, func, value, index, buffer); try { buffer.get(buf,0,maxlen); } catch ( Exception e ) { // errors can be ignored } return i; } /** * Sends a vendor request to Endpoint 0 of the EZ-USB device. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param buf The payload data buffer. * @return the number of bytes sent. * @throws UsbException if a communication error occurs. */ public int vendorRequest (int cmd, String func, ByteBuffer buf) throws UsbException { return vendorRequest (cmd, func, 0, 0, buf); } /** * Sends a vendor request to Endpoint 0 of the EZ-USB device. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data. * @param buf The payload data buffer. * @return the number of bytes sent. * @throws UsbException if a communication error occurs. */ public int vendorRequest (int cmd, String func, byte[] buf, int maxlen) throws UsbException { return vendorRequest (cmd, func, 0, 0, buf, maxlen); } // ******* vendorCommand2 ****************************************************** /** * Sends a vendor command to Endpoint 0 of the EZ-USB device and throws an {@link UsbException} if not all of the payload has been sent. * The command may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The command number (0..255). * @param func The name of the command. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param buf The payload data buffer. The full buffer is sent, i.e. transfer size is equal to buffer capacity. * @throws UsbException if a communication error occurs or if not all of the payload has been sent. */ public synchronized void vendorCommand2 (int cmd, String func, int value, int index, ByteBuffer buf) throws UsbException { int length = buf.capacity(); int i = vendorCommand (cmd, func, value, index, buf); if ( i != length ) throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + "Send " + i + " byte of data instead of " + length + " bytes"); } /** * Sends a vendor command to Endpoint 0 of the EZ-USB device and throws an {@link UsbException} if not all of the payload has been sent. * The command may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The command number (0..255). * @param func The name of the command. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param length The size of the payload data (0..65535), i.e. bytes 6 and 7 of the setup data. * @param buf The payload data buffer. * @throws UsbException if a communication error occurs or if not all of the payload has been sent. */ public synchronized void vendorCommand2 (int cmd, String func, int value, int index, byte[] buf, int length) throws UsbException { int i = vendorCommand (cmd, func, value, index, buf, length); if ( i != length ) throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + "Send " + i + " byte of data instead of " + length + " bytes"); } // ******* vendorRequest2 ****************************************************** /** * Sends a vendor request to Endpoint 0 of the EZ-USB device and throws an {@link UsbException} if not all of the payload has been received. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param buf The payload data buffer. Buffer capacity determines the length of the transfer. * @throws UsbException if a communication error occurs or not all of the payload has been received. */ public void vendorRequest2 (int cmd, String func, int value, int index, ByteBuffer buf) throws UsbException { int maxlen = buf.capacity(); int i = vendorRequest(cmd, func, value, index, buf); if ( i != maxlen ) throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + "Received " + i + " byte of data, expected "+maxlen+" bytes"); } /** * Sends a vendor request to Endpoint 0 of the EZ-USB device and throws an {@link UsbException} if not all of the payload has been received. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param buf The payload data buffer. * @throws UsbException if a communication error occurs or not all of the payload has been received. */ public void vendorRequest2 (int cmd, String func, ByteBuffer buf) throws UsbException { vendorRequest2(cmd, func, 0, 0, buf); } /** * Sends a vendor request to Endpoint 0 of the EZ-USB device and throws an {@link UsbException} if not all of the payload has been received. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data. * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data. * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data. * @param buf The payload data buffer. * @throws UsbException if a communication error occurs or not all of the payload has been received. */ public void vendorRequest2 (int cmd, String func, int value, int index, byte[] buf, int maxlen) throws UsbException { int i = vendorRequest(cmd, func, value, index, buf, maxlen); if ( i != maxlen ) throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + "Received " + i + " byte of data, expected "+maxlen+" bytes"); } /** * Sends a vendor request to Endpoint 0 of the EZ-USB device and throws an {@link UsbException} if not all of the payload has been received. * The request may be send multiple times until the {@link #controlMsgTimeout} is reached. * @param cmd The request number (0..255). * @param func The name of the request. This string is used for the generation of error messages. * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data. * @param buf The payload data buffer. * @throws UsbException if a communication error occurs or not all of the payload has been received. */ public void vendorRequest2 (int cmd, String func, byte[] buf, int maxlen) throws UsbException { vendorRequest2(cmd, func, 0, 0, buf, maxlen); } // ******* bulkWrite *********************************************************** /** * Wrapper method for ibUsb.bulkTransfer(DeviceHandle,byte,ByteBuffer,IntBuffer,long). * @param ep The endpoint number. * @param buffer The payload data buffer. The whole buffer is transferred, i.e. transfer legth is equal to buffer capacity * @param timeout The timeout in ms * @return The error code (<0) if an error occurred, otherwise the amount of transferred date */ public int bulkWrite(int ep, ByteBuffer buffer, long timeout) { IntBuffer transferred = BufferUtils.allocateIntBuffer(); int result = LibUsb.bulkTransfer(handle, (byte)(ep & 127), buffer, transferred, timeout); return result < 0 ? result : transferred.get(); } /** * Wrapper method for LibUsb.bulkTransfer(DeviceHandle,byte,ByteBuffer,IntBuffer,long). * @param ep The endpoint number. * @param buf The payload data buffer. * @param length The size of the payload data * @param timeout The timeout in ms * @return The error code (<0) if an error occurred, otherwise the amount of transferred date */ public int bulkWrite(int ep, byte[] buf, int length, long timeout) { ByteBuffer buffer = BufferUtils.allocateByteBuffer(length); buffer.put(buf,0,length); IntBuffer transferred = BufferUtils.allocateIntBuffer(); int result = LibUsb.bulkTransfer(handle, (byte)(ep & 127), buffer, transferred, timeout); return result < 0 ? result : transferred.get(); } // ******* bulkRead ************************************************************ /** * Wrapper method for LibUsb.bulkTransfer(DeviceHandle,byte,ByteBuffer,IntBuffer,long). * @param ep The endpoint number. * @param buffer The payload data buffer. The transfer length is determined by buffer capacity. * @param timeout The timeout in ms * @return The error code (<0) if an error occurred, otherwise the amount of transferred date */ public int bulkRead(int ep, ByteBuffer buffer, long timeout) { IntBuffer transferred = BufferUtils.allocateIntBuffer(); int result = LibUsb.bulkTransfer(handle, (byte)(128 | (ep & 127)), buffer, transferred, timeout); return result < 0 ? result : transferred.get(); } /** * Wrapper method for LibUsb.bulkTransfer(DeviceHandle,byte,ByteBuffer,IntBuffer,long). * @param ep The endpoint number. * @param buf The payload data buffer. * @param maxlen The size of the transfer. * @param timeout The timeout in ms * @return The error code (<0) if an error occurred, otherwise the amount of transferred date */ public int bulkRead(int ep, byte[] buf, int maxlen, long timeout) { ByteBuffer buffer = BufferUtils.allocateByteBuffer(maxlen); IntBuffer transferred = BufferUtils.allocateIntBuffer(); int result = LibUsb.bulkTransfer(handle, (byte)(128 | (ep & 127)), buffer, transferred, timeout); try { buffer.get(buf,0,maxlen); } catch ( Exception e ) { // errors can be ignored } return result < 0 ? result : transferred.get(); } // ******* allocateByteBuffer ************************************************** /** * Utility function that creates a ByteBuffer from byte array. * @param buf The byte array. * @return A ByteBuffer. */ public static ByteBuffer allocateByteBuffer(byte[] buf) { ByteBuffer buffer = BufferUtils.allocateByteBuffer(buf.length); return buffer.put(buf,0,buf.length); } /** * Utility function that creates a ByteBuffer from byte array. * @param buf The byte array. * @param offs The offset of the first data in the byte array. * @param length Length of the The byte array. * @return A ByteBuffer. */ public static ByteBuffer allocateByteBuffer(byte[] buf, int offs, int length) { ByteBuffer buffer = BufferUtils.allocateByteBuffer(length); return buffer.put(buf,offs,length); } // ******* setConfiguration **************************************************** /** * Sets the configuration. * @param config The configuration number (usually 1) * @throws UsbException if an error occurs while attempting to set the configuration. */ public synchronized void setConfiguration ( int config) throws UsbException{ int result = LibUsb.setConfiguration(handle(), config); if ( result < 0 ) throw new UsbException(dev.dev(), "Setting configuration to " + config + " failed: ", result); configurationSet = true; } // ******* trySetConfiguration **************************************************** /** * Tries to set the configuration. * If an error occurs while attempting to set the configuration, a warning message is printed to stderr. * @param config The configuration number (usually 1) */ public synchronized void trySetConfiguration ( int config) { int result = LibUsb.setConfiguration(handle(), config); if ( result < 0 ) System.err.println("Setting configuration to " + config + " failed: " + LibUsb.strError(result)); configurationSet = true; } // ******* getInterfaceClaimed ************************************************* /** * Returns true if interface is claimed. * @return true if interface is claimed * @param iface The interface number */ public synchronized boolean getInterfaceClaimed ( int iface ) { return iface>=0 && iface<256 && interfaceClaimed[iface]; } // ******* claimInterface ****************************************************** /** * Claims an interface. * @param iface The interface number (usually 0) * @throws UsbException if an error occurs while attempting to claim the interface. */ public synchronized void claimInterface ( int iface) throws UsbException{ if ( ! configurationSet ) trySetConfiguration(1); if ( iface<0 || iface>=256 || (!interfaceClaimed[iface]) ) { int result = LibUsb.claimInterface(handle(), iface); if ( result < 0 ) throw new UsbException(dev.dev(), "Claiming interface " + iface + " failed: ", result); } if ( iface>=0 && iface < 256 ) interfaceClaimed[iface]=true; } // ******* releaseInterface **************************************************** /** * Releases an interface. * @param iface The interface number (usually 0) */ public synchronized void releaseInterface ( int iface ) { if ( iface<0 || iface>=256 || interfaceClaimed[iface] ) LibUsb.releaseInterface(handle(), iface); if ( iface>=0 && iface < 256 ) interfaceClaimed[iface]=false; } // ******* findOldDevices ****************************************************** private synchronized void findOldDevices() throws DeviceLostException, UsbException { oldDev = dev.name(); oldDevices.clear(); // System.out.println("oldDev="+oldDev); ZtexContext context = new ZtexContext(); DeviceList dl = new DeviceList(); int result = LibUsb.getDeviceList(context.context(), dl); if (result < 0) { context.unref(); throw new UsbException( "findOldDevices: Unable to get device list: ", result); } try { for (Device dev: dl) { oldDevices.add(ZtexDevice1.name(dev)); // System.out.println("add " + ZtexDevice1.name(dev) ); } } finally { LibUsb.freeDeviceList(dl, true); context.unref(); } } // ******* initNewDevice ******************************************************* private synchronized void initNewDevice (String errBase, boolean scanUnconfigured ) throws DeviceLostException, UsbException, InvalidFirmwareException { // close current connection dispose(); // scan the bus for up to 60 s for a new device. Boot sequence may take a while. for ( int i=0; i<300 && dev==null; i++ ) { Device newDev = null; // wait 0.2s try { Thread.sleep( 200 ); } catch ( InterruptedException e ) { } // accept old address after 5s if ( i == 25 ) oldDevices.remove(oldDev); // scan bus for new devices ZtexContext context = new ZtexContext(); DeviceList dl = new DeviceList(); int result = LibUsb.getDeviceList(context.context(), dl); if ( result < 0 ) { context.unref(); throw new UsbException( "findNewDevice: Unable to get device list: ", result); } try { for (Device udev: dl) { String s = ZtexDevice1.name(udev); // System.out.println(s + ": " + oldDevices.indexOf(s)); if ( oldDevices.indexOf(s)<0 ) { if ( newDev != null ) throw new DeviceLostException( errBase + "More than 1 new devices found: `" + ZtexDevice1.name(newDev) + "', `" + ZtexDevice1.name(udev) + "'"); newDev = udev; } } // init new device if ( newDev != null ) { // create ZtexDevice1 DeviceDescriptor dd = new DeviceDescriptor(); result = LibUsb.getDeviceDescriptor(newDev, dd); if (result != LibUsb.SUCCESS) throw new UsbException(newDev, "Unable to read device descriptor", result); int vid = dd.idVendor() & 65535; int pid = dd.idProduct() & 65535; try { dev = new ZtexDevice1(context, newDev, dd.idVendor() & 65535, dd.idProduct() & 65535, scanUnconfigured ); } catch ( DeviceNotSupportedException e ) { throw new InvalidFirmwareException( e.getLocalizedMessage() ); } init(); } } finally { LibUsb.freeDeviceList(dl, true); context.unref(); } } if ( dev == null ) throw new DeviceLostException( errBase + ": No new device found" ); } // ******* uploadFirmware ****************************************************** /** * Uploads the firmware to the EZ-USB and manages the renumeration process. * <p> * Before the firmware is uploaded the device is set into a reset state. * After the upload the firmware is booted and the renumeration starts. * During this process the device disappears from the bus and a new one * occurs which will be assigned to this class automatically (instead of the disappeared one). * @param imgFile The firmware image. * @param force The compatibility check is skipped if true. * @throws IncompatibleFirmwareException if the given firmware is not compatible to the installed one, see {@link ZtexDevice1#compatible(int,int,int,int)} (Upload can be enforced using the <tt>force</tt> parameter) * @throws FirmwareUploadException If an error occurred while attempting to upload the firmware. * @throws UsbException if a communication error occurs. * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available. * @throws DeviceLostException if a device went lost after renumeration. * @return the upload time in ms. */ // returns upload time in ms public long uploadFirmware ( ZtexImgFile1 imgFile, boolean force ) throws IncompatibleFirmwareException, FirmwareUploadException, UsbException, InvalidFirmwareException, DeviceLostException { // load the firmware file // imgFile.dataInfo(System.out); // System.out.println(imgFile); // check for compatibility if ( ! force && dev.valid() ) { if ( imgFile.interfaceVersion() != dev.interfaceVersion() ) throw new IncompatibleFirmwareException("Wrong interface version: Expected 1, got " + imgFile.interfaceVersion() ); if ( ! dev.compatible ( imgFile.productId(0), imgFile.productId(1), imgFile.productId(2), imgFile.productId(3) ) ) throw new IncompatibleFirmwareException("Incompatible productId's: Current firmware: " + ZtexDevice1.byteArrayString(dev.productId()) + " firmware file: " + ZtexDevice1.byteArrayString(imgFile.productId()) ); } // prepare FX3 for booting from USB if ( dev.valid() && dev.fx3() ) { findOldDevices(); resetFX3(false); initNewDevice("Device lost after reset", true); } // scan the bus for comparison findOldDevices(); // upload the firmware long time = EzUsb.uploadFirmware( handle, imgFile ); // find and init new device initNewDevice("Device lost after uploading Firmware", false); return time; } /** * Uploads the firmware to the EZ-USB and manages the renumeration process. * <p> * Before the firmware is uploaded the device is set into a reset state. * After the upload the firmware is booted and the renumeration starts. * During this process the device disappears from the bus and a new one * occurs which will be assigned to this class automatically (instead of the disappeared one). * @param imgFileName The file name of the firmware image in ihx or img format. The file can be a regular file or a system resource (e.g. a file from the current jar archive). * @param force The compatibility check is skipped if true. * @throws IncompatibleFirmwareException if the given firmware is not compatible to the installed one, see {@link ZtexDevice1#compatible(int,int,int,int)} (Upload can be enforced using the <tt>force</tt> parameter) * @throws FirmwareUploadException If an error occurred while attempting to upload the firmware. * @throws UsbException if a communication error occurs. * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available. * @throws DeviceLostException if a device went lost after renumeration. * @return the upload time in ms. */ // returns upload time in ms public long uploadFirmware ( String imgFileName, boolean force ) throws IncompatibleFirmwareException, FirmwareUploadException, UsbException, InvalidFirmwareException, DeviceLostException { // load the firmware file ZtexImgFile1 imgFile; try { imgFile = new ZtexImgFile1( imgFileName ); } catch ( IOException e ) { throw new FirmwareUploadException( e.getLocalizedMessage() ); } catch ( ImgFileDamagedException e ) { throw new FirmwareUploadException( e.getLocalizedMessage() ); } return uploadFirmware( imgFile, force ); } /** * Uploads the firmware to the EZ-USB and manages the renumeration process. * <p> * Before the firmware is uploaded the device is set into a reset state. * After the upload the firmware is booted and the renumeration starts. * During this process the device disappears from the bus and a new one * occurs which will be assigned to this class automatically (instead of the disappeared one). * @param imgIn Input stream from which the img file is read. * @param name Name of the input. * @param force The compatibility check is skipped if true. * @throws IncompatibleFirmwareException if the given firmware is not compatible to the installed one, see {@link ZtexDevice1#compatible(int,int,int,int)} (Upload can be enforced using the <tt>force</tt> parameter) * @throws FirmwareUploadException If an error occurred while attempting to upload the firmware. * @throws UsbException if a communication error occurs. * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available. * @throws DeviceLostException if a device went lost after renumeration. * @return the upload time in ms. */ // returns upload time in ms public long uploadFirmware ( InputStream imgIn, String name, boolean force ) throws IncompatibleFirmwareException, FirmwareUploadException, UsbException, InvalidFirmwareException, DeviceLostException { // load the firmware file ZtexImgFile1 imgFile; try { imgFile = new ZtexImgFile1( imgIn, name ); } catch ( IOException e ) { throw new FirmwareUploadException( e.getLocalizedMessage() ); } catch ( ImgFileDamagedException e ) { throw new FirmwareUploadException( e.getLocalizedMessage() ); } return uploadFirmware( imgFile, force ); } // ******* resetFX3 ************************************************************ /** * Resets a FX3 device with ztex firmware using vendor command 0xA1. * If parameter boot is false new firmware has to be uploaded via USB. * @param boot True in order to enable booting firmware from Flash. * <p> * @throws UsbException if a communication error occurs. * @throws InvalidFirmwareException if device its not an FX3 device with ZTEX firmware. */ // boot private void resetFX3 ( boolean boot ) throws UsbException, InvalidFirmwareException { if ( !dev.valid() || !dev.fx3() ) throw new InvalidFirmwareException("Reset using vendor command 0xA1 is not supported by the device"); LibUsb.controlTransfer(handle, (byte)0x40, (byte)(0xA1 & 255), /*value*/ (short)(boot ? 1 : 0), /*index*/ (short)0, ByteBuffer.allocateDirect(0), 100); } // ******* resetEzUsb ********************************************************** /** * Resets the EZ-USB and manages the renumeration process. * <p> * After the reset the renumeration starts. * During this process the device disappears from the bus and a new one * occurs which will be assigned to this class automatically (instead of the disappeared one). * @throws FirmwareUploadException If an error occurred while attempting to reset the EZ-USB * @throws UsbException if a communication error occurs. * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available. * @throws DeviceLostException if a device went lost after renumeration. */ public void resetEzUsb () throws FirmwareUploadException, UsbException, InvalidFirmwareException, DeviceLostException { if ( !dev.valid() && dev.fx3() ) { System.err.println("Warning: Attempting to reset a FX3 device in factory state"); return; } // scan the bus for comparison findOldDevices(); if ( dev.fx3() ) { resetFX3(true); } else { // reset the EZ-USB EzUsb.resetFx2(handle,true); try { EzUsb.resetFx2(handle,false); // error (may caused by re-numeration) can be ignored } catch ( FirmwareUploadException e ) { } } // find and init new device initNewDevice( "Device lost after resetting the EZ-USB", true ); } // ******* resetDevice ********************************************************* /** * Performs a configuration or bus reset. This method is used to synchronize data toggles at start-up of the host software. * @param force True enforces a bus reset. By default a configuration reset is tried first and if it fails, a bus reset is performed. * @throws UsbException if a communication error occurs. */ public void resetDevice (boolean force) throws FirmwareUploadException, UsbException, InvalidFirmwareException, DeviceLostException { int result; if ( ! force ) { result = LibUsb.setConfiguration(handle(), -1); if ( result < 0 ) { System.err.println("Warning: Resetting configuration failed: " + LibUsb.strError(result)+ " trying bus reset"); force = true; } } if ( force ) { result = LibUsb.resetDevice(handle()); if (result != LibUsb.SUCCESS) throw new UsbException(dev.dev(), "Bus reset failed", result); } } // ******* toString ************************************************************ /** * Returns a lot of useful information about the corresponding device. * @return a lot of useful information about the corresponding device. */ public String toString () { return dev.toString(); } }