Author: tchemit Date: 2014-01-29 18:49:21 +0100 (Wed, 29 Jan 2014) New Revision: 1539 Url: http://forge.codelutin.com/projects/tutti/repository/revisions/1539 Log: refs #3875: Import des mensurations en continue depuis un ictyom?\195?\168tre Modified: trunk/pom.xml trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/IchtyometerClient.java trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReader.java trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderListener.java trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderRecord.java trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/IchtyometerClientTest.java trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderTest.java trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/interactive/CommandEngineTest.java Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/pom.xml 2014-01-29 17:49:21 UTC (rev 1539) @@ -92,6 +92,7 @@ <modules> <module>tutti-persistence</module> + <module>tutti-ichtyometer</module> <module>tutti-service</module> <module>tutti-ui-swing</module> </modules> @@ -443,6 +444,7 @@ <groupId>net.sf.bluecove</groupId> <artifactId>bluecove-gpl</artifactId> <version>${bluecoveVersion}</version> + <scope>runtime</scope> </dependency> <!-- Test --> Modified: trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/IchtyometerClient.java =================================================================== --- trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/IchtyometerClient.java 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/IchtyometerClient.java 2014-01-29 17:49:21 UTC (rev 1539) @@ -63,6 +63,22 @@ private static final Log log = LogFactory.getLog(IchtyometerClient.class); /** + * To keep a cache of discovered remote device. Keys are the name of device, values are the remote device. + */ + protected static Map<String, RemoteDevice> REMOTE_DEVICE_CACHE; + + /** + * To keep a cache of discovered connection url on remote devices. Keys are the name of device, values are + * the connection of the remote device. + */ + protected static Map<String, String> REMOTE_CONNECTION_URL_CACHE; + + public static void clearRemoteDeviceCaches() { + REMOTE_DEVICE_CACHE = null; + REMOTE_CONNECTION_URL_CACHE = null; + } + + /** * Local bluetooth device. */ protected LocalDevice localDevice; @@ -87,6 +103,11 @@ */ protected boolean open; + /** + * Friendly name of the device. + */ + protected String name; + public void open(RemoteDeviceChooser remoteDeviceChooser) throws IOException { Preconditions.checkState(!open, "Client is already opened"); @@ -97,60 +118,73 @@ throw new LocalDeviceNotFoundException(); } - // get remote devices - Map<String, RemoteDevice> devices; - try { - devices = discoverDevices(); - } catch (Exception e) { - throw new RemoteDeviceNotFoundException("Could not detected devices", e); + if (REMOTE_DEVICE_CACHE == null) { + + // build map of remote devices + + try { + REMOTE_DEVICE_CACHE = discoverDevices(); + } catch (Exception e) { + throw new RemoteDeviceNotFoundException("Could not detected devices", e); + } } - if (devices.isEmpty()) { + if (REMOTE_DEVICE_CACHE.isEmpty()) { throw new RemoteDeviceNotFoundException("No remote device found"); } // ask user to choose the device - String userDeviceName = remoteDeviceChooser.chooseRemoteDevice(devices.keySet()); + name = remoteDeviceChooser.chooseRemoteDevice(REMOTE_DEVICE_CACHE.keySet()); - if (userDeviceName == null) { + if (name == null) { throw new RemoteDeviceNotFoundException("User did not choose a remote device"); } - remoteDevice = devices.get(userDeviceName); + remoteDevice = REMOTE_DEVICE_CACHE.get(name); if (remoteDevice == null) { throw new RemoteDeviceNotFoundException( - "Could not find remote device with name '" + userDeviceName + "'"); + "Could not find remote device with name '" + name + "'"); } - int serviceIndex = 3; - List<ServiceRecord> serviceRecords; - try { - serviceRecords = discoverServiceUrls(new UUID(serviceIndex), remoteDevice); - } catch (Exception e) { - throw new RemoteDeviceNotFoundException("Could not read remote device services", e); + if (REMOTE_CONNECTION_URL_CACHE == null) { + REMOTE_CONNECTION_URL_CACHE = Maps.newTreeMap(); } - if (serviceRecords.isEmpty()) { - throw new RemoteDeviceServiceNotFoundException("No services detected."); - } + if (!REMOTE_CONNECTION_URL_CACHE.containsKey(name)) { - if (log.isInfoEnabled()) { - log.info("Found some services for index: " + serviceIndex); - } - serviceRecords.addAll(serviceRecords); + int serviceIndex = 3; + List<ServiceRecord> serviceRecords; + try { + serviceRecords = discoverServiceUrls(new UUID(serviceIndex), remoteDevice); + } catch (Exception e) { + throw new RemoteDeviceNotFoundException("Could not read remote device services", e); + } - // take first service record - ServiceRecord serviceRecord = serviceRecords.get(0); + if (serviceRecords.isEmpty()) { + throw new RemoteDeviceServiceNotFoundException("No services detected."); + } - // get connection url - connectionUrl = serviceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, true); + if (log.isInfoEnabled()) { + log.info("Found some services for index: " + serviceIndex); + } + serviceRecords.addAll(serviceRecords); - String serviceName = IchtyometerClient.getServiceName(serviceRecord); - if (log.isInfoEnabled()) { - log.info("Found service(" + serviceIndex + "): " + connectionUrl + (serviceName == null ? "" : ", name: " + serviceName)); + // take first service record + ServiceRecord serviceRecord = serviceRecords.get(0); + + // get connection url + String connectionUrl = serviceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, true); + + if (log.isInfoEnabled()) { + log.info("Found service(" + serviceIndex + "): " + connectionUrl + ", name: " + name); + } + REMOTE_CONNECTION_URL_CACHE.put(name, connectionUrl); } + // get connection url + connectionUrl = REMOTE_CONNECTION_URL_CACHE.get(name); + open = true; } @@ -197,6 +231,11 @@ return open; } + public String getName() { + checkIsOpened(); + return name; + } + protected void checkIsOpened() { if (!open) { throw new IllegalStateException("Client is not opened!"); Modified: trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReader.java =================================================================== --- trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReader.java 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReader.java 2014-01-29 17:49:21 UTC (rev 1539) @@ -37,7 +37,7 @@ import java.io.IOException; /** - * To read some records from a ichtymoeter in feed mode. + * To read some records from a ichtyometer in feed mode. * <p/> * Created on 1/24/14. * @@ -53,7 +53,7 @@ protected ReadingRunnable readingRunnable; - protected StreamConnection connection; +// protected StreamConnection connection; protected final EventListenerList listenerList; @@ -69,6 +69,20 @@ listenerList.remove(FeedReaderListener.class, listener); } + public boolean containsFeedModeReaderListener(FeedReaderListener listener) { + boolean result = false; + FeedReaderListener[] existingListeners = listenerList.getListeners(FeedReaderListener.class); + if (existingListeners != null) { + for (FeedReaderListener existingListener : existingListeners) { + if (listener == existingListener) { + result = true; + break; + } + } + } + return result; + } + public void start(IchtyometerClient client) throws IOException { Preconditions.checkNotNull(client, "client can not be null"); @@ -76,71 +90,57 @@ this.client = client; // get connection - connection = client.openConnection(); + StreamConnection connection = client.openConnection(); + // get input stream + DataInputStream dataInputStream = connection.openDataInputStream(); + if (log.isDebugEnabled()) { + log.debug("Open data stream: " + dataInputStream); + } + // start a reading stream - readingRunnable = new ReadingRunnable(connection); + readingRunnable = new ReadingRunnable(dataInputStream); - Thread readingThread = new Thread(readingRunnable); +// Thread readingThread = new Thread(readingRunnable); - readingThread.start(); + new Thread(readingRunnable).start(); - waitLock(); +// waitLock(); if (log.isDebugEnabled()) { log.debug("Ready to read remote device..."); } - FeedReaderEvent e = new FeedReaderEvent(this); - fireReaderStart(e); } @Override public void close() throws IOException { + Preconditions.checkNotNull(client, "client can not be null"); + Preconditions.checkState(client.isOpen(), "client must be opened"); + try { - if (readingRunnable != null) { - readingRunnable.setStop(true); - } - waitLock(); + readingRunnable.setStop(true); - if (client != null) { - - if (connection != null) { - client.closeConnection(connection); - } - } - } finally { Closeables.close(client, true); - - FeedReaderEvent e = new FeedReaderEvent(this); - fireReaderStop(e); } } - protected void waitLock() throws IOException { - synchronized (readingRunnable.lock) { - try { - readingRunnable.lock.wait(); - } catch (InterruptedException e) { - throw new IOException("Could not wait..."); - } - } + public String getClientName() { + return client.getName(); } - protected void fireReaderStart(FeedReaderEvent e) { - for (FeedReaderListener listener : listenerList.getListeners(FeedReaderListener.class)) { - listener.readerStart(e); - } - } +// protected void waitLock() throws IOException { +// synchronized (readingRunnable.lock) { +// try { +// readingRunnable.lock.wait(); +// } catch (InterruptedException e) { +// throw new IOException("Could not wait..."); +// } +// } +// } - protected void fireReaderStop(FeedReaderEvent e) { - for (FeedReaderListener listener : listenerList.getListeners(FeedReaderListener.class)) { - listener.readerStop(e); - } - } - protected void fireRecordRead(FeedReaderEvent e) { for (FeedReaderListener listener : listenerList.getListeners(FeedReaderListener.class)) { listener.recordRead(e); @@ -149,9 +149,9 @@ protected class ReadingRunnable implements Runnable { - protected final StreamConnection connection; + protected final DataInputStream dataInputStream; - protected final Object lock = new Object(); +// protected final Object lock = new Object(); protected boolean stop; @@ -159,81 +159,167 @@ this.stop = stop; } - public ReadingRunnable(StreamConnection connection) { - this.connection = connection; + public ReadingRunnable(DataInputStream dataInputStream) { + this.dataInputStream = dataInputStream; } - protected int records; - @Override public void run() { - try { +// try { - if (log.isDebugEnabled()) { - log.debug("Starting... " + this); - } - DataInputStream dataInputStream = connection.openDataInputStream(); + if (log.isDebugEnabled()) { + log.debug("Starting... " + this); + } - if (log.isDebugEnabled()) { - log.debug("Open data stream: " + dataInputStream); - } +// DataInputStream dataInputStream = connection.openDataInputStream(); - synchronized (lock) { - lock.notifyAll(); +// if (log.isDebugEnabled()) { +// log.debug("Open data stream: " + dataInputStream); +// } +// +// notifyOthers(); + + while (!stop) { + +// String result = ""; +// +// // wait until got two \r +// +// int nbR = 0; +// +// String record = null; +// String crc = null; +// while (nbR != 2) { +// +// if (stop) { +// break; +// } +// while (dataInputStream.available() > 0) { +// if (stop) { +// break; +// } +// int c = dataInputStream.read(); +// +// if (c == '\r') { +// +// nbR++; +// if (nbR == 1) { +// record = result; +// if (log.isDebugEnabled()) { +// log.debug("Get record: " + record); +// } +// result = ""; +// } else if (nbR == 2) { +// crc = result; +// if (log.isDebugEnabled()) { +// log.debug("Get crc: " + crc); +// } +// } +// } else { +// +// result += (char) c; +// } +// } +// } +// +// if (stop) { +// break; +// } +// if (log.isDebugEnabled()) { +// log.debug(String.format("Record: %s / %s", record, crc)); +// } + + + try { + FeedReaderRecord readerRecord = readRecord(dataInputStream); + + if (!stop) { + FeedReaderEvent e = new FeedReaderEvent(FeedReader.this, readerRecord); + fireRecordRead(e); + } + } catch (IOException e) { + if (log.isErrorEnabled()) { + log.error("Could not read record", e); + } } - while (!stop) { - String result = ""; - // wait until got two \r + } - int nbR = 0; + if (log.isInfoEnabled()) { + log.info("Reader thread stop..." + this); + } - String record = null; - String crc = null; - while (nbR != 2) { +// } catch (IOException e) { +// if (log.isErrorEnabled()) { +// log.error("Reading error", e); +// } +// } finally { +// +// notifyOthers(); +// } - while (dataInputStream.available() > 0) { - int c = dataInputStream.read(); + } - if (c == '\r') { - nbR++; - if (nbR == 1) { - record = result; - if (log.isDebugEnabled()) { - log.debug("Get record: " + record); - } - result = ""; - } else if (nbR == 2) { - crc = result; - if (log.isDebugEnabled()) { - log.debug("Get crc: " + crc); - } - } - } else { + protected FeedReaderRecord readRecord(DataInputStream dataInputStream) throws IOException { + String result = ""; - result += (char) c; + // wait until got two \r + + int nbR = 0; + + String record = null; + String crc = null; + while (nbR != 2) { + + if (stop) { + break; + } + while (dataInputStream.available() > 0) { + if (stop) { + break; + } + int c = dataInputStream.read(); + + if (c == '\r') { + + nbR++; + if (nbR == 1) { + record = result; + if (log.isDebugEnabled()) { + log.debug("Get record: " + record); } + result = ""; + } else if (nbR == 2) { + crc = result; + if (log.isDebugEnabled()) { + log.debug("Get crc: " + crc); + } } - } + } else { - if (log.isDebugEnabled()) { - log.debug(String.format("Record: %s / %s", record, crc)); + result += (char) c; } - FeedReaderRecord readerRecord = new FeedReaderRecord(record, crc); - FeedReaderEvent e = new FeedReaderEvent(FeedReader.this, readerRecord); - fireRecordRead(e); } + } - if (log.isInfoEnabled()) { - log.info("Will stop " + this); + FeedReaderRecord readerRecord = null; + + if (!stop) { + + if (log.isDebugEnabled()) { + log.debug(String.format("Record: %s / %s", record, crc)); } - } catch (IOException e) { - if (log.isErrorEnabled()) { - log.error("Reading error", e); - } + readerRecord = new FeedReaderRecord(record, crc); } + return readerRecord; } + +// protected void notifyOthers() { +// synchronized (lock) { +// lock.notifyAll(); +// } +// } } } Modified: trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderListener.java =================================================================== --- trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderListener.java 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderListener.java 2014-01-29 17:49:21 UTC (rev 1539) @@ -27,6 +27,8 @@ import java.util.EventListener; /** + * To listen records from the ichtyometer. + * <p/> * Created on 1/24/14. * * @author Tony Chemit <chemit@codelutin.com> @@ -34,10 +36,6 @@ */ public interface FeedReaderListener extends EventListener { - void readerStart(FeedReaderEvent event); - - void readerStop(FeedReaderEvent event); - void recordRead(FeedReaderEvent event); } Modified: trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderRecord.java =================================================================== --- trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderRecord.java 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/tutti-ichtyometer/src/main/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderRecord.java 2014-01-29 17:49:21 UTC (rev 1539) @@ -41,90 +41,83 @@ /** Logger. */ private static final Log log = LogFactory.getLog(FeedReaderRecord.class); - protected float length; + protected final String record; - protected float weight; + protected final String crc; - protected String species; + protected final String computedCrc; - protected String cruise; + protected final Float length; - protected String station; + protected boolean valid; - protected String pan; - - protected String sizeClass; - - protected String gender; - - protected String text; - - protected final String record; - - protected final String crc; - public static String computeCRC(String record) { // use long because int are signed and add doesn't work correctly long checksum = 0; + // to keep using 4 octets (32bites) long mask = 0b0000000000000000000000000000000011111111111111111111111111111111L; for (int i = 0, recordLength = record.length(); i < recordLength; i++) { + // keep only the first 32 bites checksum = checksum & mask; + // get msb bite value long msb = checksum >> 31; log.debug(String.format("i=%4d char=%s(int:%3d) incoming checksum=%10d msb=%d bits=%33s", i, record.charAt(i), (int) record.charAt(i), checksum, msb, Long.toBinaryString(checksum))); - // get msb - // logical shift left checksum <<= 1; log.debug(String.format("After lef shift : %33s", Long.toBinaryString(checksum))); - // MSB becomes LSB + // rotates msb to lsb checksum += msb; log.debug(String.format("After add smb : %33s", Long.toBinaryString(checksum))); - // add new car + // add new caracter checksum += record.charAt(i); log.debug(String.format("After add car : %33s", Long.toBinaryString(checksum))); } + // get a hexadecimal on 32bites -> 8 hexadecimal caracters String hex = Long.toHexString(checksum).toUpperCase(); log.debug("checksum= " + checksum); return hex; } - public static FeedReaderRecord newRecord(String record, String crc) { + public FeedReaderRecord(String record, String crc) { + this.record = record; + this.crc = crc; + this.computedCrc = computeCRC(record); - // do the crc check -// record = record.trim(); + Float length; + try { + String[] cells = record.split("\\s*,\\s*"); + String lengthCell = cells[0]; + // remove any spaces + lengthCell = lengthCell.replaceAll("\\s*", ""); - String checksum = computeCRC(record); + // remove any starting 0 + lengthCell = lengthCell.replaceAll("^0*", ""); - if (log.isInfoEnabled()) { - log.info("Incoming crc: " + crc); - log.info("Computed crc: " + checksum); + length = Float.valueOf(lengthCell) / 10; + } catch (Exception e) { + if (log.isErrorEnabled()) { + log.error("Could not get length from " + record, e); + } + length = null; } + this.length = length; - if (!crc.equals(checksum)) { - throw new IllegalArgumentException("Invalid record (" + record + "), CRC verification failed"); - } - FeedReaderRecord result = new FeedReaderRecord(record, crc); - return result; + //FIXME Uncomment when computedCrc will be ok + this.valid = length != null; /*&& crc.equals(computedCrc);*/ } - protected FeedReaderRecord(String record, String crc) { - this.record = record; - this.crc = crc; - } - public boolean isValid() { - //TODO crc check - return true; + return valid; } public String getRecord() { @@ -135,11 +128,22 @@ return crc; } + public String getComputedCrc() { + return computedCrc; + } + + public Float getLength() { + return length; + } + @Override public String toString() { return new ToStringBuilder(this) .append("record", record) .append("crc", crc) + .append("computedCrc", computedCrc) + .append("valid", valid) + .append("length", length) .toString(); } } Modified: trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/IchtyometerClientTest.java =================================================================== --- trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/IchtyometerClientTest.java 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/IchtyometerClientTest.java 2014-01-29 17:49:21 UTC (rev 1539) @@ -51,7 +51,7 @@ }; IchtyometerClient client = new IchtyometerClient(); try { - client.open(remoteDeviceChooser); + client.open(remoteDeviceChooser, ); client.close(); } catch (IOException e) { Assume.assumeTrue("Could not connect to remote device", true); Modified: trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderTest.java =================================================================== --- trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderTest.java 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/feed/FeedReaderTest.java 2014-01-29 17:49:21 UTC (rev 1539) @@ -63,7 +63,7 @@ client = new IchtyometerClient(); try { - client.open(remoteDeviceChooser); + client.open(remoteDeviceChooser, ); } catch (IOException e) { Assume.assumeTrue("Could not connect to remote device", false); } @@ -83,17 +83,8 @@ FeedReader reader = new FeedReader(); FeedReaderListener listener = new FeedReaderListener() { - @Override - public void readerStart(FeedReaderEvent event) { - log.info("Reader " + event.getSource() + " is ready to rock!"); - } @Override - public void readerStop(FeedReaderEvent event) { - log.info("Reader " + event.getSource() + " is going to bed now!"); - } - - @Override public void recordRead(FeedReaderEvent event) { log.info("Reader " + event.getSource() + " read : " + event.getRecord()); } Modified: trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/interactive/CommandEngineTest.java =================================================================== --- trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/interactive/CommandEngineTest.java 2014-01-29 17:47:27 UTC (rev 1538) +++ trunk/tutti-ichtyometer/src/test/java/fr/ifremer/tutti/ichtyometer/interactive/CommandEngineTest.java 2014-01-29 17:49:21 UTC (rev 1539) @@ -64,7 +64,7 @@ client = new IchtyometerClient(); try { - client.open(remoteDeviceChooser); + client.open(remoteDeviceChooser, ); } catch (IOException e) { if (log.isErrorEnabled()) { log.error("Could not connect to bigfin", e);