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-21
Revision:
253:ae850c19cf81
Parent:
252:3c9863f951b7
Child:
260:fe726583ba1d

File content as of revision 253:ae850c19cf81:

/******************************************************************************
 *
 * 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
            break;
        case STATE_START:
            if ( this->aboveHighFailsafe() ) {
                currentState = STATE_CONTROL_HFS_ON;
            } else if ( this->belowLowFailsafe() ) {
                currentState = STATE_CONTROL_LFS_ON;
            } else {
                currentState = STATE_CONTROL_OFF;
            }
            break;
        case STATE_CONTROL_OFF:
            if ( this->aboveHighFailsafe() ) {
                currentState = STATE_CONTROL_HFS_ON;
                if ( hfs_data.dutyCycle ) {
                    this->startHfsTimer();
                    // send an ON request to the output thread
                    sendMail(ACTION_CONTROL_ON);
                } else {
                    // fixed off
                    sendMail(ACTION_CONTROL_OFF);
                    // fixed off
                }
            } else if ( this->belowLowFailsafe() ) {
                currentState = STATE_CONTROL_LFS_ON;
            } else {
                // do nothing
            }
            break;
        case STATE_CONTROL_LFS_ON:
            if ( !this->belowLowFailsafe() ) {
                currentState = STATE_CONTROL_OFF;
            } else {
                // check the time interval
            }
            break;
        case STATE_CONTROL_LFS_OFF:
            if ( !this->belowLowFailsafe() ) {
                currentState = STATE_CONTROL_OFF;
            } else {

            }
            break;
        case STATE_CONTROL_HFS_ON:
            // the control is in HFS with the output ON
            if ( !this->aboveHighFailsafe() ) {
                currentState = STATE_CONTROL_OFF;
                // clear the timer
                this->stopHfsTimer();
            } else if ( this->hfsTimerElapsed() ) {
                // duty cyle
                printf("\rInitial timer has expired\n");
                currentState = STATE_CONTROL_HFS_OFF;
            }
            break;
        case STATE_CONTROL_HFS_OFF:
            // the control is in HFS with the output OFF
            if ( !this->aboveHighFailsafe() ) {
                currentState = STATE_CONTROL_OFF;
            } else {

            }
            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:          startHfsTimer
// description:
void FailsafeControl::startHfsTimer(void)
{
    printf("%s invoked\n", __func__);
    unsigned long currentTime = time(NULL);
    unsigned long period = hfs_data.interval * 60;

    double totalOnTime = (double)period * ((double)hfs_data.dutyCycle/(double)100.0);
    duty_timer.offTime = (unsigned long) totalOnTime;
    duty_timer.expirationTime = currentTime + period;

    printf("\rnext off time = %lu\n", duty_timer.offTime);
    printf("\rexpiration time = %lu\n", duty_timer.expirationTime);
}

void FailsafeControl::stopHfsTimer(void)
{
    memset(&duty_timer, 0, sizeof(duty_timer));
}

bool FailsafeControl::hfsTimerElapsed(void)
{
    return ( duty_timer.offTime >= time(NULL) );
}

//
// method:      sendMail
// description: send mail to the output task
//
// @param       io_tag  -> input/output tag
// @param       action  -> ON, OFF, UNREGISTER
// @return      none
//
void FailsafeControl::sendMail(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:      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();
}