Coverage for src/susi/io/camera_decode_hk.py: 90%

513 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2025-06-13 14:15 +0000

1""" 

2Decoding of MPS GSENSE camera image data and user HK headers 

3 

4Authors: A. Zerr, K. Heerlein, A. Feller, F. Iglesias 

5""" 

6 

7import sys 

8import numpy as np 

9import struct 

10from enum import Enum 

11from dataclasses import dataclass 

12from bitstring import BitArray 

13 

14from . import camera_definitions as cam_defs 

15from . import camera_calibration_constants as calibration_constants 

16from . import camera_param_convertion as convert 

17 

18from ..base import Logging 

19 

20logger = Logging.get_logger() 

21 

22 

23s_Project_name = "Project Name" 

24s_Camera_Name = "Camera name" 

25s_Camera_ID = "Camera ID" 

26s_Timestamp_us = "Timestamp us" 

27s_Timestamp_ms = "Timestamp ms" 

28s_ImageCounter = "Image Counter" 

29s_Trigger_counter = "Trigger counter" 

30s_Trigger_lost_counter = "Trigger lost counter" 

31s_Number_of_frames = "Number of frames" 

32s_Integration_time = "Integration time" 

33s_FPGA_ID = "FPGA ID" 

34s_Trigger_flag = "Trigger flag" 

35 

36s_PMU_HK7 = "HK_PMUS_I_-12V" 

37s_PMU_HK6 = "HK_PMUS_I_+12V" 

38s_PMU_HK5 = "HK_PMUS_I_+5V" 

39s_PMU_HK4 = "HK_PMUS_TMP" 

40s_PMU_HK3 = "HK_PMU_TMP" 

41s_PMU_HK2 = "HK_PMU_ANG_ERR" 

42s_PMU_HK1 = "HK_PMU_ANG" 

43s_PMU_HK0 = "HK_PMU_CUR" 

44 

45s_MeanSignal = 'Mean Signal' 

46s_timediffus = "Time Difference us" 

47 

48s_Start = 'Start_' 

49s_End = 'End_' 

50 

51s_ADC_CH15 = "ADC15_" + cam_defs.cst_CF_TEMP 

52s_ADC_CH14 = 'ADC14_VTX_H' 

53s_ADC_CH13 = 'ADC13_' + cam_defs.cst_VHDR_L_n 

54s_ADC_CH12 = 'ADC12_' + cam_defs.cst_VRST_L_n 

55s_ADC_CH11 = 'ADC11_VRST_H' 

56s_ADC_CH10 = 'ADC10_' + cam_defs.cst_VTX_L_n 

57s_ADC_CH09 = 'ADC09_VHDR_H' 

58s_ADC_CH08 = 'ADC08_TEST_VREF' 

59s_ADC_CH07 = 'ADC07_VREF' 

60s_ADC_CH06 = 'ADC06_TEST_VSIG' 

61s_ADC_CH05 = 'ADC05_RAMP_VREF' 

62s_ADC_CH04 = 'ADC04_RAMP_VSIG' 

63s_ADC_CH03 = 'ADC03_VDDPIX' 

64s_ADC_CH02 = 'ADC02_' + cam_defs.cst_PCB_TEMP 

65s_ADC_CH01 = 'ADC01_' + cam_defs.cst_CF_TEMP2 

66s_ADC_CH00 = 'ADC00_Util_3p3V' 

67 

68s_DAC_CH15 = cam_defs.kw_DAC15_SPARE 

69s_DAC_CH14 = cam_defs.kw_DAC14_SPARE 

70s_DAC_CH13 = cam_defs.kw_DAC13_TEST_VREF 

71s_DAC_CH12 = cam_defs.kw_DAC12_TEST_VSIG 

72s_DAC_CH11 = cam_defs.kw_DAC11_VDDPIX 

73s_DAC_CH10 = cam_defs.kw_DAC10_RAMP_VREF 

74s_DAC_CH09 = cam_defs.kw_DAC09_VREF 

75s_DAC_CH08 = cam_defs.kw_DAC08_RAMP_VSIG 

76s_DAC_CH07 = cam_defs.kw_DAC07_SPARE 

77s_DAC_CH06 = cam_defs.kw_DAC06_VHDR_H 

78s_DAC_CH05 = cam_defs.kw_DAC05_SPARE 

79s_DAC_CH04 = cam_defs.kw_DAC04_VRST_H 

80s_DAC_CH03 = cam_defs.kw_DAC03_VRST_L 

81s_DAC_CH02 = cam_defs.kw_DAC02_VTX_L 

82s_DAC_CH01 = cam_defs.kw_DAC01_VHDR_L 

83s_DAC_CH00 = cam_defs.kw_DAC00_VTX_H 

84 

85 

86class ValueType(enumerate): 

87 integer = "Integer" 

88 float = "Float" 

89 enum = "Enumeration" 

90 string = "String" 

91 command = "Command" 

92 boolean = "Boolean" 

93 undef = "undefined" 

94 readcur = 'pmHKreadcurr' 

95 readang = 'pmHKreadang' 

