OpenCores
URL https://opencores.org/ocsvn/usb_fpga_1_11/usb_fpga_1_11/trunk

Subversion Repositories usb_fpga_1_11

[/] [usb_fpga_1_11/] [trunk/] [java/] [ztex/] [Ztex1.java] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ZTEX
/*!
2
   Java Driver API for the ZTEX Firmware Kit
3
   Copyright (C) 2009-2010 ZTEX e.K.
4
   http://www.ztex.de
5
 
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License version 3 as
8
   published by the Free Software Foundation.
9
 
10
   This program is distributed in the hope that it will be useful, but
11
   WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
   General Public License for more details.
14
 
15
   You should have received a copy of the GNU General Public License
16
   along with this program; if not, see http://www.gnu.org/licenses/.
17
!*/
18
 
19
/*
20
    Functions for USB devices with ZTEX descriptor 1
21
*/
22
package ztex;
23
 
24
import java.io.*;
25
import java.util.*;
26
 
27
import ch.ntb.usb.*;
28
 
29
/**
30
  * This class implements the interface-independent part of the communication protocol for the interaction with the ZTEX firmware.<p>
31
  * All firmware implementations that provide the ZTEX descriptor 1 are supported.
32
  * A description of this descriptor can be found in {@link ZtexDevice1}.
33
  * <p>
34
  * The most important features of this class are the functions for uploading the firmware
35
  * and the renumeration management.
36
  * <p>
37
  * The interface dependent part of the communication protocol (currently only one is supported)
38
  * can be found in {@link Ztex1v1}.
39
  * @see ZtexDevice1
40
  * @see Ztex1v1
41
  */
