<commit_before>/*
 * Copyright (c) 2013-2020 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "sensor.h"
#include "json.h"

/*! Returns a fingerprint as JSON string. */
QString SensorFingerprint::toString() const
{
    if (endpoint == 0xFF || profileId == 0xFFFF)
    {
        return QString();
    }

    QVariantMap map;
    map["ep"] = (double)endpoint;
    map["p"] = (double)profileId;
    map["d"] = (double)deviceId;

    if (!inClusters.empty())
    {
        QVariantList ls;
        for (uint  i = 0; i < inClusters.size(); i++)
        {
            ls.append((double)inClusters[i]);
        }
        map["in"] = ls;
    }

    if (!outClusters.empty())
    {
        QVariantList ls;
        for (uint  i = 0; i < outClusters.size(); i++)
        {
            ls.append((double)outClusters[i]);
        }
        map["out"] = ls;
    }

    return deCONZ::jsonStringFromMap(map);
}

/*! Parses a fingerprint from JSON string.
    \returns true on success
*/
bool SensorFingerprint::readFromJsonString(const QString &json)
{
    if (json.isEmpty())
    {
        return false;
    }

    bool ok = false;
    QVariant var = Json::parse(json, ok);

    if (!ok)
    {
        return false;
    }

    QVariantMap map = var.toMap();

    if (map.contains("ep") && map.contains("p") && map.contains("d"))
    {
        endpoint = map["ep"].toUInt(&ok);
        if (!ok) { return false; }
        profileId = map["p"].toUInt(&ok);
        if (!ok) { return false; }
        deviceId = map["d"].toUInt(&ok);
        if (!ok) { return false; }

        inClusters.clear();
        outClusters.clear();

        if (map.contains("in") && map["in"].type() == QVariant::List)
        {
            QVariantList ls = map["in"].toList();
            QVariantList::const_iterator i = ls.constBegin();
            QVariantList::const_iterator end = ls.constEnd();
            for (; i != end; ++i)
            {
                quint16 clusterId = i->toUInt(&ok);
                if (ok)
                {
                    inClusters.push_back(clusterId);
                }
            }
        }

        if (map.contains("out") && map["out"].type() == QVariant::List)
        {
            QVariantList ls = map["out"].toList();
            QVariantList::const_iterator i = ls.constBegin();
            QVariantList::const_iterator end = ls.constEnd();
            for (; i != end; ++i)
            {
                quint16 clusterId = i->toUInt(&ok);
                if (ok)
                {
                    outClusters.push_back(clusterId);
                }
            }
        }

        return true;
    }

    return false;
}

/*! Returns true if server cluster is part of the finger print.
 */
bool SensorFingerprint::hasInCluster(quint16 clusterId) const
{
    for (size_t i = 0; i < inClusters.size(); i++)
    {
        if (inClusters[i] == clusterId)
        {
            return true;
        }
    }

    return false;
}

/*! Returns true if server cluster is part of the finger print.
 */
bool SensorFingerprint::hasOutCluster(quint16 clusterId) const
{
    for (size_t i = 0; i < outClusters.size(); i++)
    {
        if (outClusters[i] == clusterId)
        {
            return true;
        }
    }

    return false;
}

/*! Constructor. */
Sensor::Sensor() :
    Resource(RSensors),
    m_deletedstate(Sensor::StateNormal),
    m_mode(ModeTwoGroups),
    m_resetRetryCount(0),
    m_rxCounter(0)
{
    QDateTime now = QDateTime::currentDateTime();
    lastStatePush = now;
    lastConfigPush = now;
    durationDue = QDateTime();

    // common sensor items
    addItem(DataTypeString, RAttrName);
    addItem(DataTypeString, RAttrManufacturerName);
    addItem(DataTypeString, RAttrModelId);
    addItem(DataTypeString, RAttrType);
    addItem(DataTypeString, RAttrSwVersion);
    addItem(DataTypeString, RAttrId);
    addItem(DataTypeString, RAttrUniqueId);
    addItem(DataTypeBool, RConfigOn);
    addItem(DataTypeBool, RConfigReachable);
    addItem(DataTypeTime, RStateLastUpdated);

    previousDirection = 0xFF;
    previousCt = 0xFFFF;
    previousSequenceNumber = 0xFF;
    previousCommandId = 0xFF;
}

/*! Returns the sensor deleted state.
 */
Sensor::DeletedState Sensor::deletedState() const
{
    return m_deletedstate;
}

/*! Sets the sensor deleted state.
    \param deletedState the sensor deleted state
 */
void Sensor::setDeletedState(DeletedState deletedstate)
{
    m_deletedstate = deletedstate;
}

/*! Returns true if the sensor is reachable.
 */
bool Sensor::isAvailable() const
{
    const ResourceItem *i = item(RConfigReachable);
    if (i)
    {
        return i->toBool();
    }
    return true;
}

/*! Returns the sensor name.
 */
const QString &Sensor::name() const
{
   return item(RAttrName)->toString();
}

/*! Sets the sensor name.
    \param name the sensor name
 */
void Sensor::setName(const QString &name)
{
    item(RAttrName)->setValue(name);
}

/*! Returns the sensor mode.
 */
Sensor::SensorMode Sensor::mode() const
{
   return m_mode;
}

/*! Sets the sensor mode (Lighting Switch).
 * 1 = Secenes
 * 2 = Groups
 * 3 = Color Temperature
    \param mode the sensor mode
 */
void Sensor::setMode(SensorMode mode)
{
    m_mode = mode;
}

/*! Returns the sensor type.
 */
const QString &Sensor::type() const
{
    return item(RAttrType)->toString();
}

/*! Sets the sensor type.
    \param type the sensor type
 */
void Sensor::setType(const QString &type)
{
    item(RAttrType)->setValue(type);
}

/*! Returns the sensor modelId.
 */
const QString &Sensor::modelId() const
{
    return item(RAttrModelId)->toString();
}

/*! Sets the sensor modelId.
    \param mid the sensor modelId
 */
void Sensor::setModelId(const QString &mid)
{
    item(RAttrModelId)->setValue(mid.trimmed());
}

/*! Returns the resetRetryCount.
 */
uint8_t Sensor::resetRetryCount() const
{
    return m_resetRetryCount;
}

/*! Sets the resetRetryCount.
    \param resetRetryCount the resetRetryCount
 */
void Sensor::setResetRetryCount(uint8_t resetRetryCount)
{
    m_resetRetryCount = resetRetryCount;
}

/*! Returns the zdpResetSeq number.
 */
uint8_t Sensor::zdpResetSeq() const
{
    return m_zdpResetSeq;
}

/*! Sets the zdpResetSeq number.
    \param resetRetryCount the resetRetryCount
 */
void Sensor::setZdpResetSeq(uint8_t zdpResetSeq)
{
    m_zdpResetSeq = zdpResetSeq;
}

void Sensor::updateStateTimestamp()
{
    ResourceItem *i = item(RStateLastUpdated);
    if (i)
    {
        i->setValue(QDateTime::currentDateTimeUtc());
        m_rxCounter++;
    }
}

/*! Increments the number of received commands during this session. */
void Sensor::incrementRxCounter()
{
    m_rxCounter++;
}

/*! Returns number of received commands during this session. */
int Sensor::rxCounter() const
{
    return m_rxCounter;
}

/*! Returns the sensor manufacturer.
 */
const QString &Sensor::manufacturer() const
{
    return item(RAttrManufacturerName)->toString();
}

/*! Sets the sensor manufacturer.
    \param manufacturer the sensor manufacturer
 */
void Sensor::setManufacturer(const QString &manufacturer)
{
    item(RAttrManufacturerName)->setValue(manufacturer.trimmed());
}

/*! Returns the sensor software version.
    Not supported for ZGP Sensortype
 */
const QString &Sensor::swVersion() const
{
    return item(RAttrSwVersion)->toString();
}

/*! Sets the sensor software version.
    \param swVersion the sensor software version
 */
void Sensor::setSwVersion(const QString &swversion)
{
    item(RAttrSwVersion)->setValue(swversion.trimmed());
}

/*! Transfers state into JSONString.
 */
QString Sensor::stateToString()
{
    QVariantMap map;

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (strncmp(rid.suffix, "state/", 6) == 0)
        {
            const char *key = item->descriptor().suffix + 6;
            map[key] = item->toVariant();
        }
    }

    return Json::serialize(map);
}

/*! Transfers config into JSONString.
 */
QString Sensor::configToString()
{
    QVariantMap map;

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (strncmp(rid.suffix, "config/", 7) == 0)
        {
            const char *key = item->descriptor().suffix + 7;
            map[key] = item->toVariant();
        }
    }

    return Json::serialize(map);
}

