'use strict'; // Sequence + setpoint execution. Mirrors the pre-refactor Valve.handleInput // switch but delegates state transitions to host.state. Pre-shutdown ramp-down // to 0 happens here so the existing test contract holds. class FlowController { constructor(host) { this.host = host; this.logger = host.logger; } isValidSourceForMode(source, mode) { const allowed = this.host.config.mode.allowedSources[mode] || []; return allowed.has(source); } async handleInput(source, action, parameter) { if (!this.isValidSourceForMode(source, this.host.currentMode)) { const msg = `Source '${source}' is not valid for mode '${this.host.currentMode}'.`; this.logger.warn(msg); return { status: false, feedback: msg }; } this.logger.info(`Handling input from source '${source}' with action '${action}' in mode '${this.host.currentMode}'.`); try { switch (action) { case 'execSequence': await this.executeSequence(parameter); break; case 'execMovement': await this.setpoint(parameter); break; case 'emergencyStop': case 'emergencystop': this.logger.warn(`Emergency stop activated by '${source}'.`); await this.executeSequence('emergencystop'); break; case 'statusCheck': this.logger.info(`Status Check: Mode = '${this.host.currentMode}', Source = '${source}'.`); break; default: this.logger.warn(`Action '${action}' is not implemented.`); } this.logger.debug(`Action '${action}' successfully executed`); return { status: true, feedback: `Action '${action}' successfully executed.` }; } catch (error) { this.logger.error(`Error handling input: ${error}`); } } async executeSequence(sequenceName) { const sequence = this.host.config.sequences[sequenceName]; if (!sequence || sequence.size === 0) { this.logger.warn(`Sequence '${sequenceName}' not defined.`); return; } if (this.host.state.getCurrentState() === 'operational' && sequenceName === 'shutdown') { this.logger.info(`Machine will ramp down to position 0 before performing ${sequenceName} sequence`); await this.setpoint(0); } this.logger.info(` --------- Executing sequence: ${sequenceName} -------------`); for (const stateName of sequence) { try { await this.host.state.transitionToState(stateName); } catch (error) { this.logger.error(`Error during sequence '${sequenceName}': ${error}`); break; } } } async setpoint(value) { try { if (typeof value !== 'number' || value < 0) { throw new Error('Invalid setpoint: Setpoint must be a non-negative number.'); } await this.host.state.moveTo(value); } catch (error) { this.logger.error(`Error setting setpoint: ${error}`); } } } module.exports = FlowController;