int QueueManager::GetNextCommand(const COMMAND& setCommand, COMMAND** outputCmd) { *outputCmd = 0; QString address = setCommand.address(); if (address.isEmpty()) return 0; CheckContainerExist(address); int curValue = Containers[address]->Value(); if (setCommand.command != CMD_SET)/* || (curValue == setCommand.value))*/ return 0; // force repeat off if (setCommand.value == -1) { *outputCmd = new COMMAND(setCommand.channel, setCommand.unit, CMD_OFF, -1); return 1; } if (curValue == setCommand.value) { Logger::Log(ERROR, "GetNextCommand outputs 0 sub cmds"); return 0; } if (curValue == -1) { if (setCommand.value == MAX_VALUE) { *outputCmd = new COMMAND(setCommand.channel, setCommand.unit, CMD_ON, MAX_VALUE); return 1; } else { *outputCmd = new COMMAND(setCommand.channel, setCommand.unit, CMD_DIM, MAX_VALUE - 1); return 1 + MAX_VALUE - setCommand.value; } } else // already on { if (curValue > setCommand.value) { *outputCmd = new COMMAND(setCommand.channel, setCommand.unit, CMD_DIM, curValue - 1); return (curValue - setCommand.value); } else { // shortcut ? off - on - down(s) may be faster if ((setCommand.value - curValue) > (2 + MAX_VALUE - setCommand.value)) { *outputCmd = new COMMAND(setCommand.channel, setCommand.unit, CMD_OFF, -1); return (2 + MAX_VALUE - setCommand.value); } *outputCmd = new COMMAND(setCommand.channel, setCommand.unit, CMD_BRIGHT, curValue + 1); return (setCommand.value - curValue); } } // return 0; // nothing to do }
void QueueManager::QueueCommand(const COMMAND& cmd) { CheckService(); QString listNodes = NodesList(); QStringList nodes = listNodes.split(" ", QString::SkipEmptyParts); if (cmd.channel == '*' || cmd.unit == 0) { Logger::Log(INFO, "Incoming Generic Command %s", qPrintable(cmd.commandStr())); char nodeChannel = 'A'; int nodeUnit = 0; bool bMatch = false; for (int i=0; i<nodes.count(); i++) { X10::sourceToAddress(nodes[i], nodeChannel, nodeUnit); if ( ((cmd.channel == '*' ) || (nodeChannel == cmd.channel)) && ((cmd.unit == 0 ) || (nodeUnit == cmd.unit)) ) { // match desired pattern E0 * *2 among known containers QueueCommand(COMMAND(nodeChannel, nodeUnit, cmd.command, cmd.value)); bMatch = true; } } if (!bMatch) { Logger::Log(INFO, "No source matching %s in nodes list (%s)", qPrintable(cmd.address()), qPrintable(listNodes) ); } return; } Logger::Log(INFO, "Incoming Command %s", qPrintable(cmd.commandStr())); const QMutexLocker locker(&m_mutex); //check existing commmand if (config.SMART_QUEUE) { for (std::list<COMMAND*>::iterator itr = m_queueCommands.begin(); itr != m_queueCommands.end();) { COMMAND* cmdit = *itr; // same channel / unit ? if ((cmd.channel == cmdit->channel) && (cmd.unit == cmdit->unit)) { if (cmd.command == CMD_SET) { // SET erase all other command // Logger::Log(DEBUG, "Incoming SET %s CANCELLED queued command %s", qPrintable(cmd.commandStr()), qPrintable(cmdit->commandStr())); itr = m_queueCommands.erase(itr); continue; } else if (cmd.command == CMD_OFF) { // OFF erase all other command // Logger::Log(DEBUG, "Incoming Stop %s CANCELLED queued command %s", qPrintable(cmd.commandStr()), qPrintable(cmdit->commandStr())); itr = m_queueCommands.erase(itr); continue; } else if (cmd.command == CMD_BRIGHT || cmd.command == CMD_DIM) { if (cmdit->command != cmd.command) // reverse direction, remove both commands { // Logger::Log(DEBUG, "Incoming command %s CANCELLED queued command %s", qPrintable(cmd.commandStr()), qPrintable(cmdit->commandStr())); itr = m_queueCommands.erase(itr); return; } } } ++itr; } // end for } // end smart queue // enqueue m_queueCommands.push_front(new COMMAND(cmd)); queueNotEmpty.wakeOne(); }
void QueueManager::run() { SetStatus(QM_STARTING); m_isRunning = true; m_ruleManager.Load(config.RULES_LOCATION); SetStatus(QM_LOADING); m_controllerLoaded = ControllerLoad(); int res = 0; // flush queue commented because of cmd line (will wake up queue) // m_queueCommands.clear(); struct x10_ha_command x10CmdRecv; Logger::Log(DEBUG, "** QueueManager Entering loop", qPrintable(StatusStr())); while (m_isRunning) { QMutexLocker locker(&m_mutex); unsigned int nbErrors = 0; // while nothing to send while (m_isRunning && !m_queueCommands.size()) { /// Read input. if (m_controllerLoaded) { res = m_X10Controller->x10_recv(&x10CmdRecv); if (res > 0) { nbErrors = 0; Logger::Log(INFO, "X10 command received on house %c unit %d, cmd:%s res:%d", house_code_to_char(x10CmdRecv.house), unit_code_to_int(x10CmdRecv.unit), cmd_code_to_str(x10CmdRecv.cmd), res); // emit CommandReceived(*cmd); QString address = QString("%1%2") .arg(house_code_to_char(x10CmdRecv.house)) .arg(unit_code_to_int(x10CmdRecv.unit)) .toUpper(); CheckContainerExist(address); switch (x10CmdRecv.cmd) { case X10CMD_ON: Containers[address]->SetOn(true); break; case X10CMD_OFF: Containers[address]->SetOn(false); break; case X10CMD_BRIGHT: Containers[address]->PushDirection(true); break; case X10CMD_DIM: Containers[address]->PushDirection(false); break; case X10CMD_UP: case X10CMD_RIGHT: case X10CMD_DOWN: case X10CMD_LEFT: break; case X10CMD_INVALID: break; } emit CommandReceived(); } else if (res && res != -110 /*&& res != -1*/) // first res is -1 { // Logger::Log(ERROR, "res = -1 !!", res); nbErrors++; Logger::Log(DEBUG, "ERROR: (%d)", res); if (nbErrors > config.MAX_ERRORS) break; } } queueNotEmpty.wait(&m_mutex, 1000); } if (nbErrors > config.MAX_ERRORS) // reload controller { ControllerUnload(); if (!config.RELOAD_ON_ERROR) { Logger::Log(ERROR, "X10 Interface died, quitting QueueManager thread"); break; } nbErrors = 0; ControllerLoad(); continue; } COMMAND* cmd = 0; if (m_isRunning && m_queueCommands.size()) // not supposed to be empty at this point { cmd = m_queueCommands.back(); // when receiving it, it is this engine role to figure out how if (cmd->command == CMD_SET) { COMMAND* intermCmd; int nbSteps = GetNextCommand(*cmd, &intermCmd); // unique step or nothing to do if (nbSteps <= 1) m_queueCommands.remove(cmd); if (nbSteps) { if (!cmd->notified) { emit CommandCompleted(*cmd); cmd->notified = true; } intermCmd->notified = true; // not to be resent by subcmd } // Logger::Log(DEBUG, "** SET to %d produced %d steps", cmd->value, nbSteps); cmd = intermCmd; // null if nothing to do } else { // Logger::Log(DEBUG, "** SEND command"); m_queueCommands.remove(cmd); // 1 step per command } } locker.unlock(); if (!cmd) continue; // end marker x10_ha_command* x10cmd = new_x10_ha_command(parse_cmd_code(cmd->command), cmd->channel, cmd->unit); if (x10cmd) // else params out of bound { QString address = cmd->address(); CheckContainerExist(address); // for read int currentValue = Containers[address]->Value(); switch (cmd->command) { case CMD_SET: Containers[address]->SetValue(cmd->value); break; case CMD_ON: Containers[address]->SetValue(currentValue < 0 ? MAX_VALUE : currentValue); break; case CMD_OFF: Containers[address]->SetValue(-1); break; case CMD_DIM: if (currentValue == -1) currentValue = MAX_VALUE; Containers[address]->SetValue(currentValue ? currentValue - 1 : 0); break; case CMD_BRIGHT: if (currentValue == -1) currentValue = MAX_VALUE; Containers[address]->SetValue(currentValue >= MAX_VALUE ? MAX_VALUE : currentValue + 1); break; default: break; } if (m_controllerLoaded) { // emit CommandCompleted if not SET if (!cmd->notified) emit CommandCompleted(*cmd); m_X10Controller->x10_send(x10cmd); } else { Logger::Log(ERROR, "NO Controller to send Command %s", qPrintable(cmd->commandStr())); } del_x10_ha_command(x10cmd); } delete cmd; } ControllerUnload(); SetStatus(QM_STOPPED); }