Erick / Mbed 2 deprecated ICE-F412

Dependencies:   mbed-rtos mbed

ICE-Application/src/ConfigurationHandler/ConfigurationHandler.cpp

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

File content as of revision 0:61364762ee0e:

/******************************************************************************
 *
 * File:                ConfigurationHandler.cpp
 * Desciption:          source for the ICE Configuration Handler
 *
 *****************************************************************************/
#include "ConfigurationHandler.h"
#include "global.h"
#include "SetpointControl.h"
#include "TimerControl.h"
#include "CompositeControl.h"
#include "CompositeAlgorithm.h"
#include "SensorErrorControl.h"
#include "cJSON.h"
#include "utilities.h"
#include "ICELog.h"
#include <algorithm>
#include <stdlib.h>
   
//
// The control maps
//StringPIDMap            PIDTable;               // PID control object table
StringSetpointMap       setpointTable;          // setpoint control object table
StringTimerMap          timerTable;             // timer control object table
StringManualMap         manualTable;            // manual control object table
StringCompositeMap      compositeTable;         // composite control object table
StringFailsafeMap       failsafeTable;          // failsafe control object table
StringAlgorithmMap      algorithmTable;         // composite control algorithms
StringSequenceMap       sequenceTable;          // sequence control object table
StringSensorErrorMap    sensorErrorTable;       // sensor error object table

Mutex                   manual_mutex;
Mutex                   setpoint_mutex;
Mutex                   timer_mutex;
Mutex                   failsafe_mutex;
Mutex                   composite_mutex;
Mutex                   sequence_mutex;
Mutex                   sensorError_mutex;

// local function prototypes
static int loadPersistentControls(void);        // load the controls on flash

// local helper functions
static int createControl(const ConfigMessage_t *msg);
static int modifyControl(const ConfigMessage_t *msg);
static int destroyControl(const ConfigMessage_t *msg);

static unsigned int getManualControlType(const char *filename);

/*****************************************************************************
 * Function:            ConfigurationHandler()
 * Description:         The ICE Configuration Handler
 *
 * @param               args (unused)
 * @return              none
 *****************************************************************************/
void ConfigurationHandler(void const *args)
{
    (void)(args);
#ifdef LOAD_PERSISTENT_CONFIGURATIONS
    loadPersistentControls();
#endif 
    osSignalSet(mainThreadId, sig_control_continue);

    printf("\rConfigurationHandler has started...\n");

    while ( true ) {
        // wait for an event
        osEvent evt = ConfigHandlerMailBox.get();
        if (evt.status == osEventMail) {
            ConfigMessage_t *msg = (ConfigMessage_t*) evt.value.p;

            logInfo("\r%s: msg->action      = %d\n", __func__, msg->action);
            logInfo("\r%s: msg->control     = %d\n", __func__, msg->control);
            logInfo("\r%s: msg->controlFile = %s\n", __func__, msg->controlFile);

            switch ( msg->action ) {
                case ACTION_CREATE: {
                    (void)createControl(msg);
                    break;
                }
                case ACTION_MODIFY: {
                    (void)modifyControl(msg);
                    break;
                }
                case ACTION_DESTROY: {
                    (void)destroyControl(msg);
                    break;
                }
                default:
                    break;
            }

            // free the message
            ConfigHandlerMailBox.free(msg);
        }
    }
}

//
// function:        ConfigurationHandler_showSetpointControls
// description:     display contents of the setpoint control table
//
void ConfigurationHandler_showSetpointControls(void)
{
    setpoint_mutex.lock();
    if ( !setpointTable.empty() ) {
        printf("\r\n");
        StringSetpointMap::const_iterator pos;
        for ( pos = setpointTable.begin(); pos != setpointTable.end(); ++pos ) {
            pos->second->display();
        }
    }
    setpoint_mutex.unlock();
}

