《物聯(lián)網(wǎng)框架ServerSuperIO教程》-4.如開發(fā)一套設(shè)備驅(qū)動(dòng),同時(shí)支持串口和網(wǎng)絡(luò)通訊。附:將來支持Windows 10 IOT

1.C#跨平臺(tái)物聯(lián)網(wǎng)通訊框架ServerSuperIO(SSIO)介紹

《連載 | 物聯(lián)網(wǎng)框架ServerSuperIO教程》1.4種通訊模式機(jī)制。

《連載 | 物聯(lián)網(wǎng)框架ServerSuperIO教程》2.服務(wù)實(shí)例的配置參數(shù)說明

《連載 | 物聯(lián)網(wǎng)框架ServerSuperIO教程》- 3.設(shè)備驅(qū)動(dòng)介紹

 

注:ServerSuperIO有可能被移植到Windows 10 IOT上,那么將來有可能開發(fā)一套設(shè)備驅(qū)動(dòng),可以支行在服務(wù)端、嵌入式設(shè)備中,將形成完整的解決方案。

      現(xiàn)在已經(jīng)調(diào)試通過部分代碼,還得需要一段時(shí)間,一般都是晚上干,時(shí)間也有限。如下圖:

 

目       錄

4.如開發(fā)一套設(shè)備驅(qū)動(dòng),同時(shí)支持串口和網(wǎng)絡(luò)通訊... 2

4.1           概述... 2

4.2           通訊協(xié)議規(guī)定... 2

4.2.1    發(fā)送讀實(shí)時(shí)數(shù)據(jù)命令協(xié)議... 2

4.2.2    解析實(shí)時(shí)數(shù)據(jù)協(xié)議... 3

4.2.3    發(fā)送和接收數(shù)據(jù)事例... 3

4.3           開發(fā)設(shè)備驅(qū)動(dòng)... 3

4.3.1    構(gòu)建實(shí)時(shí)數(shù)據(jù)持久對(duì)象(不是必須)... 3

4.3.2    構(gòu)建參數(shù)數(shù)據(jù)持久對(duì)象... 5

4.3.3    構(gòu)建發(fā)送和解析協(xié)議命令對(duì)象... 5

4.3.4    構(gòu)建協(xié)議驅(qū)動(dòng)對(duì)象... 6

4.3.5    構(gòu)建設(shè)備驅(qū)動(dòng)對(duì)象... 8

4.4           構(gòu)建宿主程序... 12

4.5           運(yùn)行效果... 15

 

 

4.如開發(fā)一套設(shè)備驅(qū)動(dòng),同時(shí)支持串口和網(wǎng)絡(luò)通訊

4.1    概述

     作為物聯(lián)網(wǎng)通訊框架,肯定要支持多種通訊鏈路,在多種通訊鏈路的基礎(chǔ)上完成多種通訊協(xié)議的交互,例如:Modbus、自定義協(xié)議等等。但是,有一個(gè)問題:針對(duì)同一臺(tái)硬件設(shè)備或傳感器,完成串口和網(wǎng)絡(luò)兩種通訊方式的數(shù)據(jù)采集和控制,是否要分別寫代碼?如果從現(xiàn)實(shí)角度分析,同一硬件,它要完成的業(yè)務(wù)邏輯肯定是相同的,所以ServerSuperIO物聯(lián)網(wǎng)框架,允許開發(fā)一套設(shè)備驅(qū)動(dòng),同時(shí)支持串口和網(wǎng)絡(luò)兩種通訊方式的交互。

     通訊很簡(jiǎn)單、交互很簡(jiǎn)單、業(yè)務(wù)很簡(jiǎn)單……如果把很多簡(jiǎn)單的問題合在一起,那么就變得不簡(jiǎn)單了,所以要有一個(gè)框架性的東西,重新把眾多問題變得簡(jiǎn)單。

4.2    通訊協(xié)議規(guī)定

    在完成一個(gè)設(shè)備驅(qū)動(dòng)的開發(fā)之前,首先要知道它的通訊協(xié)議,好比兩個(gè)人交流的語言一樣。針對(duì)通訊協(xié)議,我們自定義一個(gè)簡(jiǎn)單交互方式,只是發(fā)送命令,提取數(shù)據(jù)信息。

