import { createSlice, PayloadAction } from "@reduxjs/toolkit"; export interface DeviceEventsState { ksx: number[]; // 32 Slots: Schleifenmessung aktiv ksy: number[]; // 32 Slots: TDR-Messung aktiv ksz: number[]; // 32 Slots: Comparison (ehem. Abgleich) aktiv anyLoopActive: boolean; anyTdrActive: boolean; anyComparisonActive: boolean; // renamed from anyAlignmentActive loopStartedAt: number | null; // unix ms timestamp when KSX became active tdrStartedAt: number | null; // unix ms timestamp when KSY became active comparisonStartedAt: number | null; // renamed from alignmentStartedAt // per-slot start timestamps (persistable) loopStartedAtBySlot: (number | null)[]; tdrStartedAtBySlot: (number | null)[]; comparisonStartedAtBySlot: (number | null)[]; // renamed from alignmentStartedAtBySlot } const ZERO32 = Array.from({ length: 32 }, () => 0); const initialState: DeviceEventsState = { ksx: ZERO32.slice(), ksy: ZERO32.slice(), ksz: ZERO32.slice(), anyLoopActive: false, anyTdrActive: false, anyComparisonActive: false, loopStartedAt: null, tdrStartedAt: null, comparisonStartedAt: null, loopStartedAtBySlot: Array.from({ length: 32 }, () => null), tdrStartedAtBySlot: Array.from({ length: 32 }, () => null), comparisonStartedAtBySlot: Array.from({ length: 32 }, () => null), }; export const deviceEventsSlice = createSlice({ name: "deviceEvents", initialState, reducers: { setEvents( state, action: PayloadAction<{ ksx?: number[]; ksy?: number[]; ksz?: number[] }> ) { const prevLoop = state.anyLoopActive; const prevTdr = state.anyTdrActive; const prevCompare = state.anyComparisonActive; const prevKsx = state.ksx.slice(); const prevKsy = state.ksy.slice(); const prevKsz = state.ksz.slice(); const to32 = (arr?: number[]) => { if (!Array.isArray(arr)) return ZERO32.slice(); const a = arr .slice(0, 32) .map((v) => (typeof v === "number" && v ? 1 : 0)); while (a.length < 32) a.push(0); return a; }; state.ksx = to32(action.payload.ksx); state.ksy = to32(action.payload.ksy); state.ksz = to32(action.payload.ksz); state.anyLoopActive = state.ksx.some((v) => v === 1); state.anyTdrActive = state.ksy.some((v) => v === 1); state.anyComparisonActive = state.ksz.some((v) => v === 1); // Global transition detection if (!prevLoop && state.anyLoopActive) state.loopStartedAt = Date.now(); if (prevLoop && !state.anyLoopActive) state.loopStartedAt = null; if (!prevTdr && state.anyTdrActive) state.tdrStartedAt = Date.now(); if (prevTdr && !state.anyTdrActive) state.tdrStartedAt = null; if (!prevCompare && state.anyComparisonActive) state.comparisonStartedAt = Date.now(); if (prevCompare && !state.anyComparisonActive) state.comparisonStartedAt = null; // Per-slot transition detection for (let i = 0; i < 32; i++) { if (prevKsx[i] === 0 && state.ksx[i] === 1) { state.loopStartedAtBySlot[i] = Date.now(); } else if (prevKsx[i] === 1 && state.ksx[i] === 0) { state.loopStartedAtBySlot[i] = null; } if (prevKsy[i] === 0 && state.ksy[i] === 1) { state.tdrStartedAtBySlot[i] = Date.now(); } else if (prevKsy[i] === 1 && state.ksy[i] === 0) { state.tdrStartedAtBySlot[i] = null; } if (prevKsz[i] === 0 && state.ksz[i] === 1) { state.comparisonStartedAtBySlot[i] = Date.now(); } else if (prevKsz[i] === 1 && state.ksz[i] === 0) { state.comparisonStartedAtBySlot[i] = null; } } }, resetEvents(state) { state.ksx = ZERO32.slice(); state.ksy = ZERO32.slice(); state.ksz = ZERO32.slice(); state.anyLoopActive = false; state.anyTdrActive = false; state.anyComparisonActive = false; state.loopStartedAt = null; state.tdrStartedAt = null; state.comparisonStartedAt = null; state.loopStartedAtBySlot = Array.from({ length: 32 }, () => null); state.tdrStartedAtBySlot = Array.from({ length: 32 }, () => null); state.comparisonStartedAtBySlot = Array.from({ length: 32 }, () => null); }, initPersistedTimings( state, action: PayloadAction<{ loop?: (number | null)[]; tdr?: (number | null)[]; compare?: (number | null)[]; // renamed key }> ) { const normalize = (arr?: (number | null)[]) => { const out: (number | null)[] = Array.isArray(arr) ? arr.slice(0, 32).map((v) => (typeof v === "number" ? v : null)) : []; while (out.length < 32) out.push(null); return out; }; if (action.payload.loop) state.loopStartedAtBySlot = normalize(action.payload.loop); if (action.payload.tdr) state.tdrStartedAtBySlot = normalize(action.payload.tdr); if (action.payload.compare) state.comparisonStartedAtBySlot = normalize(action.payload.compare); }, }, }); export const { setEvents, resetEvents, initPersistedTimings } = deviceEventsSlice.actions; export default deviceEventsSlice.reducer;