Lepton3Telemetry.java 12.3 KB
Newer Older
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
/**
 ** -----------------------------------------------------------------------------**
 ** Lepton3Telemetry.java
 **
 ** Parses FLIR Lepton3 telemetry data
 **
 ** Copyright (C) 2019 Elphel, Inc.
 **
 ** -----------------------------------------------------------------------------**
 **
 **  Lepton3Telemetry.java is free software: you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License as published by
 **  the Free Software Foundation, either version 3 of the License, or
 **  (at your option) any later version.
 **
 **  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/>.
 ** -----------------------------------------------------------------------------**
 **
 */
package com.elphel.imagej.readers;

import java.nio.ByteBuffer;
import java.util.HashMap;

public class Lepton3Telemetry {
Andrey Filippov's avatar
Andrey Filippov committed
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
	private static final int LEPTON3_IMAGE_WIDTH =     160;
	private static final int LEPTON3_IMAGE_HEIGHT =    120;
	private static final int LEPTON3_TELEMETRY_LINES =   2;
	private static final String REVISION =      "REVISION";      private static final int REVISION_OFFSET =       0;
	private static final String UPTIME =        "UPTIME";        private static final int UPTIME_OFFSET =         1;
	private static final String STATUS =        "STATUS";        private static final int STATUS_OFFSET =         3;
	private static final String MOD_SER =       "MOD_SER";       private static final int MOD_SER_OFFSET =        5;
	private static final String SOFT_REV =      "SOFT_REV";      private static final int SOFT_REV_OFFSET =      13;
	private static final String FRAME =         "FRAME";         private static final int FRAME_OFFSET =         20;
	private static final String MEAN =          "MEAN";          private static final int MEAN_OFFSET =          22;
	private static final String FPA_TCNT =      "FPA_TCNT";      private static final int FPA_TCNT_OFFSET =      23;
	private static final String FPA_KELV =      "FPA_KELV";      private static final int FPA_KELV_OFFSET =      24;
	private static final String ENCL_TCNT =     "ENCL_TCNT";     private static final int ENCL_TCNT_OFFSET =     25;
	private static final String ENCL_KELV =     "ENCL_KELV";     private static final int ENCL_KELV_OFFSET =     26;
	private static final String FFC_KELV =      "FFC_KELV";      private static final int FFC_KELV_OFFSET =      29;
	private static final String FFC_TIME =      "FFC_TIME";      private static final int FFC_TIME_OFFSET =      30;
	private static final String ENCL_FFC_KELV = "ENCL_FFC_KELV"; private static final int ENCL_FFC_KELV_OFFSET = 32;
	private static final String AGC_ROI_TLBR =  "AGC_ROI_TLBR";  private static final int AGC_ROI_TLBR_OFFSET =  34;
	private static final String AGC_CLIP_HIGH = "AGC_CLIP_HIGH"; private static final int AGC_CLIP_HIGH_OFFSET = 38;
	private static final String AGC_CLIP_LOW =  "AGC_CLIP_LOW";  private static final int AGC_CLIP_LOW_OFFSET =  38;
	private static final String VFORMAT =       "VFORMAT";       private static final int VFORMAT_OFFSET =       72;
	private static final String FFC_LOG2 =      "FFC_LOG2";      private static final int FFC_LOG2_OFFSET =      74;
	private static final String EMISS_8192 =    "EMISS_8192";    private static final int EMISS_8192_OFFSET =    19 + 80; // row B
	private static final String BGND_KELV =     "BGND_KELV";     private static final int BGND_KELV_OFFSET =     20 + 80;
	private static final String ATMOSPH_8192 =  "ATMOSPH_8192";  private static final int ATMOSPH_8192_OFFSET =  21 + 80;
	private static final String ATMOSPH_KELV =  "ATMOSPH_KELV";  private static final int ATMOSPH_KELV_OFFSET =  22 + 80;
	private static final String WND_TRANS_8192 ="WND_TRANS_8192";private static final int WND_TRANS_8192_OFFSET =23 + 80;
	private static final String WND_REFL_8192 = "WND_REFL_8192"; private static final int WND_REFL_8192_OFFSET = 24 + 80;
	private static final String WND_KELV =      "WND_KELV";      private static final int WND_KELV_OFFSET =      25 + 80;
	private static final String WND_REFL_KELV = "WND_REFL_KELV"; private static final int WND_REFL_KELV_OFFSET = 26 + 80;
	private static final String GAIN_MODE =     "GAIN_MODE";     private static final int GAIN_MODE_OFFSET =      5 + 160; // row C
	private static final String GAIN_EFF =      "GAIN_EFF";      private static final int GAIN_EFF_OFFSET =       6 + 160;
	private static final String GAIN_DFLAG =    "GAIN_DFLAG";    private static final int GAIN_DFLAG_OFFSET =     7 + 160;
	private static final String GAIN_THR_HL_C = "GAIN_THR_HL_C"; private static final int GAIN_THR_HL_C_OFFSET =  8 + 160;
	private static final String GAIN_THR_LH_C = "GAIN_THR_LH_C"; private static final int GAIN_THR_LH_C_OFFSET =  9 + 160;
	private static final String GAIN_THR_HL_K = "GAIN_THR_HL_K"; private static final int GAIN_THR_HL_K_OFFSET = 10 + 160;
	private static final String GAIN_THR_LH_K = "GAIN_THR_LH_K"; private static final int GAIN_THR_LH_K_OFFSET = 11 + 160;
	private static final String GAIN_HL_PP =    "GAIN_HL_PP";    private static final int GAIN_HL_PP_OFFSET =    14 + 160;
	private static final String GAIN_LH_PP =    "GAIN_LH_PP";    private static final int GAIN_LH_PP_OFFSET =    15 + 160;
	private static final String GAIN_ROI_TLBR = "GAIN_ROI_TLBR"; private static final int GAIN_ROI_TLBR_OFFSET = 22 + 160;
	private static final String TLIN_EN =       "TLIN_EN";       private static final int TLIN_EN_OFFSET =       48 + 160;
	private static final String TLIN_RESOL =    "TLIN_RESOL";    private static final int TLIN_RESOL_OFFSET =    49 + 160;
	private static final String SPOT_AVG_KELV = "SPOT_AVG_KELV"; private static final int SPOT_AVG_KELV_OFFSET = 50 + 160;
	private static final String SPOT_MAX_KELV = "SPOT_MAX_KELV"; private static final int SPOT_MAX_KELV_OFFSET = 51 + 160;
	private static final String SPOT_MIN_KELV = "SPOT_MIN_KELV"; private static final int SPOT_MIN_KELV_OFFSET = 52 + 160;
	private static final String SPOT_POP_PERC = "SPOT_POP_PERC"; private static final int SPOT_POP_PERC_OFFSET = 53 + 160;
	private static final String SPOT_ROI_TLBR = "SPOT_ROI_TLBR"; private static final int SPOT_ROI_TLBR_OFFSET = 54 + 160;
79

80 81 82 83 84 85 86 87 88 89 90 91