4.2.1    發(fā)送讀實(shí)時(shí)數(shù)據(jù)命令協(xié)議

     計(jì)算機(jī)發(fā)送0x61指令為讀實(shí)時(shí)數(shù)據(jù)命令,共發(fā)送6個(gè)字節(jié),校驗(yàn)和為從“從機(jī)地址”開始的累加和,不包括“數(shù)據(jù)報(bào)頭”、“校驗(yàn)和”和“協(xié)議結(jié)束”。

     發(fā)送指令數(shù)據(jù)幀如下:

幀結(jié)構(gòu)

數(shù)據(jù)報(bào)頭

從機(jī)地址

指令代碼

校驗(yàn)和

協(xié)議結(jié)束

0x55

0xAA

 

0x61

 

0x0D

字節(jié)數(shù)

1

1

1

1

1

1

  

4.2.2    解析實(shí)時(shí)數(shù)據(jù)協(xié)議

    下位機(jī)接收到讀實(shí)時(shí)數(shù)據(jù)命令后,并校驗(yàn)成功,返回實(shí)時(shí)數(shù)據(jù),校驗(yàn)和為從“從機(jī)地址”開始的累加和,不包括“數(shù)據(jù)報(bào)頭”、“校驗(yàn)和”和“協(xié)議結(jié)束”。

    接收數(shù)據(jù)幀如下:

幀結(jié)構(gòu)

數(shù)據(jù)報(bào)頭

從機(jī)地址

指令代碼

流量

信號(hào)

校驗(yàn)和

協(xié)議結(jié)束

0x55

0xAA

 

0x61

浮點(diǎn)型

浮點(diǎn)型

 

0x0D

字節(jié)數(shù)

1

1

1

1

4

 

4

1

1

4.2.3    發(fā)送和接收數(shù)據(jù)事例

發(fā)送(十六進(jìn)制):0x55 0xaa 0x00 0x61 0x61 0x0d

接收(十六進(jìn)制):0x55 0xaa 0x00 0x61 0x43 0x7a 0x00 0x00 0x43 0xb4 0x15 0x0d

流量數(shù)據(jù)為:250.00

信號(hào)數(shù)據(jù)為:360.00

4.3    開發(fā)設(shè)備驅(qū)動(dòng)

4.3.1    構(gòu)建實(shí)時(shí)數(shù)據(jù)持久對(duì)象(不是必須)

1.通過返回?cái)?shù)據(jù)的通訊協(xié)議,有流量和信號(hào)兩個(gè)動(dòng)態(tài)變量,我們需要?jiǎng)?chuàng)建一個(gè)動(dòng)態(tài)對(duì)象實(shí)體類,主要用于協(xié)議驅(qū)動(dòng)與設(shè)備驅(qū)動(dòng)之間的數(shù)據(jù)交互。代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Dyn
{
        private float _Flow = 0.0f;
        /// <summary>
        /// 流量
        /// </summary>
        public float Flow
        {
            get { return _Flow; }
            set { _Flow = value; }
        }
        private float _Signal = 0.0f;
        /// <summary>
        /// 信號(hào)
        /// </summary>
        public float Signal
        {
            get { return _Signal; }
            set { _Signal = value; }
        }
}

  2.我們主要的工作是要?jiǎng)?chuàng)建一個(gè)實(shí)時(shí)數(shù)據(jù)持久對(duì)象類,實(shí)時(shí)緩存數(shù)據(jù)信息,也可以把該實(shí)時(shí)數(shù)據(jù)信息保存到數(shù)據(jù)庫中或其他存儲(chǔ)媒質(zhì)。實(shí)時(shí)數(shù)據(jù)持久對(duì)象類的代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class DeviceDyn:DeviceDynamic
{
        public DeviceDyn() : base()
        {
            Dyn=new Dyn();
        }
        public override string GetAlertState()
        {
            throw new NotImplementedException("無報(bào)警信息");
        }
        public override object Repair()
        {
            return new DeviceDyn();
        }
        public Dyn Dyn { get; set; }
}

     DeviceDyn 類繼承自DeviceDynamic,因?yàn)槊總€(gè)硬件設(shè)備的報(bào)警信息有可能不一樣,所以GetAlertState函數(shù)可以實(shí)該功能,但是SSIO框架并沒有直接引用;這個(gè)類本質(zhì)上是一個(gè)可以序列化,在不加互斥的情況下可能造成文件損壞,所以Repair可以完成修復(fù)功能,在DeviceDynamic基類里實(shí)現(xiàn)了該功能;另外,實(shí)現(xiàn)DeviceDynamic基類自帶兩個(gè)函數(shù),Save函數(shù)用于持久化(序列化)此類的信息,Load用于獲得(反序列化)此類的信息,在設(shè)備驅(qū)動(dòng)中可以使用。

