Skip to content

Commit df8a5b2

Browse files
committed
PCFH Support
1 parent 17732bb commit df8a5b2

File tree

2 files changed

+242
-27
lines changed

2 files changed

+242
-27
lines changed

js/tracker.js

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,42 @@ var globalKeys = {
215215
"cobald_blue_backscatter": "COBALD Blue Backscatter",
216216
"cobald_red_backscatter": "COBALD Red Backscatter",
217217
"cobald_blue_monitor": "COBALD Blue Monitor",
218-
"cobald_red_monitor": "COBALD Red Monitor"
218+
"cobald_red_monitor": "COBALD Red Monitor",
219+
"pcfh_instrument_number": "PCFH Instrument Number",
220+
"pcfh_6v_analog_supply_battery_voltage": "PCFH 6V Analog Battery Voltage",
221+
"pcfh_45v_logic_supply_battery_voltage": "PCFH 4.5V Supply Battery Voltage",
222+
"pcfh_45v_peltier_and_heater_supply_battery_voltage": "PCFH 4.5V Peltier Battery Voltage",
223+
"pcfh_air_temperature_01": "PCFH Air Temperature #1",
224+
"pcfh_air_temperature_02": "PCFH Air Temperature #2",
225+
"pcfh_anticipated_frost_point_mirror_temperature_01": "PCFH Anticipated Frost Point Mirror Temperature #1",
226+
"pcfh_anticipated_frost_point_mirror_temperature_02": "PCFH Anticipated Frost Point Mirror Temperature #2",
227+
"pcfh_clean_frost_point_mirror_reflectance_01": "PCFH Clean Frost Point Mirror Reflectance #1",
228+
"pcfh_clean_frost_point_mirror_reflectance_02": "PCFH Clean Frost Point Mirror Reflectance #2",
229+
"pcfh_clean_reference_surface_reflectance_01": "PCFH Clean Reference Surface Reflectance #1",
230+
"pcfh_clean_reference_surface_reflectance_02": "PCFH Clean Reference Surface Reflectance #2",
231+
"pcfh_frost_point_mirror_reflectance_01": "PCFH Frost Point Mirror Reflectance #1",
232+
"pcfh_frost_point_mirror_reflectance_02": "PCFH Frost Point Mirror Reflectance #2",
233+
"pcfh_reference_surface_reflectance_01": "PCFH Reference Surface Reflectance #1",
234+
"pcfh_reference_surface_reflectance_01": "PCFH Reference Surface Reflectance #2",
235+
"pcfh_heat_sink_temperature_01": "PCFH Heat Sink Temperature #1",
236+
"pcfh_heat_sink_temperature_02": "PCFH Heat Sink Temperature #2",
237+
"pcfh_frost_point_mirror_temperature_01": "PCFH Frost Point Mirror Temperature #1",
238+
"pcfh_frost_point_mirror_temperature_02": "PCFH Frost Point Mirror Temperature #2",
239+
"pcfh_peltier_hot_side_temperature_01": "PCFH Peltier Hot Side Temperature #1",
240+
"pcfh_peltier_hot_side_temperature_02": "PCFH Peltier Hot Side Temperature #2",
241+
"pcfh_reference_surface_heating_current_01": "PCFH Reference Surface Heating Current #1",
242+
"pcfh_reference_surface_heating_current_02": "PCFH Reference Surface Heating Current #2",
243+
"pcfh_reference_surface_temperature_01": "PCFH Reference Surface Temperature #1",
244+
"pcfh_reference_surface_temperature_02": "PCFH Reference Surface Temperature #2",
245+
"pcfh_peltier_current_01": "PCFH Peltier Current #1",
246+
"pcfh_peltier_current_02": "PCFH Peltier Current #2",
247+
"pcfh_reserved_temperature": "PCFH Reserved Temperature",
248+
"pcfh_thermocouple_reference_temperature": "PCFH Reference Thermocouple Temperature",
249+
"pcfh_serial_number": "PCFH Serial Number",
250+
"pcfh_controller_fw_date": "PCFH Controller Firmware Date",
251+
"pcfh_fpga_fw_date": "PCFH FPGA Firmware Date",
252+
"pcfh_temperature_pcb_date": "PCFH Temperature PCB Manufacture Date",
253+
"pcfh_main_pcb_date": "PCFH Main PCB Manufacture Date"
219254
};
220255

