Skip to content

Commit

Permalink
feat(sdr): add utility methods for SDR tags and tests
Browse files Browse the repository at this point in the history
Added multiple utility methods to handle AsvSdrRecordTagTypes in AsvSdrHelper.cs. These methods include PrintTag, PrintTagValue, GetTagValueAsUInt64, SetTagValueAsUInt64, GetTagValueAsInt64, SetTagValueAsInt64, GetTagValueAsReal64, SetTagValueAsReal64, GetTagValueAsString, and SetTagValueAsString.

These methods provide a unified way to manage SDR tag values, handle various data types and improve code robustness by performing necessary checks to prevent incorrect usage. Mavlink endpoint 'AsvSdrClientRecordTag.cs' was refactored to use these new utility methods.

The changes are justified by enhancing the capacity of handling SDR tags and simplifying the client's tasks in managing these data types.

Also added corresponding tests for these new utility methods in AsvSdrHelperTest.cs to ensure their correct functionality. Tests include setting and getting tag value for all supported types (ulong, long, double, string). These added tests provide validation that new utility methods function as expected.

A method was added in MavlinkTypesHelper.cs for setting and getting string value from byte arrays. Testing for these methods was also included.

Reducing code repetition and enhancing code robustness lead to sturdier and easily maintainable codebase.
  • Loading branch information
asvol committed Nov 8, 2023
1 parent f2e4a87 commit 1e84265
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 15 deletions.
50 changes: 50 additions & 0 deletions src/Asv.Mavlink.Test/Microservices/AsvSdr/AsvSdrHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,56 @@ public void Check_mission_conversion_for_wait_vehicle(ushort index)
AsvSdrHelper.GetArgsForSdrWaitVehicleWaypoint(outputServerItem, out var indexOut);
Assert.Equal(index,indexOut);
}
[Theory]
[InlineData(ulong.MaxValue)]
[InlineData(ulong.MinValue)]
[InlineData(1234567789)]
public void Check_set_and_get_value_from_byte_array_uint64(ulong value)
{
var data = new byte[AsvSdrHelper.RecordTagValueLength];
AsvSdrHelper.SetTagValueAsUInt64(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64, value);
var valueOut = AsvSdrHelper.GetTagValueAsUInt64(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64);
Assert.Equal(value,valueOut);
}
[Theory]
[InlineData(0)]
[InlineData(123456789)]
[InlineData(long.MaxValue)]
[InlineData(long.MinValue)]
public void Check_set_and_get_value_from_byte_array_int64(long value)
{
var data = new byte[AsvSdrHelper.RecordTagValueLength];
AsvSdrHelper.SetTagValueAsInt64(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64, value);
var valueOut = AsvSdrHelper.GetTagValueAsInt64(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64);
Assert.Equal(value,valueOut);
}
[Theory]
[InlineData(0)]
[InlineData(double.Epsilon)]
[InlineData(double.NaN)]
[InlineData(12345.45)]
public void Check_set_and_get_value_from_byte_array_double(double value)
{
var data = new byte[AsvSdrHelper.RecordTagValueLength];
AsvSdrHelper.SetTagValueAsReal64(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64, value);
var valueOut = AsvSdrHelper.GetTagValueAsReal64(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64);
Assert.Equal(value,valueOut);
}

[Theory]
[InlineData("")]
[InlineData("12345678")]
[InlineData("1234")]
[InlineData("A")]
public void Check_set_and_get_value_from_byte_array_string8(string value)
{
var data = new byte[AsvSdrHelper.RecordTagValueLength];
AsvSdrHelper.SetTagValueAsString(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeString8, value);
var valueOut = AsvSdrHelper.GetTagValueAsString(data, AsvSdrRecordTagType.AsvSdrRecordTagTypeString8);
Assert.Equal(value,valueOut);
}





Expand Down
94 changes: 94 additions & 0 deletions src/Asv.Mavlink/Microservices/AsvSdr/AsvSdrHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public static void CheckRecordName(string name)
$"Record name '{name}' not match regex '{RecordNameRegexString}')");
}

#region Tags

public static void CheckTagName(string name)
{
if (name.IsNullOrWhiteSpace()) throw new Exception("Tag name is empty");
Expand All @@ -40,6 +42,98 @@ public static void CheckTagName(string name)
$"Tag name '{name}' not match regex '{RecordTagNameRegexString}')");
}

public static string PrintTag(string tagName,AsvSdrRecordTagType type, byte[] value)
{
return $"{tagName}:{PrintTagValue(type, value)}";
}
public static string PrintTagValue(AsvSdrRecordTagType type, byte[] rawValue)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException(nameof(rawValue), $"Tag value array must be {RecordTagValueLength} bytes length");
return type switch
{
AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64 => $"{BitConverter.ToUInt64(rawValue, 0)}",
AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64 => $"{BitConverter.ToInt64(rawValue, 0)}",
AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64 => $"{BitConverter.ToDouble(rawValue, 0)}",
AsvSdrRecordTagType.AsvSdrRecordTagTypeString8 => $"{MavlinkTypesHelper.GetString(rawValue)}",
_ => throw new ArgumentOutOfRangeException()
};
}