4.3.2    構(gòu)建參數(shù)數(shù)據(jù)持久對(duì)象

    一般來說硬件設(shè)備會(huì)有讀參數(shù)的命令,那么返回來的參數(shù)也需要進(jìn)行持久化存儲(chǔ),并且每臺(tái)設(shè)備的參數(shù)都可能不一樣,在此提供一個(gè)可擴(kuò)展的接口。在這個(gè)通訊協(xié)議中并沒有涉及到設(shè)備參數(shù)相關(guān)的協(xié)議說明,但是我們也需要?jiǎng)?chuàng)建一個(gè)參數(shù)數(shù)據(jù)持久對(duì)象類,可以不寫任何擴(kuò)展的參數(shù)屬性,在SSIO框架對(duì)參數(shù)的接口進(jìn)行了引用,這是必須進(jìn)行了工作。代碼如下:

1
2
3
4
5
6
7
public class DevicePara:ServerSuperIO.Device.DeviceParameter
{
        public override object Repair()
        {
            return new DevicePara();
        }
}

     DevicePara繼承自DeviceParameter類,情況與實(shí)時(shí)數(shù)據(jù)持久對(duì)象類似,可以參數(shù)。

4.3.3    構(gòu)建發(fā)送和解析協(xié)議命令對(duì)象

    與設(shè)備進(jìn)行交互會(huì)涉及到很多交互式的命令或指令代碼,而這些命令在SSIO框架內(nèi)是以協(xié)議命令對(duì)象的形式存在,大體包括三個(gè)部:執(zhí)行命令接口、打包發(fā)送數(shù)據(jù)接口、解析接收數(shù)據(jù)接口等。

    針對(duì)上面的通訊協(xié)議,有一個(gè)61指令,那么我們就可以根據(jù)61指令為命名構(gòu)建一個(gè)協(xié)議命令對(duì)象,包括發(fā)送數(shù)據(jù)和解析數(shù)據(jù)部分。如果有其他命令代碼,舉一反三。代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
internal class DeviceCommand:ProtocolCommand
{
        public override string Name
        {
            get { return "61"; }
        }
 
        public override void ExcuteCommand<T>(T t)
        {
            throw new NotImplementedException();
        }
 
        public override byte[] Package<T> (string code, T1 t1,T2 t2)
        {
            //發(fā)送:0x55 0xaa 0x00 0x61 0x61 0x0d
            byte[] data = new byte[6];
            data[0] = 0x55;
            data[1] = 0xaa;
            data[2] = byte.Parse(code);
            data[3] = 0x61;
            data[4] = this.ProtocolDriver.GetCheckData(data)[0];
            data[5] = 0x0d;
            return data;
        }
 
        public override dynamic Analysis<T>(byte[] data, T t)
        {
            Dyn dyn = new Dyn()
            //一般下位機(jī)是單片的話,接收到數(shù)據(jù)的高低位需要互換,才能正常解析。
            byte[] flow = BinaryUtil.SubBytes(data, 4, 4, true);
            dyn.Flow = BitConverter.ToSingle(flow, 0);
            byte[] signal = BinaryUtil.SubBytes(data, 8, 4, true);
            dyn.Signal = BitConverter.ToSingle(signal, 0);
            return dyn;
        }
 
}

     構(gòu)建協(xié)議命令需要全部繼承自ProtocolCommand,根據(jù)通訊協(xié)議規(guī)定,Name屬性返回61,作為關(guān)鍵字;Package是打包要送的數(shù)據(jù)信息;Analysis對(duì)應(yīng)著接收數(shù)據(jù)之后進(jìn)行解析操作。就這樣一個(gè)簡(jiǎn)單的協(xié)議命令驅(qū)動(dòng)就構(gòu)建完成了。

