524 lines
24 KiB
TypeScript
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}}
|
|
/>
|
|
<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>
|
|
<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"}}/>
|
|
<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"}}/>
|
|
<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"}}/>
|
|
<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>
|
|
<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"}
|
|
/>
|
|
<ButtonWithSnackbar
|
|
color={"primary"}
|
|
path={"/deactivate"}
|
|
text={"Deactivate"}
|
|
/>
|
|
<br/><br/>
|
|
</Grid>
|
|
<Grid item xs={1}/>
|
|
</Grid>
|
|
</Paper>
|
|
}
|
|
}
|
|
|
|
export default DetectorSettings; |