357 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
		
		
			
		
	
	
			357 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
|  | package altimeter;
 | ||
|  | 
 | ||
|  | import gnu.io.CommPortIdentifier;
 | ||
|  | import gnu.io.PortInUseException;
 | ||
|  | import gnu.io.SerialPort;
 | ||
|  | import gnu.io.UnsupportedCommOperationException;
 | ||
|  | 
 | ||
|  | import java.io.FileInputStream;
 | ||
|  | import java.io.FileOutputStream;
 | ||
|  | import java.io.IOException;
 | ||
|  | import java.io.InputStream;
 | ||
|  | import java.io.OutputStream;
 | ||
|  | import java.util.ArrayList;
 | ||
|  | import java.util.Enumeration;
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Class to interface the PerfectFlite Alt15K/WD altimeter.
 | ||
|  |  * 
 | ||
|  |  * Also includes a main method that retrieves all flight profiles and saves them to files.
 | ||
|  |  * 
 | ||
|  |  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
 | ||
|  |  */
 | ||
|  | 
 | ||
|  | public class RotationLogger {
 | ||
|  | 	private static final boolean DEBUG = false;
 | ||
|  | 	
 | ||
|  | 	private static final int BYTES = 65536; 
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	private final CommPortIdentifier portID;
 | ||
|  | 	private SerialPort port = null;
 | ||
|  | 	private InputStream is = null;
 | ||
|  | 	private OutputStream os = null;
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 
 | ||
|  | 	@SuppressWarnings("unchecked")
 | ||
|  | 	public static String[] getNames() {
 | ||
|  | 		ArrayList<String> list = new ArrayList<String>();;
 | ||
|  | 		
 | ||
|  | 		Enumeration pids = CommPortIdentifier.getPortIdentifiers();
 | ||
|  | 
 | ||
|  | 		while (pids.hasMoreElements()) {
 | ||
|  | 		    CommPortIdentifier pid = (CommPortIdentifier) pids.nextElement();
 | ||
|  | 
 | ||
|  | 		    if (pid.getPortType() == CommPortIdentifier.PORT_SERIAL)
 | ||
|  | 		    	list.add(pid.getName());
 | ||
|  | 		}
 | ||
|  | 		return list.toArray(new String[0]);
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 
 | ||
|  | 	@SuppressWarnings("unchecked")
 | ||
|  | 	public RotationLogger(String name) throws IOException {
 | ||
|  | 		CommPortIdentifier portID = null;
 | ||
|  | 		
 | ||
|  | 		Enumeration portIdentifiers = CommPortIdentifier.getPortIdentifiers();
 | ||
|  | 		while (portIdentifiers.hasMoreElements()) {
 | ||
|  | 		    CommPortIdentifier pid = (CommPortIdentifier) portIdentifiers.nextElement();
 | ||
|  | 		    
 | ||
|  | 		    if(pid.getPortType() == CommPortIdentifier.PORT_SERIAL &&
 | ||
|  | 		       pid.getName().equals(name)) {
 | ||
|  | 		        portID = pid;
 | ||
|  | 		        break;
 | ||
|  | 		    }
 | ||
|  | 		}
 | ||
|  | 		
 | ||
|  | 		if (portID==null) {
 | ||
|  | 			throw new IOException("Port '"+name+"' not found.");
 | ||
|  | 		}
 | ||
|  | 		this.portID = portID;
 | ||
|  | 	}
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	public void readData() throws IOException, PortInUseException {
 | ||
|  | 		int c;
 | ||
|  | 		
 | ||
|  | 		int[] data = new int[BYTES];
 | ||
|  | 		
 | ||
|  | 		FileOutputStream rawdump = null;
 | ||
|  | 		
 | ||
|  | 		
 | ||
|  | 		try {
 | ||
|  | 			open();
 | ||
|  | 
 | ||
|  | 			System.err.println("Sending dump mode command...");
 | ||
|  | 			
 | ||
|  | 			for (int i=0; i<16; i++) {
 | ||
|  | 				os.write('D');
 | ||
|  | 				try {
 | ||
|  | 					Thread.sleep(10);
 | ||
|  | 				} catch (InterruptedException ignore) { }
 | ||
|  | 			}
 | ||
|  | 			
 | ||
|  | 			System.err.println("Waiting for response...");
 | ||
|  | 			while (true) {
 | ||
|  | 				c = is.read();
 | ||
|  | 				if (c == 'K') {
 | ||
|  | 					break;
 | ||
|  | 				} else {
 | ||
|  | 					System.err.printf("Received spurious c=%d\n",c);
 | ||
|  | 				}
 | ||
|  | 			}
 | ||
|  | 			
 | ||
|  | 			System.err.println("Received response.");
 | ||
|  | 			
 | ||
|  | 
 | ||
|  | 			
 | ||
|  | 			System.err.println("Opening 'rawdump'...");
 | ||
|  | 			rawdump = new FileOutputStream("rawdump");
 | ||
|  | 			
 | ||
|  | 			
 | ||
|  | 			
 | ||
|  | 			System.err.println("Performing dump...");
 | ||
|  | 
 | ||
|  | 			os.write('A');
 | ||
|  | 
 | ||
|  | 			byte[] buffer = new byte[1024];
 | ||
|  | 			int printCount = 0;
 | ||
|  | 			for (int count=0; count < BYTES; ) {
 | ||
|  | 				if ((BYTES-count) < buffer.length) {
 | ||
|  | 					buffer = new byte[BYTES-count];
 | ||
|  | 				}
 | ||
|  | 				
 | ||
|  | 				int n = is.read(buffer);
 | ||
|  | 				if (n < 0) {
 | ||
|  | 					System.err.println("Error condition, n="+n);
 | ||
|  | 					return;
 | ||
|  | 				}
 | ||
|  | 			
 | ||
|  | 				rawdump.write(buffer, 0, n);
 | ||
|  | 				
 | ||
|  | 				for (int i=0; i<n; i++) {
 | ||
|  | 					data[count+i] = unsign(buffer[i]);
 | ||
|  | 				}
 | ||
|  | 				count += n;
 | ||
|  | 				if (count - printCount > 1024) {
 | ||
|  | 					System.err.println("Read "+count+" bytes...");
 | ||
|  | 					printCount = count;
 | ||
|  | 				}
 | ||
|  | 			}
 | ||
|  | 
 | ||
|  | 
 | ||
|  | 			System.err.println("Verifying checksum...");
 | ||
|  | 			int reported = is.read();
 | ||
|  | 			
 | ||
|  | 			byte computed = 0;
 | ||
|  | 			for (int i=0; i < data.length; i++) {
 | ||
|  | 				computed += data[i];
 | ||
|  | 			}
 | ||
|  | 			if (computed == reported) {
 | ||
|  | 				System.err.println("Checksum ok ("+computed+")");
 | ||
|  | 			} else {
 | ||
|  | 				System.err.println("Error in checksum, computed="+computed+
 | ||
|  | 						" reported="+reported);
 | ||
|  | 			}
 | ||
|  | 			
 | ||
|  | 			System.err.println("Communication done.");
 | ||
|  | 			
 | ||
|  | 		} catch (UnsupportedCommOperationException e) {
 | ||
|  | 			// TODO Auto-generated catch block
 | ||
|  | 			e.printStackTrace();
 | ||
|  | 		} finally {
 | ||
|  | 			close();
 | ||
|  | 			if (rawdump != null)
 | ||
|  | 				rawdump.close();
 | ||
|  | 		}
 | ||
|  | 		
 | ||
|  | 		convertData(data);
 | ||
|  | 		
 | ||
|  | 	}
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	////////////  Data interpretation   //////////////	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	private static void convertData(int[] data) {
 | ||
|  | 
 | ||
|  | 		System.err.println("Converting data...");
 | ||
|  | 
 | ||
|  | 		int lastBuffer = data[0xffff];
 | ||
|  | 		if (lastBuffer < 0 || lastBuffer > 3) {
 | ||
|  | 			System.err.println("Illegal last accessed buffer: "+lastBuffer);
 | ||
|  | 			return;
 | ||
|  | 		}
 | ||
|  | 		System.err.println("Last used buffer: "+lastBuffer);
 | ||
|  | 		
 | ||
|  | 		for (int i=4; i>0; i--) {
 | ||
|  | 			int n = (lastBuffer + i) % 4;
 | ||
|  | 			int bufNumber = 4-i;
 | ||
|  | 			
 | ||
|  | 			convertBuffer(data, n * (BYTES/4), bufNumber);
 | ||
|  | 		}
 | ||
|  | 		
 | ||
|  | 	}
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	private static void convertBuffer(int[] data, int position, int bufNumber) {
 | ||
|  | 		int startPosition;
 | ||
|  | 		
 | ||
|  | 		startPosition = data[position + 0xfd] << 8 + data[position+0xfe];
 | ||
|  | 
 | ||
|  | 		// 50 samples per 128 bytes 
 | ||
|  | 		int startTime = (startPosition -position) * 50 / 128;
 | ||
|  | 		
 | ||
|  | 		System.err.println("  Buffer "+ bufNumber + " (at position "+position+")...");
 | ||
|  | 		System.err.println("  Start position "+startPosition+" time "+startTime);
 | ||
|  | 
 | ||
|  | 		System.out.println("# Buffer "+bufNumber);
 | ||
|  | 		System.out.println("# Start position t="+startTime);
 | ||
|  | 		
 | ||
|  | 		
 | ||
|  | 		int t = 0;
 | ||
|  | 		for (int page = 0; page < 128; page++) {
 | ||
|  | 			int pageStart = position + page * 128;
 | ||
|  | 
 | ||
|  | 			if (pageStart == startPosition) {
 | ||
|  | 				System.out.println("# ---clip---");
 | ||
|  | 			}
 | ||
|  | 
 | ||
|  | 			for (int i=0; i<125; i += 5) {
 | ||
|  | 				int sample1, sample2;
 | ||
|  | 				
 | ||
|  | 				int start = pageStart + i;
 | ||
|  | //				System.err.println("page="+page+" i="+i+
 | ||
|  | //						" position="+position+" pageStart="+pageStart+" start="+start);
 | ||
|  | 				
 | ||
|  | 				sample1 = (data[start] << 2) + (data[start+1] >> 6);
 | ||
|  | 				sample2 = ((data[start+1] & 0x3f) << 4) + (data[start+2] >> 4);
 | ||
|  | 				System.out.printf("%d  %4d  %4d %4d\n", bufNumber, t, sample1, sample2);
 | ||
|  | 				t++;
 | ||
|  | 				
 | ||
|  | 				sample1 = ((data[start+2] & 0x0f) << 6) + (data[start+3] >> 2);
 | ||
|  | 				sample2 = ((data[start+3] & 3) << 8) + data[start+4];
 | ||
|  | 				System.out.printf("%d  %4d  %4d %4d\n", bufNumber, t, sample1, sample2);
 | ||
|  | 				t++;
 | ||
|  | 			}
 | ||
|  | 		}
 | ||
|  | 	}
 | ||
|  | 
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	private void open() throws PortInUseException, IOException, 
 | ||
|  | 			UnsupportedCommOperationException {
 | ||
|  | 		
 | ||
|  | 		if (port != null) {
 | ||
|  | 			System.err.println("ERROR: open() called with port="+port);
 | ||
|  | 			Thread.dumpStack();
 | ||
|  | 			close();
 | ||
|  | 		}
 | ||
|  | 		
 | ||
|  | 		if (DEBUG) {
 | ||
|  | 			System.err.println("  Opening port...");
 | ||
|  | 		}
 | ||
|  | 
 | ||
|  | 		port = (SerialPort)portID.open("OpenRocket",1000);
 | ||
|  | 		
 | ||
|  | 		port.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, 
 | ||
|  | 				SerialPort.PARITY_NONE);
 | ||
|  | 
 | ||
|  | 		port.setInputBufferSize(1);
 | ||
|  | 		port.setOutputBufferSize(1);
 | ||
|  | 
 | ||
|  | 		is = port.getInputStream();
 | ||
|  | 		os = port.getOutputStream();
 | ||
|  | 	}
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	private void close() {
 | ||
|  | 		if (DEBUG)
 | ||
|  | 			System.err.println("  Closing port");
 | ||
|  | 		
 | ||
|  | 		SerialPort p = port;
 | ||
|  | 		port = null;
 | ||
|  | 		is = null;
 | ||
|  | 		if (p != null)
 | ||
|  | 			p.close();
 | ||
|  | 	}
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 	private static int unsign(byte b) {
 | ||
|  | 		if (b >= 0)
 | ||
|  | 			return b;
 | ||
|  | 		else
 | ||
|  | 		return 256 + b;
 | ||
|  | 	}
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | 
 | ||
