Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/add digital ch triggers #486

Merged
merged 14 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 63 additions & 11 deletions src/actions/deviceActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
setProgress,
setTriggerActive,
setTriggerOrigin,
TriggerEdge,
} from '../slices/triggerSlice';
import { updateRegulator as updateRegulatorAction } from '../slices/voltageRegulatorSlice';
import { convertBits16 } from '../utils/bitConversion';
Expand Down Expand Up @@ -210,6 +211,49 @@ const initGains = (): AppThunk<RootState, Promise<void>> => async dispatch => {
);
};

function checkDigitalTriggerValidity(
unsignedBits: number,
previousUnsignedBits: number,
channelTriggerStatuses: string[]
tsvetelinpetrov marked this conversation as resolved.
Show resolved Hide resolved
): boolean {
const isTriggerValid = (bits: number) =>
tsvetelinpetrov marked this conversation as resolved.
Show resolved Hide resolved
channelTriggerStatuses.every((status, index) => {
const bit = (bits >> index) & 0x01;

if (
(status === 'Active' && bit !== 1) ||
(status === 'Inactive' && bit !== 0)
) {
return false;
}

return true;
});

return (
!isTriggerValid(previousUnsignedBits) && isTriggerValid(unsignedBits)
);
}

function checkAnalogTriggerValidity(
cappedValue: number,
prevCappedValue: number | undefined,
triggerLevel: number,
triggerEdge: TriggerEdge
): boolean {
const isRaisingEdge = triggerEdge === 'Raising Edge';
const isLoweringEdge = triggerEdge === 'Lowering Edge';
const validTriggerValue =
prevCappedValue != null &&
((isRaisingEdge &&
prevCappedValue < triggerLevel &&
cappedValue >= triggerLevel) ||
(isLoweringEdge &&
prevCappedValue > triggerLevel &&
cappedValue <= triggerLevel));
return validTriggerValue;
}

export const open =
(deviceInfo: Device): AppThunk<RootState, Promise<void>> =>
async (dispatch, getState) => {
Expand All @@ -223,6 +267,7 @@ export const open =
let prevValue = 0;
let prevCappedValue: number | undefined;
let prevBits = 0;
let prevUnsignedBits = 0;
let nbSamples = 0;
let nbSamplesTotal = 0;

Expand All @@ -243,6 +288,9 @@ export const open =
cappedValue = 0;
}

const channelTriggerStatuses =
state.app.trigger.digitalChannelsTriggersStates;
const unsignedBits = bits !== undefined ? bits & 0xff : 0;
const b16 = convertBits16(bits!);