/*! Parse the sensor state from a JSON string. */
void Sensor::jsonToState(const QString &json)
{
    bool ok;
    QVariant var = Json::parse(json, ok);

    if (!ok)
    {
        return;
    }

    QVariantMap map = var.toMap();

    if (map.contains("lastset"))
    {
        QString lastset = map["lastset"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ssZ");
        QDateTime ls = QDateTime::fromString(lastset, format);
        ls.setTimeSpec(Qt::UTC);
        map["lastset"] = ls;
    }

    // use old time stamp before deCONZ was started
    QDateTime dt = QDateTime::currentDateTime().addSecs(-120);
    if (map.contains("lastupdated"))
    {
        QString lastupdated = map["lastupdated"].toString();
        QString format = lastupdated.length() == 19 ? QLatin1String("yyyy-MM-ddTHH:mm:ss") : QLatin1String("yyyy-MM-ddTHH:mm:ss.zzz");
        QDateTime lu = QDateTime::fromString(lastupdated, format);
        if (lu < dt)
        {
            dt = lu;
        }
        lu.setTimeSpec(Qt::UTC);
        map["lastupdated"] = lu;
    }

    if (map.contains("localtime"))
    {
        QString localtime = map["localtime"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ss");
        QDateTime lt = QDateTime::fromString(localtime, format);
        map["localtime"] = lt;
    }

    if (map.contains("utc"))
    {
        QString utc = map["utc"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ssZ");
        QDateTime u = QDateTime::fromString(utc, format);
        u.setTimeSpec(Qt::UTC);
        map["utc"] = u;
    }

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (strncmp(rid.suffix, "state/", 6) == 0)
        {
            const char *key = item->descriptor().suffix + 6;

            if (map.contains(QLatin1String(key)))
            {
                item->setValue(map[key]);
                item->setTimeStamps(dt);
            }
        }
    }
}

/*! Parse the sensor config from a JSON string. */
void Sensor::jsonToConfig(const QString &json)
{
    bool ok;

    QVariant var = Json::parse(json, ok);

    if (!ok)
    {
        return;
    }
    QVariantMap map = var.toMap();

    if (map.contains("lastchange_time"))
    {
        QString lastchange_time = map["lastchange_time"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ssZ");
        QDateTime lct = QDateTime::fromString(lastchange_time, format);
        lct.setTimeSpec(Qt::UTC);
        map["lastchange_time"] = lct;
    }

    QDateTime dt = QDateTime::currentDateTime().addSecs(-120);

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (type().startsWith(QLatin1String("CLIP")))
        {}
        else if (item->descriptor().suffix == RConfigReachable)
        { // set only from live data
            item->setValue(false);
            continue;
        }

        if (strncmp(rid.suffix, "config/", 7) == 0 && rid.suffix != RConfigPending)
        {
            const char *key = item->descriptor().suffix + 7;

            if (map.contains(QLatin1String(key)))
            {
                QVariant val = map[key];

                if (val.isNull())
                {
                    if (rid.suffix == RConfigOn)
                    {
                        map[key] = true; // default value
                        setNeedSaveDatabase(true);
                    }
                    else
                    {
                        continue;
                    }
                }

                item->setValue(map[key]);
                item->setTimeStamps(dt);
            }
        }
    }
}

/*! Returns the sensor fingerprint. */
SensorFingerprint &Sensor::fingerPrint()
{
    return m_fingerPrint;
}

/*! Returns the sensor fingerprint. */
const SensorFingerprint &Sensor::fingerPrint() const
{
    return m_fingerPrint;
}

const std::vector<Sensor::ButtonMap> Sensor::buttonMap(const QMap<QString, std::vector<Sensor::ButtonMap>> &buttonMapData, QMap<QString, QString> &buttonMapForModelId)
{
    if (m_buttonMap.empty())
    {
        const QString &modelid = item(RAttrModelId)->toString();

        for (auto i = buttonMapForModelId.constBegin(); i != buttonMapForModelId.constEnd(); ++i)
        {
            if (modelid.startsWith(QString(i.key())))
            {
                m_buttonMap = buttonMapData.value(i.value());
            }
        }
    }

    return m_buttonMap;
}

<commit_msg>Workaround for Tuya<commit_after>/*
 * Copyright (c) 2013-2020 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "sensor.h"
#include "json.h"

/*! Returns a fingerprint as JSON string. */
QString SensorFingerprint::toString() const
{
    if (endpoint == 0xFF || profileId == 0xFFFF)
    {
        return QString();
    }

    QVariantMap map;
    map["ep"] = (double)endpoint;
    map["p"] = (double)profileId;
    map["d"] = (double)deviceId;

    if (!inClusters.empty())
    {
        QVariantList ls;
        for (uint  i = 0; i < inClusters.size(); i++)
        {
            ls.append((double)inClusters[i]);
        }
        map["in"] = ls;
    }

    if (!outClusters.empty())
    {
        QVariantList ls;
        for (uint  i = 0; i < outClusters.size(); i++)
        {
            ls.append((double)outClusters[i]);
        }
        map["out"] = ls;
    }

    return deCONZ::jsonStringFromMap(map);
}

/*! Parses a fingerprint from JSON string.
    \returns true on success
*/
bool SensorFingerprint::readFromJsonString(const QString &json)
{
    if (json.isEmpty())
    {
        return false;
    }

    bool ok = false;
    QVariant var = Json::parse(json, ok);

    if (!ok)
    {
        return false;
    }

    QVariantMap map = var.toMap();

    if (map.contains("ep") && map.contains("p") && map.contains("d"))
    {
        endpoint = map["ep"].toUInt(&ok);
        if (!ok) { return false; }
        profileId = map["p"].toUInt(&ok);
        if (!ok) { return false; }
        deviceId = map["d"].toUInt(&ok);
        if (!ok) { return false; }

        inClusters.clear();
        outClusters.clear();

        if (map.contains("in") && map["in"].type() == QVariant::List)
        {
            QVariantList ls = map["in"].toList();
            QVariantList::const_iterator i = ls.constBegin();
            QVariantList::const_iterator end = ls.constEnd();
            for (; i != end; ++i)
            {
                quint16 clusterId = i->toUInt(&ok);
                if (ok)
                {
                    inClusters.push_back(clusterId);
                }
            }
        }

        if (map.contains("out") && map["out"].type() == QVariant::List)
        {
            QVariantList ls = map["out"].toList();
            QVariantList::const_iterator i = ls.constBegin();
            QVariantList::const_iterator end = ls.constEnd();
            for (; i != end; ++i)
            {
                quint16 clusterId = i->toUInt(&ok);
                if (ok)
                {
                    outClusters.push_back(clusterId);
                }
            }
        }

        return true;
    }

    return false;
}

/*! Returns true if server cluster is part of the finger print.
 */
bool SensorFingerprint::hasInCluster(quint16 clusterId) const
{
    for (size_t i = 0; i < inClusters.size(); i++)
    {
        if (inClusters[i] == clusterId)
        {
            return true;
        }
    }

    return false;
}

/*! Returns true if server cluster is part of the finger print.
 */
bool SensorFingerprint::hasOutCluster(quint16 clusterId) const
{
    for (size_t i = 0; i < outClusters.size(); i++)
    {
        if (outClusters[i] == clusterId)
        {
            return true;
        }
    }

    return false;
}

/*! Constructor. */
Sensor::Sensor() :
    Resource(RSensors),
    m_deletedstate(Sensor::StateNormal),
    m_mode(ModeTwoGroups),
    m_resetRetryCount(0),
    m_rxCounter(0)
{
    QDateTime now = QDateTime::currentDateTime();
    lastStatePush = now;
    lastConfigPush = now;
    durationDue = QDateTime();

    // common sensor items
    addItem(DataTypeString, RAttrName);
    addItem(DataTypeString, RAttrManufacturerName);
    addItem(DataTypeString, RAttrModelId);
    addItem(DataTypeString, RAttrType);
    addItem(DataTypeString, RAttrSwVersion);
    addItem(DataTypeString, RAttrId);
    addItem(DataTypeString, RAttrUniqueId);
    addItem(DataTypeBool, RConfigOn);
    addItem(DataTypeBool, RConfigReachable);
    addItem(DataTypeTime, RStateLastUpdated);

    previousDirection = 0xFF;
    previousCt = 0xFFFF;
    previousSequenceNumber = 0xFF;
    previousCommandId = 0xFF;
}

/*! Returns the sensor deleted state.
 */
Sensor::DeletedState Sensor::deletedState() const
{
    return m_deletedstate;
}

/*! Sets the sensor deleted state.
    \param deletedState the sensor deleted state
 */
void Sensor::setDeletedState(DeletedState deletedstate)
{
    m_deletedstate = deletedstate;
}

/*! Returns true if the sensor is reachable.
 */
bool Sensor::isAvailable() const
{
    const ResourceItem *i = item(RConfigReachable);
    if (i)
    {
        return i->toBool();
    }
    return true;
}

/*! Returns the sensor name.
 */
const QString &Sensor::name() const
{
   return item(RAttrName)->toString();
}

/*! Sets the sensor name.
    \param name the sensor name
 */
void Sensor::setName(const QString &name)
{
    item(RAttrName)->setValue(name);
}

/*! Returns the sensor mode.
 */
Sensor::SensorMode Sensor::mode() const
{
   return m_mode;
}

/*! Sets the sensor mode (Lighting Switch).
 * 1 = Secenes
 * 2 = Groups
 * 3 = Color Temperature
    \param mode the sensor mode
 */
void Sensor::setMode(SensorMode mode)
{
    m_mode = mode;
}

/*! Returns the sensor type.
 */
const QString &Sensor::type() const
{
    return item(RAttrType)->toString();
}

/*! Sets the sensor type.
    \param type the sensor type
 */
void Sensor::setType(const QString &type)
{
    item(RAttrType)->setValue(type);
}

/*! Returns the sensor modelId.
 */
const QString &Sensor::modelId() const
{
    return item(RAttrModelId)->toString();
}

/*! Sets the sensor modelId.
    \param mid the sensor modelId
 */
void Sensor::setModelId(const QString &mid)
{
    item(RAttrModelId)->setValue(mid.trimmed());
}

/*! Returns the resetRetryCount.
 */
uint8_t Sensor::resetRetryCount() const
{
    return m_resetRetryCount;
}

/*! Sets the resetRetryCount.
    \param resetRetryCount the resetRetryCount
 */
void Sensor::setResetRetryCount(uint8_t resetRetryCount)
{
    m_resetRetryCount = resetRetryCount;
}

/*! Returns the zdpResetSeq number.
 */
uint8_t Sensor::zdpResetSeq() const
{
    return m_zdpResetSeq;
}

/*! Sets the zdpResetSeq number.
    \param resetRetryCount the resetRetryCount
 */
void Sensor::setZdpResetSeq(uint8_t zdpResetSeq)
{
    m_zdpResetSeq = zdpResetSeq;
}

void Sensor::updateStateTimestamp()
{
    ResourceItem *i = item(RStateLastUpdated);
    if (i)
    {
        i->setValue(QDateTime::currentDateTimeUtc());
        m_rxCounter++;
    }
}

/*! Increments the number of received commands during this session. */
void Sensor::incrementRxCounter()
{
    m_rxCounter++;
}

/*! Returns number of received commands during this session. */
int Sensor::rxCounter() const
{
    return m_rxCounter;
}

/*! Returns the sensor manufacturer.
 */
const QString &Sensor::manufacturer() const
{
    return item(RAttrManufacturerName)->toString();
}

/*! Sets the sensor manufacturer.
    \param manufacturer the sensor manufacturer
 */
void Sensor::setManufacturer(const QString &manufacturer)
{
    item(RAttrManufacturerName)->setValue(manufacturer.trimmed());
}

/*! Returns the sensor software version.
    Not supported for ZGP Sensortype
 */
const QString &Sensor::swVersion() const
{
    return item(RAttrSwVersion)->toString();
}

/*! Sets the sensor software version.
    \param swVersion the sensor software version
 */
void Sensor::setSwVersion(const QString &swversion)
{
    item(RAttrSwVersion)->setValue(swversion.trimmed());
}

/*! Transfers state into JSONString.
 */
QString Sensor::stateToString()
{
    QVariantMap map;

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (strncmp(rid.suffix, "state/", 6) == 0)
        {
            const char *key = item->descriptor().suffix + 6;
            map[key] = item->toVariant();
        }
    }

    return Json::serialize(map);
}

/*! Transfers config into JSONString.
 */
QString Sensor::configToString()
{
    QVariantMap map;

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (strncmp(rid.suffix, "config/", 7) == 0)
        {
            const char *key = item->descriptor().suffix + 7;
            map[key] = item->toVariant();
        }
    }

    return Json::serialize(map);
}

