# shxbee.cpp

Go to the documentation of this file.

    00001 /*
    00002  * SmartHome server: Plug-in xbee
    00003  *
    00004  * Copyright (C) 2010 Daniel Pisi <dan.pisi@gmail.com>
    00005  *
    00006  * This program is free software; you can redistribute it and/or modify it
    00007  * under the terms of version 2 of the GNU General Public License
    00008  * as published by the Free Software Foundation.
    00009  *
    00010  */
    00011
    00018 #include "shxbee.h"
    00019 #include "xbpackets.h"
    00020
    00021 #include <QRegExp>
    00022
    00023 // -----------------------------------------------------------------------------
    00024
    00025 XbModuleData::XbModuleData()
    00026 {
    00027     lastDigitalSample = 0;
    00028     inputs = outputs = 0;
    00029 }
    00030 // -----------------------------------------------------------------------------
    00031
    00032 ShXbee::ShXbee(QObject *parent) : ShObjectHelper(parent)
    00033 {
    00034 }
    00035 // -----------------------------------------------------------------------------
    00036
    00037 bool ShXbee::init(QString param)
    00038 {
    00039     mLastFrameId = 1;
    00040
    00041     mInterface = new XbInterface(param);
    00042
    00043     connect(mInterface, SIGNAL(newPacketReceived(QByteArray)),
    00044             this, SLOT(processPacket(QByteArray)));
    00045
    00046     qDebug("XBee initialized");
    00047     return true;
    00048 }
    00049 // -----------------------------------------------------------------------------
    00050
    00051 void ShXbee::updatePins(const QList<ShPin> &pins)
    00052 {
    00053     const char *cfgCmd[13] = {"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
    00054                               "",   "",   "P0", "P1", "P2"};
    00055     QRegExp rx("0X([0-9A-F]{16}):([0-9A-F])");
    00056
    00057     QMap<quint64,XbModuleData> newModules;
    00058
    00059     quint64 addr;
    00060     quint8  io;
    00061
    00062     // Create newModules list
    00063     foreach (ShPin pin, pins)
    00064     {
    00065         if (rx.exactMatch(pin.signal().toUpper()))
    00066         {
    00067             addr = rx.cap(1).toULongLong(0, 16);
    00068             io   = rx.cap(2).toULongLong(0, 16);
    00069
    00070             if (pin.isInput())  newModules[addr].inputs  |= (1 << io);
    00071             if (pin.isOutput()) newModules[addr].outputs |= (1 << io);
    00072         }
    00073     }
    00074
    00075     // Update individual pins settings
    00076     XbRemoteCommand packet;
    00077     packet.setFrameId(0);
    00078     packet.setOptions(0x02);
    00079
    00080     quint16 newInputs, newOutputs, msk;
    00081     QMapIterator<quint64,XbModuleData> newModI(newModules);
    00082
    00083     while (newModI.hasNext())
    00084     {
    00085         newModI.next();
    00086         addr = newModI.key();
    00087
    00088         newInputs  = newModI.value().inputs  & ~mModules[addr].inputs;
    00089         newOutputs = newModI.value().outputs & ~mModules[addr].outputs;
    00090
    00091         for (int i = 0; i < 16; i++)
    00092         {
    00093             msk = 1 << i;
    00094             if (newInputs & msk || newOutputs & msk)
    00095             {
    00096                 packet.setAddr64(addr);
    00097                 packet.setCommand(cfgCmd[i], newInputs & msk ? 3 : 4);
    00098                 mInterface->sendPacket(packet);
    00099             }
    00100         }
    00101         newModules[addr].lastDigitalSample = mModules[addr].lastDigitalSample;
    00102     }
    00103
    00104     mModules = newModules;
    00105
    00106     // Update configuration and query input values
    00107     XbRemoteCommand prCmd, icCmd, isCmd;
    00108
    00109     foreach (addr, mModules.keys())
    00110     {
    00111         prCmd.setFrameId(0);
    00112         prCmd.setAddr64(addr);
    00113         prCmd.setOptions(0x02);
    00114         prCmd.setCommand("PR", new XbUint16Block(0x1FFF));
    00115         mInterface->sendPacket(prCmd);
    00116
    00117         icCmd.setFrameId(0);
    00118         icCmd.setAddr64(addr);
    00119         icCmd.setOptions(0x02);
    00120         icCmd.setCommand("IC", new XbUint16Block(0x1FFF));
    00121         mInterface->sendPacket(icCmd);
    00122
    00123         isCmd.setFrameId(nextFrameId());
    00124         isCmd.setAddr64(addr);
    00125         isCmd.setOptions(0x02);
    00126         isCmd.setCommand("IS");
    00127         mInterface->sendPacket(isCmd);
    00128     }
    00129 }
    00130 // -----------------------------------------------------------------------------
    00131
    00132 quint8 ShXbee::nextFrameId()
    00133 {
    00134     mLastFrameId = (mLastFrameId == 255) ? 1 : mLastFrameId+1;
    00135     return mLastFrameId;
    00136 }
    00137 // -----------------------------------------------------------------------------
    00138
    00139 void ShXbee::processMessage(ShMessagePtr message)
    00140 {
    00141     const char *cfgCmd[13] = {"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
    00142                               "",   "",   "P0", "P1", "P2"};
    00143
    00144     qDebug(QString("Xbee: Processing message from object %1, signal = %2").arg(message->senderId()).arg(message->signal()).toLatin1());
    00145
    00146     QRegExp rx1("0X([0-9A-F]{16}):([0-9A-F])");
    00147     QRegExp rx2("0X([0-9A-F]{16})");
    00148
    00149     if (message->msgType() == ShMessage::mtValue)
    00150     {
    00151         if (rx1.exactMatch(message->signal().toUpper()))
    00152         {
    00153             XbRemoteCommand *packet = new XbRemoteCommand;
    00154
    00155             packet->setFrameId(nextFrameId());
    00156             packet->setAddr64(rx1.cap(1).toULongLong(0, 16));
    00157             packet->setOptions(0x02);
    00158             packet->setCommand(QByteArray(cfgCmd[rx1.cap(2).toInt(0,16)]), message->value().toBool() ? 4 : 5);
    00159
    00160             sendPacket(packet->frameId(), message, packet);
    00161             qDebug(QString("Value of %1 set to %2").arg(message->signal(), message->value().toString()).toLatin1());
    00162         }
    00163         else if (rx2.exactMatch(message->signal().toUpper()))
    00164         {
    00165             XbTransmitRequest *packet = new XbTransmitRequest;
    00166
    00167             packet->setFrameId(nextFrameId());
    00168             packet->setAddr64(rx2.cap(1).toULongLong(0, 16));
    00169             packet->setRfData(message->value().toByteArray());
    00170             sendPacket(packet->frameId(), message, packet);
    00171         }
    00172     }
    00173     else if (message->msgType() == ShMessage::mtGet)
    00174     {
    00175         if (rx1.exactMatch(message->signal().toUpper()))
    00176         {
    00177             XbRemoteCommand *packet = new XbRemoteCommand;
    00178
    00179             packet->setFrameId(nextFrameId());
    00180             packet->setAddr64(rx1.cap(1).toULongLong(0, 16));
    00181             packet->setOptions(0x02);
    00182             packet->setCommand("IS");
    00183             sendPacket(packet->frameId(), message, packet);
    00184         }
    00185         else if (rx2.exactMatch(message->signal().toUpper()))
    00186         {
    00187             XbTransmitRequest *packet = new XbTransmitRequest;
    00188
    00189             packet->setFrameId(nextFrameId());
    00190             packet->setAddr64(rx2.cap(1).toULongLong(0, 16));
    00191             packet->setRfData("get");
    00192             sendPacket(packet->frameId(), message, packet);
    00193         }
    00194     }
    00195 }
    00196 // -----------------------------------------------------------------------------
    00197
    00198 bool ShXbee::sendPacket(int id, ShMessagePtr message, XbPacket *packet)
    00199 {
    00200     if (mMsgPool.contains(id))
    00201         return false;
    00202
    00203     mMsgPool[id] = XbMessagePtr(new XbMessage(this));
    00204
    00205     connect(mMsgPool[id].data(), SIGNAL(timeout()), this, SLOT(messageTimeout()));
    00206
    00207     mMsgPool[id]->message = message;
    00208     mMsgPool[id]->packet  = QSharedPointer<XbPacket>(packet);
    00209
    00210     mInterface->sendPacket(*packet);
    00211     mMsgPool[id]->timer->start();
    00212
    00213     return true;
    00214 }
    00215 // -----------------------------------------------------------------------------
    00216
    00217 void ShXbee::messageProcessed(int id)
    00218 {
    00219     if (!mMsgPool.contains(id))
    00220         return;
    00221
    00222     mMsgPool[id]->timer->stop();
    00223
    00224     if (mMsgPool[id]->message->requireAck())
    00225         ackMessage(mMsgPool[id]->message);
    00226
    00227     mMsgPool.remove(id);
    00228 }
    00229 // -----------------------------------------------------------------------------
    00230
    00231 void ShXbee::messageError(int id, QString reason)
    00232 {
    00233     if (!mMsgPool.contains(id))
    00234         return;
    00235
    00236     mMsgPool[id]->timer->stop();
    00237
    00238     errorMessage(mMsgPool[id]->message, reason);
    00239     mMsgPool.remove(id);
    00240 }
    00241 // -----------------------------------------------------------------------------
    00242
    00243 void ShXbee::messageTimeout()
    00244 {
    00245     XbMessage *xbMsg = qobject_cast<XbMessage*>(sender());
    00246     if (xbMsg == NULL) return;
    00247
    00248     errorMessage(xbMsg->message, "timeout");
    00249     mMsgPool.remove(mMsgPool.key(QWeakPointer<XbMessage>(xbMsg)));
    00250 }
    00251 // -----------------------------------------------------------------------------
    00252
    00253 void ShXbee::processPacket(QByteArray data)
    00254 {
    00255     if (!XbPacket::valid(data))
    00256         return;
    00257
    00258     qDebug("Processing packet " + data.toHex());
    00259
    00260     switch ((quint8)data.at(3))
    00261     {
    00262         case 0x8B:
    00263         {
    00264             XbTransmitStatus packet;
    00265             if (packet.parseFrameData(data))
    00266             {
    00267                 if ((packet.deliveryStatus() == 0x00) ||
    00268                     (packet.deliveryStatus() == 0x23))
    00269                 {
    00270                     messageProcessed(packet.frameId());
    00271                 }
    00272                 else
    00273                     messageError(packet.frameId(), packet.deliveryStatusString());
    00274             }
    00275             else
    00276                 qWarning("Parsing of the transmit status packet failed.");
    00277         }
    00278         break;
    00279
    00280         case 0x90:
    00281         {
    00282             XbReceivedData packet;
    00283             if (packet.parseFrameData(data))
    00284             {
    00285                 QString signal = "0x" + QString("%1").arg(packet.addr64(), 16, 16, QLatin1Char('0')).toUpper();
    00286                 outputUpdated(signal, packet.rfData());
    00287             }
    00288             else
    00289                 qWarning("Parsing of the received data packet failed.");
    00290         }
    00291         break;
    00292
    00293         case 0x92:
    00294         {
    00295             XbIoSample packet;
    00296             if (packet.parseFrameData(data))
    00297             {
    00298                 quint16 sample = packet.ioSamples()->digitalSample();
    00299                 quint16 mask = packet.ioSamples()->digitalMask();
    00300
    00301                 qDebug(QString("new digital sample = %1, mask = %2").arg(sample, 4, 16, QChar('0')).arg(mask, 4, 16, QChar('0')).toLatin1());
    00302
    00303                 if (sample != mModules[packet.addr64()].lastDigitalSample)
    00304                 {
    00305                     bool input, input0;
    00306                     QString signal = "0x" + QString("%1:%2").arg(packet.addr64(), 16, 16, QLatin1Char('0')).toUpper();
    00307                     for (int i = 0; i < 13; i++)
    00308                     {
    00309                         input  = sample & (1 << i);
    00310                         input0 = mModules[packet.addr64()].lastDigitalSample & (1 << i);
    00311
    00312                         if (input != input0)
    00313                             outputUpdated(signal.arg(i), input ? 0 : 1);
    00314                     }
    00315                     mModules[packet.addr64()].lastDigitalSample = sample;
    00316                 }
    00317             }
    00318             else
    00319                 qWarning("Parsing of the received I/O sample packet failed.");
    00320         }
    00321         break;
    00322
    00323         case 0x97:
    00324         {
    00325             XbRemoteCommandResponse packet;
    00326
    00327             packet.parseFrameData(data);
    00328
    00329             if (packet.command() == "IS")
    00330             {
    00331                 mModules[packet.addr64()].lastDigitalSample = ((XbIoSamplesBlock*)(packet.cmdParam()))->digitalSample();
    00332                 qDebug(QString("digital = %1").arg(mModules[packet.addr64()].lastDigitalSample,4,16).toLatin1());
    00333             }
    00334
    00335             messageProcessed(packet.frameId());
    00336         }
    00337         break;
    00338     }
    00339 }
    00340
    00341 // -----------------------------------------------------------------------------
    00342
    00343 Q_EXPORT_PLUGIN2(xbee, ShXbee);

All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends