Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 105 additions & 7 deletions interface/Device.tt
Original file line number Diff line number Diff line change
Expand Up @@ -464,9 +464,10 @@ if (isPrivate)
if (member.Value.HasConverter)
{
var memberType = TemplateHelper.GetInterfaceType(member.Value, register.Type);
var converterInterfaceType = member.Value.GetConverterInterfaceType(register.Type);
#>

private static partial <#= memberType #> ParsePayload<#= member.Key #>(<#= register.PayloadInterfaceType #> payload<#= member.Key #>);
private static partial <#= memberType #> ParsePayload<#= member.Key #>(<#= converterInterfaceType #> payload<#= member.Key #>);
<#
}
}
Expand All @@ -482,7 +483,8 @@ if (isPrivate)
member.Key,
member.Value,
"payload",
register.Type);
register,
deviceMetadata);
#>
result.<#= member.Key #> = <#= memberConversion #>;
<#
Expand Down Expand Up @@ -532,16 +534,16 @@ if (isPrivate)
foreach (var member in register.PayloadSpec)
{
var payloadIndex = member.Value.Offset.GetValueOrDefault(0);
var memberIndexer = member.Value.Offset.HasValue ? $"[{member.Value.Offset}]" : string.Empty;
var memberConversion = TemplateHelper.GetPayloadMemberFormatter(
var memberAssignment = TemplateHelper.GetPayloadMemberAssignmentFormatter(
member.Key,
member.Value,
$"value.{member.Key}",
register.Type,
"result",
register,
deviceMetadata,
assigned[payloadIndex]);
assigned[payloadIndex] = true;
#>
result<#= memberIndexer #><#= memberConversion #>;
<#= memberAssignment #>;
<#
}
#>
Expand Down Expand Up @@ -1002,4 +1004,100 @@ foreach (var groupMask in deviceMetadata.GroupMasks)
<#
}
#>