96 readangerr = 'pmHKreadangerr' 

97 readtmp = 'pmHKreadtmp' 

98 

99 

100class DataType(Enum): 

101 integer = "Integer" 

102 float = "Float" 

103 enum = "Enumeration" 

104 string = "String" 

105 command = "Command" 

106 boolean = "Boolean" 

107 undef = "undefined" 

108 

109 

110@dataclass 

111class ImageHKStructure: 

112 name: str = "" 

113 word: int = -1 

114 msb: int = 0 

115 lsb: int = 0 

116 type: ValueType = ValueType.undef 

117 trnslate: str = "" 

118 val = [] 

119 converted = [] 

120 formatstr = [] 

121 unit: str = "" 

122 

123 

124@dataclass 

125class DataTypeID: 

126 field_id = 0x80 

127 string = 0x0 

128 int32 = 0x1 

129 int64 = 0x2 

130 float32 = 0x3 

131 float64 = 0x4 

132 

133 

134def calcExpSTD(numlines, SensorTimingCycle): 

135 """calculate the exposure time in seconds, standard mode""" 

136 cst_pixelclk = 25E6 

137 TLine = SensorTimingCycle * 1 / cst_pixelclk # SensorTimingCylce is normally 513 

138 Result = numlines * TLine + 380 * 1 / cst_pixelclk 

139 return Result 

140 

141 

142def getfactoroffset(Aname, cf): 

143 if cam_defs.kw_DAC00_VTX_H in Aname: 

144 factor = cf.f_DAC_cst_VTX_H 

145 offset = cf.o_DAC_cst_VTX_H 

146 elif cam_defs.kw_DAC01_VHDR_L in Aname: 

147 factor = cf.f_DAC_cst_VHDR_L 

148 offset = cf.o_DAC_cst_VHDR_L 

149 elif cam_defs.kw_DAC02_VTX_L in Aname: 

150 factor = cf.f_DAC_cst_VTX_L 

151 offset = cf.o_DAC_cst_VTX_L 

152 elif cam_defs.kw_DAC03_VRST_L in Aname: 

153 factor = cf.f_DAC_cst_VRST_L 

154 offset = cf.o_DAC_cst_VRST_L 

155 elif cam_defs.kw_DAC04_VRST_H in Aname: 

156 factor = cf.f_DAC_cst_VRST_H 

157 offset = cf.o_DAC_cst_VRST_H 

158 elif cam_defs.kw_DAC05_SPARE in Aname: 

159 factor = cf.f_DAC_cst_SPARE 

160 offset = cf.o_DAC_cst_SPARE 

161 elif cam_defs.kw_DAC06_VHDR_H in Aname: 

162 factor = cf.f_DAC_cst_VHDR_H 

163 offset = cf.o_DAC_cst_VHDR_H 

164 elif cam_defs.kw_DAC07_SPARE in Aname: 

165 factor = cf.f_DAC_cst_SPARE 

166 offset = cf.o_DAC_cst_SPARE 

167 elif cam_defs.kw_DAC08_RAMP_VSIG in Aname: 

168 factor = cf.f_DAC_cst_RAMP_VSIG 

169 offset = cf.o_DAC_cst_RAMP_VSIG 

170 elif cam_defs.kw_DAC09_VREF in Aname: 

171 factor = cf.f_DAC_cst_VREF 

172 offset = cf.o_DAC_cst_VREF 

173 elif cam_defs.kw_DAC10_RAMP_VREF in Aname: 

174 factor = cf.f_DAC_cst_RAMP_VREF 

175 offset = cf.o_DAC_cst_RAMP_VREF 

176 elif cam_defs.kw_DAC11_VDDPIX in Aname: 

177 factor = cf.f_DAC_cst_VDDPIX 

178 offset = cf.o_DAC_cst_VDDPIX 

179 elif cam_defs.kw_DAC12_TEST_VSIG in Aname: 

180 factor = cf.f_DAC_cst_TEST_VSIG 

181 offset = cf.o_DAC_cst_TEST_VSIG 

182 elif cam_defs.kw_DAC13_TEST_VREF in Aname: 

183 factor = cf.f_DAC_cst_TEST_VREF 

184 offset = cf.o_DAC_cst_TEST_VREF 

185 elif cam_defs.kw_DAC14_SPARE in Aname: 

186 factor = cf.f_DAC_cst_SPARE 

187 offset = cf.o_DAC_cst_SPARE 

188 elif cam_defs.kw_DAC15_SPARE in Aname: 

189 factor = cf.f_DAC_cst_SPARE 

190 offset = cf.o_DAC_cst_SPARE 

191 return factor, offset 

192 

193 

194def convDACtoBiasV(Aname, valueDec, cf): 

195 """Pass name and dec value and get converted Bias Voltage""" 

196 factor, offsetV = getfactoroffset(Aname, cf) 

197 if isinstance(valueDec, list): 

198 val = [float(x * factor + offsetV) for x in valueDec] 

199 else: 

200 val = valueDec * factor + offsetV 

201 return val 

202 

