Every MID in the library was rewritten to describe its data fields through attributes on the properties themselves, instead of building a Dictionary<int, List<DataField>> by hand and lazily converting values on every property access. Parsing now walks the package as a ReadOnlySpan<char> and writes the converted value straight into the property, and packing reads it back from there.
Breaking changes
Property type changes
| MID | Property | Before | After |
|---|---|---|---|
Mid0008 |
SubscriptionMid |
string |
int |
Mid0009 |
UnsubscriptionMid |
string |
int |
Mid0105, Mid0106, Mid0107 |
DataNumberSystem |
int |
long |
Mid1201 |
ResultDataIdentifier |
int |
long |
Mid1201 |
ResultStatus |
bool |
int |
MID 0008/0009 now expose the subscribed/unsubscribed MID as an int, matching the documentation (and matching Mid0006.RequestedMid, which was already an int).
Removed / changed members
Mid0702.ToolNumberwas removed — MID 0702 is answered from a MID 0006 request whose extra data carries the tool number, so it now lives inMid0702ExtraData.Mid0702.NumberOfToolParameters(read-only) became the settableNumberOfToolPIDs.DataField.String/Boolean/Timestamp/...factory methods now returnDataField<T>instead ofDataField. Source compatible when the result is assigned to aDataField, binary breaking.VariableDataField.ParseAllandOpenProtocolConvert.ToString(...)for variable data fields now work withList<VariableDataField>instead ofIEnumerable<VariableDataField>.
Custom MIDs inheriting from Mid
The parse/pack pipeline is span based, so MIDs that override it need their signatures adjusted:
ProcessDataFields(string)→ProcessDataFields(ReadOnlySpan<char>)(plus the new per-field hookProcessDataField(DataField, ReadOnlySpan<char>), which is usually what you want to override now)Pack(int revision, ref int prefixIndex)→Pack(int revision)Pack(List<DataField>, ref int prefixIndex)→Pack(IEnumerable<DataField>)GetValue(DataField, string)→GetValue(DataField, ReadOnlySpan<char>)
RegisterDatafields() is still virtual and still works exactly as before, so a custom MID written against the old style keeps working as long as it doesn't override the methods above.
Packaging
- The
netstandard2.0target now depends onSystem.Memory(4.5.5) forSpan<T>.
Improvements
- Changed way of parsing Mid properties, previously it would "lazy parse/convert" values at get/set, with this new way, the datafield is directly attached to the property and it is updated at the time the parsing happens. Reflection over the attributes happens once per MID type and is cached in a static dictionary; field registration itself became lazy, so a MID that is only constructed to be packed doesn't pay for it upfront.
- Added packing tests not only parsing which could make not testing setting properties — the suite went from 573 to 860 test methods (1202 test cases, all green), and several packing bugs surfaced because of it (see below).
- Revamped logos, updated badges and linking in the README.
- Parsing is span based end to end (
Header,Mid,DataField,OpenProtocolConvert), slicing the package instead of allocating substrings.netstandard2.0keeps the oldstringpath behind#if. Header.Parse(string)/Header.Parse(ReadOnlySpan<char>)are now public, so you can read the MID number, revision and length without going throughMidInterpreter(#118).- Added
OpenProtocolConvertoverloads forDateTimeOffset/unix timestamps and span inputs. - README largely rewritten accordingly with the newest update
New Features
- Added support to set a
DefaultEncodingproperty atMidand an overload atbyte[]methods (#117) - Added support to setting
Mid0006,Mid0008andMid0009Extra data based on pre build extra data, also, enabled to create your own withIExtraDataRequest,IExtraDataSubscriptionandIExtraDataUnsubscriptioninterfaces. (#104) Mid.GetField(string propertyName)andGetField<T>(int revision, int field)for the cases where a field's size only becomes known after another field has been read.
Bug fixes
- Fixed MID 0140 packing (the collection size wasn't being enforced before packing).
- Fixed parsing an enum-backed property through
Int32DataFieldDefinition— the underlying value wasn't being converted to the enum type. - Fixed the unix epoch calculation on
netstandard2.0, which has noDateTimeOffset.UnixEpoch. - Fixed data field counting/indexing on several MIDs where the field index was wrong or missing:
Mid0001,Mid0002,Mid0004,Mid0005,Mid0006,Mid0008,Mid0009,Mid0061,Mid0200,Mid0214,Mid0215,Mid0251,Mid0254,Mid0255,Mid0265,Mid0401,Mid0411.
Mids updates
- New
Mid2502(password request) - New
Mid2503(password response). - MIDs updated to specification 2.18.0:
Mid0001/Mid0002(OptionalKeepAlive,OptionalToolLockAtDisconnection,OptionalEarlyLock,StationCellId)Mid0045(ExtendedCalibrationValue,TransducerNumber)Mid0065- New
ToolTypevalues (XPBM,ExBC,ExD).
Mid0015Mid0035Mid0061Mid0065(JointId,SelectedIdentifierNumber,NumberOfStagesInMultistage,NumberOfStageResults).PIDRestrictiontype added forMid0704.
Funding
Added .github/FUNDING.yml with GitHub Sponsors and Buy Me a Coffee (rickedb on both), so the repository shows the "Sponsor" button. This project has been maintained on free time for years — if it saves you or your company some of it, that button is now there. It changes nothing about the license or the roadmap: the library stays MIT and issues/PRs are handled the same way.