mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-17 18:10:47 -04:00
167 lines
4.0 KiB
JavaScript
167 lines
4.0 KiB
JavaScript
import { DEFAULT_KEYMAP, DEFAULT_MACROS } from './constants.js';
|
|
|
|
function createDriveState() {
|
|
return {
|
|
vector: { x: 0, y: 0, boost: false },
|
|
speeds: { left: 0, right: 0 },
|
|
source: null,
|
|
lastUpdatedAt: 0,
|
|
};
|
|
}
|
|
|
|
function createAuxState() {
|
|
return { main: 0, side: 0, vacuum: 0 };
|
|
}
|
|
|
|
function createCameraState() {
|
|
return {
|
|
enabled: false,
|
|
angle: null,
|
|
config: null,
|
|
};
|
|
}
|
|
|
|
export const initialControlState = {
|
|
roverId: null,
|
|
mode: 'drive',
|
|
drive: createDriveState(),
|
|
aux: createAuxState(),
|
|
camera: createCameraState(),
|
|
macros: DEFAULT_MACROS,
|
|
keymap: DEFAULT_KEYMAP,
|
|
inputs: {},
|
|
settings: {
|
|
status: 'idle',
|
|
error: null,
|
|
lastLoadedAt: null,
|
|
lastSavedAt: null,
|
|
data: null,
|
|
},
|
|
};
|
|
|
|
function mergeSettings(state, payload) {
|
|
const nextSettings = {
|
|
status: 'ready',
|
|
error: null,
|
|
lastLoadedAt: Date.now(),
|
|
lastSavedAt: state.settings.lastSavedAt,
|
|
data: payload ?? state.settings.data,
|
|
};
|
|
const nextState = { ...state, settings: nextSettings };
|
|
if (payload?.keymap) {
|
|
nextState.keymap = { ...state.keymap, ...payload.keymap };
|
|
}
|
|
if (payload?.macros) {
|
|
nextState.macros = payload.macros;
|
|
}
|
|
return nextState;
|
|
}
|
|
|
|
export function controlReducer(state, action) {
|
|
switch (action.type) {
|
|
case 'control/set-rover':
|
|
return {
|
|
...state,
|
|
roverId: action.payload ?? null,
|
|
drive: action.payload ? state.drive : createDriveState(),
|
|
aux: action.payload ? state.aux : createAuxState(),
|
|
};
|
|
case 'control/set-mode':
|
|
return state.mode === action.payload
|
|
? state
|
|
: { ...state, mode: action.payload === 'dock' ? 'dock' : 'drive' };
|
|
case 'control/update-drive': {
|
|
const { vector, speeds, source } = action.payload;
|
|
return {
|
|
...state,
|
|
drive: {
|
|
vector: vector ?? state.drive.vector,
|
|
speeds: speeds ?? state.drive.speeds,
|
|
source: source ?? state.drive.source,
|
|
lastUpdatedAt: Date.now(),
|
|
},
|
|
};
|
|
}
|
|
case 'control/set-aux-motors':
|
|
return {
|
|
...state,
|
|
aux: {
|
|
...state.aux,
|
|
...action.payload,
|
|
},
|
|
};
|
|
case 'control/set-camera-config':
|
|
return {
|
|
...state,
|
|
camera: {
|
|
...state.camera,
|
|
enabled: Boolean(action.payload?.config),
|
|
config: action.payload?.config ?? null,
|
|
angle:
|
|
typeof action.payload?.angle === 'number'
|
|
? action.payload.angle
|
|
: action.payload?.config
|
|
? action.payload.config.homeAngle ?? state.camera.angle
|
|
: null,
|
|
},
|
|
};
|
|
case 'control/set-camera-angle':
|
|
return {
|
|
...state,
|
|
camera: { ...state.camera, angle: action.payload },
|
|
};
|
|
case 'control/register-input-state': {
|
|
const sourceKey = action.payload?.source || 'unknown';
|
|
return {
|
|
...state,
|
|
inputs: {
|
|
...state.inputs,
|
|
[sourceKey]: {
|
|
...(state.inputs[sourceKey] ?? {}),
|
|
...action.payload?.state,
|
|
updatedAt: Date.now(),
|
|
},
|
|
},
|
|
};
|
|
}
|
|
case 'control/settings/loading':
|
|
return {
|
|
...state,
|
|
settings: {
|
|
...state.settings,
|
|
status: 'loading',
|
|
error: null,
|
|
},
|
|
};
|
|
case 'control/settings/loaded':
|
|
return mergeSettings(state, action.payload);
|
|
case 'control/settings/error':
|
|
return {
|
|
...state,
|
|
settings: {
|
|
...state.settings,
|
|
status: 'error',
|
|
error: action.payload,
|
|
},
|
|
};
|
|
case 'control/set-keymap':
|
|
return {
|
|
...state,
|
|
keymap: { ...state.keymap, ...(action.payload ?? {}) },
|
|
};
|
|
case 'control/set-macros':
|
|
return {
|
|
...state,
|
|
macros: Array.isArray(action.payload) ? action.payload : state.macros,
|
|
};
|
|
case 'control/reset':
|
|
return {
|
|
...state,
|
|
drive: createDriveState(),
|
|
aux: createAuxState(),
|
|
};
|
|
default:
|
|
return state;
|
|
}
|
|
}
|