if (samplingRunning && sampleFreq < maxSampleFreq) {
Expand All @@ -267,20 +315,25 @@ export const open =
prevBits = 0;

if (getRecordingMode(state) === 'Scope') {
const isRaisingEdge = state.app.trigger.edge === 'Raising Edge';
const isLoweringEdge =
state.app.trigger.edge === 'Lowering Edge';
const triggerCategory = state.app.trigger.category;

const validTriggerValue =
prevCappedValue != null &&
((isRaisingEdge &&
prevCappedValue < state.app.trigger.level &&
cappedValue >= state.app.trigger.level) ||
(isLoweringEdge &&
prevCappedValue > state.app.trigger.level &&
cappedValue <= state.app.trigger.level));
triggerCategory === 'Analog'
? checkAnalogTriggerValidity(
cappedValue,
prevCappedValue,
state.app.trigger.level,
state.app.trigger.edge
)
: prevUnsignedBits !== unsignedBits &&
checkDigitalTriggerValidity(
unsignedBits,
prevUnsignedBits,
channelTriggerStatuses
);

prevCappedValue = cappedValue;
prevUnsignedBits = unsignedBits;

if (!DataManager().isInSync()) {
return;
Expand All @@ -296,7 +349,6 @@ export const open =
}
dispatch(setTriggerActive(true));
const biasPercentage = getTriggerBias(getState());
console.log('biasPercentage', biasPercentage);
dispatch(
processTrigger(
cappedValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,11 @@ import {
import { appState } from '../../slices/appSlice';
import { getRecordingMode } from '../../slices/chartSlice';
import {
getTriggerBias,
getTriggerEdge,
getTriggerRecordingLength,
getTriggerType,
getTriggerValue,
setTriggerBias,
setTriggerEdge,
setTriggerLevel,
setTriggerRecordingLength,
setTriggerType,
TriggerEdgeValues,
TriggerTypeValues,
} from '../../slices/triggerSlice';

const CurrentUnitValues = ['mA', '\u00B5A'] as const;
Expand All @@ -50,15 +43,9 @@ const convertToMicroAmps = (unit: CurrentUnit, value: number) => {
}
};

const calculateBiasTime = (recordingLength: number, bias: number) =>
Number((recordingLength * (bias / 100)).toFixed(2));

export default () => {
const dispatch = useDispatch();
const recordingLength = useSelector(getTriggerRecordingLength);
const triggerBias = useSelector(getTriggerBias);
const triggerValue = useSelector(getTriggerValue);
const triggerType = useSelector(getTriggerType);
const triggerEdge = useSelector(getTriggerEdge);
const { samplingRunning } = useSelector(appState);
const dataLoggerActive =
Expand All @@ -73,12 +60,6 @@ export default () => {

const [internalTriggerValue, setInternalTriggerValue] =
useState(triggerValue);
const [internalTriggerLength, setInternalTriggerLength] =
useState(recordingLength);
const [triggerBiasValue, setTriggerBiasValue] = useState(triggerBias);
const [computedBias, setComputedBias] = useState(
calculateBiasTime(internalTriggerLength, triggerBias)
);

useEffect(() => {
if (triggerValue > 1000) {
Expand All @@ -90,59 +71,8 @@ export default () => {
}
}, [triggerValue]);

useEffect(() => {
setInternalTriggerLength(recordingLength);
}, [recordingLength]);

useEffect(() => {
setTriggerBiasValue(triggerBias);
}, [triggerBias]);

return (
<>
<NumberInput
range={{
min: 1,
max: 1000,
decimals: 2,
step: 0.01,
}}
title="Duration of trigger window"
value={internalTriggerLength}
onChange={setInternalTriggerLength}
onChangeComplete={(value: number) => {
dispatch(setTriggerRecordingLength(value));
setComputedBias(calculateBiasTime(value, triggerBias));
}}
unit="ms"
label="Length"
disabled={dataLoggerActive}
showSlider
/>
<NumberInput
range={{
min: 0,
max: 100,
decimals: 0,
step: 1,
}}
title='Trigger bias from "Start of trigger window"'
value={triggerBiasValue}
onChange={setTriggerBiasValue}
onChangeComplete={(value: number) => {
dispatch(setTriggerBias(value));
setComputedBias(
calculateBiasTime(internalTriggerLength, value)
);
}}
unit="%"
label="Bias"
disabled={dataLoggerActive}
showSlider
/>
<span className="tw-mb-2 tw-text-sm tw-text-gray-500">
Computed bias: {computedBias} ms
</span>
<NumberInput
range={{
min: getMin(levelUnit),
Expand Down Expand Up @@ -176,12 +106,6 @@ export default () => {
disabled={dataLoggerActive}
showSlider
/>
<StateSelector
items={[...TriggerTypeValues]}
onSelect={m => dispatch(setTriggerType(TriggerTypeValues[m]))}
selectedItem={triggerType}
disabled={samplingRunning}
/>
<StateSelector
items={[...TriggerEdgeValues]}
onSelect={m => {
Expand Down
80 changes: 80 additions & 0 deletions src/components/SidePanel/DigitalTriggerSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
*/

import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
Dropdown,
DropdownItem,
} from '@nordicsemiconductor/pc-nrfconnect-shared';

import {
DigitalChannelTriggerState,
DigitalChannelTriggerStatesEnum,
getDigitalChannelsTriggersStates,
setDigitalChannelsTriggersStates,
} from '../../slices/triggerSlice';

const dropdownItems: DropdownItem[] = [
{
value: DigitalChannelTriggerStatesEnum.Active,
label: DigitalChannelTriggerStatesEnum.Active,
},
{
value: DigitalChannelTriggerStatesEnum.Inactive,
label: DigitalChannelTriggerStatesEnum.Inactive,
},
{
value: DigitalChannelTriggerStatesEnum.DontCare,
label: DigitalChannelTriggerStatesEnum.DontCare,
},
];

export default () => {
const dispatch = useDispatch();
const digitalChannelTriggerStates = useSelector(
getDigitalChannelsTriggersStates
);

const handleDigitalChannelsTriggerStateChange = (
index: number,
state: DigitalChannelTriggerState
) => {
const newStates = [...digitalChannelTriggerStates];
newStates[index] = state;
dispatch(
setDigitalChannelsTriggersStates({
digitalChannelsTriggers: newStates,
})
);
};

return (
<div className="tw-flex tw-flex-col tw-gap-3">
{digitalChannelTriggerStates.map((state, index) => (
<div
key={`d-trigger-${index + 1}`}
className="tw-flex tw-flex-row tw-gap-3"
>
<div>{`Digital channel ${index}:`}</div>
<Dropdown
onSelect={value => {
handleDigitalChannelsTriggerStateChange(
index,
value.value as DigitalChannelTriggerState
);
}}
items={dropdownItems}
selectedItem={
dropdownItems.find(item => item.value === state) ??
dropdownItems[0]
}
/>
</div>
))}
</div>
);
};
Loading
Loading