From ad5563ffc8cfe4876fcf5e3eed0432869fa0e3ea Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sun, 6 Oct 2024 11:04:52 +0200 Subject: [PATCH 01/12] wip --- Tests/EDSMappingTests.cs | 50 +++++++ libEDSsharp/CanOpenEDSMapping.cs | 233 +++++++++++++++++++++++++++++++ libEDSsharp/libEDSsharp.csproj | 1 + 3 files changed, 284 insertions(+) create mode 100644 Tests/EDSMappingTests.cs create mode 100644 libEDSsharp/CanOpenEDSMapping.cs diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs new file mode 100644 index 0000000..2053861 --- /dev/null +++ b/Tests/EDSMappingTests.cs @@ -0,0 +1,50 @@ +using Xunit; +using libEDSsharp; +using LibCanOpen; +using System.Linq; + +namespace Tests +{ + public class EDSMappingTests + { + [Fact] + public void Test_ToProtobufferAssertConfig() + { + var eds = new EDSsharp(); + eds.ods = new System.Collections.Generic.SortedDictionary(); + ODentry od = new ODentry + { + objecttype = ObjectType.VAR, + parameter_name = "Test REC", + Index = 0x2000 + }; + + ODentry sub = new ODentry(); + sub.parameter_name = "some value"; + sub.datatype = DataType.UNSIGNED8; + sub.parent = od; + sub.accesstype = EDSsharp.AccessType.ro; + sub.defaultvalue = "1"; + sub.PDOtype = PDOMappingType.no; + sub.objecttype = ObjectType.VAR; + + od.subobjects.Add(0x00, sub); + eds.ods.Add(0x2000, od); + + //Assert is called inside the map function + var tmp = MappingEDS.MapToProtobuffer(eds); + } + [Fact] + public void Test_FromProtobufferAssertConfig() + { + var d = new CanOpenDevice(); + d.FileInfo = new CanOpen_FileInfo(); + d.DeviceInfo = new CanOpen_DeviceInfo(); + d.DeviceCommissioning = new CanOpen_DeviceCommissioning(); + + //Assert is called inside the map function + var tmp = MappingEDS.MapFromProtobuffer(d); + + } + } +} diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs new file mode 100644 index 0000000..a9100e0 --- /dev/null +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -0,0 +1,233 @@ +/* + This file is part of libEDSsharp. + + libEDSsharp is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + libEDSsharp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libEDSsharp. If not, see . + + Copyright(c) 2024 Lars E. Susaas +*/ + +using AutoMapper; +using Google.Protobuf.WellKnownTypes; +using LibCanOpen; +using libEDSsharp; +using System; +using System.Globalization; +using System.Linq; + +namespace libEDSsharp +{ + /// + /// Conversion class to/from EDS to protobuffer + /// + public class MappingEDS + { + /// + /// Converts from protobuffer to EDS + /// + /// protobuffer device + /// new EDS device containing data from protobuffer device + public static EDSsharp MapFromProtobuffer(CanOpenDevice source) + { + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.Dirty, opt => opt.Ignore()) + .ForMember(dest => dest.xddfilename_1_1, opt => opt.Ignore()) + .ForMember(dest => dest.xddfilenameStripped, opt => opt.Ignore()) + .ForMember(dest => dest.edsfilename, opt => opt.Ignore()) + .ForMember(dest => dest.dcffilename, opt => opt.Ignore()) + .ForMember(dest => dest.ODfilename, opt => opt.Ignore()) + .ForMember(dest => dest.ODfileVersion, opt => opt.Ignore()) + .ForMember(dest => dest.mdfilename, opt => opt.Ignore()) + .ForMember(dest => dest.xmlfilename, opt => opt.Ignore()) + .ForMember(dest => dest.xddfilename_1_0, opt => opt.Ignore()) + .ForMember(dest => dest.xddTemplate, opt => opt.Ignore()) + .ForMember(dest => dest.dummy_ods, opt => opt.Ignore()) + .ForMember(dest => dest.CO_storageGroups, opt => opt.Ignore()) + .ForMember(dest => dest.md, opt => opt.Ignore()) + .ForMember(dest => dest.oo, opt => opt.Ignore()) + .ForMember(dest => dest.mo, opt => opt.Ignore()) + .ForMember(dest => dest.c, opt => opt.Ignore()) + .ForMember(dest => dest.du, opt => opt.Ignore()) + .ForMember(dest => dest.td, opt => opt.Ignore()) + .ForMember(dest => dest.sm, opt => opt.Ignore()) + .ForMember(dest => dest.cm, opt => opt.Ignore()) + .ForMember(dest => dest.modules, opt => opt.Ignore()) + .ForMember(dest => dest.NodeID, opt => opt.Ignore()) + .ForMember(dest => dest.projectFilename, opt => opt.MapFrom(src => src.DeviceInfo.ProductName)) + .ForMember(dest => dest.NodeID, opt => opt.MapFrom(src => src.DeviceCommissioning.NodeId)) + .ForMember(dest => dest.fi, opt => opt.MapFrom(src => src.FileInfo)) + .ForMember(dest => dest.di, opt => opt.MapFrom(src => src.DeviceInfo)) + .ForMember(dest => dest.dc, opt => opt.MapFrom(src => src.DeviceCommissioning)) + .ForMember(dest => dest.ods, opt => opt.MapFrom(src => src.Objects)); + cfg.CreateMap() + .ForMember(dest => dest.FileName, opt => opt.Ignore()) + .ForMember(dest => dest.LastEDS, opt => opt.Ignore()) + .ForMember(dest => dest.EDSVersionMajor, opt => opt.Ignore()) + .ForMember(dest => dest.EDSVersionMinor, opt => opt.Ignore()) + .ForMember(dest => dest.EDSVersion, opt => opt.Ignore()) + .ForMember(dest => dest.exportFolder, opt => opt.Ignore()) + .ForMember(dest => dest.FileRevision, opt => opt.MapFrom(src => (byte)src.FileVersion.ElementAtOrDefault(0))) + .ForMember(dest => dest.CreationDateTime, opt => opt.MapFrom(src => src.CreationTime.ToDateTime())) + .ForMember(dest => dest.CreationDate, opt => opt.MapFrom(src => src.CreationTime.ToDateTime().ToString("MM-dd-yyyy"))) + .ForMember(dest => dest.CreationTime, opt => opt.MapFrom(src => src.CreationTime.ToDateTime().ToString("h:mmtt"))) + .ForMember(dest => dest.ModificationDateTime, opt => opt.MapFrom(src => src.ModificationTime.ToDateTime())) + .ForMember(dest => dest.ModificationDate, opt => opt.MapFrom(src => src.ModificationTime.ToDateTime().ToString("MM-dd-yyyy"))) + .ForMember(dest => dest.ModificationTime, opt => opt.MapFrom(src => src.ModificationTime.ToDateTime().ToString("h:mmtt"))); + cfg.CreateMap() + .ForMember(dest => dest.VendorNumber, opt => opt.Ignore()) + .ForMember(dest => dest.ProductNumber, opt => opt.Ignore()) + .ForMember(dest => dest.RevisionNumber, opt => opt.Ignore()) + .ForMember(dest => dest.SimpleBootUpMaster, opt => opt.Ignore()) + .ForMember(dest => dest.SimpleBootUpSlave, opt => opt.Ignore()) + .ForMember(dest => dest.Granularity, opt => opt.Ignore()) + .ForMember(dest => dest.DynamicChannelsSupported, opt => opt.Ignore()) + .ForMember(dest => dest.CompactPDO, opt => opt.Ignore()) + .ForMember(dest => dest.GroupMessaging, opt => opt.Ignore()) + .ForMember(dest => dest.NrOfRXPDO, opt => opt.Ignore()) // TODO Calculate this + .ForMember(dest => dest.NrOfTXPDO, opt => opt.Ignore()) // TODO Calculate this + .ForMember(dest => dest.LSS_Supported, opt => opt.MapFrom(src => src.LssSlave)) + .ForMember(dest => dest.LSS_Master, opt => opt.MapFrom(src => src.LssMaster)) + .ForMember(dest => dest.NG_Slave, opt => opt.Ignore()) + .ForMember(dest => dest.NG_Master, opt => opt.Ignore()) + .ForMember(dest => dest.NrOfNG_MonitoredNodes, opt => opt.Ignore()); + cfg.CreateMap() + .ForMember(dest => dest.NetNumber, opt => opt.Ignore()) + .ForMember(dest => dest.NetworkName, opt => opt.Ignore()) + .ForMember(dest => dest.CANopenManager, opt => opt.Ignore()) + .ForMember(dest => dest.LSS_SerialNumber, opt => opt.Ignore()); + }); + config.AssertConfigurationIsValid(); + var mapper = config.CreateMapper(); + return mapper.Map(source); + } + /// + /// Converts from EDS to protobuffer + /// + /// EDS device + /// protobuffer device containing data from EDS + public static CanOpenDevice MapToProtobuffer(EDSsharp source) + { + var config = new MapperConfiguration(cfg => + { + cfg.CreateMap() + .ForMember(dest => dest.FileInfo, opt => opt.MapFrom(src => src.fi)) + .ForMember(dest => dest.DeviceInfo, opt => opt.MapFrom(src => src.di)) + .ForMember(dest => dest.DeviceCommissioning, opt => opt.MapFrom(src => src.dc)) + .ForMember(dest => dest.Objects, opt => opt.MapFrom(src => src.ods)); + cfg.CreateMap() + .ForMember(dest => dest.CreationTime, opt => opt.MapFrom(new EDSDateAndTimeResolver("creation"))) + .ForMember(dest => dest.ModificationTime, opt => opt.MapFrom(new EDSDateAndTimeResolver("modification"))); + cfg.CreateMap() + .ForMember(dest => dest.BaudRate10, opt => opt.MapFrom(src => src.BaudRate_10)) + .ForMember(dest => dest.BaudRate20, opt => opt.MapFrom(src => src.BaudRate_20)) + .ForMember(dest => dest.BaudRate50, opt => opt.MapFrom(src => src.BaudRate_50)) + .ForMember(dest => dest.BaudRate125, opt => opt.MapFrom(src => src.BaudRate_125)) + .ForMember(dest => dest.BaudRate250, opt => opt.MapFrom(src => src.BaudRate_250)) + .ForMember(dest => dest.BaudRate500, opt => opt.MapFrom(src => src.BaudRate_500)) + .ForMember(dest => dest.BaudRate800, opt => opt.MapFrom(src => src.BaudRate_800)) + .ForMember(dest => dest.BaudRate1000, opt => opt.MapFrom(src => src.BaudRate_1000)) + .ForMember(dest => dest.BaudRateAuto, opt => opt.MapFrom(src => src.BaudRate_auto)) + .ForMember(dest => dest.LssSlave, opt => opt.MapFrom(src => src.LSS_Supported)) + .ForMember(dest => dest.LssMaster, opt => opt.MapFrom(src => src.LSS_Master)); + cfg.CreateMap(); + cfg.CreateMap() + .ForMember(dest => dest.Disabled, opt => opt.Ignore()) + .ForMember(dest => dest.Alias, opt => opt.Ignore()) + .ForMember(dest => dest.StorageGroup, opt => opt.Ignore()) + .ForMember(dest => dest.FlagsPDO, opt => opt.Ignore()) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) + .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.objecttype)) + .ForMember(dest => dest.CountLabel, opt => opt.MapFrom(src => src.Label)); + cfg.CreateMap() + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) + .ForMember(dest => dest.Alias, opt => opt.Ignore()) + .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.datatype)) + .ForMember(dest => dest.Sdo, opt => opt.MapFrom(src => src.AccessSDO())) + .ForMember(dest => dest.Pdo, opt => opt.MapFrom(src => src.AccessPDO())) + .ForMember(dest => dest.Srdo, opt => opt.Ignore()) + .ForMember(dest => dest.StringLengthMin, opt => opt.MapFrom(src => src.Lengthofstring)); + }); + + config.AssertConfigurationIsValid(); + var mapper = config.CreateMapper(); + return mapper.Map(source); + } + } +} + +/// +/// Helper class to convert EDS date and time into datetime used in the protobuffer timestand (datetime) +/// +public class EDSDateAndTimeResolver : IValueResolver +{ + string _type; + public EDSDateAndTimeResolver(string type) + { + _type = type; + } + /// + /// Resolver to convert eds date and time into protobuffer timestamp (datetime) + /// + /// source EDS fileinfo object + /// protobuffer fileinfo object + /// result object + /// resolve context + /// result + public Timestamp Resolve(FileInfo source, CanOpen_FileInfo destination, Timestamp member, ResolutionContext context) + { + string strTime; + string strDate; + if(_type == "creation") + { + strDate = source.CreationDate; + strTime = source.CreationTime; + } + else + { + strDate = source.ModificationDate; + strTime = source.ModificationTime; + } + + var time = new DateTime(0); + var date = new DateTime(0); + + try + { + time = DateTime.ParseExact(strTime, "h:mmtt", CultureInfo.InvariantCulture); + } + catch (Exception e) + { + if (e is FormatException) + { + //Silently ignore + } + } + + try + { + date = DateTime.ParseExact(strDate, "MM-dd-yyyy", CultureInfo.InvariantCulture); + } + catch (Exception e) + { + if (e is FormatException) + { + //Silently ignore + } + } + + var datetime = date.AddTicks(time.TimeOfDay.Ticks); + return Timestamp.FromDateTime(datetime.ToUniversalTime()); + } +} diff --git a/libEDSsharp/libEDSsharp.csproj b/libEDSsharp/libEDSsharp.csproj index 767f8e7..8ea791b 100644 --- a/libEDSsharp/libEDSsharp.csproj +++ b/libEDSsharp/libEDSsharp.csproj @@ -47,6 +47,7 @@ + From 2c75776de63feba17b786419bd878ddb5056e717 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sat, 16 Nov 2024 17:46:41 +0100 Subject: [PATCH 02/12] More tests and some fixes --- Tests/EDSMappingTests.cs | 269 ++++++++++++++++++++++++++++--- Tests/EDSParserTests.cs | 12 +- libEDSsharp/CanOpenEDSMapping.cs | 135 ++++++++++------ 3 files changed, 345 insertions(+), 71 deletions(-) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index 2053861..70ef3ec 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -1,7 +1,9 @@ using Xunit; using libEDSsharp; using LibCanOpen; -using System.Linq; +using System.Globalization; +using System; +using Google.Protobuf.WellKnownTypes; namespace Tests { @@ -10,41 +12,272 @@ public class EDSMappingTests [Fact] public void Test_ToProtobufferAssertConfig() { - var eds = new EDSsharp(); - eds.ods = new System.Collections.Generic.SortedDictionary(); - ODentry od = new ODentry + var eds = new EDSsharp + { + ods = new System.Collections.Generic.SortedDictionary() + }; + var od = new ODentry { objecttype = ObjectType.VAR, parameter_name = "Test REC", Index = 0x2000 }; - ODentry sub = new ODentry(); - sub.parameter_name = "some value"; - sub.datatype = DataType.UNSIGNED8; - sub.parent = od; - sub.accesstype = EDSsharp.AccessType.ro; - sub.defaultvalue = "1"; - sub.PDOtype = PDOMappingType.no; - sub.objecttype = ObjectType.VAR; + var sub = new ODentry + { + parameter_name = "some value", + datatype = DataType.UNSIGNED8, + parent = od, + accesstype = EDSsharp.AccessType.ro, + defaultvalue = "1", + PDOtype = PDOMappingType.no, + objecttype = ObjectType.VAR + }; od.subobjects.Add(0x00, sub); eds.ods.Add(0x2000, od); //Assert is called inside the map function - var tmp = MappingEDS.MapToProtobuffer(eds); + MappingEDS.MapToProtobuffer(eds); } [Fact] public void Test_FromProtobufferAssertConfig() { - var d = new CanOpenDevice(); - d.FileInfo = new CanOpen_FileInfo(); - d.DeviceInfo = new CanOpen_DeviceInfo(); - d.DeviceCommissioning = new CanOpen_DeviceCommissioning(); + var d = new CanOpenDevice + { + FileInfo = new CanOpen_FileInfo(), + DeviceInfo = new CanOpen_DeviceInfo(), + DeviceCommissioning = new CanOpen_DeviceCommissioning() + }; //Assert is called inside the map function - var tmp = MappingEDS.MapFromProtobuffer(d); + MappingEDS.MapFromProtobuffer(d); + } + [Fact] + public void Test_ToProtobufferFileInfo() + { + var eds = new EDSsharp + { + fi = new FileInfo + { + CreatedBy = "CreatedBy", + CreationDate = "01-20-2000", + CreationTime = "12:20am", + Description = "Description", + FileRevision = (byte)'A', + FileVersion = "1.0.0", + ModificationDate = "02-10-1000", + ModificationTime = "12:20pm", + ModifiedBy = "ModifiedBy" + } + }; + + var creationDateTime = DateTime.ParseExact($"{eds.fi.CreationTime} {eds.fi.CreationDate}", "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); + var modificationDateTime = DateTime.ParseExact($"{eds.fi.ModificationTime} {eds.fi.ModificationDate}", "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); + var creationTimestamp = Timestamp.FromDateTime(creationDateTime.ToUniversalTime()); + var modificationTimestamp = Timestamp.FromDateTime(modificationDateTime.ToUniversalTime()); + + var tmp = MappingEDS.MapToProtobuffer(eds); + Assert.Equal(eds.fi.CreatedBy, tmp.FileInfo.CreatedBy); + Assert.Equal(creationTimestamp, tmp.FileInfo.CreationTime); + Assert.Equal(eds.fi.Description, tmp.FileInfo.Description); + Assert.Equal(eds.fi.FileVersion, tmp.FileInfo.FileVersion); + Assert.Equal(eds.fi.ModifiedBy, tmp.FileInfo.ModifiedBy); + Assert.Equal(modificationTimestamp, tmp.FileInfo.ModificationTime); + } + [Fact] + public void Test_ToProtobufferDeviceInfo() + { + var eds = new EDSsharp + { + di = new DeviceInfo + { + BaudRate_10 = true, + BaudRate_20 = false, + BaudRate_50 = true, + BaudRate_125 = false, + BaudRate_250 = true, + BaudRate_500 = false, + BaudRate_800 = true, + BaudRate_1000 = false, + BaudRate_auto = true, + LSS_Master = false, + LSS_Supported = true, + VendorName = "VendorName", + ProductName = "ProductName" + } + }; + + var tmp = MappingEDS.MapToProtobuffer(eds); + Assert.Equal(eds.di.BaudRate_10, tmp.DeviceInfo.BaudRate10); + Assert.Equal(eds.di.BaudRate_20, tmp.DeviceInfo.BaudRate20); + Assert.Equal(eds.di.BaudRate_50, tmp.DeviceInfo.BaudRate50); + Assert.Equal(eds.di.BaudRate_125, tmp.DeviceInfo.BaudRate125); + Assert.Equal(eds.di.BaudRate_250, tmp.DeviceInfo.BaudRate250); + Assert.Equal(eds.di.BaudRate_500, tmp.DeviceInfo.BaudRate500); + Assert.Equal(eds.di.BaudRate_800, tmp.DeviceInfo.BaudRate800); + Assert.Equal(eds.di.BaudRate_1000, tmp.DeviceInfo.BaudRate1000); + Assert.Equal(eds.di.BaudRate_auto, tmp.DeviceInfo.BaudRateAuto); + Assert.Equal(eds.di.LSS_Master, tmp.DeviceInfo.LssMaster); + Assert.Equal(eds.di.LSS_Supported, tmp.DeviceInfo.LssSlave); + Assert.Equal(eds.di.VendorName, tmp.DeviceInfo.VendorName); + Assert.Equal(eds.di.ProductName, tmp.DeviceInfo.ProductName); + } + [Fact] + public void Test_ToProtobufferDeviceCommissioning() + { + var eds = new EDSsharp + { + dc = new DeviceCommissioning + { + NodeID = 123, + NodeName = "NodeName", + Baudrate = 456, + } + }; + + var tmp = MappingEDS.MapToProtobuffer(eds); + Assert.Equal(eds.dc.NodeID, tmp.DeviceCommissioning.NodeId); + Assert.Equal(eds.dc.NodeName, tmp.DeviceCommissioning.NodeName); + Assert.Equal(eds.dc.Baudrate, tmp.DeviceCommissioning.Baudrate); + } + [Theory] + [InlineData(OdObject.Types.ObjectType.Array, ObjectType.ARRAY)] + [InlineData(OdObject.Types.ObjectType.Record, ObjectType.RECORD)] + [InlineData(OdObject.Types.ObjectType.Var, ObjectType.VAR)] + [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.DEFSTRUCT)] + [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.DEFTYPE)] + [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.DOMAIN)] + [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.NULL)] + [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.UNKNOWN)] + void Test_ToProtobufferODObject(OdObject.Types.ObjectType objTypeProto, ObjectType objTypeEDS) + { + var eds = new EDSsharp + { + ods = new System.Collections.Generic.SortedDictionary() + }; + var od = new ODentry + { + objecttype = objTypeEDS, + parameter_name = "parameter name", + Index = 0x2000 + }; + eds.ods.Add(od.Index, od); + var tmp = MappingEDS.MapToProtobuffer(eds); + Assert.Equal(objTypeProto, tmp.Objects[od.Index.ToString()].Type); + } + + [Theory] + [InlineData(OdSubObject.Types.DataType.Unspecified, DataType.UNKNOWN)] + [InlineData(OdSubObject.Types.DataType.Boolean, DataType.BOOLEAN)] + [InlineData(OdSubObject.Types.DataType.Integer8, DataType.INTEGER8)] + [InlineData(OdSubObject.Types.DataType.Integer16, DataType.INTEGER16)] + [InlineData(OdSubObject.Types.DataType.Integer32, DataType.INTEGER32)] + [InlineData(OdSubObject.Types.DataType.Unsigned8, DataType.UNSIGNED8)] + [InlineData(OdSubObject.Types.DataType.Unsigned16, DataType.UNSIGNED16)] + [InlineData(OdSubObject.Types.DataType.Unsigned32, DataType.UNSIGNED32)] + [InlineData(OdSubObject.Types.DataType.Real32, DataType.REAL32)] + [InlineData(OdSubObject.Types.DataType.VisibleString, DataType.VISIBLE_STRING)] + [InlineData(OdSubObject.Types.DataType.OctetString, DataType.OCTET_STRING)] + [InlineData(OdSubObject.Types.DataType.UnicodeString, DataType.UNICODE_STRING)] + [InlineData(OdSubObject.Types.DataType.TimeOfDay, DataType.TIME_OF_DAY)] + [InlineData(OdSubObject.Types.DataType.TimeDifference, DataType.TIME_DIFFERENCE)] + [InlineData(OdSubObject.Types.DataType.Domain, DataType.DOMAIN)] + [InlineData(OdSubObject.Types.DataType.Integer24, DataType.INTEGER24)] + [InlineData(OdSubObject.Types.DataType.Real64, DataType.REAL64)] + [InlineData(OdSubObject.Types.DataType.Integer40, DataType.INTEGER40)] + [InlineData(OdSubObject.Types.DataType.Integer48, DataType.INTEGER48)] + [InlineData(OdSubObject.Types.DataType.Integer56, DataType.INTEGER56)] + [InlineData(OdSubObject.Types.DataType.Integer64, DataType.INTEGER64)] + [InlineData(OdSubObject.Types.DataType.Unsigned24, DataType.UNSIGNED24)] + [InlineData(OdSubObject.Types.DataType.Unsigned40, DataType.UNSIGNED40)] + [InlineData(OdSubObject.Types.DataType.Unsigned48, DataType.UNSIGNED48)] + [InlineData(OdSubObject.Types.DataType.Unsigned56, DataType.UNSIGNED56)] + [InlineData(OdSubObject.Types.DataType.Unsigned64, DataType.UNSIGNED64)] + void Test_ToProtobufferSubODObjectDatatype(OdSubObject.Types.DataType datatypeProto, DataType datatypeEDS) + { + var eds = new EDSsharp + { + ods = new System.Collections.Generic.SortedDictionary() + }; + var od = new ODentry + { + objecttype = ObjectType.RECORD, + Index = 0x2000 + }; + var sub = new ODentry + { + datatype = datatypeEDS, + parent = od, + }; + od.subobjects.Add(0x00, sub); + eds.ods.Add(od.Index, od); + var tmp = MappingEDS.MapToProtobuffer(eds); + Assert.Equal(datatypeProto, tmp.Objects[od.Index.ToString()].SubObjects["0"].Type); + } + [Theory] + [InlineData(OdSubObject.Types.AccessPDO.Tr, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rw)] + [InlineData(OdSubObject.Types.AccessPDO.T, OdSubObject.Types.AccessSDO.Ro, EDSsharp.AccessType.ro)] + [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Wo, EDSsharp.AccessType.wo)] + [InlineData(OdSubObject.Types.AccessPDO.T, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rwr)] + [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rww)] + [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Ro, EDSsharp.AccessType.@const)] + [InlineData(OdSubObject.Types.AccessPDO.No, OdSubObject.Types.AccessSDO.No, EDSsharp.AccessType.UNKNOWN)] + void Test_ToProtobufferSubODObjectAccesstype(OdSubObject.Types.AccessPDO accessPDOProto, OdSubObject.Types.AccessSDO accessSDOProto, EDSsharp.AccessType datatypeEDS) + { + var eds = new EDSsharp + { + ods = new System.Collections.Generic.SortedDictionary() + }; + var od = new ODentry + { + objecttype = ObjectType.RECORD, + Index = 0x2000 + }; + var sub = new ODentry + { + parent = od, + accesstype = datatypeEDS, + PDOtype = PDOMappingType.no, + }; + + od.subobjects.Add(0x00, sub); + eds.ods.Add(od.Index, od); + var tmp = MappingEDS.MapToProtobuffer(eds); + Assert.Equal(accessPDOProto, tmp.Objects[od.Index.ToString()].SubObjects["0"].Pdo); + Assert.Equal(accessSDOProto, tmp.Objects[od.Index.ToString()].SubObjects["0"].Sdo); + } + [Fact] + public void Test_ToProtobufferSubODObjectMembers() + { + var eds = new EDSsharp + { + ods = new System.Collections.Generic.SortedDictionary() + }; + var od = new ODentry + { + objecttype = ObjectType.RECORD, + Index = 0x2000 + }; + var sub = new ODentry + { + parent = od, + actualvalue = "123", + parameter_name = "parameter_name", + HighLimit = "HighLimit", + LowLimit = "LowLimit", + defaultvalue = "defaultvalue", + }; + + od.subobjects.Add(0x00, sub); + eds.ods.Add(od.Index, od); + var tmp = MappingEDS.MapToProtobuffer(eds); + Assert.Equal(sub.actualvalue, tmp.Objects[od.Index.ToString()].SubObjects["0"].ActualValue); + Assert.Equal(sub.parameter_name, tmp.Objects[od.Index.ToString()].SubObjects["0"].Name); + Assert.Equal(sub.HighLimit, tmp.Objects[od.Index.ToString()].SubObjects["0"].HighLimit); + Assert.Equal(sub.LowLimit, tmp.Objects[od.Index.ToString()].SubObjects["0"].LowLimit); + Assert.Equal(sub.defaultvalue, tmp.Objects[od.Index.ToString()].SubObjects["0"].DefaultValue); } } } diff --git a/Tests/EDSParserTests.cs b/Tests/EDSParserTests.cs index 917f6eb..a1919b3 100644 --- a/Tests/EDSParserTests.cs +++ b/Tests/EDSParserTests.cs @@ -336,16 +336,20 @@ public void Test_datetimeparse() public void Test_accesstype() { { - Dictionary> section = new Dictionary>(); - section.Add("[1234]", new Dictionary()); + Dictionary> section = new Dictionary> + { + { "[1234]", new Dictionary() } + }; section["[1234]"].Add("AccessType", "ro"); KeyValuePair> kvp = section.Single(); this.ParseEDSentry(kvp); } { - Dictionary> section = new Dictionary>(); - section.Add("[1234]", new Dictionary()); + Dictionary> section = new Dictionary> + { + { "[1234]", new Dictionary() } + }; section["[1234]"].Add("AccessType", "RO"); KeyValuePair> kvp = section.Single(); this.ParseEDSentry(kvp); diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index a9100e0..93641aa 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -20,7 +20,6 @@ You should have received a copy of the GNU General Public License using AutoMapper; using Google.Protobuf.WellKnownTypes; using LibCanOpen; -using libEDSsharp; using System; using System.Globalization; using System.Linq; @@ -150,6 +149,7 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.objecttype)) .ForMember(dest => dest.CountLabel, opt => opt.MapFrom(src => src.Label)); + cfg.CreateMap().ConvertUsing(); cfg.CreateMap() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) .ForMember(dest => dest.Alias, opt => opt.Ignore()) @@ -165,69 +165,106 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) return mapper.Map(source); } } -} -/// -/// Helper class to convert EDS date and time into datetime used in the protobuffer timestand (datetime) -/// -public class EDSDateAndTimeResolver : IValueResolver -{ - string _type; - public EDSDateAndTimeResolver(string type) - { - _type = type; - } + /// - /// Resolver to convert eds date and time into protobuffer timestamp (datetime) + /// Helper class to convert EDS date and time into datetime used in the protobuffer timestand (datetime) /// - /// source EDS fileinfo object - /// protobuffer fileinfo object - /// result object - /// resolve context - /// result - public Timestamp Resolve(FileInfo source, CanOpen_FileInfo destination, Timestamp member, ResolutionContext context) + public class EDSDateAndTimeResolver : IValueResolver { - string strTime; - string strDate; - if(_type == "creation") + private readonly string _type; + public EDSDateAndTimeResolver(string type) { - strDate = source.CreationDate; - strTime = source.CreationTime; + _type = type; } - else + /// + /// Resolver to convert eds date and time into protobuffer timestamp (datetime) + /// + /// source EDS fileinfo object + /// protobuffer fileinfo object + /// result object + /// resolve context + /// result + public Timestamp Resolve(FileInfo source, CanOpen_FileInfo destination, Timestamp member, ResolutionContext context) { - strDate = source.ModificationDate; - strTime = source.ModificationTime; - } + string strTime; + string strDate; + if (_type == "creation") + { + strDate = source.CreationDate; + strTime = source.CreationTime; + } + else + { + strDate = source.ModificationDate; + strTime = source.ModificationTime; + } - var time = new DateTime(0); - var date = new DateTime(0); + var time = new DateTime(0); + var date = new DateTime(0); - try - { - time = DateTime.ParseExact(strTime, "h:mmtt", CultureInfo.InvariantCulture); - } - catch (Exception e) - { - if (e is FormatException) + try { - //Silently ignore + time = DateTime.ParseExact(strTime, "h:mmtt", CultureInfo.InvariantCulture); + } + catch (Exception e) + { + if (e is FormatException) + { + //Silently ignore + } } - } - try - { - date = DateTime.ParseExact(strDate, "MM-dd-yyyy", CultureInfo.InvariantCulture); + try + { + date = DateTime.ParseExact(strDate, "MM-dd-yyyy", CultureInfo.InvariantCulture); + } + catch (Exception e) + { + if (e is FormatException) + { + //Silently ignore + } + } + + var datetime = date.AddTicks(time.TimeOfDay.Ticks); + return Timestamp.FromDateTime(datetime.ToUniversalTime()); } - catch (Exception e) + } + + /// + /// Helper class to convert Enum types + /// + /// Checkout AutoMapper.Extensions.EnumMapping when .net framework is gone + public class ODTypeResolver : ITypeConverter + { + /// + /// Resolver to convert eds date and time into protobuffer timestamp (datetime) + /// + /// source EDS fileinfo object + /// protobuffer fileinfo object + /// result object + /// resolve context + /// result + public OdObject.Types.ObjectType Convert(ObjectType source, OdObject.Types.ObjectType destination, ResolutionContext context) { - if (e is FormatException) + switch (source) { - //Silently ignore + case ObjectType.VAR: + return OdObject.Types.ObjectType.Var; + case ObjectType.ARRAY: + return OdObject.Types.ObjectType.Array; + case ObjectType.RECORD: + return OdObject.Types.ObjectType.Record; + case ObjectType.UNKNOWN: + case ObjectType.NULL: + case ObjectType.DOMAIN: + case ObjectType.DEFTYPE: + case ObjectType.DEFSTRUCT: + default: + return OdObject.Types.ObjectType.Unspecified; } - } - var datetime = date.AddTicks(time.TimeOfDay.Ticks); - return Timestamp.FromDateTime(datetime.ToUniversalTime()); + } } -} +} \ No newline at end of file From fb808620195780365fc2b02b646ef72a9c390803 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sat, 30 Nov 2024 22:08:39 +0100 Subject: [PATCH 03/12] completed test of eds -> protobuffer tests --- Tests/EDSMappingTests.cs | 37 ++++++++------- libEDSsharp/CanOpenEDSMapping.cs | 80 ++++++++++++++++++++++++++++---- 2 files changed, 90 insertions(+), 27 deletions(-) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index 70ef3ec..3633c32 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -41,19 +41,6 @@ public void Test_ToProtobufferAssertConfig() MappingEDS.MapToProtobuffer(eds); } [Fact] - public void Test_FromProtobufferAssertConfig() - { - var d = new CanOpenDevice - { - FileInfo = new CanOpen_FileInfo(), - DeviceInfo = new CanOpen_DeviceInfo(), - DeviceCommissioning = new CanOpen_DeviceCommissioning() - }; - - //Assert is called inside the map function - MappingEDS.MapFromProtobuffer(d); - } - [Fact] public void Test_ToProtobufferFileInfo() { var eds = new EDSsharp @@ -150,7 +137,7 @@ public void Test_ToProtobufferDeviceCommissioning() [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.DOMAIN)] [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.NULL)] [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.UNKNOWN)] - void Test_ToProtobufferODObject(OdObject.Types.ObjectType objTypeProto, ObjectType objTypeEDS) + public void Test_ToProtobufferODObject(OdObject.Types.ObjectType objTypeProto, ObjectType objTypeEDS) { var eds = new EDSsharp { @@ -194,7 +181,7 @@ void Test_ToProtobufferODObject(OdObject.Types.ObjectType objTypeProto, ObjectTy [InlineData(OdSubObject.Types.DataType.Unsigned48, DataType.UNSIGNED48)] [InlineData(OdSubObject.Types.DataType.Unsigned56, DataType.UNSIGNED56)] [InlineData(OdSubObject.Types.DataType.Unsigned64, DataType.UNSIGNED64)] - void Test_ToProtobufferSubODObjectDatatype(OdSubObject.Types.DataType datatypeProto, DataType datatypeEDS) + public void Test_ToProtobufferSubODObjectDatatype(OdSubObject.Types.DataType datatypeProto, DataType datatypeEDS) { var eds = new EDSsharp { @@ -216,15 +203,16 @@ void Test_ToProtobufferSubODObjectDatatype(OdSubObject.Types.DataType datatypePr var tmp = MappingEDS.MapToProtobuffer(eds); Assert.Equal(datatypeProto, tmp.Objects[od.Index.ToString()].SubObjects["0"].Type); } + [Theory] [InlineData(OdSubObject.Types.AccessPDO.Tr, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rw)] - [InlineData(OdSubObject.Types.AccessPDO.T, OdSubObject.Types.AccessSDO.Ro, EDSsharp.AccessType.ro)] - [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Wo, EDSsharp.AccessType.wo)] + [InlineData(OdSubObject.Types.AccessPDO.No, OdSubObject.Types.AccessSDO.Ro, EDSsharp.AccessType.ro)] + [InlineData(OdSubObject.Types.AccessPDO.No, OdSubObject.Types.AccessSDO.Wo, EDSsharp.AccessType.wo)] [InlineData(OdSubObject.Types.AccessPDO.T, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rwr)] [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rww)] [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Ro, EDSsharp.AccessType.@const)] [InlineData(OdSubObject.Types.AccessPDO.No, OdSubObject.Types.AccessSDO.No, EDSsharp.AccessType.UNKNOWN)] - void Test_ToProtobufferSubODObjectAccesstype(OdSubObject.Types.AccessPDO accessPDOProto, OdSubObject.Types.AccessSDO accessSDOProto, EDSsharp.AccessType datatypeEDS) + public void Test_ToProtobufferSubODObjectAccesstype(OdSubObject.Types.AccessPDO accessPDOProto, OdSubObject.Types.AccessSDO accessSDOProto, EDSsharp.AccessType datatypeEDS) { var eds = new EDSsharp { @@ -279,5 +267,18 @@ public void Test_ToProtobufferSubODObjectMembers() Assert.Equal(sub.LowLimit, tmp.Objects[od.Index.ToString()].SubObjects["0"].LowLimit); Assert.Equal(sub.defaultvalue, tmp.Objects[od.Index.ToString()].SubObjects["0"].DefaultValue); } + [Fact] + public void Test_FromProtobufferAssertConfig() + { + var d = new CanOpenDevice + { + FileInfo = new CanOpen_FileInfo(), + DeviceInfo = new CanOpen_DeviceInfo(), + DeviceCommissioning = new CanOpen_DeviceCommissioning() + }; + + //Assert is called inside the map function + MappingEDS.MapFromProtobuffer(d); + } } } diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index 93641aa..c9d870a 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -150,12 +150,14 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.objecttype)) .ForMember(dest => dest.CountLabel, opt => opt.MapFrom(src => src.Label)); cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); cfg.CreateMap() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) .ForMember(dest => dest.Alias, opt => opt.Ignore()) .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.datatype)) - .ForMember(dest => dest.Sdo, opt => opt.MapFrom(src => src.AccessSDO())) - .ForMember(dest => dest.Pdo, opt => opt.MapFrom(src => src.AccessPDO())) + .ForMember(dest => dest.Sdo, opt => opt.MapFrom(src => src.accesstype)) + .ForMember(dest => dest.Pdo, opt => opt.MapFrom(src => src.accesstype)) .ForMember(dest => dest.Srdo, opt => opt.Ignore()) .ForMember(dest => dest.StringLengthMin, opt => opt.MapFrom(src => src.Lengthofstring)); }); @@ -166,7 +168,6 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) } } - /// /// Helper class to convert EDS date and time into datetime used in the protobuffer timestand (datetime) /// @@ -233,16 +234,16 @@ public Timestamp Resolve(FileInfo source, CanOpen_FileInfo destination, Timestam } /// - /// Helper class to convert Enum types + /// Helper class to convert object type enum /// /// Checkout AutoMapper.Extensions.EnumMapping when .net framework is gone public class ODTypeResolver : ITypeConverter { /// - /// Resolver to convert eds date and time into protobuffer timestamp (datetime) + /// Resolver to convert object types /// - /// source EDS fileinfo object - /// protobuffer fileinfo object + /// EDS object type object + /// protobuffer object type /// result object /// resolve context /// result @@ -264,7 +265,68 @@ public OdObject.Types.ObjectType Convert(ObjectType source, OdObject.Types.Objec default: return OdObject.Types.ObjectType.Unspecified; } - } } -} \ No newline at end of file + /// + /// Helper class to convert Enum types + /// + /// Checkout AutoMapper.Extensions.EnumMapping when .net framework is gone + public class ODSDOAccessTypeResolver : ITypeConverter + { + /// + /// Resolver to convert eds access into SDO access type + /// + /// EDS accesstype + /// protobuffer sdo access type + /// result object + /// resolve context + /// result + public OdSubObject.Types.AccessSDO Convert(EDSsharp.AccessType source, OdSubObject.Types.AccessSDO destination, ResolutionContext context) + { + switch (source) + { + case EDSsharp.AccessType.rw: + case EDSsharp.AccessType.rwr: + case EDSsharp.AccessType.rww: + return OdSubObject.Types.AccessSDO.Rw; + case EDSsharp.AccessType.ro: + case EDSsharp.AccessType.@const: + return OdSubObject.Types.AccessSDO.Ro; + case EDSsharp.AccessType.wo: + return OdSubObject.Types.AccessSDO.Wo; + case EDSsharp.AccessType.UNKNOWN: + default: + return OdSubObject.Types.AccessSDO.No; + } + } + } + public class ODPDOAccessTypeResolver : ITypeConverter + { + /// + /// Resolver to convert eds access into PDO access type + /// + /// EDS accesstype + /// protobuffer pdo access type + /// result object + /// resolve context + /// result + public OdSubObject.Types.AccessPDO Convert(EDSsharp.AccessType source, OdSubObject.Types.AccessPDO destination, ResolutionContext context) + { + switch (source) + { + case EDSsharp.AccessType.rw: + return OdSubObject.Types.AccessPDO.Tr; + case EDSsharp.AccessType.rwr: + return OdSubObject.Types.AccessPDO.T; + case EDSsharp.AccessType.rww: + case EDSsharp.AccessType.@const: + return OdSubObject.Types.AccessPDO.R; + case EDSsharp.AccessType.ro: + case EDSsharp.AccessType.wo: + case EDSsharp.AccessType.UNKNOWN: + default: + return OdSubObject.Types.AccessPDO.No; + } + } + } +} From 85078f994ede8e292fd627fe2dee5a865457b066 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sat, 30 Nov 2024 22:12:46 +0100 Subject: [PATCH 04/12] fixing merge with main problems --- Tests/EDSMappingTests.cs | 4 ++-- libEDSsharp/CanOpenEDSMapping.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index 3633c32..a786a66 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -151,7 +151,7 @@ public void Test_ToProtobufferODObject(OdObject.Types.ObjectType objTypeProto, O }; eds.ods.Add(od.Index, od); var tmp = MappingEDS.MapToProtobuffer(eds); - Assert.Equal(objTypeProto, tmp.Objects[od.Index.ToString()].Type); + Assert.Equal(objTypeProto, tmp.Objects[od.Index.ToString()].ObjectType); } [Theory] @@ -201,7 +201,7 @@ public void Test_ToProtobufferSubODObjectDatatype(OdSubObject.Types.DataType dat od.subobjects.Add(0x00, sub); eds.ods.Add(od.Index, od); var tmp = MappingEDS.MapToProtobuffer(eds); - Assert.Equal(datatypeProto, tmp.Objects[od.Index.ToString()].SubObjects["0"].Type); + Assert.Equal(datatypeProto, tmp.Objects[od.Index.ToString()].SubObjects["0"].DataType); } [Theory] diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index c9d870a..374f9c6 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -147,7 +147,7 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) .ForMember(dest => dest.StorageGroup, opt => opt.Ignore()) .ForMember(dest => dest.FlagsPDO, opt => opt.Ignore()) .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) - .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.objecttype)) + .ForMember(dest => dest.ObjectType, opt => opt.MapFrom(src => src.objecttype)) .ForMember(dest => dest.CountLabel, opt => opt.MapFrom(src => src.Label)); cfg.CreateMap().ConvertUsing(); cfg.CreateMap().ConvertUsing(); @@ -155,7 +155,7 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) cfg.CreateMap() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) .ForMember(dest => dest.Alias, opt => opt.Ignore()) - .ForMember(dest => dest.Type, opt => opt.MapFrom(src => src.datatype)) + .ForMember(dest => dest.DataType, opt => opt.MapFrom(src => src.datatype)) .ForMember(dest => dest.Sdo, opt => opt.MapFrom(src => src.accesstype)) .ForMember(dest => dest.Pdo, opt => opt.MapFrom(src => src.accesstype)) .ForMember(dest => dest.Srdo, opt => opt.Ignore()) From 99607380068ca514c0b6b3510f6ea992710de871 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sun, 1 Dec 2024 08:01:39 +0100 Subject: [PATCH 05/12] added workaround for automapper bug in .net8 --- libEDSsharp/CanOpenEDSMapping.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index 374f9c6..fc3aa2a 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -40,6 +40,9 @@ public static EDSsharp MapFromProtobuffer(CanOpenDevice source) { var config = new MapperConfiguration(cfg => { + // workaround for https://github.com/AutoMapper/AutoMapper/issues/2959 + // Cant update untill after .net framwork is gone + cfg.ShouldMapMethod = (m => m.Name == "ARandomStringThatDoesNotMatchAnyFunctionName"); cfg.CreateMap() .ForMember(dest => dest.Dirty, opt => opt.Ignore()) .ForMember(dest => dest.xddfilename_1_1, opt => opt.Ignore()) @@ -120,6 +123,9 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) { var config = new MapperConfiguration(cfg => { + // workaround for https://github.com/AutoMapper/AutoMapper/issues/2959 + // Cant update untill after .net framwork is gone + cfg.ShouldMapMethod = (m => m.Name == "ARandomStringThatDoesNotMatchAnyFunctionName"); cfg.CreateMap() .ForMember(dest => dest.FileInfo, opt => opt.MapFrom(src => src.fi)) .ForMember(dest => dest.DeviceInfo, opt => opt.MapFrom(src => src.di)) From 111d1bc1d91127bc39e5f1d8e1ec4e27f572bb79 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sun, 8 Dec 2024 14:49:44 +0100 Subject: [PATCH 06/12] Testing the rest of standard protobufffer -> eds --- Tests/EDSMappingTests.cs | 238 ++++++++++++++++++++++++++++++- libEDSsharp/CanOpenEDSMapping.cs | 134 ++++++++++++++++- 2 files changed, 366 insertions(+), 6 deletions(-) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index a786a66..d81e297 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -269,16 +269,248 @@ public void Test_ToProtobufferSubODObjectMembers() } [Fact] public void Test_FromProtobufferAssertConfig() + { + var d = new CanOpenDevice { }; + + var od = new OdObject + { + ObjectType = OdObject.Types.ObjectType.Var, + Name = "Test VAR", + }; + + var sub = new OdSubObject + { + Name = "some value", + DataType = OdSubObject.Types.DataType.Unsigned8, + Pdo = OdSubObject.Types.AccessPDO.T, + Sdo = OdSubObject.Types.AccessSDO.Ro, + DefaultValue = "1", + }; + od.SubObjects.Add("0", sub); + d.Objects.Add("0x2000", od); + + //Assert is called inside the map function + MappingEDS.MapFromProtobuffer(d); + } + [Fact] + public void Test_FromProtobufferFileInfo() { var d = new CanOpenDevice { - FileInfo = new CanOpen_FileInfo(), - DeviceInfo = new CanOpen_DeviceInfo(), - DeviceCommissioning = new CanOpen_DeviceCommissioning() + FileInfo = new CanOpen_FileInfo() }; + var CreationTime = DateTime.ParseExact($"11:22AM 11-22-1234", "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); + var ModificationTime = DateTime.ParseExact($"11:22AM 11-22-1234", "h:mmtt MM-dd-yyyy", CultureInfo.InvariantCulture); + + d.FileInfo.FileVersion = "FileVersion"; + d.FileInfo.Description = "Description"; + d.FileInfo.CreationTime = Timestamp.FromDateTime(CreationTime.ToUniversalTime()); + d.FileInfo.ModificationTime = Timestamp.FromDateTime(ModificationTime.ToUniversalTime()); + d.FileInfo.ModifiedBy = "ModifiedBy"; + + var tmp = MappingEDS.MapFromProtobuffer(d); + Assert.Equal(d.FileInfo.CreatedBy, tmp.fi.CreatedBy); + Assert.Equal(d.FileInfo.CreationTime.ToDateTime().ToString("h:mmtt"), tmp.fi.CreationTime); + Assert.Equal(d.FileInfo.CreationTime.ToDateTime().ToString("MM-dd-yyyy"), tmp.fi.CreationDate); + Assert.Equal(d.FileInfo.Description, tmp.fi.Description); + Assert.Equal(d.FileInfo.FileVersion, tmp.fi.FileVersion); + Assert.Equal(d.FileInfo.ModifiedBy, tmp.fi.ModifiedBy); + Assert.Equal(d.FileInfo.ModificationTime.ToDateTime().ToString("h:mmtt"), tmp.fi.ModificationTime); + Assert.Equal(d.FileInfo.ModificationTime.ToDateTime().ToString("MM-dd-yyyy"), tmp.fi.ModificationDate); //Assert is called inside the map function MappingEDS.MapFromProtobuffer(d); } + [Fact] + public void Test_FromProtobufferDeviceInfo() + { + var d = new CanOpenDevice + { + DeviceInfo = new CanOpen_DeviceInfo() + { + BaudRate10 = true, + BaudRate20 = false, + BaudRate50 = true, + BaudRate125 = false, + BaudRate250 = true, + BaudRate500 = false, + BaudRate800 = true, + BaudRate1000 = false, + BaudRateAuto = true, + LssMaster = false, + LssSlave = true, + VendorName = "VendorName", + ProductName = "ProductName" + } + }; + + var tmp = MappingEDS.MapFromProtobuffer(d); + Assert.Equal(d.DeviceInfo.BaudRate10, tmp.di.BaudRate_10); + Assert.Equal(d.DeviceInfo.BaudRate20, tmp.di.BaudRate_20); + Assert.Equal(d.DeviceInfo.BaudRate50, tmp.di.BaudRate_50); + Assert.Equal(d.DeviceInfo.BaudRate125, tmp.di.BaudRate_125); + Assert.Equal(d.DeviceInfo.BaudRate250, tmp.di.BaudRate_250); + Assert.Equal(d.DeviceInfo.BaudRate500, tmp.di.BaudRate_500); + Assert.Equal(d.DeviceInfo.BaudRate800, tmp.di.BaudRate_800); + Assert.Equal(d.DeviceInfo.BaudRate1000, tmp.di.BaudRate_1000); + Assert.Equal(d.DeviceInfo.BaudRateAuto, tmp.di.BaudRate_auto); + Assert.Equal(d.DeviceInfo.LssMaster, tmp.di.LSS_Master); + Assert.Equal(d.DeviceInfo.LssSlave, tmp.di.LSS_Supported); + Assert.Equal(d.DeviceInfo.VendorName, tmp.di.VendorName); + Assert.Equal(d.DeviceInfo.ProductName, tmp.di.ProductName); + } + + [Fact] + public void Test_FromProtobufferDeviceCommissioning() + { + var d = new CanOpenDevice + { + DeviceCommissioning = new CanOpen_DeviceCommissioning + { + Baudrate = 456, + NodeId = 123, + NodeName = "NodeName" + + } + }; + + var tmp = MappingEDS.MapFromProtobuffer(d); + Assert.Equal(d.DeviceCommissioning.NodeId, tmp.dc.NodeID); + Assert.Equal(d.DeviceCommissioning.NodeName, tmp.dc.NodeName); + Assert.Equal(d.DeviceCommissioning.Baudrate, tmp.dc.Baudrate); + } + + [Theory] + [InlineData(OdObject.Types.ObjectType.Array, ObjectType.ARRAY)] + [InlineData(OdObject.Types.ObjectType.Record, ObjectType.RECORD)] + [InlineData(OdObject.Types.ObjectType.Var, ObjectType.VAR)] + [InlineData(OdObject.Types.ObjectType.Unspecified, ObjectType.UNKNOWN)] + public void Test_FromProtobufferODObject(OdObject.Types.ObjectType objTypeProto, ObjectType objTypeEDS) + { + ushort index = 0x2000; + var d = new CanOpenDevice(); + var od = new OdObject + { + ObjectType = objTypeProto, + Name = "Name" + }; + d.Objects.Add(index.ToString(), od); + var tmp = MappingEDS.MapFromProtobuffer(d); + Assert.Equal(index, tmp.ods[index].Index); + Assert.Equal(objTypeEDS, tmp.ods[index].objecttype); + Assert.Equal(od.Name, tmp.ods[index].parameter_name); + } + + [Theory] + [InlineData(OdSubObject.Types.DataType.Unspecified, DataType.UNKNOWN)] + [InlineData(OdSubObject.Types.DataType.Boolean, DataType.BOOLEAN)] + [InlineData(OdSubObject.Types.DataType.Integer8, DataType.INTEGER8)] + [InlineData(OdSubObject.Types.DataType.Integer16, DataType.INTEGER16)] + [InlineData(OdSubObject.Types.DataType.Integer32, DataType.INTEGER32)] + [InlineData(OdSubObject.Types.DataType.Unsigned8, DataType.UNSIGNED8)] + [InlineData(OdSubObject.Types.DataType.Unsigned16, DataType.UNSIGNED16)] + [InlineData(OdSubObject.Types.DataType.Unsigned32, DataType.UNSIGNED32)] + [InlineData(OdSubObject.Types.DataType.Real32, DataType.REAL32)] + [InlineData(OdSubObject.Types.DataType.VisibleString, DataType.VISIBLE_STRING)] + [InlineData(OdSubObject.Types.DataType.OctetString, DataType.OCTET_STRING)] + [InlineData(OdSubObject.Types.DataType.UnicodeString, DataType.UNICODE_STRING)] + [InlineData(OdSubObject.Types.DataType.TimeOfDay, DataType.TIME_OF_DAY)] + [InlineData(OdSubObject.Types.DataType.TimeDifference, DataType.TIME_DIFFERENCE)] + [InlineData(OdSubObject.Types.DataType.Domain, DataType.DOMAIN)] + [InlineData(OdSubObject.Types.DataType.Integer24, DataType.INTEGER24)] + [InlineData(OdSubObject.Types.DataType.Real64, DataType.REAL64)] + [InlineData(OdSubObject.Types.DataType.Integer40, DataType.INTEGER40)] + [InlineData(OdSubObject.Types.DataType.Integer48, DataType.INTEGER48)] + [InlineData(OdSubObject.Types.DataType.Integer56, DataType.INTEGER56)] + [InlineData(OdSubObject.Types.DataType.Integer64, DataType.INTEGER64)] + [InlineData(OdSubObject.Types.DataType.Unsigned24, DataType.UNSIGNED24)] + [InlineData(OdSubObject.Types.DataType.Unsigned40, DataType.UNSIGNED40)] + [InlineData(OdSubObject.Types.DataType.Unsigned48, DataType.UNSIGNED48)] + [InlineData(OdSubObject.Types.DataType.Unsigned56, DataType.UNSIGNED56)] + [InlineData(OdSubObject.Types.DataType.Unsigned64, DataType.UNSIGNED64)] + public void Test_FromProtobufferSubODObjectDatatype(OdSubObject.Types.DataType datatypeProto, DataType datatypeEDS) + { + ushort index = 0x2000; + ushort subindex = 0x1; + var d = new CanOpenDevice(); + var od = new OdObject + { + ObjectType = OdObject.Types.ObjectType.Record + }; + var sub = new OdSubObject + { + DataType = datatypeProto, + }; + + od.SubObjects.Add(subindex.ToString(), sub); + d.Objects.Add(index.ToString(), od); + + var tmp = MappingEDS.MapFromProtobuffer(d); + + Assert.Equal(datatypeEDS, tmp.ods[index].subobjects[subindex].datatype); + } + + [Theory] + [InlineData(OdSubObject.Types.AccessPDO.Tr, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rw)] + [InlineData(OdSubObject.Types.AccessPDO.No, OdSubObject.Types.AccessSDO.Ro, EDSsharp.AccessType.ro)] + [InlineData(OdSubObject.Types.AccessPDO.No, OdSubObject.Types.AccessSDO.Wo, EDSsharp.AccessType.wo)] + [InlineData(OdSubObject.Types.AccessPDO.T, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rwr)] + [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Rw, EDSsharp.AccessType.rww)] + [InlineData(OdSubObject.Types.AccessPDO.R, OdSubObject.Types.AccessSDO.Ro, EDSsharp.AccessType.@const)] + [InlineData(OdSubObject.Types.AccessPDO.No, OdSubObject.Types.AccessSDO.No, EDSsharp.AccessType.UNKNOWN)] + public void Test_FromProtobufferSubODObjectAccesstype(OdSubObject.Types.AccessPDO accessPDOProto, OdSubObject.Types.AccessSDO accessSDOProto, EDSsharp.AccessType datatypeEDS) + { + ushort index = 0x2000; + ushort subindex = 0x1; + var d = new CanOpenDevice(); + var od = new OdObject + { + ObjectType = OdObject.Types.ObjectType.Record + }; + var sub = new OdSubObject + { + Sdo = accessSDOProto, + Pdo = accessPDOProto, + }; + + od.SubObjects.Add(subindex.ToString(), sub); + d.Objects.Add(index.ToString(), od); + + var tmp = MappingEDS.MapFromProtobuffer(d); + + Assert.Equal(datatypeEDS, tmp.ods[index].subobjects[subindex].accesstype); + } + + [Fact] + public void Test_FromProtobufferSubODObjectMembers() + { + ushort index = 0x2000; + ushort subindex = 0x1; + var d = new CanOpenDevice(); + var od = new OdObject + { + ObjectType = OdObject.Types.ObjectType.Record + }; + var sub = new OdSubObject + { + ActualValue = "123", + Name = "some value", + HighLimit = "HighLimit", + LowLimit = "LowLimit", + DefaultValue = "defaultvalue", + }; + + od.SubObjects.Add(subindex.ToString(), sub); + d.Objects.Add(index.ToString(), od); + var tmp = MappingEDS.MapFromProtobuffer(d); + + Assert.Equal(sub.ActualValue, tmp.ods[index].subobjects[subindex].actualvalue); + Assert.Equal(sub.Name, tmp.ods[index].subobjects[subindex].parameter_name); + Assert.Equal(sub.HighLimit, tmp.ods[index].subobjects[subindex].HighLimit); + Assert.Equal(sub.LowLimit, tmp.ods[index].subobjects[subindex].LowLimit); + Assert.Equal(sub.DefaultValue, tmp.ods[index].subobjects[subindex].defaultvalue); + Assert.Equal(index, tmp.ods[index].subobjects[subindex].Index); + Assert.Equal(subindex, tmp.ods[index].subobjects[subindex].Subindex); + } } } diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index fc3aa2a..b64ef4a 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -21,6 +21,7 @@ You should have received a copy of the GNU General Public License using Google.Protobuf.WellKnownTypes; using LibCanOpen; using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -43,6 +44,7 @@ public static EDSsharp MapFromProtobuffer(CanOpenDevice source) // workaround for https://github.com/AutoMapper/AutoMapper/issues/2959 // Cant update untill after .net framwork is gone cfg.ShouldMapMethod = (m => m.Name == "ARandomStringThatDoesNotMatchAnyFunctionName"); + cfg.CreateMap().ConvertUsing(); cfg.CreateMap() .ForMember(dest => dest.Dirty, opt => opt.Ignore()) .ForMember(dest => dest.xddfilename_1_1, opt => opt.Ignore()) @@ -109,10 +111,63 @@ public static EDSsharp MapFromProtobuffer(CanOpenDevice source) .ForMember(dest => dest.NetworkName, opt => opt.Ignore()) .ForMember(dest => dest.CANopenManager, opt => opt.Ignore()) .ForMember(dest => dest.LSS_SerialNumber, opt => opt.Ignore()); + cfg.CreateMap() + .ForMember(dest => dest.CO_accessSRDO, opt => opt.Ignore()) + .ForMember(dest => dest.CO_stringLengthMin, opt => opt.Ignore()); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap() + .ForMember(dest => dest.Index, opt => opt.Ignore()) + .ForMember(dest => dest.parameter_name, opt => opt.MapFrom(src => src.Name)) + .ForMember(dest => dest.denotation, opt => opt.Ignore()) + .ForMember(dest => dest.datatype, opt => opt.Ignore()) + .ForMember(dest => dest.accesstype, opt => opt.Ignore()) + .ForMember(dest => dest.defaultvalue, opt => opt.Ignore()) + .ForMember(dest => dest.LowLimit, opt => opt.Ignore()) + .ForMember(dest => dest.HighLimit, opt => opt.Ignore()) + .ForMember(dest => dest.actualvalue, opt => opt.Ignore()) + .ForMember(dest => dest.ObjFlags, opt => opt.Ignore()) + .ForMember(dest => dest.CompactSubObj, opt => opt.Ignore()) + .ForMember(dest => dest.count, opt => opt.Ignore()) + .ForMember(dest => dest.ObjExtend, opt => opt.Ignore()) + .ForMember(dest => dest.PDOtype, opt => opt.Ignore()) + .ForMember(dest => dest.Label, opt => opt.Ignore()) + .ForMember(dest => dest.parent, opt => opt.Ignore()) + .ForMember(dest => dest.prop, opt => opt.MapFrom(src => src)) + .ForMember(dest => dest.uniqueID, opt => opt.Ignore()); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap() + .ForMember(dest => dest.parameter_name, opt => opt.MapFrom(src => src.Name)) + .ForMember(dest => dest.Index, opt => opt.Ignore()) + .ForMember(dest => dest.denotation, opt => opt.Ignore()) + .ForMember(dest => dest.accesstype, opt => opt.MapFrom(src => src)) + .ForMember(dest => dest.ObjFlags, opt => opt.Ignore()) + .ForMember(dest => dest.CompactSubObj, opt => opt.Ignore()) + .ForMember(dest => dest.count, opt => opt.Ignore()) + .ForMember(dest => dest.ObjExtend, opt => opt.Ignore()) + .ForMember(dest => dest.PDOtype, opt => opt.Ignore()) + .ForMember(dest => dest.Label, opt => opt.Ignore()) + .ForMember(dest => dest.parent, opt => opt.Ignore()) + .ForMember(dest => dest.prop, opt => opt.Ignore()) + .ForMember(dest => dest.uniqueID, opt => opt.Ignore()) + .ForMember(dest => dest.objecttype, opt => opt.Ignore()) + .ForMember(dest => dest.Description, opt => opt.Ignore()) + .ForMember(dest => dest.subobjects, opt => opt.Ignore()); }); config.AssertConfigurationIsValid(); var mapper = config.CreateMapper(); - return mapper.Map(source); + + var result = mapper.Map(source); + + //Post processing, add index / subindex + foreach (KeyValuePair obj in result.ods) + { + obj.Value.Index = obj.Key; + foreach (KeyValuePair subObj in obj.Value.subobjects) + { + subObj.Value.parent = obj.Value; + } + } + return result; } /// /// Converts from EDS to protobuffer @@ -243,7 +298,7 @@ public Timestamp Resolve(FileInfo source, CanOpen_FileInfo destination, Timestam /// Helper class to convert object type enum /// /// Checkout AutoMapper.Extensions.EnumMapping when .net framework is gone - public class ODTypeResolver : ITypeConverter + public class ODTypeResolver : ITypeConverter, ITypeConverter { /// /// Resolver to convert object types @@ -272,12 +327,37 @@ public OdObject.Types.ObjectType Convert(ObjectType source, OdObject.Types.Objec return OdObject.Types.ObjectType.Unspecified; } } + /// + /// Resolver to convert object types + /// + /// EDS object type object + /// protobuffer object type + /// result object + /// resolve context + /// result + public ObjectType Convert(OdObject.Types.ObjectType source, ObjectType destination, ResolutionContext context) + { + switch (source) + { + case OdObject.Types.ObjectType.Unspecified: + return ObjectType.UNKNOWN; + case OdObject.Types.ObjectType.Var: + return ObjectType.VAR; + case OdObject.Types.ObjectType.Array: + return ObjectType.ARRAY; + case OdObject.Types.ObjectType.Record: + return ObjectType.RECORD; + default: + return ObjectType.UNKNOWN; + } + } } /// /// Helper class to convert Enum types /// /// Checkout AutoMapper.Extensions.EnumMapping when .net framework is gone - public class ODSDOAccessTypeResolver : ITypeConverter + public class ODSDOAccessTypeResolver : ITypeConverter, + ITypeConverter { /// /// Resolver to convert eds access into SDO access type @@ -305,6 +385,31 @@ public OdSubObject.Types.AccessSDO Convert(EDSsharp.AccessType source, OdSubObje return OdSubObject.Types.AccessSDO.No; } } + /// + /// Resolver to convert SDO access type into eds access into + /// + /// protobuffer sdo access type + /// EDS accesstype + /// result object + /// resolve context + /// result + public EDSsharp.AccessType Convert(OdSubObject source, EDSsharp.AccessType destination, ResolutionContext context) + { + if (source.Pdo == OdSubObject.Types.AccessPDO.Tr && source.Sdo == OdSubObject.Types.AccessSDO.Rw) + return EDSsharp.AccessType.rw; + else if (source.Pdo == OdSubObject.Types.AccessPDO.No && source.Sdo == OdSubObject.Types.AccessSDO.Ro) + return EDSsharp.AccessType.ro; + else if (source.Pdo == OdSubObject.Types.AccessPDO.No && source.Sdo == OdSubObject.Types.AccessSDO.Wo) + return EDSsharp.AccessType.wo; + else if (source.Pdo == OdSubObject.Types.AccessPDO.T && source.Sdo == OdSubObject.Types.AccessSDO.Rw) + return EDSsharp.AccessType.rwr; + else if (source.Pdo == OdSubObject.Types.AccessPDO.R && source.Sdo == OdSubObject.Types.AccessSDO.Rw) + return EDSsharp.AccessType.rww; + else if (source.Pdo == OdSubObject.Types.AccessPDO.R && source.Sdo == OdSubObject.Types.AccessSDO.Ro) + return EDSsharp.AccessType.@const; + else + return EDSsharp.AccessType.UNKNOWN; + } } public class ODPDOAccessTypeResolver : ITypeConverter { @@ -335,4 +440,27 @@ public OdSubObject.Types.AccessPDO Convert(EDSsharp.AccessType source, OdSubObje } } } + public class ODStringToShortTypeResolver : ITypeConverter + { + /// + /// Resolver to convert index & subindex string into short, will try hex, then descimal + /// + /// string containing index or subindex + /// short int interpreted from the string + /// result object + /// resolve context + /// result + public UInt16 Convert(string source, UInt16 destination, ResolutionContext context) + { + if (source.StartsWith("0x")) + { + var hex = source.Substring(2); + return System.Convert.ToUInt16(hex, 16); + } + else + { + return System.Convert.ToUInt16(source); + } + } + } } From be9493a1844963f8bcbf20ecaa2e5ab878783b02 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sun, 8 Dec 2024 14:52:44 +0100 Subject: [PATCH 07/12] cleaning up the access resolvers --- libEDSsharp/CanOpenEDSMapping.cs | 65 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index b64ef4a..2ef2fdf 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -134,7 +134,7 @@ public static EDSsharp MapFromProtobuffer(CanOpenDevice source) .ForMember(dest => dest.parent, opt => opt.Ignore()) .ForMember(dest => dest.prop, opt => opt.MapFrom(src => src)) .ForMember(dest => dest.uniqueID, opt => opt.Ignore()); - cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); cfg.CreateMap() .ForMember(dest => dest.parameter_name, opt => opt.MapFrom(src => src.Name)) .ForMember(dest => dest.Index, opt => opt.Ignore()) @@ -211,8 +211,8 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) .ForMember(dest => dest.ObjectType, opt => opt.MapFrom(src => src.objecttype)) .ForMember(dest => dest.CountLabel, opt => opt.MapFrom(src => src.Label)); cfg.CreateMap().ConvertUsing(); - cfg.CreateMap().ConvertUsing(); - cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); + cfg.CreateMap().ConvertUsing(); cfg.CreateMap() .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) .ForMember(dest => dest.Alias, opt => opt.Ignore()) @@ -353,10 +353,11 @@ public ObjectType Convert(OdObject.Types.ObjectType source, ObjectType destinati } } /// - /// Helper class to convert Enum types + /// Helper class to convert Access types /// /// Checkout AutoMapper.Extensions.EnumMapping when .net framework is gone - public class ODSDOAccessTypeResolver : ITypeConverter, + public class ODAccessTypeResolver : ITypeConverter, + ITypeConverter, ITypeConverter { /// @@ -385,34 +386,6 @@ public OdSubObject.Types.AccessSDO Convert(EDSsharp.AccessType source, OdSubObje return OdSubObject.Types.AccessSDO.No; } } - /// - /// Resolver to convert SDO access type into eds access into - /// - /// protobuffer sdo access type - /// EDS accesstype - /// result object - /// resolve context - /// result - public EDSsharp.AccessType Convert(OdSubObject source, EDSsharp.AccessType destination, ResolutionContext context) - { - if (source.Pdo == OdSubObject.Types.AccessPDO.Tr && source.Sdo == OdSubObject.Types.AccessSDO.Rw) - return EDSsharp.AccessType.rw; - else if (source.Pdo == OdSubObject.Types.AccessPDO.No && source.Sdo == OdSubObject.Types.AccessSDO.Ro) - return EDSsharp.AccessType.ro; - else if (source.Pdo == OdSubObject.Types.AccessPDO.No && source.Sdo == OdSubObject.Types.AccessSDO.Wo) - return EDSsharp.AccessType.wo; - else if (source.Pdo == OdSubObject.Types.AccessPDO.T && source.Sdo == OdSubObject.Types.AccessSDO.Rw) - return EDSsharp.AccessType.rwr; - else if (source.Pdo == OdSubObject.Types.AccessPDO.R && source.Sdo == OdSubObject.Types.AccessSDO.Rw) - return EDSsharp.AccessType.rww; - else if (source.Pdo == OdSubObject.Types.AccessPDO.R && source.Sdo == OdSubObject.Types.AccessSDO.Ro) - return EDSsharp.AccessType.@const; - else - return EDSsharp.AccessType.UNKNOWN; - } - } - public class ODPDOAccessTypeResolver : ITypeConverter - { /// /// Resolver to convert eds access into PDO access type /// @@ -439,7 +412,33 @@ public OdSubObject.Types.AccessPDO Convert(EDSsharp.AccessType source, OdSubObje return OdSubObject.Types.AccessPDO.No; } } + /// + /// Resolver to convert SDO access type into eds access into + /// + /// protobuffer sdo access type + /// EDS accesstype + /// result object + /// resolve context + /// result + public EDSsharp.AccessType Convert(OdSubObject source, EDSsharp.AccessType destination, ResolutionContext context) + { + if (source.Pdo == OdSubObject.Types.AccessPDO.Tr && source.Sdo == OdSubObject.Types.AccessSDO.Rw) + return EDSsharp.AccessType.rw; + else if (source.Pdo == OdSubObject.Types.AccessPDO.No && source.Sdo == OdSubObject.Types.AccessSDO.Ro) + return EDSsharp.AccessType.ro; + else if (source.Pdo == OdSubObject.Types.AccessPDO.No && source.Sdo == OdSubObject.Types.AccessSDO.Wo) + return EDSsharp.AccessType.wo; + else if (source.Pdo == OdSubObject.Types.AccessPDO.T && source.Sdo == OdSubObject.Types.AccessSDO.Rw) + return EDSsharp.AccessType.rwr; + else if (source.Pdo == OdSubObject.Types.AccessPDO.R && source.Sdo == OdSubObject.Types.AccessSDO.Rw) + return EDSsharp.AccessType.rww; + else if (source.Pdo == OdSubObject.Types.AccessPDO.R && source.Sdo == OdSubObject.Types.AccessSDO.Ro) + return EDSsharp.AccessType.@const; + else + return EDSsharp.AccessType.UNKNOWN; + } } + public class ODStringToShortTypeResolver : ITypeConverter { /// From 4025f1b3bc49fe372735f3a939b11d52eebe0d29 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sun, 8 Dec 2024 14:55:45 +0100 Subject: [PATCH 08/12] cleanup --- Tests/EDSMappingTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index d81e297..b9ca44d 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -1,9 +1,9 @@ -using Xunit; -using libEDSsharp; +using Google.Protobuf.WellKnownTypes; using LibCanOpen; -using System.Globalization; +using libEDSsharp; using System; -using Google.Protobuf.WellKnownTypes; +using System.Globalization; +using Xunit; namespace Tests { From 79021baf4573b3fc01715d6e19ac44e37d9a05a2 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sat, 14 Dec 2024 13:28:10 +0100 Subject: [PATCH 09/12] Testing the canopenNode spesial propertys prop->eds --- Tests/EDSMappingTests.cs | 48 ++++++++++++++++++++++++++++++++ libEDSsharp/CanOpenEDSMapping.cs | 2 ++ 2 files changed, 50 insertions(+) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index b9ca44d..a1b6450 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -512,5 +512,53 @@ public void Test_FromProtobufferSubODObjectMembers() Assert.Equal(index, tmp.ods[index].subobjects[subindex].Index); Assert.Equal(subindex, tmp.ods[index].subobjects[subindex].Subindex); } + [Fact] + public void Test_FromProtobufferODObject_CustomProperties() + { + ushort index = 0x2000; + var d = new CanOpenDevice(); + var od = new OdObject + { + ObjectType = OdObject.Types.ObjectType.Record, + Disabled = true, + CountLabel = "CountLabel", + StorageGroup = "StorageGroup" + }; + + d.Objects.Add(index.ToString(), od); + var tmp = MappingEDS.MapFromProtobuffer(d); + + Assert.Equal(od.Disabled, tmp.ods[index].prop.CO_disabled); + Assert.Equal(od.CountLabel, tmp.ods[index].prop.CO_countLabel); + Assert.Equal(od.StorageGroup, tmp.ods[index].prop.CO_storageGroup); + } + [Theory] + [InlineData(OdSubObject.Types.AccessSRDO.No, AccessSRDO.no )] + [InlineData(OdSubObject.Types.AccessSRDO.Rx, AccessSRDO.rx)] + [InlineData(OdSubObject.Types.AccessSRDO.Trx, AccessSRDO.trx)] + [InlineData(OdSubObject.Types.AccessSRDO.Tx, AccessSRDO.tx)] + public void Test_FromProtobufferSubODObject_CustomProperties(OdSubObject.Types.AccessSRDO accessSRDO, AccessSRDO co_prop) + { + ushort index = 0x2000; + ushort subindex = 0x1; + var d = new CanOpenDevice(); + var od = new OdObject + { + ObjectType = OdObject.Types.ObjectType.Record + }; + var sub = new OdSubObject + { + Srdo = accessSRDO, + StringLengthMin = 123, + }; + + od.SubObjects.Add(subindex.ToString(), sub); + d.Objects.Add(index.ToString(), od); + var tmp = MappingEDS.MapFromProtobuffer(d); + + Assert.Equal(co_prop, tmp.ods[index].subobjects[subindex].prop.CO_accessSRDO); + //Assert.Equal(sub.ActualValue, tmp.ods[index].subobjects[subindex].prop.CO_flagsPDO); + Assert.Equal(sub.StringLengthMin, tmp.ods[index].subobjects[subindex].prop.CO_stringLengthMin); + } } } diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index 2ef2fdf..afecaf3 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -148,6 +148,8 @@ public static EDSsharp MapFromProtobuffer(CanOpenDevice source) .ForMember(dest => dest.Label, opt => opt.Ignore()) .ForMember(dest => dest.parent, opt => opt.Ignore()) .ForMember(dest => dest.prop, opt => opt.Ignore()) + .ForPath(dest => dest.prop.CO_accessSRDO, opt => opt.MapFrom(src => src.Srdo)) + .ForPath(dest => dest.prop.CO_stringLengthMin, opt => opt.MapFrom(src => src.StringLengthMin)) .ForMember(dest => dest.uniqueID, opt => opt.Ignore()) .ForMember(dest => dest.objecttype, opt => opt.Ignore()) .ForMember(dest => dest.Description, opt => opt.Ignore()) From 7b7aad549070905c130a18e96d857bf1fb959043 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sat, 14 Dec 2024 21:11:05 +0100 Subject: [PATCH 10/12] Testing the canopenNode spesial propertys eds->prop --- Tests/EDSMappingTests.cs | 54 ++++++++++++++++++++++++++++++++ libEDSsharp/CanOpenEDSMapping.cs | 10 +++--- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index a1b6450..eb235ec 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -267,6 +267,60 @@ public void Test_ToProtobufferSubODObjectMembers() Assert.Equal(sub.LowLimit, tmp.Objects[od.Index.ToString()].SubObjects["0"].LowLimit); Assert.Equal(sub.defaultvalue, tmp.Objects[od.Index.ToString()].SubObjects["0"].DefaultValue); } + [Fact] + public void Test_ToProtobufferODObject_CustomProperties() + { + var eds = new EDSsharp + { + ods = new System.Collections.Generic.SortedDictionary() + }; + var od = new ODentry + { + objecttype = ObjectType.RECORD, + Index = 0x2000, + }; + od.prop.CO_disabled = true; + od.prop.CO_countLabel = "CO_countLabel"; + od.prop.CO_storageGroup = "CO_storageGroup"; + + eds.ods.Add(od.Index, od); + var tmp = MappingEDS.MapToProtobuffer(eds); + + Assert.Equal(od.prop.CO_disabled, tmp.Objects[od.Index.ToString()].Disabled); + Assert.Equal(od.prop.CO_countLabel, tmp.Objects[od.Index.ToString()].CountLabel); + Assert.Equal(od.prop.CO_storageGroup, tmp.Objects[od.Index.ToString()].StorageGroup); + } + [Theory] + [InlineData(OdSubObject.Types.AccessSRDO.No, AccessSRDO.no)] + [InlineData(OdSubObject.Types.AccessSRDO.Rx, AccessSRDO.rx)] + [InlineData(OdSubObject.Types.AccessSRDO.Trx, AccessSRDO.trx)] + [InlineData(OdSubObject.Types.AccessSRDO.Tx, AccessSRDO.tx)] + public void Test_ToProtobufferSubODObject_CustomProperties(OdSubObject.Types.AccessSRDO accessSRDO, AccessSRDO co_prop) + { + var eds = new EDSsharp + { + ods = new System.Collections.Generic.SortedDictionary() + }; + var od = new ODentry + { + objecttype = ObjectType.RECORD, + Index = 0x2000 + }; + var sub = new ODentry + { + parent = od, + }; + sub.prop.CO_accessSRDO = co_prop; + sub.prop.CO_stringLengthMin = 123; + + od.subobjects.Add(0x00, sub); + eds.ods.Add(od.Index, od); + var tmp = MappingEDS.MapToProtobuffer(eds); + + Assert.Equal(accessSRDO, tmp.Objects[od.Index.ToString()].SubObjects["0"].Srdo); + Assert.Equal(sub.prop.CO_stringLengthMin, tmp.Objects[od.Index.ToString()].SubObjects["0"].StringLengthMin); + } + [Fact] public void Test_FromProtobufferAssertConfig() { diff --git a/libEDSsharp/CanOpenEDSMapping.cs b/libEDSsharp/CanOpenEDSMapping.cs index afecaf3..6468f27 100644 --- a/libEDSsharp/CanOpenEDSMapping.cs +++ b/libEDSsharp/CanOpenEDSMapping.cs @@ -205,13 +205,13 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) .ForMember(dest => dest.LssMaster, opt => opt.MapFrom(src => src.LSS_Master)); cfg.CreateMap(); cfg.CreateMap() - .ForMember(dest => dest.Disabled, opt => opt.Ignore()) + .ForMember(dest => dest.Disabled, opt => opt.MapFrom(src => src.prop.CO_disabled)) .ForMember(dest => dest.Alias, opt => opt.Ignore()) - .ForMember(dest => dest.StorageGroup, opt => opt.Ignore()) + .ForMember(dest => dest.StorageGroup, opt => opt.MapFrom(src => src.prop.CO_storageGroup)) .ForMember(dest => dest.FlagsPDO, opt => opt.Ignore()) .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.parameter_name)) .ForMember(dest => dest.ObjectType, opt => opt.MapFrom(src => src.objecttype)) - .ForMember(dest => dest.CountLabel, opt => opt.MapFrom(src => src.Label)); + .ForMember(dest => dest.CountLabel, opt => opt.MapFrom(src => src.prop.CO_countLabel)); cfg.CreateMap().ConvertUsing(); cfg.CreateMap().ConvertUsing(); cfg.CreateMap().ConvertUsing(); @@ -221,8 +221,8 @@ public static CanOpenDevice MapToProtobuffer(EDSsharp source) .ForMember(dest => dest.DataType, opt => opt.MapFrom(src => src.datatype)) .ForMember(dest => dest.Sdo, opt => opt.MapFrom(src => src.accesstype)) .ForMember(dest => dest.Pdo, opt => opt.MapFrom(src => src.accesstype)) - .ForMember(dest => dest.Srdo, opt => opt.Ignore()) - .ForMember(dest => dest.StringLengthMin, opt => opt.MapFrom(src => src.Lengthofstring)); + .ForMember(dest => dest.Srdo, opt => opt.MapFrom(src => src.prop.CO_accessSRDO)) + .ForMember(dest => dest.StringLengthMin, opt => opt.MapFrom(src => src.prop.CO_stringLengthMin)); }); config.AssertConfigurationIsValid(); From 96af1e845214f8e025975d2b3cea14557708f57a Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sat, 14 Dec 2024 21:19:46 +0100 Subject: [PATCH 11/12] reverting unintended changes --- Tests/EDSParserTests.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Tests/EDSParserTests.cs b/Tests/EDSParserTests.cs index a1919b3..917f6eb 100644 --- a/Tests/EDSParserTests.cs +++ b/Tests/EDSParserTests.cs @@ -336,20 +336,16 @@ public void Test_datetimeparse() public void Test_accesstype() { { - Dictionary> section = new Dictionary> - { - { "[1234]", new Dictionary() } - }; + Dictionary> section = new Dictionary>(); + section.Add("[1234]", new Dictionary()); section["[1234]"].Add("AccessType", "ro"); KeyValuePair> kvp = section.Single(); this.ParseEDSentry(kvp); } { - Dictionary> section = new Dictionary> - { - { "[1234]", new Dictionary() } - }; + Dictionary> section = new Dictionary>(); + section.Add("[1234]", new Dictionary()); section["[1234]"].Add("AccessType", "RO"); KeyValuePair> kvp = section.Single(); this.ParseEDSentry(kvp); From e9582cfb4bd0fe7010bbbc8f02a8a7a0712561f3 Mon Sep 17 00:00:00 2001 From: Lars Elgtvedt Susaas Date: Sat, 14 Dec 2024 21:19:57 +0100 Subject: [PATCH 12/12] cleanup --- Tests/EDSMappingTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/EDSMappingTests.cs b/Tests/EDSMappingTests.cs index eb235ec..e03f3df 100644 --- a/Tests/EDSMappingTests.cs +++ b/Tests/EDSMappingTests.cs @@ -587,7 +587,7 @@ public void Test_FromProtobufferODObject_CustomProperties() Assert.Equal(od.StorageGroup, tmp.ods[index].prop.CO_storageGroup); } [Theory] - [InlineData(OdSubObject.Types.AccessSRDO.No, AccessSRDO.no )] + [InlineData(OdSubObject.Types.AccessSRDO.No, AccessSRDO.no)] [InlineData(OdSubObject.Types.AccessSRDO.Rx, AccessSRDO.rx)] [InlineData(OdSubObject.Types.AccessSRDO.Trx, AccessSRDO.trx)] [InlineData(OdSubObject.Types.AccessSRDO.Tx, AccessSRDO.tx)]