//
// function:        ConfigurationHandler_showManualControls
// description:     display contents of the manual control table
//
void ConfigurationHandler_showManualControls(void)
{
    manual_mutex.lock();
    if ( !manualTable.empty() ) {
        printf("\r\n");
        StringManualMap::const_iterator pos;
        for ( pos = manualTable.begin(); pos != manualTable.end(); ++pos ) {
            pos->second->display();
        }
    }
    manual_mutex.unlock();
}

//
// function:        ConfigurationHandler_showTimerControls
// description:     display contents of the timer control table
//
void ConfigurationHandler_showTimerControls(void)
{
    timer_mutex.lock();
    if ( !timerTable.empty() ) {
        printf("\r\n");
        StringTimerMap::const_iterator pos;
        for ( pos = timerTable.begin(); pos != timerTable.end(); ++pos ) {
            pos->second->display();
        }
    }
    timer_mutex.unlock();
}

//
// function:        ConfigurationHandler_showCompositeControls
// description:     display contents of the composite control table
//
void ConfigurationHandler_showCompositeControls(void )
{
    composite_mutex.lock();
    if ( !compositeTable.empty() ) {
        printf("\r\n");
        StringCompositeMap::const_iterator pos;
        for ( pos = compositeTable.begin(); pos != compositeTable.end(); ++pos) {
            pos->second->display();
        }
    }
    composite_mutex.unlock();
}

//
// function:        ConfigurationHandler_showFailsafeControls
// description:     display contents of the failsafe control table
//
// @param[in]       none
// @param[out]      none
// @return          none
//
void ConfigurationHandler_showFailsafeControls(void)
{
    failsafe_mutex.lock();
    if ( !failsafeTable.empty() ) {
        printf("\r\n");
        StringFailsafeMap::const_iterator pos;
        for ( pos = failsafeTable.begin(); pos != failsafeTable.end(); ++pos ) {
            pos->second->display();
        }
    }
    failsafe_mutex.unlock();
}

//
// function:        ConfigurationHandler_showFailsafeControls
// description:     display contents of the failsafe control table
//
// @param[in]       none
// @param[out]      none
// @return          none
//
void ConfigurationHandler_showSensorErrorControls(void)
{
    sensorError_mutex.lock();
    if ( !sensorErrorTable.empty() ) {
        printf("\r\n");
        StringSensorErrorMap::const_iterator pos;
        for ( pos = sensorErrorTable.begin(); pos != sensorErrorTable.end(); ++pos ) {
            pos->second->display();
        }
    }
    sensorError_mutex.unlock();
}


//
// function:            ConfigurationHandler_showSequenceControls()
// description:         display contents of the sequence control table
//
// @param[in]           none
// @param[out]          none
// @return              none
//
void ConfigurationHandler_showSequenceControls(void)
{
    sequence_mutex.lock();
    if ( !sequenceTable.empty() ) {
        printf("\r\n");
        StringSequenceMap::const_iterator pos;
        for ( pos = sequenceTable.begin(); pos != sequenceTable.end(); ++pos ) {
            pos->second->display();
        }
    }
    sequence_mutex.unlock();
}

//
// Function:            ConfigurationHandler_showControls()
// Description:         show the controls
//
// @param[in]           none
// @return              none
//
void ConfigurationHandler_showControls(void)
{
    ConfigurationHandler_showSetpointControls();
    ConfigurationHandler_showTimerControls();
    ConfigurationHandler_showManualControls();
    ConfigurationHandler_showFailsafeControls();
    ConfigurationHandler_showCompositeControls();
    ConfigurationHandler_showSequenceControls();
    ConfigurationHandler_showSensorErrorControls();
    // TODO: PID controls
}

//
// function:        ConfigurationHandler_showAlgorithms
// description:     display the control algorithms
//
// @param           none
// @return          none
//
void ConfigurationHandler_showAlgorithms(void)
{
    StringAlgorithmMap::const_iterator pos;

    for ( pos = algorithmTable.begin(); pos != algorithmTable.end(); ++pos ) {
        pos->second->display();
    }
}