42
public class Ztex1 {
43
    private int handle;
44
    private ZtexDevice1 dev = null;
45
    private boolean oldDevices[] = new boolean[128];
46
    private String usbBusName = null;
47
/** * Setting to true enables certain workarounds, e.g. to deal with bad driver/OS implementations. */
48
    public boolean certainWorkarounds = false;
49
/** * The timeout for  control messages in ms. */
50
    public int controlMsgTimeout = 1000;        // in ms
51
    private long lastVendorCommandT = 0;
52
 
53
// ******* Ztex1 ***************************************************************
54
/**
55
  * Constructs an instance from a given device.
56
  * @param pDev The given device.
57
  * @throws UsbException if an communication error occurred.
58
  */
59
    public Ztex1 ( ZtexDevice1 pDev ) throws UsbException {
60
        dev = pDev;
61
 
62
        handle = LibusbJava.usb_open(dev.dev());
63
//      if ( handle<=0 ) 
64
//          throw new UsbException(dev.dev(), "Error opening device");
65
    }
66
 
67
// ******* finalize ************************************************************
68
/** * The destructor closes the USB file handle. */
69
    protected void finalize () {
70
        LibusbJava.usb_close(handle);
71
    }
72
 
73
// ******* handle **************************************************************
74
/** * Returns the USB file handle. */
75
    public final int handle()
76
    {
77
        return handle;
78
    }
79
 
80
// ******* dev *****************************************************************
81
/**
82
  * Returns the corresponding {@link ZtexDevice1}.
83
  * @return the corresponding {@link ZtexDevice1}.
84
  */
85
    public final ZtexDevice1 dev()
86
    {
87
        return dev;
88
    }
89
 
90
// ******* valid ***************************************************************
91
/**
92
  * Returns true if ZTEX descriptor 1 is available.
93
  * @return true if ZTEX descriptor 1 is available.
94
  */
95
    public boolean valid ( ) {
96
        return dev.valid();
97
    }
98
 
99
// ******* checkValid **********************************************************
100
/**
101
  * Checks whether ZTEX descriptor 1 is available.
102
  * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available.
103
  */
104
    public void checkValid () throws InvalidFirmwareException {
105
        if ( ! dev.valid() )
106
            throw new InvalidFirmwareException(this, "Can't read ZTEX descriptor 1");
107
    }
108
 
109
// ******* vendorCommand *******************************************************
110
/**
111
  * Sends a vendor command to Endpoint 0 of the EZ-USB device.
112
  * The command may be send multiple times until the {@link #controlMsgTimeout} is reached.
113
  * @param cmd The command number (0..255).
114
  * @param func The name of the command. This string is used for the generation of error messages.
115
  * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data.
116
  * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data.
117
  * @param length The size of the payload data (0..65535), i.e. bytes 6 and 7 of the setup data.
118
  * @param buf The payload data buffer.
119
  * @return the number of bytes sent.
120
  * @throws UsbException if a communication error occurs.
121
  */
122
    public synchronized int vendorCommand (int cmd, String func, int value, int index, byte[] buf, int length) throws UsbException {
123
        long t0 = new Date().getTime()-100;
124
        int trynum = 0;
125
        int i = -1;
126
        if ( controlMsgTimeout < 200 )
127
            controlMsgTimeout = 200;
128
        while ( i<=0 && new Date().getTime()-t0<controlMsgTimeout ) {            // we repeat the message until the timeout has reached
129
            i = LibusbJava.usb_control_msg(handle, 0x40, cmd, value, index, buf, length, controlMsgTimeout);
130
            if ( certainWorkarounds ) {
131
                try {
132
                    Thread.sleep(2);
133
                }
134
                    catch ( InterruptedException e ) {
135
                }
136
            }
137
            lastVendorCommandT = new Date().getTime();
138
            if ( i < 0 ) {
139
                System.err.println("Warning (try " + (trynum+1) + "): " + LibusbJava.usb_strerror() );
140
                try {
141
                    Thread.sleep( 1 << trynum );                                // we don't want to bother the USB device to often
142
                }
143
                    catch ( InterruptedException e ) {
144
                }
145
                trynum++;
146
            }
147
        }
148
        if ( i < 0 )
149
            throw new UsbException( dev.dev(), (func != null ? func + ": " : "" )+ LibusbJava.usb_strerror());
150
        return i;
151
    }
152
 
153
/**
154
  * Sends a vendor command with no payload data to Endpoint 0 of the EZ-USB device.
155
  * The command may be send multiple times until the {@link #controlMsgTimeout} is reached.
156
  * @param cmd The command number (0..255).
157
  * @param func The name of the command. This string is used for the generation of error messages.
158
  * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data.
159
  * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data.
160
  * @return the number of bytes sent.
161
  * @throws UsbException if a communication error occurs.
162
  */
163
    public int vendorCommand (int cmd, String func, int value, int index) throws UsbException {
164
        byte[] buf = { 0 };
165
        return vendorCommand (cmd, func, value, index, buf, 0);
166
    }
167
 
168
/**
169
  * Sends a vendor command with no payload data and no setup data to Endpoint 0 of the EZ-USB device.
170
  * The command may be send multiple times until the {@link #controlMsgTimeout} is reached.
171
  * @param cmd The command number (0..255).
172
  * @param func The name of the command. This string is used for the generation of error messages.
173
  * @return the number of bytes sent.
174
  * @throws UsbException if a communication error occurs.
175
  */
176
    public int vendorCommand (int cmd, String func) throws UsbException {
177
        byte[] buf = { 0 };
178
        return vendorCommand (cmd, func, 0, 0, buf, 0);
179
    }
180
 
181
// ******* vendorRequest *******************************************************
182
/**
183
  * Sends a vendor request to Endpoint 0 of the EZ-USB device.
184
  * The request may be send multiple times until the {@link #controlMsgTimeout} is reached.
185
  * @param cmd The request number (0..255).
186
  * @param func The name of the request. This string is used for the generation of error messages.
187
  * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data.
188
  * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data.
189
  * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data.
190
  * @param buf The payload data buffer.
191
  * @return the number of bytes received.
192
  * @throws UsbException if a communication error occurs.
193
  */
194
    public synchronized int vendorRequest (int cmd, String func, int value, int index, byte[] buf, int maxlen) throws UsbException {
195
        long t0 = new Date().getTime()-100;
196
        int trynum = 0;
197
        int i = -1;
198
        if ( controlMsgTimeout < 200 )
199
            controlMsgTimeout = 200;
200
        while ( i<=0 && new Date().getTime()-t0<controlMsgTimeout ) {            // we repeat the message until the timeout has reached
201
            /*
202
                The HSNAK mechanism of EP0 usually avoids that a request is sent before a command has been completed.
203
                Unfortunately this mechanism is only 99.99% reliable. Therefore we wait at least 1ms after the last
204
                command has been send before we transmit a new request.
205
            */
206
            long ms = new Date().getTime() - lastVendorCommandT;
207
            if ( ms < 2 ) {     //
208
                try {
209
                    Thread.sleep(1);
210
                }
211
                    catch ( InterruptedException e ) {
212
                }
213
            }
214
 
215
            i = LibusbJava.usb_control_msg(handle, 0xc0, cmd, value, index, buf, maxlen, controlMsgTimeout);
216
            if ( certainWorkarounds ) {
217
                try {
218
                    Thread.sleep(2);
219
                }
220
                    catch ( InterruptedException e ) {
221
                }
222
            }
223
            if ( i < 0 ) {
224
                System.err.println("Warning (try " + (trynum+1) + "): " + LibusbJava.usb_strerror() );
225
                try {
226
                    Thread.sleep( 1 << trynum );                                // we don't want to bother the USB device to often
227
                }
228
                    catch ( InterruptedException e ) {
229
                }
230
                trynum++;
231
            }
232
        }
233
        if ( i < 0 )
234
            throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + LibusbJava.usb_strerror());
235
        return i;
236
    }
