Erick / Mbed 2 deprecated ICE-F412

Dependencies:   mbed-rtos mbed

ICE-Application/src/ConfigurationHandler/Controls/CompositeControl.cpp

Committer:
jmarkel44
Date:
2017-01-24
Revision:
0:61364762ee0e

File content as of revision 0:61364762ee0e:

/******************************************************************************
 *
 * File:                CompositeControl.cpp
 * Desciption:          ICE Composite Control Class implementation
 *
 *****************************************************************************/
#include "CompositeControl.h"
#include "ConfigurationHandler.h"
#include "cJSON.h"
#include "ModbusMasterApi.h"
#include "global.h"
#include "ICELog.h"
#include <string>
#include <iostream>
#include <iomanip>

#ifdef MDOT_ICE
extern mDot *GLOBAL_mdot;
#endif 

using namespace std;


//
// method:          load
// description:     load a composite control
//
// @param[in]       _controlFile -> the file containing the JSON data
// @return          false if an error occurs; true otherwise
//

bool CompositeControl::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);
    
    // TODO: validate the list fo outputs
    
    return true;
}

//
// method:              validateControlData
// description:         validate JSON formatted control data
//
// @param[in]           buf -> JSON formatted string
// @param[out]          none
// @return              true if valid; false otherwise
//

bool CompositeControl::validateControlData(const char *buf)
{
    bool rc = true;
    cJSON * root    = cJSON_Parse(buf);

    if ( !cJSON_HasObjectItem(root, "id") ||
            !cJSON_HasObjectItem(root, "tag") ||
            !cJSON_HasObjectItem(root, "priority") ||
            !cJSON_HasObjectItem(root, "ca") ||
            !cJSON_HasObjectItem(root, "outputs") ) {
        logError("%s: control file missing expected tags", __func__);
        cJSON_Delete(root);
        return false;
    }

    cJSON_Delete(root);
    return rc;
}

//
// method:              copyControlData
// description:         copy the JSON formatted data
//
// @param[in]           buf -> JSON formatted string
// @param[out]          none
// @return              none
//
void CompositeControl::copyControlData(const char *buf)
{
    cJSON * root    = cJSON_Parse(buf);

    id              = cJSON_GetObjectItem(root,"id")->valuestring;
    tag             = cJSON_GetObjectItem(root, "tag")->valuestring;
    priority        = atoi(cJSON_GetObjectItem(root, "priority")->valuestring);
    ca              = cJSON_GetObjectItem(root, "ca")->valuestring;
    cJSON *array    = cJSON_GetObjectItem(root, "outputs");
    for ( int i = 0; i < cJSON_GetArraySize(array); ++i ) {
        cJSON *subitem = cJSON_GetArrayItem(array, i);
        std::string tag      = cJSON_GetObjectItem(subitem, "tag")->valuestring;
        std::string response = cJSON_GetObjectItem(subitem, "responseA")->valuestring;
        OutputElement x = { tag, response };
        outputs.push_back(x);
    }
    cJSON_Delete(root);
}

//
// method:          start
// description:     start the composite control
//
// @param           none
// @return          none
//
void CompositeControl::start(void)
{
    currentState = STATE_START;
}

//
// method:          update
// description:     updater for the composite control
//
// @param           none
// @return          none
//
CompositeControlError_t CompositeControl::update(void)
{
    CompositeControlError_t rc = COMPOSITE_CONTROL_OK;
    std::string function;

    switch ( currentState ) {
        case STATE_INIT:
            // do nothing
            break;
        case STATE_START:
            function = executeCommand();
            if ( function == "responseA" ) {
                currentState = STATE_CONTROL_ON;
                triggerOutputs(function);
            } else if ( function == "nothing" ) {
                currentState = STATE_CONTROL_OFF;
            }
            break;
        case STATE_CONTROL_ON:
            function = executeCommand();
            if ( function == "nothing" ) {
                currentState = STATE_CONTROL_OFF;
                unregisterControls();
            } else {
                // do nothing
            }
            break;
        case STATE_CONTROL_OFF:
            function = executeCommand();
            if ( function == "responseA" ) {
                currentState = STATE_CONTROL_ON;
                triggerOutputs(function);
            } else {
                // do nothing
            }
            break;
        default:
            logError("%s: unknown state %d", __func__, this->currentState);
            rc = COMPOSITE_CONTROL_UNK_STATE;
            break;
    }
    return rc;
}

//
// method:          executeCommand
// description:     execute the command specified in the control algorithm
//
// @param           none
// @return          none
//
std::string CompositeControl::executeCommand(void)
{
    // look up the algorithm
    StringAlgorithmMap::const_iterator pos;
    pos = algorithmTable.find(this->ca);
    if ( pos != algorithmTable.end() ) {
        // we found the control algorithm
        return this->executeOperation(pos->second);
    }
    return "nothing";
}