/*****************************************************************************
 * Function:            loadPersistentControls()
 * Description:         load persistent controls from flash
 *
 * @param               none
 * @return              none
 *****************************************************************************/
static int loadPersistentControls(void)
{
    static bool loaded = false;

    if ( !loaded ) {        // lazy protection

        printf("\rLoading persistent controls: \n");
        std::vector<std::string> file_list = GLOBAL_mdot->listUserFiles();

        loaded = true;

        for (std::vector<std::string>::const_iterator i = file_list.begin(); i != file_list.end(); ++i) {
            if( strncmp( i->c_str(), CONTROL_SP_STR, strlen(CONTROL_SP_STR)) == 0 ) {
                // create the setpoint control
                ConfigMessage_t msg;
                msg.control = CONTROL_SETPOINT;
                strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                int rc = createControl(&msg);
                if ( rc != 0 ) {
                    logError("%s: failed to load %s", __func__, msg.controlFile);
                } else {
                    printf("\r   setpoint control %s loaded.\n", msg.controlFile);
                }
            } else if ( strncmp( i->c_str(), CONTROL_TM_STR, strlen(CONTROL_TM_STR)) == 0  ) {
                // create the timer control
                ConfigMessage_t msg;
                msg.control = CONTROL_TIMER;
                strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                int rc = createControl(&msg);
                if ( rc != 0 ) {
                    logError("%s: failed to load %s", __func__, msg.controlFile);

                } else {
                    printf("\r   timer control %s loaded.\n", msg.controlFile);
                }
            } else if ( strncmp( i->c_str(), CONTROL_COMP_STR, strlen(CONTROL_COMP_STR)) == 0 ) {
                ConfigMessage_t msg;
                msg.control = CONTROL_COMPOSITE;
                strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                int rc = createControl(&msg);
                if ( rc != 0 ) {
                    logError("%s: failed to load %s\n", __func__, msg.controlFile);
                } else {
                    printf("\r   composite control %s loaded.\n", msg.controlFile);
                }
            } else if ( strncmp( i->c_str(), CONTROL_CA_STR, strlen(CONTROL_CA_STR)) == 0 ) {
                ConfigMessage_t msg;
                msg.control = CONTROL_ALGORITHM;
                strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                int rc = createControl(&msg);
                if ( rc != 0 ) {
                    logError("%s: failed to load %s\n", __func__, msg.controlFile);
                } else {
                    printf("\r   algorithmic control %s loaded.\n", msg.controlFile);
                }
            } else if ( strncmp( i->c_str(), CONTROL_FS_STR, strlen(CONTROL_FS_STR)) == 0 ) {
                ConfigMessage_t msg;
                msg.control = CONTROL_FAILSAFE;
                strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                int rc = createControl(&msg);
                if ( rc != 0 ) {
                    logError("%s: failed to load %s\n", __func__, msg.controlFile);
                } else {
                    printf("\r   failsafe control %s loaded.\n", msg.controlFile);
                }
            } else if ( strncmp( i->c_str(), CONTROL_PID_STR, strlen(CONTROL_PID_STR)) == 0 ) {
                // TODO:
            } else if ( strncmp( i->c_str(), CONTROL_MN_STR, strlen(CONTROL_MN_STR)) == 0 ) {
                // TODO: delete any timed manual control, not continuous...
                if  ( getManualControlType(i->c_str()) == MANUAL_CONTROL_TYPE_CONTINUOUS ) {
                    ConfigMessage_t msg;
                    msg.control = CONTROL_MANUAL;
                    strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                    int rc = createControl(&msg);
                    if ( rc != 0 ) {
                        logError("%s: failed to load %s\n", __func__, msg.controlFile);
                    } else {
                        printf("\r   manual control %s loaded\n", msg.controlFile);
                    }
                } else {
                    GLOBAL_mdot->deleteUserFile(i->c_str());
                }
            } else if ( strncmp( i->c_str(), CONTROL_SEQ_STR, strlen(CONTROL_SEQ_STR)) == 0 ) {
                ConfigMessage_t msg;
                msg.control = CONTROL_SEQUENCE;
                strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                int rc = createControl(&msg);
                if ( rc != 0 ) {
                    logError("%s: failed to load %s\n", __func__, msg.controlFile);
                } else {
                    printf("\r   sequence control %s loaded.\n", msg.controlFile);
                }
            } else if ( strncmp( i->c_str(), CONTROL_SE_STR, strlen(CONTROL_SE_STR)) == 0 ) {
                ConfigMessage_t msg;
                msg.control = CONTROL_SENSOR_ERROR;
                strncpy(msg.controlFile, i->c_str(), sizeof(msg.controlFile));
                int rc = createControl(&msg);
                if ( rc != 0 ) {
                    logError("%s: failed to load %s\n", __func__, msg.controlFile);
                } else {
                    printf("\r    sensor error control %s loaded.\n", msg.controlFile);
                }
            } else {
                logInfo("\rNot A Control File%s\r\n", i->c_str());
                // not a control file
            }
        }
    }
    return 0;
}