237
 
238
/**
239
  * Sends a vendor request to Endpoint 0 of the EZ-USB device.
240
  * The request may be send multiple times until the {@link #controlMsgTimeout} is reached.
241
  * @param cmd The request number (0..255).
242
  * @param func The name of the request. This string is used for the generation of error messages.
243
  * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data.
244
  * @param buf The payload data buffer.
245
  * @return the number of bytes sent.
246
  * @throws UsbException if a communication error occurs.
247
  */
248
    public int vendorRequest (int cmd, String func, byte[] buf, int maxlen) throws UsbException {
249
        return vendorRequest (cmd, func, 0, 0, buf, maxlen);
250
    }
251
 
252
// ******* vendorCommand2 ******************************************************
253
/**
254
  * 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.
255
  * The command may be send multiple times until the {@link #controlMsgTimeout} is reached.
256
  * @param cmd The command number (0..255).
257
  * @param func The name of the command. This string is used for the generation of error messages.
258
  * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data.
259
  * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data.
260
  * @param length The size of the payload data (0..65535), i.e. bytes 6 and 7 of the setup data.
261
  * @param buf The payload data buffer.
262
  * @throws UsbException if a communication error occurs or if not all of the payload has been sent.
263
  */
264
    public synchronized void vendorCommand2 (int cmd, String func, int value, int index, byte[] buf, int length) throws UsbException {
265
        int i = vendorCommand (cmd, func, value, index, buf, length);
266
        if ( i != length )
267
            throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + "Send " + i + " byte of data instead of " + length + " bytes");
268
    }
269
 
270
// ******* vendorRequest2 ******************************************************
271
/**
272
  * 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.
273
  * The request may be send multiple times until the {@link #controlMsgTimeout} is reached.
274
  * @param cmd The request number (0..255).
275
  * @param func The name of the request. This string is used for the generation of error messages.
276
  * @param value The value (0..65535), i.e bytes 2 and 3 of the setup data.
277
  * @param index The index (0..65535), i.e. bytes 4 and 5 of the setup data.
278
  * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data.
279
  * @param buf The payload data buffer.
280
  * @throws UsbException if a communication error occurs or not all of the payload has been received.
281
  */
282
    public void vendorRequest2 (int cmd, String func, int value, int index, byte[] buf, int maxlen) throws UsbException {
283
        int i = vendorRequest(cmd, func, value, index, buf, maxlen);
284
        if ( i != maxlen )
285
            throw new UsbException( dev.dev(), (func != null ? func + ": " : "" ) + "Received " + i + " byte of data, expected "+maxlen+" bytes");
286
    }
287
 
288
/**
289
  * 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.
290
  * The request may be send multiple times until the {@link #controlMsgTimeout} is reached.
291
  * @param cmd The request number (0..255).
292
  * @param func The name of the request. This string is used for the generation of error messages.
293
  * @param maxlen The size of the requested payload data (0..65535), i.e. bytes 6 and 7 of the setup data.
294
  * @param buf The payload data buffer.
295
  * @throws UsbException if a communication error occurs or not all of the payload has been received.
296
  */
297
    public void vendorRequest2 (int cmd, String func, byte[] buf, int maxlen) throws UsbException {
298
        vendorRequest2(cmd, func, 0, 0, buf, maxlen);
299
    }
300
 
301
 
302
 
303
// ******* setConfiguration ****************************************************
304
/**
305
  * Sets the configuration.
306
  * @param config The configuration number (usually 1)
307
  * @throws UsbException if an error occurs while attempting to set the configuration.
308
  */
