#ifndef SAPROTOCOL_H #define SAPROTOCOL_H #include #include class SAProtocol { Q_GADGET Q_ENUMS(Role FrameType ControlFrameType) public: static const QBluetoothUuid dataServiceUuid; static const QBluetoothUuid nudgeServiceUuid; enum Role { ClientRole, ServerRole }; static const quint8 currentProtocolVersion = 0; static const quint16 defaultSessionId = 0x3FF; static const quint16 maxSessionId = 0x3FF; static quint16 computeCrc16(const QByteArray &buf); static const char peerDescriptionSeparator = ';'; /** One of the early connection setup messages. Seems to describe each * other's capabilities and network settings to the remote peer. */ struct PeerDescription { /** No idea: either 5 or 6. Wild guess: 5 is request, 6 is response. */ quint8 messageType; quint16 accessoryProtocolVersion; quint16 accessorySoftwareVersion; /** Status code. 0 generally means "no error". */ quint8 status; quint8 errorCode; /**< Used when status != 0 and messageType == 6 */ /* Seemingly network parameters, but I am not sure how the other end * actually handles them. Seem to do nothing. */ quint32 APDUSize; quint16 SSDUSize; quint16 sessions; /**< Seemingly maximum number of sessions allowed. */ quint16 timeout; /**< Looks like a timeout, but no idea what for. */ /* No idea. */ quint8 unk_1; quint16 unk_2; quint8 unk_3; /* No one cares about the ones below. Seemingly free-form text. */ QString product; QString manufacturer; QString name; QString profile; }; static PeerDescription unpackPeerDescription(const QByteArray &data); static QByteArray packPeerDescription(const PeerDescription &desc); enum SecurityFrameType { SecurityAuthenticateRequest = 0x10, SecurityAuthenticateResponse = 0x11, SecurityAuthenticateConfirm = 0x12 }; struct SecurityFrame { SecurityFrameType type; quint8 authType; // ??? quint8 version; // Always 0 so far. quint8 dataType; // ??? QByteArray data; }; static SecurityFrame unpackSecurityFrame(const QByteArray &data); static QByteArray packSecurityFrame(const SecurityFrame &sframe); enum FrameType { FrameData = 0, FrameControl = 1 }; struct Frame { quint8 protocolVersion; // Always 0 so far. FrameType type; quint16 sessionId; QByteArray data; }; static Frame unpackFrame(const QByteArray &data); static QByteArray packFrame(const Frame& frame); static QByteArray packFrame(quint16 sessionId, const QByteArray &data, FrameType type = FrameData); enum FragmentStatus { FragmentNone = 0, FragmentMiddle = 1, FragmentLast = 3 }; struct DataFrame { bool withSeqNum; // (not actually present in frame) // The following field is only present if "withSeqNum": quint16 seqNum; // Monotonically increasing bool withFragStatus; // (not actually present in frame) FragmentStatus fragStatus; QByteArray data; }; static DataFrame unpackDataFrame(const QByteArray &data, bool withSeqNum, bool withFragStatus); static QByteArray packDataFrame(const DataFrame& frame); enum ControlFrameType { ControlFrameImmediateAck = 0, ControlFrameBlockAck = 1, ControlFrameNak = 2 }; typedef QPair SeqNumRange; struct ControlFrame { ControlFrameType type; QList seqNums; // Used for Naks only quint16 seqNum; }; static ControlFrame unpackControlFrame(const QByteArray &data); static QByteArray packControlFrame(const ControlFrame& frame); /* Default session messages */ enum DefaultSessionMessageType { ServiceConnectionRequest = 1, ServiceConnectionResponse = 2, ServiceTerminationRequest = 3, ServiceTerminationResponse = 4 }; /** The following settings map 1:1 to contents in service.xml files (thank god). * That does not mean I understand what they do, specially the QoS part. */ struct ServiceConnectionRequestSession { quint16 sessionId; quint16 channelId; quint8 qosType; quint8 qosDataRate; quint8 qosPriority; quint8 payloadType; }; struct ServiceConnectionRequestFrame { quint8 messageType; quint16 acceptorId; quint16 initiatorId; QString profile; QList sessions; }; static ServiceConnectionRequestFrame unpackServiceConnectionRequestFrame(const QByteArray &data); static QByteArray packServiceConnectionRequestFrame(const ServiceConnectionRequestFrame &frame); struct ServiceConnectionResponseFrame { quint8 messageType; quint16 acceptorId; quint16 initiatorId; QString profile; quint8 statusCode; QList sessions; }; static ServiceConnectionResponseFrame unpackServiceConnectionResponseFrame(const QByteArray &data); static QByteArray packServiceConnectionResponseFrame(const ServiceConnectionResponseFrame &frame); struct ServiceTerminationRequestFrame { quint8 messageType; quint16 acceptorId; quint16 initiatorId; QString profile; }; static ServiceTerminationRequestFrame unpackServiceTerminationRequestFrame(const QByteArray &data); static QByteArray packServiceTerminationRequestFrame(const ServiceTerminationRequestFrame &frame); struct ServiceTerminationResponseFrame { quint8 messageType; quint16 acceptorId; quint16 initiatorId; QString profile; quint8 statusCode; }; static ServiceTerminationResponseFrame unpackServiceTerminationResponseFrame(const QByteArray &data); static QByteArray packServiceTerminationResponseFrame(const ServiceTerminationResponseFrame &frame); /* Capability discovery messages */ static const QLatin1String capabilityDiscoveryProfile; static const quint16 capabilityDiscoveryChannel = 255; static const quint16 capabilityDiscoveryAgentId = 0xFFFF; enum CapabilityDiscoveryMessageType { CapabilityDiscoveryMessageTypeQuery = 1, CapabilityDiscoveryMessageTypeResponse = 2 }; struct CapabilityDiscoveryQuery { CapabilityDiscoveryMessageType messageType; quint8 queryType; quint32 checksum; QList records; }; static CapabilityDiscoveryQuery unpackCapabilityDiscoveryQuery(const QByteArray &data); static QByteArray packCapabilityDiscoveryQuery(const CapabilityDiscoveryQuery &msg); struct CapabilityDiscoveryService { quint16 componentId; quint16 aspVersion; quint8 role; quint16 connTimeout; QString profile; }; struct CapabilityDiscoveryProvider { quint16 uuid; QString name; QList services; }; struct CapabilityDiscoveryResponse { CapabilityDiscoveryMessageType messageType; quint8 queryType; quint32 checksum; QList providers; }; static CapabilityDiscoveryResponse unpackCapabilityDiscoveryResponse(const QByteArray &data); static QByteArray packCapabilityDiscoveryResponse(const CapabilityDiscoveryResponse &msg); private: Q_DISABLE_COPY(SAProtocol) SAProtocol(); }; #endif // SAPROTOCOL_H