Files
Jungfraujoch/frontend/src/components/DetectorSettings.tsx
T
2024-11-17 14:55:09 +01:00

524 lines
24 KiB
TypeScript

import React, {Component} from 'react';
import {Checkbox, FormControlLabel, FormGroup, Grid, List, ListItem, Switch, Tooltip} from "@mui/material";
import Paper from "@mui/material/Paper";
import FormControl from "@mui/material/FormControl";
import InputLabel from "@mui/material/InputLabel";
import Select, {SelectChangeEvent} from "@mui/material/Select";
import MenuItem from "@mui/material/MenuItem";
import {DefaultService, detector_settings, detector_timing} from "../openapi";
import NumberTextField from "./NumberTextField";
import _ from "lodash";
import ButtonWithSnackbar from "./ButtonWithSnackbar";
type MyProps = {
s?: detector_settings
}
type MyState = {
s: detector_settings,
last_downloaded_s: detector_settings,
bit_width_selection: string,
storage_cell_list_value: string,
timing_mode_list_value: detector_timing,
frame_time_err: boolean,
count_time_err: boolean,
storage_cell_delay_err: boolean,
detector_trigger_delay_err: boolean,
internal_frame_generator_images_err: boolean,
pedestal_g0_frames_err: boolean,
pedestal_g1_frames_err: boolean,
pedestal_g2_frames_err: boolean,
pedestal_min_image_count_err: boolean,
eiger_threshold_err: boolean,
eiger_threshold_keV_old: number,
download_counter: number
}
function extractDepthForSelection(input: detector_settings) : string {
if (input.eiger_bit_depth === undefined)
return 'a';
else if (input.eiger_bit_depth === detector_settings.eiger_bit_depth._16)
return '16';
else if (input.eiger_bit_depth === detector_settings.eiger_bit_depth._32)
return '32';
else if (input.eiger_bit_depth === detector_settings.eiger_bit_depth._8)
return '8';
else
return "";
}
class DetectorSettings extends Component<MyProps, MyState> {
state : MyState = {
s: {
frame_time_us: 1000
},
last_downloaded_s: {
frame_time_us: 1000
},
bit_width_selection: "a",
timing_mode_list_value: detector_timing.TRIGGER,
storage_cell_list_value: "1",
pedestal_g0_frames_err: false,
pedestal_g1_frames_err: false,
pedestal_g2_frames_err: false,
pedestal_min_image_count_err: false,
storage_cell_delay_err: false,
detector_trigger_delay_err: false,
frame_time_err: false,
count_time_err: false,
internal_frame_generator_images_err: false,
eiger_threshold_err: false,
eiger_threshold_keV_old: 6.0,
download_counter: 0
}
eigerThresholdToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.checked)
this.setState(prevState => ({s : {...prevState.s,
eiger_threshold_keV: prevState.eiger_threshold_keV_old}}));
else
this.setState(prevState => ({s: {...prevState.s, eiger_threshold_keV: undefined}}));
}
countTimeToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
if (event.target.checked)
this.setState(prevState => ({s : {...prevState.s, count_time_us: prevState.s.frame_time_us - 20}}));
else
this.setState(prevState => ({s : {...prevState.s, count_time_us: undefined}}));
}
internalFrameGeneratorToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState(prevState => ({s : {...prevState.s, internal_frame_generator: event.target.checked}}));
}
useGainHG0Toggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState(prevState => ({s : {...prevState.s, jungfrau_use_gain_hg0: event.target.checked}}));
}
fixedGainG1Toggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState(prevState => ({s : {...prevState.s, jungfrau_fixed_gain_g1: event.target.checked}}));
}
deactivate = () => {
DefaultService.postDeactivate()
.catch(error => {} );
}
handleBitWidthChange = (event: SelectChangeEvent) => {
let val: detector_settings.eiger_bit_depth|undefined = undefined;
if (event.target.value === "a")
val = undefined;
else if (event.target.value === "8")
val = detector_settings.eiger_bit_depth._8;
else if (event.target.value === "16")
val = detector_settings.eiger_bit_depth._16;
else if (event.target.value === "32")
val = detector_settings.eiger_bit_depth._32;
this.setState(prevState => ({
bit_width_selection: event.target.value,
s: {
...prevState.s,
eiger_bit_depth: val
}
}));
};
handleTimingChange = (event : SelectChangeEvent<detector_timing>) => {
let d : detector_timing = detector_timing.TRIGGER;
switch (event.target.value) {
case "trigger":
d = detector_timing.TRIGGER;
break;
case "auto":
d = detector_timing.AUTO;
break;
case "burst":
d = detector_timing.BURST;
break;
case "gated":
d = detector_timing.GATED;
break;
}
this.setState(prevState => ({
timing_mode_list_value: d,
s : {...prevState.s,
timing: d
}
})
);
};
handleChange = (event : SelectChangeEvent<String>) => {
this.setState(prevState => ({
storage_cell_list_value: String(event.target.value).toString(),
s : {...prevState.s,
jungfrau_storage_cell_count: Number(event.target.value)
}
})
);
};
getValues() {
if (this.props.s !== undefined) {
let det_set: detector_settings = this.props.s;
if (!_.isEqual(det_set, this.state.last_downloaded_s)) {
this.setState(prevState => ({
download_counter: prevState.download_counter + 1,
s: det_set,
bit_width_selection: extractDepthForSelection(det_set),
last_downloaded_s: det_set,
storage_cell_list_value: String(det_set.jungfrau_storage_cell_count ?? "1"),
timing_mode_list_value: det_set.timing ?? detector_timing.TRIGGER,
pedestal_g0_frames_err: false,
pedestal_g1_frames_err: false,
pedestal_g2_frames_err: false,
pedestal_min_image_count_err: false,
storage_cell_delay_err: false,
detector_trigger_delay_err: false,
frame_time_err: false,
count_time_err: false,
internal_frame_generator_images_err: false,
eiger_threshold_err: false,
eiger_threshold_keV_old: 6.0
}));
}
}
}
componentDidMount() {
this.getValues();
}
componentDidUpdate() {
this.getValues();
}
render() {
return <Paper style={{textAlign: 'center'}} sx={{ height: 1150, width: '100%' }}>
<Grid container>
<Grid item xs={1}/>
<Grid item xs={10}>
<br/><strong>Detector settings </strong>
<br/><br/><br/>
<NumberTextField start_val={this.state.s.frame_time_us}
label={"Internal frame time"}
units={"us"}
min={450}
fullWidth
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
frame_time_err: err,
s: {...prevState.s, frame_time_us: val}
}));
}}/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={2}/>
<Grid item xs={8}>
<List>
<ListItem>
<Switch onChange={this.countTimeToggle}
checked={this.state.s.count_time_us !== undefined}/>
<NumberTextField
start_val={this.state.s.count_time_us}
disabled={this.state.s.count_time_us === undefined}
label={"Count time"}
units={"us"}
min={0}
max={1980}
fullWidth
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
count_time_err: err,
s: {...prevState.s, count_time_us: val}
}));
}}/>
</ListItem>
</List>
</Grid>
<Grid item xs={2}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<NumberTextField start_val={this.state.s.detector_trigger_delay_ns}
label={"Detector delay"}
units={"ns"}
default={0}
min={0}
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
detector_trigger_delay_err: err,
s: {...prevState.s, detector_trigger_delay_ns: val}
}));
}}
sx={{width: 120}}
/>&nbsp;&nbsp;
<FormControl>
<InputLabel id="timing-select-label">Timing mode</InputLabel>
<Select
sx={{width: 120}}
labelId="timing-select-label"
id="timing-select"
value={this.state.timing_mode_list_value}
label="Storage cell count"
onChange={this.handleTimingChange}
>
<MenuItem value={"trigger"}>Trigger</MenuItem>
<MenuItem value={"auto"}>Auto</MenuItem>
<MenuItem value={"burst"}>Burst (EIGER)</MenuItem>
<MenuItem value={"gated"}>Gated (EIGER)</MenuItem>
</Select>
</FormControl>
<br/><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<b>Internal image generator (FPGA) </b><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={3}/>
<Grid item xs={6}>
<br/>
<List>
<Tooltip title="Internal generator allows to test Jungfraujoch without having detector connected.">
<ListItem>
<Checkbox onChange={this.internalFrameGeneratorToggle}
checked={this.state.s.internal_frame_generator === true}/>
<FormControl fullWidth>
<NumberTextField start_val={this.state.s.internal_frame_generator_images}
label={"Images"}
min={1}
default={1}
max={128}
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
internal_frame_generator_images_err: err,
s: {...prevState.s, internal_frame_generator_images: val}
}));
}}
disabled={!this.state.s.internal_frame_generator}
fullWidth/>
</FormControl>
</ListItem>
</Tooltip>
</List>
</Grid>
<Grid item xs={3}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<b>JUNGFRAU settings </b><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={3}/>
<Grid item xs={6}>
<FormGroup>
<FormControlLabel control={
<Checkbox onChange={this.useGainHG0Toggle} checked={this.state.s.jungfrau_use_gain_hg0 === true}/>
} label="HG0"/>
<FormControlLabel control={
<Checkbox onChange={this.fixedGainG1Toggle} checked={this.state.s.jungfrau_fixed_gain_g1 === true}/>
} label="Fixed G1"/>
</FormGroup><br/>
</Grid>
<Grid item xs={3}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<b>JUNGFRAU storage cells </b><br/><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<FormControl>
<InputLabel id="demo-simple-select-label">Count</InputLabel>
<Select
sx={{width: 120}}
labelId="demo-simple-select-label"
id="demo-simple-select"
value={this.state.storage_cell_list_value}
label="Storage cell count"
onChange={this.handleChange}
>
<MenuItem value={"1"}>1</MenuItem>
<MenuItem value={"2"}>2</MenuItem>
<MenuItem value={"4"}>4</MenuItem>
<MenuItem value={"8"}>8</MenuItem>
<MenuItem value={"15"}>15</MenuItem>
<MenuItem value={"16"}>16</MenuItem>
</Select>
</FormControl>&nbsp;&nbsp;
<NumberTextField start_val={this.state.s.jungfrau_storage_cell_delay_ns}
label={"Delay"}
units={"ns"}
min={2100}
default={2100}
counter={this.state.download_counter}
sx={{ width: "140px" }}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
storage_cell_delay_err: err,
s: {...prevState.s, jungfrau_storage_cell_delay_ns: val}
}));
}}
disabled={this.state.storage_cell_list_value === "1"}
fullWidth/>
<br/><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<b>JUNGFRAU Pedestal</b><br/><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<NumberTextField start_val={this.state.s.jungfrau_pedestal_g0_frames}
label={"G0"}
min={0}
default={2000}
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
pedestal_g0_frames_err: err,
s: {...prevState.s, jungfrau_pedestal_g0_frames: val}
}));
}}
sx={{width: "80px"}}/>&nbsp;
<NumberTextField start_val={this.state.s.jungfrau_pedestal_g1_frames}
label={"G1"}
min={0}
default={300}
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
pedestal_g1_frames_err: err,
s: {...prevState.s, jungfrau_pedestal_g1_frames: val}
}));
}}
sx={{width: "80px"}}/>&nbsp;
<NumberTextField start_val={this.state.s.jungfrau_pedestal_g2_frames}
label={"G2"}
min={0}
default={300}
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
pedestal_g2_frames_err: err,
s: {...prevState.s, jungfrau_pedestal_g2_frames: val}
}));
}}
sx={{width: "80px"}}/>
&nbsp;<br/><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<NumberTextField start_val={this.state.s.jungfrau_pedestal_min_image_count}
label={"Min. image count"}
min={0}
default={128}
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
this.setState(prevState => ({
pedestal_min_image_count_err: err,
s: {...prevState.s, jungfrau_pedestal_min_image_count: val}
}));
}}
sx={{width: "120px"}}/><br/><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<b>EIGER settings </b><br/><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<ListItem>
<Checkbox onChange={this.eigerThresholdToggle}
checked={this.state.s.eiger_threshold_keV !== undefined}/>
<FormControl fullWidth>
<NumberTextField
default={this.state.eiger_threshold_keV_old}
start_val={this.state.s.eiger_threshold_keV}
label={"Energy threshold"}
min={1.0}
max={100.0}
units={"keV"}
float={true}
counter={this.state.download_counter}
callback={(val: number, err: boolean) => {
let old: number = this.state.eiger_threshold_keV_old;
if (!err)
old = val;
this.setState(prevState => ({
eiger_threshold_err: err,
eiger_threshold_keV_old: old,
s: {...prevState.s, eiger_threshold_keV: val}
}));
}}
disabled={this.state.s.eiger_threshold_keV === undefined}
/>
</FormControl>&nbsp;
<FormControl>
<InputLabel id="demo-simple-select-label">Read-out</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
label="Detector"
value={this.state.bit_width_selection}
onChange={this.handleBitWidthChange}
sx={{minWidth:106}}
>
<MenuItem value={"a"}>Auto</MenuItem>
<MenuItem value={"8"}>8-bit</MenuItem>
<MenuItem value={"16"}>16-bit</MenuItem>
<MenuItem value={"32"}>32-bit</MenuItem>
</Select>
</FormControl><br/><br/>
</ListItem><br/>
</Grid>
<Grid item xs={1}/>
<Grid item xs={1}/>
<Grid item xs={10}>
<ButtonWithSnackbar
color={"primary"}
path={"/config/detector"}
disabled={this.state.count_time_err
|| this.state.frame_time_err
|| this.state.internal_frame_generator_images_err
|| this.state.detector_trigger_delay_err
|| this.state.storage_cell_delay_err
|| this.state.pedestal_g0_frames_err
|| this.state.pedestal_g1_frames_err
|| this.state.pedestal_g2_frames_err
|| this.state.pedestal_min_image_count_err}
text={"Upload"}
input={JSON.stringify(this.state.s)}
method={"PUT"}
/>&nbsp;&nbsp;
<ButtonWithSnackbar
color={"primary"}
path={"/deactivate"}
text={"Deactivate"}
/>
<br/><br/>
</Grid>
<Grid item xs={1}/>
</Grid>
</Paper>
}
}
export default DetectorSettings;