/*! Parse the sensor state from a JSON string. */
void Sensor::jsonToState(const QString &json)
{
    bool ok;
    QVariant var = Json::parse(json, ok);

    if (!ok)
    {
        return;
    }

    QVariantMap map = var.toMap();

    if (map.contains("lastset"))
    {
        QString lastset = map["lastset"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ssZ");
        QDateTime ls = QDateTime::fromString(lastset, format);
        ls.setTimeSpec(Qt::UTC);
        map["lastset"] = ls;
    }

    // use old time stamp before deCONZ was started
    QDateTime dt = QDateTime::currentDateTime().addSecs(-120);
    if (map.contains("lastupdated"))
    {
        QString lastupdated = map["lastupdated"].toString();
        QString format = lastupdated.length() == 19 ? QLatin1String("yyyy-MM-ddTHH:mm:ss") : QLatin1String("yyyy-MM-ddTHH:mm:ss.zzz");
        QDateTime lu = QDateTime::fromString(lastupdated, format);
        if (lu < dt)
        {
            dt = lu;
        }
        lu.setTimeSpec(Qt::UTC);
        map["lastupdated"] = lu;
    }

    if (map.contains("localtime"))
    {
        QString localtime = map["localtime"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ss");
        QDateTime lt = QDateTime::fromString(localtime, format);
        map["localtime"] = lt;
    }

    if (map.contains("utc"))
    {
        QString utc = map["utc"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ssZ");
        QDateTime u = QDateTime::fromString(utc, format);
        u.setTimeSpec(Qt::UTC);
        map["utc"] = u;
    }

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (strncmp(rid.suffix, "state/", 6) == 0)
        {
            const char *key = item->descriptor().suffix + 6;

            if (map.contains(QLatin1String(key)))
            {
                item->setValue(map[key]);
                item->setTimeStamps(dt);
            }
        }
    }
}

/*! Parse the sensor config from a JSON string. */
void Sensor::jsonToConfig(const QString &json)
{
    bool ok;

    QVariant var = Json::parse(json, ok);

    if (!ok)
    {
        return;
    }
    QVariantMap map = var.toMap();

    if (map.contains("lastchange_time"))
    {
        QString lastchange_time = map["lastchange_time"].toString();
        QString format = QLatin1String("yyyy-MM-ddTHH:mm:ssZ");
        QDateTime lct = QDateTime::fromString(lastchange_time, format);
        lct.setTimeSpec(Qt::UTC);
        map["lastchange_time"] = lct;
    }

    QDateTime dt = QDateTime::currentDateTime().addSecs(-120);

    for (int i = 0; i < itemCount(); i++)
    {
        ResourceItem *item = itemForIndex(i);
        const ResourceItemDescriptor &rid = item->descriptor();

        if (type().startsWith(QLatin1String("CLIP")))
        {}
        else if (item->descriptor().suffix == RConfigReachable)
        { // set only from live data
            item->setValue(false);
            continue;
        }

        if (strncmp(rid.suffix, "config/", 7) == 0 && rid.suffix != RConfigPending)
        {
            const char *key = item->descriptor().suffix + 7;

            if (map.contains(QLatin1String(key)))
            {
                QVariant val = map[key];

                if (val.isNull())
                {
                    if (rid.suffix == RConfigOn)
                    {
                        map[key] = true; // default value
                        setNeedSaveDatabase(true);
                    }
                    else
                    {
                        continue;
                    }
                }

                item->setValue(map[key]);
                item->setTimeStamps(dt);
            }
        }
    }
}

/*! Returns the sensor fingerprint. */
SensorFingerprint &Sensor::fingerPrint()
{
    return m_fingerPrint;
}

/*! Returns the sensor fingerprint. */
const SensorFingerprint &Sensor::fingerPrint() const
{
    return m_fingerPrint;
}

const std::vector<Sensor::ButtonMap> Sensor::buttonMap(const QMap<QString, std::vector<Sensor::ButtonMap>> &buttonMapData, QMap<QString, QString> &buttonMapForModelId)
{
    if (m_buttonMap.empty())
    {
        const QString &modelid = item(RAttrModelId)->toString();
        const QString &manufacturer = item(RAttrManufacturerName)->toString();

        for (auto i = buttonMapForModelId.constBegin(); i != buttonMapForModelId.constEnd(); ++i)
        {
            if (modelid.startsWith(QString(i.key())))
            {
                m_buttonMap = buttonMapData.value(i.value());
            }
        }
        // Workaround for Tuya without usable modelid
        if (manufacturer == QLatin1String("_TZ3000_bi6lpsew")) // can't use model id but manufacture name is device specific
        {
            m_buttonMap = buttonMapData.value("Tuya3gangMap");
        }
    }

    return m_buttonMap;
}

<|endoftext|>


<commit_before><commit_msg>Prediction: Fix lint error.<commit_after><|endoftext|>


<commit_before>#include "Piezas.h"
#include <vector>
/** CLASS Piezas
 * Class for representing a Piezas vertical board, which is roughly based
 * on the game "Connect Four" where pieces are placed in a column and
 * fall to the bottom of the column, or on top of other pieces already in
 * that column. For an illustration of the board, see:
 *  https://en.wikipedia.org/wiki/Connect_Four
 *
 * Board coordinates [row,col] should match with:
 * [2,0][2,1][2,2][2,3]
 * [1,0][1,1][1,2][1,3]
 * [0,0][0,1][0,2][0,3]
 * So that a piece dropped in column 2 should take [0,2] and the next one
 * dropped in column 2 should take [1,2].
**/

using namespace std;

void Piezas::toggleTurn()
{
  if(this->turn == X)
  {
    this->turn = O;
  }
  else if(this->turn == O)
  {
    this->turn = X;
  }
}

/**
 * Constructor sets an empty board (default 3 rows, 4 columns) and
 * specifies it is X's turn first
**/
Piezas::Piezas()
{
  board.resize(BOARD_ROWS);
  for(int i=0; i<BOARD_ROWS; i++)
  {
    board[i].resize(BOARD_COLS);
    for(int j=0; j<BOARD_COLS;j++)
    {
      board[i][j] = Blank;
    }
  }
  this->turn = X;
}

/**
 * Resets each board location to the Blank Piece value, with a board of the
 * same size as previously specified
**/
void Piezas::reset()
{
  for(int i=0; i<BOARD_ROWS; i++)
  {
    for(int j=0; j<BOARD_COLS;j++)
    {
      board[i][j] = Blank;
    }
  }
}

/**
 * Places a piece of the current turn on the board, returns what
 * piece is placed, and toggles which Piece's turn it is. dropPiece does
 * NOT allow to place a piece in a location where a column is full.
 * In that case, placePiece returns Piece Blank value
 * Out of bounds coordinates return the Piece Invalid value
 * Trying to drop a piece where it cannot be placed loses the player's turn
**/
Piece Piezas::dropPiece(int column)
{
  if(column > 3 || column < 0)
  {
    toggleTurn();
    return Invalid;
  }
  for(int i=0; i<BOARD_ROWS; i++)
  {
    if(board[i][column] == Blank)
    {
      board[i][column] = turn;
      Piece temp = turn;
      toggleTurn();
      return temp;
    }
  }
  toggleTurn();
  return Blank;
}

/**
 * Returns what piece is at the provided coordinates, or Blank if there
 * are no pieces there, or Invalid if the coordinates are out of bounds
**/
Piece Piezas::pieceAt(int row, int column)
{
  if(row > 2 || row < 0 || column > 3 || column < 0)
  {
    return Invalid;
  }
  else return board[row][column];
}

/**
 * Returns which Piece has won, if there is a winner, Invalid if the game
 * is not over, or Blank if the board is filled and no one has won ("tie").
 * For a game to be over, all locations on the board must be filled with X's
 * and O's (i.e. no remaining Blank spaces). The winner is which player has
 * the most adjacent pieces in a single line. Lines can go either vertically
 * or horizontally. If both X's and O's have the same max number of pieces in a
 * line, it is a tie.
**/
Piece Piezas::gameState()
{
  bool board_full = true;
  for(int i=0; i<BOARD_ROWS; i++)
  {
    for(int j=0; j<BOARD_COLS;j++)
    {
      if(board[i][j] == Blank)
      {
        board_full = false;
      }
    }
  }
  if(board_full == false)
  {
    return Invalid;
  }

  int X_count = 0;
  int max_X = 0;
  int O_count = 0;
  int max_O = 0;

  for(int i=0; i<BOARD_ROWS; i++)
  {
    for(int j=0; j<BOARD_COLS;j++)
    {
      if(board[i][j] == X)
      {
        X_count++;
        if(X_count > max_X)
        {
          max_X = X_count;
        }
        O_count = 0;
      }
      else if(board[i][j] == O)
      {
        O_count++;
        if(O_count > max_O)
        {
          max_O = O_count;
        }
        X_count = 0;
      }
    }
  }

  for(int i=0; i<BOARD_COLS; i++)
  {
    for(int j=0; j<BOARD_ROWS;j++)
    {
      if(board[i][j] == X)
      {
        X_count++;
        if(X_count > max_X)
        {
          max_X = X_count;
        }
        O_count = 0;
      }
      else if(board[i][j] == O)
      {
        O_count++;
        if(O_count > max_O)
        {
          max_O = O_count;
        }
        X_count = 0;
      }
    }
  }

  if(max_X > max_O)
  {
    return X;
  }

  else if(max_O > max_X)
  {
    return O;
  }

  return Blank;
}
<commit_msg>fifth commit<commit_after>#include "Piezas.h"
#include <vector>
/** CLASS Piezas
 * Class for representing a Piezas vertical board, which is roughly based
 * on the game "Connect Four" where pieces are placed in a column and
 * fall to the bottom of the column, or on top of other pieces already in
 * that column. For an illustration of the board, see:
 *  https://en.wikipedia.org/wiki/Connect_Four
 *
 * Board coordinates [row,col] should match with:
 * [2,0][2,1][2,2][2,3]
 * [1,0][1,1][1,2][1,3]
 * [0,0][0,1][0,2][0,3]
 * So that a piece dropped in column 2 should take [0,2] and the next one
 * dropped in column 2 should take [1,2].
**/

using namespace std;

void Piezas::toggleTurn()
{
  if(this->turn == X)
  {
    this->turn = O;
  }
  else if(this->turn == O)
  {
    this->turn = X;
  }
}

/**
 * Constructor sets an empty board (default 3 rows, 4 columns) and
 * specifies it is X's turn first
**/
Piezas::Piezas()
{
  board.resize(BOARD_ROWS);
  for(int i=0; i<BOARD_ROWS; i++)
  {
    board[i].resize(BOARD_COLS);
    for(int j=0; j<BOARD_COLS;j++)
    {
      board[i][j] = Blank;
    }
  }
  this->turn = X;
}

/**
 * Resets each board location to the Blank Piece value, with a board of the
 * same size as previously specified
**/
void Piezas::reset()
{
  for(int i=0; i<BOARD_ROWS; i++)
  {
    for(int j=0; j<BOARD_COLS;j++)
    {
      board[i][j] = Blank;
    }
  }
}

/**
 * Places a piece of the current turn on the board, returns what
 * piece is placed, and toggles which Piece's turn it is. dropPiece does
 * NOT allow to place a piece in a location where a column is full.
 * In that case, placePiece returns Piece Blank value
 * Out of bounds coordinates return the Piece Invalid value
 * Trying to drop a piece where it cannot be placed loses the player's turn
**/
Piece Piezas::dropPiece(int column)
{
  if(column > 3 || column < 0)
  {
    toggleTurn();
    return Invalid;
  }
  for(int i=0; i<BOARD_ROWS; i++)
  {
    if(board[i][column] == Blank)
    {
      board[i][column] = turn;
      Piece temp = turn;
      toggleTurn();
      return temp;
    }
  }
  toggleTurn();
  return Blank;
}

/**
 * Returns what piece is at the provided coordinates, or Blank if there
 * are no pieces there, or Invalid if the coordinates are out of bounds
**/
Piece Piezas::pieceAt(int row, int column)
{
  if(row > 2 || row < 0 || column > 3 || column < 0)
  {
    return Invalid;
  }
  else return board[row][column];
}

/**
 * Returns which Piece has won, if there is a winner, Invalid if the game
 * is not over, or Blank if the board is filled and no one has won ("tie").
 * For a game to be over, all locations on the board must be filled with X's
 * and O's (i.e. no remaining Blank spaces). The winner is which player has
 * the most adjacent pieces in a single line. Lines can go either vertically
 * or horizontally. If both X's and O's have the same max number of pieces in a
 * line, it is a tie.
**/
Piece Piezas::gameState()
{
  bool board_full = true;
  for(int i=0; i<BOARD_ROWS; i++)
  {
    for(int j=0; j<BOARD_COLS;j++)
    {
      if(board[i][j] == Blank)
      {
        board_full = false;
      }
    }
  }
  if(board_full == false)
  {
    return Invalid;
  }

  int X_count = 0;
  int max_X = 0;
  int O_count = 0;
  int max_O = 0;

  for(int i=0; i<BOARD_ROWS; i++)
  {
    for(int j=0; j<BOARD_COLS;j++)
    {
      if(board[i][j] == X)
      {
        X_count++;
        if(X_count > max_X)
        {
          max_X = X_count;
        }
        O_count = 0;
      }
      else if(board[i][j] == O)
      {
        O_count++;
        if(O_count > max_O)
        {
          max_O = O_count;
        }
        X_count = 0;
      }
    }
  }

  for(int i=0; i<BOARD_COLS; i++)
  {
    for(int j=0; j<BOARD_ROWS;j++)
    {
      if(board[j][i] == X)
      {
        X_count++;
        if(X_count > max_X)
        {
          max_X = X_count;
        }
        O_count = 0;
      }
      else if(board[j][i] == O)
      {
        O_count++;
        if(O_count > max_O)
        {
          max_O = O_count;
        }
        X_count = 0;
      }
    }
  }

  if(max_X > max_O)
  {
    return X;
  }

  else if(max_O > max_X)
  {
    return O;
  }

  return Blank;
}
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: sysinfo.C,v 1.5 2005/01/25 17:15:50 amoll Exp $
//

#include <BALL/SYSTEM/sysinfo.h>

#ifndef BALL_PLATFORM_WINDOWS
 #include <sys/sysinfo.h>
 #include <BALL/SYSTEM/file.h>
#else
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
#endif

namespace BALL
{
	namespace SysInfo
	{

		float getAvailableMemory()
		{
			float mem = getFreeMemory();
#ifndef BALL_PLATFORM_WINDOWS
			mem += getBufferdMemory();
#endif
			return mem;
		}

		float getFreeMemory()
		{
#ifdef BALL_PLATFORM_WINDOWS
			/*
			MEMORYSTATUS ms;
			GlobalMemoryStatus (&ms);
			return (float) ms.dwAvailPhys;
			*/
			MEMORYSTATUSEX statex;
			GlobalMemoryStatusEx (&statex);
			return (float) statex.ullAvailPhys
#else
			try
			{
				File cpuinfo("/proc/meminfo");
				char buffer[1024];
				String line;
				while (!cpuinfo.eof())
				{
					cpuinfo.getline(buffer, 1024);
					line.assign(buffer);
					if (line.hasPrefix("MemFree:"))
					{
						line = line.after(":");
						line.trimLeft();
						line = line.before(" ");
						return line.toFloat() * 1024;
					}
				}
			}
			catch(...)
			{
			}

			// sysinfo seems to return somewhat unsane values, but better than nothing...
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.freeram;
#endif
		}

		float getTotalMemory()
		{
#ifdef BALL_PLATFORM_WINDOWS
			/*
			MEMORYSTATUS ms;
			GlobalMemoryStatus (&ms);
			return (float) ms.dwTotalPhys;
			*/
 			MEMORYSTATUSEX statex;
			GlobalMemoryStatusEx (&statex);
			return (float) statex.ullFullPhys
#else
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.totalram;
#endif
		}

		float getBufferdMemory()
		{
#ifdef BALL_PLATFORM_WINDOWS
#else
			try
			{
				File cpuinfo("/proc/meminfo");
				char buffer[1024];
				String line;
				while (!cpuinfo.eof())
				{
					cpuinfo.getline(buffer, 1024);
					line.assign(buffer);
					if (line.hasPrefix("Cached:"))
					{
						line = line.after(":");
						line.trimLeft();
						line = line.before(" ");
						return line.toFloat() * 1024;
					}
				}
			}
			catch(...)
			{
			}

			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.bufferram;
#endif
		}

		float getUptime()
		{
#ifdef BALL_PLATFORM_WINDOWS
			return -1;
#else
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.uptime;
#endif
		}

		Index getNumberOfProcessors()
		{
#ifdef BALL_PLATFORM_WINDOWS
			struct SYSTEM_INFO sysinfo;
			GetSystemInfo(&sysinfo);
			return sysinfo.dwNumberOfProcessors;
#else
			try
			{
				File cpuinfo("/proc/cpuinfo");
				char buffer[1024];
				String line;
				Index nr_processors = 0;
				while (!cpuinfo.eof())
				{
					cpuinfo.getline(buffer, 1024);
					line.assign(buffer);
					if (line.hasPrefix("processor"))
					{
						nr_processors++;
					}
				}

				if (nr_processors == 0) return -1;

				return nr_processors;
			}
			catch(...)
			{
			}

			return -1;
#endif
		}

		float getFreeSwapSpace()
		{
#ifdef BALL_PLATFORM_WINDOWS
 			MEMORYSTATUSEX statex;
			GlobalMemoryStatusEx (&statex);
			return (float) statex.ullAvailPageFile;
#else
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.freeswap;
#endif

		}

	} // namespace SysInfo
} // namespace BALL

<commit_msg>no message<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: sysinfo.C,v 1.6 2005/01/27 12:39:15 amoll Exp $
//

#include <BALL/SYSTEM/sysinfo.h>

#ifndef BALL_PLATFORM_WINDOWS
 #include <sys/sysinfo.h>
 #include <BALL/SYSTEM/file.h>
#else
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
#endif

namespace BALL
{
	namespace SysInfo
	{

		float getAvailableMemory()
		{
			float mem = getFreeMemory();
#ifndef BALL_PLATFORM_WINDOWS
			mem += getBufferdMemory();
#endif
			return mem;
		}

		float getFreeMemory()
		{
#ifdef BALL_PLATFORM_WINDOWS
			/*
			MEMORYSTATUS ms;
			GlobalMemoryStatus (&ms);
			return (float) ms.dwAvailPhys;
			*/
			MEMORYSTATUSEX statex;
			GlobalMemoryStatusEx (&statex);
			return (float) statex.ullAvailPhys;
#else
			try
			{
				File cpuinfo("/proc/meminfo");
				char buffer[1024];
				String line;
				while (!cpuinfo.eof())
				{
					cpuinfo.getline(buffer, 1024);
					line.assign(buffer);
					if (line.hasPrefix("MemFree:"))
					{
						line = line.after(":");
						line.trimLeft();
						line = line.before(" ");
						return line.toFloat() * 1024;
					}
				}
			}
			catch(...)
			{
			}

			// sysinfo seems to return somewhat unsane values, but better than nothing...
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.freeram;
#endif
		}

		float getTotalMemory()
		{
#ifdef BALL_PLATFORM_WINDOWS
			/*
			MEMORYSTATUS ms;
			GlobalMemoryStatus (&ms);
			return (float) ms.dwTotalPhys;
			*/
 			MEMORYSTATUSEX statex;
			GlobalMemoryStatusEx (&statex);
			return (float) statex.ullTotalPhys;
#else
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.totalram;
#endif
		}

		float getBufferdMemory()
		{
#ifdef BALL_PLATFORM_WINDOWS
#else
			try
			{
				File cpuinfo("/proc/meminfo");
				char buffer[1024];
				String line;
				while (!cpuinfo.eof())
				{
					cpuinfo.getline(buffer, 1024);
					line.assign(buffer);
					if (line.hasPrefix("Cached:"))
					{
						line = line.after(":");
						line.trimLeft();
						line = line.before(" ");
						return line.toFloat() * 1024;
					}
				}
			}
			catch(...)
			{
			}

			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.bufferram;
#endif
		}

		float getUptime()
		{
#ifdef BALL_PLATFORM_WINDOWS
			return -1;
#else
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.uptime;
#endif
		}

		Index getNumberOfProcessors()
		{
#ifdef BALL_PLATFORM_WINDOWS
			SYSTEM_INFO sysinfo;
			GetSystemInfo(&sysinfo);
			return sysinfo.dwNumberOfProcessors;
#else
			try
			{
				File cpuinfo("/proc/cpuinfo");
				char buffer[1024];
				String line;
				Index nr_processors = 0;
				while (!cpuinfo.eof())
				{
					cpuinfo.getline(buffer, 1024);
					line.assign(buffer);
					if (line.hasPrefix("processor"))
					{
						nr_processors++;
					}
				}

				if (nr_processors == 0) return -1;

				return nr_processors;
			}
			catch(...)
			{
			}

			return -1;
#endif
		}

		float getFreeSwapSpace()
		{
#ifdef BALL_PLATFORM_WINDOWS
 			MEMORYSTATUSEX statex;
			GlobalMemoryStatusEx (&statex);
			return (float) statex.ullAvailPageFile;
#else
			struct sysinfo info;
			float result = sysinfo(&info);
			if (result == -1) return result;
			return info.freeswap;
#endif

		}

	} // namespace SysInfo
} // namespace BALL

<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2020 Intel Corporation. All Rights Reserved.

#include "common.h"
#include <common/utilities/string/string-utilities.h>
#include <ostream>
using namespace utilities::string;

template <typename T, typename std::enable_if <std::is_arithmetic<T>::value>::type* = nullptr> // check if T is arithmetic during compile
std::string to_str(const T& t)
{
    /// The std::to_string will make the min float value equal zero, so another function is
    /// params: a value type T
    /// returns: a string of the given number
    std::ostringstream os;
    os << t;
    return os.str();
}

template<typename T>
struct string_checker
{
    std::string str;
    T value;
    bool expected_res;
};

template<typename T>
void check_tests(std::vector<string_checker<T>>& tests)
{
    T value;
    for (const auto& test : tests)
    {
        CHECK(string_to_value<T>(test.str, value) == test.expected_res);
        if (test.expected_res)
        {
            CHECK(value == test.value);
        }
    }
}

TEST_CASE("string to value", "[string]")
{
    // int
    std::vector<string_checker<int>> int_tests;
    int_tests.push_back(string_checker<int>{ "123", 123, true });
    int_tests.push_back(string_checker<int>{ "-123", -123, true });
    int_tests.push_back(string_checker<int>{ "-123456789", -123456789, true });
    int_tests.push_back(string_checker<int>{ std::to_string(std::numeric_limits<int>::max())+"0", 0, false });
    int_tests.push_back(string_checker<int>{ std::to_string(std::numeric_limits<int>::min())+"0", 0, false });
    int_tests.push_back(string_checker<int>{ "abc", 0, false });

    check_tests<int>(int_tests);

    // unsigned int
    std::vector<string_checker<unsigned int>> uint_tests;
    uint_tests.push_back(string_checker<unsigned int>{ "123", 123, true });
    uint_tests.push_back(string_checker<unsigned int>{ "123456789", 123456789, true });
    uint_tests.push_back(string_checker<unsigned int>{ "-123456789", 0, false });
    uint_tests.push_back(string_checker<unsigned int>{ std::to_string(std::numeric_limits<unsigned int>::max())+"0", 0, false });
    uint_tests.push_back(string_checker<unsigned int>{ "abc", 0, false });

    check_tests<unsigned int>(uint_tests);

    // short
    std::vector<string_checker<short>> s_tests;
    s_tests.push_back(string_checker<short>{ "123", 123, true });
    s_tests.push_back(string_checker<short>{ "-123", -123, true });
    s_tests.push_back(string_checker<short>{ std::to_string(std::numeric_limits<short>::max())+"0", 0, false });
    s_tests.push_back(string_checker<short>{ std::to_string(std::numeric_limits<short>::min())+"0", 0, false });
    s_tests.push_back(string_checker<short>{ "abc", 0, false });

    check_tests<short>(s_tests);

    // unsigned short
    std::vector<string_checker<unsigned short>> us_tests;
    us_tests.push_back(string_checker<unsigned short>{ "123", 123, true });
    us_tests.push_back(string_checker<unsigned short>{ "-123", 0, false });
    us_tests.push_back(string_checker<unsigned short>{std::to_string(std::numeric_limits<unsigned short>::max())+"0", 0, false });
    us_tests.push_back(string_checker<unsigned short>{ "abc", 0, false });

    check_tests<unsigned short>(us_tests);

    // long
    std::vector<string_checker<long>> l_tests;
    l_tests.push_back(string_checker<long>{ "123", 123, true });
    l_tests.push_back(string_checker<long>{ "-123", -123, true });
    l_tests.push_back(string_checker<long>{ "-123456789", -123456789, true });
    l_tests.push_back(string_checker<long>{ std::to_string(std::numeric_limits<long>::max())+"0", 0, false });
    l_tests.push_back(string_checker<long>{ std::to_string(std::numeric_limits<long>::min())+"0", 0, false });
    l_tests.push_back(string_checker<long>{ "abc", 0, false });

    check_tests<long>(l_tests);

    // long long
    std::vector<string_checker<long long>> ll_tests;
    ll_tests.push_back(string_checker<long long>{ "123", 123, true });
    ll_tests.push_back(string_checker<long long>{ "-123", -123, true });
    ll_tests.push_back(string_checker<long long>{ "12345", 12345, true });
    ll_tests.push_back(string_checker<long long>{ "-12345", -12345, true });
    ll_tests.push_back(string_checker<long long>{ std::to_string(std::numeric_limits<long long>::max())+"0", 0, false });
    ll_tests.push_back(string_checker<long long>{ std::to_string(std::numeric_limits<long long>::min()) + "0", 0, false });
    ll_tests.push_back(string_checker<long long>{ "abc", 0, false });

    check_tests<long long>(ll_tests);

    // ungined long long
    std::vector<string_checker<unsigned long long>> ull_tests;
    ull_tests.push_back(string_checker<unsigned long long>{ "123", 123, true });
    ull_tests.push_back(string_checker<unsigned long long>{ "123456789", 123456789, true });
    ull_tests.push_back(string_checker<unsigned long long>{ "-123456789", 0, false });
    ull_tests.push_back(string_checker<unsigned long long>{ std::to_string(std::numeric_limits<unsigned long long>::max())+"0", 0, false });
    ull_tests.push_back(string_checker<unsigned long long>{ "abc", 0, false });

    check_tests<unsigned long long>(ull_tests);

    // float
    std::vector<string_checker<float>> f_tests;
    f_tests.push_back(string_checker<float>{ "1.23456789", 1.23456789f, true });
    f_tests.push_back(string_checker<float>{ "2.12121212", 2.12121212f, true });
    f_tests.push_back(string_checker<float>{ "-1.23456789", -1.23456789f, true });
    f_tests.push_back(string_checker<float>{ "-2.12121212", -2.12121212f, true });
    f_tests.push_back(string_checker<float>{ "INF", 0.f, false });
    f_tests.push_back(string_checker<float>{ "-INF", 0.f, false });
    f_tests.push_back(string_checker<float>{ to_str(std::numeric_limits<float>::max()) + "0", 0.f, false });
    f_tests.push_back(string_checker<float>{ to_str(std::numeric_limits<float>::min())+"0", 0.f, false });
    f_tests.push_back(string_checker<float>{ to_str(std::numeric_limits<float>::lowest())+"0", 0.f, false });
    f_tests.push_back(string_checker<float>{ "NaN", 0.f, false });
    f_tests.push_back(string_checker<float>{ "abc", 0.f, false });

    check_tests<float>(f_tests);

    // double
    std::vector<string_checker<double>> d_tests;
    d_tests.push_back(string_checker<double>{ "1.2345", 1.2345, true });
    d_tests.push_back(string_checker<double>{ "2.12121212", 2.12121212, true });
    d_tests.push_back(string_checker<double>{ "-1.2345", -1.2345, true });
    d_tests.push_back(string_checker<double>{ "-2.12121212", -2.12121212, true });
    d_tests.push_back(string_checker<double>{ "INF", 0., false });
    d_tests.push_back(string_checker<double>{ "-INF", 0., false });
    d_tests.push_back(string_checker<double>{ to_str(std::numeric_limits<double>::max())+"0", 0., false });
    d_tests.push_back(string_checker<double>{ to_str(std::numeric_limits<double>::min())+"0", 0., false });
    d_tests.push_back(string_checker<double>{ to_str(std::numeric_limits<double>::lowest())+"0", 0., false });
    d_tests.push_back(string_checker<double>{ "NaN", 0., false });
    d_tests.push_back(string_checker<double>{ "abc", 0., false });

    check_tests<double>(d_tests);

    // long double
    std::vector<string_checker<long double>> ld_tests;
    ld_tests.push_back(string_checker<long double>{ "1.23456789", 1.23456789, true });
    ld_tests.push_back(string_checker<long double>{ "-1.23456789", -1.23456789, true });
    ld_tests.push_back(string_checker<long double>{ "2.12121212", 2.12121212, true });
    ld_tests.push_back(string_checker<long double>{ "-2.12121212", -2.12121212, true });
    ld_tests.push_back(string_checker<long double>{ "INF", 0., false });
    ld_tests.push_back(string_checker<long double>{ "-INF", 0., false });
    ld_tests.push_back(string_checker<long double>{ to_str(std::numeric_limits<long double>::max())+"0", 0., false });
    ld_tests.push_back(string_checker<long double>{ to_str(std::numeric_limits<long double>::min())+"0", 0., false });
    ld_tests.push_back(string_checker<long double>{ to_str(std::numeric_limits<long double>::lowest())+"0", 0., false });
    ld_tests.push_back(string_checker<long double>{ "NaN", 0., false });
    ld_tests.push_back(string_checker<long double>{ "abc", 0., false });

    check_tests<long double>(ld_tests);
}
<commit_msg>adjustments for string_to_num unit-test<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2020 Intel Corporation. All Rights Reserved.

#include "common.h"
#include <common/utilities/string/string-utilities.h>
#include <ostream>
using namespace utilities::string;

template <typename T, typename std::enable_if <std::is_arithmetic<T>::value>::type* = nullptr> // check if T is arithmetic during compile
std::string to_str(const T& t)
{
    /// The std::to_string will make the min float value equal zero, so another function is
    /// params: a value type T
    /// returns: a string of the given number
    std::ostringstream os;
    os << t;
    return os.str();
}

template<typename T>
struct string_checker
{
    std::string str;
    T value;
    bool expected_res;
};

template<typename T>
void check_tests(std::vector<string_checker<T>>& tests)
{
    T value;
    for (const auto test : tests)
    {
        CAPTURE(test.str);
        CAPTURE(test.expected_res);
        CHECK(string_to_value<T>(test.str, value) == test.expected_res);
        if (test.expected_res)
        {
            CAPTURE(value);
            CAPTURE(test.value);
            if (std::is_integral<T>::value)
                CHECK(value == test.value);
            else // floating-point
            {
                CHECK(value == Approx(test.value));
            }
        }
    }
}

TEST_CASE("string to value", "[string]")
{
    // int
    std::vector<string_checker<int>> int_tests;
    int_tests.push_back(string_checker<int>{ "123", 123, true });
    int_tests.push_back(string_checker<int>{ "-123", -123, true });
    int_tests.push_back(string_checker<int>{ "-123456789", -123456789, true });
    int_tests.push_back(string_checker<int>{ std::to_string(std::numeric_limits<int>::max())+"0", 0, false });
    int_tests.push_back(string_checker<int>{ std::to_string(std::numeric_limits<int>::min())+"0", 0, false });
    int_tests.push_back(string_checker<int>{ "abc", 0, false });

    check_tests<int>(int_tests);

    // unsigned int
    std::vector<string_checker<unsigned int>> uint_tests;
    uint_tests.push_back(string_checker<unsigned int>{ "123", 123, true });
    uint_tests.push_back(string_checker<unsigned int>{ "123456789", 123456789, true });
    uint_tests.push_back(string_checker<unsigned int>{ "-123456789", 0, false });
    uint_tests.push_back(string_checker<unsigned int>{ std::to_string(std::numeric_limits<unsigned int>::max())+"0", 0, false });
    uint_tests.push_back(string_checker<unsigned int>{ "abc", 0, false });

    check_tests<unsigned int>(uint_tests);

    // short
    std::vector<string_checker<short>> s_tests;
    s_tests.push_back(string_checker<short>{ "123", 123, true });
    s_tests.push_back(string_checker<short>{ "-123", -123, true });
    s_tests.push_back(string_checker<short>{ std::to_string(std::numeric_limits<short>::max())+"0", 0, false });
    s_tests.push_back(string_checker<short>{ std::to_string(std::numeric_limits<short>::min())+"0", 0, false });
    s_tests.push_back(string_checker<short>{ "abc", 0, false });

    check_tests<short>(s_tests);

    // unsigned short
    std::vector<string_checker<unsigned short>> us_tests;
    us_tests.push_back(string_checker<unsigned short>{ "123", 123, true });
    us_tests.push_back(string_checker<unsigned short>{ "-123", 0, false });
    us_tests.push_back(string_checker<unsigned short>{std::to_string(std::numeric_limits<unsigned short>::max())+"0", 0, false });
    us_tests.push_back(string_checker<unsigned short>{ "abc", 0, false });

    check_tests<unsigned short>(us_tests);

    // long
    std::vector<string_checker<long>> l_tests;
    l_tests.push_back(string_checker<long>{ "123", 123, true });
    l_tests.push_back(string_checker<long>{ "-123", -123, true });
    l_tests.push_back(string_checker<long>{ "-123456789", -123456789, true });
    l_tests.push_back(string_checker<long>{ std::to_string(std::numeric_limits<long>::max())+"0", 0, false });
    l_tests.push_back(string_checker<long>{ std::to_string(std::numeric_limits<long>::min())+"0", 0, false });
    l_tests.push_back(string_checker<long>{ "abc", 0, false });

    check_tests<long>(l_tests);

    // long long
    std::vector<string_checker<long long>> ll_tests;
    ll_tests.push_back(string_checker<long long>{ "123", 123, true });
    ll_tests.push_back(string_checker<long long>{ "-123", -123, true });
    ll_tests.push_back(string_checker<long long>{ "12345", 12345, true });
    ll_tests.push_back(string_checker<long long>{ "-12345", -12345, true });
    ll_tests.push_back(string_checker<long long>{ std::to_string(std::numeric_limits<long long>::max())+"0", 0, false });
    ll_tests.push_back(string_checker<long long>{ std::to_string(std::numeric_limits<long long>::min()) + "0", 0, false });
    ll_tests.push_back(string_checker<long long>{ "abc", 0, false });

    check_tests<long long>(ll_tests);

    // ungined long long
    std::vector<string_checker<unsigned long long>> ull_tests;
    ull_tests.push_back(string_checker<unsigned long long>{ "123", 123, true });
    ull_tests.push_back(string_checker<unsigned long long>{ "123456789", 123456789, true });
    ull_tests.push_back(string_checker<unsigned long long>{ "-123456789", 0, false });
    ull_tests.push_back(string_checker<unsigned long long>{ std::to_string(std::numeric_limits<unsigned long long>::max())+"0", 0, false });
    ull_tests.push_back(string_checker<unsigned long long>{ "abc", 0, false });

    check_tests<unsigned long long>(ull_tests);

    // float
    std::vector<string_checker<float>> f_tests;
    f_tests.push_back(string_checker<float>{ "1.23456789", 1.23456789f, true });
    f_tests.push_back(string_checker<float>{ "2.12121212", 2.12121212f, true });
    f_tests.push_back(string_checker<float>{ "-1.23456789", -1.23456789f, true });
    f_tests.push_back(string_checker<float>{ "-2.12121212", -2.12121212f, true });
    f_tests.push_back(string_checker<float>{ "INF", 0.f, false });
    f_tests.push_back(string_checker<float>{ "-INF", 0.f, false });
    f_tests.push_back(string_checker<float>{ to_str(std::numeric_limits<float>::max()) + "0", 0.f, false });
    f_tests.push_back(string_checker<float>{ to_str(std::numeric_limits<float>::min())+"0", 0.f, false });
    f_tests.push_back(string_checker<float>{ to_str(std::numeric_limits<float>::lowest())+"0", 0.f, false });
    f_tests.push_back(string_checker<float>{ "NaN", 0.f, false });
    f_tests.push_back(string_checker<float>{ "abc", 0.f, false });

    check_tests<float>(f_tests);

    // double
    std::vector<string_checker<double>> d_tests;
    d_tests.push_back(string_checker<double>{ "9.876543", 9.876543, true });
    d_tests.push_back(string_checker<double>{ "2.12121212", 2.12121212, true });
    d_tests.push_back(string_checker<double>{ "-1.234598765", -1.234598765, true });
    d_tests.push_back(string_checker<double>{ "-2.12121212", -2.12121212, true });
    d_tests.push_back(string_checker<double>{ "INF", 0., false });
    d_tests.push_back(string_checker<double>{ "-INF", 0., false });
    d_tests.push_back(string_checker<double>{ to_str(std::numeric_limits<double>::max())+"0", 0., false });
    d_tests.push_back(string_checker<double>{ to_str(std::numeric_limits<double>::min())+"0", 0., false });
    d_tests.push_back(string_checker<double>{ to_str(std::numeric_limits<double>::lowest())+"0", 0., false });
    d_tests.push_back(string_checker<double>{ "NaN", 0., false });
    d_tests.push_back(string_checker<double>{ "abc", 0., false });

    check_tests<double>(d_tests);

    // long double
    std::vector<string_checker<long double>> ld_tests;
    ld_tests.push_back(string_checker<long double>{ "12345.6789123456789", 12345.6789123456789, true });
    ld_tests.push_back(string_checker<long double>{ "5432.123456789", 5432.123456789, true });
    ld_tests.push_back(string_checker<long double>{ "-12345678.23456789", -12345678.23456789, true });
    ld_tests.push_back(string_checker<long double>{ "INF", 0., false });
    ld_tests.push_back(string_checker<long double>{ "-INF", 0., false });
    ld_tests.push_back(string_checker<long double>{ to_str(std::numeric_limits<long double>::max())+"0", 0., false });
    ld_tests.push_back(string_checker<long double>{ to_str(std::numeric_limits<long double>::min())+"0", 0., false });
    ld_tests.push_back(string_checker<long double>{ to_str(std::numeric_limits<long double>::lowest())+"0", 0., false });
    ld_tests.push_back(string_checker<long double>{ "NaN", 0., false });
    ld_tests.push_back(string_checker<long double>{ "abc", 0., false });

    check_tests<long double>(ld_tests);
}
<|endoftext|>


<commit_before>/* * This file is part of Maliit framework *
 *
 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * Copyright (C) 2012 One Laptop per Child Association
 *
 * Contact: maliit-discuss@lists.maliit.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

// This file is based on mkeyboardstatetracker.cpp from libmeegotouch

#include <QSocketNotifier>

#include <libudev.h>
#include <linux/input.h>

#include "mimhwkeyboardtracker.h"
#include "mimhwkeyboardtracker_p.h"

/* bit array ops */
#define BITS2BYTES(x) ((((x) - 1) / 8) + 1)
#define TEST_BIT(bit, array) (array[(bit) / 8] & (1 << (bit) % 8))

namespace {
    const char * const keyboardPresent("/maemo/InternalKeyboard/Present");
    const char * const keyboardOpen("/maemo/InternalKeyboard/Open");
}

MImHwKeyboardTrackerPrivate::MImHwKeyboardTrackerPrivate(MImHwKeyboardTracker *q_ptr) :
#ifdef HAVE_CONTEXTSUBSCRIBER
    keyboardOpenProperty(),
#elif defined(Q_WS_MAEMO_5)
    keyboardOpenConf("/system/osso/af/slide-open"),
#else
    evdevTabletModePending(-1),
#endif
    present(false)
{
#ifdef HAVE_CONTEXTSUBSCRIBER
    ContextProperty keyboardPresentProperty(keyboardPresent);
    keyboardOpenProperty.reset(new ContextProperty(keyboardOpen));
    keyboardPresentProperty.waitForSubscription(true);
    keyboardOpenProperty->waitForSubscription(true);
    present = keyboardPresentProperty.value().toBool();
    if (present) {
        QObject::connect(keyboardOpenProperty.data(), SIGNAL(valueChanged()),
                         q_ptr, SIGNAL(stateChanged()));
    } else {
        keyboardOpenProperty.reset();
    }
#elif defined(Q_WS_MAEMO_5)
    present = true;
    QObject::connect(&keyboardOpenConf, SIGNAL(valueChanged()),
                     q_ptr, SIGNAL(stateChanged()));
#else
    Q_UNUSED(q_ptr);
    QObject::connect(this, SIGNAL(stateChanged()),
                     q_ptr, SIGNAL(stateChanged()));

    detectEvdev();
#endif
}

void MImHwKeyboardTrackerPrivate::detectEvdev()
{
    // Use udev to enumerate all input devices, using evdev on each device to
    // find the first device offering a SW_TABLET_MODE switch. If found, this
    // switch is used to determine keyboard presence.

    struct udev_list_entry *device;
    struct udev_list_entry *devices;

    struct udev *udev = udev_new();
    if (!udev)
        return;

    struct udev_enumerate *enumerate = udev_enumerate_new(udev);
    if (!enumerate) {
        udev_unref(udev);
        return;
    }

    udev_enumerate_add_match_subsystem(enumerate, "input");
    udev_enumerate_add_match_property(enumerate, "ID_INPUT", "1");
    udev_enumerate_scan_devices(enumerate);
    devices = udev_enumerate_get_list_entry(enumerate);

    udev_list_entry_foreach(device, devices) {
        const char *syspath = udev_list_entry_get_name(device);
        struct udev_device *udev_device =
            udev_device_new_from_syspath(udev, syspath);
        const char *device = udev_device_get_devnode(udev_device);

        if (device)
            tryEvdevDevice(device);

        udev_device_unref(udev_device);
        if (present)
            break;
    }
    udev_enumerate_unref(enumerate);
    udev_unref(udev);
}

void MImHwKeyboardTrackerPrivate::evdevEvent()
{
    // Parse the evdev event and look for SW_TABLET_MODE status.

    struct input_event ev;

    qint64 len = evdevFile->read((char *) &ev, sizeof(ev));
    if (len != sizeof(ev))
        return;

    // We wait for a SYN before "committing" the new state, just in case.
    if (ev.type == EV_SW && ev.code == SW_TABLET_MODE) {
        evdevTabletModePending = ev.value;
    } else if (ev.type == EV_SYN && ev.code == SYN_REPORT
            && evdevTabletModePending != -1) {
        evdevTabletMode = evdevTabletModePending;
        evdevTabletModePending = -1;
        Q_EMIT stateChanged();
    }

}

void MImHwKeyboardTrackerPrivate::tryEvdevDevice(const char *device)
{
    QFile *qfile = new QFile(this);
    unsigned char evbits[BITS2BYTES(EV_MAX)];
    int fd;

    qfile->setFileName(device);
    if (!qfile->open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
        delete qfile;
        return;
    }

    fd = qfile->handle();
    if (fd == -1) {
        delete qfile;
        return;
    }

    if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evbits) < 0) {
        delete qfile;
        return;
    }

    // Check that this input device has switches
    if (!TEST_BIT(EV_SW, evbits)) {
        delete qfile;
        return;
    }

    unsigned char swbit[BITS2BYTES(EV_MAX)];
    if (ioctl(fd, EVIOCGBIT(EV_SW, SW_CNT), swbit) < 0) {
        delete qfile;
        return;
    }

    // Check that there is a tablet mode switch here
    if (!TEST_BIT(SW_TABLET_MODE, swbit)) {
        delete qfile;
        return;
    }

    // Found an appropriate device - start monitoring it
    QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, qfile);
    sn->setEnabled(true);
    QObject::connect(sn, SIGNAL(activated(int)), this, SLOT(evdevEvent()));

    evdevFile = qfile;
    present = true;

    // Initialise initial tablet mode state
    unsigned long state[BITS2BYTES(SW_MAX)];
    if (ioctl(fd, EV_SW, state) < 0)
        return;

    evdevTabletMode = TEST_BIT(SW_TABLET_MODE, state);
}

