ln.ethercat/ln.ethercat/ECSlave.cs

181 lines
5.9 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, ushort bitlength, 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 ushort BitLength { get; private set; }
public string Name { get; private set; }
public ECDataTypes DataType { get; private set; }
public SDOValue(SDODescriptor descriptor,byte subIndex)
{
Descriptor = descriptor;
SubIndex = subIndex;
if ((Descriptor.MaxSubIndex > 0) && (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, ushort bitlength, String name)=>{
Name = (SubIndex == 0) ? descriptor.Name : name;
BitLength = bitlength;
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);
}
}
}
}