C++ (Qt)struct BasePacket { enum { OpCodeOffset = 0, LenOffset = 2, ParamsOffset = 3; } BasePacket (QByteArray &packet): packet(packet) { } quint16 opCode() const { quint16 opcode = 0; // read the opcode field from packet from OpCodeOffset return opcode; } QByteArray packet;}; struct FooPacket : public BasePacket { enum { Foo_OpCode = 0x1234, Foo_PacketSize = xxx }; bool isValid() const { if (packet.size() != Foo_PacketSize) return false; if (packet.at(LenOffset ) != (packet.size() - ParamsOffset)) return false; if (opCode() != Foo_OpCode) return false; return true; }}; struct BarPacket : public BasePacket { enum { Bar_OpCode = 0x5678, Bar_PacketSize = yyy }; bool isValid() const { if (packet.size() != Bar_PacketSize) return false; if (packet.at(LenOffset ) != (packet.size() - ParamsOffset)) return false; if (opCode() != Bar_OpCode) return false; return true; }};
C++ (Qt)class BasePacketHandler{public: virtual bool canHandle(const QByteArray &packet) const = 0;} class FooPacketHandler : public BasePacketHandler{public: bool canHandle(const QByteArray &packet) const { return FooPacket(packet).isValid(); }} class BarPacketHandler : public BasePacketHandler{public: bool canHandle(const QByteArray &packet) const { return BarPacket(packet).isValid(); }}
C++ (Qt)struct BasePacket { enum { OpCodeOffset = 0, LenOffset = 2, ParamsOffset = 3; } BasePacket (QByteArray &packet): packet(packet) { } static quint16 opCode(QByteArray &packet) { quint16 opcode = 0; // read the opcode field from packet from OpCodeOffset return opcode; } QByteArray packet;}; struct FooPacket : public BasePacket { enum { Foo_OpCode = 0x1234, Foo_PacketSize = xxx }; static bool isValid(QByteArray &packet) { if (packet.size() != Foo_PacketSize) return false; if (packet.at(LenOffset ) != (packet.size() - ParamsOffset)) return false; if (opCode(packet) != Foo_OpCode) return false; return true; }}; struct BarPacket : public BasePacket { enum { Bar_OpCode = 0x5678, Bar_PacketSize = yyy }; static bool isValid(QByteArray &packet) { if (packet.size() != Bar_PacketSize) return false; if (packet.at(LenOffset ) != (packet.size() - ParamsOffset)) return false; if (opCode(packet) != Bar_OpCode) return false; return true; }};
C++ (Qt)class BasePacketHandler{public: virtual bool canHandle(const QByteArray &packet) const = 0;}; class FooPacketHandler : public BasePacketHandler{public: bool canHandle(const QByteArray &packet) const { return FooPacket::isValid(packet); }}; class BarPacketHandler : public BasePacketHandler{public: bool canHandle(const QByteArray &packet) const { return BarPacket::isValid(packet); }};
C++ (Qt)template <qint32 packID, qint32 packSize>struct CPacket { CPacket( QByteArray & ba ) : mError(false), mBA(ba) { int id = 0, size = 0; QDataStream ds(ba); ds >> id >> size; mError = (id != packID) || (size != packSize) || (mBA.size() - sizeof(qint32) * 2 != packSize); } bool mError; QByteArray & mBA; }; int main(int argc, char *argv[]) { typedef CPacket <'PAC1', 32> MyPacket; QByteArray ba; MyPacket p(ba); if (!p.mError) return 1; return 0;}
C++ (Qt)template <qint32 packID, qint32 packSize>struct CPacket : public BasePacket {...// BasePacket virtuals virtual int OpCode( void ) const { return packID; } virtual int DataSize( void ) const { return packSize; } ...};
C++ (Qt)typedef std::map <int, BasePacket *> TPacketMap;TPacketMap mPacketMap; void Add2Factory( BasePacket * p ){ mPacketMap[p->OpCode()] = p;} Add2Factory(new CPacket <'PAC1', 32> ());Add2Factory(new CPacket <'PAC2', 15> ());Add2Factory(new CPacket <'PAC3', 20> ());...
C++ (Qt)BasePacket * Lookup( int opCode ){ TPacketMap::iterator it = mPacketMap.find(opCode); return (it == mPacketMap.end()) ? 0 : it->second;}
C++ (Qt) QByteArray data1; // приняли пакет FooPacket FooPacket foo(data1);QString name = foo.name(); QByteArray data2; // приняли пакет BarPacket BarPacket bar(data2);quint8 type = bar.type();Address address = bar.address();
C++ (Qt) class BasePacketHandler{public: virtual bool canHandle(const QByteArray &packet) const = 0;}; class FooPacketHandler : public BasePacketHandler{public: bool canHandle(const QByteArray &packet) const { // как тут правильнее парсить? return true/false; }}; class BarPacketHandler : public BasePacketHandler{public: bool canHandle(const QByteArray &packet) const { // как тут правильнее парсить? return true/false; }}; QList<BasePacketHandler *> handlers = QList<BasePacketHandler *>() << new FooPacketHandler << new BarPacketHandler; void Manager::handleIncomingPacket(const QByteArray &packet){ foreach (BasePacketHandler *handler, handlers) { if (handler->canHandle(packet) { // do something } }}
C++ (Qt)class BasePacketHandler{public: virtual bool canHandle(const QByteArray &packet) const = 0;}; class FooPacketHandler : public BasePacketHandler{public: bool canHandle(const QByteArray &packet) const { // как тут правильнее парсить? return true/false; }};
C++ (Qt)class BasePacketHandler{public: virtual bool canHandle(const QByteArray &packet) const { return (packet.size() >= 3) && (*(unsigned short *) &packet[0] == OpCode()); }};
C++ (Qt)QByteArray data1; // приняли пакет FooPacket FooPacket foo(data1);QString name = foo.name(); QByteArray data2; // приняли пакет BarPacket BarPacket bar(data2);quint8 type = bar.type();Address address = bar.address();
C++ (Qt)const ResetCmd cmd;Reply *reply = manager->exec(cmd);connect(reply, SIGNAL(finished(), this, SLOT(onResetComplete())); Foo::onResetComplete(){ Reply *reply = qobject_cast<Reply *>(sender()); QByteArray req = reply->request(); // RAW команда которая была послана QByteArray resp = reply->response(); // RAW евент (ответ), который был получен на команду // естественно, что этот слот - это уже готовый (обработанный результат), который обрабатывает Manager. // и в этом Manager вся логика и обработчики // но теперь я хочу получить параметры ответа resp. сразу и без проблем, т.к. я точно знаю его тип ResetCompleteEvent ev(resp); quint status = ev.status(); QString name = ev.name(); // далее могу обработать status (или иные параметры) как мне надо if (status == xxx) { // команда успешна } else if (status == yyy) { // команда сфейлилась } else ... emit deviceDiscovered(name); // и прочее }
C++ (Qt)class HciReplyHandler{public: virtual bool canHandleRequest(const QByteArray &request) const = 0; virtual bool canHandleResponse(const QByteArray &response) const = 0;};
C++ (Qt)HciReply *HciAccessManager::execute(const QByteArray &request){ foreach (HciReplyHandler *handler, m_handlers) { // перебираем зарегистрированные обработчики Q_ASSERT(handler); if (!handler->canHandleRequest(request)) // проверяем - а чей, собственно запрос? continue; HciReply *reply = new HciReply(handler->replyType(), this); if (reply->type() == HciReply::Pending) { reply->setRequest(request); m_pendingReplies.insert(reply, handler); // засовываем Reply и его обработчик в хеш m_transport->writeCommandPacket(request); } return reply; } return 0;}
C++ (Qt)void HciAccessManager::response(const QByteArray &packet){ foreach (HciReplyHandler *handler, m_handlers) { // перебираем обработчики и ищем подходяший Q_ASSERT(handler); if (!handler->canHandleResponse(packet)) // а чей, собственно ответ? continue; // ищем Reply по обработчику (тут, конечно, косячно все т.к. к одному обработчику могут принадлежать несколько Reply) // но в данном случае - пофик, т.к. оно найдет первый попавшийся и нам этого достаточно, т.к. без разницы :) HciReply *reply = m_pendingReplies.key(handler); Q_ASSERT(reply); reply->setResponse(packet); if (handler->replyType() == HciReply::Pending) m_pendingReplies.take(reply); finalizeEventReply(reply); return; }}
C++ (Qt)HciResetCommand::HciResetCommand() : HciCommand(HciCommand::ControllerBasebandGroup, HciCommand::ResetCode){ packet.resize(packet.size() + TotalParametersLength); setTotalParametersLength(TotalParametersLength);} HciResetCommand::HciResetCommand(const QByteArray &packet) : HciCommand(packet){} bool HciResetCommand::isValid() const{ return isComplete() && (opCode() == HciCommand::opCode(HciCommand::ControllerBasebandGroup, HciCommand::ResetCode));} HciResetCommandCompleteEvent::HciResetCommandCompleteEvent(const QByteArray &packet) : HciCommandCompleteEvent(packet){} quint8 HciResetCommandCompleteEvent::status() const{ return packet.at(parametersOffset() + ReturnParametersOffset + StatusOffset);} bool HciResetCommandCompleteEvent::isValid() const{ return isComplete() && (packet.size() == TotalPackeSize) && (opCode() == HciCommand::opCode(HciCommand::ControllerBasebandGroup, HciCommand::ResetCode));} bool HciResetReplyHandler::canHandleRequest(const QByteArray &request) const{ return HciResetCommand(request).isValid();} bool HciResetReplyHandler::canHandleResponse(const QByteArray &response) const{ return HciResetCommandCompleteEvent(response).isValid();}
#pragma pack(push, 1)struct MyStruct{ // ...};#pragma pack(pop)