MImHwKeyboardTrackerPrivate::~MImHwKeyboardTrackerPrivate()
{
}

MImHwKeyboardTracker::MImHwKeyboardTracker()
    : QObject(),
      d_ptr(new MImHwKeyboardTrackerPrivate(this))
{
}

MImHwKeyboardTracker::~MImHwKeyboardTracker()
{
}

bool MImHwKeyboardTracker::isPresent() const
{
    Q_D(const MImHwKeyboardTracker);

    return d->present;
}

bool MImHwKeyboardTracker::isOpen() const
{
    Q_D(const MImHwKeyboardTracker);

    if (!d->present) {
        return false;
    }

#ifdef HAVE_CONTEXTSUBSCRIBER
    return d->keyboardOpenProperty->value().toBool();
#elif defined(Q_WS_MAEMO_5)
    return d->keyboardOpenConf.value().toBool();
#else
    // If we found a talet mode switch, we report that the hardware keyboard
    // is available when the system is not in tablet mode (switch closed),
    // and is not available otherwise (switch open).
    if (d->evdevFile)
        return !d->evdevTabletMode;

    return false;
#endif
}
<commit_msg>Fixes: MALIIT#197 - Read initial SW_TABLET_MODE state correctly<commit_after>/* * This file is part of Maliit framework *
 *
 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * Copyright (C) 2012 One Laptop per Child Association
 *
 * Contact: maliit-discuss@lists.maliit.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

// This file is based on mkeyboardstatetracker.cpp from libmeegotouch

#include <QSocketNotifier>

#include <libudev.h>
#include <linux/input.h>

#include "mimhwkeyboardtracker.h"
#include "mimhwkeyboardtracker_p.h"

/* bit array ops */
#define BITS2BYTES(x) ((((x) - 1) / 8) + 1)
#define TEST_BIT(bit, array) (array[(bit) / 8] & (1 << (bit) % 8))

namespace {
    const char * const keyboardPresent("/maemo/InternalKeyboard/Present");
    const char * const keyboardOpen("/maemo/InternalKeyboard/Open");
}

MImHwKeyboardTrackerPrivate::MImHwKeyboardTrackerPrivate(MImHwKeyboardTracker *q_ptr) :
#ifdef HAVE_CONTEXTSUBSCRIBER
    keyboardOpenProperty(),
#elif defined(Q_WS_MAEMO_5)
    keyboardOpenConf("/system/osso/af/slide-open"),
#else
    evdevTabletModePending(-1),
    evdevTabletMode(0),
#endif
    present(false)
{
#ifdef HAVE_CONTEXTSUBSCRIBER
    ContextProperty keyboardPresentProperty(keyboardPresent);
    keyboardOpenProperty.reset(new ContextProperty(keyboardOpen));
    keyboardPresentProperty.waitForSubscription(true);
    keyboardOpenProperty->waitForSubscription(true);
    present = keyboardPresentProperty.value().toBool();
    if (present) {
        QObject::connect(keyboardOpenProperty.data(), SIGNAL(valueChanged()),
                         q_ptr, SIGNAL(stateChanged()));
    } else {
        keyboardOpenProperty.reset();
    }
#elif defined(Q_WS_MAEMO_5)
    present = true;
    QObject::connect(&keyboardOpenConf, SIGNAL(valueChanged()),
                     q_ptr, SIGNAL(stateChanged()));
#else
    Q_UNUSED(q_ptr);
    QObject::connect(this, SIGNAL(stateChanged()),
                     q_ptr, SIGNAL(stateChanged()));

    detectEvdev();
#endif
}