309
    public void setConfiguration ( int config) throws UsbException{
310
        if ( LibusbJava.usb_set_configuration(handle(), config) < 0 )
311
            throw new UsbException("Setting configuration to " + config + " failed: " + LibusbJava.usb_strerror());
312
    }
313
 
314
 
315
// ******* trySetConfiguration ****************************************************
316
/**
317
  * Tries to set the configuration.
318
  * If an error occurs while attempting to set the configuration, a warning messaage is printed to stderr.
319
  * @param config The configuration number (usually 1)
320
  */
321
    public void trySetConfiguration ( int config) {
322
        if ( LibusbJava.usb_set_configuration(handle(), config) < 0 )
323
            System.err.println("Setting configuration to " + config + " failed: " + LibusbJava.usb_strerror());
324
    }
325
 
326
 
327
// ******* claimInterface ******************************************************
328
/**
329
  * Claims an interface.
330
  * @param iface The interface number (usually 0)
331
  * @throws UsbException if an error occurs while attempting to claim the interface.
332
  */
333
    public void claimInterface ( int iface) throws UsbException{
334
        if ( LibusbJava.usb_claim_interface(handle(), iface) < 0 )
335
            throw new UsbException("Claiming interface " + iface + " failed: " + LibusbJava.usb_strerror());
336
    }
337
 
338
 
339
// ******* releaseInterface ****************************************************
340
/**
341
  * Releases an interface.
342
  * @param iface The interface number (usually 0)
343
  */
344
    public void releaseInterface ( int iface ) {
345
        LibusbJava.usb_release_interface(handle(), iface);
346
    }
347
 
348
 
349
// ******* findOldDevices ******************************************************
350
    private synchronized void findOldDevices () {
351
        Usb_Bus bus = dev.dev().getBus();
352
        usbBusName = bus.getDirname();
353
 
354
        for ( int i=0; i<=127; i++ )
355
            oldDevices[i] = false;
356
 
357
        Usb_Device d = bus.getDevices();
358
        while ( d != null ) {
359
            byte b = d.getDevnum();
360
            if ( b > 0 )
361
                oldDevices[b] = true;
362
            d = d.getNext();
363
        }
364
        oldDevices[dev.dev().getDevnum()] = false;
365
    }
366
 
367
// ******* findNewDevice *******************************************************
368
    private synchronized Usb_Device findNewDevice ( String errMsg ) throws DeviceLostException {
369
        Usb_Device newDev = null;
370
        LibusbJava.usb_find_busses();
371
        LibusbJava.usb_find_devices();
372
 
373
        Usb_Bus bus = LibusbJava.usb_get_busses();
374
        while ( bus != null && ! bus.getDirname().equals(usbBusName) )
375
            bus = bus.getNext();
376
 
377
        Usb_Device d = bus != null ? bus.getDevices() : null;
378
        while ( d != null ) {
379
            byte b = d.getDevnum();
380
            if ( b > 0 && ! oldDevices[b] ) {
381
                if ( newDev != null )
382
                    throw new DeviceLostException( errMsg + "More than 2 new devices found" );
383
                newDev = d;
384
            }
385
            d = d.getNext();
386
        }
387
 
388
        return newDev;
389
    }
390
 
391
// ******* initNewDevice *******************************************************
392
    private void initNewDevice ( String errBase ) throws DeviceLostException, UsbException, InvalidFirmwareException {
393
// scan the bus for up to 60 s for a new device. Boot sequence may take a while.
394
        Usb_Device newDev = null;
395
        for ( int i=0; i<300 && newDev==null; i++ ) {
396
            try {
397
                Thread.sleep( 200 );
398
            }
399
                catch ( InterruptedException e ) {
400
            }
401
            newDev = findNewDevice( errBase + ": " );
402
        }
403
        if ( newDev == null )
404
            throw new DeviceLostException( errBase + ": No new device found" );
405
 
406
// init new device
407
        Usb_Device_Descriptor dd = newDev.getDescriptor();
408
        int vid = dd.getIdVendor() & 65535;
409
        int pid = dd.getIdProduct() & 65535;
410
        try {
411
            dev = new ZtexDevice1( newDev, vid, pid );
412
        }
413
        catch ( InvalidFirmwareException e ) {
414
            if ( vid == ZtexDevice1.cypressVendorId && pid == ZtexDevice1.cypressProductId ) {
415
                dev = new ZtexDevice1( newDev, -1, -1 );
416
            }
417
            else {
418
                throw e;
419
            }
420
        }
421
        handle = LibusbJava.usb_open( dev.dev() );
422
    }
