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.
Dependencies: NaturalTinyShell_ice libmDot-12Sept mbed-rtos mbed
Fork of ICE by
src/OutputTask/OutputTask.cpp
- Committer:
- jmarkel44
- Date:
- 2016-09-23
- Revision:
- 122:4db48b933115
- Parent:
- 121:650205ffa656
- Child:
- 128:534bf29132f8
File content as of revision 122:4db48b933115:
/****************************************************************************** * * File: OutputTask.cpp * Desciption: source for the ICE Output task * *****************************************************************************/ #include "OutputTask.h" #include "global.h" #include "MbedJSONValue.h" #include "ModbusMasterApi.h" #include "LoggerApi.h" #include <vector> #include <string> #include <algorithm> // local functions static int createOutput(const char *controlFile); static void loadPersistentOutputs(void); static void refreshOutputs(const string); static int enableOutputReq(OutputControlMsg_t *msg); static int disableOutputReq(OutputControlMsg_t *msg); static int unregisterControl(const char *id, unsigned int pri, const char *output); // The Output Map // // this is the main data structure used to distinguish which control has // priority of an output. the layout is as-follows: // // outputMap["o_rly1"]-> Control<"ManCtrl_rly1", 100, ON > // Control<"SetpointCtrl_rly1", 800, OFF> // outputMap["o_rly2"]-> Control<"SetpointCtrl_rly2", 800, ON > // outputMap["o_rly3"]-> Control<"TimerControl_rl3", 500, ON> // // The Control Vector (per relay) is always sorted by priority, whereas // the highest priority control is at the beginning (v.begin()) of the // list. typedef std::map<string, vector<Control> > StringOutputVector_t; StringOutputVector_t outputMap; // operator for sorting the outputs vectors per output bool operator<(const Control &control1, const Control &control2) { return control1.getPriority() < control2.getPriority(); } /***************************************************************************** * Function: OutputTask * Description: Main entry point for the Output Task * * @param args -> not used * @return none *****************************************************************************/ void OutputTask(void const *args) { int rc; UNUSED(args); printf("\r%s has started...\n", __func__); loadPersistentOutputs(); osSignalSet(mainThreadId, sig_output_continue); while (true) { // wait for an event osEvent evt = OutputMasterMailBox.get(); if (evt.status == osEventMail) { OutputControlMsg_t *msg = (OutputControlMsg_t*) evt.value.p; switch ( msg->action ) { case ACTION_NEW: // read the file and and create an output entry rc = createOutput(msg->controlFile); if ( rc != 0 ) { logError("%s: failed to create output %s\n", __func__, msg->controlFile); } break; case ACTION_CONTROL_ON: logInfo("%s is requesting ON control of %s", msg->id, msg->output_tag); rc = enableOutputReq(msg); if ( rc != 0 ) { logError("%s: failed to enabled output for %s", __func__, msg->id); } break; case ACTION_CONTROL_OFF: logInfo("%s is requesting OFF control of %s", msg->id, msg->output_tag); rc = disableOutputReq(msg); if ( rc != 0 ) { printf("%s: failed to disabled output for %s", __func__, msg->id); } break; case ACTION_CONTROL_UNREGISTER: logInfo("%s is requesting its deletion from %s", msg->id, msg->output_tag); rc = unregisterControl(msg->id, msg->priority, msg->output_tag); if ( rc != 0 ) { printf("%s: failed to unregister control %s", __func__, msg->id); } break; default: break; } // free the message OutputMasterMailBox.free(msg); // refresh the outputs refreshOutputs(msg->id); } } } void recordEvent(std::string output, const Control *control) { EventReasonStruct_t ev; ModbusValue input_value; ModbusValue output_value; memset(&ev, 0, sizeof(ev)); switch ( control->getControlType() ) { case CONTROL_SETPOINT: ev.eventReason = EVENT_REASON_AUTO; strncpy(ev.inputTag, control->getInput().c_str(), sizeof(ev.inputTag)); strncpy(ev.outputTag, output.c_str(), sizeof(ev.outputTag)); ModbusMasterReadRegister(control->getInput(), &input_value); ModbusMasterReadRegister(output, &output_value); ev.inputValue = input_value.value; ev.outputValue = output_value.value; printf("\rEVENT RECORD\n"); printf("\rev.eventReason = %d\n", ev.eventReason); printf("\rev.inputTag = %s\n", ev.inputTag); printf("\rev.outputTag = %s\n", ev.outputTag); printf("\rev.inputValue = %.02f\n", ev.inputValue); printf("\rev.outputValue = %.02f\n", ev.outputValue); EventLoggerApi(ev); break; case CONTROL_MANUAL: ev.eventReason = EVENT_REASON_MANUAL; strncpy(ev.outputTag, output.c_str(), sizeof(ev.outputTag)); ModbusMasterReadRegister(output, &output_value); ev.outputValue = output_value.value; printf("\rEVENT RECORD\n"); printf("\rev.eventReason = %d\n", ev.eventReason); printf("\rev.outputTag = %s\n", ev.outputTag); printf("\rev.outputValue = %.02f\n", ev.outputValue); EventLoggerApi(ev); break; default: break; } } /***************************************************************************** * Function: refreshOutputs * Description: send a message to the modbus master of who's in control * * * @param args -> not used * @return none *****************************************************************************/ static void refreshOutputs(const string id) { //who's in control here? StringOutputVector_t::iterator pos; for ( pos = outputMap.begin(); pos != outputMap.end(); ++pos ) { if ( pos->second.empty() ) { // safeguarding ModbusMasterWriteRegister(pos->first, 0.00); } else { // a control is tied to this output if ( id == pos->second.begin()->getId() ) { ModbusMasterWriteRegister(pos->first, pos->second.begin()->getState()); recordEvent(pos->first, (Control*)pos->second.begin()); } } } } /***************************************************************************** * Function: DisplayOutputs * Description: Display a list of outputs and its controls * * @param args -> not used * @return none *****************************************************************************/ void DisplayOutputs(void) { StringOutputVector_t::iterator pos; for ( pos = outputMap.begin(); pos != outputMap.end(); ++pos ) { if ( pos->second.empty() ) { printf("\r [%s]->[no controls]\n", pos->first.c_str()); } else { printf("\r [%s]->", pos->first.c_str()); vector<Control>::iterator i; for ( i = pos->second.begin(); i != pos->second.end(); ++i ) { i->display(); } printf("\n"); } } printf("\r\n"); } /***************************************************************************** * Function: createOutput * Description: * * @param controlFile -> name of output file * @return none *****************************************************************************/ static int createOutput(const char *outputFile) { char dataBuf[1024]; int status = GLOBAL_mdot->readUserFile(outputFile, (void *)dataBuf, sizeof(dataBuf)); if ( status != true ) { logError("%s failed to read %s", __func__, outputFile); return -1; } MbedJSONValue json_value; parse(json_value, dataBuf); // extract the relay information string id = json_value["id"].get<string>(); // maps don't allow duplicates, and the vector is empty for now vector<Control> v; outputMap[id] = v; return 0; } /***************************************************************************** * Function: enableOutputReq * Description: Display a list of outputs and its controls * * @param args -> not used * @return none *****************************************************************************/ static int enableOutputReq(OutputControlMsg_t *msg) { // attempt to find the output in the map StringOutputVector_t::iterator pos; pos = outputMap.find(msg->output_tag); if ( pos == outputMap.end() ) { printf("%s: failed to find the designated output %s\n", __func__, msg->output_tag); return -1; } if ( pos->second.empty() ) { // this is a new request string cid(msg->id); string input(msg->input_tag); Control c(cid, msg->controlType, input, msg->priority, CONTROL_ON); pos->second.push_back(c); } else { // find this control in the list vector<Control>::iterator v; for ( v = pos->second.begin(); v != pos->second.end(); ++v ) { if ( strcmp(v->getId().c_str(), msg->id) == 0 ) { v->setState(CONTROL_ON); break; } } if ( v == pos->second.end() ) { // this is a new request, so add it and sort the vector string cid(msg->id); string input(msg->input_tag); Control c(cid, msg->controlType, input, msg->priority, CONTROL_ON); pos->second.push_back(c); std::sort(pos->second.begin(), pos->second.end()); } } return 0; } /***************************************************************************** * Function: disableOutputReq * Description: * * @param args -> not used * @return none *****************************************************************************/ static int disableOutputReq(OutputControlMsg_t *msg) { // attempt to find the output in the map StringOutputVector_t::iterator pos; pos = outputMap.find(msg->output_tag); if ( pos == outputMap.end() ) { printf("%s: failed to find the designated output %s\n", __func__, msg->output_tag); return -1; } // if the control list is empty, push this control on the list if ( pos->second.empty() ) { string cid(msg->id); string input(msg->input_tag); Control c(cid, msg->controlType, input, msg->priority, CONTROL_OFF); pos->second.push_back(c); } else { // find this control in the list vector<Control>::iterator v; for ( v = pos->second.begin(); v != pos->second.end(); ++v ) { if ( strcmp(v->getId().c_str(), msg->id) == 0 ) { v->setState(CONTROL_OFF); break; } } if ( v == pos->second.end() ) { // this is a new request, so add it and sort the vector string cid(msg->id); string input(msg->input_tag); Control c(cid, msg->controlType, input, msg->priority, CONTROL_OFF); pos->second.push_back(c); std::sort(pos->second.begin(), pos->second.end()); } } return 0; } /***************************************************************************** * Function: unregisterControl * Description: * * @param id -> control identifier * @param pri -> priority * @param output -> output (e.g. "o_rly5) * * @return 0 on success; -1 on error *****************************************************************************/ static int unregisterControl(const char *id, unsigned int pri, const char *output) { // attempt to find the output in the map StringOutputVector_t::iterator pos; bool found = false; pos = outputMap.find(output); if ( pos == outputMap.end() ) { printf("%s: failed to find the designated output %s\n", __func__, output); return -1; } // find the control in the list vector<Control>::iterator v; for ( v = pos->second.begin(); v != pos->second.end(); ++v) { if ( strcmp(v->getId().c_str(), id) == 0 ) { // delete this entry pos->second.erase(v); found = true; break; } } if ( !found ) { logError("%s: failed to find control %s in list", __func__, id); return -1; } return 0; } /***************************************************************************** * Function: loadPersistentOutputs * Description: pump up the output map based on persistent files * * @param args -> not used * @return none *****************************************************************************/ static void loadPersistentOutputs(void) { bool status; MbedJSONValue json_value; printf("\rLoading persistent outputs:\n"); std::vector<mDot::mdot_file> file_list = GLOBAL_mdot->listUserFiles(); for (std::vector<mDot::mdot_file>::iterator i = file_list.begin(); i != file_list.end(); ++i) { if( strncmp( i->name, OUTPUT_STR, strlen(OUTPUT_STR)) == 0 ) { logInfo("%s: FOUND OUTPUT FILE: %s", __func__, i->name); char scratchBuf[1024]; status = GLOBAL_mdot->readUserFile(i->name, scratchBuf, 1024); if( status != true ) { logInfo("(%d)read file failed, status=%d", __LINE__, status); } else { logInfo("(%d)Read File SUCCESS: %s", __LINE__, scratchBuf ); } parse( json_value, scratchBuf ); string id = json_value["id"].get<string>(); printf("\r output %s loaded\n", i->name); // emplace the empty control vector into the output map vector<Control> v; outputMap[id] = v; } } }