internal static class RuntimeArrayHelpers
{
internal static T[] GetSubArray<T>(this T[] array, int offset, int count)
{
var result = new T[count];
Array.Copy(array, offset, result, 0, count);
return result;
}

internal static byte ToByte(this ArraySegment<byte> segment) => segment.Array[segment.Offset];

internal static sbyte ToSByte(this ArraySegment<byte> segment) => (sbyte)segment.Array[segment.Offset];

internal static ushort ToUInt16(this ArraySegment<byte> segment) => BitConverter.ToUInt16(segment.Array, segment.Offset);

internal static short ToInt16(this ArraySegment<byte> segment) => BitConverter.ToInt16(segment.Array, segment.Offset);

internal static uint ToUInt32(this ArraySegment<byte> segment) => BitConverter.ToUInt32(segment.Array, segment.Offset);

internal static int ToInt32(this ArraySegment<byte> segment) => BitConverter.ToInt32(segment.Array, segment.Offset);

internal static ulong ToUInt64(this ArraySegment<byte> segment) => BitConverter.ToUInt64(segment.Array, segment.Offset);

internal static long ToInt64(this ArraySegment<byte> segment) => BitConverter.ToInt64(segment.Array, segment.Offset);

internal static float ToSingle(this ArraySegment<byte> segment) => BitConverter.ToSingle(segment.Array, segment.Offset);

internal static string ToUTF8String(this ArraySegment<byte> segment) => System.Text.Encoding.UTF8.GetString(segment.Array, segment.Offset, segment.Count);

internal static void WriteBytes(this ArraySegment<byte> segment, byte value) => segment.Array[segment.Offset] = value;

internal static void WriteBytes(this ArraySegment<byte> segment, sbyte value) => segment.Array[segment.Offset] = (byte)value;

internal static void WriteBytes(this ArraySegment<byte> segment, ushort value)
{
segment.Array[segment.Offset] = (byte)value;
segment.Array[segment.Offset + 1] = (byte)(value >> 8);
}

internal static void WriteBytes(this ArraySegment<byte> segment, short value)
{
segment.Array[segment.Offset] = (byte)value;
segment.Array[segment.Offset + 1] = (byte)(value >> 8);
}

internal static void WriteBytes(this ArraySegment<byte> segment, uint value)
{
segment.Array[segment.Offset] = (byte)value;
segment.Array[segment.Offset + 1] = (byte)(value >> 8);
segment.Array[segment.Offset + 2] = (byte)(value >> 16);
segment.Array[segment.Offset + 3] = (byte)(value >> 24);
}

internal static void WriteBytes(this ArraySegment<byte> segment, int value)
{
segment.Array[segment.Offset] = (byte)value;
segment.Array[segment.Offset + 1] = (byte)(value >> 8);
segment.Array[segment.Offset + 2] = (byte)(value >> 16);
segment.Array[segment.Offset + 3] = (byte)(value >> 24);
}

internal static void WriteBytes(this ArraySegment<byte> segment, ulong value)
{
segment.Array[segment.Offset] = (byte)value;
segment.Array[segment.Offset + 1] = (byte)(value >> 8);
segment.Array[segment.Offset + 2] = (byte)(value >> 16);
segment.Array[segment.Offset + 3] = (byte)(value >> 24);
segment.Array[segment.Offset + 4] = (byte)(value >> 32);
segment.Array[segment.Offset + 5] = (byte)(value >> 40);
segment.Array[segment.Offset + 6] = (byte)(value >> 48);
segment.Array[segment.Offset + 7] = (byte)(value >> 56);
}

internal static void WriteBytes(this ArraySegment<byte> segment, long value)
{
segment.Array[segment.Offset] = (byte)value;
segment.Array[segment.Offset + 1] = (byte)(value >> 8);
segment.Array[segment.Offset + 2] = (byte)(value >> 16);
segment.Array[segment.Offset + 3] = (byte)(value >> 24);
segment.Array[segment.Offset + 4] = (byte)(value >> 32);
segment.Array[segment.Offset + 5] = (byte)(value >> 40);
segment.Array[segment.Offset + 6] = (byte)(value >> 48);
segment.Array[segment.Offset + 7] = (byte)(value >> 56);
}

internal static unsafe void WriteBytes(this ArraySegment<byte> segment, float value) => WriteBytes(segment, *(int*)&value);

internal static unsafe void WriteBytes(this ArraySegment<byte> segment, string value) =>
System.Text.Encoding.UTF8.GetBytes(value, 0, segment.Count, segment.Array, segment.Offset);

internal static void WriteBytes<T>(this ArraySegment<byte> segment, T[] values) where T : unmanaged
{
Buffer.BlockCopy(values, 0, segment.Array, segment.Offset, segment.Count);
}
}
}
130 changes: 124 additions & 6 deletions interface/Interface.tt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class PayloadMemberInfo
{
public int? Mask;
public int? Offset;
public int? Length;
public string MaskType;
public string InterfaceType;
public MemberConverter Converter;
Expand All @@ -79,6 +80,17 @@ public class PayloadMemberInfo
public float? DefaultValue;

public bool HasConverter => Converter > MemberConverter.None;
public string GetConverterInterfaceType(PayloadType payloadType)
{
return Converter switch
{
MemberConverter.RawPayload => "ArraySegment<byte>",
MemberConverter.Payload => Length.GetValueOrDefault() > 0
? $"ArraySegment<{TemplateHelper.GetInterfaceType(payloadType, 0)}>"
: TemplateHelper.GetInterfaceType(payloadType, 0),
MemberConverter.None => TemplateHelper.GetInterfaceType(payloadType, Length.GetValueOrDefault())
};
}
}

public class BitMaskInfo
Expand Down Expand Up @@ -131,7 +143,7 @@ public static partial class TemplateHelper
{
if (!string.IsNullOrEmpty(member.InterfaceType)) return member.InterfaceType;
else if (!string.IsNullOrEmpty(member.MaskType)) return member.MaskType;
else return GetInterfaceType(payloadType);
else return GetInterfaceType(payloadType, member.Length.GetValueOrDefault());
}

public static string GetInterfaceType(PayloadType payloadType)
Expand Down Expand Up @@ -166,6 +178,26 @@ public static partial class TemplateHelper
else return "uint";
}

public static bool GetInterfaceTypeSize(string interfaceType, out PayloadType payloadType, out int size)
{
payloadType = interfaceType switch
{
"byte" => PayloadType.U8,
"sbyte" => PayloadType.S8,
"ushort" => PayloadType.U16,
"short" => PayloadType.S16,
"uint" => PayloadType.U32,
"int" => PayloadType.S32,
"ulong" => PayloadType.U64,
"long" => PayloadType.S64,
"float" => PayloadType.Float,
_ => 0
};

size = GetPayloadTypeSize(payloadType);
return payloadType > 0;
}

public static string GetPayloadTypeSuffix(PayloadType payloadType, int payloadLength = 0)
{
if (payloadLength > 0)
Expand All @@ -189,6 +221,11 @@ public static partial class TemplateHelper
}
}

static int GetPayloadTypeSize(PayloadType payloadType)
{
return (int)payloadType & 0xF;
}

public static string GetRangeAttributeDeclaration(float? minValue, float? maxValue)
{
var minValueDeclaration = minValue.HasValue ? minValue.Value.ToString() : "long.MinValue";
Expand Down Expand Up @@ -244,15 +281,61 @@ public static partial class TemplateHelper
return (int)Math.Log(lsb, 2);
}

