Complete typed COM decoding
This commit is contained in:
@@ -9,6 +9,39 @@ constexpr quint8 COM_CDC_CONST_PACKET_HEAD2 = 0x55;
|
|||||||
constexpr int COM_CDC_CONST_FRAME_OVERHEAD = 5;
|
constexpr int COM_CDC_CONST_FRAME_OVERHEAD = 5;
|
||||||
constexpr int COM_CDC_CONST_MAX_PAYLOAD_LENGTH = 64;
|
constexpr int COM_CDC_CONST_MAX_PAYLOAD_LENGTH = 64;
|
||||||
|
|
||||||
|
quint16 Com_Cdc_Func_ReadLe16(const QByteArray& ByteArray, int Offset)
|
||||||
|
{
|
||||||
|
return static_cast<quint16>(
|
||||||
|
static_cast<quint8>(ByteArray.at(Offset)) |
|
||||||
|
(static_cast<quint16>(static_cast<quint8>(ByteArray.at(Offset + 1))) << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 Com_Cdc_Func_ReadLe32(const QByteArray& ByteArray, int Offset)
|
||||||
|
{
|
||||||
|
quint32 Value = 0;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < 4; ++Index)
|
||||||
|
{
|
||||||
|
Value |= static_cast<quint32>(static_cast<quint8>(ByteArray.at(Offset + Index))) <<
|
||||||
|
(Index * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 Com_Cdc_Func_ReadLe64(const QByteArray& ByteArray, int Offset)
|
||||||
|
{
|
||||||
|
quint64 Value = 0;
|
||||||
|
|
||||||
|
for (int Index = 0; Index < 8; ++Index)
|
||||||
|
{
|
||||||
|
Value |= static_cast<quint64>(static_cast<quint8>(ByteArray.at(Offset + Index))) <<
|
||||||
|
(Index * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
bool Com_Cdc_Func_IsKnownLengthValid(Packet_Type Type, quint8 DataLength)
|
bool Com_Cdc_Func_IsKnownLengthValid(Packet_Type Type, quint8 DataLength)
|
||||||
{
|
{
|
||||||
switch (Type)
|
switch (Type)
|
||||||
@@ -48,6 +81,15 @@ bool Com_Cdc_Func_IsKnownLengthValid(Packet_Type Type, quint8 DataLength)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_Type Type,
|
||||||
|
quint8 ExpectedLength)
|
||||||
|
{
|
||||||
|
return (PacketData.type == Type) &&
|
||||||
|
(PacketData.data.size() == ExpectedLength);
|
||||||
|
}
|
||||||
|
|
||||||
bool Com_Cdc_Func_ParseFrameAtStart(const QByteArray& ByteArray, Packet* p_Packet)
|
bool Com_Cdc_Func_ParseFrameAtStart(const QByteArray& ByteArray, Packet* p_Packet)
|
||||||
{
|
{
|
||||||
if ((p_Packet == nullptr) || (ByteArray.size() < COM_CDC_CONST_FRAME_OVERHEAD))
|
if ((p_Packet == nullptr) || (ByteArray.size() < COM_CDC_CONST_FRAME_OVERHEAD))
|
||||||
@@ -196,3 +238,187 @@ bool Com_Cdc_Func_TryTakeFrame(QByteArray* p_Buffer, Packet* p_Packet)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseHelloReq(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_HelloReq* p_HelloReq)
|
||||||
|
{
|
||||||
|
if ((p_HelloReq == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_HelloReq,
|
||||||
|
Packet_len::Com_Len_HelloReq))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_HelloReq HelloReq;
|
||||||
|
HelloReq.ProtocolVersion = static_cast<quint8>(PacketData.data.at(0));
|
||||||
|
*p_HelloReq = HelloReq;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseHelloRsp(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_HelloRsp* p_HelloRsp)
|
||||||
|
{
|
||||||
|
if ((p_HelloRsp == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_HelloRsp,
|
||||||
|
Packet_len::Com_Len_HelloRsp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_HelloRsp HelloRsp;
|
||||||
|
HelloRsp.ProtocolVersion = static_cast<quint8>(PacketData.data.at(0));
|
||||||
|
HelloRsp.VendorId = Com_Cdc_Func_ReadLe16(PacketData.data, 1);
|
||||||
|
HelloRsp.ProductId = Com_Cdc_Func_ReadLe16(PacketData.data, 3);
|
||||||
|
HelloRsp.FirmwareMajor = static_cast<quint8>(PacketData.data.at(5));
|
||||||
|
HelloRsp.FirmwareMinor = static_cast<quint8>(PacketData.data.at(6));
|
||||||
|
HelloRsp.CapabilityFlags = Com_Cdc_Func_ReadLe16(PacketData.data, 7);
|
||||||
|
*p_HelloRsp = HelloRsp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseBitmap(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_Bitmap* p_Bitmap)
|
||||||
|
{
|
||||||
|
if ((p_Bitmap == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_Bitmap,
|
||||||
|
Packet_len::Com_Len_Bitmap))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_Bitmap Bitmap;
|
||||||
|
Bitmap.UsageBitmap = PacketData.data;
|
||||||
|
*p_Bitmap = Bitmap;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseFunctionKeyEvent(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_FunctionKeyEvent* p_Event)
|
||||||
|
{
|
||||||
|
if ((p_Event == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_FunctionKeyEvent,
|
||||||
|
Packet_len::Com_Len_FunctionKeyEvent))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_FunctionKeyEvent EventData;
|
||||||
|
EventData.Usage = Com_Cdc_Func_ReadLe16(PacketData.data, 0);
|
||||||
|
EventData.Action = static_cast<quint8>(PacketData.data.at(2));
|
||||||
|
*p_Event = EventData;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseLedState(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_LedState* p_LedState)
|
||||||
|
{
|
||||||
|
if ((p_LedState == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_LedState,
|
||||||
|
Packet_len::Com_Len_LedState))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_LedState LedState;
|
||||||
|
LedState.LedMask = static_cast<quint8>(PacketData.data.at(0));
|
||||||
|
*p_LedState = LedState;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseTimeSync(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_TimeSync* p_TimeSync)
|
||||||
|
{
|
||||||
|
if ((p_TimeSync == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_TimeSync,
|
||||||
|
Packet_len::Com_Len_TimeSync))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_TimeSync TimeSync;
|
||||||
|
TimeSync.Version = static_cast<quint8>(PacketData.data.at(0));
|
||||||
|
TimeSync.Flags = static_cast<quint8>(PacketData.data.at(1));
|
||||||
|
TimeSync.TimezoneMin = Com_Cdc_Func_ReadLe16(PacketData.data, 2);
|
||||||
|
TimeSync.UtcMs = Com_Cdc_Func_ReadLe64(PacketData.data, 4);
|
||||||
|
TimeSync.AccuracyMs = Com_Cdc_Func_ReadLe32(PacketData.data, 12);
|
||||||
|
*p_TimeSync = TimeSync;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseThemeRgb(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_ThemeRgb* p_ThemeRgb)
|
||||||
|
{
|
||||||
|
if ((p_ThemeRgb == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_ThemeRgb,
|
||||||
|
Packet_len::Com_Len_ThemeRgb))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_ThemeRgb ThemeRgb;
|
||||||
|
ThemeRgb.Red = static_cast<quint8>(PacketData.data.at(0));
|
||||||
|
ThemeRgb.Green = static_cast<quint8>(PacketData.data.at(1));
|
||||||
|
ThemeRgb.Blue = static_cast<quint8>(PacketData.data.at(2));
|
||||||
|
*p_ThemeRgb = ThemeRgb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseAck(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_Ack* p_Ack)
|
||||||
|
{
|
||||||
|
if ((p_Ack == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_Ack,
|
||||||
|
Packet_len::Com_Len_Ack))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_Ack Ack;
|
||||||
|
Ack.AckedType = static_cast<quint8>(PacketData.data.at(0));
|
||||||
|
*p_Ack = Ack;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseError(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_Error* p_Error)
|
||||||
|
{
|
||||||
|
if ((p_Error == nullptr) ||
|
||||||
|
!Com_Cdc_Func_IsExpectedPacket(
|
||||||
|
PacketData,
|
||||||
|
Com_Type_Error,
|
||||||
|
Packet_len::Com_Len_Error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Packet_Error Error;
|
||||||
|
Error.ErrorType = static_cast<quint8>(PacketData.data.at(0));
|
||||||
|
Error.ErrorCode = static_cast<quint8>(PacketData.data.at(1));
|
||||||
|
*p_Error = Error;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,3 +6,31 @@
|
|||||||
|
|
||||||
bool Com_Cdc_Func_ParseFrame(const QByteArray& ByteArray, Packet* p_Packet);
|
bool Com_Cdc_Func_ParseFrame(const QByteArray& ByteArray, Packet* p_Packet);
|
||||||
bool Com_Cdc_Func_TryTakeFrame(QByteArray* p_Buffer, Packet* p_Packet);
|
bool Com_Cdc_Func_TryTakeFrame(QByteArray* p_Buffer, Packet* p_Packet);
|
||||||
|
|
||||||
|
bool Com_Cdc_Func_ParseHelloReq(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_HelloReq* p_HelloReq);
|
||||||
|
bool Com_Cdc_Func_ParseHelloRsp(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_HelloRsp* p_HelloRsp);
|
||||||
|
bool Com_Cdc_Func_ParseBitmap(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_Bitmap* p_Bitmap);
|
||||||
|
bool Com_Cdc_Func_ParseFunctionKeyEvent(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_FunctionKeyEvent* p_Event);
|
||||||
|
bool Com_Cdc_Func_ParseLedState(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_LedState* p_LedState);
|
||||||
|
bool Com_Cdc_Func_ParseTimeSync(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_TimeSync* p_TimeSync);
|
||||||
|
bool Com_Cdc_Func_ParseThemeRgb(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_ThemeRgb* p_ThemeRgb);
|
||||||
|
bool Com_Cdc_Func_ParseAck(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_Ack* p_Ack);
|
||||||
|
bool Com_Cdc_Func_ParseError(
|
||||||
|
const Packet& PacketData,
|
||||||
|
Packet_Error* p_Error);
|
||||||
|
|||||||
92
docs/host_com_rebuild.md
Normal file
92
docs/host_com_rebuild.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# Host COM Rebuild
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Keep the COM layer small, explicit, and easy to teach.
|
||||||
|
|
||||||
|
The COM layer should:
|
||||||
|
|
||||||
|
- define packet types and payload structures
|
||||||
|
- build full wire frames
|
||||||
|
- parse full wire frames
|
||||||
|
- parse typed packet payloads
|
||||||
|
|
||||||
|
The COM layer should not:
|
||||||
|
|
||||||
|
- enumerate devices
|
||||||
|
- open ports
|
||||||
|
- own handshake state
|
||||||
|
- own UI state
|
||||||
|
|
||||||
|
## Current file roles
|
||||||
|
|
||||||
|
### `Com_Cdc.h`
|
||||||
|
|
||||||
|
Owns the packet model:
|
||||||
|
|
||||||
|
- packet types
|
||||||
|
- fixed payload lengths
|
||||||
|
- payload structs
|
||||||
|
|
||||||
|
### `Com_CdcEncode.h/.cpp`
|
||||||
|
|
||||||
|
Owns the write direction:
|
||||||
|
|
||||||
|
- checksum
|
||||||
|
- full frame build
|
||||||
|
- typed payload encode
|
||||||
|
|
||||||
|
### `Com_CdcDecode.h/.cpp`
|
||||||
|
|
||||||
|
Owns the read direction:
|
||||||
|
|
||||||
|
- full frame parse
|
||||||
|
- stream extraction
|
||||||
|
- typed payload decode
|
||||||
|
|
||||||
|
## Completed nodes
|
||||||
|
|
||||||
|
### Node 1: legacy frame encode baseline
|
||||||
|
|
||||||
|
Already present before this step:
|
||||||
|
|
||||||
|
- build full frame
|
||||||
|
- build all typed packets
|
||||||
|
|
||||||
|
### Node 2: typed packet decode completion
|
||||||
|
|
||||||
|
Files updated in this step:
|
||||||
|
|
||||||
|
- `KeyBorad/KeyBorad/COM/Com_CdcDecode.h`
|
||||||
|
- `KeyBorad/KeyBorad/COM/Com_CdcDecode.cpp`
|
||||||
|
|
||||||
|
Design notes:
|
||||||
|
|
||||||
|
- keep decode logic flat and explicit
|
||||||
|
- one helper for little-endian reads
|
||||||
|
- one helper for type + length validation
|
||||||
|
- one decode function per packet type
|
||||||
|
|
||||||
|
Implemented behavior:
|
||||||
|
|
||||||
|
- parse frame header and checksum
|
||||||
|
- extract frames from a byte stream
|
||||||
|
- decode:
|
||||||
|
- `HelloReq`
|
||||||
|
- `HelloRsp`
|
||||||
|
- `Bitmap`
|
||||||
|
- `FunctionKeyEvent`
|
||||||
|
- `LedState`
|
||||||
|
- `TimeSync`
|
||||||
|
- `ThemeRgb`
|
||||||
|
- `Ack`
|
||||||
|
- `Error`
|
||||||
|
|
||||||
|
## COM done criteria
|
||||||
|
|
||||||
|
For the current project stage, COM is considered done when:
|
||||||
|
|
||||||
|
1. every supported packet can be built
|
||||||
|
2. every supported packet can be parsed
|
||||||
|
3. stream extraction is stable
|
||||||
|
4. higher layers no longer need to know byte offsets
|
||||||
Reference in New Issue
Block a user