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.
ICE-Application/src/ConfigurationHandler/Controls/SensorErrorControl.cpp
- Committer:
- jmarkel44
- Date:
- 2017-01-24
- Revision:
- 0:61364762ee0e
File content as of revision 0:61364762ee0e:
/****************************************************************************** * * 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(); }