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/ManualControl.cpp
- Committer:
- jmarkel44
- Date:
- 2017-01-24
- Revision:
- 0:61364762ee0e
File content as of revision 0:61364762ee0e:
/******************************************************************************
*
* File: ManualControl.cpp
* Desciption: ICE Manual Control Class implementation
*
*****************************************************************************/
#include "ManualControl.h"
#include "ICELog.h"
#include "cJSON.h"
#include "ModbusMasterApi.h"
#include "global.h"
#include <string>
#include <iostream>
#include <iomanip>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
// for debugging - this can be set via the console command:
// "debug-man 1 or debug-man 0
bool debugManualControl = false;
static void debug(const char *fmt, ...)
{
if ( debugManualControl ) {
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 ManualControl::load(std::string _controlFile)
{
controlFile = _controlFile;
endTime = 0;
char dataBuf[MAX_FILE_SIZE];
// read the data into the buffer
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 tags in the control file
if ( validateControlData(dataBuf) != true ) {
logError("%s: invalid control data.", __func__);
return false;
}
// assign object data from control file
copyControlData(dataBuf);
ModbusValue val;
// validate the output
if ( ModbusMasterReadRegister(output, &val) == false ) {
logError("%s failed to find output %s", id.c_str(), output.c_str());
return false;
}
return true;
}
//
// method: validateControlData
// description: validate JSON formatted data
//
// @param[in] buf -> JSON formatted string
// @param[out] none
// @return true if valid; false otherwise
//
bool ManualControl::validateControlData(const char* buf)
{
bool rc = true;
cJSON * root = cJSON_Parse(buf);
if ( !cJSON_HasObjectItem(root, "id") ||
!cJSON_HasObjectItem(root, "output") ||
!cJSON_HasObjectItem(root, "type") ||
!cJSON_HasObjectItem(root, "priority") ||
!cJSON_HasObjectItem(root, "duration") ||
!cJSON_HasObjectItem(root, "setpoint") ||
!cJSON_HasObjectItem(root, "state") ||
!cJSON_HasObjectItem(root, "percent") ) {
logError("%s: control file is missing expected tags", __func__);
rc = false;
}
cJSON_Delete(root);
return rc;
}
//
// method: copyControlData
// description: copy JSON formatted control data to object
//
// @param[in] buf -> JSON formatted string
// @param[out] none
// @return none
//
void ManualControl::copyControlData(const char *buf)
{
cJSON * root = cJSON_Parse(buf);
id = cJSON_GetObjectItem(root,"id")->valuestring;
output = cJSON_GetObjectItem(root,"output")->valuestring;
type = atoi(cJSON_GetObjectItem(root,"type")->valuestring);
priority = atoi(cJSON_GetObjectItem(root, "priority")->valuestring);
duration = atoi(cJSON_GetObjectItem(root, "duration")->valuestring);
setpoint = atof(cJSON_GetObjectItem(root, "setpoint")->valuestring);
state = atoi(cJSON_GetObjectItem(root, "state")->valuestring);
percent = atoi(cJSON_GetObjectItem(root, "percent")->valuestring);
cJSON_Delete(root);
}
//
// method: start
// description: start the manual control
//
// @param none
// @return none
//
void ManualControl::start(void)
{
currentState = STATE_STARTUP;
if ( type == MANUAL_CONTROL_TYPE_TIMED ) {
debug("\r%s:%s-> manual control is timed\n", __func__, id.c_str());
endTime = time(NULL) + duration;
}
}
//
// method: update
// description: the manual control's state machine
//
// @param none
// @return none
//
ManualControlError_t ManualControl::update(void)
{
ManualControlError_t rc = MANUAL_CONTROL_OK;
switch ( this->currentState ) {
case STATE_INIT:
// do nothing
break;
case STATE_STARTUP:
if ( state & 0x01 ) {
this->currentState = STATE_CONTROL_ON;
debug("\r%s: [STARTUP]->manual on->[ON]\n", id.c_str());
} else {
this->currentState = STATE_CONTROL_OFF;
debug("\r%s: [STARTUP]->manual off->[OFF]\n", id.c_str());
}
//this->currentState = (state & 0x01) ? STATE_CONTROL_ON : STATE_CONTROL_OFF;
this->powerOutput();
break;
case STATE_CONTROL_ON:
if ( !(state & 0x1) ) {
this->currentState = STATE_CONTROL_OFF;
// user has changed state, so this is (or becomes) a pure
// manual control
endTime = 0;
this->powerOutput();
debug("\r%s: [ON]->manual off->[OFF]\n", id.c_str());
} else if ( endTime != 0 && time(NULL) >= endTime ) {
// timed interval has elapsed
currentState = STATE_CONTROL_FINISHED;
debug("\r%s: [ON]->timer expired->[FINISHED]\n", id.c_str());
}
break;
case STATE_CONTROL_OFF:
if ( state & 0x1 ) {
this->currentState = STATE_CONTROL_ON;
// user has changed the state, so this (or becomes) a pure
// manual control
endTime = 0;
this->powerOutput();
debug("\r%s: [OFF]->manual on->[ON]\n", id.c_str());
} else if ( endTime != 0 && time(NULL) >= endTime ) {
// timed interval has elapsed
currentState = STATE_CONTROL_FINISHED;
debug("\r%s: [OFF]->timer expired->[FINISHED]\n", id.c_str());
}
break;
case STATE_CONTROL_FINISHED:
// mark for deletion (control task will do the cleanup)
rc = MANUAL_CONTROL_DESTROY;
break;
default:
logError("%s unknown state %d\n", __func__, this->currentState);
rc = MANUAL_CONTROL_ERROR;
break;
}
return rc;
}
//
// method: unregisterControl
// description: unregister this control with the output master
//
// @param none
// @return none
//
int ManualControl::unregisterControl(void)
{
logInfo("%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->controlType = CONTROL_MANUAL;
output_mail->action = ACTION_CONTROL_UNREGISTER;
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);
return 0;
}
//
// method: powerOutput
// description: send a message to the output thread to power the relay
//
// @param none
// @return -1 on error; 0 otherwise
//
int ManualControl::powerOutput(void)
{
printf("\r%s-> id:%s attempting to manually turn %s relay %s\n",
__func__, id.c_str(), (state & 0x1) ? "ON" : "OFF", output.c_str());
OutputControlMsg_t *output_mail = OutputMasterMailBox.alloc();
memset(output_mail, 0, sizeof(OutputControlMsg_t));
output_mail->controlType = CONTROL_MANUAL;
output_mail->action = (state & 0x1) ? ACTION_CONTROL_ON : ACTION_CONTROL_OFF;
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);
return 0;
}
//
// method: display
// description: display the pertinents
//
// @param none
// @return none
//
void ManualControl::display(void)
{
string mapper[] = { "INIT",
"STARTUP",
"CONTROL_ON",
"CONTROL_OFF"
};
printf("\r\n");
std::cout << left << setw(10) << setfill(' ') << "manual: ";
std::cout << left << setw(40) << setfill(' ') << controlFile;
std::cout << left << setw(20) << setfill(' ') << id;
std::cout << left << setw(20) << setfill(' ') << output;
std::cout << left << setw(6) << setfill(' ') << type;
std::cout << left << setw(6) << setfill(' ') << priority;
std::cout << left << setw(8) << setfill(' ') << duration;
//std::cout << left << setw(8) << setfill(' ') << percent;
std::cout << left << setw(16) << setfill(' ') << mapper[currentState];
if ( type == MANUAL_CONTROL_TYPE_TIMED ) {
std::cout << left << setw(8) << setfill(' ') << "Time Remaining (secs): " << endTime - time(NULL);
}
std::cout.flush();
}