203 

204def downto_range(bits, i_start, i_end, downto=True): 

205 # convert bit(s) position into slice range. Default format is 'VHDL downto' 

206 if downto: 

207 s_start = -(i_start + 1) 

208 if i_end == 0: 

209 s_end = None 

210 else: 

211 s_end = -i_end 

212 else: 

213 s_start = i_start 

214 s_end = i_end + 1 

215 # get the field from the bits array 

216 field = bits[s_start:s_end] 

217 return field 

218 

219 

220def getCFfromCameraID(id): 

221 if not (id is None): 

222 if id == 2: # EM camera 

223 data = calibration_constants.HardwarefromId_2 

224 elif id == 3: 

225 data = calibration_constants.HardwarefromId_4 

226 elif id == 4: 

227 data = calibration_constants.HardwarefromId_4 

228 elif id == 5: 

229 data = calibration_constants.HardwarefromId_5 

230 elif id == 6: 

231 data = calibration_constants.HardwarefromId_6 

232 elif id == 7: 

233 data = calibration_constants.HardwarefromId_7 

234 elif id == 8: 

235 data = calibration_constants.HardwarefromId_8 

236 else: 

237 data = calibration_constants.HardwarefromId_unknown 

238 logger.warning("setting calibrations Hardware unknown".format()) 

239 else: 

240 logger.error("Error: setHardwarefromBoardId failed - camera register value CAM_ID was None") 

241 return data 

242 

243 

244class ImageHousekeeping(): 

245 

246 def setHKStructure(self): 

