Erick / Mbed 2 deprecated ICE-F412

Dependencies:   mbed-rtos mbed

Committer:
jmarkel44
Date:
Tue Jan 24 19:05:33 2017 +0000
Revision:
0:61364762ee0e
Port from IAR to Nucleo-F412 board

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jmarkel44 0:61364762ee0e 1 /******************************************************************************
jmarkel44 0:61364762ee0e 2 *
jmarkel44 0:61364762ee0e 3 * File: FailsafeControl.cpp
jmarkel44 0:61364762ee0e 4 * Desciption: ICE Failsafe Control Class implementation
jmarkel44 0:61364762ee0e 5 *
jmarkel44 0:61364762ee0e 6 *****************************************************************************/
jmarkel44 0:61364762ee0e 7 #include "FailsafeControl.h"
jmarkel44 0:61364762ee0e 8 #include "cJSON.h"
jmarkel44 0:61364762ee0e 9 #include "ICELog.h"
jmarkel44 0:61364762ee0e 10 #include "global.h"
jmarkel44 0:61364762ee0e 11 #include "ModbusMasterApi.h"
jmarkel44 0:61364762ee0e 12 #include "utilities.h"
jmarkel44 0:61364762ee0e 13 #include <string>
jmarkel44 0:61364762ee0e 14 #include <iostream>
jmarkel44 0:61364762ee0e 15 #include <iomanip>
jmarkel44 0:61364762ee0e 16 #include <stdarg.h>
jmarkel44 0:61364762ee0e 17 #include <stdlib.h>
jmarkel44 0:61364762ee0e 18 #include <time.h>
jmarkel44 0:61364762ee0e 19
jmarkel44 0:61364762ee0e 20 using namespace std;
jmarkel44 0:61364762ee0e 21
jmarkel44 0:61364762ee0e 22 #ifdef MDOT_ICE
jmarkel44 0:61364762ee0e 23 extern mDot *GLOBAL_mdot;
jmarkel44 0:61364762ee0e 24 #endif
jmarkel44 0:61364762ee0e 25
jmarkel44 0:61364762ee0e 26 // for debugging - this can be set via the console command:
jmarkel44 0:61364762ee0e 27 // "debug-fs 1 or debug-fs 0
jmarkel44 0:61364762ee0e 28 bool debugFailsafeControl = false;
jmarkel44 0:61364762ee0e 29
jmarkel44 0:61364762ee0e 30 static void debug(const char *fmt, ...)
jmarkel44 0:61364762ee0e 31 {
jmarkel44 0:61364762ee0e 32 if ( debugFailsafeControl ) {
jmarkel44 0:61364762ee0e 33 va_list vargs;
jmarkel44 0:61364762ee0e 34 va_start(vargs, fmt);
jmarkel44 0:61364762ee0e 35 vfprintf(stdout, fmt, vargs);
jmarkel44 0:61364762ee0e 36 va_end(vargs);
jmarkel44 0:61364762ee0e 37 }
jmarkel44 0:61364762ee0e 38 }
jmarkel44 0:61364762ee0e 39
jmarkel44 0:61364762ee0e 40 //
jmarkel44 0:61364762ee0e 41 // method: load
jmarkel44 0:61364762ee0e 42 // description: load a composite control
jmarkel44 0:61364762ee0e 43 //
jmarkel44 0:61364762ee0e 44 // @param none
jmarkel44 0:61364762ee0e 45 // @return none
jmarkel44 0:61364762ee0e 46 //
jmarkel44 0:61364762ee0e 47 bool FailsafeControl::load(std::string _controlFile)
jmarkel44 0:61364762ee0e 48 {
jmarkel44 0:61364762ee0e 49 controlFile = _controlFile;
jmarkel44 0:61364762ee0e 50
jmarkel44 0:61364762ee0e 51
jmarkel44 0:61364762ee0e 52 // read the data into a buffer
jmarkel44 0:61364762ee0e 53 char dataBuf[MAX_FILE_SIZE];
jmarkel44 0:61364762ee0e 54
jmarkel44 0:61364762ee0e 55 bool rc = GLOBAL_mdot->readUserFile(controlFile.c_str(), (void *)dataBuf, sizeof(dataBuf));
jmarkel44 0:61364762ee0e 56 if ( rc != true ) {
jmarkel44 0:61364762ee0e 57 logError("%s: failed to read %s", __func__, controlFile.c_str());
jmarkel44 0:61364762ee0e 58 // caller should destroy the object
jmarkel44 0:61364762ee0e 59 return false;
jmarkel44 0:61364762ee0e 60 }
jmarkel44 0:61364762ee0e 61
jmarkel44 0:61364762ee0e 62
jmarkel44 0:61364762ee0e 63 if ( !validateControlData(dataBuf) ) {
jmarkel44 0:61364762ee0e 64 logError("%s: failed to validate control data", __func__);
jmarkel44 0:61364762ee0e 65 return false;
jmarkel44 0:61364762ee0e 66 }
jmarkel44 0:61364762ee0e 67
jmarkel44 0:61364762ee0e 68 copyControlData(dataBuf);
jmarkel44 0:61364762ee0e 69
jmarkel44 0:61364762ee0e 70 ModbusValue val;
jmarkel44 0:61364762ee0e 71 // validate the input & output
jmarkel44 0:61364762ee0e 72 if ( ModbusMasterReadRegister(input, &val) == false ) {
jmarkel44 0:61364762ee0e 73 logError("%s failed to find input %s", id.c_str(), input.c_str());
jmarkel44 0:61364762ee0e 74 return false;
jmarkel44 0:61364762ee0e 75 }
jmarkel44 0:61364762ee0e 76 if ( ModbusMasterReadRegister(output, &val) == false ) {
jmarkel44 0:61364762ee0e 77 logError("%s failed to find output %s", id.c_str(), output.c_str());
jmarkel44 0:61364762ee0e 78 return false;
jmarkel44 0:61364762ee0e 79 }
jmarkel44 0:61364762ee0e 80
jmarkel44 0:61364762ee0e 81 isVirtualOutput = Util_isVirtualOutput(output) ? true : false;
jmarkel44 0:61364762ee0e 82 return true;
jmarkel44 0:61364762ee0e 83 }
jmarkel44 0:61364762ee0e 84 //
jmarkel44 0:61364762ee0e 85 // method: validateControlData
jmarkel44 0:61364762ee0e 86 // description: validate the JSON formatted strings for
jmarkel44 0:61364762ee0e 87 // expected tags
jmarkel44 0:61364762ee0e 88 //
jmarkel44 0:61364762ee0e 89 // @param[in] buf -> JSON formatted string
jmarkel44 0:61364762ee0e 90 // @param[out] none
jmarkel44 0:61364762ee0e 91 // @return true if valid; false otherwise
jmarkel44 0:61364762ee0e 92 //
jmarkel44 0:61364762ee0e 93 bool FailsafeControl::validateControlData(const char *buf)
jmarkel44 0:61364762ee0e 94 {
jmarkel44 0:61364762ee0e 95 bool rc = true;
jmarkel44 0:61364762ee0e 96 // parse the data
jmarkel44 0:61364762ee0e 97 cJSON * root = cJSON_Parse(buf);
jmarkel44 0:61364762ee0e 98
jmarkel44 0:61364762ee0e 99 if ( !cJSON_HasObjectItem(root, "id") ||
jmarkel44 0:61364762ee0e 100 !cJSON_HasObjectItem(root, "priority") ||
jmarkel44 0:61364762ee0e 101 !cJSON_HasObjectItem(root, "input") ||
jmarkel44 0:61364762ee0e 102 !cJSON_HasObjectItem(root, "output") ||
jmarkel44 0:61364762ee0e 103 !cJSON_HasObjectItem(root, "hfsValue") ||
jmarkel44 0:61364762ee0e 104 !cJSON_HasObjectItem(root, "hfsDutyCycle") ||
jmarkel44 0:61364762ee0e 105 !cJSON_HasObjectItem(root, "hfsInterval") ||
jmarkel44 0:61364762ee0e 106 !cJSON_HasObjectItem(root, "lfsValue") ||
jmarkel44 0:61364762ee0e 107 !cJSON_HasObjectItem(root, "lfsDutyCycle") ||
jmarkel44 0:61364762ee0e 108 !cJSON_HasObjectItem(root, "lfsInterval") ) {
jmarkel44 0:61364762ee0e 109 logError("%s: control file is missing expected tags", __func__);
jmarkel44 0:61364762ee0e 110 rc = false;
jmarkel44 0:61364762ee0e 111 }
jmarkel44 0:61364762ee0e 112
jmarkel44 0:61364762ee0e 113 cJSON_Delete(root);
jmarkel44 0:61364762ee0e 114 return rc;
jmarkel44 0:61364762ee0e 115 }
jmarkel44 0:61364762ee0e 116
jmarkel44 0:61364762ee0e 117 //
jmarkel44 0:61364762ee0e 118 // method: copyControlData
jmarkel44 0:61364762ee0e 119 // description: copy data from JSON buffer to object
jmarkel44 0:61364762ee0e 120 //
jmarkel44 0:61364762ee0e 121 // @param[in] buf -> JSON formattted string
jmarkel44 0:61364762ee0e 122 // @param[out] none
jmarkel44 0:61364762ee0e 123 // @return none
jmarkel44 0:61364762ee0e 124 //
jmarkel44 0:61364762ee0e 125 void FailsafeControl::copyControlData(const char *buf)
jmarkel44 0:61364762ee0e 126 {
jmarkel44 0:61364762ee0e 127 cJSON *root = cJSON_Parse(buf);
jmarkel44 0:61364762ee0e 128
jmarkel44 0:61364762ee0e 129 id = cJSON_GetObjectItem(root, "id")->valuestring;
jmarkel44 0:61364762ee0e 130 priority = atoi(cJSON_GetObjectItem(root, "priority")->valuestring);
jmarkel44 0:61364762ee0e 131 input = cJSON_GetObjectItem(root, "input")->valuestring;
jmarkel44 0:61364762ee0e 132 output = cJSON_GetObjectItem(root, "output")->valuestring;
jmarkel44 0:61364762ee0e 133
jmarkel44 0:61364762ee0e 134 // high failsafe data
jmarkel44 0:61364762ee0e 135 hfs_data.value = atof(cJSON_GetObjectItem(root, "hfsValue")->valuestring);
jmarkel44 0:61364762ee0e 136 hfs_data.dutyCycle = atoi(cJSON_GetObjectItem(root, "hfsDutyCycle")->valuestring);
jmarkel44 0:61364762ee0e 137 hfs_data.interval = atoi(cJSON_GetObjectItem(root, "hfsInterval")->valuestring);
jmarkel44 0:61364762ee0e 138
jmarkel44 0:61364762ee0e 139 // low failsafe data
jmarkel44 0:61364762ee0e 140 lfs_data.value = atof(cJSON_GetObjectItem(root, "lfsValue")->valuestring);
jmarkel44 0:61364762ee0e 141 lfs_data.dutyCycle = atoi(cJSON_GetObjectItem(root, "lfsDutyCycle")->valuestring);
jmarkel44 0:61364762ee0e 142 lfs_data.interval = atoi(cJSON_GetObjectItem(root, "lfsInterval")->valuestring);
jmarkel44 0:61364762ee0e 143
jmarkel44 0:61364762ee0e 144 cJSON_Delete(root);
jmarkel44 0:61364762ee0e 145 }
jmarkel44 0:61364762ee0e 146
jmarkel44 0:61364762ee0e 147 //
jmarkel44 0:61364762ee0e 148 // method: start
jmarkel44 0:61364762ee0e 149 // description: start the failsafe control
jmarkel44 0:61364762ee0e 150 //
jmarkel44 0:61364762ee0e 151 // @param none
jmarkel44 0:61364762ee0e 152 // @return none
jmarkel44 0:61364762ee0e 153 //
jmarkel44 0:61364762ee0e 154 void FailsafeControl::start(void)
jmarkel44 0:61364762ee0e 155 {
jmarkel44 0:61364762ee0e 156 currentState = STATE_START;
jmarkel44 0:61364762ee0e 157 }
jmarkel44 0:61364762ee0e 158
jmarkel44 0:61364762ee0e 159 //
jmarkel44 0:61364762ee0e 160 // method: update
jmarkel44 0:61364762ee0e 161 // description: update the faisafe control using the FSM
jmarkel44 0:61364762ee0e 162 //
jmarkel44 0:61364762ee0e 163 // @param none
jmarkel44 0:61364762ee0e 164 // @return none
jmarkel44 0:61364762ee0e 165 //
jmarkel44 0:61364762ee0e 166 FailsafeControlError_t FailsafeControl::update(void)
jmarkel44 0:61364762ee0e 167 {
jmarkel44 0:61364762ee0e 168 FailsafeControlError_t rc = FAILSAFE_CONTROL_OK;
jmarkel44 0:61364762ee0e 169
jmarkel44 0:61364762ee0e 170 switch (this->currentState) {
jmarkel44 0:61364762ee0e 171 case STATE_INIT:
jmarkel44 0:61364762ee0e 172 // do nothing - control must be programatically started
jmarkel44 0:61364762ee0e 173 break;
jmarkel44 0:61364762ee0e 174 case STATE_START:
jmarkel44 0:61364762ee0e 175 // control has programmatically started, do some checking
jmarkel44 0:61364762ee0e 176 if ( this->aboveHighFailsafe() ) {
jmarkel44 0:61364762ee0e 177 if ( hfs_data.dutyCycle) {
jmarkel44 0:61364762ee0e 178 debug("\r%s: [START]->above hfs->[ON_HFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 179 // start high failsafe duty cycle
jmarkel44 0:61364762ee0e 180 this->currentState = STATE_CONTROL_ON_HFS;
jmarkel44 0:61364762ee0e 181 // turn the pump ON for the duty cycle, start the timer
jmarkel44 0:61364762ee0e 182 sendMailToOutput(ACTION_CONTROL_ON);
jmarkel44 0:61364762ee0e 183 this->startHfsDutyTimer();
jmarkel44 0:61364762ee0e 184 } else {
jmarkel44 0:61364762ee0e 185 // no duty cycle specified, so go into the high-faisafe
jmarkel44 0:61364762ee0e 186 // fixed-off state
jmarkel44 0:61364762ee0e 187 debug("\r%s: [START]->above hfs && !dc->[OFF_HFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 188 this->currentState = STATE_CONTROL_OFF_HFS;
jmarkel44 0:61364762ee0e 189 sendMailToOutput(ACTION_CONTROL_OFF);
jmarkel44 0:61364762ee0e 190 // no need to start the duty timer
jmarkel44 0:61364762ee0e 191 }
jmarkel44 0:61364762ee0e 192 } else if ( this->belowLowFailsafe() ) {
jmarkel44 0:61364762ee0e 193 debug("\r%s: [START]->below lfs->[ON_LFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 194 // start low failsafe duty cycle
jmarkel44 0:61364762ee0e 195 if ( lfs_data.dutyCycle ) {
jmarkel44 0:61364762ee0e 196 this->currentState = STATE_CONTROL_ON_LFS;
jmarkel44 0:61364762ee0e 197 // turn the pump ON for the duty cycle, start the timer
jmarkel44 0:61364762ee0e 198 sendMailToOutput(ACTION_CONTROL_ON);
jmarkel44 0:61364762ee0e 199 this->startLfsDutyTimer();
jmarkel44 0:61364762ee0e 200 } else {
jmarkel44 0:61364762ee0e 201 // no duty cycle specified, so go into the low-failsafe
jmarkel44 0:61364762ee0e 202 // fixed off-state
jmarkel44 0:61364762ee0e 203 this->currentState = STATE_CONTROL_OFF_LFS;
jmarkel44 0:61364762ee0e 204 sendMailToOutput(ACTION_CONTROL_OFF);
jmarkel44 0:61364762ee0e 205 // no need to start the timer
jmarkel44 0:61364762ee0e 206 }
jmarkel44 0:61364762ee0e 207 } else {
jmarkel44 0:61364762ee0e 208 debug("\r%s: [START]->no conditions->[OFF]\n", id.c_str());
jmarkel44 0:61364762ee0e 209 this->currentState = STATE_CONTROL_OFF;
jmarkel44 0:61364762ee0e 210 }
jmarkel44 0:61364762ee0e 211 break;
jmarkel44 0:61364762ee0e 212 case STATE_CONTROL_OFF:
jmarkel44 0:61364762ee0e 213 // control is acting normal, within bounds
jmarkel44 0:61364762ee0e 214 if ( this->aboveHighFailsafe() ) {
jmarkel44 0:61364762ee0e 215 if ( hfs_data.dutyCycle ) {
jmarkel44 0:61364762ee0e 216 debug("\r%s: [OFF]->above hfs->[ON HFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 217 this->currentState = STATE_CONTROL_ON_HFS;
jmarkel44 0:61364762ee0e 218 sendMailToOutput(ACTION_CONTROL_ON);
jmarkel44 0:61364762ee0e 219 this->startHfsDutyTimer();
jmarkel44 0:61364762ee0e 220 } else {
jmarkel44 0:61364762ee0e 221 debug("\r%s: [OFF]->above hfs && no dc->[OFF HFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 222 this->currentState = STATE_CONTROL_OFF_HFS;
jmarkel44 0:61364762ee0e 223 sendMailToOutput(ACTION_CONTROL_OFF);
jmarkel44 0:61364762ee0e 224 }
jmarkel44 0:61364762ee0e 225 } else if ( this->belowLowFailsafe() ) {
jmarkel44 0:61364762ee0e 226 // restart the low failsafe duty cycle
jmarkel44 0:61364762ee0e 227 debug("\r%s: [OFF]->below lfs->[ON_LFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 228 if ( lfs_data.dutyCycle ) {
jmarkel44 0:61364762ee0e 229 this->currentState = STATE_CONTROL_ON_LFS;
jmarkel44 0:61364762ee0e 230 sendMailToOutput(ACTION_CONTROL_ON);
jmarkel44 0:61364762ee0e 231 this->startLfsDutyTimer();
jmarkel44 0:61364762ee0e 232 } else {
jmarkel44 0:61364762ee0e 233 this->currentState = STATE_CONTROL_OFF_LFS;
jmarkel44 0:61364762ee0e 234 sendMailToOutput(ACTION_CONTROL_OFF);
jmarkel44 0:61364762ee0e 235 }
jmarkel44 0:61364762ee0e 236 } else {
jmarkel44 0:61364762ee0e 237 // do nothing
jmarkel44 0:61364762ee0e 238 }
jmarkel44 0:61364762ee0e 239 break;
jmarkel44 0:61364762ee0e 240 case STATE_CONTROL_ON_LFS:
jmarkel44 0:61364762ee0e 241 // control is in low-failsafe with duty cycle ON
jmarkel44 0:61364762ee0e 242 if ( !this->belowLowFailsafe() ) {
jmarkel44 0:61364762ee0e 243 // input has fallen below the failsafe, so turn off the control
jmarkel44 0:61364762ee0e 244 debug("\r%s: [ON_LFS]->above lfs->[OFF]\n", id.c_str());
jmarkel44 0:61364762ee0e 245 this->currentState = STATE_CONTROL_OFF;
jmarkel44 0:61364762ee0e 246 this->unregisterControl();
jmarkel44 0:61364762ee0e 247 } else if ( this->dutyOnExpired() ) {
jmarkel44 0:61364762ee0e 248 // duty ON has expired, so let's idle in the OFF-LFS state now
jmarkel44 0:61364762ee0e 249 debug("\r%s: [ON_LFS]->duty on expired->[OFF LFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 250 this->currentState = STATE_CONTROL_OFF_LFS;
jmarkel44 0:61364762ee0e 251 sendMailToOutput(ACTION_CONTROL_OFF);
jmarkel44 0:61364762ee0e 252 } else {
jmarkel44 0:61364762ee0e 253 // do nothing
jmarkel44 0:61364762ee0e 254 }
jmarkel44 0:61364762ee0e 255 break;
jmarkel44 0:61364762ee0e 256 case STATE_CONTROL_OFF_LFS:
jmarkel44 0:61364762ee0e 257 // control is in low-failsafe with duty cycle OFF
jmarkel44 0:61364762ee0e 258 if ( !this->belowLowFailsafe() ) {
jmarkel44 0:61364762ee0e 259 // no longer in dangerous waters, so transition to OFF
jmarkel44 0:61364762ee0e 260 debug("\r%s: [OFF_LFS]->above lfs->[OFF]\n", id.c_str());
jmarkel44 0:61364762ee0e 261 this->currentState = STATE_CONTROL_OFF;
jmarkel44 0:61364762ee0e 262 this->unregisterControl();
jmarkel44 0:61364762ee0e 263 } else if ( this->dutyOffExpired() && lfs_data.dutyCycle ) {
jmarkel44 0:61364762ee0e 264 debug("\r%s: [OFF_LFS]->duty OFF exp->[ON_LFS]", id.c_str());
jmarkel44 0:61364762ee0e 265 // turn the PUMP back on and restart the duty timer
jmarkel44 0:61364762ee0e 266 this->currentState = STATE_CONTROL_ON_LFS;
jmarkel44 0:61364762ee0e 267 sendMailToOutput(ACTION_CONTROL_ON);
jmarkel44 0:61364762ee0e 268 this->startLfsDutyTimer();
jmarkel44 0:61364762ee0e 269
jmarkel44 0:61364762ee0e 270 } else {
jmarkel44 0:61364762ee0e 271 // do nothing
jmarkel44 0:61364762ee0e 272 }
jmarkel44 0:61364762ee0e 273 break;
jmarkel44 0:61364762ee0e 274 case STATE_CONTROL_ON_HFS:
jmarkel44 0:61364762ee0e 275 // control is in high-failsafe with duty cycle ON
jmarkel44 0:61364762ee0e 276 if ( !this->aboveHighFailsafe() ) {
jmarkel44 0:61364762ee0e 277 debug("\r%s: [ON_HFS]->below hfs->[OFF]\n", id.c_str());
jmarkel44 0:61364762ee0e 278 this->currentState = STATE_CONTROL_OFF;
jmarkel44 0:61364762ee0e 279 this->unregisterControl();
jmarkel44 0:61364762ee0e 280 } else if ( this->dutyOnExpired() ) {
jmarkel44 0:61364762ee0e 281 debug("\r%s: [ON_HFS]->duty ON expired->[OFF_HFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 282 this->currentState = STATE_CONTROL_OFF_HFS;
jmarkel44 0:61364762ee0e 283 sendMailToOutput(ACTION_CONTROL_OFF);
jmarkel44 0:61364762ee0e 284 } else {
jmarkel44 0:61364762ee0e 285 // do nothing
jmarkel44 0:61364762ee0e 286 }
jmarkel44 0:61364762ee0e 287 break;
jmarkel44 0:61364762ee0e 288 case STATE_CONTROL_OFF_HFS:
jmarkel44 0:61364762ee0e 289 // control is in high-failsafe with cuty cycle OFF
jmarkel44 0:61364762ee0e 290 if ( !this->aboveHighFailsafe() ) {
jmarkel44 0:61364762ee0e 291 debug("\r%s: [OFF_HFS]->below hfs->[OFF]\n", id.c_str());
jmarkel44 0:61364762ee0e 292 this->currentState = STATE_CONTROL_OFF;
jmarkel44 0:61364762ee0e 293 this->unregisterControl();
jmarkel44 0:61364762ee0e 294 } else if ( this->dutyOffExpired() && hfs_data.dutyCycle ) {
jmarkel44 0:61364762ee0e 295 debug("\r%s: [OFF_HFS]->duty OFF expired->[ON_HFS]\n", id.c_str());
jmarkel44 0:61364762ee0e 296 this->currentState = STATE_CONTROL_ON_HFS;
jmarkel44 0:61364762ee0e 297 sendMailToOutput(ACTION_CONTROL_ON);
jmarkel44 0:61364762ee0e 298 this->startHfsDutyTimer();
jmarkel44 0:61364762ee0e 299 } else {
jmarkel44 0:61364762ee0e 300 // do nothing
jmarkel44 0:61364762ee0e 301 }
jmarkel44 0:61364762ee0e 302 break;
jmarkel44 0:61364762ee0e 303 default:
jmarkel44 0:61364762ee0e 304 logError("%s: unknown state %d", __func__, this->currentState);
jmarkel44 0:61364762ee0e 305 rc = FAILSAFE_CONTROL_UNK_STATE;
jmarkel44 0:61364762ee0e 306 break;
jmarkel44 0:61364762ee0e 307 }
jmarkel44 0:61364762ee0e 308 return rc;
jmarkel44 0:61364762ee0e 309 }
jmarkel44 0:61364762ee0e 310
jmarkel44 0:61364762ee0e 311 //
jmarkel44 0:61364762ee0e 312 // method: belowFailsafe
jmarkel44 0:61364762ee0e 313 // description: returns true if the input signal is below the
jmarkel44 0:61364762ee0e 314 // failsafe mark
jmarkel44 0:61364762ee0e 315 //
jmarkel44 0:61364762ee0e 316 // @param[in] none
jmarkel44 0:61364762ee0e 317 // @param[out] none
jmarkel44 0:61364762ee0e 318 // @return true if below; false otherwise
jmarkel44 0:61364762ee0e 319 //
jmarkel44 0:61364762ee0e 320 bool FailsafeControl::belowLowFailsafe(void)
jmarkel44 0:61364762ee0e 321 {
jmarkel44 0:61364762ee0e 322 // read the modbus input
jmarkel44 0:61364762ee0e 323 ModbusValue value;
jmarkel44 0:61364762ee0e 324 ModbusMasterReadRegister(input, &value);
jmarkel44 0:61364762ee0e 325 return ( value.value <= lfs_data.value );
jmarkel44 0:61364762ee0e 326 }
jmarkel44 0:61364762ee0e 327
jmarkel44 0:61364762ee0e 328 //
jmarkel44 0:61364762ee0e 329 // method: aboveHighFailsafe
jmarkel44 0:61364762ee0e 330 // description: returns true if the input signal is above the
jmarkel44 0:61364762ee0e 331 // failsafe mark
jmarkel44 0:61364762ee0e 332 //
jmarkel44 0:61364762ee0e 333 // @param[in] none
jmarkel44 0:61364762ee0e 334 // @param[out] none
jmarkel44 0:61364762ee0e 335 // @return true if above; false otherwise
jmarkel44 0:61364762ee0e 336 //
jmarkel44 0:61364762ee0e 337 bool FailsafeControl::aboveHighFailsafe(void)
jmarkel44 0:61364762ee0e 338 {
jmarkel44 0:61364762ee0e 339 // read the modbus input
jmarkel44 0:61364762ee0e 340 ModbusValue value;
jmarkel44 0:61364762ee0e 341 ModbusMasterReadRegister(input, &value);
jmarkel44 0:61364762ee0e 342 return ( value.value >= hfs_data.value );
jmarkel44 0:61364762ee0e 343 }
jmarkel44 0:61364762ee0e 344
jmarkel44 0:61364762ee0e 345 //
jmarkel44 0:61364762ee0e 346 // method: startHfsDutyTimer
jmarkel44 0:61364762ee0e 347 // description: start the high failsafe duty timer
jmarkel44 0:61364762ee0e 348 //
jmarkel44 0:61364762ee0e 349 // @param none
jmarkel44 0:61364762ee0e 350 // @return none
jmarkel44 0:61364762ee0e 351 //
jmarkel44 0:61364762ee0e 352 void FailsafeControl::startHfsDutyTimer(void)
jmarkel44 0:61364762ee0e 353 {
jmarkel44 0:61364762ee0e 354 unsigned long currentTime = time(NULL);
jmarkel44 0:61364762ee0e 355 unsigned long period = hfs_data.interval * 60;
jmarkel44 0:61364762ee0e 356
jmarkel44 0:61364762ee0e 357 duty_timer.offTime = currentTime + ((double)period * ((double)hfs_data.dutyCycle/100.0));
jmarkel44 0:61364762ee0e 358 duty_timer.expirationTime = currentTime + period;
jmarkel44 0:61364762ee0e 359
jmarkel44 0:61364762ee0e 360 debug("\r%s:%s-> currentTime = %lu\n", __func__, id.c_str(), currentTime);
jmarkel44 0:61364762ee0e 361 debug("\r%s:%s-> off Time = %lu\n", __func__, id.c_str(), duty_timer.offTime);
jmarkel44 0:61364762ee0e 362 debug("\r%s:%s-> expiration = %lu\n", __func__, id.c_str(),duty_timer.expirationTime);
jmarkel44 0:61364762ee0e 363 }
jmarkel44 0:61364762ee0e 364
jmarkel44 0:61364762ee0e 365 //
jmarkel44 0:61364762ee0e 366 // method: stopHfsDutyTimer
jmarkel44 0:61364762ee0e 367 // description: stop the high failsafe duty timer
jmarkel44 0:61364762ee0e 368 //
jmarkel44 0:61364762ee0e 369 // @param [in] none
jmarkel44 0:61364762ee0e 370 // @param[out] none
jmarkel44 0:61364762ee0e 371 // @return none
jmarkel44 0:61364762ee0e 372 //
jmarkel44 0:61364762ee0e 373 void FailsafeControl::stopHfsDutyTimer(void)
jmarkel44 0:61364762ee0e 374 {
jmarkel44 0:61364762ee0e 375 debug("\r%sL%s-> invoked\n", __func__, id.c_str());
jmarkel44 0:61364762ee0e 376 memset(&duty_timer, 0, sizeof(duty_timer));
jmarkel44 0:61364762ee0e 377 }
jmarkel44 0:61364762ee0e 378
jmarkel44 0:61364762ee0e 379 //
jmarkel44 0:61364762ee0e 380 // method: startLfsDutyTimer
jmarkel44 0:61364762ee0e 381 // descrption: start the low failsafe duty-timer
jmarkel44 0:61364762ee0e 382 //
jmarkel44 0:61364762ee0e 383 // @param[in] none
jmarkel44 0:61364762ee0e 384 // @param[out] none
jmarkel44 0:61364762ee0e 385 // @return none
jmarkel44 0:61364762ee0e 386 //
jmarkel44 0:61364762ee0e 387 void FailsafeControl::startLfsDutyTimer(void)
jmarkel44 0:61364762ee0e 388 {
jmarkel44 0:61364762ee0e 389 unsigned long currentTime = time(NULL);
jmarkel44 0:61364762ee0e 390 unsigned long period = lfs_data.interval * 60;
jmarkel44 0:61364762ee0e 391
jmarkel44 0:61364762ee0e 392 duty_timer.offTime = currentTime + ((double)period * ((double)lfs_data.dutyCycle/100.0));
jmarkel44 0:61364762ee0e 393 duty_timer.expirationTime = currentTime + period;
jmarkel44 0:61364762ee0e 394
jmarkel44 0:61364762ee0e 395 debug("\r%s:%s-> next off time = %lu\n", __func__, id.c_str(), duty_timer.offTime);
jmarkel44 0:61364762ee0e 396 debug("\r%s:%s->expiration time = %lu\n", __func__, id.c_str(), duty_timer.expirationTime);
jmarkel44 0:61364762ee0e 397 }
jmarkel44 0:61364762ee0e 398
jmarkel44 0:61364762ee0e 399 //
jmarkel44 0:61364762ee0e 400 // method: stopLfsDutyTimer
jmarkel44 0:61364762ee0e 401 // description: stop the low failsafe duty-timer
jmarkel44 0:61364762ee0e 402 //
jmarkel44 0:61364762ee0e 403 // @param none
jmarkel44 0:61364762ee0e 404 // @return none
jmarkel44 0:61364762ee0e 405 //
jmarkel44 0:61364762ee0e 406 void FailsafeControl::stopLfsDutyTimer(void)
jmarkel44 0:61364762ee0e 407 {
jmarkel44 0:61364762ee0e 408 debug("\r%s:5s-> invoked\n", __func__, id.c_str());
jmarkel44 0:61364762ee0e 409 memset(&duty_timer, 0, sizeof(duty_timer));
jmarkel44 0:61364762ee0e 410 }
jmarkel44 0:61364762ee0e 411
jmarkel44 0:61364762ee0e 412 //
jmarkel44 0:61364762ee0e 413 // method: dutyOnExpired
jmarkel44 0:61364762ee0e 414 // description: returns true if ON cycle has expired; false otherwise
jmarkel44 0:61364762ee0e 415 //
jmarkel44 0:61364762ee0e 416 // @param none
jmarkel44 0:61364762ee0e 417 // @return none
jmarkel44 0:61364762ee0e 418 //
jmarkel44 0:61364762ee0e 419 bool FailsafeControl::dutyOnExpired(void)
jmarkel44 0:61364762ee0e 420 {
jmarkel44 0:61364762ee0e 421 return (time(0) >= duty_timer.offTime);
jmarkel44 0:61364762ee0e 422 }
jmarkel44 0:61364762ee0e 423
jmarkel44 0:61364762ee0e 424 //
jmarkel44 0:61364762ee0e 425 // method: dutyOffExpired
jmarkel44 0:61364762ee0e 426 // description: returns true if OFF cycle has expired; false otherwise
jmarkel44 0:61364762ee0e 427 //
jmarkel44 0:61364762ee0e 428 // @param none
jmarkel44 0:61364762ee0e 429 // @return none
jmarkel44 0:61364762ee0e 430 //
jmarkel44 0:61364762ee0e 431 bool FailsafeControl::dutyOffExpired(void)
jmarkel44 0:61364762ee0e 432 {
jmarkel44 0:61364762ee0e 433 return (duty_timer.expirationTime < time(NULL));
jmarkel44 0:61364762ee0e 434 }
jmarkel44 0:61364762ee0e 435
jmarkel44 0:61364762ee0e 436 //
jmarkel44 0:61364762ee0e 437 // method: sendMailToOutput
jmarkel44 0:61364762ee0e 438 // description: send mail to the output task
jmarkel44 0:61364762ee0e 439 //
jmarkel44 0:61364762ee0e 440 // @param io_tag -> input/output tag
jmarkel44 0:61364762ee0e 441 // @param action -> ON, OFF, UNREGISTER
jmarkel44 0:61364762ee0e 442 // @return none
jmarkel44 0:61364762ee0e 443 //
jmarkel44 0:61364762ee0e 444 void FailsafeControl::sendMailToOutput(OutputAction action)
jmarkel44 0:61364762ee0e 445 {
jmarkel44 0:61364762ee0e 446 logInfo("%s: failsafe control %s attempting to send action %d\n",
jmarkel44 0:61364762ee0e 447 __func__, id.c_str(), action);
jmarkel44 0:61364762ee0e 448
jmarkel44 0:61364762ee0e 449 if ( isVirtualOutput ) {
jmarkel44 0:61364762ee0e 450 debug("%s:%s-> updating the virtual output %s\n", __func__, id.c_str(), output.c_str());
jmarkel44 0:61364762ee0e 451 ModbusMasterWriteRegister(this->output,
jmarkel44 0:61364762ee0e 452 (action == ACTION_CONTROL_ON) ? 1.0 : 0.0);
jmarkel44 0:61364762ee0e 453 } else {
jmarkel44 0:61364762ee0e 454 OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc();
jmarkel44 0:61364762ee0e 455 memset(output_mail, 0, sizeof(OutputControlMsg_t));
jmarkel44 0:61364762ee0e 456
jmarkel44 0:61364762ee0e 457 output_mail->action = action;
jmarkel44 0:61364762ee0e 458 output_mail->controlType = CONTROL_FAILSAFE;
jmarkel44 0:61364762ee0e 459 output_mail->priority = this->priority;
jmarkel44 0:61364762ee0e 460
jmarkel44 0:61364762ee0e 461 strncpy(output_mail->input_tag, this->input.c_str(), sizeof(output_mail->input_tag)-1);
jmarkel44 0:61364762ee0e 462 strncpy(output_mail->output_tag, this->output.c_str(), sizeof(output_mail->output_tag)-1);
jmarkel44 0:61364762ee0e 463 strncpy(output_mail->id, this->id.c_str(), sizeof(output_mail->id)-1);
jmarkel44 0:61364762ee0e 464
jmarkel44 0:61364762ee0e 465 OutputMasterMailBox.put(output_mail);
jmarkel44 0:61364762ee0e 466 }
jmarkel44 0:61364762ee0e 467 }
jmarkel44 0:61364762ee0e 468
jmarkel44 0:61364762ee0e 469
jmarkel44 0:61364762ee0e 470 //
jmarkel44 0:61364762ee0e 471 // method: unregisterControl
jmarkel44 0:61364762ee0e 472 // description: unregister this control with the output task
jmarkel44 0:61364762ee0e 473 //
jmarkel44 0:61364762ee0e 474 // @param none
jmarkel44 0:61364762ee0e 475 // @return none
jmarkel44 0:61364762ee0e 476 //
jmarkel44 0:61364762ee0e 477 void FailsafeControl::unregisterControl(void)
jmarkel44 0:61364762ee0e 478 {
jmarkel44 0:61364762ee0e 479 logInfo("%s: %s attempting to unregister %s\n",
jmarkel44 0:61364762ee0e 480 __func__, id.c_str(), controlFile.c_str());
jmarkel44 0:61364762ee0e 481
jmarkel44 0:61364762ee0e 482 if ( isVirtualOutput ) {
jmarkel44 0:61364762ee0e 483 debug("%s: %s attempting to unregister virtual output %s\n",
jmarkel44 0:61364762ee0e 484 __func__, id.c_str(), output.c_str());
jmarkel44 0:61364762ee0e 485 ModbusMasterWriteRegister(output, 0.0);
jmarkel44 0:61364762ee0e 486 } else {
jmarkel44 0:61364762ee0e 487 OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc();
jmarkel44 0:61364762ee0e 488 memset(output_mail, 0, sizeof(OutputControlMsg_t));
jmarkel44 0:61364762ee0e 489
jmarkel44 0:61364762ee0e 490 output_mail->action = ACTION_CONTROL_UNREGISTER;
jmarkel44 0:61364762ee0e 491 output_mail->controlType = CONTROL_FAILSAFE;
jmarkel44 0:61364762ee0e 492 output_mail->priority = this->priority;
jmarkel44 0:61364762ee0e 493 strncpy(output_mail->output_tag, this->output.c_str(), sizeof(output_mail->output_tag)-1);
jmarkel44 0:61364762ee0e 494 strncpy(output_mail->id, this->id.c_str(), sizeof(output_mail->id)-1);
jmarkel44 0:61364762ee0e 495
jmarkel44 0:61364762ee0e 496 OutputMasterMailBox.put(output_mail);
jmarkel44 0:61364762ee0e 497 }
jmarkel44 0:61364762ee0e 498 }
jmarkel44 0:61364762ee0e 499
jmarkel44 0:61364762ee0e 500 //
jmarkel44 0:61364762ee0e 501 // method: display
jmarkel44 0:61364762ee0e 502 // description: display the pertinents
jmarkel44 0:61364762ee0e 503 //
jmarkel44 0:61364762ee0e 504 // @param none
jmarkel44 0:61364762ee0e 505 // @return none
jmarkel44 0:61364762ee0e 506 //
jmarkel44 0:61364762ee0e 507 void FailsafeControl::display(void)
jmarkel44 0:61364762ee0e 508 {
jmarkel44 0:61364762ee0e 509 const char *mapper[] = { "INIT",
jmarkel44 0:61364762ee0e 510 "START",
jmarkel44 0:61364762ee0e 511 "OFF",
jmarkel44 0:61364762ee0e 512 "ON_LFS",
jmarkel44 0:61364762ee0e 513 "OFF_LFS",
jmarkel44 0:61364762ee0e 514 "ON_HFS",
jmarkel44 0:61364762ee0e 515 "OFF_HFS",
jmarkel44 0:61364762ee0e 516 "SENSOR_ERR",
jmarkel44 0:61364762ee0e 517 "invalid"
jmarkel44 0:61364762ee0e 518 };
jmarkel44 0:61364762ee0e 519
jmarkel44 0:61364762ee0e 520 printf("\r\n");
jmarkel44 0:61364762ee0e 521 std::cout << left << setw(10) << setfill(' ') << "failsafe: ";
jmarkel44 0:61364762ee0e 522 std::cout << left << setw(40) << setfill(' ') << controlFile;
jmarkel44 0:61364762ee0e 523 std::cout << left << setw(20) << setfill(' ') << id;
jmarkel44 0:61364762ee0e 524 std::cout << left << setw(6) << setfill(' ') << priority;
jmarkel44 0:61364762ee0e 525 std::cout << left << setw(20) << setfill(' ') << input;
jmarkel44 0:61364762ee0e 526 std::cout << left << setw(20) << setfill(' ') << output;
jmarkel44 0:61364762ee0e 527 std::cout << left << setw(16) << setfill(' ') << mapper[currentState];
jmarkel44 0:61364762ee0e 528 std::cout << left << setw(12) << setfill(' ') << "lfs-> "
jmarkel44 0:61364762ee0e 529 << lfs_data.value << ":" << lfs_data.dutyCycle << ":" << lfs_data.interval;
jmarkel44 0:61364762ee0e 530 std::cout << right << setw(12) << setfill(' ') << "hfs-> "
jmarkel44 0:61364762ee0e 531 << hfs_data.value << ":" << hfs_data.dutyCycle << ":" << hfs_data.interval;
jmarkel44 0:61364762ee0e 532
jmarkel44 0:61364762ee0e 533 std::cout.flush();
jmarkel44 0:61364762ee0e 534 }