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.
Diff: ICE-Application/src/ConfigurationHandler/ConfigurationHandler.cpp
- Revision:
- 0:61364762ee0e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ICE-Application/src/ConfigurationHandler/ConfigurationHandler.cpp Tue Jan 24 19:05:33 2017 +0000 @@ -0,0 +1,733 @@ +/****************************************************************************** + * + * 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; +}