void MImHwKeyboardTrackerPrivate::detectEvdev()
{
    // Use udev to enumerate all input devices, using evdev on each device to
    // find the first device offering a SW_TABLET_MODE switch. If found, this
    // switch is used to determine keyboard presence.

    struct udev_list_entry *device;
    struct udev_list_entry *devices;

    struct udev *udev = udev_new();
    if (!udev)
        return;

    struct udev_enumerate *enumerate = udev_enumerate_new(udev);
    if (!enumerate) {
        udev_unref(udev);
        return;
    }

    udev_enumerate_add_match_subsystem(enumerate, "input");
    udev_enumerate_add_match_property(enumerate, "ID_INPUT", "1");
    udev_enumerate_scan_devices(enumerate);
    devices = udev_enumerate_get_list_entry(enumerate);

    udev_list_entry_foreach(device, devices) {
        const char *syspath = udev_list_entry_get_name(device);
        struct udev_device *udev_device =
            udev_device_new_from_syspath(udev, syspath);
        const char *device = udev_device_get_devnode(udev_device);

        if (device)
            tryEvdevDevice(device);

        udev_device_unref(udev_device);
        if (present)
            break;
    }
    udev_enumerate_unref(enumerate);
    udev_unref(udev);
}

void MImHwKeyboardTrackerPrivate::evdevEvent()
{
    // Parse the evdev event and look for SW_TABLET_MODE status.

    struct input_event ev;

    qint64 len = evdevFile->read((char *) &ev, sizeof(ev));
    if (len != sizeof(ev))
        return;

    // We wait for a SYN before "committing" the new state, just in case.
    if (ev.type == EV_SW && ev.code == SW_TABLET_MODE) {
        evdevTabletModePending = ev.value;
    } else if (ev.type == EV_SYN && ev.code == SYN_REPORT
            && evdevTabletModePending != -1) {
        evdevTabletMode = evdevTabletModePending;
        evdevTabletModePending = -1;
        Q_EMIT stateChanged();
    }

}

