The basic interface to hardware is the HardwareInterface. It is turn has sub-interfaces to various kinds of hardware. You need to implement the appropriate interfaces (e.g. AEMonitorInterface) and if you want to be able to use multiple instances, you also need to make a HardwareInterfaceFactory to build the devices.
Hint: You will need to use Device Manager to see which devices are connected. See http://www.annoyances.org/exec/show/article01-420 for how to make a shortcut to Windows Device Manager.
Devices like the silicon retina use the CypressFX2LP high speed USB interface chip. Under windows, they communicate with jAER via the Thesycon USBIO library. The base class for these interfaces is CypressFX2. Particular devices subclass CypressFX2 to customize the method translateEvents, which takes the raw data bytes and fills the AEPacketRaw objects that hold the raw timestamped events. See for instance the class CypressFX2DVS128HardwareInterface.
Specific steps to make your own CypressFX2 subclass are to
1. Subclass CypressFX2
1. Override the subclass AEReader of CypressFX2 to override, in particular, the method translateEvents
1. Override the method startAEReader to start the subclassed AEReader
The method translate events gets called every time a new packet arrives from hardware. It gets a synchronized referenced to the current AEPacketRaw to write events to (needs to be synchronized because the rendering thread is rendering a different packet). Then it appends the new data to this AEPacketRaw.
Here is an example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | package ch.unizh.ini.caviar.hardwareinterface.usb; import ch.unizh.ini.caviar.aemonitor.AEPacketRaw; import ch.unizh.ini.caviar.hardwareinterface.HardwareInterfaceException; import ch.unizh.ini.caviar.hardwareinterface.HasUpdatableFirmware; import de.thesycon.usbio.UsbIoBuf; import de.thesycon.usbio.UsbIoInterface; import de.thesycon.usbio.structs.USBIO_CLASS_OR_VENDOR_REQUEST; import de.thesycon.usbio.structs.USBIO_DATA_BUFFER; import java.io.IOException; /** * The hardware interface for the DVS128 (second Tmpdiff128 board, with CPLD) retina boards. * * @author tobi/rapha */ public class CypressFX2DVS128HardwareInterface extends CypressFX2Biasgen implements HasUpdatableFirmware { public final static String FIRMWARE_FILENAME_DVS128_XSVF="/ch/unizh/ini/caviar/hardwareinterface/usb/dvs128CPLD.xsvf"; /** Creates a new instance of CypressFX2Biasgen */ protected CypressFX2DVS128HardwareInterface(int devNumber) { super(devNumber); } /** * Starts reader buffer pool thread and enables in endpoints for AEs. This method is overridden to construct our own reader with its translateEvents method */ @Override public void startAEReader() throws HardwareInterfaceException { // raphael: changed from private to protected, because i need to access this method setAeReader(new RetinaAEReader(this)); allocateAEBuffers(); getAeReader().startThread(3); // arg is number of errors before giving up HardwareInterfaceException.clearException(); } /** This reader understands the format of raw USB data and translates to the AEPacketRaw */ public class RetinaAEReader extends CypressFX2.AEReader{ public RetinaAEReader(CypressFX2 cypress) throws HardwareInterfaceException{ super(cypress); } /** Does the translation, timestamp unwrapping and reset * @param b the raw buffer */ @Override protected void translateEvents(UsbIoBuf b){ // System.out.println("buf has "+b.BytesTransferred+" bytes"); synchronized(aePacketRawPool){ AEPacketRaw buffer=aePacketRawPool.writeBuffer(); // if(buffer.overrunOccuredFlag) return; // don't bother if there's already an overrun, consumer must get the events to clear this flag before there is more room for new events int shortts; int NumberOfWrapEvents; NumberOfWrapEvents=0; byte[] aeBuffer=b.BufferMem; // byte lsb,msb; int bytesSent=b.BytesTransferred; if(bytesSent%4!=0){ // System.out.println("CypressFX2.AEReader.translateEvents(): warning: "+bytesSent+" bytes sent, which is not multiple of 4"); bytesSent=(bytesSent/4)*4; // truncate off any extra part-event } int[] addresses=buffer.getAddresses(); int[] timestamps=buffer.getTimestamps(); // write the start of the packet buffer.lastCaptureIndex=eventCounter; for(int i=0;i<bytesSent;i+=4){ if((aeBuffer[i+3]&0x80)==0x80){ // timestamp bit 16 is one -> wrap // now we need to increment the wrapAdd wrapAdd+=0x4000L; //uses only 14 bit timestamps //System.out.println("received wrap event, index:" + eventCounter + " wrapAdd: "+ wrapAdd); NumberOfWrapEvents++; } else if ((aeBuffer[i+3]&0x40)==0x40 ) { // timestamp bit 15 is one -> wrapAdd reset // this firmware version uses reset events to reset timestamps this.resetTimestamps(); // log.info("got reset event, timestamp " + (0xffff&((short)aeBuffer[i]&0xff | ((short)aeBuffer[i+1]&0xff)<<8))); } else if ((eventCounter>aeBufferSize-1) || (buffer.overrunOccuredFlag)) { // just do nothing, throw away events buffer.overrunOccuredFlag=true; } else { // address is LSB MSB addresses[eventCounter]=(int)((aeBuffer[i]&0xFF) | ((aeBuffer[i+1]&0xFF)<<8)); // same for timestamp, LSB MSB shortts=(aeBuffer[i+2]&0xff | ((aeBuffer[i+3]&0xff)<<8)); // this is 15 bit value of timestamp in TICK_US tick timestamps[eventCounter]=(int)(TICK_US*(shortts+wrapAdd)); //*TICK_US; //add in the wrap offset and convert to 1us tick // this is USB2AERmini2 or StereoRetina board which have 1us timestamp tick eventCounter++; buffer.setNumEvents(eventCounter); } } // end for // write capture size buffer.lastCaptureLength=eventCounter-buffer.lastCaptureIndex; // if (NumberOfWrapEvents!=0) { //System.out.println("Number of wrap events received: "+ NumberOfWrapEvents); //} //System.out.println("wrapAdd : "+ wrapAdd); } // sync on aePacketRawPool } } /** set the pixel array reset * @param value true to reset the pixels, false to let them run normally */ synchronized public void setArrayReset(boolean value) { arrayResetEnabled=value; // send vendor request for device to reset array if(gUsbIo==null){ throw new RuntimeException("device must be opened before sending this vendor request"); } // make vendor request structure and populate it USBIO_CLASS_OR_VENDOR_REQUEST VendorRequest=new USBIO_CLASS_OR_VENDOR_REQUEST(); VendorRequest.Flags=UsbIoInterface.USBIO_SHORT_TRANSFER_OK; VendorRequest.Type=UsbIoInterface.RequestTypeVendor; VendorRequest.Recipient=UsbIoInterface.RecipientDevice; VendorRequest.RequestTypeReservedBits=0; VendorRequest.Request=VENDOR_REQUEST_SET_ARRAY_RESET; VendorRequest.Index=0; VendorRequest.Value=(short)(value?1:0); // this is the request bit, if value true, send value 1, false send value 0 USBIO_DATA_BUFFER dataBuffer=new USBIO_DATA_BUFFER(0); // no data, value is in request value dataBuffer.setNumberOfBytesToTransfer(dataBuffer.Buffer().length); status=gUsbIo.classOrVendorOutRequest(dataBuffer,VendorRequest); if(status!=USBIO_ERR_SUCCESS){ System.err.println("CypressFX2.resetPixelArray: couldn't send vendor request to reset array"); } } public boolean isArrayReset(){ return arrayResetEnabled; } /** Updates the firmware by downloading to the board's EEPROM */ public void updateFirmware() throws HardwareInterfaceException { this.writeCPLDfirmware(FIRMWARE_FILENAME_DVS128_XSVF); log.info("New firmware written to CPLD"); byte[] fw; try { fw = this.loadBinaryFirmwareFile(CypressFX2.FIRMWARE_FILENAME_DVS128_IIC); } catch (java.io.IOException e) { e.printStackTrace(); throw new HardwareInterfaceException("Could not load firmware file "); } this.writeEEPROM(0, fw); log.info("New firmware written to EEPROM"); } } |
After you have created your own subclass of CypressFX2, you still need the factory to manufacture it for you. You can do this by adding your factory to the method getInterface(int n) in the CypressFX2Factory, which is shown below. The switch constructs the appropriate HardwareInterface based on the product ID (PID) of the device.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | /** returns the n-th interface in the list, either Tmpdiff128Retina, USBAERmini2 or USB2AERmapper, TCVS320, or MonitorSequencer depending on PID *@param n the number to instance (0 based) */ public USBInterface getInterface(int n) { int numAvailable = getNumInterfacesAvailable(); if (n > numAvailable - 1) { log.warning("Only " + numAvailable + " interfaces available but you asked for number " + n); return null; } UsbIo dev = new UsbIo(); gDevList = UsbIo.createDeviceList(GUID); int status = dev.open(n, gDevList, GUID); if (status != this.USBIO_ERR_SUCCESS) { log.warning(UsbIo.errorText(status)); dev.close(); UsbIo.destroyDeviceList(gDevList); return null; } USB_DEVICE_DESCRIPTOR deviceDescriptor = new USB_DEVICE_DESCRIPTOR(); status = dev.getDeviceDescriptor(deviceDescriptor); if (status != USBIO_ERR_SUCCESS) { UsbIo.destroyDeviceList(gDevList); log.warning(UsbIo.errorText(status)); dev.close(); return null; } dev.close(); UsbIo.destroyDeviceList(gDevList); short pid = (short) (0xffff & deviceDescriptor.idProduct); // for some reason returns 0xffff8613 from blank cypress fx2 switch (pid) { case CypressFX2.PID_USB2AERmapper: return new CypressFX2Mapper(n); case CypressFX2.PID_DVS128_REV0: // case CypressFX2.PID_TMPDIFF128_FX2_SMALL_BOARD: // VID/PID replaced with the ones from thesycon return new CypressFX2DVS128HardwareInterface(n); case CypressFX2.PID_TMPDIFF128_RETINA: return new CypressFX2TmpdiffRetinaHardwareInterface(n); case CypressFX2.PID_TCVS320_RETINA: return new CypressFX2TCVS320RetinaHardwareInterface(n); case CypressFX2.PID_USBAERmini2: return new CypressFX2MonitorSequencer(n); default: log.warning("PID=" + HexString.toString(pid) + " doesn't match any device, returning CypressFX2MonitorSequencer"); return new CypressFX2MonitorSequencer(n); } } |