|  | 	
 | ||
|  | 	public static void main(String[] arg) throws Exception {
 | ||
|  | 		
 | ||
|  | 		if (arg.length > 2) {
 | ||
|  | 			System.err.println("Illegal arguments.");
 | ||
|  | 			return;
 | ||
|  | 		}
 | ||
|  | 		if (arg.length == 1) {
 | ||
|  | 			FileInputStream is = new FileInputStream(arg[0]);
 | ||
|  | 			byte[] buffer = new byte[BYTES];
 | ||
|  | 			int n = is.read(buffer);
 | ||
|  | 			if (n != BYTES) {
 | ||
|  | 				System.err.println("Could read only "+n+" bytes");
 | ||
|  | 				return;
 | ||
|  | 			}
 | ||
|  | 			
 | ||
|  | 			int[] data = new int[BYTES];
 | ||
|  | 			for (int i=0; i<BYTES; i++) {
 | ||
|  | 				data[i] = unsign(buffer[i]);
 | ||
|  | 			}
 | ||
|  | 
 | ||
|  | 			int checksum=0;
 | ||
|  | 			for (int i=0; i<BYTES; i++) {
 | ||
|  | 				checksum += data[i];
 | ||
|  | 			}
 | ||
|  | 			checksum = checksum%256;
 | ||
|  | 			System.err.println("Checksum: "+checksum);
 | ||
|  | 			
 | ||
|  | 			convertData(data);
 | ||
|  | 			return;			
 | ||
|  | 		}
 | ||
|  | 		
 | ||
|  | 		
 | ||
|  | 		String device = null;
 | ||
|  | 		String[] devices = RotationLogger.getNames();
 | ||
|  | 		for (int i=0; i<devices.length; i++) {
 | ||
|  | 			if (devices[i].matches(".*USB.*")) {
 | ||
|  | 				device = devices[i];
 | ||
|  | 				break;
 | ||
|  | 			}
 | ||
|  | 		}
 | ||
|  | 		if (device == null) {
 | ||
|  | 			System.err.println("Device not found.");
 | ||
|  | 			return;
 | ||
|  | 		}
 | ||
|  | 		
 | ||
|  | 		
 | ||
|  | 		System.err.println("Selected device "+device);
 | ||
|  | 		
 | ||
|  | 		
 | ||
|  | 		RotationLogger p = new RotationLogger(device);
 | ||
|  | 		
 | ||
|  | 		p.readData();
 | ||
|  | 		
 | ||
|  | 	}
 | ||
|  | 	
 | ||
|  | 	
 | ||
|  | }
 |