247 self.hk_structure = [ 

248 ImageHKStructure(s_Project_name, 0, 63, 0, DataType.string), 

249 ImageHKStructure(s_Camera_Name, 1, 47, 16, DataType.string), 

250 ImageHKStructure(s_Camera_ID, 1, 4, 0, DataType.integer), 

251 ImageHKStructure(s_Timestamp_us, 2, 40, 0, DataType.integer), 

252 ImageHKStructure(s_Timestamp_ms, 3, 63, 32, DataType.integer), 

253 ImageHKStructure(s_ImageCounter, 3, 31, 0, DataType.integer), 

254 ImageHKStructure(s_Trigger_counter, 4, 63, 32, DataType.integer), 

255 ImageHKStructure(s_Trigger_lost_counter, 4, 31, 0, DataType.integer), 

256 ImageHKStructure(s_Number_of_frames, 5, 59, 48, DataType.integer), 

257 ImageHKStructure(s_Integration_time, 5, 47, 24, DataType.integer), 

258 ImageHKStructure(s_FPGA_ID, 5, 23, 8, DataType.integer), 

259 ImageHKStructure(s_Trigger_flag, 5, 0, 0, DataType.integer), 

260 

261 # PMU 

262 ImageHKStructure(s_PMU_HK7, 8, 63, 48, DataType.integer), 

263 ImageHKStructure(s_PMU_HK6, 8, 47, 32, DataType.integer), 

264 ImageHKStructure(s_PMU_HK5, 8, 31, 16, DataType.integer), 

265 ImageHKStructure(s_PMU_HK4, 8, 15, 0, DataType.integer), 

266 ImageHKStructure(s_PMU_HK3, 9, 63, 48, DataType.integer), 

267 ImageHKStructure(s_PMU_HK2, 9, 47, 32, DataType.integer), 

268 ImageHKStructure(s_PMU_HK1, 9, 31, 16, DataType.integer), 

269 ImageHKStructure(s_PMU_HK0, 9, 15, 0, DataType.integer), 

270 

271 # ADC 

272 ImageHKStructure(s_ADC_CH15, 10, 63, 48, DataType.integer), 

273 ImageHKStructure(s_ADC_CH14, 10, 47, 32, DataType.integer), 

274 ImageHKStructure(s_ADC_CH13, 10, 31, 16, DataType.integer), 

275 ImageHKStructure(s_ADC_CH12, 10, 15, 0, DataType.integer), 

276 ImageHKStructure(s_ADC_CH11, 11, 63, 48, DataType.integer), 

277 ImageHKStructure(s_ADC_CH10, 11, 47, 32, DataType.integer), 

278 ImageHKStructure(s_ADC_CH09, 11, 31, 16, DataType.integer), 

279 ImageHKStructure(s_ADC_CH08, 11, 15, 0, DataType.integer), 

280 ImageHKStructure(s_ADC_CH07, 12, 63, 48, DataType.integer), 

281 ImageHKStructure(s_ADC_CH06, 12, 47, 32, DataType.integer), 

282 ImageHKStructure(s_ADC_CH05, 12, 31, 16, DataType.integer), 

283 ImageHKStructure(s_ADC_CH04, 12, 15, 0, DataType.integer), 

284 ImageHKStructure(s_ADC_CH03, 13, 63, 48, DataType.integer), 

285 ImageHKStructure(s_ADC_CH02, 13, 47, 32, DataType.integer), 

286 ImageHKStructure(s_ADC_CH01, 13, 31, 16, DataType.integer), 

287 ImageHKStructure(s_ADC_CH00, 13, 15, 0, DataType.integer), 

288 

289 # DAC 

290 ImageHKStructure(s_DAC_CH15, 14, 63, 48, DataType.integer), 

291 ImageHKStructure(s_DAC_CH14, 14, 47, 32, DataType.integer), 

292 ImageHKStructure(s_DAC_CH13, 14, 31, 16, DataType.integer), 

293 ImageHKStructure(s_DAC_CH12, 14, 15, 0, DataType.integer), 

294 ImageHKStructure(s_DAC_CH11, 15, 63, 48, DataType.integer), 

295 ImageHKStructure(s_DAC_CH10, 15, 47, 32, DataType.integer), 

296 ImageHKStructure(s_DAC_CH09, 15, 31, 16, DataType.integer), 

297 ImageHKStructure(s_DAC_CH08, 15, 15, 0, DataType.integer), 

298 ImageHKStructure(s_DAC_CH07, 16, 63, 48, DataType.integer), 

299 ImageHKStructure(s_DAC_CH06, 16, 47, 32, DataType.integer), 

300 ImageHKStructure(s_DAC_CH05, 16, 31, 16, DataType.integer), 

301 ImageHKStructure(s_DAC_CH04, 16, 15, 0, DataType.integer), 

302 ImageHKStructure(s_DAC_CH03, 17, 63, 48, DataType.integer), 

303 ImageHKStructure(s_DAC_CH02, 17, 47, 32, DataType.integer), 

304 ImageHKStructure(s_DAC_CH01, 17, 31, 16, DataType.integer), 

305 ImageHKStructure(s_DAC_CH00, 17, 15, 0, DataType.integer), 

306 

307 # Sensor register DataIn 

308 ImageHKStructure("SensorReg_DataIn_7", 18, 63, 32, DataType.integer), 

309 ImageHKStructure("SensorReg_DataIn_6", 18, 31, 0, DataType.integer), 

310 ImageHKStructure("SensorReg_DataIn_5", 19, 63, 32, DataType.integer), 

311 ImageHKStructure("SensorReg_DataIn_4", 19, 31, 0, DataType.integer), 

312 ImageHKStructure("SensorReg_DataIn_3", 20, 63, 32, DataType.integer), 

313 ImageHKStructure("SensorReg_DataIn_2", 20, 31, 0, DataType.integer), 

314 ImageHKStructure("SensorReg_DataIn_1", 21, 63, 32, DataType.integer), 

315 ImageHKStructure("SensorReg_DataIn_0", 21, 31, 0, DataType.integer), 

316 

317 # Sensor register DataOut 

318 ImageHKStructure("SensorReg_DataOut_7", 22, 63, 32, DataType.integer), 

319 ImageHKStructure("SensorReg_DataOut_6", 22, 31, 0, DataType.integer), 

320 ImageHKStructure("SensorReg_DataOut_5", 23, 63, 32, DataType.integer), 

321 ImageHKStructure("SensorReg_DataOut_4", 23, 31, 0, DataType.integer), 

322 ImageHKStructure("SensorReg_DataOut_3", 24, 63, 32, DataType.integer), 

323 ImageHKStructure("SensorReg_DataOut_2", 24, 31, 0, DataType.integer), 

324 ImageHKStructure("SensorReg_DataOut_1", 25, 63, 32, DataType.integer), 

325 ImageHKStructure("SensorReg_DataOut_0", 25, 31, 0, DataType.integer), 

326 ImageHKStructure("SensorReg_Temperature", 26, 63, 48, DataType.integer), 

327 

328 # SysMon 

329 ImageHKStructure("SysMon_Status", 27, 61, 60, DataType.integer), 

330 ImageHKStructure("SysMon_Temperature", 27, 57, 48, DataType.integer), 

331 ImageHKStructure("SysMon_VCCINT", 27, 41, 32, DataType.integer), 

332 ImageHKStructure("SysMon_VCCAUX", 27, 25, 16, DataType.integer), 

333 ImageHKStructure("SysMon_VCCBRAM", 27, 9, 0, DataType.integer), 

334 

335 # PID and status 

336 ImageHKStructure("AcquisitionMode", 28, 62, 61, DataType.integer), 

337 ImageHKStructure("HK_Status: hk_adc_busy", 28, 60, 60, DataType.integer), 

338 ImageHKStructure("Trigger_Select", 28, 59, 59, DataType.integer), 

339 ImageHKStructure("HeaterRelays: RLY_HTR_NEG_F", 28, 58, 58, DataType.integer), 

340 ImageHKStructure("HeaterRelays: RLY_HTR_POS_F", 28, 57, 57, DataType.integer), 

341 ImageHKStructure("Heater_Select", 28, 56, 56, DataType.integer), 

342 ImageHKStructure("PID_Status: pid_high_limit_flag", 28, 55, 55, DataType.integer), 

343 ImageHKStructure("PID_Status: pid_low_limit_flag", 28, 54, 54, DataType.integer), 

344 ImageHKStructure("PID_Status: pid_active", 28, 53, 53, DataType.integer), 

345 ImageHKStructure("PID_Config: pid_en", 28, 52, 52, DataType.integer), 

346 ImageHKStructure("PID_Config: select_temp_sensor", 28, 51, 48, DataType.integer), 

347 ImageHKStructure("PID_SetTemperature", 28, 43, 32, DataType.integer), 

348 ImageHKStructure("PID_TemperatureLimit: pid_low_limit", 28, 27, 16, DataType.integer), 

349 ImageHKStructure("PID_TemperatureLimit: pid_high_limit", 28, 11, 0, DataType.integer), 

350 

351 # Image size 

352 ImageHKStructure("Height", 29, 60, 48, DataType.integer), 

353 ImageHKStructure("Width", 29, 44, 32, DataType.integer), 

354 ImageHKStructure("Sensor_RowStart", 29, 27, 16, DataType.integer), 

355 ImageHKStructure("Sensor_RowLength", 29, 11, 0, DataType.integer) 

356 ] 

