// ----------------------------------------------------------------------------- /// @file SignalProfileGenerator.c /// @brief Description // ----------------------------------------------------------------------------- // Micro-Key bv // Industrieweg 28, 9804 TG Noordhorn // Postbus 92, 9800 AB Zuidhorn // The Netherlands // Tel: +31 594 503020 // Fax: +31 594 505825 // Email: support@microkey.nl // Web: www.microkey.nl // ----------------------------------------------------------------------------- /// $Revision$ /// $Author$ /// $Date$ // (c) 2017 Micro-Key bv // ----------------------------------------------------------------------------- /// @file SignalProfileGenerator.c /// @ingroup {group_name} // ----------------------------------------------------------------------------- // Include files // ----------------------------------------------------------------------------- #include "SignalProfileGenerator.h" #include "PCBA.h" #include "Logger.h" // ----------------------------------------------------------------------------- // Constant and macro definitions // ----------------------------------------------------------------------------- #define SPG_0V_OFFSET_ANODE (1153) #define SPG_0V_OFFSET_CMCP (-241) #define SPG_0V_OFFSET_TESLA (681) #define SPG_PAUSE_SOFTSTART (300) // 5 minutes softstart after pause #define SPG_FIXPOINT_FACTOR (1000) // ----------------------------------------------------------------------------- // Type definitions // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // File-scope variables // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // Function declarations // ----------------------------------------------------------------------------- static inline void incrementSecondsCounter(struct SignalProfileGenerator* self); // ----------------------------------------------------------------------------- // Function definitions // ----------------------------------------------------------------------------- ErrorStatus SignalProfileGenerator_construct(struct SignalProfileGenerator* self, const struct RepairPreset* preset) { ErrorStatus returnValue = SUCCESS; if (!self->initialized) { if (preset != NULL) { self->secondsCounter = 0; self->currentPresetIndex = 0; self->currentState = SPG_PREPARE; self->initialized = true; self->isProcessRunning = false; self->repairPreset = preset; self->signal = 0; self->statePriorToPause = SPG_PREPARE; self->totalRunTime = 0; self->totalStartTime = 0; self->pauseSoftStartTimer = 0; self->pauseStartTime = 0; self->pauseStartVoltage = 0; self->softStartTimer = 0; self->startTime = 0; self->startVoltage = 0; self->voltageHoldTimer = 0; self->voltagePriorToPause = 0; } else { returnValue = ERROR; } } else { returnValue = ERROR; } return returnValue; } void SignalProfileGenerator_destruct(struct SignalProfileGenerator* self) { self->initialized = false; } void SignalProfileGenerator_calculate(struct SignalProfileGenerator* self) { if (self->initialized) { switch (self->currentState) { case SPG_PREPARE: { // Prepare a new repair process //Load the timers self->startTime = self->secondsCounter; self->softStartTimer = self->secondsCounter + self->repairPreset->preset[self->currentPresetIndex].softstartDuration; self->voltageHoldTimer = self->secondsCounter + self->repairPreset->preset[self->currentPresetIndex].duration + self->repairPreset->preset[self->currentPresetIndex].softstartDuration; // Calculate the complete timer for ALL stages - but only when in first stage, so this // calculation does not get re-done with every new stage if (self->currentPresetIndex == 0) { // RESET the total runtime prior to new calculation // Take the current time (starttime) as offset self->totalStartTime = self->startTime; self->totalRunTime = self->startTime; // The total run-time is the sum of all softstart times and hold times int loopcounter; for (loopcounter = 0; loopcounter < self->repairPreset->numberOfStages; loopcounter++) { self->totalRunTime += self->repairPreset->preset[loopcounter].softstartDuration; self->totalRunTime += self->repairPreset->preset[loopcounter].duration; } } // If first preset, start voltage is 0 (or the representative 0-offset values per PCBA) if (self->currentPresetIndex == 0) { // RESET the signal to 0 at the very start of a new signalprofile self->signal = 0; if (PCBA_getInstance()->pcba == PCBA_Anode) { self->startVoltage = SPG_0V_OFFSET_ANODE; } else if (PCBA_getInstance()->pcba == PCBA_CathodeMCP) { self->startVoltage = SPG_0V_OFFSET_CMCP; } else if (PCBA_getInstance()->pcba == PCBA_Tesla) { self->startVoltage = SPG_0V_OFFSET_TESLA; } } else { // Softstart for another stage - start voltage is hold voltage of previous preset self->startVoltage = self->repairPreset->preset[self->currentPresetIndex - 1].voltage; } incrementSecondsCounter(self); self->currentState = SPG_SOFTSTART; break; } case SPG_SOFTSTART: { self->isProcessRunning = true; self->signal = ((self->repairPreset->preset[self->currentPresetIndex].voltage * SPG_FIXPOINT_FACTOR - (self->startVoltage * SPG_FIXPOINT_FACTOR)) / self->repairPreset->preset[self->currentPresetIndex].softstartDuration) * (self->secondsCounter - self->startTime) + (self->startVoltage * SPG_FIXPOINT_FACTOR); self->signal = self->signal / SPG_FIXPOINT_FACTOR; incrementSecondsCounter(self); // Check for end of softstart if (self->softStartTimer < self->secondsCounter) { // softstart finished self->currentState = SPG_VOLTAGE_HOLD; } break; } case SPG_VOLTAGE_HOLD: { self->signal = self->repairPreset->preset[self->currentPresetIndex].voltage; incrementSecondsCounter(self); // Check for end of voltage hold if (self->voltageHoldTimer < self->secondsCounter) { // softstart finished self->currentState = SPG_FINISH_VERIFY; } break; } case SPG_PAUSE: { // Nothing happens here, just wait until the process gets continued break; } case SPG_PAUSE_RESTORE: { self->pauseStartTime = self->secondsCounter; self->pauseSoftStartTimer = self->secondsCounter + SPG_PAUSE_SOFTSTART; self->softStartTimer = self->softStartTimer + SPG_PAUSE_SOFTSTART; self->voltageHoldTimer = self->voltageHoldTimer + SPG_PAUSE_SOFTSTART; self->currentState = SPG_PAUSE_RESTORE_SOFTSTART; // Add the pause time twice because the total time actually increases self->totalRunTime = self->totalRunTime + SPG_PAUSE_SOFTSTART; break; } case SPG_PAUSE_RESTORE_SOFTSTART: { if (PCBA_getInstance()->pcba == PCBA_Anode) { self->pauseStartVoltage = SPG_0V_OFFSET_ANODE; } else if (PCBA_getInstance()->pcba == PCBA_CathodeMCP) { self->pauseStartVoltage = SPG_0V_OFFSET_CMCP; } else if (PCBA_getInstance()->pcba == PCBA_Tesla) { self->pauseStartVoltage = SPG_0V_OFFSET_TESLA; } self->signal = ((self->voltagePriorToPause * SPG_FIXPOINT_FACTOR - self->pauseStartVoltage * SPG_FIXPOINT_FACTOR) / SPG_PAUSE_SOFTSTART) * (self->secondsCounter - self->pauseStartTime) + self->pauseStartVoltage * SPG_FIXPOINT_FACTOR; self->signal = self->signal / SPG_FIXPOINT_FACTOR; incrementSecondsCounter(self); // Check for end of softstart if (self->pauseSoftStartTimer < self->secondsCounter) { // softstart finished self->currentState = self->statePriorToPause; } break; } case SPG_FINISH_VERIFY: { incrementSecondsCounter(self); // The current preset might contain multiple stages, so before going to FINISHED state // verify that no further stage must be entered // presetIndex carries the current index in the preset array // number of stages is 1-based (Starting with 1) while presetIndex is 0-based // So, the verification must compensate for the different bases if (self->repairPreset->numberOfStages > (self->currentPresetIndex + 1)) { // A next stage is available self->currentPresetIndex++; self->currentState = SPG_PREPARE; } else { self->currentState = SPG_FINISHED; } break; } case SPG_FINISHED: { self->isProcessRunning = false; self->signal = 0; break; } } } else { self->signal = -1; } } void SignalProfileGenerator_pause(struct SignalProfileGenerator* self) { self->voltagePriorToPause = self->signal; self->statePriorToPause = self->currentState; self->currentState = SPG_PAUSE; } bool SignalProfileGenerator_isPaused(struct SignalProfileGenerator* self) { bool returnValue; if (self->currentState == SPG_PAUSE) { returnValue = true; } else { returnValue = false; } return returnValue; } bool SignalProfileGenerator_isFinished(struct SignalProfileGenerator* self) { bool returnValue; if (self->currentState == SPG_FINISHED) { returnValue = true; } else { returnValue = false; } return returnValue; } void SignalProfileGenerator_continue(struct SignalProfileGenerator* self) { self->currentState = SPG_PAUSE_RESTORE; } uint32_t SignalProfileGenerator_getRemainingTime(const struct SignalProfileGenerator* self) { uint32_t returnValue; if ((self->initialized) && (self->isProcessRunning)) { if (self->totalRunTime >= self->secondsCounter) { returnValue = (self->totalRunTime - self->secondsCounter); } else { // ERROR - negative time returnValue = 0; } } else { returnValue = 0xFFFFFFFF; } return returnValue; } uint32_t SignalProfileGenerator_getTotalRepairTime(const struct SignalProfileGenerator* self) { uint32_t returnValue; if ((self->initialized) && (self->isProcessRunning)) { returnValue = (self->totalRunTime - self->totalStartTime); } else { returnValue = 0xFFFFFFFF; } return returnValue; } static inline void incrementSecondsCounter(struct SignalProfileGenerator* self) { self->secondsCounter++; }