using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; namespace FLY.Modbus { /// <summary> /// 通知命名数据改变是的参数 /// </summary> public class NameDataChangedEventArgs : EventArgs { /// <summary> /// 初始化 NameDataChangedEventArgs 类的新实例。 /// </summary> /// <param name="owner">数据类</param> /// <param name="propertyName">已更改的数据名。</param> public NameDataChangedEventArgs(object owner, string propertyName) { this.owner = owner; this.propertyName = propertyName; } object owner; string propertyName; /// <summary> /// 获取数据所属类 /// </summary> public object Owener { get { return owner; } } /// <summary> /// 获取已更改的数据名名。 /// </summary> public string PropertyName { get { return propertyName; } } } /// <summary> /// 通知Modbus数据改变的参数 /// </summary> public class ModbusDataChangedEventArgs : EventArgs { PLCAddressArea dataarea; int addr; int num; /// <summary> /// /// </summary> /// <param name="dataarea">数据类型</param> /// <param name="addr">地址</param> /// <param name="num">数量</param> public ModbusDataChangedEventArgs(PLCAddressArea dataarea, int addr, int num) { this.dataarea = dataarea; this.addr = addr; this.num = num; } /// <summary> /// 数据类型 /// </summary> public virtual PLCAddressArea DataArea { get { return dataarea; } } /// <summary> /// 地址 /// </summary> public virtual int Addr { get { return addr; } } /// <summary> /// 数量 /// </summary> public virtual int Num { get { return num; } } } /// <summary> /// NameData 改变事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public delegate void NameDataChangedEventHandler(object sender, NameDataChangedEventArgs e); /// <summary> /// ModbusData 改变事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public delegate void ModbusDataChangedEventHandler(object sender, ModbusDataChangedEventArgs e); /// <summary> /// 命名数据到Modbus数据的映射 /// </summary> public class ModbusMapper : IModbusRegister, INotifyPropertyChanged { /// <summary> /// 一次读取的数据量 /// </summary> const int MaxRegsOfOneRead = 50; const int MaxCoilsOfOneRead = 800; #region 数据变化通知 /// <summary> /// 命名数据改变事件 /// </summary> public event NameDataChangedEventHandler NameDataChanged; protected void NotifyNameDataChanged(object dataclass, string dataname) { NameDataChanged?.Invoke(this, new NameDataChangedEventArgs(dataclass, dataname)); } public event ModbusDataChangedEventHandler ModbusDataChanged; public event PropertyChangedEventHandler PropertyChanged; protected void NotifyModbusDataChanged(PLCAddressArea dataarea, int addr, int num) { ModbusDataChanged?.Invoke(this, new ModbusDataChangedEventArgs(dataarea, addr, num)); } #endregion #region 数据映射 /// <summary> /// 数据映射的类 /// </summary> public class DataToRegs { /// <summary> /// 所属的plc /// </summary> public ModbusMapper mapper; /// <summary> /// 对应 PLC寄存器区 coil or register /// </summary> public PLCAddressArea dataArea; /// <summary> /// PLC 首地址 /// </summary> public int addr; /// <summary> /// value 的C#类型 float,int16,int32 /// </summary> public REG_TYPE type; /// <summary> /// 放大倍数, value * scale 才是属性的值 /// </summary> public double scale; /// <summary> /// object /// </summary> public object owner; /// <summary> /// object 的 property 名称, 只能是 数字类型都是double, 剩下就是 bool /// </summary> public string propertyName; /// <summary> /// property 的值, 没有缩小. 只有 double 与 bool /// </summary> public object value; /// <summary> /// 需要从PLC读取数据更新 /// </summary> public bool isNeedUpdate = false; /// <summary> /// /// </summary> /// <param name="mapper"></param> /// <param name="dataArea"></param> /// <param name="addr"></param> /// <param name="type"></param> /// <param name="scale"></param> /// <param name="owner"></param> /// <param name="propertyname"></param> public DataToRegs(ModbusMapper mapper, PLCAddressArea dataArea, int addr, REG_TYPE type, double scale, object owner, string propertyname) { this.mapper = mapper; this.dataArea = dataArea; this.addr = addr; this.type = type; this.scale = scale; this.owner = owner; this.propertyName = string.Copy(propertyname); } /// <summary> /// C# 类型数据 转 PLC寄存器 /// </summary> /// <param name="value"></param> /// <returns></returns> public bool[] ToBools(object value) { bool b = (bool)value; return new bool[] { b }; } /// <summary> /// C# 类型数据 转 PLC寄存器, 会/scale /// </summary> /// <param name="value"></param> /// <returns></returns> public ushort[] ToRegs(object value) { return RegTypeConverter.ToRegs(value, type, scale); } public override string ToString() { return propertyName+ " [" + ((int)dataArea).ToString() + "](" + addr + ")" ; } } /// <summary> /// 数据映射表,根据这个表,以后自动更新PLC寄存器,或更新property /// </summary> public List<DataToRegs> DRmap = new List<DataToRegs>(); /// <summary> /// 查找数据-寄存器对应表 /// </summary> public DataToRegs FindDataMap(object owner, string propertyName) { return DRmap.Find((dr) => { return (dr.propertyName == propertyName && dr.owner == owner); }); } /// <summary> /// 数据映射到寄存器 /// </summary> /// <param name="dataArea">modbus 寄存器类型</param> /// <param name="addr">modbus 寄存器首地址</param> /// <param name="type">plc 数据对应类型</param> /// <param name="scale">plc 数据放大倍数</param> /// <param name="obj">Property 所属对象</param> /// <param name="propertyname">Property Name</param> /// <returns></returns> public DataToRegs MapDataToRegs(PLCAddressArea dataArea, int addr, REG_TYPE type, double scale, object obj, string propertyname) { DataToRegs dr = FindDataMap(obj, propertyname); if (dr == null) { dr = new DataToRegs(this, dataArea, addr, type, scale, obj, propertyname); DRmap.Add(dr); DRmap.Sort(delegate (DataToRegs X, DataToRegs Y) { int ct = X.dataArea.CompareTo(Y.dataArea); if (ct != 0) return ct; return X.addr.CompareTo(Y.addr); }); return dr; } return null; } public ModbusMapper() { registers = new RegisterData(PLCAddressArea.Register, MaxRegsOfOneRead); coils = new CoilData(PLCAddressArea.Coil, MaxCoilsOfOneRead); mAreaManager.Add(registers); mAreaManager.Add(coils); } #endregion #region Modbus数据 /// <summary> /// 每次向PLC读取寄存器的任务 /// </summary> public class Plan { /// <summary> /// coil or register /// </summary> public PLCAddressArea area; /// <summary> /// 地址 /// </summary> public int addr; /// <summary> /// 数量 /// </summary> public int num; /// <summary> /// 是否正在读取 /// </summary> public bool isDoing; /// <summary> /// /// </summary> /// <param name="area"></param> /// <param name="addr"></param> /// <param name="num"></param> public Plan(PLCAddressArea area, int addr, int num) { this.area = area; this.addr = addr; this.num = num; } } public abstract class PLCRegObj { /// <summary> /// 该寄存器所属的 property /// </summary> public DataToRegs dr; /// <summary> /// 最后一个寄存器地址 /// </summary> public int EndAddr; public PLCRegObj() { } public virtual void Init(DataToRegs dr) { this.dr = dr; EndAddr = dr.addr; } public override string ToString() { return dr.ToString(); } } /// <summary> /// PLC中的寄存器对象 /// </summary> public class Register : PLCRegObj { /// <summary> /// 寄存器当前值 /// </summary> public UInt16[] value; /// <summary> /// 寄存器值是否改变 /// </summary> public bool changed; public override void Init(DataToRegs dr) { base.Init(dr); value = new UInt16[RegSize(dr.type)]; EndAddr = dr.addr + value.Count() - 1; } } /// <summary> /// PLC中的继电器对象, 与 Regs 对应 /// </summary> public class Coil : PLCRegObj { /// <summary> /// Coil的值 /// </summary> public bool value; } public abstract class AreaManagerBase { protected List<Plan> plan = new List<Plan>(); protected int currIndex = 0; /// <summary> /// 获取下一个plan,返回下一个plan,若已经到了最后一个,则在开始 /// 下一个之前,返回一个null /// </summary> /// <returns></returns> public Plan GetNextPlan() { int cnt = plan.Count(); if (cnt <= 0) return null; if (currIndex >= cnt) { currIndex = 0; return null; } Plan p = plan.ElementAt(currIndex); currIndex += 1; return p; } /// <summary> /// 清除doing状态 /// </summary> public void ClearPlanState() { foreach (Plan p in plan) { p.isDoing = false; } currIndex = 0; } } public abstract class AreaManager<T> :AreaManagerBase where T : PLCRegObj, new() { /// <summary> /// 一个property 对应 N个 PLC寄存器; /// 地址必须是从小到大排列,不能有重叠 /// </summary> public List<T> regs = new List<T>(); protected PLCAddressArea area; protected int currIndex = 0; protected int maxOfOneRead = 50; public AreaManager(PLCAddressArea area, int maxOfOneRead) { this.area = area; this.maxOfOneRead = maxOfOneRead; } /// <summary> /// 根据DataToRegs列表构建数组 /// </summary> public virtual void BuildArray(List<DataToRegs> DRmap) { List<DataToRegs> drs = DRmap.FindAll((c) => { return c.dataArea == area; }); // 分配寄存器存储空间 regs.Clear(); foreach (DataToRegs dr in drs) { T r = new T(); r.Init(dr); regs.Add(r); } regs.Sort((r1, r2) => { if (r1.dr.addr < r2.dr.addr) return -1; else if (r1.dr.addr > r2.dr.addr) return 1; else return 0; }); } /// <summary> /// 根据当前regs的配置指定读寄存器的计划 /// </summary> public abstract void MakePlan(); } /// <summary> /// property 与 PLC继电器 更新操作,与 RegsData 对应 /// </summary> public class CoilData : AreaManager<Coil> { public CoilData(PLCAddressArea area, int maxOfOneRead) : base(area, maxOfOneRead) { } /// <summary> /// 根据当前regs的配置指定读寄存器的计划 /// </summary> public override void MakePlan() { //this.maxOfOneRead = maxOfOneRead; if (regs == null) { throw new Exception("还没有执行 BuildArray()"); } plan.Clear(); int addr = -1; int num = 0; for (int i = 0; i < regs.Count(); i++) { if (!regs[i].dr.isNeedUpdate) continue; if (addr == -1) { addr = regs[i].dr.addr; num = 1; } else { int n = regs[i].dr.addr - addr + 1; if (n <= maxOfOneRead) { num = n; } else { plan.Add(new Plan(area, addr, num)); addr = -1; i--; } } } if (addr != -1) { plan.Add(new Plan(area, addr, num)); addr = -1; } } } /// <summary> /// property 与 PLC寄存器 更新操作 /// </summary> public class RegisterData: AreaManager<Register> { /// <summary> /// /// </summary> public RegisterData(PLCAddressArea area, int maxOfOneRead):base(area,maxOfOneRead) { } /// <summary> /// 根据当前regs的配置指定读寄存器的计划 /// </summary> public override void MakePlan() { if (regs == null) { throw new Exception("还没有执行 BuildArray()"); } plan.Clear(); int addr=-1; int num=0; for (int i = 0; i < regs.Count(); i++) { if (!regs[i].dr.isNeedUpdate) continue; if (addr == -1) { addr = regs[i].dr.addr; num = regs[i].value.Count(); if (num > maxOfOneRead) { //一片区域已经大于 最大读取寄存器数,分拆 while (num > maxOfOneRead) { plan.Add(new Plan(area, addr, maxOfOneRead)); addr += maxOfOneRead; num -= maxOfOneRead; } if (num > 0) plan.Add(new Plan(area, addr, num)); addr = -1; } } else { int n = regs[i].dr.addr + regs[i].value.Count() - 1 - addr + 1; if (n <= maxOfOneRead) { num = n; } else { plan.Add(new Plan(area, addr, num)); addr = -1; i--; } } } if (addr != -1) { plan.Add(new Plan(area, addr, num)); addr = -1; } } } /// <summary> /// PLC寄存器 对应的 property /// </summary> public RegisterData registers; /// <summary> /// PLC 继电器 对应的 property /// </summary> public CoilData coils; public List<AreaManagerBase> mAreaManager = new List<AreaManagerBase>(); #endregion #region 数据读写 /// <summary> /// 为命名数据赋值,会改变Modbus的寄存器值,并产生通知 /// </summary> /// <param name="obj">属性所属的对象, 可为null</param> /// <param name=propertyName">属性名,不能为空</param> /// <param name="val">数据值,不能为空</param> /// <returns>赋值的结果</returns> public virtual bool SetNameData(object obj, string propertyName, object val) { DataToRegs dr = FindDataMap(obj, propertyName); if (dr == null) return false; return SetNameData(dr, val); } /// <summary> /// PC想向PLC写入数据; /// 为命名数据赋值,会改变Modbus的寄存器值,并产生通知 /// </summary> /// <param name="dr">数据映射</param> /// <param name="val">数据值,不能为空</param> /// <returns></returns> public virtual bool SetNameData(DataToRegs dr, object val) { dr.value = val; switch (dr.dataArea) { case PLCAddressArea.Coil: { Coil c = coils.regs.Find(_c => { return _c.dr == dr; }); c.value = (bool)val; NotifyModbusDataChanged(PLCAddressArea.Coil, dr.addr, 1); } return true; case PLCAddressArea.Register: { ushort[] regs_data = dr.ToRegs(val); Register r = registers.regs.Find(_r => { return _r.dr == dr; }); if (regs_data.Count() != r.value.Count()) { throw new Exception("DataToRegs转换的类型长度 与 Regs 的长度不一致"); } Array.Copy(regs_data, r.value, regs_data.Count()); NotifyModbusDataChanged(PLCAddressArea.Register, dr.addr, regs_data.Count()); } return true; } return false; } /// <summary> /// 取命名数据的值 /// </summary> /// <param name="obj">属性所属 的对象</param> /// <param name="propertyName">属性名</param> /// <returns>属性的值</returns> public virtual object GetNameData(object obj, string propertyName) { DataToRegs dr = FindDataMap(obj, propertyName); if (dr == null) return null; return dr.value; } #region IModbusRegister实现 /// <summary> /// 是从PLC读取数据后; /// 设置Modbus的值,会改变相应命名数据的值,并产生通知 /// </summary> /// <param name="dataarea">coil or register</param> /// <param name="addr">地址</param> /// <param name="value">值</param> /// <returns></returns> public virtual void SetModbusData(PLCAddressArea dataarea, int addr, object value) { switch (dataarea) { case PLCAddressArea.Register: { ushort[] vals = (ushort[])value; //找寄存器 int endAddr = addr + vals.Count() - 1; RegisterData area_regs = registers; for (int i = 0; i < area_regs.regs.Count(); i++) { if (endAddr < area_regs.regs[i].dr.addr) { //在前面 break; } else if (addr <= area_regs.regs[i].EndAddr)//有交集 { int addr_act = Math.Max(addr, area_regs.regs[i].dr.addr); int endAddr_act = Math.Min(endAddr, area_regs.regs[i].EndAddr); int num_act = endAddr_act - addr_act + 1; for (int j = 0; j < num_act; j++) { int idx1 = addr_act - area_regs.regs[i].dr.addr + j; int idx2 = addr_act - addr + j; if (area_regs.regs[i].value[idx1] != vals[idx2]) { area_regs.regs[i].value[idx1] = vals[idx2]; area_regs.regs[i].changed = true; } } if (endAddr_act == area_regs.regs[i].EndAddr) { if (area_regs.regs[i].changed) { area_regs.regs[i].changed = false; DataToRegs dr = area_regs.regs[i].dr; //触发事件 dr.value = RegTypeConverter.ToObject( area_regs.regs[i].value, dr.type, dr.scale); NotifyNameDataChanged(dr.owner, dr.propertyName); } } } else { //在后面 } } }break; case PLCAddressArea.Coil: { bool[] vals = (bool[])value; //找寄存器 int endAddr = addr + vals.Count() - 1; CoilData area_coils = coils; for (int i = 0; i < area_coils.regs.Count(); i++) { if (endAddr < area_coils.regs[i].dr.addr) { //在前面 break; } else if (addr <= area_coils.regs[i].dr.addr)//有交集 { int addr_act = area_coils.regs[i].dr.addr; int idx2 = addr_act - addr; if (area_coils.regs[i].value != vals[idx2]) { area_coils.regs[i].value = vals[idx2]; DataToRegs dr = area_coils.regs[i].dr; //触发事件 dr.value = area_coils.regs[i].value; NotifyNameDataChanged(dr.owner, dr.propertyName); } } else { //在后面 } } }break; } } /// <summary> /// 获取Modbus的数据值 /// </summary> /// <param name="dataarea">0,1,3,4数据模型</param> /// <param name="addr">地址</param> /// <param name="num">数量</param> /// <returns></returns> public virtual object GetModbusData(PLCAddressArea dataarea, int addr, int num) { switch (dataarea) { case PLCAddressArea.Register: { //多余,不需要实现的 //找寄存器 int endAddr = addr + num - 1; ushort[] ret = new UInt16[num]; RegisterData area_regs = registers; for (int i = 0; i < area_regs.regs.Count(); i++) { if (endAddr < area_regs.regs[i].dr.addr) { //在前面 break; } else if (addr <= area_regs.regs[i].EndAddr)//有交集 { int addr_act = Math.Max(addr, area_regs.regs[i].dr.addr); int endAddr_act = Math.Min(endAddr, area_regs.regs[i].EndAddr); int num_act = endAddr_act - addr_act + 1; for (int j = 0; j < num_act; j++) { int idx1 = addr_act - area_regs.regs[i].dr.addr + j; int idx2 = addr_act - addr + j; ret[idx2] = area_regs.regs[i].value[idx1]; } } else { //在后面 } } return ret; }break; case PLCAddressArea.Coil: { //多余,不需要实现的 //找寄存器 int endAddr = addr + num - 1; bool[] ret = new bool[num]; CoilData area_regs = coils; for (int i = 0; i < area_regs.regs.Count(); i++) { if (endAddr < area_regs.regs[i].dr.addr) { //在前面 break; } else if (addr <= area_regs.regs[i].dr.addr)//有交集 { int addr_act = area_regs.regs[i].dr.addr; int idx2 = addr_act - addr; ret[idx2] = area_regs.regs[i].value; } else { //在后面 } } return ret; } default: throw new Exception("GetModbusData, datamode=" + dataarea + " 不存在的类型"); } } #endregion #endregion #region 类的静态函数 /// <summary> /// C#类型,对应PLC寄存器个数 /// </summary> /// <param name="type"></param> /// <returns></returns> public static int RegSize(REG_TYPE type) { switch (type) { case REG_TYPE.FLOAT: return sizeof(float) / sizeof(Int16); case REG_TYPE.UINT16: return sizeof(UInt16) / sizeof(Int16); case REG_TYPE.INT32: return sizeof(Int32) / sizeof(Int16); case REG_TYPE.INT16: return sizeof(Int16) / sizeof(Int16); case REG_TYPE.UINT32: return sizeof(Int32) / sizeof(Int16); default: { throw new NotImplementedException("不支持类型 " + type); } } } /// <summary> /// string 转 C#类型 /// </summary> /// <param name="typename"></param> /// <returns></returns> public static REG_TYPE TranslateToREG_TYPE(string typename) { typename = typename.ToLower(); if (typename == "int32") return REG_TYPE.INT32; if (typename == "uint32") return REG_TYPE.UINT32; if (typename == "bool") return REG_TYPE.BOOL; if (typename == "int16") return REG_TYPE.INT16; if (typename == "uint16") return REG_TYPE.UINT16; if (typename == "float") return REG_TYPE.FLOAT; return REG_TYPE.Unknown; } /// <summary> /// string 转modbus类型 /// </summary> /// <param name="dm"></param> /// <returns></returns> public static PLCAddressArea TranslateToPLCAddressArea(string dm) { if (dm.CompareTo("0") == 0) return PLCAddressArea.Coil; if (dm.CompareTo("1") == 0) return PLCAddressArea.Coil; if (dm.CompareTo("3") == 0) return PLCAddressArea.Register; if (dm.CompareTo("4") == 0) return PLCAddressArea.Register; else { throw new Exception("{0} 不是合法的 PLCAddressArea类型"); } } #endregion #region 寄存器读取更新计划 Dictionary<object, List<DataToRegs>> plans = new Dictionary<object, List<DataToRegs>>(); /// <summary> /// 登记寄存器更新计划 /// </summary> /// <param name="owner"></param> /// <param name="propertyName"></param> public void PlanAdd(object key, DataToRegs dr) { if (plans.ContainsKey(key)) { if (!plans[key].Contains(dr)) plans[key].Add(dr); } else { plans.Add(key, new List<DataToRegs>()); plans[key].Add(dr); } } /// <summary> /// 删除寄存器更新计划 /// </summary> /// <param name="key"></param> public void PlanRemove(object key) { plans.Remove(key); } /// <summary> /// 删除全部寄存器更新计划 /// </summary> public void PlanClear() { plans.Clear(); } /// <summary> /// 需要被更新的 寄存器数量 /// </summary> public int DRNeedUpdateCnt { get; private set; } /// <summary> /// 总寄存器数量 /// </summary> public int DRCnt { get; private set; } /// <summary> /// 创建寄存器更新计划 /// </summary> public void PlanMake() { foreach (DataToRegs dr in DRmap) { dr.isNeedUpdate = false; } foreach (KeyValuePair<object, List<DataToRegs>> kv in plans) { foreach (DataToRegs dr in kv.Value) { dr.isNeedUpdate = true; } } DRNeedUpdateCnt = DRmap.Count((dr) => dr.isNeedUpdate); DRCnt = DRmap.Count; //TODO, 应该提前做!!!! registers.BuildArray(DRmap); coils.BuildArray(DRmap); registers.MakePlan(); coils.MakePlan(); } #endregion } /// <summary> /// C# 类型枚举 /// </summary> public enum REG_TYPE { /// <summary> /// 出错 /// </summary> Unknown = 0, /// <summary> /// float /// </summary> FLOAT = 1, /// <summary> /// uint16 /// </summary> UINT16 = 2, /// <summary> /// int16 /// </summary> INT16 = 3, /// <summary> /// uint32 /// </summary> UINT32 = 4, /// <summary> /// int32 /// </summary> INT32 = 5, /// <summary> /// bool /// </summary> BOOL = 6, } /// <summary> /// PLC寄存器 与 C# 类型数据 转换, 不含bool /// </summary> public class RegTypeConverter { /// <summary> /// PLC寄存器 转 C# 类型数据 /// </summary> /// <param name="data">PLC 寄存器数据</param> /// <param name="type">PLC 数据类型</param> /// <param name="scale">PLC数据放大倍数</param> /// <returns></returns> public static object ToObject(ushort[] data, REG_TYPE type,double scale) { switch (type) { //case REG_TYPE.BOOL: // { // return data[0] != 0 ? true : false; // } case REG_TYPE.INT16: { float v = (Int16)data[0]; v = (float)(v * scale); return v; } case REG_TYPE.UINT16: { float v = (UInt16)data[0]; v = (float)(v * scale); return v; } case REG_TYPE.UINT32: { float v = (UInt32)(data[0] | (data[1] << 16)); v = (float)(v * scale); return v; } case REG_TYPE.INT32: { float v = (Int32)(data[0] | (data[1] << 16)); v = (float)(v * scale); return v; } case REG_TYPE.FLOAT: { byte[] dat = new byte[] { (byte)data[0], (byte)(data[0] >> 8), (byte)data[1], (byte)(data[1] >> 8) }; float v = BitConverter.ToSingle(dat, 0); if ((v > 1000000) || (v < -1000000)) v = 0; v = (float)(v * scale); return v; } default: { throw new Exception("ToObject type=" + type + "不支持的类型"); } } } /// <summary> /// C# 类型数据 转 PLC寄存器 /// </summary> /// <param name="value">C#中数值 只能是 float or bool</param> /// <param name="type">PLC 数据类型</param> /// <param name="scale">PLC数据放大倍数</param> /// <returns></returns> public static ushort[] ToRegs(object value, REG_TYPE type, double scale) { byte[] bs; //if (type == REG_TYPE.BOOL) //{ // bool v = (bool)value; // if (v) // { // return new ushort[1] { 1 }; // } // else // { // return new ushort[1] { 0 }; // } //} float f = (float)value; f = (float)(f / scale); switch (type) { case REG_TYPE.INT16: { short v = (short)f; return new ushort[] { (ushort)v }; } case REG_TYPE.UINT16: { ushort v = (ushort)f; return new ushort[] { v }; } case REG_TYPE.FLOAT: { float v = (float)f; bs = BitConverter.GetBytes(v); return new ushort[] { (ushort)((bs[1] << 8) | bs[0]), (ushort)((bs[3] << 8) | bs[2]) }; }break; case REG_TYPE.INT32: { Int32 v = (Int32)f; bs = BitConverter.GetBytes(v); return new ushort[] { (ushort)((bs[1] << 8) | bs[0]), (ushort)((bs[3] << 8) | bs[2]) }; } case REG_TYPE.UINT32: { UInt32 v = (UInt32)f; bs = BitConverter.GetBytes(v); return new ushort[] { (ushort)((bs[1] << 8) | bs[0]), (ushort)((bs[3] << 8) | bs[2]) }; } } return null; } } }