Creating nested TLV8 structures
Is there any example on how to easily create nested TLV8 structures with the given API?
Maybe similiar to this implementation? https://github.com/maximkulkin/esp32-homekit-camera/blob/261363ce0a9e0a561a1804213294a24737881480/main/accessory.c#L695-L711
This is an incomplete example which shows how I could do it.
Is this correct? How could I improve the .valueOffset calculation?
UPDATE:
Got it working. I was not aware of the C builtin command offsetof() after all those years. 😄
This makes the offset calculation a lot better.
bool isValid(void *unsused HAP_UNUSED)
{
return true;
}
typedef struct
{
struct
{
uint8_t videoCodecType;
struct
{
uint8_t profileID;
uint8_t level;
uint8_t packetizationMode;
} videoCodecParams;
} videoConfigCodec;
} supportedVideoConfigStruct;
supportedVideoConfigStruct supportedVideoConfigValue =
{
{
.videoCodecType = 0,
{
.profileID = 0,
.level = 0,
.packetizationMode = 0
}
}
};
HAP_STRUCT_TLV_SUPPORT(void, supportedVideoConfigFormat)
HAP_STRUCT_TLV_SUPPORT(void, videoCodecConfigFormat)
HAP_STRUCT_TLV_SUPPORT(void, videoCodecParamsFormat)
HAP_STRUCT_TLV_SUPPORT(void, videoAttributesFormat)
const HAPUInt8TLVFormat videoCodecParamsProfileID = {
.type = kHAPTLVFormatType_UInt8,
.constraints = { .minimumValue = 0, .maximumValue = 2},
.callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecParamsProfileIDMember = {
.valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams.profileID),
.isSetOffset = 0,
.tlvType = 1,
.debugDescription = "Video Config Config Params Profile ID",
.format = &videoCodecParamsProfileID,
.isOptional = false,
.isFlat = false
};
const HAPUInt8TLVFormat videoCodecParamsLevel = {
.type = kHAPTLVFormatType_UInt8,
.constraints = { .minimumValue = 0, .maximumValue = 2},
.callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecParamsLevelMember = {
.valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams.level),
.isSetOffset = 0,
.tlvType = 2,
.debugDescription = "Video Config Config Params Level",
.format = &videoCodecParamsLevel,
.isOptional = false,
.isFlat = false
};
const HAPUInt8TLVFormat videoCodecParamsPacketizationMode = {
.type = kHAPTLVFormatType_UInt8,
.constraints = { .minimumValue = 0, .maximumValue = 2},
.callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecParamsPacketizationModeMember = {
.valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams.packetizationMode),
.isSetOffset = 0,
.tlvType = 3,
.debugDescription = "Video Config Config Packetization Mode",
.format = &videoCodecParamsPacketizationMode,
.isOptional = false,
.isFlat = false
};
/* ---------------------------------------------------------------------------------------------*/
const HAPUInt8TLVFormat videoCodecType = {
.type = kHAPTLVFormatType_UInt8,
.constraints = { .minimumValue = 0, .maximumValue = 1},
.callbacks = { .getDescription = NULL }
};
const HAPStructTLVMember videoCodecTypeMember = {
.valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecType),
.isSetOffset = 0,
.tlvType = 1,
.debugDescription = "Video Codec Type",
.format = &videoCodecType,
.isOptional = false,
.isFlat = false
};
const videoCodecConfigFormat videoCodecParams = {
.type = kHAPTLVFormatType_Struct,
.members = (const HAPStructTLVMember* const[]) { &videoCodecParamsProfileIDMember,
&videoCodecParamsLevelMember,
&videoCodecParamsPacketizationModeMember,
NULL},
.callbacks = { .isValid = isValid }
};
const HAPStructTLVMember videoCodecParamsMember = {
.valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec.videoCodecParams),
.isSetOffset = 0,
.tlvType = 2,
.debugDescription = "Video Codec Parameters",
.format = &videoCodecParams,
.isOptional = false,
.isFlat = false
};
const videoCodecConfigFormat videoCodecConfig = {
.type = kHAPTLVFormatType_Struct,
.members = (const HAPStructTLVMember* const[]) { &videoCodecTypeMember,
&videoCodecParamsMember,
NULL},
.callbacks = { .isValid = isValid }
};
const HAPStructTLVMember videoCodecConfigMember = {
.valueOffset = offsetof(supportedVideoConfigStruct, videoConfigCodec),
.isSetOffset = 0,
.tlvType = 1,
.debugDescription = "Video Config Config",
.format = &videoCodecConfig,
.isOptional = false,
.isFlat = false
};
const supportedVideoConfigFormat supported_video_config = {
.type = kHAPTLVFormatType_Struct,
.members = (const HAPStructTLVMember* const[]) { &videoCodecConfigMember, NULL},
.callbacks = { .isValid = isValid }
};
/**
* Handle read request to the 'SupportedVideoStreamConfiguration' characteristic of the Camera RTP Stream Management service.
*/
HAP_RESULT_USE_CHECK
HAPError HandleSupportedVideoStreamConfigurationRead(
HAPAccessoryServerRef* server HAP_UNUSED,
const HAPTLV8CharacteristicReadRequest* request HAP_UNUSED,
HAPTLVWriterRef* responseWriter,
void* _Nullable context HAP_UNUSED) {
HAPPrecondition(responseWriter);
HAPLogInfo(&kHAPLog_Default, "%s", __func__);
HAPError err;
err = HAPTLVWriterEncode(responseWriter, &supported_video_config, &supportedVideoConfigValue);
if (err) {
HAPAssert(err == kHAPError_OutOfResources);
return err;
}
return kHAPError_None;
}
Of course there are more things missing. The attributes and so on. But at least it shows how to create nested TLV8 structures from C structs.
Have you expanded on this any more to include an array of structs possibly? I'm working through something similar but trying to support multiple ".videoAttributes".