357 

358 def __init__(self, raw_file_name=None, image_array=None): 

359 self.hk_line = np.zeros(2048 * 2, dtype=">u1") 

360 self.hk_resorted = np.zeros(384 * 64 // 8, dtype=">u1") 

361 self.hk_array64 = [] 

362 self.hk_array32 = [] 

363 self.image_hk = {} 

364 self.user_hk = {} 

365 self.max_field_name_len = 60 

366 self.exit_by_wrong_id = True 

367 self.setHKStructure() 

368 

369 if raw_file_name is not None: 

370 self.file_name = raw_file_name 

371 # read data (byte aligned) from image raw file 

372 image_array = np.fromfile(raw_file_name, dtype="uint8", count=-1) 

373 self.hk_line = self.get_hk_line(image_array) 

374 elif image_array is not None: 

375 # logger.debug("ImageHousekeeping.__init__() - Getting HK line from Image Array") 

376 self.hk_line = self.get_hk_line(image_array) 

377 self.resort_hk_line(self.hk_line) 

378 

379 def get_hk_line(self, image_array): 

380 if image_array.dtype == np.uint16: 

381 hkarray = image_array[-1] 

382 hk_line = np.frombuffer(hkarray.tobytes(), dtype='uint8') 

383 self.hk_line = hk_line 

384 else: 

385 # re-shape to 2D array 

386 image_array = np.reshape(image_array, (2049, 2048 * 2)) 

387 # keep only the line with HKs 

388 self.hk_line = image_array[-1] 

389 return self.hk_line 

390 

391 def resort_hk_line(self, hk_line=None): 

392 # Resort (re-pack) the HK line 

393 # Use input parameter or already read hk line 

394 if hk_line is None: 

395 hk_line = self.hk_line 

396 # resort (re-pack) the bytes 

397 for index in range(len(self.hk_resorted) // 3): 

398 self.hk_resorted[index * 3] = hk_line[index * 4] 

399 self.hk_resorted[index * 3 + 1] = hk_line[index * 4 + 2] << 4 | hk_line[index * 4 + 1] 

400 self.hk_resorted[index * 3 + 2] = hk_line[index * 4 + 3] << 4 | hk_line[index * 4 + 2] >> 4 

401 # Store as array of 4bits words 

402 for index in range(len(self.hk_resorted) // 8): 

403 self.hk_array64.append(np.frombuffer(self.hk_resorted[index * 8:index * 8 + 8].tobytes(), ">u8")[-1]) 

404 return self.hk_array64 

405 

406 def get_image_hk(self): 

407 # Extract single HKs from the HK line 

408 # Use input parameter or already read hk line 

409 if not self.hk_array64: 

410 self.image_hk = {} 

411 logger.error("Array hk_array64 is empty! Can't extract image HKs") 

412 else: 

413 # extract single fields from the HK array 

414 for field in self.hk_structure: 

415 rawvalue = [] 

416 value: BitArray 

417 word = BitArray("0x{:>016X}".format(self.hk_array64[field.word])) 

418 # get field value (field msb downto lsb) 

419 value = downto_range(word, field.msb, field.lsb) 

420 # check data type: string or unsigned integer 

421 if field.name == s_Camera_ID: 

422 HWInfofromID = getCFfromCameraID(value.int) 

423 cf = HWInfofromID[calibration_constants.s_calibration] 

424 

425 rawvalue.append(value.uint) 

426 field.formatstr = '{:}' 

427 field.converted = [] 

428 field.converted.append('{:} {:}'.format(HWInfofromID[cam_defs.s_hardwareid], HWInfofromID[ 

429 cam_defs.s_model])) 

430 elif field.type == DataType.string: 

431 # convert 64 ASCII value to string (uint -> bytes -> string) 

432 str_length = (field.msb - field.lsb + 1) // 8 # calculate the string length 

433 rawvalue.append(int(value.int).to_bytes(str_length, "big").decode()) 

434 field.converted = [] 

435 field.formatstr = '{:s}' 

436 

437 else: 

438 # Unsigned integer 

439 rawvalue.append(value.uint) 

440 converted, formatstr, unitstr = decodeHK(field.name, rawvalue, cf) 

441 

442 if isinstance(converted, list): 

443 field.converted = converted 

444 else: 

445 field.converted = [] 

446 field.converted.append(converted) 

447 field.formatstr = formatstr 

448 field.unit = unitstr 

449 

450 field.val = rawvalue 

451 

452 # Store image HKs in dictionary 

453 self.image_hk[field.name] = field 

454 # Check the header 

455 hk_header = self.hk_structure[0].val[0] 

456 if hk_header != "Sunrise3": 

457 logger.warning("Image HK header is wrong! Expected: Sunrise3, got: {}".format(hk_header)) 

458 return self.image_hk 

459 

460 def get_user_hk(self): 

461 # Use input parameter or already read hk line 

462 if not self.hk_array64: 

463 self.user_hk = {} 

464 logger.error("Array hk_array64 is empty! Can't extract user HKs") 

465 else: 

466 # split the 64bits into 32bits 

467 for word64 in self.hk_array64[64:319]: 

468 self.hk_array32.append(int(word64) & 0xFFFFFFFF) 

469 self.hk_array32.append(int(word64) >> 32) 

470 

471 # get user HKs 

472 self.user_hk = self.decode_user_hk(self.hk_array32) 

473 return self.user_hk 

474 

475 def decode_user_hk(self, data_array32: list): 

476 user_hk_dict = {} 

477 word_i = 0 

478 while True: 

479 # decode and check header. Only field ID 0x80 is supported now 

480 header = data_array32[word_i] 

481 word_i += 1 

482 # Check the field ID of the header 

483 if DataTypeID.field_id != (header >> 24): 

484 if not self.exit_by_wrong_id: 

485 logger.debug("Wrong field ID! Skip the word.") 

486 continue 

487 else: 

488 logger.debug("Wrong field ID! Finish the parsing.") 

489 break 

490 # decode name field 

491 name_type = (header >> 20) & 0xF 

492 name_length = (header >> 16) & 0xF 

493 name = data_array32[word_i:word_i + name_length] 

494 name = self.decode_field(name_type, name) 

495 word_i += name_length 

496 # decode data field 

497 data_type = (header >> 12) & 0xF 

498 data_length = (header >> 0) & 0xFFF 

499 if data_length != 0: 

500 data = data_array32[word_i:word_i + data_length] 

501 data = self.decode_field(data_type, data) 

502 else: 

503 data = None 

504 word_i += data_length 

505 # check and add item to the dictionary 

506 if name in user_hk_dict: 

507 logger.warning("Name '{}' is already defined!".format(name)) 

508 else: 

509 user_hk_dict[name] = data 

510 

511 # Exit the loop if all elements are parsed 

512 if (word_i + 1) > len(data_array32): 

513 break 

514 return user_hk_dict 

515 

516 def decode_field(self, field_type: DataTypeID, field_data: list): 

517 if field_type == DataTypeID.string: 

518 ret_data = "" 

519 for i in field_data: 

520 ret_data = ret_data + i.to_bytes(4, "big").decode() 

521 elif field_type == DataTypeID.int32: 

522 ret_data = field_data[0] 

523 elif field_type == DataTypeID.float32: 

524 ret_data = field_data[0].to_bytes(4, "big") 

525 ret_data = struct.unpack(">f", ret_data)[0] 

526 else: 

527 ret_data = None 

528 return ret_data 

529 

530 

531def decodeHK(itemname, rawdata, cf): 

532 try: 

533 formatstr = '{:}' 

534 converted = [] 

535 unitstr = '' 

536 if s_ADC_CH15.lower() in itemname.lower(): 

537 converted = [x for x in rawdata] 

538 converted, format, unitstr = convert.convertADC15toTemperature(rawdata, cf) 

539 formatstr = '{:3.3f}' 

540 unitstr = 'degC' 

541 elif s_ADC_CH02.lower() in itemname.lower(): 

542 rawdata = [x for x in rawdata] 

543 converted, format, unitstr = convert.convertADC2toTemperature(rawdata, cf) 

544 formatstr = '{:3.1f}' 

545 unitstr = 'degC' 

546 elif s_ADC_CH01.lower() in itemname.lower(): 

547 rawdata = [x for x in rawdata] 

548 converted, format, unitstr = convert.convertADC1toTemperature(rawdata, cf) 

549 formatstr = '{:3.1f}' 

550 unitstr = 'degC' 

551 elif s_ADC_CH13.lower() in itemname.lower(): 

552 converted = [-(x * cf.cst_ADCconv) + 2 for x in rawdata] 

553 formatstr = '{:2.3f}' 

554 unitstr = 'V' 

555 elif s_ADC_CH10.lower() in itemname.lower(): 

556 converted = [-(x * cf.cst_ADCconv) + 2 for x in rawdata] 

557 formatstr = '{:2.3f}' 

558 unitstr = 'V' 

559 elif s_ADC_CH11.lower() in itemname.lower(): 

560 converted = [x * cf.cst_ADCconv for x in rawdata] 

561 formatstr = '{:2.3f}' 

562 unitstr = 'V' 

563 elif s_ADC_CH12.lower() in itemname.lower(): 

564 converted = [x * cf.cst_ADCconv for x in rawdata] 

565 formatstr = '{:2.3f}' 

566 unitstr = 'V' 

567 elif cam_defs.name_SysMon_Temperature.lower() in itemname.lower(): 

568 rawdata = [x for x in rawdata] 

569 converted = [x * 502.9098 / 1024 - 273.8195 for x in rawdata] 

570 formatstr = '{:3.2f}' 

571 unitstr = 'degC' 

572 elif cam_defs.name_SysMon_VCCINT.lower() in itemname.lower(): 

573 rawdata = [x for x in rawdata] 

574 converted = [x / 1024 * 3 for x in rawdata] 

575 formatstr = '{:2.3f}' 

576 unitstr = 'V' 

577 elif cam_defs.name_SysMon_VCCAUX.lower() in itemname.lower(): 

578 rawdata = [x for x in rawdata] 

579 converted = [x / 1024 * 3 for x in rawdata] 

580 formatstr = '{:2.3f}' 

581 unitstr = 'V' 

582 elif cam_defs.name_SysMon_VCCBRAM.lower() in itemname.lower(): 

583 rawdata = [x for x in rawdata] 

584 converted = [x / 1024 * 3 for x in rawdata] 

585 formatstr = '{:2.3f}' 

586 unitstr = 'V' 

587 elif s_ADC_CH03.lower() in itemname.lower(): 

588 converted = [x * cf.cst_ADCconv for x in rawdata] 

589 formatstr = '{:2.3f}' 

590 unitstr = 'V' 

591 elif s_ADC_CH00.lower() in itemname.lower(): 

592 converted = [x * cf.cst_ADCconv for x in rawdata] 

593 formatstr = '{:2.3f}' 

594 unitstr = 'V' 

595 elif s_ADC_CH04.lower() in itemname.lower(): 

596 converted = [x * cf.cst_ADCconv for x in rawdata] 

597 formatstr = '{:2.3f}' 

598 unitstr = 'V' 

599 elif s_ADC_CH05.lower() in itemname.lower(): 

600 converted = [x * cf.cst_ADCconv for x in rawdata] 

601 formatstr = '{:2.3f}' 

602 unitstr = 'V' 

603 elif itemname.lower() == s_ADC_CH06.lower(): 

604 converted = [x * cf.cst_ADCconv for x in rawdata] 

605 formatstr = '{:2.3f}' 

606 unitstr = 'V' 

607 elif itemname.lower() == s_ADC_CH07.lower(): 

608 converted = [x * cf.cst_ADCconv for x in rawdata] 

609 formatstr = '{:2.3f}' 

610 unitstr = 'V' 

611 elif itemname.lower() == s_ADC_CH08.lower(): 

612 converted = [x * cf.cst_ADCconv for x in rawdata] 

613 formatstr = '{:2.3f}' 

614 unitstr = 'V' 

615 elif itemname.lower() == s_ADC_CH09.lower(): 

616 converted = [x * cf.cst_ADCconv for x in rawdata] 

617 formatstr = '{:2.3f}' 

618 unitstr = 'V' 

619 elif itemname.lower() == s_ADC_CH10.lower(): 

620 converted = [x * cf.cst_ADCconv for x in rawdata] 

621 formatstr = '{:2.3f}' 

622 unitstr = 'V' 

623 elif itemname.lower() == s_ADC_CH14.lower(): 

624 converted = [x * cf.cst_ADCconv for x in rawdata] 

625 formatstr = '{:2.3f}' 

626 unitstr = 'V' 

627 elif itemname.lower() == 'PSU_E3631A_CH1_Voltage'.lower(): 

628 converted = [float(x) for x in rawdata] 

629 elif itemname.lower() == 'PSU_E3631A_CH1_Current'.lower(): 

630 converted = [float(x) for x in rawdata] 

631 elif itemname.lower() == 'PSU_E3631A_CH2_Voltage'.lower(): 

632 converted = [float(x) for x in rawdata] 

633 elif itemname.lower() == 'PSU_E3631A_CH2_Current'.lower(): 

634 converted = [float(x) for x in rawdata] 

635 elif itemname.lower() == 'PSU_E3631A_CH3_Voltage'.lower(): 

636 converted = [float(x) for x in rawdata] 

637 elif itemname.lower() == 'PSU_E3631A_CH3_Current'.lower(): 

638 converted = [float(x) for x in rawdata] 

639 elif itemname.lower() == 'PSU_HMP4040_CH1_Voltage'.lower(): 

640 converted = [float(x) for x in rawdata] 

641 elif itemname.lower() == 'PSU_HMP4040_CH1_Current'.lower(): 

642 converted = [float(x) for x in rawdata] 

643 elif itemname.lower() == 'PSU_HMP4040_CH2_Voltage'.lower(): 

644 converted = [float(x) for x in rawdata] 

645 elif itemname.lower() == 'PSU_HMP4040_CH2_Current'.lower(): 

646 converted = [float(x) for x in rawdata] 

647 elif itemname.lower() == 'PSU_HMP4040_CH3_Voltage'.lower(): 

648 converted = [float(x) for x in rawdata] 

649 elif itemname.lower() == 'PSU_HMP4040_CH3_Current'.lower(): 

650 converted = [float(x) for x in rawdata] 

651 elif itemname.lower() == 'PSU_HMP4040_CH4_Voltage'.lower(): 

652 converted = [float(x) for x in rawdata] 

653 elif itemname.lower() == 'PSU_HMP4040_CH4_Current'.lower(): 

654 converted = [float(x) for x in rawdata] 

655 elif 'DAC'.lower() in itemname.lower(): 

656 converted = convDACtoBiasV(itemname, rawdata, cf) 

657 formatstr = '{:3.2f}' 

658 unitstr = 'V' 

659 elif 'PMU'.lower() in itemname.lower(): 

660 voltagevalue = [x * (5 / 4095) for x in rawdata] 

661 if itemname == s_PMU_HK7: # read current -12V 

662 # -100mA = 5V 

663 converted = [float(-0.02 * x) for x in voltagevalue] 

664 formatstr = '{:3.2f}' 

665 unitstr = 'A' 

666 elif itemname == s_PMU_HK6: # read current +12V 

667 # 100mA = 5V 

668 converted = [float(0.02 * x) for x in voltagevalue] 

669 formatstr = '{:3.2f}' 

670 unitstr = 'A' 

671 elif itemname == s_PMU_HK5: # read current +5V 

672 # 1A = 5V 

673 converted = [float(0.2 * x) for x in voltagevalue] 

674 formatstr = '{:3.2f}' 

675 unitstr = 'A' 

676 elif itemname == s_PMU_HK4: # PMUS Temp 

677 # 423K / 5V 

678 converted = [float((423 / 5 * x) - 273.15) for x in voltagevalue] 

679 formatstr = '{:3.2f}' 

680 unitstr = 'degC' 

681 elif s_PMU_HK3.lower() in itemname.lower(): # PMU Temp 

682 converted = [__convert_voltvalue(x) for x in voltagevalue] 

683 formatstr = '{:3.2f}' 

684 unitstr = 'degC' 

685 elif s_PMU_HK2.lower() in itemname.lower(): # PMU ANG Err 

686 converted = [float((x - 2.5) / 0.3255) for x in voltagevalue] 

687 formatstr = '{:3.2f}' 

688 unitstr = 'deg' 

689 elif s_PMU_HK1.lower() in itemname.lower(): # PMU ANG 

690 converted = [float(x / 0.0138890) for x in voltagevalue] 

691 formatstr = '{:3.2f}' 

692 unitstr = 'deg' 

693 elif s_PMU_HK0.lower() in itemname.lower(): # PMU Current 

694 converted = [float(x / 5) for x in voltagevalue] 

695 formatstr = '{:3.2f}' 

696 unitstr = 'A' 

697 else: 

698 logger.warning("unrecognised PMU SYNC data") # this should not occur, only in for bug testing.####### 

699 elif s_Integration_time.lower() in itemname.lower(): 

700 converted = [] 

701 for i in range(len(rawdata)): 

702 val = calcExpSTD(int(rawdata[i]), 513) 

703 formatstr = '{:3.2e}' 

704 unitstr = 's' 

705 converted.append(val) 

706 elif itemname.lower() == s_Timestamp_us.lower(): 

707 unitstr = 'us' 

708 elif itemname.lower() == s_Timestamp_ms.lower(): 

709 unitstr = 'ms' 

710 except Exception as e: 

711 logger.error("{:} - {:}".format(sys._getframe().f_code.co_name, e)) 

712 

713 return converted, formatstr, unitstr 

714 

715 

716def full_hk(file_name): 

717 hk = ImageHousekeeping(file_name) 

718 image_hk = hk.get_image_hk() 

719 user_hk = hk.get_user_hk() 

720 image_array = np.fromfile(file_name, dtype="<u2", count=-1) 

721 if len(image_array) == 2048: 

722 image_array_withhk = None # it was just a HK line of 2048 bytes 

723 else: 

724 image_array_withhk = np.reshape(image_array, (2049, 2048)) 

725 return image_hk, user_hk, image_array_withhk 

726 

727 

728def camera_hk(image_array): 

729 """ 

730 Returns the image housekeeping information from row 2049 of image_array 

731 """ 

732 hk = ImageHousekeeping(raw_file_name=None, image_array=image_array) 

733 image_hk = hk.get_image_hk() 

734 return image_hk 

735 

736 

737def __convert_voltvalue(val): 

738 # changed by Francisco on 20210609 due to a K. Herline recommendation (email) 

739 denom = (0.0014708 + 0.00023783 * np.log(-10000 / (-5 + val)) + 1.03 * 10 ** -7 * np.log(-10000 / (-5 + val)) ** 3) 

740 return -273.15 + 1 / denom