4.3.4    構(gòu)建協(xié)議驅(qū)動(dòng)對(duì)象

    有了協(xié)議命令之后,我們需要構(gòu)建協(xié)議驅(qū)動(dòng)對(duì)象,SSIO框架支持自定義協(xié)議也在于此,并且與設(shè)備驅(qū)動(dòng)的接口相關(guān)聯(lián),在SSIO框架的高級(jí)應(yīng)用中也進(jìn)行了引用,構(gòu)建這引對(duì)象很關(guān)鍵。代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
internal class DeviceProtocol:ProtocolDriver
{
        public override bool CheckData(byte[] data)
        {
            if (data[0] == 0x55 && data[1] == 0xaa && data[data.Length - 1] == 0x0d)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
 
        public override byte[] GetCommand(byte[] data)
        {
            return new byte[] { data[3] };
        }
 
        public override int GetAddress(byte[] data)
        {
            return data[2];
        }
 
        public override byte[] GetHead(byte[] data)
        {
            return new byte[] { data[0], data[1] };
        }
 
        public override byte[] GetEnd(byte[] data)
        {
            return new byte[] { data[data.Length - 1] };
        }
 
        public override byte[] GetCheckData(byte[] data)
        {
            byte checkSum = 0;
            for (int i = 2; i < data.Length - 2; i++)
            {
                checkSum += data[i];
            }
            return new byte[] { checkSum };
        }
 
        public override string GetCode(byte[] data)
        {
            throw new NotImplementedException();
        }
 
        public override int GetPackageLength(byte[] data, IChannel channel, ref int readTimeout)
        {
           throw new NotImplementedException();
        }
}

     DeviceProtocol 協(xié)議驅(qū)動(dòng)繼承自ProtocolDriver ,一個(gè)設(shè)備驅(qū)動(dòng)只存在一個(gè)協(xié)議驅(qū)動(dòng),一個(gè)協(xié)議驅(qū)動(dòng)可以存在多個(gè)協(xié)議命令(如61命令)。該類中的CheckData函數(shù)很關(guān)鍵,SSIO框架中的設(shè)備驅(qū)動(dòng)基類引用了,主要是完成校驗(yàn)接收數(shù)據(jù)的完事性,是否符合協(xié)議,從而決定了通訊狀態(tài):通訊正常、通訊中斷、通訊干擾、以及通訊未知,不同的通訊狀態(tài)也決定了調(diào)用設(shè)備驅(qū)動(dòng)中的哪個(gè)函數(shù)接口:Communicate、CommunicateInterrupt、CommunicateError和CommunicateNone。

4.3.5    構(gòu)建設(shè)備驅(qū)動(dòng)對(duì)象

     上邊的基礎(chǔ)工作都做完之后,現(xiàn)在就構(gòu)建設(shè)備驅(qū)動(dòng)的核心部分,也就是SSIO框架與設(shè)備驅(qū)動(dòng)對(duì)接、協(xié)調(diào)、調(diào)度的唯一接口,寫完這個(gè)接口,設(shè)備驅(qū)動(dòng)就可以在SSIO上直接運(yùn)行了,并且與硬件設(shè)備進(jìn)行交互。直接上代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
public class DeviceDriver:RunDevice
{
        private DeviceDyn _deviceDyn;
        private DevicePara _devicePara;
        private DeviceProtocol _protocol;
        public DeviceDriver() : base()
        {
            _devicePara = new DevicePara();
            _deviceDyn = new DeviceDyn();
            _protocol = new DeviceProtocol();
        }
 
        public override void Initialize(string devid)
        {
            this.Protocol.InitDriver(this.GetType(),null);
            //初始化設(shè)備參數(shù)信息
            _devicePara.DeviceID = devid;//設(shè)備的ID必須先賦值,因?yàn)橐檎覍?duì)應(yīng)的參數(shù)文件。
            if (System.IO.File.Exists(_devicePara.SavePath))
            {
                //如果參數(shù)文件存在,則獲得參數(shù)實(shí)例
                _devicePara = _devicePara.Load<DevicePara>();
            }
            else
            {
                //如果參數(shù)文件不存在,則序列化一個(gè)文件
                _devicePara.Save<DevicePara>(_devicePara);
            }
 
            //初始化設(shè)備實(shí)時(shí)數(shù)據(jù)信息
            _deviceDyn.DeviceID = devid;//設(shè)備的ID必須先賦值,因?yàn)橐檎覍?duì)應(yīng)的實(shí)時(shí)數(shù)據(jù)文件。
            if (System.IO.File.Exists(_deviceDyn.SavePath))
            {
                //參數(shù)文件存在,則獲得參數(shù)實(shí)例
                _deviceDyn = _deviceDyn.Load<DeviceDyn>();
            }
            else
            {
                //如果參數(shù)文件不存在,則序列化一個(gè)文件
                _deviceDyn.Save<DeviceDyn>(_deviceDyn);
            }
        }
  