/*****************************************************************************
 * Function:            createControl()
 * Description:         creates a new control
 *
 * @param               none
 * @return              0 on success; -1 otherwise
 *****************************************************************************/
static int createControl(const ConfigMessage_t *msg)
{
    int status = 0;

    logInfo("\r%s invoked\n", __func__);

    switch (msg->control) {
        case CONTROL_SETPOINT: {
            SetpointControl *setpointControl = new SetpointControl;
            bool rc = setpointControl->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s\n", __func__, msg->controlFile);
                delete setpointControl;
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                status = -1;
            } else {
                setpoint_mutex.lock();
                setpointTable[msg->controlFile] = setpointControl;
                setpoint_mutex.unlock();
                setpointControl->start();
            }
            break;
        }
        case CONTROL_TIMER: {
            TimerControl *timerControl = new TimerControl;
            bool rc = timerControl->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s\n", __func__, msg->controlFile);
                delete timerControl;
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                status = -1;
            } else {
                timer_mutex.lock();
                timerTable[msg->controlFile] = timerControl;
                timer_mutex.unlock();
                timerControl->start();
            }
            break;
        }
        case CONTROL_MANUAL: {
            ManualControl *manualControl = new ManualControl;
            bool rc = manualControl->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s\n", __func__, msg->controlFile);
                delete manualControl;
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                status = -1;

            } else {
                manual_mutex.lock();
                manualTable[msg->controlFile] = manualControl;
                manual_mutex.unlock();
                manualControl-> start();
            }
            break;
        }

        case CONTROL_PID: {
            // TODO: PID
            break;
        }
        case CONTROL_COMPOSITE: {
            CompositeControl *compositeControl = new CompositeControl;
            bool rc = compositeControl->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s\n", __func__, msg->controlFile);
                delete compositeControl;
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                status = -1;
            } else {
                composite_mutex.lock();
                compositeTable[msg->controlFile] = compositeControl;
                composite_mutex.unlock();
                compositeControl->start();
            }
            break;
        }

        case CONTROL_SEQUENCE: {
            SequenceControl *sequenceControl = new SequenceControl;
            bool rc = sequenceControl->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s", __func__, msg->controlFile);
                delete sequenceControl;
                //GLOBAL_mdot->deleteUserFile(msg->controlFile);
                status = -1;
            } else {
                sequence_mutex.lock();
                sequenceTable[msg->controlFile] = sequenceControl;
                sequence_mutex.unlock();
                sequenceControl->start();
            }
            break;
        }
        case CONTROL_FAILSAFE: {
            FailsafeControl *failsafeControl = new FailsafeControl;
            bool rc = failsafeControl->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s\n", __func__, msg->controlFile);
                delete failsafeControl;
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                status = -1;
            } else {
                failsafe_mutex.lock();
                failsafeTable[msg->controlFile] = failsafeControl;
                failsafe_mutex.unlock();
                failsafeControl->start();
            }
            break;
        }
        case CONTROL_SENSOR_ERROR: {
            SensorErrorControl *sensorErrorControl = new SensorErrorControl;
            bool rc = sensorErrorControl->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s\n", __func__, msg->controlFile);
                delete sensorErrorControl;
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                status = -1;
            } else {
                sensorError_mutex.lock();
                sensorErrorTable[msg->controlFile] = sensorErrorControl;
                sensorError_mutex.unlock();
                sensorErrorControl->start();
            }
            break;
        }
        case CONTROL_ALGORITHM: {
            CompositeAlgorithm *compositeAlgorithm = new CompositeAlgorithm;
            bool rc = compositeAlgorithm->load(msg->controlFile);
            if ( rc != true ) {
                logError("%s: failed to load %s\n", __func__, msg->controlFile);
                status = -1;
            } else {
                // add this algorithm to the table
                algorithmTable[compositeAlgorithm->getId()] = compositeAlgorithm;
            }
            break;
        }
        default:
            logInfo("\r%s: control type %d not implemented yet...\n",
                    __func__, msg->control);
            break;
    }
    return status;
}