void MImHwKeyboardTrackerPrivate::tryEvdevDevice(const char *device)
{
    QFile *qfile = new QFile(this);
    unsigned char evbits[BITS2BYTES(EV_MAX)];
    int fd;

    qfile->setFileName(device);
    if (!qfile->open(QIODevice::ReadOnly | QIODevice::Unbuffered)) {
        delete qfile;
        return;
    }

    fd = qfile->handle();
    if (fd == -1) {
        delete qfile;
        return;
    }

    if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evbits) < 0) {
        delete qfile;
        return;
    }

    // Check that this input device has switches
    if (!TEST_BIT(EV_SW, evbits)) {
        delete qfile;
        return;
    }

    unsigned char swbit[BITS2BYTES(EV_MAX)];
    if (ioctl(fd, EVIOCGBIT(EV_SW, SW_CNT), swbit) < 0) {
        delete qfile;
        return;
    }

    // Check that there is a tablet mode switch here
    if (!TEST_BIT(SW_TABLET_MODE, swbit)) {
        delete qfile;
        return;
    }

    // Found an appropriate device - start monitoring it
    QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, qfile);
    sn->setEnabled(true);
    QObject::connect(sn, SIGNAL(activated(int)), this, SLOT(evdevEvent()));

    evdevFile = qfile;
    present = true;

    // Initialise initial tablet mode state
    unsigned long state[BITS2BYTES(SW_MAX)];
    if (ioctl(fd, EVIOCGSW(SW_MAX), state) < 0)
        return;

    evdevTabletMode = TEST_BIT(SW_TABLET_MODE, state);
}

MImHwKeyboardTrackerPrivate::~MImHwKeyboardTrackerPrivate()
{
}

MImHwKeyboardTracker::MImHwKeyboardTracker()
    : QObject(),
      d_ptr(new MImHwKeyboardTrackerPrivate(this))
{
}

MImHwKeyboardTracker::~MImHwKeyboardTracker()
{
}

bool MImHwKeyboardTracker::isPresent() const
{
    Q_D(const MImHwKeyboardTracker);

    return d->present;
}

bool MImHwKeyboardTracker::isOpen() const
{
    Q_D(const MImHwKeyboardTracker);

    if (!d->present) {
        return false;
    }

#ifdef HAVE_CONTEXTSUBSCRIBER
    return d->keyboardOpenProperty->value().toBool();
#elif defined(Q_WS_MAEMO_5)
    return d->keyboardOpenConf.value().toBool();
#else
    // If we found a talet mode switch, we report that the hardware keyboard
    // is available when the system is not in tablet mode (switch closed),
    // and is not available otherwise (switch open).
    if (d->evdevFile)
        return !d->evdevTabletMode;

    return false;
#endif
}
<|endoftext|>


<commit_before>#include "Player.h"
#include "SDL.h"
#include "InputHandler.h"

Player::Player(const LoaderParams* pParams) : SDLGameObject(pParams) { }

void Player::draw()
{
	SDLGameObject::draw();	//we now use SDLGameObject
}

void Player::update()
{
	m_velocity.setX(0);
	m_velocity.setY(0);

	m_acceleration.setX(0);
	m_acceleration.setY(0);

	handleInput();	//adding our function

	m_currentFrame = int(((SDL_GetTicks() / 100) % 6));

	SDLGameObject::update();
}

void Player::clean()
{
	//blank clean() function
}

void Player::handleInput()
{
	if (TheInputHandler::Instance()->joysticksInitialised())
	{
		//for analog sticks of the first joystick
		if ((TheInputHandler::Instance()->xvalue(0, 1) > 0) || (TheInputHandler::Instance()->xvalue(0, 1) < 0))
		{
			//if we are moving the player with analog stick while pressing Y
			//it will get an acceleration of 2 in that direction
			m_velocity.setX((float)1 * TheInputHandler::Instance()->xvalue(0, 1));
			if (TheInputHandler::Instance()->getButtonState(0, 3))	//Button 3(Yellow)
			{
				//give the player some acceleration
				m_acceleration.setX((float)2 * TheInputHandler::Instance()->xvalue(0, 1));
			}
		}

		if ((TheInputHandler::Instance()->yvalue(0, 1) > 0) || (TheInputHandler::Instance()->yvalue(0, 1) < 0))
		{
			m_velocity.setY((float)1 * TheInputHandler::Instance()->yvalue(0, 1));
			if (TheInputHandler::Instance()->getButtonState(0, 3))
			{
				m_acceleration.setY((float)2 * TheInputHandler::Instance()->yvalue(0,1));
			}
		}

		if ((TheInputHandler::Instance()->xvalue(0, 2) > 0) || (TheInputHandler::Instance()->xvalue(0, 2) < 0))
		{
			m_velocity.setX((float)1 * TheInputHandler::Instance()->xvalue(0, 2));
			if (TheInputHandler::Instance()->getButtonState(0, 3))
			{
				m_acceleration.setX((float)2 * TheInputHandler::Instance()->xvalue(0, 1));
			}
		}

		if ((TheInputHandler::Instance()->yvalue(0, 2) > 0) || (TheInputHandler::Instance()->yvalue(0, 2) < 0))
		{
			m_velocity.setY((float)1 * TheInputHandler::Instance()->yvalue(0, 2));
			if (TheInputHandler::Instance()->getButtonState(0, 3))
			{
				m_acceleration.setY((float)2 * TheInputHandler::Instance()->yvalue(0, 1));
			}
		}
		/*	Code as in the book
		//for buttons of the first joystick
		if (TheInputHandler::Instance()->getButtonState(0, 3))	//Button 3(Yellow)
		{
			//give the player some acceleration
			m_acceleration.setX(1);
		}
		*/
	}
}<commit_msg>Player function sets acceleration to 1 if LEFT mouse button is pressed<commit_after>#include "Player.h"
#include "SDL.h"
#include "InputHandler.h"

Player::Player(const LoaderParams* pParams) : SDLGameObject(pParams) { }

void Player::draw()
{
	SDLGameObject::draw();	//we now use SDLGameObject
}

void Player::update()
{
	m_velocity.setX(0);
	m_velocity.setY(0);

	m_acceleration.setX(0);
	m_acceleration.setY(0);

	handleInput();	//adding our function

	m_currentFrame = int(((SDL_GetTicks() / 100) % 6));

	SDLGameObject::update();
}

void Player::clean()
{
	//blank clean() function
}

void Player::handleInput()
{
	if (TheInputHandler::Instance()->joysticksInitialised())
	{
		//for analog sticks of the first joystick
		if ((TheInputHandler::Instance()->xvalue(0, 1) > 0) || (TheInputHandler::Instance()->xvalue(0, 1) < 0))
		{
			//if we are moving the player with analog stick while pressing Y
			//it will get an acceleration of 2 in that direction
			m_velocity.setX((float)1 * TheInputHandler::Instance()->xvalue(0, 1));
			if (TheInputHandler::Instance()->getButtonState(0, 3))	//Button 3(Yellow)
			{
				//give the player some acceleration
				m_acceleration.setX((float)2 * TheInputHandler::Instance()->xvalue(0, 1));
			}
		}

		if ((TheInputHandler::Instance()->yvalue(0, 1) > 0) || (TheInputHandler::Instance()->yvalue(0, 1) < 0))
		{
			m_velocity.setY((float)1 * TheInputHandler::Instance()->yvalue(0, 1));
			if (TheInputHandler::Instance()->getButtonState(0, 3))
			{
				m_acceleration.setY((float)2 * TheInputHandler::Instance()->yvalue(0,1));
			}
		}

		if ((TheInputHandler::Instance()->xvalue(0, 2) > 0) || (TheInputHandler::Instance()->xvalue(0, 2) < 0))
		{
			m_velocity.setX((float)1 * TheInputHandler::Instance()->xvalue(0, 2));
			if (TheInputHandler::Instance()->getButtonState(0, 3))
			{
				m_acceleration.setX((float)2 * TheInputHandler::Instance()->xvalue(0, 1));
			}
		}

		if ((TheInputHandler::Instance()->yvalue(0, 2) > 0) || (TheInputHandler::Instance()->yvalue(0, 2) < 0))
		{
			m_velocity.setY((float)1 * TheInputHandler::Instance()->yvalue(0, 2));
			if (TheInputHandler::Instance()->getButtonState(0, 3))
			{
				m_acceleration.setY((float)2 * TheInputHandler::Instance()->yvalue(0, 1));
			}
		}
		/*	Code as in the book
		//for buttons of the first joystick
		if (TheInputHandler::Instance()->getButtonState(0, 3))	//Button 3(Yellow)
		{
			//give the player some acceleration
			m_acceleration.setX(1);
		}
		*/

		//check for mouse button input
		if (InputHandler::Instance()->getMouseButtonState[LEFT])
		{
			m_acceleration.setX(1);
		}
	}
}<|endoftext|>


<commit_before>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc \r\n[tux machine number] \r\n[probability of packet corruption in int form] \r\n[probability of packet loss in int form] \r\n[probability of packet delay] \r\n[length of delay in ms] \r\n"
#define PORT 10038
#define PAKSIZE 512
#define ACK 0
#define NAK 1
#define BUFSIZE 505
#define FILENAME "Testfile"
#define TIMEOUT 100 //in ms
#define WIN_SIZE 16

using namespace std;

bool isvpack(unsigned char * p);
bool init(int argc, char** argv);
bool loadFile();
bool getFile();
bool sendFile();
bool isAck();
void handleAck();
void handleNak(int& x);
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb);
Packet createPacket(int index);
void loadWindow();
bool sendPacket();
bool getGet();

struct sockaddr_in a;
struct sockaddr_in ca;
socklen_t calen;
int rlen;
int s;
bool ack;
string fstr;
char * file;
int probCorrupt;
int probLoss;
int probDelay;
int delayT;
Packet p;
Packet window[16];
int length;
bool dropPck;
bool delayPck;
int toms;
unsigned char b[BUFSIZE];
int base;

int main(int argc, char** argv) {

  if(!init(argc, argv)) return -1;

  sendFile();

  return 0;
}

bool init(int argc, char** argv){

  if(argc != 6) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);
  char * probDelayStr = argv[4];
  probDelay = boost::lexical_cast<int>(probDelayStr);
  char* delayTStr = argv[5];
  delayT = boost::lexical_cast<int>(delayTStr);

  struct timeval timeout;
  timeout.tv_usec = TIMEOUT * 1000;
  toms = TIMEOUT;

  /* Create our socket. */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return 0;
  }

  setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

  /*
   * Bind our socket to an IP (whatever the computer decides)
   * and a specified port.
   *
   */

  if (!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY);
  a.sin_port = htons(PORT);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) {
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return 0;
  }

  fstr = string(file);
  cout << "File: " << endl << fstr << endl;

  base = 0;
  dropPck = false;
  calen = sizeof(ca);

  getGet();

  return true;
}

bool getGet(){
	unsigned char packet[PAKSIZE + 1];
	rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);
	return (rlen > 0) ? true : false;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[7];
  memcpy(css, &p[1], 6);
  css[6] = '\0';

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == 0) return false; //doesn't matter, only for the old version (netwark)
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){

  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);

    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        //seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p (false, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&ca, calen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

void loadWindow(){
	for(int i = base; i < base + WIN_SIZE; i++) {
		window[i-base] = createPacket(i);
		if(strlen(window[i-base].getDataBuffer()) < BUFSIZE - 1 && window[i-base].getDataBuffer()[0] != 'G') {
			for(++i; i < base + WIN_SIZE; i++){
				window[i-base].loadDataBuffer("\0");
			}
			return;
		}
	}
}

bool sendFile() {
	/*Currently causes the program to only send the first 16 packets of file out
		requires additional code later to sendFile again with updated window*/
	base = 0;
	while(base * BUFSIZE < length) {
		loadWindow();

		cout << "packet " << base << ": " << window[0].str() << endl;

		for(int x = 0; x < WIN_SIZE; x++) {
			p = window[x];
			if(!sendPacket()) continue;
		}
		if(p.str()[0] == '\0') break;
		for(int x = 0; x < WIN_SIZE; x++) {
			if(recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&ca, &calen) < 0) {
				cout << "=== ACK TIMEOUT" << endl;
				x--;
				continue;
			}

			if(isAck()) {
				handleAck();
			} else {
				handleAck();
				//handleNak(x);
			}

			memset(b, 0, BUFSIZE);
		}
	}

	if(sendto(s, "\0", BUFSIZE, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Final package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
	}
	return true;
}