        public override byte[] GetConstantCommand()
        {
            return this.Protocol.DriverPackage<String>("0", "61", null);
        }
  
        public override void Communicate(ServerSuperIO.Communicate.IRequestInfo info)
        {
            Dyn dyn = this.Protocol.DriverAnalysis<String>("61", info.Data, null);
            if (dyn != null)
            {
                _deviceDyn.Dyn = dyn;
            }
            OnDeviceRuningLog("通訊正常");
        }
 
        public override void CommunicateInterrupt(ServerSuperIO.Communicate.IRequestInfo info)
        {
            OnDeviceRuningLog("通訊中斷");
        }
  
        public override void CommunicateError(ServerSuperIO.Communicate.IRequestInfo info)
        {
            OnDeviceRuningLog("通訊干擾");
        }
  
        public override void CommunicateNone()
        {
            OnDeviceRuningLog("通訊未知");
        }
 
        public override void Alert()
        {
            return;
        }
 
        public override void Save()
        {
            try
            {
                _deviceDyn.Save<DeviceDyn>(_deviceDyn);
            }
            catch (Exception ex)
            {
                OnDeviceRuningLog(ex.Message);
            }
        }
 
        public override void Show()
        {
            List<string> list=new List<string>();
            list.Add(_devicePara.DeviceName);
            list.Add(_deviceDyn.Dyn.Flow.ToString());
            list.Add(_deviceDyn.Dyn.Signal.ToString());
            OnDeviceObjectChanged(list.ToArray());
        }
  
        public override void UnknownIO()
        {
            OnDeviceRuningLog("未知通訊接口");
        }
 
        public override void CommunicateStateChanged(ServerSuperIO.Communicate.CommunicateState comState)
        {
            OnDeviceRuningLog("通訊狀態(tài)改變");
        }
 
        public override void ChannelStateChanged(ServerSuperIO.Communicate.ChannelState channelState)
        {
            OnDeviceRuningLog("通道狀態(tài)改變");
        }
 
        public override void Exit()
        {
            OnDeviceRuningLog("退出設(shè)備");
        }
 
        public override void Delete()
        {
            OnDeviceRuningLog("刪除設(shè)備");
        }
  
        public override object GetObject()
        {
            throw new NotImplementedException();
        }
 
        public override void ShowContextMenu()
        {
            throw new NotImplementedException();
        }
 
        public override IDeviceDynamic DeviceDynamic
        {
            get { return _deviceDyn; }
        }
 
        public override IDeviceParameter DeviceParameter
        {
            get { return _devicePara; }
        }
 
        public override IProtocolDriver Protocol
       {
            get { return _protocol;}
        }
 
        public override DeviceType DeviceType
        {
            get { return DeviceType.Common; }
        }
 
        public override string ModelNumber
        {
            get { return "serversuperio"; }
        }
 
        public override System.Windows.Forms.Control DeviceGraphics
        {
            get { throw new NotImplementedException(); }
        }
}

    實(shí)時(shí)動(dòng)態(tài)數(shù)據(jù)對(duì)象_deviceDyn、參數(shù)數(shù)據(jù)對(duì)象_devicePara、協(xié)議驅(qū)動(dòng)對(duì)象_protocol分別提供給接口:DeviceDynamic、DeviceParameter和Protocol,為SSIO提供可引用的基礎(chǔ)屬性參數(shù)。

     Initialize是設(shè)備驅(qū)動(dòng)初始化的函數(shù)接口,在這個(gè)接口完成兩個(gè)主要工作:初始化協(xié)議驅(qū)動(dòng)和參數(shù)性的信息。通過this.Protocol.InitDriver(this.GetType(),null);代碼可以加載所有協(xié)議命令到協(xié)議驅(qū)動(dòng)的緩存中,以便實(shí)時(shí)調(diào)用。當(dāng)然這里邊也可以進(jìn)行其他方面的工作,但是注意對(duì)異常的處理。

