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:
- 1:b2e90cda7a5a
- Parent:
- 0:61364762ee0e
File content as of revision 1:b2e90cda7a5a:
/******************************************************************************
*
* 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();
}