221256
var globalSuffixes = {
@@ -252,7 +287,28 @@ var globalSuffixes = {
252287
"cfh_optics_voltage": " V",
253288
"cfh_optics_temperature": "°C",
254289
"cfh_battery": " V",
255-
"cobald_internal_temperature": "°C"
290+
"cobald_internal_temperature": "°C",
291+
"pcfh_6v_analog_supply_battery_voltage": " V",
292+
"pcfh_45v_logic_supply_battery_voltage": " V",
293+
"pcfh_45v_peltier_and_heater_supply_battery_voltage": " V",
294+
"pcfh_air_temperature_01": "°C",
295+
"pcfh_air_temperature_02": "°C",
296+
"pcfh_anticipated_frost_point_mirror_temperature_01": "°C",
297+
"pcfh_anticipated_frost_point_mirror_temperature_02": "°C",
298+
"pcfh_heat_sink_temperature_01": "°C",
299+
"pcfh_heat_sink_temperature_02": "°C",
300+
"pcfh_frost_point_mirror_temperature_01": "°C",
301+
"pcfh_frost_point_mirror_temperature_02": "°C",
302+
"pcfh_peltier_hot_side_temperature_01": "°C",
303+
"pcfh_peltier_hot_side_temperature_02": "°C",
304+
"pcfh_reference_surface_heating_current_01": " A",
305+
"pcfh_reference_surface_heating_current_02": " A",
306+
"pcfh_reference_surface_temperature_01": "°C",
307+
"pcfh_reference_surface_temperature_02": "°C",
308+
"pcfh_peltier_current_01": " A",
309+
"pcfh_peltier_current_02": " A",
310+
"pcfh_reserved_temperature": "°C",
311+
"pcfh_thermocouple_reference_temperature": "°C",
256312
};
257313

258314
// localStorage vars

js/xdata.js

Lines changed: 184 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,7 @@ function parseOIF411(xdata, pressure){
4848
// https://www.vaisala.com/sites/default/files/documents/Ozone%20Sounding%20with%20Vaisala%20Radiosonde%20RS41%20User%27s%20Guide%20M211486EN-C.pdf
4949
//
5050
// Sample data: 0501036402B958B07500 (length = 20 characters)
51-
// More sample data: 0501R20234850000006EI (length = 21 characters)
52-
53-
// Cast to string if not already
54-
xdata = String(xdata);
51+
// More sample data: 0501R20234850000006EI (length = 21 characters)
5552

5653
// Run some checks over the input
5754
if(xdata.length < 20){
@@ -91,8 +88,6 @@ function parseOIF411(xdata, pressure){
9188

9289
// Version number
9390
_output['oif411_version'] = (parseInt(xdata.substr(16,4),16)/100).toFixed(2);
94-
95-
return _output
9691
} else if (xdata.length == 20){
9792
// Measurement Data (Table 18)
9893
// Ozone pump temperature - signed int16
@@ -128,12 +123,9 @@ function parseOIF411(xdata, pressure){
128123

129124
_O3_partial_pressure = (4.30851e-4)*(_output['oif411_ozone_current_uA'] - Ibg)*(_output['oif411_ozone_pump_temp']+273.15)*FlowRate*Cef; // mPa
130125
_output['oif411_O3_partial_pressure'] = Math.round(_O3_partial_pressure * 1000) / 1000; // 3 DP
126+
}
131127

132-
return _output
133-
134-
} else {
135-
return {}
136-
}
128+
return _output
137129
}
138130

139131
function parseCFH(xdata) {
@@ -145,9 +137,6 @@ function parseCFH(xdata) {
145137
//
146138
// Sample data: 0802E21FFD85C8CE078A0193 (length = 24 characters)
147139

148-
// Cast to string if not already
149-
xdata = String(xdata);
150-
151140
// Run some checks over the input
152141
if(xdata.length != 24){
153142
// Invalid CFH dataset
@@ -176,9 +165,6 @@ function parseCOBALD(xdata) {
176165
//
177166
// Sample data: 190213fffe005fcf00359943912cca (length = 30 characters)
178167

179-
// Cast to string if not already
180-
xdata = String(xdata);
181-
182168
// Run some checks over the input
183169
if(xdata.length != 30){
184170
// Invalid COBALD dataset
@@ -246,9 +232,6 @@ function parseSKYDEW(xdata) {
246232
//
247233
// Sample data: 3F0141DF73B940F600150F92FF27D5C8304102 (length = 38 characters)
248234

249-
// Cast to string if not already
250-
xdata = String(xdata);
251-
252235
// Run some checks over the input
253236
if(xdata.length != 38){
254237
// Invalid SKYDEW dataset
@@ -280,6 +263,183 @@ function parseSKYDEW(xdata) {
280263
return _output
281264
}
282265

266+
function getPCFHdate(code) {
267+
// months reference list
268+
var PCFHmonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
269+
270+
// Get year from first character
271+
var year = parseInt(code.charAt(0),16);
272+
year = year + 2016;
273+
274+
// Get month from second character
275+
var month = parseInt(code.charAt(1),16);
276+
month = PCFHmonths[month-1];
277+
278+
// Generate string
279+
_part_date = month + " " + year;
280+
return _part_date;
281+
}
282+
283+
function parsePCFH(xdata) {
284+
// Attempt to parse an XDATA string from a Peltier Cooled Frost point Hygrometer (PCFH)
285+
// Returns an object with parameters to be added to the sondes telemetry.
286+
//
287+
// References:
288+
// Peltier Cooled Frost point Hygrometer (PCFH) Telemetry Interface PDF
289+
//
290+
// Sample data: 3c0101434a062c5cd4a5747b81486c93 (length = 32 characters)
291+
// 3c0103456076175ec5fc9df9b1 (length = 26 characters)
292+
// 3c0104a427104e203a9861a8ab6a65 (length = 30 characters)
293+
// 3c010000011b062221 (length = 18 characters)
294+
295+
// Run some checks over the input
296+
if(xdata.length > 32){
297+
// Invalid PCFH dataset
298+
return {};
299+
}
300+
301+
if(xdata.substr(0,2) !== '3C'){
302+
// Not a PCFH (shouldn't get here)
303+
return {};
304+
}
305+
306+
var _output = {};
307+
308+
// Instrument number is common to all XDATA types.
309+
_output['pcfh_instrument_number'] = parseInt(xdata.substr(2,2),16);
310+
311+
// Packet ID
312+
var packetID = xdata.substr(4,2);
313+
314+
// Packet type
315+
if (packetID == "00") { // Individual instrument identification (10 s)
316+
// Serial number
317+
_output["pcfh_serial_number"] = parseInt(xdata.substr(6,4));
318+
319+
// Temperature PCB date
320+
_output["pcfh_temperature_pcb_date"] = getPCFHdate(xdata.substr(10,2));
321+
322+
// Main PCB date
323+
_output["pcfh_main_pcb_date"] = getPCFHdate(xdata.substr(12,2));
324+
325+
// Controller FW date
326+
_output["pcfh_controller_fw_date"] = getPCFHdate(xdata.substr(14,2));
327+
328+
// FPGA FW date
329+
_output["pcfh_fpga_fw_date"] = getPCFHdate(xdata.substr(16,2));
330+
} else if (packetID == "01" || packetID == "02") { // Regular one second data, sub-sensor 1/2
331+
// Frost point mirror temperature
332+
_frost_point_mirror_temperature = parseInt(xdata.substr(8,3),16);
333+
_frost_point_mirror_temperature = (_frost_point_mirror_temperature*0.05) - 125;
334+
_output['pcfh_frost_point_mirror_temperature_' + packetID] = Math.round(_frost_point_mirror_temperature * 100) / 100; // 2 DP
335+
336+
// Peltier hot side temperature
337+
_peltier_hot_side_temperature = parseInt(xdata.substr(11,3),16);
338+
_peltier_hot_side_temperature = (_peltier_hot_side_temperature*0.05) - 125;
339+
_output['pcfh_peltier_hot_side_temperature_' + packetID] = Math.round(_peltier_hot_side_temperature * 100) / 100; // 2 DP
340+
341+
// Air temperature
342+
_air_temperature = parseInt(xdata.substr(14,3),16);
343+
_air_temperature = (_air_temperature*0.05) - 125;
344+
_output['pcfh_air_temperature_' + packetID] = Math.round(_air_temperature * 100) / 100; // 2 DP
345+
346+
// Anticipated frost point mirror temperature
347+
_anticipated_frost_point_mirror_temperature = parseInt(xdata.substr(17,3),16);
348+
_anticipated_frost_point_mirror_temperature = (_anticipated_frost_point_mirror_temperature*0.05) - 125;
349+
_output['pcfh_anticipated_frost_point_mirror_temperature_' + packetID] = Math.round(_anticipated_frost_point_mirror_temperature * 100) / 100; // 2 DP
350+
351+
// Frost point mirror reflectance
352+
_frost_point_mirror_reflectance = parseInt(xdata.substr(20,4),16);
353+
_frost_point_mirror_reflectance = _frost_point_mirror_reflectance/32768;
354+
_output['pcfh_frost_point_mirror_reflectance_' + packetID] = Math.round(_frost_point_mirror_reflectance * 1000) / 1000; // 3 DP
355+
356+
// Reference surface reflectance
357+
_reference_surface_reflectance = parseInt(xdata.substr(24,4),16);
358+
_reference_surface_reflectance = _reference_surface_reflectance/32768;
359+
_output['pcfh_reference_surface_reflectance_' + packetID] = Math.round(_reference_surface_reflectance * 1000) / 1000; // 3 DP
360+
361+
// Reference surface heating current
362+
_reference_surface_heating_current = parseInt(xdata.substr(28,2),16);
363+
_reference_surface_heating_current = _reference_surface_heating_current/2.56;
364+
_output['pcfh_reference_surface_heating_current_' + packetID] = Math.round(_reference_surface_heating_current * 100) / 100; // 2 DP
365+
366+
// Peltier current
367+
_peltier_current = parseInt(xdata.substr(30,2),16);
368+
if ((_peltier_current & 0x80) > 0) {
369+
_peltier_current = _peltier_current - 0x100;
370+
}
371+
_peltier_current = _peltier_current/64;
372+
_output['pcfh_peltier_current_' + packetID] = Math.round(_peltier_current * 1000) / 1000; // 3 DP
373+
} else if (packetID == "03") { // Regular five second data
374+
// Heat sink temperature 1
375+
_heat_sink_temperature = parseInt(xdata.substr(8,3),16);
376+
_heat_sink_temperature = (_heat_sink_temperature*0.05) - 125;
377+
_output['pcfh_heat_sink_temperature_01'] = Math.round(_heat_sink_temperature * 100) / 100; // 2 DP
378+
379+
// Reference surface temperature 1
380+
_reference_surface_temperature = parseInt(xdata.substr(11,3),16);
381+
_reference_surface_temperature = (_reference_surface_temperature*0.05) - 125;
382+
_output['pcfh_reference_surface_temperature_01'] = Math.round(_reference_surface_temperature * 100) / 100; // 2 DP
383+
384+
// Heat sink temperature 2
385+
_heat_sink_temperature = parseInt(xdata.substr(14,3),16);
386+
_heat_sink_temperature = (_heat_sink_temperature*0.05) - 125;
387+
_output['pcfh_heat_sink_temperature_02'] = Math.round(_heat_sink_temperature * 100) / 100; // 2 DP
388+
389+
// Reference surface temperature 2
390+
_reference_surface_temperature = parseInt(xdata.substr(17,3),16);
391+
_reference_surface_temperature = (_reference_surface_temperature*0.05) - 125;
392+
_output['pcfh_reference_surface_temperature_02'] = Math.round(_reference_surface_temperature * 100) / 100; // 2 DP
393+
394+
// Thermocouple reference temperature
395+
_thermocouple_reference_temperature = parseInt(xdata.substr(20,3),16);
396+
_thermocouple_reference_temperature = (_thermocouple_reference_temperature*0.05) - 125;
397+
_output['pcfh_thermocouple_reference_temperature'] = Math.round(_thermocouple_reference_temperature * 100) / 100; // 2 DP
398+
399+
// Reserved temperature
400+
_reserved_temperature = parseInt(xdata.substr(23,3),16);
401+
_reserved_temperature = (_reserved_temperature*0.05) - 125;
402+
_output['pcfh_reserved_temperature'] = Math.round(_reserved_temperature * 100) / 100; // 2 DP
403+
} else if (packetID == "04") { // Instrument status (10 s)
404+
// Clean frost point mirror reflectance 1
405+
_clean_frost_point_mirror_reflectance = parseInt(xdata.substr(8,4),16);
406+
_clean_frost_point_mirror_reflectance = _clean_frost_point_mirror_reflectance*0.001;
407+
_output['pcfh_clean_frost_point_mirror_reflectance_01'] = Math.round(_clean_frost_point_mirror_reflectance * 1000) / 1000; // 3 DP
408+
409+
// Clean reference surface reflectance 1
410+
_clean_reference_surface_reflectance = parseInt(xdata.substr(12,4),16);
411+
_clean_reference_surface_reflectance = _clean_reference_surface_reflectance*0.001;
412+
_output['pcfh_clean_reference_surface_reflectance_01'] = Math.round(_clean_reference_surface_reflectance * 1000) / 1000; // 3 DP
413+
414+
// Clean frost point mirror reflectance 2
415+
_clean_frost_point_mirror_reflectance = parseInt(xdata.substr(16,4),16);
416+
_clean_frost_point_mirror_reflectance = _clean_frost_point_mirror_reflectance*0.001;
417+
_output['pcfh_clean_frost_point_mirror_reflectance_02'] = Math.round(_clean_frost_point_mirror_reflectance * 1000) / 1000; // 3 DP
418+
419+
// Clean reference surface reflectance 2
420+
_clean_reference_surface_reflectance = parseInt(xdata.substr(20,4),16);
421+
_clean_reference_surface_reflectance = _clean_reference_surface_reflectance*0.001;
422+
_output['pcfh_clean_reference_surface_reflectance_02'] = Math.round(_clean_reference_surface_reflectance * 1000) / 1000; // 3 DP
423+
424+
// 6V Analog supply battery voltage
425+
_6v_analog_supply_battery_voltage = parseInt(xdata.substr(24,2),16);
426+
_6v_analog_supply_battery_voltage = (_6v_analog_supply_battery_voltage*0.02) + 2.5;
427+
_output['pcfh_6v_analog_supply_battery_voltage'] = Math.round(_6v_analog_supply_battery_voltage * 100) / 100; // 2 DP
428+
429+
// 4.5V Logic supply battery voltage
430+
_45v_logic_supply_battery_voltage = parseInt(xdata.substr(26,2),16);
431+
_45v_logic_supply_battery_voltage = (_45v_logic_supply_battery_voltage*0.02) + 2.5;
432+
_output['pcfh_45v_logic_supply_battery_voltage'] = Math.round(_45v_logic_supply_battery_voltage * 100) / 100; // 2 DP
433+
434+
// 4.5V Peltier and heater supply battery voltage
435+
_45v_peltier_and_heater_supply_battery_voltage = parseInt(xdata.substr(28,2),16);
436+
_45v_peltier_and_heater_supply_battery_voltage = (_45v_peltier_and_heater_supply_battery_voltage*0.02) + 2.5;
437+
_output['pcfh_45v_peltier_and_heater_supply_battery_voltage'] = Math.round(_45v_peltier_and_heater_supply_battery_voltage * 100) / 100; // 2 DP
438+
}
439+
440+
return _output
441+
}
442+
283443
function parseXDATA(data, pressure){
284444
// Accept an XDATA string, or multiple XDATA entries, delimited by '#'
285445
// Attempt to parse each one, and return an object
@@ -302,6 +462,8 @@ function parseXDATA(data, pressure){
302462
for(xdata_i = 0; xdata_i < data_split.length; xdata_i++){
303463
_current_xdata = data_split[xdata_i];
304464

465+
_current_xdata = String(_current_xdata).toUpperCase();
466+
305467
// Get Instrument ID
306468
// https://gml.noaa.gov/aftp/user/jordan/XDATA%20Instrument%20ID%20Allocation.pdf
307469
// https://www.gruan.org/gruan/editor/documents/gruan/GRUAN-TN-11_GruanToolRs92_v1.0_2020-10-01.pdf
@@ -341,11 +503,8 @@ function parseXDATA(data, pressure){
341503
if (!_instruments.includes("OPC")) _instruments.push('OPC');
342504
} else if (_instrument === '3C'){
343505
// PCFH
344-
// SRNO, H0, H1, F0, F1
345-
// 3c010000184b4b5754
346-
// 3c0103ce7b58647a98748befff
347-
// 3c010148719fff8e54b9af627e249fe0
348-
// 3c01028d696fff8db4b7865980cdbbb3
506+
_xdata_temp = parsePCFH(_current_xdata);
507+
_output = Object.assign(_output,_xdata_temp);
349508
if (!_instruments.includes("PCFH")) _instruments.push('PCFH');
350509
} else if (_instrument === '3D'){
351510
// FLASH-B

0 commit comments

Comments
 (0)