	private float [] pixels =  null;
	private byte  [] btm =     null;
	private ByteBuffer bbtm  = null;

	public Lepton3Telemetry(ByteBuffer bb, float [] pixels, boolean bottom) {
		this.pixels = pixels;
		int offset = 2*(bottom?(LEPTON3_IMAGE_WIDTH * LEPTON3_IMAGE_HEIGHT):0);
		if (pixels.length > LEPTON3_IMAGE_WIDTH*LEPTON3_IMAGE_HEIGHT) {
			this.btm = new byte [LEPTON3_IMAGE_WIDTH* LEPTON3_TELEMETRY_LINES * 2];
			bb.position(offset);
92 93 94 95 96 97 98 99 100 101
			byte dbg = bb.get();
			dbg = bb.get();
			dbg = bb.get();
			dbg = bb.get();
			dbg = bb.get();
			bb.position(offset);

//			this.bbtm =
			bb.get(btm, 0,btm.length);
			this.bbtm = ByteBuffer.wrap(btm);
102 103 104 105 106 107 108 109 110 111
			this.bbtm.order( bb.order()); // or is it already same as in bb?
			this.pixels = new float [LEPTON3_IMAGE_WIDTH * LEPTON3_IMAGE_HEIGHT];
			System.arraycopy(
					pixels,
					(bottom? 0: LEPTON3_IMAGE_WIDTH * LEPTON3_TELEMETRY_LINES),
					this.pixels,
					0,
					this.pixels.length);
		}
	}
Andrey Filippov's avatar
Andrey Filippov committed
112 113 114
	public static int getWidth() {
		return LEPTON3_IMAGE_WIDTH;
	}
115

Andrey Filippov's avatar
Andrey Filippov committed
116 117 118 119 120 121 122 123
	public static int getHeight() {
		return LEPTON3_IMAGE_HEIGHT;
	}
	