Packet createPacket(int index){
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);

	if(mstr.length() < BUFSIZE) {
		cout << "Null terminated mstr." << endl;
		mstr[length - (index * BUFSIZE)] = '\0';
    }
    return Packet (index, mstr.c_str());
}

bool sendPacket(){
	cout << endl;
    cout << "=== TRANSMISSION START" << endl;
	cout << "Sequence number before gremlin function: " << p.getSequenceNum() << endl;
    int pc = probCorrupt; int pl = probLoss; int pd = probDelay;
	bool* pckStatus = gremlin(&p, pc, pl, pd);

	dropPck = pckStatus[0];
	delayPck = pckStatus[1];

	if (dropPck == true) return false;
	if (delayPck == true) p.setAckNack(1);

    if(sendto(s, p.str(), BUFSIZE + 8, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
    }
    return true;
}
bool isAck() {
    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {
	int ack = boost::lexical_cast<int>(b);
	if(base < ack) base = ack;
	cout << "Window base: " << base << endl;
}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb){

  bool* packStatus = new bool[2];
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  packStatus[0] = false;
  packStatus[1] = false;

  if(r <= (lossProb)){
	packStatus[0] = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (delayProb)){
	  packStatus[1] = true;
	  cout << "Delayed!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
	cout << "Seq. num (pre-gremlin): " << pack->getSequenceNum() << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  //cout << "Message: "  << pack->getDataBuffer() << endl;

  return packStatus;
}<commit_msg>Expand further on testing<commit_after>#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include "packet.h"

#define USAGE "Usage:\r\nc \r\n[tux machine number] \r\n[probability of packet corruption in int form] \r\n[probability of packet loss in int form] \r\n[probability of packet delay] \r\n[length of delay in ms] \r\n"
#define PORT 10038
#define PAKSIZE 512
#define ACK 0
#define NAK 1
#define BUFSIZE 505
#define FILENAME "Testfile"
#define TIMEOUT 100 //in ms
#define WIN_SIZE 16

using namespace std;

bool isvpack(unsigned char * p);
bool init(int argc, char** argv);
bool loadFile();
bool getFile();
bool sendFile();
bool isAck();
void handleAck();
void handleNak(int& x);
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb);
Packet createPacket(int index);
void loadWindow();
bool sendPacket();
bool getGet();

struct sockaddr_in a;
struct sockaddr_in ca;
socklen_t calen;
int rlen;
int s;
bool ack;
string fstr;
char * file;
int probCorrupt;
int probLoss;
int probDelay;
int delayT;
Packet p;
Packet window[16];
int length;
bool dropPck;
bool delayPck;
int toms;
unsigned char b[BUFSIZE];
int base;

int main(int argc, char** argv) {

  if(!init(argc, argv)) return -1;

  sendFile();

  return 0;
}

bool init(int argc, char** argv){

  if(argc != 6) {
    cout << USAGE << endl;
    return false;
  }

  char * probCorruptStr = argv[2];
  probCorrupt = boost::lexical_cast<int>(probCorruptStr);
  char * probLossStr = argv[3];
  probLoss = boost::lexical_cast<int>(probLossStr);
  char * probDelayStr = argv[4];
  probDelay = boost::lexical_cast<int>(probDelayStr);
  char* delayTStr = argv[5];
  delayT = boost::lexical_cast<int>(delayTStr);

  struct timeval timeout;
  timeout.tv_usec = TIMEOUT * 1000;
  toms = TIMEOUT;

  /* Create our socket. */
  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    cout << "Socket creation failed. (socket s)" << endl;
    return 0;
  }

  setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

  /*
   * Bind our socket to an IP (whatever the computer decides)
   * and a specified port.
   *
   */

  if (!loadFile()) {
    cout << "Loading file failed. (filename FILENAME)" << endl;
    return false;
  }

  memset((char *)&a, 0, sizeof(a));
  a.sin_family = AF_INET;
  a.sin_addr.s_addr = htonl(INADDR_ANY);
  a.sin_port = htons(PORT);

  if (bind(s, (struct sockaddr *)&a, sizeof(a)) < 0) {
    cout << "Socket binding failed. (socket s, address a)" << endl;
    return 0;
  }

  fstr = string(file);
  cout << "File: " << endl << fstr << endl;

  base = 0;
  dropPck = false;
  calen = sizeof(ca);

  getGet();

  return true;
}

bool getGet(){
	unsigned char packet[PAKSIZE + 1];
	rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);
	return (rlen > 0) ? true : false;
}

bool isvpack(unsigned char * p) {
  cout << endl << "=== IS VALID PACKET TESTING" << endl;

  char * sns = new char[2];
  memcpy(sns, &p[0], 1);
  sns[1] = '\0';

  char * css = new char[7];
  memcpy(css, &p[1], 6);
  css[6] = '\0';

  char * db = new char[121 + 1];
  memcpy(db, &p[2], 121);
  db[121] = '\0';

  cout << "Seq. num: " << sns << endl;
  cout << "Checksum: " << css << endl;
  cout << "Message: " << db << endl;

  int sn = boost::lexical_cast<int>(sns);
  int cs = boost::lexical_cast<int>(css);

  Packet pk (0, db);
  pk.setSequenceNum(sn);

  // change to validate based on checksum and sequence number

  if(sn == 0) return false; //doesn't matter, only for the old version (netwark)
  if(cs != pk.generateCheckSum()) return false;
  return true;
}

bool getFile(){

  /* Loop forever, waiting for messages from a client. */
  cout << "Waiting on port " << PORT << "..." << endl;

  ofstream file("Dumpfile");

  for (;;) {
    unsigned char packet[PAKSIZE + 1];
    unsigned char dataPull[PAKSIZE - 7 + 1];
    rlen = recvfrom(s, packet, PAKSIZE, 0, (struct sockaddr *)&ca, &calen);

    for(int x = 0; x < PAKSIZE - 7; x++) {
      dataPull[x] = packet[x + 7];
    }
    dataPull[PAKSIZE - 7] = '\0';
    packet[PAKSIZE] = '\0';
    if (rlen > 0) {
      char * css = new char[6];
      memcpy(css, &packet[1], 5);
      css[5] = '\0';
      cout << endl << endl << "=== RECEIPT" << endl;
      cout << "Seq. num: " << packet[0] << endl;
      cout << "Checksum: " << css << endl;
      cout << "Received message: " << dataPull << endl;
      cout << "Sent response: ";
      if(isvpack(packet)) {
        ack = ACK;
        //seqNum = (seqNum) ? false : true;
        file << dataPull;
      } else {
        ack = NAK;
      }
      cout << ((ack == ACK) ? "ACK" : "NAK") << endl;
      Packet p (false, reinterpret_cast<const char *>(dataPull));
      p.setCheckSum(boost::lexical_cast<int>(css));
      p.setAckNack(ack);

      if(sendto(s, p.str(), PAKSIZE, 0, (struct sockaddr *)&ca, calen) < 0) {
        cout << "Acknowledgement failed. (socket s, acknowledgement message ack, client address ca, client address length calen)" << endl;
        return 0;
      }
      delete css;
    }
  }
  file.close();
  return true;
}

bool loadFile() {

  ifstream is (FILENAME, ifstream::binary);

  if(is) {
    is.seekg(0, is.end);
    length = is.tellg();
    is.seekg(0, is.beg);

    file = new char[length];

    cout << "Reading " << length << " characters..." << endl;
    is.read(file, length);

    if(!is) { cout << "File reading failed. (filename " << FILENAME << "). Only " << is.gcount() << " could be read."; return false; }
    is.close();
  }
  return true;
}

void loadWindow(){
	for(int i = base; i < base + WIN_SIZE; i++) {
		window[i-base] = createPacket(i);
		if(strlen(window[i-base].getDataBuffer()) < BUFSIZE - 1 && window[i-base].getDataBuffer()[0] != 'G') {
			for(++i; i < base + WIN_SIZE; i++){
				window[i-base].loadDataBuffer("\0");
			}
			return;
		}
	}
}

bool sendFile() {
	/*Currently causes the program to only send the first 16 packets of file out
		requires additional code later to sendFile again with updated window*/
	base = 0;
	while(base * BUFSIZE < length) {
		loadWindow();

		cout << "packet " << base << ": " << window[0].str() << endl;

		for(int x = 0; x < WIN_SIZE; x++) {
			p = window[x];
			if(!sendPacket()) continue;
		}
		if(p.str()[0] == '\0') break;
		for(int x = 0; x < WIN_SIZE; x++) {
			if(recvfrom(s, b, BUFSIZE + 7, 0, (struct sockaddr *)&ca, &calen) < 0) {
				cout << "=== ACK TIMEOUT" << endl;
				x--;
				continue;
			}

			if(isAck()) {
				handleAck();
			} else {
				handleAck();
				//handleNak(x);
			}

			memset(b, 0, BUFSIZE);
		}
	}

	if(sendto(s, "\0", BUFSIZE, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Final package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
	}
	return true;
}

Packet createPacket(int index){
    string mstr = fstr.substr(index * BUFSIZE, BUFSIZE);

	if(mstr.length() < BUFSIZE) {
		cout << "Null terminated mstr." << endl;
		mstr[length - (index * BUFSIZE)] = '\0';
    }

	cout << "index: " << index << endl;
    return Packet (index, mstr.c_str());
}

bool sendPacket(){
	cout << endl;
    cout << "=== TRANSMISSION START" << endl;
	cout << "Sequence number before gremlin function: " << p.getSequenceNum() << endl;
    int pc = probCorrupt; int pl = probLoss; int pd = probDelay;
	bool* pckStatus = gremlin(&p, pc, pl, pd);

	dropPck = pckStatus[0];
	delayPck = pckStatus[1];

	if (dropPck == true) return false;
	if (delayPck == true) p.setAckNack(1);

    if(sendto(s, p.str(), BUFSIZE + 8, 0, (struct sockaddr *)&ca, sizeof(ca)) < 0) {
		cout << "Package sending failed. (socket s, server address sa, message m)" << endl;
		return false;
    }
    return true;
}
bool isAck() {
    cout << endl << "=== SERVER RESPONSE TEST" << endl;
    cout << "Data: " << b << endl;
    if(b[6] == '0') return true;
    else return false;
}
void handleAck() {
	int ack = boost::lexical_cast<int>(b);
	if(base < ack) base = ack;
	cout << "Window base: " << base << endl;
}
void handleNak(int& x) {

      char * sns = new char[2];
      memcpy(sns, &b[0], 1);
      sns[1] = '\0';

      char * css = new char[5];
      memcpy(css, &b[1], 5);

      char * db = new char[BUFSIZE + 1];
      memcpy(db, &b[2], BUFSIZE);
      db[BUFSIZE] = '\0';

      cout << "Sequence number: " << sns << endl;
      cout << "Checksum: " << css << endl;

      Packet pk (0, db);
      pk.setSequenceNum(boost::lexical_cast<int>(sns));
      pk.setCheckSum(boost::lexical_cast<int>(css));

      if(!pk.chksm()) x--;
      else x = (x - 2 > 0) ? x - 2 : 0;
}
bool* gremlin(Packet * pack, int corruptProb, int lossProb, int delayProb){

  bool* packStatus = new bool[2];
  int r = rand() % 100;

  cout << "Corruption probability: " << corruptProb << endl;
  cout << "Random number: " << r << endl;

  packStatus[0] = false;
  packStatus[1] = false;

  if(r <= (lossProb)){
	packStatus[0] = true;
    cout << "Dropped!" << endl;
  }
  else if(r <= (delayProb)){
	  packStatus[1] = true;
	  cout << "Delayed!" << endl;
  }
  else if(r <= (corruptProb)){
    cout << "Corrupted!" << endl;
	cout << "Seq. num (pre-gremlin): " << pack->getSequenceNum() << endl;
    pack->loadDataBuffer((char*)"GREMLIN LOL");
  }
  cout << "Seq. num: " << pack->getSequenceNum() << endl;
  cout << "Checksum: " << pack->getCheckSum() << endl;
  //cout << "Message: "  << pack->getDataBuffer() << endl;

  return packStatus;
}<|endoftext|>