179 lines
5.7 KiB
C#
179 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using ln.collections;
|
|
using ln.ethercat.controller;
|
|
using ln.logging;
|
|
using ln.type;
|
|
|
|
namespace ln.ethercat
|
|
{
|
|
|
|
public class ECSlave
|
|
{
|
|
internal ECMaster ECMaster;
|
|
public UInt16 Id { get; }
|
|
|
|
MappingBTree<UInt16, SDODescriptor> sdoCache = new MappingBTree<UInt16, SDODescriptor>((sdo)=>sdo.Index);
|
|
|
|
public ECSlave(ECMaster ecMaster,UInt16 slave_id)
|
|
{
|
|
ECMaster = ecMaster;
|
|
Id = slave_id;
|
|
|
|
ECMBind.ecmbind_enumerate_servicedescriptors(Id, (int slave, int index)=>{
|
|
sdoCache.Add(new SDODescriptor(this, (UInt16)index));
|
|
});
|
|
|
|
foreach (SDODescriptor sdo in sdoCache)
|
|
sdo.Update();
|
|
}
|
|
|
|
public IEnumerable<SDODescriptor> GetSDODescriptors() => sdoCache.Values;
|
|
|
|
public bool GetDescriptor(UInt16 index, out SDODescriptor descriptor) => sdoCache.TryGet(index, out descriptor);
|
|
|
|
|
|
}
|
|
|
|
public class SDODescriptor
|
|
{
|
|
internal ECSlave Slave;
|
|
public UInt16 SlaveId => Slave.Id;
|
|
public UInt16 Index { get; }
|
|
|
|
public string Name { get; private set; }
|
|
public ECDataTypes DataType { get; set; }
|
|
public ECObjectCodes ObjectCode { get; set; }
|
|
public int MaxSubIndex { get; set; }
|
|
|
|
MappingBTree<byte, SDOValue> valueCache;
|
|
|
|
public SDODescriptor(ECSlave slave, UInt16 index)
|
|
{
|
|
Slave = slave;
|
|
Index = index;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (ECMBind.ecmbind_read_objectdescription(Slave.Id, Index, (int slave, int index, ECDataTypes dataType, ECObjectCodes objectCode, int maxsub, String name)=>{
|
|
Name = name;
|
|
DataType = dataType;
|
|
ObjectCode = objectCode;
|
|
MaxSubIndex = maxsub;
|
|
}) <= 0)
|
|
{
|
|
Logging.Log(LogLevel.WARNING, "cannot create SDO instance for {0}:{1:X4} not found.", Slave.Id, Index);
|
|
}
|
|
}
|
|
|
|
void EnsureValueCache()
|
|
{
|
|
if (valueCache == null)
|
|
{
|
|
valueCache = new MappingBTree<byte, SDOValue>((v)=>v.SubIndex);
|
|
for (byte subIndex = 0; subIndex <= MaxSubIndex; subIndex++)
|
|
valueCache.Add(new SDOValue(this, subIndex));
|
|
}
|
|
}
|
|
|
|
public IEnumerable<SDOValue> GetValues()
|
|
{
|
|
EnsureValueCache();
|
|
return valueCache.Values;
|
|
}
|
|
|
|
public SDOValue GetValue(byte subIndex)
|
|
{
|
|
EnsureValueCache();
|
|
return valueCache[subIndex];
|
|
}
|
|
|
|
public bool GetValue(byte subIndex, out SDOValue sdoValue)
|
|
{
|
|
EnsureValueCache();
|
|
return valueCache.TryGet(subIndex, out sdoValue);
|
|
}
|
|
|
|
|
|
public override string ToString() => String.Format("[SDODescriptor Slave={0} Index=0x{1:X4} ObjectCode={2} DataType={3}]", Slave.Id, Index, ObjectCode, DataType);
|
|
}
|
|
|
|
public class SDOValue
|
|
{
|
|
public SDODescriptor Descriptor;
|
|
public byte SubIndex { get; }
|
|
|
|
public string Name { get; private set; }
|
|
public ECDataTypes DataType { get; private set; }
|
|
|
|
public SDOValue(SDODescriptor descriptor,byte subIndex)
|
|
{
|
|
Descriptor = descriptor;
|
|
SubIndex = subIndex;
|
|
|
|
if (SubIndex == 0)
|
|
{
|
|
DataType = descriptor.DataType;
|
|
Name = descriptor.Name;
|
|
} else {
|
|
if (ECMBind.ecmbind_read_objectdescription_entry(Descriptor.SlaveId, descriptor.Index, SubIndex, (int slave, int index, ECDataTypes dataType, ECObjectCodes objectCode, int si, String name)=>{
|
|
Name = name;
|
|
DataType = dataType;
|
|
}) <= 0)
|
|
{
|
|
Logging.Log(LogLevel.WARNING, "SDOValue: could not read object description entry {0}:{1:X4}.{2}", descriptor.SlaveId, descriptor.Index, SubIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public T GetValue<T>() => (T)GetValue();
|
|
public object GetValue(){
|
|
if (GetValue(out object value))
|
|
return value;
|
|
throw new IOException();
|
|
}
|
|
public bool GetValue(out object value)
|
|
{
|
|
if (GetRawValue(out byte[] data))
|
|
return ECDataTypeConverter.FromEthercat(DataType, data, out value);
|
|
value = null;
|
|
return false;
|
|
}
|
|
|
|
public bool GetRawValue(out byte[] rawValue)
|
|
{
|
|
if (Descriptor.Slave.ECMaster.GetPDOItem(this, out PDO pdo))
|
|
{
|
|
return Descriptor.Slave.ECMaster.GetIOmapData(pdo.AddressOffset, pdo.ByteLength, out rawValue);
|
|
} else {
|
|
return Descriptor.Slave.ECMaster.ReadSDO(Descriptor.SlaveId, Descriptor.Index, SubIndex, out rawValue);
|
|
}
|
|
}
|
|
|
|
public void SetValue<T>(T value)
|
|
{
|
|
if (ECDataTypeConverter.ToEthercat(DataType, value, out byte[] rawValue))
|
|
{
|
|
SetRawValue(rawValue);
|
|
} else {
|
|
Logging.Log(LogLevel.ERROR, "SDOValue: SetValue<>({0}): could not convert to ethercat", value);
|
|
}
|
|
}
|
|
|
|
public void SetRawValue(byte[] rawValue)
|
|
{
|
|
if (Descriptor.Slave.ECMaster.GetPDOItem(this, out PDO pdo))
|
|
{
|
|
Descriptor.Slave.ECMaster.SetIOmapData(pdo.AddressOffset, pdo.ByteLength, rawValue);
|
|
} else {
|
|
Descriptor.Slave.ECMaster.WriteSDO(Descriptor.SlaveId, Descriptor.Index, SubIndex, rawValue);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} |