/*****************************************************************************
 * Function:            modifyControl()
 * Description:         modifies a control
 *
 * @param               msg
 * @return              none
 *****************************************************************************/
static int modifyControl(const ConfigMessage_t *msg)
{
    logInfo("\r%s invoked\n", __func__);

    switch (msg->control) {
        case CONTROL_SETPOINT: {
            // find the control in the table
            StringSetpointMap::const_iterator pos;
            setpoint_mutex.lock();
            pos = setpointTable.find(msg->controlFile);
            if ( pos != setpointTable.end() ) {
                bool rc = pos->second->load(msg->controlFile);
                if ( rc != true ) {
                    logError("\rFailed to reload the setpoint control %s\n", msg->controlFile);
                } else {
                    logInfo("\rReloaded the setpoint control %s\n", msg->controlFile);
                }
            }
            setpoint_mutex.unlock();
            break;
        }
        case CONTROL_MANUAL: {
            // find the manual control in the table
            StringManualMap::const_iterator pos;
            manual_mutex.lock();
            pos = manualTable.find(msg->controlFile);
            if ( pos != manualTable.end() ) {
                bool rc = pos->second->load(msg->controlFile);
                if ( rc != true ) {
                    logError("\rFailed to reload the manual control %s\n", msg->controlFile);
                } else {
                    logInfo("\rReloaded the manual control %s\n", msg->controlFile);
                }
            }
            manual_mutex.unlock();
            break;
        }
        default:
            logError("%s: unknown control %d\n", __func__, msg->control);
            break;
    }

    return 0;
}

/*****************************************************************************
 * Function:            destroyControl()
 * Description:         destroys a controls
 *
 * @param               msg
 * @return              none
 *****************************************************************************/
