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/SetpointControl.cpp
- Committer:
- jmarkel44
- Date:
- 2017-01-24
- Revision:
- 0:61364762ee0e
File content as of revision 0:61364762ee0e:
/****************************************************************************** * * File: SetpointControl.cpp * Desciption: ICE Setpoint Control class implementation * *****************************************************************************/ #include "SetpointControl.h" #include "ICELog.h" #include "cJSON.h" #include "ModbusMasterApi.h" #include "global.h" #include "utilities.h" #include <string> #include <iostream> #include <iomanip> #include <stdarg.h> #include <stdlib.h> // for debugging - this can be set via the console command: // "debug-sp 1 or debug-sp 0 bool debugSetpointControl = false; static void debug(const char *fmt, ...) { if ( debugSetpointControl ) { va_list vargs; va_start(vargs, fmt); vfprintf(stdout, fmt, vargs); va_end(vargs); } } #ifdef MDOT_ICE extern mDot *GLOBAL_mdot; #endif // // method: load // description: open the configuration file and assign data to the // setpoint control object // // @param controlFile -> name of the control file // @return true if data is assigned; false on error // bool SetpointControl::load(std::string _controlFile) { controlFile = _controlFile; char dataBuf[MAX_FILE_SIZE]; // read the control data 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 control data if ( !validateControlData(dataBuf) ) { logError("%s: failed to validate control data", __func__); return false; } // copy control data copyControlData(dataBuf); ModbusValue val; // validate the input & output if ( ModbusMasterReadRegister(input, &val) == false ) { logError("%s failed to find the input %s", id.c_str(), input.c_str()); return false; } if ( ModbusMasterReadRegister(output, &val) == false ) { logError("%s failed to find output %s", id.c_str(), output.c_str()); return false; } isVirtualOutput = Util_isVirtualOutput(output) ? true : false; return true; } // // method: validateControlData // description: validate JSON formatted string // bool SetpointControl::validateControlData(const char *buf) { bool rc = true; 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, "setpoint") || !cJSON_HasObjectItem(root, "prodfact") || !cJSON_HasObjectItem(root, "actingDir") || !cJSON_HasObjectItem(root, "tol") ) { logError("Setpoint control is missing expected tags\n"); rc = false; } cJSON_Delete(root); return rc; } // // method: copyControlData // description: copy JSON formatted data // void SetpointControl::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; setpoint = atof(cJSON_GetObjectItem(root,"setpoint")->valuestring); productFactor = atof(cJSON_GetObjectItem(root, "prodfact")->valuestring); actingDir = atoi(cJSON_GetObjectItem(root, "actingDir")->valuestring); tolerance = atof(cJSON_GetObjectItem(root, "tol")->valuestring); cJSON_Delete(root); } // // method: start // description: start the setpoint control // // @param none // @return none // void SetpointControl::start(void) { // this is the initial state; what else needs to be done?? this->currentState = STATE_STARTUP; } // // method: // description: based on the state of the control, check for // under limit and over limit values, adjust the // state accordingly // // @param none // @return none // SetpointControlError_t SetpointControl::update(void) { SetpointControlError_t rc = SETPOINT_CONTROL_OK; switch (this->currentState) { case STATE_INIT: // do nothing break; case STATE_STARTUP: if ( this->underLimit() ) { // start the feed right away this->startFeed(); this->currentState = STATE_CONTROL_ON; debug("\r%s: [START]->under limit->[ON]\n", id.c_str()); } else { this->currentState = STATE_CONTROL_OFF; this->stopFeed(); debug("\r%s: [START]->!under limit->[OFF]\n", id.c_str()); } break; case STATE_CONTROL_ON: if ( this->overLimit() ) { // stop the feed this->stopFeed(); this->currentState = STATE_CONTROL_OFF; debug("\r%s: [ON]->over limit->[OFF]\n", id.c_str()); } else { // do nothing } break; case STATE_CONTROL_OFF: if ( this->underLimit() ) { // start the feed this->startFeed(); this->currentState = STATE_CONTROL_ON; debug("\r%s: [OFF]->under limit->[ON]\n", id.c_str()); } else { // do nothing } break; default: rc = SETPOINT_CONTROL_UNK_STATE; break; } return rc; } // // method: overLimit // description: (see @return) // // @param none // @return true if product is over the upper limit for normal mode // or under the limit for reverse mode; false otherwise // bool SetpointControl::overLimit(void) { ModbusValue value; ModbusMasterReadRegister( input, &value ); float flimit; if ( !actingDir ) { flimit = setpoint + tolerance; return (value.value >= flimit); } else { flimit = setpoint - tolerance; return (value.value <= flimit); } } // // method: underLimit // description: (see @return) // // @param none // @return true if product is under lower limit for normal mode or // over the upper limit for reverse mode; false otherwise // bool SetpointControl::underLimit(void) { ModbusValue value; ModbusMasterReadRegister( input, &value ); float flimit; if ( !actingDir ) { flimit = setpoint - tolerance; return (value.value <= flimit); } else { flimit = setpoint + tolerance; return (value.value >= flimit); } } // // method: startFeed() // description: send ON indication to Output Master for this control's // relay // // @param none // @return none // void SetpointControl::startFeed(void) { logInfo("%s: %s attempting to start feed on relay %s\n", __func__, controlFile.c_str(), output.c_str()); if ( isVirtualOutput ) { ModbusMasterWriteRegister(output, 1.0); } else { OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc(); memset(output_mail, 0, sizeof(OutputControlMsg_t)); output_mail->action = ACTION_CONTROL_ON; output_mail->controlType = CONTROL_SETPOINT; 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); output_mail->priority = this->priority; strncpy(output_mail->id, this->id.c_str(), sizeof(output_mail->id)-1); OutputMasterMailBox.put(output_mail); } } // // method: stopFeed // description: send OFF indication to Output Master for this control's // relay // // @param none // @return none // void SetpointControl::stopFeed(void) { logInfo("%s: %s attempting to stop feed on relay %s\n", __func__, controlFile.c_str(), output.c_str()); if ( isVirtualOutput ) { ModbusMasterWriteRegister(output, 0.0); } else { OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc(); memset(output_mail, 0, sizeof(OutputControlMsg_t)); output_mail->action = ACTION_CONTROL_OFF; output_mail->controlType = CONTROL_SETPOINT; 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); output_mail->priority = this->priority; strncpy(output_mail->id, this->id.c_str(), sizeof(output_mail->id)-1); OutputMasterMailBox.put(output_mail); } } // // method: unregisterControl // description: send OFF indication to Output Master for this control's // relay // // @param none // @return none // void SetpointControl::unregisterControl(void) { logInfo("%s: %s attempting to unregister %s\n", __func__, id.c_str(), controlFile.c_str()); if ( isVirtualOutput ) { ModbusMasterWriteRegister(output, 0.0); } else { OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc(); memset(output_mail, 0, sizeof(OutputControlMsg_t)); output_mail->action = ACTION_CONTROL_UNREGISTER; output_mail->controlType = CONTROL_MANUAL; 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: display the control's information // // @param none // @return none // void SetpointControl::display(void) { // NOTE: this mapping must be 1:1 with "State" enumeration in SetpointControl.h std::string mapper[] = { "INIT", "STARTUP", "CONTROL_OFF", "CONTROL_ON", "CONTROL_DISABLE", "CONTROL_PAUSE", "CONTROL_MAX" }; ModbusValue inputValue; ModbusMasterReadRegister(input, &inputValue); printf("\r\n"); std::cout << std::left << std::setw(10) << std::setfill(' ') << "setpoint: "; std::cout << std::left << std::setw(40) << std::setfill(' ') << controlFile; std::cout << std::left << std::setw(20) << std::setfill(' ') << id; std::cout << std::left << std::setw(6) << std::setfill(' ') << priority; std::cout << std::left << std::setw(20) << std::setfill(' ') << input; std::cout << std::left << std::setw(20) << std::setfill(' ') << output; std::cout << std::left << std::setw(8) << std::setfill(' ') << setpoint; std::cout << std::left << std::setw(12) << std::setfill(' ') << (actingDir ? "direct" : "indirect"); std::cout << std::left << std::setw(16) << std::setfill(' ') << mapper[currentState]; std::cout << std::right << std::setw(8) << std::setfill(' ') << setpoint + tolerance << " <- "; std::cout << std::left << std::setw(8) << std::setfill(' ') << inputValue.value << " -> "; std::cout << std::left << std::setw(8) << std::setfill(' ') << setpoint - tolerance; //std::cout << left << setw(10) << setfill(' ') << highFailsafe << " : " << lowFailsafe; std::cout.flush(); }