423
 
424
// ******* uploadFirmware ******************************************************
425
/**
426
  * Uploads the firmware to the EZ-USB and manages the renumeration process.
427
  * <p>
428
  * Before the firmware is uploaded the device is set into a reset state.
429
  * After the upload the firmware is booted and the renumeration starts.
430
  * During this process the device disappears from the bus and a new one
431
  * occurs which will be assigned to this class automatically (instead of the disappeared one).
432
  * @param ihxFileName The file name of the firmware image in ihx format. The file can be a regular file or a system resource (e.g. a file from the current jar archive).
433
  * @param force The compatibility check is skipped if true.
434
  * @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)
435
  * @throws FirmwareUploadException If an error occurred while attempting to upload the firmware.
436
  * @throws UsbException if a communication error occurs.
437
  * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available.
438
  * @throws DeviceLostException if a device went lost after renumeration.
439
  */
440
//  returns upload time in ms
441
    public long uploadFirmware ( String ihxFileName, boolean force ) throws IncompatibleFirmwareException, FirmwareUploadException, UsbException, InvalidFirmwareException, DeviceLostException {
442
// load the ihx file
443
        ZtexIhxFile1 ihxFile;
444
        try {
445
            ihxFile = new ZtexIhxFile1( ihxFileName );
446
        }
447
        catch ( IOException e ) {
448
            throw new FirmwareUploadException( e.getLocalizedMessage() );
449
        }
450
        catch ( IhxFileDamagedException e ) {
451
            throw new FirmwareUploadException( e.getLocalizedMessage() );
452
        }
453
//      ihxFile.dataInfo(System.out);
454
//      System.out.println(ihxFile);
455
 
456
// check for compatibility
457
        if ( ! force && dev.valid() ) {
458
            if ( ihxFile.interfaceVersion() != 1 )
459
                throw new IncompatibleFirmwareException("Wrong interface version: Expected 1, got " + ihxFile.interfaceVersion() );
460
 
461
            if ( ! dev.compatible ( ihxFile.productId(0), ihxFile.productId(1), ihxFile.productId(2), ihxFile.productId(3) ) )
462
                throw new IncompatibleFirmwareException("Incompatible productId's: Current firmware: " + ZtexDevice1.byteArrayString(dev.productId())
463
                    + "  Ihx File: " + ZtexDevice1.byteArrayString(ihxFile.productId()) );
464
        }
465
 
466
// scan the bus for comparison
467
        findOldDevices();
468
 
469
// upload the firmware
470
        long time = EzUsb.uploadFirmware( handle, ihxFile );
471
 
472
// find and init new device
473
        initNewDevice("Device lost after uploading Firmware");
474
 
475
        return time;
476
    }
477
 
478
// ******* resetEzUsb **********************************************************
479
/**
480
  * Resets the EZ-USB and manages the renumeration process.
481
  * <p>
482
  * After the reset the renumeration starts.
483
  * During this process the device disappears from the bus and a new one
484
  * occurs which will be assigned to this class automatically (instead of the disappeared one).
485
  * @throws FirmwareUploadException If an error occurred while attempting to upload the firmware.
486
  * @throws UsbException if a communication error occurs.
487
  * @throws InvalidFirmwareException if ZTEX descriptor 1 is not available.
488
  * @throws DeviceLostException if a device went lost after renumeration.
489
  */
490
    public void resetEzUsb () throws FirmwareUploadException, UsbException, InvalidFirmwareException, DeviceLostException {
491
// scan the bus for comparison
492
        findOldDevices();
493
 
494
// reset the EZ-USB
495
        EzUsb.reset(handle,true);
496
        try {
497
            EzUsb.reset(handle,false);          // error (may caused by re-numeration) can be ignored
498
        }
499
        catch ( FirmwareUploadException e ) {
500
        }
501
 
502
// find and init new device
503
        initNewDevice( "Device lost after resetting the EZ-USB" );
504
    }
505
 
506
// ******* toString ************************************************************
507
/**
508
  * Returns a lot of useful information about the corresponding device.
509
  * @return a lot of useful information about the corresponding device.
510
  */
511
    public String toString () {
512
        return dev.toString();
513
    }
514
 
515
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.