Erick / Mbed 2 deprecated ICE_BLE_TEST

Dependencies:   NaturalTinyShell_ice libmDot-12Sept mbed-rtos mbed

Fork of ICE by Erick

src/ConfigurationHandler/Controls/FailsafeControl.cpp

Committer:
jmarkel44
Date:
2016-10-24
Revision:
260:fe726583ba1d
Parent:
253:ae850c19cf81
Child:
261:4e9a588c938e

File content as of revision 260:fe726583ba1d:

/******************************************************************************
 *
 * 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 - must be invoked
            break;
        case STATE_START:
            // control has been started, do some checking
            if ( this->aboveHighFailsafe() ) {
                this->currentState = STATE_CONTROL_HFS_ON;
            } else if ( this->belowLowFailsafe() ) {
                this->currentState = STATE_CONTROL_LFS_ON;
            } else {
                this->currentState = STATE_CONTROL_OFF;
            }
            break;
        case STATE_CONTROL_OFF:
            // control is acting normal, within bounds
            if ( this->aboveHighFailsafe() ) {
                this->currentState = STATE_CONTROL_HFS_ON;
            } else if ( this->belowLowFailsafe() ) {
                this->currentState = STATE_CONTROL_LFS_ON;
            } 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;
            } else if ( this->dutyOnExpired() ) {
                this->currentState = STATE_CONTROL_LFS_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;
            } else if ( this->dutyOffExpired() ) {
                this->currentState = STATE_CONTROL_LFS_ON;
            } 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;
            } else if ( this->dutyOnExpired() ) {
                this->currentState = STATE_CONTROL_HFS_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;
            } else if ( this->dutyOffExpired() ) {
                this->currentState = STATE_CONTROL_LFS_ON;
            } 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 );
}

bool FailsafeControl::dutyOnExpired() 
{
    return false;
}

bool FailsafeControl::dutyOffExpired()
{
    return false;
}

//
// 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();
}