976 lines
26 KiB
C++
976 lines
26 KiB
C++
|
|
#include "COM/Com_Protocol.h"
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
|
||
|
|
constexpr quint8 kProtoWireVarint = 0;
|
||
|
|
constexpr quint8 kProtoWireFixed64 = 1;
|
||
|
|
constexpr quint8 kProtoWireBytes = 2;
|
||
|
|
constexpr quint8 kProtoWireFixed32 = 5;
|
||
|
|
|
||
|
|
constexpr quint32 kFieldHelloReq = 1;
|
||
|
|
constexpr quint32 kFieldHelloRsp = 2;
|
||
|
|
constexpr quint32 kFieldBitmap = 3;
|
||
|
|
constexpr quint32 kFieldFunctionKeyEvent = 4;
|
||
|
|
constexpr quint32 kFieldLedState = 5;
|
||
|
|
constexpr quint32 kFieldTimeSync = 6;
|
||
|
|
constexpr quint32 kFieldThemeRgb = 7;
|
||
|
|
constexpr quint32 kFieldAck = 8;
|
||
|
|
constexpr quint32 kFieldError = 9;
|
||
|
|
|
||
|
|
constexpr quint16 kUsageModifierFirst = 0x00E0;
|
||
|
|
constexpr quint16 kUsageModifierLast = 0x00E7;
|
||
|
|
constexpr quint16 kUsageNormalLast = 0x00DF;
|
||
|
|
constexpr int kUsageBitmapSize = 29;
|
||
|
|
|
||
|
|
bool Com_Protocol_ReadVarint(const QByteArray& Bytes, int* p_Offset, quint64* p_Value)
|
||
|
|
{
|
||
|
|
quint64 Value = 0;
|
||
|
|
int Shift = 0;
|
||
|
|
int Offset = *p_Offset;
|
||
|
|
|
||
|
|
while (Offset < Bytes.size())
|
||
|
|
{
|
||
|
|
const quint8 Byte = static_cast<quint8>(Bytes.at(Offset++));
|
||
|
|
Value |= static_cast<quint64>(Byte & 0x7FU) << Shift;
|
||
|
|
if ((Byte & 0x80U) == 0U)
|
||
|
|
{
|
||
|
|
*p_Offset = Offset;
|
||
|
|
*p_Value = Value;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
Shift += 7;
|
||
|
|
if (Shift >= 64)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_ReadKey(
|
||
|
|
const QByteArray& Bytes,
|
||
|
|
int* p_Offset,
|
||
|
|
quint32* p_FieldNumber,
|
||
|
|
quint8* p_WireType)
|
||
|
|
{
|
||
|
|
quint64 Key = 0;
|
||
|
|
if (!Com_Protocol_ReadVarint(Bytes, p_Offset, &Key))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*p_FieldNumber = static_cast<quint32>(Key >> 3);
|
||
|
|
*p_WireType = static_cast<quint8>(Key & 0x07U);
|
||
|
|
return *p_FieldNumber > 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_ReadLengthDelimited(
|
||
|
|
const QByteArray& Bytes,
|
||
|
|
int* p_Offset,
|
||
|
|
QByteArray* p_Value)
|
||
|
|
{
|
||
|
|
quint64 Length = 0;
|
||
|
|
if (!Com_Protocol_ReadVarint(Bytes, p_Offset, &Length))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((Length > static_cast<quint64>(Bytes.size())) ||
|
||
|
|
(*p_Offset > Bytes.size() - static_cast<int>(Length)))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*p_Value = Bytes.mid(*p_Offset, static_cast<int>(Length));
|
||
|
|
*p_Offset += static_cast<int>(Length);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_ReadFixed32(const QByteArray& Bytes, int* p_Offset, quint32* p_Value)
|
||
|
|
{
|
||
|
|
if (*p_Offset > Bytes.size() - 4)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
quint32 Value = 0;
|
||
|
|
for (int Index = 0; Index < 4; ++Index)
|
||
|
|
{
|
||
|
|
Value |= static_cast<quint32>(
|
||
|
|
static_cast<quint8>(Bytes.at(*p_Offset + Index))) << (Index * 8);
|
||
|
|
}
|
||
|
|
|
||
|
|
*p_Offset += 4;
|
||
|
|
*p_Value = Value;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_ReadFixed64(const QByteArray& Bytes, int* p_Offset, quint64* p_Value)
|
||
|
|
{
|
||
|
|
if (*p_Offset > Bytes.size() - 8)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
quint64 Value = 0;
|
||
|
|
for (int Index = 0; Index < 8; ++Index)
|
||
|
|
{
|
||
|
|
Value |= static_cast<quint64>(
|
||
|
|
static_cast<quint8>(Bytes.at(*p_Offset + Index))) << (Index * 8);
|
||
|
|
}
|
||
|
|
|
||
|
|
*p_Offset += 8;
|
||
|
|
*p_Value = Value;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_SkipField(const QByteArray& Bytes, int* p_Offset, quint8 WireType)
|
||
|
|
{
|
||
|
|
switch (WireType)
|
||
|
|
{
|
||
|
|
case kProtoWireVarint:
|
||
|
|
{
|
||
|
|
quint64 Dummy = 0;
|
||
|
|
return Com_Protocol_ReadVarint(Bytes, p_Offset, &Dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
case kProtoWireFixed64:
|
||
|
|
if (*p_Offset > Bytes.size() - 8)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
*p_Offset += 8;
|
||
|
|
return true;
|
||
|
|
|
||
|
|
case kProtoWireBytes:
|
||
|
|
{
|
||
|
|
QByteArray Dummy;
|
||
|
|
return Com_Protocol_ReadLengthDelimited(Bytes, p_Offset, &Dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
case kProtoWireFixed32:
|
||
|
|
if (*p_Offset > Bytes.size() - 4)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
*p_Offset += 4;
|
||
|
|
return true;
|
||
|
|
|
||
|
|
default:
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Com_Protocol_AppendVarint(QByteArray* p_Bytes, quint64 Value)
|
||
|
|
{
|
||
|
|
do
|
||
|
|
{
|
||
|
|
quint8 Byte = static_cast<quint8>(Value & 0x7FU);
|
||
|
|
Value >>= 7;
|
||
|
|
if (Value != 0)
|
||
|
|
{
|
||
|
|
Byte = static_cast<quint8>(Byte | 0x80U);
|
||
|
|
}
|
||
|
|
p_Bytes->append(static_cast<char>(Byte));
|
||
|
|
} while (Value != 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Com_Protocol_AppendKey(QByteArray* p_Bytes, quint32 FieldNumber, quint8 WireType)
|
||
|
|
{
|
||
|
|
Com_Protocol_AppendVarint(
|
||
|
|
p_Bytes,
|
||
|
|
(static_cast<quint64>(FieldNumber) << 3) | static_cast<quint64>(WireType));
|
||
|
|
}
|
||
|
|
|
||
|
|
void Com_Protocol_AppendUInt32Field(QByteArray* p_Bytes, quint32 FieldNumber, quint32 Value)
|
||
|
|
{
|
||
|
|
Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireVarint);
|
||
|
|
Com_Protocol_AppendVarint(p_Bytes, Value);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Com_Protocol_AppendSInt32Field(QByteArray* p_Bytes, quint32 FieldNumber, qint32 Value)
|
||
|
|
{
|
||
|
|
const quint32 ZigZag = static_cast<quint32>(
|
||
|
|
(static_cast<quint32>(Value) << 1) ^ static_cast<quint32>(Value >> 31));
|
||
|
|
Com_Protocol_AppendUInt32Field(p_Bytes, FieldNumber, ZigZag);
|
||
|
|
}
|
||
|
|
|
||
|
|
void Com_Protocol_AppendFixed32Field(QByteArray* p_Bytes, quint32 FieldNumber, quint32 Value)
|
||
|
|
{
|
||
|
|
Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireFixed32);
|
||
|
|
for (int Index = 0; Index < 4; ++Index)
|
||
|
|
{
|
||
|
|
p_Bytes->append(static_cast<char>((Value >> (Index * 8)) & 0xFFU));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Com_Protocol_AppendFixed64Field(QByteArray* p_Bytes, quint32 FieldNumber, quint64 Value)
|
||
|
|
{
|
||
|
|
Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireFixed64);
|
||
|
|
for (int Index = 0; Index < 8; ++Index)
|
||
|
|
{
|
||
|
|
p_Bytes->append(static_cast<char>((Value >> (Index * 8)) & 0xFFU));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void Com_Protocol_AppendBytesField(
|
||
|
|
QByteArray* p_Bytes,
|
||
|
|
quint32 FieldNumber,
|
||
|
|
const QByteArray& Value)
|
||
|
|
{
|
||
|
|
Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireBytes);
|
||
|
|
Com_Protocol_AppendVarint(p_Bytes, static_cast<quint64>(Value.size()));
|
||
|
|
p_Bytes->append(Value);
|
||
|
|
}
|
||
|
|
|
||
|
|
quint32 Com_Protocol_FieldNumberForType(Com_Enum_ProtocolType Type)
|
||
|
|
{
|
||
|
|
switch (Type)
|
||
|
|
{
|
||
|
|
case Com_Enum_ProtocolType_HelloReq: return kFieldHelloReq;
|
||
|
|
case Com_Enum_ProtocolType_HelloRsp: return kFieldHelloRsp;
|
||
|
|
case Com_Enum_ProtocolType_Bitmap: return kFieldBitmap;
|
||
|
|
case Com_Enum_ProtocolType_FunctionKeyEvent: return kFieldFunctionKeyEvent;
|
||
|
|
case Com_Enum_ProtocolType_LedState: return kFieldLedState;
|
||
|
|
case Com_Enum_ProtocolType_TimeSync: return kFieldTimeSync;
|
||
|
|
case Com_Enum_ProtocolType_ThemeRgb: return kFieldThemeRgb;
|
||
|
|
case Com_Enum_ProtocolType_Ack: return kFieldAck;
|
||
|
|
case Com_Enum_ProtocolType_Error: return kFieldError;
|
||
|
|
default:
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Com_Enum_ProtocolType Com_Protocol_TypeForFieldNumber(quint32 FieldNumber)
|
||
|
|
{
|
||
|
|
switch (FieldNumber)
|
||
|
|
{
|
||
|
|
case kFieldHelloReq: return Com_Enum_ProtocolType_HelloReq;
|
||
|
|
case kFieldHelloRsp: return Com_Enum_ProtocolType_HelloRsp;
|
||
|
|
case kFieldBitmap: return Com_Enum_ProtocolType_Bitmap;
|
||
|
|
case kFieldFunctionKeyEvent: return Com_Enum_ProtocolType_FunctionKeyEvent;
|
||
|
|
case kFieldLedState: return Com_Enum_ProtocolType_LedState;
|
||
|
|
case kFieldTimeSync: return Com_Enum_ProtocolType_TimeSync;
|
||
|
|
case kFieldThemeRgb: return Com_Enum_ProtocolType_ThemeRgb;
|
||
|
|
case kFieldAck: return Com_Enum_ProtocolType_Ack;
|
||
|
|
case kFieldError: return Com_Enum_ProtocolType_Error;
|
||
|
|
default:
|
||
|
|
return Com_Enum_ProtocolType_None;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType Type, const QByteArray& MessageBytes)
|
||
|
|
{
|
||
|
|
QByteArray PacketBody;
|
||
|
|
const quint32 FieldNumber = Com_Protocol_FieldNumberForType(Type);
|
||
|
|
if ((FieldNumber == 0) || MessageBytes.isEmpty())
|
||
|
|
{
|
||
|
|
return PacketBody;
|
||
|
|
}
|
||
|
|
|
||
|
|
Com_Protocol_AppendBytesField(&PacketBody, FieldNumber, MessageBytes);
|
||
|
|
return PacketBody;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeEnvelope(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Enum_ProtocolType* p_Type,
|
||
|
|
QByteArray* p_MessageBytes)
|
||
|
|
{
|
||
|
|
int Offset = 0;
|
||
|
|
while (Offset < PacketBody.size())
|
||
|
|
{
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(PacketBody, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
const Com_Enum_ProtocolType Type = Com_Protocol_TypeForFieldNumber(FieldNumber);
|
||
|
|
if (Type == Com_Enum_ProtocolType_None)
|
||
|
|
{
|
||
|
|
if (!Com_Protocol_SkipField(PacketBody, &Offset, WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (WireType != kProtoWireBytes)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if (!Com_Protocol_ReadLengthDelimited(PacketBody, &Offset, &MessageBytes))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*p_Type = Type;
|
||
|
|
*p_MessageBytes = MessageBytes;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeEnvelopeForExpectedType(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Enum_ProtocolType ExpectedType,
|
||
|
|
QByteArray* p_MessageBytes)
|
||
|
|
{
|
||
|
|
Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None;
|
||
|
|
if (!Com_Protocol_DecodeEnvelope(PacketBody, &Type, p_MessageBytes))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Type == ExpectedType;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeHelloRspMessage(
|
||
|
|
const QByteArray& MessageBytes,
|
||
|
|
Com_Struct_ProtocolHelloRsp* p_Message)
|
||
|
|
{
|
||
|
|
*p_Message = Com_Struct_ProtocolHelloRsp();
|
||
|
|
int Offset = 0;
|
||
|
|
while (Offset < MessageBytes.size())
|
||
|
|
{
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
quint64 Value = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (FieldNumber)
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->ProtocolVersion = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 2:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->VendorId = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 3:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->ProductId = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 4:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->FirmwareMajor = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 5:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->FirmwareMinor = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 6:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->CapabilityFlags = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeUsageBitmapMessage(
|
||
|
|
const QByteArray& MessageBytes,
|
||
|
|
QByteArray* p_UsageBitmap)
|
||
|
|
{
|
||
|
|
p_UsageBitmap->clear();
|
||
|
|
|
||
|
|
int Offset = 0;
|
||
|
|
while (Offset < MessageBytes.size())
|
||
|
|
{
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (FieldNumber == 1)
|
||
|
|
{
|
||
|
|
if ((WireType != kProtoWireBytes) ||
|
||
|
|
!Com_Protocol_ReadLengthDelimited(MessageBytes, &Offset, p_UsageBitmap))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_IsUsageBitmapValid(*p_UsageBitmap);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeFunctionKeyEventMessage(
|
||
|
|
const QByteArray& MessageBytes,
|
||
|
|
Com_Struct_ProtocolFunctionKeyEvent* p_Message)
|
||
|
|
{
|
||
|
|
*p_Message = Com_Struct_ProtocolFunctionKeyEvent();
|
||
|
|
|
||
|
|
bool HasBitmap = false;
|
||
|
|
bool HasLegacyUsage = false;
|
||
|
|
bool HasLegacyAction = false;
|
||
|
|
|
||
|
|
int Offset = 0;
|
||
|
|
while (Offset < MessageBytes.size())
|
||
|
|
{
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
quint64 Value = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (FieldNumber)
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
if (WireType == kProtoWireBytes)
|
||
|
|
{
|
||
|
|
if (!Com_Protocol_ReadLengthDelimited(
|
||
|
|
MessageBytes,
|
||
|
|
&Offset,
|
||
|
|
&p_Message->UsageBitmap) ||
|
||
|
|
!Com_Protocol_IsUsageBitmapValid(p_Message->UsageBitmap))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
HasBitmap = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (Value > 0xFFFFU)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
p_Message->Usage = static_cast<quint16>(Value);
|
||
|
|
HasLegacyUsage = true;
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 2:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
p_Message->Action = static_cast<quint32>(Value);
|
||
|
|
HasLegacyAction = true;
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
p_Message->HasUsageAction = HasLegacyUsage && HasLegacyAction;
|
||
|
|
return HasBitmap || p_Message->HasUsageAction;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeLedStateMessage(
|
||
|
|
const QByteArray& MessageBytes,
|
||
|
|
Com_Struct_ProtocolLedState* p_Message)
|
||
|
|
{
|
||
|
|
*p_Message = Com_Struct_ProtocolLedState();
|
||
|
|
int Offset = 0;
|
||
|
|
while (Offset < MessageBytes.size())
|
||
|
|
{
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
quint64 Value = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (FieldNumber == 1)
|
||
|
|
{
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
p_Message->LedMask = static_cast<quint32>(Value);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeAckMessage(
|
||
|
|
const QByteArray& MessageBytes,
|
||
|
|
Com_Struct_ProtocolAck* p_Message)
|
||
|
|
{
|
||
|
|
*p_Message = Com_Struct_ProtocolAck();
|
||
|
|
int Offset = 0;
|
||
|
|
while (Offset < MessageBytes.size())
|
||
|
|
{
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
quint64 Value = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (FieldNumber == 1)
|
||
|
|
{
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
p_Message->AckedType = static_cast<quint32>(Value);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeErrorMessage(
|
||
|
|
const QByteArray& MessageBytes,
|
||
|
|
Com_Struct_ProtocolError* p_Message)
|
||
|
|
{
|
||
|
|
*p_Message = Com_Struct_ProtocolError();
|
||
|
|
int Offset = 0;
|
||
|
|
while (Offset < MessageBytes.size())
|
||
|
|
{
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
quint64 Value = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (FieldNumber)
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->ErrorType = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case 2:
|
||
|
|
if ((WireType != kProtoWireVarint) ||
|
||
|
|
!Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
p_Message->ErrorCode = static_cast<quint32>(Value);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_GetBitmapPosition(quint16 Usage, int* p_ByteIndex, quint8* p_BitMask)
|
||
|
|
{
|
||
|
|
if ((p_ByteIndex == nullptr) || (p_BitMask == nullptr))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((Usage >= kUsageModifierFirst) && (Usage <= kUsageModifierLast))
|
||
|
|
{
|
||
|
|
*p_ByteIndex = 0;
|
||
|
|
*p_BitMask = static_cast<quint8>(1U << (Usage - kUsageModifierFirst));
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (Usage <= kUsageNormalLast)
|
||
|
|
{
|
||
|
|
*p_ByteIndex = 1 + static_cast<int>(Usage / 8U);
|
||
|
|
*p_BitMask = static_cast<quint8>(1U << (Usage % 8U));
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeMessageType(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Enum_ProtocolType* p_Type)
|
||
|
|
{
|
||
|
|
if (p_Type == nullptr)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
return Com_Protocol_DecodeEnvelope(PacketBody, p_Type, &MessageBytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_TryTakePacket(
|
||
|
|
QByteArray* p_StreamBuffer,
|
||
|
|
QByteArray* p_PacketBody,
|
||
|
|
Com_Enum_ProtocolType* p_Type)
|
||
|
|
{
|
||
|
|
if ((p_StreamBuffer == nullptr) ||
|
||
|
|
(p_PacketBody == nullptr) ||
|
||
|
|
(p_Type == nullptr))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
p_PacketBody->clear();
|
||
|
|
*p_Type = Com_Enum_ProtocolType_None;
|
||
|
|
if (p_StreamBuffer->isEmpty())
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
int Offset = 0;
|
||
|
|
quint32 FieldNumber = 0;
|
||
|
|
quint8 WireType = 0;
|
||
|
|
if (!Com_Protocol_ReadKey(*p_StreamBuffer, &Offset, &FieldNumber, &WireType))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
const Com_Enum_ProtocolType Type = Com_Protocol_TypeForFieldNumber(FieldNumber);
|
||
|
|
if ((Type == Com_Enum_ProtocolType_None) || (WireType != kProtoWireBytes))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if (!Com_Protocol_ReadLengthDelimited(*p_StreamBuffer, &Offset, &MessageBytes))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
*p_PacketBody = p_StreamBuffer->left(Offset);
|
||
|
|
*p_Type = Type;
|
||
|
|
p_StreamBuffer->remove(0, Offset);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray Com_Protocol_EncodeHelloReq()
|
||
|
|
{
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
Com_Protocol_AppendUInt32Field(&MessageBytes, 1, 1);
|
||
|
|
return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_HelloReq, MessageBytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray Com_Protocol_EncodeBitmap(const QByteArray& UsageBitmap)
|
||
|
|
{
|
||
|
|
if (!Com_Protocol_IsUsageBitmapValid(UsageBitmap))
|
||
|
|
{
|
||
|
|
return QByteArray();
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
Com_Protocol_AppendBytesField(&MessageBytes, 1, UsageBitmap);
|
||
|
|
return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_Bitmap, MessageBytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray Com_Protocol_EncodeTimeSync(
|
||
|
|
quint32 Version,
|
||
|
|
quint32 Flags,
|
||
|
|
qint32 TimezoneMinutes,
|
||
|
|
quint64 UtcMilliseconds,
|
||
|
|
quint32 AccuracyMilliseconds)
|
||
|
|
{
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
Com_Protocol_AppendUInt32Field(&MessageBytes, 1, Version);
|
||
|
|
Com_Protocol_AppendUInt32Field(&MessageBytes, 2, Flags);
|
||
|
|
Com_Protocol_AppendSInt32Field(&MessageBytes, 3, TimezoneMinutes);
|
||
|
|
Com_Protocol_AppendFixed64Field(&MessageBytes, 4, UtcMilliseconds);
|
||
|
|
Com_Protocol_AppendFixed32Field(&MessageBytes, 5, AccuracyMilliseconds);
|
||
|
|
return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_TimeSync, MessageBytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray Com_Protocol_EncodeThemeRgb(quint8 Red, quint8 Green, quint8 Blue)
|
||
|
|
{
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
Com_Protocol_AppendUInt32Field(&MessageBytes, 1, Red);
|
||
|
|
Com_Protocol_AppendUInt32Field(&MessageBytes, 2, Green);
|
||
|
|
Com_Protocol_AppendUInt32Field(&MessageBytes, 3, Blue);
|
||
|
|
return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_ThemeRgb, MessageBytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeHelloRsp(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Struct_ProtocolHelloRsp* p_Message)
|
||
|
|
{
|
||
|
|
Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None;
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if ((p_Message == nullptr) ||
|
||
|
|
!Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) ||
|
||
|
|
(Type != Com_Enum_ProtocolType_HelloRsp))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_DecodeHelloRspMessage(MessageBytes, p_Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeFunctionKeyEvent(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Struct_ProtocolFunctionKeyEvent* p_Message)
|
||
|
|
{
|
||
|
|
Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None;
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if ((p_Message == nullptr) ||
|
||
|
|
!Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) ||
|
||
|
|
(Type != Com_Enum_ProtocolType_FunctionKeyEvent))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_DecodeFunctionKeyEventMessage(MessageBytes, p_Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeLedState(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Struct_ProtocolLedState* p_Message)
|
||
|
|
{
|
||
|
|
Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None;
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if ((p_Message == nullptr) ||
|
||
|
|
!Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) ||
|
||
|
|
(Type != Com_Enum_ProtocolType_LedState))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_DecodeLedStateMessage(MessageBytes, p_Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeAck(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Struct_ProtocolAck* p_Message)
|
||
|
|
{
|
||
|
|
Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None;
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if ((p_Message == nullptr) ||
|
||
|
|
!Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) ||
|
||
|
|
(Type != Com_Enum_ProtocolType_Ack))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_DecodeAckMessage(MessageBytes, p_Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeError(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Struct_ProtocolError* p_Message)
|
||
|
|
{
|
||
|
|
Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None;
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if ((p_Message == nullptr) ||
|
||
|
|
!Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) ||
|
||
|
|
(Type != Com_Enum_ProtocolType_Error))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_DecodeErrorMessage(MessageBytes, p_Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeAckForType(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Enum_ProtocolType EnvelopeType,
|
||
|
|
Com_Struct_ProtocolAck* p_Message)
|
||
|
|
{
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if ((p_Message == nullptr) ||
|
||
|
|
(EnvelopeType != Com_Enum_ProtocolType_Ack) ||
|
||
|
|
!Com_Protocol_DecodeEnvelopeForExpectedType(
|
||
|
|
PacketBody,
|
||
|
|
Com_Enum_ProtocolType_Ack,
|
||
|
|
&MessageBytes))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_DecodeAckMessage(MessageBytes, p_Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_DecodeErrorForType(
|
||
|
|
const QByteArray& PacketBody,
|
||
|
|
Com_Enum_ProtocolType EnvelopeType,
|
||
|
|
Com_Struct_ProtocolError* p_Message)
|
||
|
|
{
|
||
|
|
QByteArray MessageBytes;
|
||
|
|
if ((p_Message == nullptr) ||
|
||
|
|
(EnvelopeType != Com_Enum_ProtocolType_Error) ||
|
||
|
|
!Com_Protocol_DecodeEnvelopeForExpectedType(
|
||
|
|
PacketBody,
|
||
|
|
Com_Enum_ProtocolType_Error,
|
||
|
|
&MessageBytes))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return Com_Protocol_DecodeErrorMessage(MessageBytes, p_Message);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_IsUsageBitmapValid(const QByteArray& UsageBitmap)
|
||
|
|
{
|
||
|
|
return UsageBitmap.size() == kUsageBitmapSize;
|
||
|
|
}
|
||
|
|
|
||
|
|
QByteArray Com_Protocol_CreateUsageBitmap()
|
||
|
|
{
|
||
|
|
return QByteArray(kUsageBitmapSize, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_TestUsageBitmapBit(const QByteArray& UsageBitmap, quint16 Usage)
|
||
|
|
{
|
||
|
|
int ByteIndex = 0;
|
||
|
|
quint8 BitMask = 0;
|
||
|
|
if (!Com_Protocol_IsUsageBitmapValid(UsageBitmap) ||
|
||
|
|
!Com_Protocol_GetBitmapPosition(Usage, &ByteIndex, &BitMask))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return (static_cast<quint8>(UsageBitmap.at(ByteIndex)) & BitMask) != 0U;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool Com_Protocol_SetUsageBitmapBit(QByteArray* p_UsageBitmap, quint16 Usage, bool IsPressed)
|
||
|
|
{
|
||
|
|
int ByteIndex = 0;
|
||
|
|
quint8 BitMask = 0;
|
||
|
|
if ((p_UsageBitmap == nullptr) ||
|
||
|
|
!Com_Protocol_IsUsageBitmapValid(*p_UsageBitmap) ||
|
||
|
|
!Com_Protocol_GetBitmapPosition(Usage, &ByteIndex, &BitMask))
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
quint8 ByteValue = static_cast<quint8>(p_UsageBitmap->at(ByteIndex));
|
||
|
|
if (IsPressed)
|
||
|
|
{
|
||
|
|
ByteValue = static_cast<quint8>(ByteValue | BitMask);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
ByteValue = static_cast<quint8>(ByteValue & ~BitMask);
|
||
|
|
}
|
||
|
|
|
||
|
|
(*p_UsageBitmap)[ByteIndex] = static_cast<char>(ByteValue);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
QVector<quint16> Com_Protocol_BuildPressedUsageList(const QByteArray& UsageBitmap)
|
||
|
|
{
|
||
|
|
QVector<quint16> UsageList;
|
||
|
|
if (!Com_Protocol_IsUsageBitmapValid(UsageBitmap))
|
||
|
|
{
|
||
|
|
return UsageList;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (quint16 Usage = 0; Usage <= kUsageNormalLast; ++Usage)
|
||
|
|
{
|
||
|
|
if (Com_Protocol_TestUsageBitmapBit(UsageBitmap, Usage))
|
||
|
|
{
|
||
|
|
UsageList.append(Usage);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (quint16 Usage = kUsageModifierFirst; Usage <= kUsageModifierLast; ++Usage)
|
||
|
|
{
|
||
|
|
if (Com_Protocol_TestUsageBitmapBit(UsageBitmap, Usage))
|
||
|
|
{
|
||
|
|
UsageList.append(Usage);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return UsageList;
|
||
|
|
}
|