Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: ICE-Application/src/ConfigurationHandler/Controls/SensorErrorControl.cpp
- Revision:
- 2:02cb20446785
- Parent:
- 1:b2e90cda7a5a
--- a/ICE-Application/src/ConfigurationHandler/Controls/SensorErrorControl.cpp Tue Jan 24 19:06:45 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,418 +0,0 @@ -/****************************************************************************** -* -* File: SensorErrorControl.cpp -* Desciption: ICE Sensor Error Control class implementation -* -*****************************************************************************/ -#include "SensorErrorControl.h" -#include "cJSON.h" -#include "ModbusMasterApi.h" -#include "utilities.h" -#include "ICELog.h" -#include <string> -#include <iostream> -#include <iomanip> -#include <stdarg.h> - -using namespace std; - -// for debugging - this can be set via the console command: -// "debug-se 1 -bool debugSensorError = false; - -static void debug(const char *fmt, ...) -{ - if ( debugSensorError ) { - va_list vargs; - va_start(vargs, fmt); - vfprintf(stdout, fmt, vargs); - va_end(vargs); - } -} - -// -// method: load -// description: load data from the control file -// -// @param[in] _controlFile -> the control file -// @return true if loaded; false otherwise -// -bool SensorErrorControl::load(const std::string _controlFile) -{ - controlFile = _controlFile; - - // read the data into a buffer - char dataBuf[MAX_FILE_SIZE]; - - bool rc = GLOBAL_mdot->readUserFile(controlFile.c_str(), (void *)dataBuf, sizeof(dataBuf)); - if ( rc != true ) { - logError("%s: failed to read %s", __func__, controlFile.c_str()); - // caller should destroy the object - return false; - } - - // validate the JSON formatted control data - if ( !validateControlData(dataBuf) ) { - logError("%s: failed to validate control data", __func__); - return false; - } - - // copy the control data - copyControlData(dataBuf); - - ModbusValue val; - // validate the input - if ( ModbusMasterReadRegister(input, &val) == false ) { - logError("%s failed to find input %s", id.c_str(), input.c_str()); - return false; - } - - isVirtualOutput = Util_isVirtualOutput(output) ? true : false; - return true; -} - -// -// @method: validateControlData -// @description: vaqlidate the JSON formatted string -// -// @param[in] buf -> JSON formatted string -// @param[out] none -// @return true if valid; false otherwise -// -bool SensorErrorControl::validateControlData(const char *buf) -{ - bool rc = true; - - // parse the data - cJSON * root = cJSON_Parse(buf); - - if ( !cJSON_HasObjectItem(root, "id") || - !cJSON_HasObjectItem(root, "priority") || - !cJSON_HasObjectItem(root, "input") || - !cJSON_HasObjectItem(root, "output") || - !cJSON_HasObjectItem(root, "dutyCycle") || - !cJSON_HasObjectItem(root, "interval") ) { - logError("%s: control file is missing expected tags", __func__); - rc = false; - } - - cJSON_Delete(root); - return rc; -} - -// -// method: copyControlData -// description: copy the data from the control file to the object -// -// @param[in] buf -> JSON formatted string -// @param[out] none -// @return none -// -void SensorErrorControl::copyControlData(const char *buf) -{ - cJSON *root = cJSON_Parse(buf); - - id = cJSON_GetObjectItem(root, "id")->valuestring; - priority = atoi(cJSON_GetObjectItem(root, "priority")->valuestring); - input = cJSON_GetObjectItem(root, "input")->valuestring; - output = cJSON_GetObjectItem(root, "output")->valuestring; - dutyCycle.dutyCycle = atoi(cJSON_GetObjectItem(root, "dutyCycle")->valuestring); - dutyCycle.interval = atoi(cJSON_GetObjectItem(root, "interval")->valuestring); - - cJSON_Delete(root); -} - -// -// @method: start -// @description: put the control in the start state -// -// @param[in] none -// @param[out] none -// @return none -// -void SensorErrorControl::start(void) -{ - currentState = STATE_START; -} - -// -// @method update -// @description run the simplified state machine -// -// @param[in] none -// @param[out] none -// @return OK on success; error otherwise -// -SensorErrorControlError_t SensorErrorControl::update(void) -{ - SensorErrorControlError_t rc = SENSOR_ERROR_CONTROL_OK; - - switch (this->currentState) { - case STATE_INIT: - // do nothing: control must be programmatically started - break; - case STATE_START: - if ( this->isSensorError() ) { - if ( dutyCycle.dutyCycle > 0 ) { - this->startDutyTimer(); - this->currentState = STATE_DUTY_CYCLE_ON; - sendMailToOutput(ACTION_CONTROL_ON); - debug("\r%s: [STARTUP]->sensor error->[DUTY_CYCLE_ON] time=%lu\n", id.c_str(), time(0)); - } else { - // this is a fixed-off state - this->stopDutyTimer(); // probably not needed - this->currentState = STATE_DUTY_CYCLE_OFF; - // tell the output task to turn off the relay - sendMailToOutput(ACTION_CONTROL_OFF); - debug("\r%s: [STARTUP]->sensor error (no duty)->[DUTY_CYCLE_OFF] %lu\n", id.c_str(), time(0)); - } - } else { - // input signal is OK - debug("\r%s: [STARTUP]->OK->[OFF] %lu\n", id.c_str(), time(0)); - this->currentState = STATE_CONTROL_OFF; - } - break; - case STATE_CONTROL_OFF: - if ( isSensorError() ) { - if ( dutyCycle.dutyCycle > 0 ) { - this->startDutyTimer(); - this->currentState = STATE_DUTY_CYCLE_ON; - sendMailToOutput(ACTION_CONTROL_ON); - debug("\r%s: [STARTUP]->sensor error->[DUTY_CYCLE_ON] %lu\n", id.c_str(), time(0)); - } else { - // this is a fixed off state - this->stopDutyTimer(); // probably not needed - this->currentState = STATE_DUTY_CYCLE_OFF; - // tell the output task to turn off the relay - sendMailToOutput(ACTION_CONTROL_OFF); - debug("\r%s: [STARTUP]->sensor error (no duty)->[DUTY_CYCLE_OFF] %lu\n", id.c_str(), time(0)); - } - } else { - // input signal is OK, so don't do anything - } - break; - case STATE_DUTY_CYCLE_ON: - if ( !isSensorError() ) { - this->stopDutyTimer(); - this->currentState = STATE_CONTROL_OFF; - this->unregisterControl(); - debug("\r%s: [DUTY_CYCLE_ON]->no error->[OFF] %lu\n", id.c_str(), time(0)); - - } else if ( dutyOnExpired() ) - if ( dutyCycle.dutyCycle < 100 ) { - this->currentState = STATE_DUTY_CYCLE_OFF; - sendMailToOutput(ACTION_CONTROL_OFF); - debug("\r%s: [DUTY_CYCLE_ON]->on expired->[DUTY_CYCLE_OFF] %lu\n", id.c_str(), time(0)); - } else { - // fixed-on state - // do nothing - we'll need to wait for the sensor error - // to clear before something can happen - } - break; - case STATE_DUTY_CYCLE_OFF: - if ( !isSensorError() ) { - // there is no sensor error, so unregister the control and cleanup - this->stopDutyTimer(); - this->currentState = STATE_CONTROL_OFF; - this->unregisterControl(); - debug("\r%s: [DUTY_CYCLE_OFF]->no error->[OFF] %lu\n", id.c_str(), time(0)); - stopDutyTimer(); - } else if ( dutyOffExpired() ) { - if ( dutyCycle.dutyCycle > 0 ) { - // we go back to the OFF state so the start and expiration - // times are recalculated - this->currentState = STATE_CONTROL_OFF; - sendMailToOutput(ACTION_CONTROL_OFF); - debug("\r%s: [DUTY_CYCLE_OFF]->off expired->[OFF] %lu\n", id.c_str(), time(0)); - } else { - // fixed-off state - // do nothing - we'll need to wait for the sensor error - // to clear before something can happen - } - } - break; - default: - logError("%s: unknown state\n", __func__); - rc = SENSOR_ERROR_CONTROL_UNK_STATE; - break; - } - return rc; -} - -// -// @method: isSensorError -// @description: reads the modbus register to get the error condition of -// the input signal -// -// @param[in] none -// @param[out] none -// @return true if in error; false otherwise -// -bool SensorErrorControl::isSensorError() -{ - ModbusValue val; - - if ( ModbusMasterReadRegister(this->input, &val) != true ) { - logError("Failed to read %s\n", this->input.c_str()); - return true; - } else if ( val.errflag ) { - // input is in sensor error - return true; - } - return false; -} - -// -// @method: dutyOnExpired -// @description: returns true of duty ON time expired -// -// @param[in] none -// @param[out] none -// @return true if expired; false otherwise -// -bool SensorErrorControl::dutyOnExpired(void) -{ - return (time(0) >= duty_timer.offTime); -} - -// -// @method: dutyOffExpired -// @description: returns true of duty OFF time expired -// -// @param[in] none -// @param[out] none -// @return true if expired; false otherwise -// -bool SensorErrorControl::dutyOffExpired(void) -{ - return (duty_timer.expirationTime < time(0)); -} - -// -// method: startDutyTimer -// descrption: start the sensor error duty-timer -// -// @param none -// @return none -// -void SensorErrorControl::startDutyTimer(void) -{ - unsigned long currentTime = time(0); - unsigned long period = dutyCycle.interval * 60; - - duty_timer.offTime = currentTime + ((double)period * ((double)dutyCycle.dutyCycle/100.0)); - duty_timer.expirationTime = currentTime + period; - - debug("\r%s:%s-> currentTime = %lu\n", __func__, id.c_str(), currentTime); - debug("\r%s:%s-> off Time = %lu\n", __func__, id.c_str(), duty_timer.offTime); - debug("\r%s:%s-> expiration = %lu\n", __func__, id.c_str(), duty_timer.expirationTime); -} - -// -// method: stopDutyTimer -// descrption: stop the sensor error duty-timer -// -// @param none -// @return none -// -void SensorErrorControl::stopDutyTimer(void) -{ - memset(&duty_timer, 0, sizeof(duty_timer)); -} - -// -// method: sendMailToOutput -// description: send a message to the output thread -// -// @param[in] action -> on, off, etc. -// @param[out] none -// @return -// -void SensorErrorControl::sendMailToOutput(OutputAction action) -{ - - if ( isVirtualOutput ) { - debug("%s:%s updating the virtual output %s\n", __func__, id.c_str(), output.c_str()); - ModbusMasterWriteRegister(this->output, - (action == ACTION_CONTROL_ON) ? 1.0 : 0.0); - } else { - debug("%s:%s sensor error control attempting to send action %d\n", - __func__, id.c_str(), action); - - OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc(); - memset(output_mail, 0, sizeof(OutputControlMsg_t)); - - output_mail->action = action; - output_mail->controlType = CONTROL_SENSOR_ERROR; - output_mail->priority = this->priority; - - strncpy(output_mail->input_tag, this->input.c_str(), sizeof(output_mail->input_tag)-1); - strncpy(output_mail->output_tag, this->output.c_str(), sizeof(output_mail->output_tag)-1); - strncpy(output_mail->id, this->id.c_str(), sizeof(output_mail->id)-1); - - OutputMasterMailBox.put(output_mail); - } -} - -// -// @method: unregisterControl -// @description: unregister the control with the output task -// -// @param[in] none -// @param[out] none -// @return none -// -void SensorErrorControl::unregisterControl(void) -{ - if ( isVirtualOutput ) { - debug("%s: %s attempting to unregister virtual output %s\n", __func__, id.c_str(), output.c_str()); - ModbusMasterWriteRegister(output, 0.0); - } else { - debug("%s: %s attempting to unregister output %s\n", - __func__, id.c_str(), output.c_str()); - - OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc(); - memset(output_mail, 0, sizeof(OutputControlMsg_t)); - - output_mail->action = ACTION_CONTROL_UNREGISTER; - output_mail->controlType = CONTROL_FAILSAFE; - output_mail->priority = this->priority; - strncpy(output_mail->output_tag, this->output.c_str(), sizeof(output_mail->output_tag)-1); - strncpy(output_mail->id, this->id.c_str(), sizeof(output_mail->id)-1); - - OutputMasterMailBox.put(output_mail); - } -} - -// -// @method: display -// @description: show the pertinents -// -// @param[in] none -// @param[out] none -// @return none -// -void SensorErrorControl::display(void) -{ - const char *mapper[] = { "INIT", - "START", - "OFF", - "DUTY CYCLE ON", - "DUTY CYCLE OFF", - "invalid" - }; - - printf("\r\n"); - std::cout << left << setw(10) << setfill(' ') << "sensor error: "; - std::cout << left << setw(40) << setfill(' ') << controlFile; - std::cout << left << setw(20) << setfill(' ') << id; - std::cout << left << setw(6) << setfill(' ') << priority; - std::cout << left << setw(20) << setfill(' ') << input; - std::cout << left << setw(20) << setfill(' ') << output; - std::cout << left << setw(16) << setfill(' ') << mapper[currentState]; - std::cout << "duty cycle: " << left << setw(4) << setfill(' ') << dutyCycle.dutyCycle; - std::cout << "interval: " << left << setw(4) << setfill(' ') << dutyCycle.interval; - - std::cout.flush(); -} -