public static ulong GetTagValueAsUInt64(ReadOnlySpan<byte> rawValue, AsvSdrRecordTagType type)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64}", nameof(type));
return BitConverter.ToUInt64(rawValue);
}
public static void SetTagValueAsUInt64(Span<byte> rawValue, AsvSdrRecordTagType type, ulong value)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64}", nameof(type));
if (BitConverter.TryWriteBytes(rawValue, value) == false)
throw new ArgumentException($"Can't write value {value} to tag value array", nameof(value));

}
public static long GetTagValueAsInt64(ReadOnlySpan<byte> rawValue, AsvSdrRecordTagType type)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64}", nameof(type));
return BitConverter.ToInt64(rawValue);
}

public static void SetTagValueAsInt64(Span<byte> rawValue, AsvSdrRecordTagType type, long value)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64}", nameof(type));
if (BitConverter.TryWriteBytes(rawValue, value) == false)
throw new ArgumentException($"Can't write value {value} to tag value array", nameof(value));
}
public static double GetTagValueAsReal64(ReadOnlySpan<byte> rawValue, AsvSdrRecordTagType type)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64}", nameof(type));
return BitConverter.ToDouble(rawValue);
}

public static void SetTagValueAsReal64(Span<byte> rawValue, AsvSdrRecordTagType type, double value)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64}", nameof(type));
if (BitConverter.TryWriteBytes(rawValue, value) == false)
throw new ArgumentException($"Can't write value {value} to tag value array", nameof(value));
}

public static string GetTagValueAsString(byte[] rawValue, AsvSdrRecordTagType type)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeString8)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64}", nameof(type));
return MavlinkTypesHelper.GetString(rawValue);
}

public static void SetTagValueAsString(byte[] rawValue, AsvSdrRecordTagType type, string value)
{
if (rawValue.Length != RecordTagValueLength)
throw new ArgumentException($"Tag value array must be {RecordTagValueLength} bytes length", nameof(rawValue));
if (type != AsvSdrRecordTagType.AsvSdrRecordTagTypeString8)
throw new ArgumentException($"Tag type must be {AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64}", nameof(type));
MavlinkTypesHelper.SetString(rawValue, value);
}

#endregion

public static readonly ListDataFileFormat FileFormat = new()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,12 @@ internal AsvSdrClientRecordTag(TagId id, AsvSdrRecordTagPayload payload)

public AsvSdrRecordTagType Type { get; }

public ulong GetUint64() => BitConverter.ToUInt64(RawValue,0);
public long GetInt64() => BitConverter.ToInt64(RawValue,0);
public double GetReal64() => BitConverter.ToDouble(RawValue,0);
public string GetString() => MavlinkTypesHelper.GetString(RawValue);
public ulong GetUint64() => AsvSdrHelper.GetTagValueAsUInt64(RawValue, Type);
public long GetInt64() => AsvSdrHelper.GetTagValueAsInt64(RawValue, Type);
public double GetReal64() => AsvSdrHelper.GetTagValueAsReal64(RawValue,Type);
public string GetString() => AsvSdrHelper.GetTagValueAsString(RawValue,Type);

public override string ToString()
{
return Type switch
{
AsvSdrRecordTagType.AsvSdrRecordTagTypeUint64 => $"{Name}:{GetUint64()}",
AsvSdrRecordTagType.AsvSdrRecordTagTypeInt64 => $"{Name}:{GetInt64()}",
AsvSdrRecordTagType.AsvSdrRecordTagTypeReal64 => $"{Name}:{GetReal64()}",
AsvSdrRecordTagType.AsvSdrRecordTagTypeString8 => $"{Name}:{GetString()}",
_ => throw new ArgumentOutOfRangeException()
};
}
public override string ToString() => AsvSdrHelper.PrintTag(Name, Type, RawValue);

public void CopyTo(AsvSdrRecordTagPayload dest)
{
Expand Down
26 changes: 26 additions & 0 deletions src/Asv.Mavlink/Tools/MavlinkTypesHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@ public static void SetString(byte[] data,string value)
}
Encoding.ASCII.GetBytes(value,0,value.Length, data, 0);
}

public static void SetString(Span<byte> data,string value)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (value.IsNullOrWhiteSpace())
{
for (var i = 0; i < data.Length; i++)
{
data[i] = (byte)'\0';
}
return;
}
Encoding.ASCII.GetBytes(value,data);
}
public static void SetString(char[] data,string value)
{
if (data == null) throw new ArgumentNullException(nameof(data));
Expand Down Expand Up @@ -101,6 +115,18 @@ public static string GetString(byte[] data)
}
return sb.ToString();
}

public static string GetString(ReadOnlySpan<byte> data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
var sb = new StringBuilder(data.Length);
foreach (var _ in data)
{
if (_ == '\0') break;
sb.Append((char)_);
}
return sb.ToString();
}

public static GeoPoint FromInt32ToGeoPoint(int lat, int lon,float alt)
{
Expand Down

0 comments on commit 1e84265

Please sign in to comment.