//
// method:          executeOperation
// description:     execute an operations from the control equation
//
// @param[in]       ca -> composite control algorithm
// @return          string to the result
//
std::string CompositeControl::executeOperation(const CompositeAlgorithm *ca)
{
    // (this->tag) <op> <opr> = <result>
    //
    // example:
    // this->tag = "i_flowswitch"
    // opr = "1"
    // op = "=="
    // if true return "responseA" else return "nothing"

    ModbusValue value;
    bool rc = ModbusMasterReadRegister(tag,&value);
    if ( rc != true ) {
        logError("%s cannot find tag", __func__);
        return "nothing";
    }

    // equal to operator
    if ( ca->getOp() == "==" ) {
        // perform the equality operation
        if ( value.value == atof(ca->getOpr().c_str()) ) {
            return ca->getResultTrue();
        } else {
            return ca->getResultFalse();
        }
    }
    if ( ca->getOp() == ">=" ) {
        if ( value.value >= atof(ca->getOpr().c_str()) ) {
            return ca->getResultTrue();
        } else {
            return ca->getResultFalse();
        }
    }

    if ( ca->getOp() == "&" ) {
        if ( (int)value.value & (int)atoi(ca->getOpr().c_str()) ) {
            return ca->getResultTrue();
        } else {
            return ca->getResultFalse();
        }
    }

    // addition operator
    if ( ca->getOp() == "+" ) {
        // TODO
    }
    // multiply operator
    if ( ca->getOp() == "*" ) {
        // TODO:
    }
    // subtraction operator
    if ( ca->getOp() == "-" ) {
        // TODO:
    }

    return "nothing";
}

//
// method:          triggerOutputs
// description:     trigger the output(s) to do something
//
// @param[in]       result -> the result of the operation
// @return          none
//
void CompositeControl::triggerOutputs(std::string result)
{

    // loop through the list
    StringAlgorithmMap::const_iterator pos;
    pos = algorithmTable.find(this->ca);
    if ( pos != algorithmTable.end() ) {
        std::vector<OutputElement>::const_iterator it;
        for ( it = outputs.begin(); it != outputs.end(); ++it ) {
            if ( it->response == "fixed off" ) {
                printf("\rSending an OFF control for %s\n", it->tag.c_str());
                sendMail(it->tag, ACTION_CONTROL_OFF);
            } else if ( it->response == "fixed on" ) {
                printf("\rSending an ON request for %s\n", it->tag.c_str());
                sendMail(it->tag, ACTION_CONTROL_ON);
            }
        }
    } else {
        logError("%s: failed to find the control algorithm %s\n", __func__, this->ca.c_str());
    }
}

//
// method:          sendMail
// description:     send mail to the output task
//
// @param[in]       io_tag  -> input/output tag
// @param[in]       action  -> ON, OFF, UNREGISTER
// @return          none
//
void CompositeControl::sendMail(const std::string io_tag, OutputAction action)
{
    logInfo("%s: composite 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_COMPOSITE;
    output_mail->priority       = this->priority;

    strncpy(output_mail->input_tag,  this->tag.c_str(),  sizeof(output_mail->input_tag)-1);
    strncpy(output_mail->output_tag, io_tag.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:          unregisterControls
// description:     unregister the control with the output task
//
// @param           none
// @return          none
//
void CompositeControl::unregisterControls(void)
{
    // loop through the list
    StringAlgorithmMap::const_iterator pos;
    pos = algorithmTable.find(this->ca);
    if ( pos != algorithmTable.end() ) {
        std::vector<OutputElement>::const_iterator it;
        for ( it = outputs.begin(); it != outputs.end(); ++it ) {
            sendMail(it->tag, ACTION_CONTROL_UNREGISTER);
        }
    } else {
        logError("%s: failed to find the control algorithm %s\n", __func__, this->ca.c_str());
    }
}

//
// method:          display
// description:     display the pertinents
//
// @param           none
// @return          none
//
void CompositeControl::display(void)
{
    const char *mapper[] = { "INIT",
                             "START",
                             "CONTROL_OFF",
                             "CONTROL_ON"
                           };

    printf("\r\n");
    std::cout << left << setw(10) << setfill(' ') << "composite: ";
    std::cout << left << setw(40) << setfill(' ') << controlFile;
    std::cout << left << setw(20) << setfill(' ') << id;
    std::cout << left << setw(20) << setfill(' ') << tag;
    std::cout << left << setw(6)  << setfill(' ') << priority;
    std::cout << left << setw(20) << setfill(' ') << ca;
    std::cout << left << setw(16) << setfill(' ') << mapper[currentState];

    vector<OutputElement>::const_iterator it;
    for ( it = outputs.begin(); it != outputs.end(); ++it ) {
        std::cout << left << (*it).tag << ":" << (*it).response << "  ";
    }

    std::cout.flush();

}