     DeviceType這個(gè)是設(shè)備的類型,一般指定為Common就好了。其他函數(shù)接口功能已經(jīng)在《物聯(lián)網(wǎng)框架ServerSuperIO教程-3.設(shè)備驅(qū)動(dòng)介紹》中詳細(xì)介紹了,請(qǐng)參考。

4.4    構(gòu)建宿主程序

     一個(gè)簡(jiǎn)單的設(shè)備驅(qū)動(dòng)就已經(jīng)開發(fā)好了,光有驅(qū)動(dòng)還不行,那么我們基于SSIO框架再寫幾行代碼,完成一個(gè)宿主程序,把設(shè)備驅(qū)動(dòng)實(shí)例化,放SSIO的服務(wù)實(shí)例中運(yùn)行,完成串口和網(wǎng)絡(luò)兩種方式的通訊交互,代碼也非常簡(jiǎn)單。代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Program
{
        static void Main(string[] args)
        {
            DeviceDriver dev1 = new DeviceDriver();
            dev1.DeviceParameter.DeviceName = "串口設(shè)備1";
            dev1.DeviceParameter.DeviceAddr = 0;
            dev1.DeviceParameter.DeviceID = "0";
            dev1.DeviceDynamic.DeviceID = "0";
            dev1.DeviceParameter.COM.Port = 1;
            dev1.DeviceParameter.COM.Baud = 9600;
            dev1.CommunicateType = CommunicateType.COM;
            dev1.Initialize("0");
 
            DeviceDriver dev4 = new DeviceDriver();
            dev4.DeviceParameter.DeviceName = "網(wǎng)絡(luò)設(shè)備2";
            dev4.DeviceParameter.DeviceAddr = 0;
            dev4.DeviceParameter.DeviceID = "3";
            dev4.DeviceDynamic.DeviceID = "3";
            dev4.DeviceParameter.NET.RemoteIP = "127.0.0.1";
            dev4.DeviceParameter.NET.RemotePort = 9600;
            dev4.CommunicateType = CommunicateType.NET;
            dev4.Initialize("3");
 
            IServer server = new ServerFactory().CreateServer(new ServerConfig()
            {
                ServerName = "服務(wù)實(shí)例1",
                SocketMode = SocketMode.Tcp,
                ControlMode = ControlMode.Loop,
                CheckSameSocketSession = false,
                StartCheckPackageLength = false,
            });
 
            server.AddDeviceCompleted += server_AddDeviceCompleted;
            server.DeleteDeviceCompleted += server_DeleteDeviceCompleted;
            server.SocketConnected+=server_SocketConnected;
            server.SocketClosed+=server_SocketClosed;
            server.Start();
 
            server.AddDevice(dev1);
            server.AddDevice(dev4);
 
            while ("exit"==Console.ReadLine())
            {
                 server.Stop();
            }
        }
 
        private static void server_SocketClosed(string ip, int port)
        {
            Console.WriteLine(String.Format("斷開:{0}-{1} 成功", ip, port));
        }
 
        private static void server_SocketConnected(string ip, int port)
        {
            Console.WriteLine(String.Format("連接:{0}-{1} 成功",ip, port));
        }
 
        private static void server_AddDeviceCompleted(string devid, string devName, bool isSuccess)
 
        {
            Console.WriteLine(devName+",增加:"+isSuccess.ToString());
        }
 
        private static void server_DeleteDeviceCompleted(string devid, string devName, bool isSuccess)
        {
            Console.WriteLine(devName + ",刪除:" + isSuccess.ToString());
        }
    }
}

     這個(gè)代碼大家都能看明白,具體的控制模式我們接下來會(huì)一一介紹。在構(gòu)建宿主程序的時(shí)候,切忌對(duì)服務(wù)實(shí)例這樣引用:server.ChannelManager、server.ControllerManager、server.DeviceManager。盡管提供了這樣的接口,主要是為了SSIO框架內(nèi)部使用的,不需要我們單獨(dú)去操作這些接口。有的網(wǎng)友是這樣的寫的,那么就變成了一個(gè)純的通信IO框架,那么就失去了SSIO框架本身的價(jià)值。作為二次開發(fā)者,只需要設(shè)置設(shè)備驅(qū)動(dòng)的參數(shù),以及向服務(wù)實(shí)例中增加或刪除設(shè)備就行了,其他所有的運(yùn)行全部交給SSIO框架來完成。

4.5    運(yùn)行效果