static int GetMemberLength(
PayloadMemberInfo member,
RegisterInfo register,
DeviceInfo deviceMetadata,
out PayloadType payloadType)
{
payloadType = 0;
if (member.Length.HasValue)
return member.Length.GetValueOrDefault();

var interfaceType = GetInterfaceType(member, register.Type);
if (deviceMetadata.GroupMasks.TryGetValue(interfaceType, out GroupMaskInfo groupMask))
interfaceType = groupMask.InterfaceType;
else if (deviceMetadata.BitMasks.TryGetValue(interfaceType, out BitMaskInfo bitMask))
interfaceType = bitMask.InterfaceType;

if (GetInterfaceTypeSize(interfaceType, out payloadType, out int size))
return size;
else
return GetPayloadTypeSize(register.Type);
}

public static string GetPayloadMemberParser(
string name,
PayloadMemberInfo member,
string expression,
PayloadType payloadType)
RegisterInfo register,
DeviceInfo deviceMetadata)
{
if (member.Offset.HasValue)
var payloadType = register.Type;
var memberLength = GetMemberLength(member, register, deviceMetadata, out PayloadType memberPayloadType);
var memberOffset = member.Offset.GetValueOrDefault();
var payloadInterfaceType = GetInterfaceType(payloadType);
if (memberLength > 0 && member.InterfaceType != payloadInterfaceType && member.InterfaceType != "bool")
{
expression = $"{expression}[{member.Offset.Value}]";
if (member.Converter == MemberConverter.RawPayload)
throw new NotSupportedException("Raw payload converters inside payload spec is not currently supported.");

if (member.InterfaceType == "string")
return $"new ArraySegment<{payloadInterfaceType}>({expression}, {memberOffset}, {memberLength}).ToUTF8String()";
else if (member.Converter == MemberConverter.Payload || memberPayloadType > 0)
{
expression = $"new ArraySegment<{payloadInterfaceType}>({expression}, {memberOffset}, {memberLength})";
if (memberPayloadType > 0)
{
expression = $"{expression}.To{GetPayloadTypeSuffix(memberPayloadType)}()";
return GetConversionToInterfaceType(member.MaskType, expression);
}
}
else
expression = $"{expression}.GetSubArray({memberOffset}, {memberLength})";
}
else if (member.Offset.HasValue)
{
expression = $"{expression}[{member.Offset.GetValueOrDefault()}]";
}
if (member.Mask.HasValue)
{
Expand All @@ -266,7 +349,6 @@ public static partial class TemplateHelper
expression = $"({expression} >> {shift})";
}

var payloadInterfaceType = GetInterfaceType(payloadType);
expression = $"({payloadInterfaceType}){expression}";
}
}
Expand All @@ -278,7 +360,43 @@ public static partial class TemplateHelper
return GetConversionToInterfaceType(member.InterfaceType ?? member.MaskType, expression);
}

public static string GetPayloadMemberFormatter(
public static string GetPayloadMemberAssignmentFormatter(
string name,
PayloadMemberInfo member,
string expression,
RegisterInfo register,
DeviceInfo deviceMetadata,
bool assigned)
{
var payloadType = register.Type;
var memberLength = GetMemberLength(member, register, deviceMetadata, out PayloadType memberPayloadType);
var memberOffset = member.Offset.GetValueOrDefault();
var payloadInterfaceType = GetInterfaceType(payloadType);
if (memberLength > 0 && member.InterfaceType != payloadInterfaceType && member.InterfaceType != "bool")
{
if (member.Converter == MemberConverter.RawPayload)
throw new NotSupportedException("Raw payload converters inside payload spec is not currently supported.");

expression = $"new ArraySegment<{payloadInterfaceType}>({expression}, {memberOffset}, {memberLength})";
var valueExpression = $"value.{name}";
if (!string.IsNullOrEmpty(member.MaskType) && memberPayloadType > 0)
valueExpression = GetConversionToInterfaceType(GetInterfaceType(memberPayloadType), valueExpression);
expression = $"{expression}.WriteBytes({valueExpression})";
return expression;
}

var memberIndexer = member.Offset.HasValue ? $"[{memberOffset}]" : string.Empty;
var memberConversion = TemplateHelper.GetPayloadMemberValueFormatter(
name,
member,
$"value.{name}",
payloadType,
assigned);
return $"{expression}{memberIndexer}{memberConversion}";
}


public static string GetPayloadMemberValueFormatter(
string name,
PayloadMemberInfo member,
string expression,
Expand Down