Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Thick-Common
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
潘栩锋
Thick-Common
Commits
620060c9
Commit
620060c9
authored
Aug 20, 2019
by
潘栩锋
🚴
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1. 添加 FLY.ModbusMapper
parent
39a52e19
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
2245 additions
and
895 deletions
+2245
-895
AreaManager.cs
Project.FLY.ModbusMapper/FLY.ModbusMapper/AreaManager.cs
+179
-0
ClientTCP.cs
Project.FLY.ModbusMapper/FLY.ModbusMapper/ClientTCP.cs
+1
-1
CoilData.cs
Project.FLY.ModbusMapper/FLY.ModbusMapper/CoilData.cs
+72
-0
DataToRegs.cs
Project.FLY.ModbusMapper/FLY.ModbusMapper/DataToRegs.cs
+174
-0
FLY.ModbusMapper.csproj
...FLY.ModbusMapper/FLY.ModbusMapper/FLY.ModbusMapper.csproj
+13
-7
ModbusMapper.cs
Project.FLY.ModbusMapper/FLY.ModbusMapper/ModbusMapper.cs
+112
-833
ModbusMapper_Client.cs
....FLY.ModbusMapper/FLY.ModbusMapper/ModbusMapper_Client.cs
+43
-51
Pack_Proto.cs
Project.FLY.ModbusMapper/FLY.ModbusMapper/Pack_Proto.cs
+3
-3
RegTypeConverter.cs
...ect.FLY.ModbusMapper/FLY.ModbusMapper/RegTypeConverter.cs
+174
-0
RegisterData.cs
Project.FLY.ModbusMapper/FLY.ModbusMapper/RegisterData.cs
+91
-0
ClientTCP.cs
...FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ClientTCP.cs
+409
-0
IModbusClient.cs
...ModbusMapper/FLY.ModbusMapper/WithThread/IModbusClient.cs
+90
-0
IModbusServer.cs
...ModbusMapper/FLY.ModbusMapper/WithThread/IModbusServer.cs
+48
-0
ModbusMapper_Client.cs
...Mapper/FLY.ModbusMapper/WithThread/ModbusMapper_Client.cs
+278
-0
ServerTCP.cs
...FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ServerTCP.cs
+558
-0
No files found.
Project.FLY.ModbusMapper/FLY.ModbusMapper/AreaManager.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
FLY.Modbus
{
/// <summary>
/// PLC 区管理
/// </summary>
public
abstract
class
AreaManager
{
/// <summary>
/// 现在工作中的读取计划任务
/// </summary>
public
List
<
Plan
>
plan
=
new
List
<
Plan
>();
/// <summary>
/// 当true, plan_buffer -> plan
/// </summary>
protected
bool
isPlanChanged
=
false
;
/// <summary>
/// 设置读取计划任务时的缓冲,目前线程安全
/// </summary>
protected
List
<
Plan
>
plan_buffer
=
new
List
<
Plan
>();
/// <summary>
/// 当前执行的计划任务序号
/// </summary>
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
;
}
/// <summary>
/// 一个property 对应 N个 PLC寄存器;
/// 地址必须是从小到大排列,不能有重叠
/// </summary>
public
List
<
DataToRegs
>
regs
=
new
List
<
DataToRegs
>();
protected
PLCAddressArea
area
;
protected
int
maxOfOneRead
=
50
;
public
AreaManager
(
PLCAddressArea
area
,
int
maxOfOneRead
)
{
this
.
area
=
area
;
this
.
maxOfOneRead
=
maxOfOneRead
;
}
/// <summary>
/// 根据DataToRegs列表构建数组
/// </summary>
public
void
BuildArray
(
List
<
DataToRegs
>
DRmap
)
{
List
<
DataToRegs
>
drs
=
DRmap
.
FindAll
((
c
)
=>
{
return
c
.
dataArea
==
area
;
});
// 分配寄存器存储空间
regs
.
Clear
();
foreach
(
DataToRegs
dr
in
drs
)
{
regs
.
Add
(
dr
);
}
regs
.
Sort
((
r1
,
r2
)
=>
{
if
(
r1
.
addr
<
r2
.
addr
)
return
-
1
;
else
if
(
r1
.
addr
>
r2
.
addr
)
return
1
;
else
return
0
;
});
}
/// <summary>
///
/// </summary>
public
void
MakePlanReal
()
{
lock
(
plan_buffer
)
{
if
(
isPlanChanged
)
{
isPlanChanged
=
false
;
plan
.
Clear
();
plan
.
AddRange
(
plan_buffer
);
}
}
}
/// <summary>
/// 根据当前regs的配置指定读寄存器的计划
/// 只是设置 plan_buffer
/// </summary>
public
abstract
void
MakePlan
();
/// <summary>
/// 从本地PC 属性获取value 更新到 本地PLC 寄存器,
/// 目的: 当从PLC读取寄存器值时,能比较不同,产生变化事件
/// </summary>
public
void
SetAllIsPlcValueChanged
()
{
foreach
(
DataToRegs
dr
in
regs
)
{
dr
.
isPlcValueChanged
=
true
;
}
}
}
/// <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
;
}
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/ClientTCP.cs
View file @
620060c9
...
...
@@ -118,7 +118,7 @@ namespace FLY.Modbus
{
Pack_Proto
p
=
new
Pack_Proto
();
int
rlen
;
if
(!
p
.
TryParse
(
inBuf
,
startIndex
,
out
rlen
))
if
(!
p
.
TryParse
(
inBuf
,
startIndex
,
inBuf
.
Length
,
out
rlen
))
{
//处理失败
return
startIndex
;
...
...
Project.FLY.ModbusMapper/FLY.ModbusMapper/CoilData.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
FLY.Modbus
{
/// <summary>
/// property 与 PLC继电器 更新操作,与 RegsData 对应
/// </summary>
public
class
CoilData
:
AreaManager
{
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()"
);
}
lock
(
plan_buffer
)
{
plan_buffer
.
Clear
();
int
addr
=
-
1
;
int
num
=
0
;
for
(
int
i
=
0
;
i
<
regs
.
Count
();
i
++)
{
if
(!
regs
[
i
].
isNeedUpdate
)
continue
;
if
(
addr
==
-
1
)
{
addr
=
regs
[
i
].
addr
;
num
=
1
;
}
else
{
int
n
=
regs
[
i
].
addr
-
addr
+
1
;
if
(
n
<=
maxOfOneRead
)
{
num
=
n
;
}
else
{
plan_buffer
.
Add
(
new
Plan
(
area
,
addr
,
num
));
addr
=
-
1
;
i
--;
}
}
}
if
(
addr
!=
-
1
)
{
plan_buffer
.
Add
(
new
Plan
(
area
,
addr
,
num
));
addr
=
-
1
;
}
isPlanChanged
=
true
;
}
}
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/DataToRegs.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
FLY.Modbus
{
/// <summary>
/// 数据映射的类;
/// Data: PC 属性
/// Regs: PLC 对象(寄存器、线圈)
/// </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>
/// PLC 尾地址
/// </summary>
public
int
endAddr
;
/// <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 obj ,bool or UInt16[]
/// </summary>
public
object
plcValue
;
/// <summary>
/// PLC obj 寄存器值是否改变
/// </summary>
public
bool
isPlcValueChanged
;
/// <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
);
if
(
type
==
REG_TYPE
.
BOOL
)
{
plcValue
=
false
;
endAddr
=
addr
;
}
else
{
plcValue
=
new
UInt16
[
ModbusMapper
.
RegSize
(
type
)];
endAddr
=
addr
+
((
UInt16
[])
plcValue
).
Count
()
-
1
;
}
}
/// <summary>
/// PLC 对象(寄存器、线圈)转 PC 属性
/// </summary>
/// <param name="plc_value">bool or UInt16[]</param>
/// <returns></returns>
public
object
ToPropertyObj
(
object
plc_value
)
{
if
(
type
==
REG_TYPE
.
BOOL
)
{
return
plc_value
;
}
else
{
return
RegTypeConverter
.
ToObject
((
UInt16
[])
plc_value
,
type
,
scale
);
}
}
/// <summary>
/// PLC 对象(寄存器、线圈)转 PC 属性, 本地
/// </summary>
public
void
ToPropertyObj
()
{
value
=
ToPropertyObj
(
plcValue
);
}
/// <summary>
/// PC 属性 转 PLC 对象(寄存器、线圈)
/// </summary>
/// <param name="value"></param>
/// <returns>bool or UInt16[]</returns>
public
object
ToPLCObj
(
object
value
)
{
if
(
type
==
REG_TYPE
.
BOOL
)
return
value
;
else
return
RegTypeConverter
.
ToRegs
(
value
,
type
,
scale
);
}
/// <summary>
/// PC 属性 转 PLC 对象(寄存器、线圈), 本地
/// </summary>
public
void
ToPLCObj
()
{
object
plcobj
=
ToPLCObj
(
value
);
//更新 本地的 PLC 数据
switch
(
dataArea
)
{
case
PLCAddressArea
.
Coil
:
plcValue
=
plcobj
;
break
;
case
PLCAddressArea
.
Register
:
{
UInt16
[]
src
=
plcobj
as
UInt16
[];
UInt16
[]
dest
=
plcValue
as
UInt16
[];
Array
.
Copy
(
src
,
dest
,
dest
.
Length
);
}
break
;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public
override
string
ToString
()
{
return
propertyName
+
" ["
+
((
int
)
dataArea
).
ToString
()
+
"]("
+
addr
+
")"
;
}
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/FLY.ModbusMapper.csproj
View file @
620060c9
...
...
@@ -46,14 +46,23 @@
<Reference
Include=
"System.Xml"
/>
</ItemGroup>
<ItemGroup>
<Compile
Include=
"AreaManager.cs"
/>
<Compile
Include=
"CoilData.cs"
/>
<Compile
Include=
"RegisterData.cs"
/>
<Compile
Include=
"RegTypeConverter.cs"
/>
<Compile
Include=
"ClientTCP.cs"
/>
<Compile
Include=
"DataToRegs.cs"
/>
<Compile
Include=
"ModbusMapper_Client.cs"
/>
<Compile
Include=
"IModbusClient.cs"
/>
<Compile
Include=
"IModbusRegister.cs"
/>
<Compile
Include=
"ModbusMapper.cs"
/>
<Compile
Include=
"Pack_Proto.cs"
/>
<Compile
Include=
"PLCGroup.cs"
/>
<Compile
Include=
"Properties\AssemblyInfo.cs"
/>
<Compile
Include=
"WithThread\ClientTCP.cs"
/>
<Compile
Include=
"WithThread\IModbusClient.cs"
/>
<Compile
Include=
"WithThread\IModbusServer.cs"
/>
<Compile
Include=
"WithThread\ModbusMapper_Client.cs"
/>
<Compile
Include=
"WithThread\ServerTCP.cs"
/>
</ItemGroup>
<ItemGroup>
<ProjectReference
Include=
"..\..\Project.FLY.FObjSys\FObjSys\FObjBase.csproj"
>
...
...
@@ -70,14 +79,11 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource
Include=
"FodyWeavers.xml"
/>
<Resource
Include=
"FodyWeavers.xml"
>
<SubType>
Designer
</SubType>
</Resource>
</ItemGroup>
<ItemGroup>
<PackageReference
Include=
"Fody"
>
<Version>
4.2.1
</Version>
<IncludeAssets>
runtime; build; native; contentfiles; analyzers
</IncludeAssets>
<PrivateAssets>
all
</PrivateAssets>
</PackageReference>
<PackageReference
Include=
"PropertyChanged.Fody"
>
<Version>
2.6.1
</Version>
</PackageReference>
...
...
Project.FLY.ModbusMapper/FLY.ModbusMapper/ModbusMapper.cs
View file @
620060c9
This diff is collapsed.
Click to expand it.
Project.FLY.ModbusMapper/FLY.ModbusMapper/ModbusMapper_Client.cs
View file @
620060c9
...
...
@@ -40,32 +40,21 @@ namespace FLY.Modbus
/// </summary>
public
int
UpdateInterval
=
200
;
TimeSpan
actUpdateInterval
;
/// <summary>
/// 实际更新间隔
/// </summary>
public
TimeSpan
ActUpdateInterval
{
get
;
protected
set
;
}
//{
// get { return actUpdateInterval; }
// protected set {
// if (actUpdateInterval != value)
// {
// actUpdateInterval = value;
// NotifyPropertyChanged("ActUpdateInterval");
// }
// }
//}
private
Stopwatch
mStopwatch
=
new
Stopwatch
();
class
RegWrite
{
public
PLCAddressArea
dataArea
;
public
int
addr
;
public
DataToRegs
dr
;
public
object
val
;
public
RegWrite
(
PLCAddressArea
dataArea
,
int
ad
dr
,
object
val
)
public
RegWrite
(
DataToRegs
dr
,
object
val
)
{
this
.
dataArea
=
dataArea
;
this
.
addr
=
addr
;
this
.
dr
=
dr
;
this
.
val
=
val
;
}
}
...
...
@@ -101,23 +90,28 @@ namespace FLY.Modbus
{
if
(!
mclient
.
IsConnected
)
{
coils
.
ClearPlanState
();
registers
.
ClearPlanState
();
foreach
(
var
areaManager
in
mAreaManager
)
areaManager
.
ClearPlanState
();
//复位全部状态
isInCommunication
=
false
;
p_doing
=
null
;
isUpdating
=
false
;
curr_area_idx
=
0
;
// DRMap 的数据 与 下端 属性的数据一致
foreach
(
RegWrite
rw
in
rws
)
{
//更新 本地的 PLC 数据
SetModbusData
(
rw
.
dataArea
,
rw
.
addr
,
rw
.
val
);
}
rws
.
Clear
();
//foreach (var areaManager in mAreaManager)
// areaManager.UpdatePLCObjFromProperty();
//rws.Clear();
mStopwatch
.
Stop
();
}
else
{
foreach
(
var
areaManager
in
mAreaManager
)
areaManager
.
SetAllIsPlcValueChanged
();
rws
.
Clear
();
}
}
}
...
...
@@ -137,6 +131,11 @@ namespace FLY.Modbus
isUpdating
=
true
;
ActUpdateInterval
=
mStopwatch
.
Elapsed
;
mStopwatch
.
Restart
();
foreach
(
var
areaManager
in
mAreaManager
)
{
areaManager
.
MakePlanReal
();
}
}
}
NextPlan
();
...
...
@@ -185,7 +184,7 @@ namespace FLY.Modbus
/// <param name="obj"></param>
void
Do_01_callback
(
bool
[]
val
,
object
obj
)
{
ModbusMapper
.
Plan
p
=
obj
as
ModbusMapper
.
Plan
;
Plan
p
=
obj
as
Plan
;
p
.
isDoing
=
false
;
SetModbusData
(
PLCAddressArea
.
Coil
,
p
.
addr
,
val
);
...
...
@@ -200,7 +199,7 @@ namespace FLY.Modbus
void
Do_03_callback
(
UInt16
[]
val
,
object
obj
)
{
ModbusMapper
.
Plan
p
=
obj
as
ModbusMapper
.
Plan
;
Plan
p
=
obj
as
Plan
;
p
.
isDoing
=
false
;
SetModbusData
(
PLCAddressArea
.
Register
,
p
.
addr
,
val
);
isInCommunication
=
false
;
...
...
@@ -216,7 +215,6 @@ namespace FLY.Modbus
{
isInCommunication
=
false
;
NextPlan
();
}
/// <summary>
/// 正在通讯中
...
...
@@ -229,7 +227,7 @@ namespace FLY.Modbus
/// <summary>
/// 读更新 的计划
/// </summary>
ModbusMapper
.
Plan
p_doing
=
null
;
Plan
p_doing
=
null
;
///// <summary>
/////
///// </summary>
...
...
@@ -251,23 +249,15 @@ namespace FLY.Modbus
/// <param name="dr">数据映射</param>
/// <param name="val">数据值,不能为空</param>
/// <returns></returns>
public
override
bool
SetNameData
(
DataToRegs
dr
,
object
val
)
public
override
void
SetNameData
(
DataToRegs
dr
,
object
val
)
{
RegWrite
rw
;
switch
(
dr
.
dataArea
)
{
case
PLCAddressArea
.
Coil
:
rw
=
rws
.
Find
((
c
)
=>
{
return
(
c
.
addr
==
dr
.
addr
)
&&
(
c
.
dataArea
==
PLCAddressArea
.
Coil
);
});
if
(
rw
!=
null
)
rws
.
Remove
(
rw
);
rws
.
Add
(
new
RegWrite
(
dr
.
dataArea
,
dr
.
addr
,
dr
.
ToBools
(
val
)));
return
true
;
case
PLCAddressArea
.
Register
:
rw
=
rws
.
Find
((
c
)
=>
{
return
(
c
.
addr
==
dr
.
addr
)
&&
(
c
.
dataArea
==
PLCAddressArea
.
Register
);
});
if
(
rw
!=
null
)
rws
.
Remove
(
rw
);
rws
.
Add
(
new
RegWrite
(
dr
.
dataArea
,
dr
.
addr
,
dr
.
ToRegs
(
val
)));
return
true
;
}
return
false
;
//rw = rws.Find((c) => { return (c.dr == dr); });
//if (rw != null)
// rws.Remove(rw);
rw
=
new
RegWrite
(
dr
,
val
);
rws
.
Add
(
rw
);
}
/// <summary>
/// 更新写命令缓冲区
...
...
@@ -275,23 +265,23 @@ namespace FLY.Modbus
void
UpdateWriteData
()
{
RegWrite
rw
=
rws
.
First
();
switch
(
rw
.
dataArea
)
rws
.
Remove
(
rw
);
//更新 本地的 PLC 数据
rw
.
dr
.
isPlcValueChanged
=
true
;
switch
(
rw
.
dr
.
dataArea
)
{
case
PLCAddressArea
.
Coil
:
if
(
mclient
.
Do_0F
((
UInt16
)
rw
.
addr
,
(
bool
[])(
rw
.
val
)
,
Do_0F_callback
,
null
)
!=
ModbusClient_Errno
.
OK
)
if
(
mclient
.
Do_0F
((
UInt16
)
rw
.
dr
.
addr
,
new
bool
[]
{
(
bool
)
rw
.
dr
.
plcValue
}
,
Do_0F_callback
,
null
)
!=
ModbusClient_Errno
.
OK
)
return
;
SetModbusData
(
rw
.
dataArea
,
rw
.
addr
,
rw
.
val
);
break
;
case
PLCAddressArea
.
Register
:
if
(
mclient
.
Do_10
((
UInt16
)
rw
.
addr
,
(
UInt16
[])
rw
.
val
,
Do_10_callback
,
null
)
!=
ModbusClient_Errno
.
OK
)
if
(
mclient
.
Do_10
((
UInt16
)
rw
.
dr
.
addr
,
(
UInt16
[])
rw
.
dr
.
plcValue
,
Do_10_callback
,
null
)
!=
ModbusClient_Errno
.
OK
)
return
;
SetModbusData
(
rw
.
dataArea
,
rw
.
addr
,
rw
.
val
);
break
;
}
//更新 本地的 PLC 数据
SetModbusData
(
rw
.
dataArea
,
rw
.
addr
,
rw
.
val
);
rws
.
Remove
(
rw
);
isInCommunication
=
true
;
}
void
UpdateReadData
()
...
...
@@ -308,6 +298,8 @@ namespace FLY.Modbus
p_doing
.
isDoing
=
true
;
isInCommunication
=
true
;
}
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/Pack_Proto.cs
View file @
620060c9
...
...
@@ -65,7 +65,7 @@ namespace FLY.Modbus
return
buf
.
ToArray
();
}
public
bool
TryParse
(
byte
[]
value
,
int
startIndex
,
out
int
rlen
)
public
bool
TryParse
(
byte
[]
value
,
int
startIndex
,
int
value_len
,
out
int
rlen
)
{
//格式——————————————
//MBAP
...
...
@@ -82,7 +82,7 @@ namespace FLY.Modbus
rlen
=
0
;
int
cnt
=
7
+
1
;
if
(
value
.
Count
()
<
cnt
)
if
(
value
_len
<
cnt
)
return
false
;
int
index
=
startIndex
;
tranid
=
COMMON
.
ToUInt16_Big_endian
(
value
,
index
);
...
...
@@ -94,7 +94,7 @@ namespace FLY.Modbus
index
+=
2
;
cnt
+=
len
-
2
;
if
(
value
.
Count
()
<
cnt
)
if
(
value
_len
<
cnt
)
return
false
;
unitid
=
value
[
index
];
...
...
Project.FLY.ModbusMapper/FLY.ModbusMapper/RegTypeConverter.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
FLY.Modbus
{
/// <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
;
}
}
/// <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
,
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/RegisterData.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
FLY.Modbus
{
/// <summary>
/// property 与 PLC寄存器 更新操作
/// </summary>
public
class
RegisterData
:
AreaManager
{
/// <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()"
);
}
lock
(
plan_buffer
)
{
plan_buffer
.
Clear
();
int
addr
=
-
1
;
int
num
=
0
;
for
(
int
i
=
0
;
i
<
regs
.
Count
();
i
++)
{
if
(!
regs
[
i
].
isNeedUpdate
)
continue
;
if
(
addr
==
-
1
)
{
addr
=
regs
[
i
].
addr
;
UInt16
[]
plc_value
=
(
UInt16
[])
regs
[
i
].
plcValue
;
num
=
plc_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
{
UInt16
[]
plc_value
=
(
UInt16
[])
regs
[
i
].
plcValue
;
int
n
=
regs
[
i
].
addr
+
plc_value
.
Count
()
-
1
-
addr
+
1
;
if
(
n
<=
maxOfOneRead
)
{
num
=
n
;
}
else
{
plan_buffer
.
Add
(
new
Plan
(
area
,
addr
,
num
));
addr
=
-
1
;
i
--;
}
}
}
if
(
addr
!=
-
1
)
{
plan_buffer
.
Add
(
new
Plan
(
area
,
addr
,
num
));
addr
=
-
1
;
}
isPlanChanged
=
true
;
}
}
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ClientTCP.cs
0 → 100644
View file @
620060c9
This diff is collapsed.
Click to expand it.
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/IModbusClient.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
namespace
FLY.Modbus.WithThread
{
/// <summary>
/// 同一时刻只能有一个通信,当同时执行 Do_xx, 这些指令会被hold住
/// 如果连接断开,或者异常,这些 Do_xx,全部返回 false
/// </summary>
public
interface
IModbusClient
{
/// <summary>
/// 通信超时
/// </summary>
TimeSpan
Timeout
{
get
;
set
;
}
/// <summary>
/// socket 错误信息
/// </summary>
string
ErrMsg
{
get
;
set
;
}
/// <summary>
/// 连接成功
/// </summary>
bool
IsConnected
{
get
;
set
;
}
/// <summary>
/// 远端地址
/// </summary>
IPEndPoint
RemoteEP
{
get
;
set
;
}
/// <summary>
/// 建立连接
/// </summary>
bool
Connect
();
/// <summary>
/// 停止
/// </summary>
void
Close
();
/// <summary>
/// 读多个 COIL
/// </summary>
/// <param name="addr"></param>
/// <param name="cnt"></param>
/// <param name="values"></param>
/// <returns></returns>
bool
Do_01
(
int
addr
,
int
cnt
,
out
IEnumerable
<
bool
>
values
);
/// <summary>
/// 读多个Holding REGs
/// </summary>
/// <param name="addr"></param>
/// <param name="cnt"></param>
/// <param name="values"></param>
/// <returns></returns>
bool
Do_03
(
int
addr
,
int
cnt
,
out
IEnumerable
<
UInt16
>
values
);
/// <summary>
/// Write Single Coil
/// </summary>
/// <param name="addr"></param>
/// <param name="data"></param>
/// <returns></returns>
bool
Do_05
(
int
addr
,
bool
data
);
/// <summary>
/// 写多个coil
/// </summary>
/// <param name="addr"></param>
/// <param name="datas"></param>
/// <returns></returns>
bool
Do_0F
(
int
addr
,
IEnumerable
<
bool
>
datas
);
/// <summary>
/// 写多个REG
/// </summary>
/// <param name="addr"></param>
/// <param name="datas"></param>
/// <returns></returns>
bool
Do_10
(
int
addr
,
IEnumerable
<
UInt16
>
datas
);
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/IModbusServer.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
namespace
FLY.Modbus.WithThread
{
public
interface
IModbusServer
{
/// <summary>
/// 通信超时, client 长时间连接上,但不通讯,会被断开
/// </summary>
TimeSpan
Timeout
{
get
;
set
;
}
/// <summary>
/// 本地地址
/// </summary>
IPEndPoint
LocalEP
{
get
;
set
;
}
/// <summary>
/// 当前连接数
/// </summary>
int
ConnectedCnt
{
get
;
}
/// <summary>
/// 工作中
/// </summary>
bool
IsRunning
{
get
;
set
;
}
/// <summary>
/// socket 错误信息
/// </summary>
string
ErrMsg
{
get
;
set
;
}
GetValueHander
GetValue
{
get
;
}
SetValueHander
SetValue
{
get
;
}
void
Start
();
void
Stop
();
}
public
delegate
void
GetValueHander
(
int
addr
,
object
values
);
public
delegate
void
SetValueHander
(
int
addr
,
object
values
);
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ModbusMapper_Client.cs
0 → 100644
View file @
620060c9
using
System
;
using
System.Collections.Generic
;
using
System.Diagnostics
;
using
System.Linq
;
using
System.Net
;
using
System.Text
;
using
System.Threading
;
using
System.Threading.Tasks
;
namespace
FLY.Modbus.WithThread
{
/// <summary>
/// 使用线程版本
/// 支持自定义逻辑
/// </summary>
public
class
ModbusMapper_Client
:
ModbusMapper
{
/// <summary>
/// 更新周期,单位ms,
/// </summary>
public
int
UpdateInterval
=
100
;
/// <summary>
/// 实际更新间隔
/// </summary>
public
TimeSpan
ActUpdateInterval
{
get
;
private
set
;
}
/// <summary>
/// 工作中
/// </summary>
public
bool
IsRunning
{
get
;
private
set
;
}
/// <summary>
/// 异常次数
/// </summary>
public
int
ErrorCnt
{
get
;
private
set
;
}
class
RegWrite
{
public
DataToRegs
dr
;
public
object
val
;
public
RegWrite
(
DataToRegs
dr
,
object
val
)
{
this
.
dr
=
dr
;
this
.
val
=
val
;
}
}
List
<
RegWrite
>
rws
=
new
List
<
RegWrite
>();
/// <summary>
/// tcp client
/// </summary>
public
ClientTCP
Client
{
get
;
set
;
}
CancellationTokenSource
cts
;
/// <summary>
///
/// </summary>
/// <param name="ep">服务器ep</param>
public
ModbusMapper_Client
(
IPEndPoint
ep
)
{
Client
=
new
ClientTCP
(
ep
);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public
override
string
ToString
()
{
return
Client
.
ToString
();
}
/// <summary>
/// 启动
/// </summary>
public
void
Start
()
{
lock
(
this
)
{
if
(
IsRunning
)
return
;
IsRunning
=
true
;
cts
=
new
CancellationTokenSource
();
Task
.
Factory
.
StartNew
(
OnPoll_update
,
cts
.
Token
);
}
}
/// <summary>
/// 停止
/// </summary>
public
void
Stop
()
{
lock
(
this
)
{
if
(!
IsRunning
)
return
;
cts
.
Cancel
();
Client
.
Close
();
}
}
void
OnPoll_update
()
{
Stopwatch
stopwatch
=
new
Stopwatch
();
bool
isTimeForRead
=
true
;
_connect
:
while
(
true
)
{
if
(
cts
.
IsCancellationRequested
)
goto
_end
;
bool
isconnected
=
Client
.
Connect
();
if
(
cts
.
IsCancellationRequested
)
goto
_end
;
if
(
isconnected
)
break
;
else
Thread
.
Sleep
(
1000
);
}
//刚连接成功。
//从本地PC 属性获取value 更新到 本地PLC 寄存器,
//目的: 当从PLC读取寄存器值时,能比较不同,产生变化事件
foreach
(
var
areaManager
in
mAreaManager
)
areaManager
.
SetAllIsPlcValueChanged
();
//清空 写缓存
lock
(
rws
)
{
rws
.
Clear
();
}
stopwatch
.
Restart
();
isTimeForRead
=
true
;
while
(
true
)
{
if
(
cts
.
IsCancellationRequested
)
goto
_end
;
if
(
stopwatch
.
ElapsedMilliseconds
>=
UpdateInterval
)
{
isTimeForRead
=
true
;
}
if
(
isTimeForRead
)
{
isTimeForRead
=
false
;
TimeSpan
elapsed
=
stopwatch
.
Elapsed
;
ActUpdateInterval
=
elapsed
;
stopwatch
.
Restart
();
if
(!
UpdateReadData
())
{
if
(
cts
.
IsCancellationRequested
)
//可能是外部强制关闭
goto
_end
;
goto
_error
;
//连接断开,终止更新线程
}
}
//输出写入数据
if
(!
UpdateWriteData
())
{
if
(
cts
.
IsCancellationRequested
)
//可能是外部强制关闭
goto
_end
;
goto
_error
;
//连接断开,终止更新线程
}
Thread
.
Sleep
(
30
);
}
_error
:
ErrorCnt
++;
goto
_connect
;
_end
:
Client
.
Close
();
IsRunning
=
false
;
}
/// <summary>
/// 更新一次读全部数据
/// </summary>
/// <returns></returns>
bool
UpdateReadData
()
{
foreach
(
var
areaManager
in
mAreaManager
)
{
areaManager
.
MakePlanReal
();
}
//int curr_area_idx = 0;
foreach
(
var
areaManager
in
mAreaManager
)
{
foreach
(
Plan
p_doing
in
areaManager
.
plan
)
{
switch
(
p_doing
.
area
)
{
case
PLCAddressArea
.
Coil
:
{
if
(!
Client
.
Do_01
(
p_doing
.
addr
,
p_doing
.
num
,
out
IEnumerable
<
bool
>
values
))
return
false
;
SetModbusData
(
PLCAddressArea
.
Coil
,
p_doing
.
addr
,
values
);
}
break
;
case
PLCAddressArea
.
Register
:
{
if
(!
Client
.
Do_03
(
p_doing
.
addr
,
p_doing
.
num
,
out
IEnumerable
<
UInt16
>
values
))
return
false
;
SetModbusData
(
PLCAddressArea
.
Register
,
p_doing
.
addr
,
values
);
}
break
;
}
}
}
return
true
;
}
/// <summary>
/// PC -> PLC
/// 为命名数据赋值,会改变Modbus的寄存器值,并产生通知
/// </summary>
/// <param name="dr">数据映射</param>
/// <param name="val">数据值,不能为空</param>
/// <returns></returns>
public
override
void
SetNameData
(
DataToRegs
dr
,
object
val
)
{
RegWrite
rw
=
new
RegWrite
(
dr
,
val
);
lock
(
rws
)
{
rws
.
Add
(
rw
);
}
}
/// <summary>
/// 提取全部写命令缓冲区 输出
/// </summary>
bool
UpdateWriteData
()
{
while
(
true
)
{
RegWrite
rw
;
lock
(
rws
)
{
if
(
rws
.
Count
()
==
0
)
break
;
rw
=
rws
.
First
();
rws
.
RemoveAt
(
0
);
}
//强制令读时,推送数据
rw
.
dr
.
isPlcValueChanged
=
true
;
object
plc_value
=
rw
.
dr
.
ToPLCObj
(
rw
.
val
);
switch
(
rw
.
dr
.
dataArea
)
{
case
PLCAddressArea
.
Coil
:
if
(!
Client
.
Do_0F
((
UInt16
)
rw
.
dr
.
addr
,
new
bool
[]
{(
bool
)
plc_value
}))
return
false
;
break
;
default
:
//case PLCAddressArea.Register:
if
(!
Client
.
Do_10
((
UInt16
)
rw
.
dr
.
addr
,
(
UInt16
[])
plc_value
))
return
false
;
break
;
}
}
return
true
;
}
}
}
Project.FLY.ModbusMapper/FLY.ModbusMapper/WithThread/ServerTCP.cs
0 → 100644
View file @
620060c9
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment