Closed smremde closed 6 years ago
Yikes. I have considered adding something-other-than-null terminated string support. Maybe that would be appropriate. But let me play around with it. These mixed ascii/bin protocols are deadly and sometimes there’s just no good way to cleanly support them.
— Planning for failure is even dumber than regular planning
From: Stephen Remde notifications@github.com Sent: Thursday, November 2, 2017 7:00:59 AM To: jefffhaynes/BinarySerializer Cc: Subscribed Subject: [jefffhaynes/BinarySerializer] Advice on approach (#76)
Hi,
I'm trying to use this package to interface with Sick Lidars. The protocol is a weird mashup of the an ASCII and binary protocol and wanted some advice.
The protocol specification is here:
The issue is that the packet type is a two strings (0x20 terminated!) one fixed length and one variable length
[image]https://user-images.githubusercontent.com/986075/32322218-a88f2322-bfbb-11e7-8cba-c395c55cf6f8.png
I initially started with
public class Packet { // header 02020202 ignored for sycing [FieldOrder(1)] public uint Length { get; set; }
[FieldOrder(2)]
[FieldLength("Length")]
[FieldChecksum("Checksum", Mode = ChecksumMode.Xor)]
public PacketContent Content { get; set; }
[FieldOrder(3)]
public byte Checksum { get; set; }
}
public class PacketContent { [FieldOrder(0)] [FieldLength(4)] public MessageType MessageType { get; set; }
[FieldOrder(1)]
[SerializeUntil((byte)20)]
public string MessageSubType { get; set; }
[FieldOrder(2)]
[Subtype("MessageType", "SetAccessMode", typeof(sMN_SetAccessMode))]
public PacketPayload Payload { get; set; }
}
public enum MessageType { [SerializeAsEnum("sRN ")] sRN, [SerializeAsEnum("sWN ")] sWN, [SerializeAsEnum("sMN ")] sMN, [SerializeAsEnum("sEN ")] sEN, [SerializeAsEnum("sRA ")] sRA, [SerializeAsEnum("sWA ")] sWA, [SerializeAsEnum("sEA ")] sEA, [SerializeAsEnum("sSN ")] sSN, }
,
But actually, the subtype depends on both fields here.
Also, using when serialising an field with the attribute [SerializeUntil((byte)20)] the string is null terminated.
Any advice?
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/jefffhaynes/BinarySerializer/issues/76, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AJSKR_DzAYFxVMUJ7JXGOxSSNtct1kDuks5syaDqgaJpZM4QPgbD.
My approach has been to Implement an IBinarySerializable
public class PacketType : IBinarySerializable
{
[Ignore]
public string Type { get; set; }
public PacketType()
{
}
public PacketType(string type)
{
Type = type;
}
public void Deserialize(Stream stream, Endianness endianness, BinarySerializationContext serializationContext)
{
StringBuilder sb = new StringBuilder();
var spacecount = 0;
while (spacecount <2)
{
var b = stream.ReadByte();
if (b == -1)
throw new InvalidOperationException("Reached end of stream before end of PacketType.");
if (b == 0x20)
spacecount++;
sb.Append((char)b);
}
Type = sb.ToString();
}
public void Serialize(Stream stream, Endianness endianness, BinarySerializationContext serializationContext)
{
var bytes = new ASCIIEncoding().GetBytes(Type);
stream.Write(bytes, 0, bytes.Length);
}
public override bool Equals(object obj)
{
var other = obj as PacketType;
return (other != null && other.Type == Type) || obj.ToString() == Type;
}
public override int GetHashCode()
{
return Type.GetHashCode();
}
}
I have overridden the equals to implement string comparison so the subtype will work on the parent class:
public class PacketContent
{
[FieldOrder(0)]
public PacketType PacketType { get; set; }
[FieldOrder(1)]
[Subtype("PacketType", "sMN SetAccessMode ", typeof(sMN_SetAccessMode))]
[Subtype("PacketType", "sAN SetAccessMode ", typeof(sAN_SetAccessMode))]
[Subtype("PacketType", "sMN mLMPsetscancfg ", typeof(sMN_mLMPsetscancfg))]
public PacketPayload Payload { get; set; }
}
This unfortunately means I need to populate PacketType
manually
ser.Serialize(ms, new Packet
{
Content = new PacketContent
{
PacketType = new PacketType("sMN SetAccessMode "),
Payload = new sMN_SetAccessMode
{
UserLevel = UserLevel.AuthorizedClient,
Password= 0xF4724744
}
}
});
Do you see a work around for this?
I'm going to add support for non-null string terminators and see where that gets us
Requires 7.6:
public enum CommandClass
{
[SerializeAsEnum("sRN")]
Srn,
[SerializeAsEnum("sWN")]
Swn,
[SerializeAsEnum("sMN")]
Smn,
[SerializeAsEnum("sEN")]
Sen,
[SerializeAsEnum("sRA")]
Sra,
[SerializeAsEnum("sWA")]
Swa,
[SerializeAsEnum("sEA")]
Sea,
[SerializeAsEnum("sSN")]
Ssn
}
public enum CommandType
{
SetAccessMode,
[SerializeAsEnum("mLMPsetscancfg")]
SetScanConfig,
[SerializeAsEnum("LMDscandatacfg")]
ScanDataConfig
// etc
}
public class Packet
{
[FieldOrder(0)]
public uint Length { get; set; }
[FieldOrder(1)]
[FieldLength("Length")]
[FieldChecksum("Checksum", Mode = ChecksumMode.Xor)]
public PacketContent Content { get; set; }
[FieldOrder(2)]
public byte Checksum { get; set; }
}
public class PacketContent
{
[FieldOrder(0)]
[SerializeAs(SerializedType.TerminatedString, StringTerminator = 0x20)]
public CommandClass CommandClass { get; set; }
[FieldOrder(1)]
[Subtype("CommandClass", CommandClass.Smn, typeof(SmnCommandContainer))]
public CommandContainer Payload { get; set; }
}
public abstract class CommandContainer
{
[SerializeAs(SerializedType.TerminatedString, StringTerminator = 0x20)]
public CommandType CommandType { get; set; }
}
public class SmnCommandContainer : CommandContainer
{
[Subtype("CommandType", CommandType.SetAccessMode, typeof(SetAccessModeCommand))]
public Command Command { get; set; }
}
public abstract class Command
{
}
public enum UserLevel : byte
{
AuthorizedClient = 0x3
}
public class SetAccessModeCommand : Command
{
[FieldOrder(0)]
public UserLevel UserLevel { get; set; } = UserLevel.AuthorizedClient;
[FieldOrder(1)]
[FieldLength(4)]
public byte[] Password { get; set; } = { 0xF4, 0x72, 0x47, 0x44 };
}
The key here is using a different class for the command "class" vs the specific command. That plus the new terminator thing makes it pretty straightforward.
Added this as a test.
Hi,
I'm trying to use this package to interface with Sick Lidars. The protocol is a weird mashup of the an ASCII and binary protocol and wanted some advice.
The protocol specification is here:
https://www.sick.com/media/docs/7/27/927/Technical_information_Telegram_Listing_Ranging_sensors_LMS1xx_LMS5xx_TiM5xx_NAV310_LD_OEM15xx_LD_LRS36xx_en_IM0045927.PDF
The issue is that the packet type is a two strings (0x20 terminated!) one fixed length and one variable length
I initially started with
,
But actually, the subtype depends on both fields here.
Also, using when serialising an field with the attribute [SerializeUntil((byte)20)] the string is null terminated.
Any advice?