	public static int getTelemetryLines() {
		return LEPTON3_TELEMETRY_LINES;
	}
	
124 125 126 127 128 129 130 131 132 133 134
	public boolean hasTelemetry() {
		return bbtm != null;
	}

	public float [] getPixels() {
		return pixels;
	}

	public HashMap<String, String> parseTelemetry(){
		HashMap<String, String> tm = new HashMap<String, String>();
		byte [] bytes = getBytes(REVISION_OFFSET,2);
135 136 137 138 139 140 141 142 143 144 145
		tm.put(REVISION,       "" + bytes[1] + "." + bytes[0]);
		tm.put(UPTIME,         String.format("%.3f", getSeconds (UPTIME_OFFSET)));
		tm.put(STATUS,         "" + getU32     (STATUS_OFFSET));
		tm.put(MOD_SER,        "" + getHex     (MOD_SER_OFFSET,8));
		tm.put(SOFT_REV,       "" + getHex     (SOFT_REV_OFFSET,4));
		tm.put(FPA_TCNT,       "" + getU16     (FPA_TCNT_OFFSET));
		tm.put(FPA_KELV,       String.format("%.2f", getKelv    (FPA_KELV_OFFSET)));
		tm.put(ENCL_TCNT,      "" + getU16     (ENCL_TCNT_OFFSET));
		tm.put(ENCL_KELV,      String.format("%.2f", getKelv    (ENCL_KELV_OFFSET)));
		tm.put(FFC_KELV,       String.format("%.2f", getKelv    (FFC_KELV_OFFSET)));
		tm.put(FFC_TIME,       String.format("%.3f", getSeconds (FFC_TIME_OFFSET)));
146

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
		tm.put(ENCL_FFC_KELV,  String.format("%.2f", getKelv    (ENCL_FFC_KELV_OFFSET)));
		tm.put(AGC_ROI_TLBR,
				"" +  getU16 (AGC_ROI_TLBR_OFFSET) +
				" " + getU16 (AGC_ROI_TLBR_OFFSET + 1) +
				" " + getU16 (AGC_ROI_TLBR_OFFSET + 2) +
				" " + getU16 (AGC_ROI_TLBR_OFFSET + 3));
		tm.put(AGC_CLIP_HIGH,  "" + getU16     (AGC_CLIP_HIGH_OFFSET));
		tm.put(AGC_CLIP_LOW,   "" + getU16     (AGC_CLIP_LOW_OFFSET));
		tm.put(VFORMAT,        "" + getU32     (VFORMAT_OFFSET));
		tm.put(FFC_LOG2,       "" + getU16     (FFC_LOG2_OFFSET));

		tm.put(EMISS_8192,     "" + getU16     (EMISS_8192_OFFSET));
		tm.put(BGND_KELV,      String.format("%.2f", getKelv    (BGND_KELV_OFFSET)));
		tm.put(ATMOSPH_8192,   "" + getU16     (ATMOSPH_8192_OFFSET));
		tm.put(ATMOSPH_KELV,   String.format("%.2f", getKelv    (ATMOSPH_KELV_OFFSET)));
		tm.put(WND_TRANS_8192, "" + getU16     (WND_TRANS_8192_OFFSET));
		tm.put(WND_REFL_8192,  "" + getU16     (WND_REFL_8192_OFFSET));
		tm.put(WND_KELV,       String.format("%.2f", getKelv    (WND_KELV_OFFSET)));
		tm.put(WND_REFL_KELV,  String.format("%.2f", getKelv    (WND_REFL_KELV_OFFSET)));
		tm.put(GAIN_MODE,      "" + getU16     (GAIN_MODE_OFFSET));
		tm.put(GAIN_EFF,       "" + getU16     (GAIN_EFF_OFFSET));
		tm.put(GAIN_DFLAG,     "" + getU16     (GAIN_DFLAG_OFFSET));
		tm.put(GAIN_THR_HL_C,  "" + getU16     (GAIN_THR_HL_C_OFFSET));
		tm.put(GAIN_THR_LH_C,  "" + getU16     (GAIN_THR_LH_C_OFFSET));
		tm.put(GAIN_THR_HL_K,  "" + getU16     (GAIN_THR_HL_K_OFFSET));
		tm.put(GAIN_THR_LH_K,  "" + getU16     (GAIN_THR_LH_K_OFFSET));
		tm.put(GAIN_HL_PP,     "" + getU16     (GAIN_HL_PP_OFFSET));
		tm.put(GAIN_LH_PP,     "" + getU16     (GAIN_LH_PP_OFFSET));
		tm.put(GAIN_ROI_TLBR,
				"" +  getU16 (GAIN_ROI_TLBR_OFFSET) +
				" " + getU16 (GAIN_ROI_TLBR_OFFSET + 1) +
				" " + getU16 (GAIN_ROI_TLBR_OFFSET + 2) +
				" " + getU16 (GAIN_ROI_TLBR_OFFSET + 3));
		tm.put(TLIN_EN,        "" + getU16 (TLIN_EN_OFFSET));
		tm.put(TLIN_RESOL,     "" + getU16     (TLIN_RESOL_OFFSET));
		tm.put(SPOT_AVG_KELV,  String.format("%.2f", getKelv    (SPOT_AVG_KELV_OFFSET)));
		tm.put(SPOT_MAX_KELV,  String.format("%.2f", getKelv    (SPOT_MAX_KELV_OFFSET)));
		tm.put(SPOT_MIN_KELV,  String.format("%.2f", getKelv    (SPOT_MIN_KELV_OFFSET)));
		tm.put(SPOT_POP_PERC,  "" + getU16     (SPOT_POP_PERC_OFFSET));
		tm.put(SPOT_ROI_TLBR,
				"" +  getU16 (SPOT_ROI_TLBR_OFFSET) +
				" " + getU16 (SPOT_ROI_TLBR_OFFSET + 1) +
				" " + getU16 (SPOT_ROI_TLBR_OFFSET + 2) +
				" " + getU16 (SPOT_ROI_TLBR_OFFSET + 3));
191 192 193 194 195 196 197 198 199 200 201 202 203 204
		return tm;
	}
	// internal methods
	// input byte array depends on tiff endian for short (16-bit) words, but FLIR word sequence is little endian
	private byte[] getBytes (int offset, int len) { // offset in shorts, len in shorts
		byte [] bytes = new byte [2*len];
		for (int i = 0; i<len; i++) {
			int d = (bbtm.getShort(2 * (offset + i))) & 0xffff;
			bytes[2*i+0] = (byte) (d & 0xff);
			bytes[2*i+1] = (byte) ((d >> 8) & 0xff);
		}
		return bytes;
	}

205 206 207 208
//	private String getString (int offset, int len) { // offset in shorts, len in shorts
//		return new String(getBytes(offset, len));
//	}

209 210 211 212 213 214 215 216
	private String getHex (int offset, int len) { // offset in shorts, len in shorts
		String s = "";
		for (byte b :getBytes(offset, len)) {
			s += String.format("%02x", b);
		}
		return s;
	}

217 218 219
	private double getKelv(int offset) {
		return 0.01*((bbtm.getShort(2 * offset)) & 0xffff);
	}
220 221 222 223
	private int getU16(int offset) {
		return (bbtm.getShort(2 * offset)) & 0xffff;
	}

224 225 226 227
	private double getSeconds(int offset) {
		return 0.001*(((long) (bbtm.getShort(2 * offset)) & 0xffff) + (((long) (bbtm.getShort(2 * (offset+1))) & 0xffff) << 16));
	}

228 229 230 231 232 233
	private long getU32(int offset) {
		return ((long) (bbtm.getShort(2 * offset)) & 0xffff) + (((long) (bbtm.getShort(2 * (offset+1))) & 0xffff) << 16);
	}


}