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.
Dependencies: NaturalTinyShell_ice libmDot-12Sept mbed-rtos mbed
Fork of ICE by
src/ConfigurationHandler/Controls/FailsafeControl.cpp
- Committer:
- jmarkel44
- Date:
- 2016-10-24
- Revision:
- 262:696cd48bb04a
- Parent:
- 261:4e9a588c938e
- Child:
- 269:97243a7f56ba
File content as of revision 262:696cd48bb04a:
/******************************************************************************
*
* File: CompositeControl.cpp
* Desciption: ICE Composite Control Class implementation
*
*****************************************************************************/
#include "FailsafeControl.h"
#include "cJSON.h"
#include "mDot.h"
#include "global.h"
#include "ModbusMasterApi.h"
#include <string>
#include <iostream>
#include <iomanip>
extern mDot *GLOBAL_mdot;
//
// method: load
// description: load a composite control
//
// @param none
// @return none
//
bool FailsafeControl::load(std::string _controlFile)
{
controlFile = _controlFile;
// open and read from the control file
mDot::mdot_file file = GLOBAL_mdot->openUserFile(controlFile.c_str(), mDot::FM_RDONLY);
if ( file.fd < 0 ) {
logError("%s: failed to open %s\n", __func__, controlFile.c_str());
return false;
}
// read the data into a buffer
char dataBuf[MAX_FILE_SIZE];
int bytes_read = GLOBAL_mdot->readUserFile(file, (void *)dataBuf, sizeof(dataBuf));
if ( bytes_read != sizeof(dataBuf) ) {
logError("%s: failed to read %d bytes from %s", __func__, sizeof(dataBuf), controlFile.c_str());
// caller should destroy the object
return false;
}
// close the file
GLOBAL_mdot->closeUserFile(file);
// parse the data
cJSON * root = cJSON_Parse(dataBuf);
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;
hfs_data.value = atof(cJSON_GetObjectItem(root, "hfsValue")->valuestring);
hfs_data.dutyCycle = atoi(cJSON_GetObjectItem(root, "hfsDutyCycle")->valuestring);
hfs_data.interval = atoi(cJSON_GetObjectItem(root, "hfsInterval")->valuestring);
lfs_data.value = atof(cJSON_GetObjectItem(root, "lfsValue")->valuestring);
lfs_data.dutyCycle = atoi(cJSON_GetObjectItem(root, "lfsDutyCycle")->valuestring);
lfs_data.interval = atoi(cJSON_GetObjectItem(root, "lfsInterval")->valuestring);
return true;
}
//
// method: start
// description: start the failsafe control
//
// @param none
// @return none
//
void FailsafeControl::start(void)
{
currentState = STATE_START;
}
//
// method: update
// description: update the faisafe control using the FSM
//
// @param none
// @return none
//
void FailsafeControl::update(void)
{
switch (this->currentState) {
case STATE_INIT:
// do nothing - control must be started
break;
case STATE_START:
// control has been started, do some checking
if ( this->aboveHighFailsafe() ) {
// start high failsafe duty cycle
this->currentState = STATE_CONTROL_HFS_ON;
sendMailToOutput(ACTION_CONTROL_ON);
this->startHfsDutyTimer();
} else if ( this->belowLowFailsafe() ) {
// start low failsafe duty cycle
this->currentState = STATE_CONTROL_LFS_ON;
sendMailToOutput(ACTION_CONTROL_ON);
this->startLfsDutyTimer();
} else {
this->currentState = STATE_CONTROL_OFF;
}
break;
case STATE_CONTROL_OFF:
// control is acting normal, within bounds
if ( this->aboveHighFailsafe() ) {
// restart the high failsafe duty cycle
this->currentState = STATE_CONTROL_HFS_ON;
sendMailToOutput(ACTION_CONTROL_ON);
this->startHfsDutyTimer();
} else if ( this->belowLowFailsafe() ) {
// restart the low failsafe duty cycle
this->currentState = STATE_CONTROL_LFS_ON;
sendMailToOutput(ACTION_CONTROL_ON);
this->startLfsDutyTimer();
} else {
// do nothing
}
break;
case STATE_CONTROL_LFS_ON:
// control is in low-failsafe with duty cycle ON
if ( !this->belowLowFailsafe() ) {
this->currentState = STATE_CONTROL_OFF;
this->unregisterControl();
} else if ( this->dutyOnExpired() ) {
this->currentState = STATE_CONTROL_LFS_OFF;
sendMailToOutput(ACTION_CONTROL_OFF);
} else {
// do nothing
}
break;
case STATE_CONTROL_LFS_OFF:
// control is in low-failsafe with duty cycle OFF
if ( !this->belowLowFailsafe() ) {
this->currentState = STATE_CONTROL_OFF;
this->unregisterControl();
} else if ( this->dutyOffExpired() ) {
this->currentState = STATE_CONTROL_LFS_ON;
this->startLfsDutyTimer();
} else {
// do nothing
}
break;
case STATE_CONTROL_HFS_ON:
// control is in high-failsafe with duty cycle ON
if ( !this->aboveHighFailsafe() ) {
this->currentState = STATE_CONTROL_OFF;
this->unregisterControl();
} else if ( this->dutyOnExpired() ) {
this->currentState = STATE_CONTROL_HFS_OFF;
sendMailToOutput(ACTION_CONTROL_OFF);
} else {
// do nothing
}
break;
case STATE_CONTROL_HFS_OFF:
// control is in high-failsafe with cuty cycle OFF
if ( !this->aboveHighFailsafe() ) {
this->currentState = STATE_CONTROL_OFF;
this->unregisterControl();
} else if ( this->dutyOffExpired() ) {
this->currentState = STATE_CONTROL_LFS_ON;
sendMailToOutput(ACTION_CONTROL_ON);
this->startLfsDutyTimer();
} else {
// do nothing
}
break;
default:
break;
}
}
bool FailsafeControl::belowLowFailsafe(void)
{
// read the modbus input
ModbusValue value;
ModbusMasterReadRegister(input, &value);
#if 0
if ( value.errflag ) {
logError("%s: error reading %s:", __func__, input);
return false;
}
#endif
return ( value.value <= lfs_data.value );
}
bool FailsafeControl::aboveHighFailsafe(void)
{
// read the modbus input
ModbusValue value;
ModbusMasterReadRegister(input, &value);
// TODO: check the error flag
#if 0
if ( value.errflag ) {
logError("%s: error reading %s:", __func__, input);
return false;
}
#endif
return ( value.value >= hfs_data.value );
}
//
// method: startHfsDutyTimer
// description: start the high failsafe duty timer
//
// @param none
// @return none
//
void FailsafeControl::startHfsDutyTimer(void)
{
unsigned long currentTime = time(NULL);
unsigned long period = hfs_data.interval * 60;
duty_timer.offTime = currentTime + ((double)period * ((double)hfs_data.dutyCycle/100.0));
duty_timer.expirationTime = currentTime + period;
printf("\r%s: currentTime = %lu\n", __func__, currentTime);
printf("\r%s: off Time = %lu\n", __func__, duty_timer.offTime);
printf("\r%s: expiration = %lu\n", __func__, duty_timer.expirationTime);
}
//
// method: stopHfsDutyTimer
// description: stop the high failsafe duty timer
//
// @param none
// @return none
//
void FailsafeControl::stopHfsDutyTimer(void)
{
printf("\r%s invoked\n", __func__);
memset(&duty_timer, 0, sizeof(duty_timer));
}
//
// method: startLfsDutyTimer
// descrption: start the low failsafe duty-timer
//
// @param none
// @return none
//
void FailsafeControl::startLfsDutyTimer(void)
{
unsigned long currentTime = time(NULL);
unsigned long period = lfs_data.interval * 60;
duty_timer.offTime = (double)period * ((double)lfs_data.dutyCycle/100.0);
duty_timer.expirationTime = currentTime + period;
}
//
// method: stopLfsDutyTimer
// description: stop the low failsafe duty-timer
//
// @param none
// @return none
//
void FailsafeControl::stopLfsDutyTimer(void)
{
printf("\r%s invoked\n", __func__);
memset(&duty_timer, 0, sizeof(duty_timer));
}
//
// method: dutyOnExpired
// description: returns true if ON cycle has expired; false otherwise
//
// @param none
// @return none
//
bool FailsafeControl::dutyOnExpired(void)
{
return (duty_timer.offTime < time(NULL));
}
//
// method: dutyOffExpired
// description: returns true if OFF cycle has expired; false otherwise
//
// @param none
// @return none
//
bool FailsafeControl::dutyOffExpired(void)
{
return (duty_timer.expirationTime < time(NULL));
}
//
// method: sendMailToOutput
// description: send mail to the output task
//
// @param io_tag -> input/output tag
// @param action -> ON, OFF, UNREGISTER
// @return none
//
void FailsafeControl::sendMailToOutput(OutputAction action)
{
logInfo("%s: failsafe control attempting to send action %d\n",
__func__, action);
OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc();
memset(output_mail, 0, sizeof(OutputControlMsg_t));
output_mail->action = action;
output_mail->controlType = CONTROL_FAILSAFE;
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 this control with the output task
//
// @param none
// @return none
//
void FailsafeControl::unregisterControl(void)
{
logInfo("%s: %s attempting to unregister %s\n",
__func__, controlFile.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: display the pertinents
//
// @param none
// @return none
//
void FailsafeControl::display(void)
{
const char *mapper[] = { "INIT",
"START",
"CONTROL_OFF",
"LFS_ON",
"LFS_OFF",
"HFS_ON",
"HFS_OFF",
"invalid"
};
printf("\r\n");
std::cout << left << setw(10) << setfill(' ') << "failsafe: ";
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 << left << setw(12) << setfill(' ') << "lfs-> "
<< lfs_data.value << ":" << lfs_data.dutyCycle << ":" << lfs_data.interval;
std::cout << right << setw(12) << setfill(' ') << "hfs-> "
<< hfs_data.value << ":" << hfs_data.dutyCycle << ":" << hfs_data.interval;
std::cout.flush();
}