static int destroyControl(const ConfigMessage_t *msg)
{
    logInfo("\r%s invoked\n", __func__);

    switch ( msg->control ) {
        case CONTROL_SETPOINT: {
            StringSetpointMap::iterator pos;
            setpoint_mutex.lock();
            pos = setpointTable.find(msg->controlFile);
            if ( pos != setpointTable.end() ) {
                if ( !Util_isSequenceSubControl(msg->controlFile) ) {
                    GLOBAL_mdot->deleteUserFile(msg->controlFile);
                }
                logInfo("%s: deleted %s", __func__, msg->controlFile);
                pos->second->unregisterControl();
                delete (pos->second);
                setpointTable.erase(pos);
            } else {
                logError("%s: unable to find %s\n", __func__, msg->controlFile);
            }
            setpoint_mutex.unlock();
            break;
        }
        case CONTROL_TIMER: {
            StringTimerMap::iterator pos;
            timer_mutex.lock();
            pos = timerTable.find(msg->controlFile);
            if ( pos != timerTable.end() ) {
                if ( !Util_isSequenceSubControl(msg->controlFile) ) {
                    GLOBAL_mdot->deleteUserFile(msg->controlFile);
                }
                logInfo("%s: deleted %s", __func__, msg->controlFile);
                pos->second->unregisterControl();
                delete (pos->second);
                timerTable.erase(pos);
            } else {
                logError("%s: unable to find %s\n", __func__, msg->controlFile);
            }
            timer_mutex.unlock();
            break;
        }
        case CONTROL_MANUAL: {
            StringManualMap::iterator pos;
            manual_mutex.lock();
            pos = manualTable.find(msg->controlFile);
            if ( pos != manualTable.end() ) {
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                logInfo("%s: deleted %s", __func__, msg->controlFile);
                // unregister with the output thread
                pos->second->unregisterControl();
                delete (pos->second);
                manualTable.erase(pos);
            } else {
                logError("%s: unable to find %s", __func__, msg->controlFile);
            }
            manual_mutex.unlock();
            break;
        }
        case CONTROL_COMPOSITE: {
            StringCompositeMap::iterator pos;
            composite_mutex.lock();
            pos = compositeTable.find(msg->controlFile);
            if ( pos != compositeTable.end() ) {
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                logInfo("%s: deleted %s", __func__, msg->controlFile);
                pos->second->unregisterControls();
                delete (pos->second);
                compositeTable.erase(pos);
            } else {
                logError("%s: unable to find %s", __func__, msg->controlFile);
            }
            composite_mutex.unlock();
            break;
        }
        case CONTROL_SEQUENCE: {
            StringSequenceMap::iterator pos;
            sequence_mutex.lock();
            pos = sequenceTable.find(msg->controlFile);
            if ( pos != sequenceTable.end() ) {
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                logInfo("%s: delete %s", __func__, msg->controlFile);
                // TODO:
                // pos->second->unregisterControls();
                delete (pos->second);
                sequenceTable.erase(pos);
            } else {
                logError("%s: unable to find %s", __func__, msg->controlFile);
            }
            sequence_mutex.unlock();
            break;
        }
        case CONTROL_SENSOR_ERROR: {
            StringSensorErrorMap::iterator pos;
            sensorError_mutex.lock();
            pos = sensorErrorTable.find(msg->controlFile);
            if ( pos != sensorErrorTable.end() ) {
                GLOBAL_mdot->deleteUserFile(msg->controlFile);
                logInfo("%s: deleted %s", __func__, msg->controlFile);
                pos->second->unregisterControl();
                delete (pos->second);
                sensorErrorTable.erase(pos);
            } else {
                logError("%s: unable to find %s", __func__, msg->controlFile);
            }
            sensorError_mutex.unlock();
            break;
        }
        case CONTROL_PID: {
            // TODO:
            break;
        }
        default:
            break;
    }
    return 0;
}
//
// function:            getManualControlType
// description:         extract the manual control type (continuous or timed)
//
// @param[in]           filename
// @return              control type (int)
//
static unsigned int getManualControlType(const char *filename)
{
    char buf[MAX_FILE_SIZE];
    unsigned int type = MANUAL_CONTROL_TYPE_NONE;
    bool rc = GLOBAL_mdot->readUserFile(filename, buf, MAX_FILE_SIZE);
    if ( rc != true ) {
        logError("%s: failed to read %s", __func__, filename);
    } else {
        cJSON * root = cJSON_Parse(buf);
        type = atoi(cJSON_GetObjectItem(root,"type")->valuestring);
        cJSON_Delete(root);
    }
    return type;
}