예제 #1
0
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
}
예제 #2
0
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();
}
예제 #3
0
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);
}