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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
package com.dy.rtuMw;
 
import java.util.ArrayList;
import java.util.List;
 
import com.dy.common.util.ConfigProperties;
import com.dy.rtuMw.server.*;
import com.dy.rtuMw.server.msCenter.MsCenterConfigVo;
import com.dy.rtuMw.server.msCenter.MsCenterUnit;
import com.dy.rtuMw.server.rtuData.RtuDataUnit;
import com.dy.rtuMw.server.rtuData.RtuDataUnitConfigVo;
import com.dy.rtuMw.server.tasks.FromRtuComResultConstantTask;
import com.dy.rtuMw.server.tasks.FromRtuDataConstantTask;
import com.dy.common.mw.UnitInterface;
import com.dy.common.mw.channel.tcp.TcpConfigVo;
import com.dy.common.mw.channel.tcp.TcpUnit;
import com.dy.common.mw.core.CoreUnit;
import com.dy.common.mw.core.CoreUnitConfigVo;
import com.dy.common.mw.protocol.ProtocolConfigVo;
import com.dy.common.mw.protocol.ProtocolUnit;
import com.dy.common.mw.support.SupportUnit;
import com.dy.common.mw.support.SupportUnitConfigVo;
import com.dy.rtuMw.server.tasks.SendMsConstantTask;
import com.dy.rtuMw.server.tasks.RtuDownConstantTask;
import com.dy.rtuMw.resource.ResourceUnit;
import com.dy.rtuMw.resource.ResourceUnitConfigVo;
import com.dy.common.springUtil.SpringContextUtil;
import com.dy.common.util.ConfigXml4Springboot;
import com.dy.common.util.IDLongGenerator;
 
import com.dy.rtuMw.server.upgrade.UpgradeUnit;
import com.dy.rtuMw.server.upgrade.UpgradeUnitConfigVo;
import org.jdom2.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
 
@Component
public class Server {
 
    private ConfigXml4Springboot conf = null ;
    private Document doc = null ;
    private boolean showStartInfo = false ;
    
    private String RmiSvUrl ;
    private String TcpSvUrl ;
    @Value("${server.port}")
    private String HttpSvPort ;
    @Value("${server.servlet.context-path}")
    private String HttpSvPath ;
 
    @Autowired
    protected ResourceLoader resourceLoader ;
 
    private List<UnitInterface> units = new ArrayList<UnitInterface>() ;
 
    /*
     * @param args 参数
    public static void main(String[] args) {
        new Server().startServer();
    }
    */
 
    public void  startServer(){
        /**
        try {
            URL url = Server.class.getResource("/config/this.licence");
            if(!new Lnp(null).parese(url.getPath())){
                System.out.println("licence error!") ;
                return ;
            }
        } catch (Exception e) {
            System.out.println("licence error!") ;
            return ;
        }
        */
        if(this.doStartServer()){
            ServerShutDownHook.OnShutDown();
        }
    }
    /**
     * 启动服务
      */
    private boolean doStartServer(){
        boolean running = false ;
        long start = System.currentTimeMillis() ;
        try {
            ConfigProperties.init(this.getClass().getResourceAsStream("/config.properties"), false);
            
            this.conf = new ConfigXml4Springboot() ;
            this.doc = this.conf.createDom(this.resourceLoader, "config.xml") ;
            ////////////////
            //服务 配置
            this.showStartInfo = this.conf.getSetAttrBoolean(this.doc, "config.server", "showStartInfo", null, null) ;
 
            this.startUnits() ;
            
            String svName ;
            try{
                svName = this.conf.getSetAttrTxt(this.doc, "config.server", "name", null, false, null) ;
            }catch(Exception e){
                svName = "" ;
            }
            svName += (ServerProperties.isLowPower?"(低功耗)": "") + "-" ;
            
            String company ;
            try{
                company = this.conf.getSetAttrTxt(this.doc, "config.server", "company", null, true, null) ;
            }catch(Exception e){
                company = "" ;
            }
            System.out.println("OOOOOOOOOO           OOOOOOOO       OOOOOOOO") ;
            System.out.println("@@@@@@@@@@@@@@@@#O    $@@@@@@@@&    @@@@@@@@#") ;       
            System.out.println("@@@@@@@@@@@@@@@@@@@#    @@@@@@@@# $@@@@@@@@&") ;        
            System.out.println("@@@@@@@@@@@@@@@@@@@@@#   #@@@@@@@@@@@@@@@@O") ;    
            System.out.println("@@@@@@@@@@@@@@@@@@@@@@@   &@@@@@@@@@@@@@@") ;           
            System.out.println("@@@@@@$      $@@@@@@@@@&   O@@@@@@@@@@@#") ;        
            System.out.println("@@@@@@$        @@@@@@@@@     @@@@@@@@@&      " + svName + "RtuMw 1.0.00" ) ;             
            if(this.HttpSvPath != null && this.HttpSvPort != null){
                System.out.println("@@@@@@$       O@@@@@@@@@     &@@@@@@@@       HttpSv [ip]:" + this.HttpSvPort + this.HttpSvPath) ;
            }else{
                System.out.println("@@@@@@$       O@@@@@@@@@     &@@@@@@@@") ;
            }
 
            if(this.TcpSvUrl != null){
                System.out.println("@@@@@@$       O@@@@@@@@@     &@@@@@@@@       TcpSv " + this.TcpSvUrl ) ;
            }else{
                System.out.println("@@@@@@$       O@@@@@@@@@     &@@@@@@@@") ;              
            }
            if(this.RmiSvUrl != null){
                System.out.println("@@@@@@$      #@@@@@@@@@$     &@@@@@@@@       RmiSv " + this.RmiSvUrl ) ;        
            }else{
                System.out.println("@@@@@@$      #@@@@@@@@@$     &@@@@@@@@" ) ;        
            }
            System.out.println("@@@@@@@@@@@@@@@@@@@@@@#      &@@@@@@@@       Running in standalone mode" ) ;
            System.out.println("@@@@@@@@@@@@@@@@@@@@@&       &@@@@@@@@       Startup in " + (System.currentTimeMillis() - start) + " MS" ) ;              
            System.out.println("@@@@@@@@@@@@@@@@@@@#         &@@@@@@@@       " + company) ;            
            System.out.println("@@@@@@@@@@@@@@@@#O           &@@@@@@@@") ;
            running = true ;
        }catch(Exception e){
            e.printStackTrace();
            running = false ;
        }
        return running ;
    }
    
    private void startUnits(){
        try {
            ///////////////
            //基本配置
            ServerProperties.orgTag = this.conf.getSetAttrTxt(this.doc, "config.base", "orgTag", null, false, null) ;
            if(ServerProperties.orgTag==null || ServerProperties.orgTag.trim().equals("")){
                throw new Exception("机构tag不能为空") ;
            }
            ServerProperties.isLowPower = conf.getSetAttrBoolean(doc, "config.base", "isLowPower", null, null) ; 
            if(ServerProperties.isLowPower == null){
                ServerProperties.isLowPower = false ;
            }
 
            String onlyDealRtus = conf.getSetAttrTxt(doc, "config.base", "onlyDealRtus", null, true, null) ;
            if(onlyDealRtus == null || onlyDealRtus.trim().equals("")){
                ServerProperties.onlyDealRtusTest = false ;
            }else{
                onlyDealRtus = onlyDealRtus.replaceAll(",", ",") ;
                onlyDealRtus = onlyDealRtus.replaceAll(" ", "") ;
                ServerProperties.onlyDealRtus = onlyDealRtus.split(",") ;
                if(ServerProperties.onlyDealRtus != null && ServerProperties.onlyDealRtus.length > 0){
                    ServerProperties.onlyDealRtusTest = true ;
                }else{
                    ServerProperties.onlyDealRtusTest = false ;
                }
            }
 
            //在支持多通信协议时,只有RTU上线了,才能识别出该RTU实际用的通信协议,进而用此协议解析上行数据及构造下行命令。
            //如果RTU未曾上线(通信中间件启动后该RTU未曾上线),那么在向它发送下行命令时,不能判断出其采用的协议,也不能构造命令,尤其是低功耗情况下,不上线是正常现象。
            // 当只有一个协议情况下,在RTU未曾上线时,也能用此协议构造命令并缓存下来,尤其适合低功耗情况。
            //onlyOne=true: 通信中间件当前只有一个协议   
            ServerProperties.onlyOneProtocol = conf.getSetAttrBoolean(doc, "config.base", "onlyOneProtocol", null, null) ; 
            if(ServerProperties.onlyOneProtocol == null){
                ServerProperties.onlyOneProtocol = false ;
            }
            //下行命令允许发送的最大次数X,即允许重发X-1
            ServerProperties.downComandMaxResendTimes = conf.getSetAttrPlusInt(doc, "config.base", "downComandMaxResendTimes", null, 1, 5, null).byteValue() ;
            //针对一个RTU,下发命令的时间间隔
            ServerProperties.commandSendInterval = conf.getSetAttrPlusInt(doc, "config.base", "commandSendInterval", null, 1, 40, null) * 1000L ;
            //针对一个RTU,下发快速命令的时间间隔
            ServerProperties.fastCommandSendInterval = conf.getSetAttrPlusInt(doc, "config.base", "fastCommandSendInterval", null, 1, 40000, null) * 1L ;
            //命令已经发送达最大次数,仍未收到命令结果,需要在缓存继续等待,其等待最大时长
            ServerProperties.cacheWaitResultTimeout = conf.getSetAttrPlusInt(doc, "config.base", "cacheWaitResultTimeout", null, 10, 360, null) * 1000L ;
            //不在线缓存的命令最大缓存时长
            ServerProperties.offLineCacheTimeout = conf.getSetAttrPlusInt(doc, "config.base", "offLineCacheTimeout", null, 15, 172800, null) * 1000L ;
            //TCP上行数据时刻缓存时长,当达到时长时,TCP上行数据时刻被清空,采用TCP上行数据时刻目的是,阻止上数据同时下发数据,因为RTU处理不过来
            ServerProperties.lastUpDataTimeLive = conf.getSetAttrPlusInt(doc, "config.base", "lastUpDataTimeLive", null, 0, 5000, null) * 1L ;
            //数据库数据id生成器的id后缀,0是默认的后缀,一般web系统应用,数据中间件id后缀大于等于1
            ServerProperties.dbDataIdSuffix = conf.getSetAttrInt(doc, "config.base", "dbDataIdSuffix", null, 0, 99, null);
            //上下行数据缓存队列中缓存数据个数的报警量,这个与现实项目所接水表数相关
            ServerProperties.cacheUpDownDataWarnCount = conf.getSetAttrPlusInt(doc, "config.base", "cacheUpDownDataWarnCount", null, 1, null, null) ;
            //上下行数据缓存队列中缓存数据个数的最大值,这个与现实项目所接水表数相关
            ServerProperties.cacheUpDownDataMaxCount = conf.getSetAttrPlusInt(doc, "config.base", "cacheUpDownDataMaxCount", null, 1, null, null) ;
            if(ServerProperties.cacheUpDownDataMaxCount <= ServerProperties.cacheUpDownDataWarnCount){
                throw new Exception("cacheUpDownDataMaxCount必须大于cacheUpDownDataWarnCount") ;
            }
            //没有上行数据的分钟数,达到这个分钟数,认为RTU断网了,取值范围是2-100
            ServerProperties.disconnectedByNoUpDataMinutes =  0L + conf.getSetAttrPlusInt(doc, "config.base", "disconnectedByNoUpDataMinutes", null, 1, 100, null) ;
            if(ServerProperties.disconnectedByNoUpDataMinutes < 1 || ServerProperties.disconnectedByNoUpDataMinutes > 100){
                throw new Exception("disconnectedByNoUpDataMinutes取值必须是1~100") ;
            }
            ServerProperties.disconnectedByNoUpDataMinutes = ServerProperties.disconnectedByNoUpDataMinutes * 60 * 1000 ;
 
            //工作报太频繁,N次上报处理1次,取值范围是1-100
            ServerProperties.workReportDealOneByTimes =  conf.getSetAttrPlusInt(doc, "config.base", "workReportDealOneByTimes", null, 1, 100, null) ;
 
            //触发发送钉钉报警消息的取水口日漏损量的最小值(包括但除0.0外)
            ServerProperties.intakeAlarmLossMinValue =  conf.getSetAttrPlusDouble(doc, "config.base", "intakeAlarmLossMinValue", null, 0.0, 1000000.0, null) ;
 
            //有报警发生时,向钉钉发送消息的间隔时长(分钟)
            ServerProperties.sendDingDingAlarmMsInterval =  conf.getSetAttrPlusInt(doc, "config.base", "sendDingDingAlarmMsInterval", null, 1, 600, null) ;
 
            //设置ID生成器的后缀
            IDLongGenerator.setSuffix(ServerProperties.dbDataIdSuffix.intValue());
 
 
            ////////////////
            //协议模块
            ProtocolConfigVo protoVo = new ProtocolConfigVo();
            protoVo.centerAddr = conf.getSetAttrPlusInt(doc, "config.protocol", "centerAddr", null, 1, 4, null) ;
            protoVo.synchroRtuClock = conf.getSetAttrBoolean(doc, "config.protocol", "synchroRtuClock", null, null) ; 
            //当RTU与服务器时钟相差一定秒钟后,进行校时
            protoVo.synchroRtuClockTimepieces = 1000 * conf.getSetAttrPlusInt(doc, "config.protocol", "synchroRtuClockTimepieces", null, null, null, null) ; 
            protoVo.showStartInfo = showStartInfo ;
            AdapterImp_ProtocolUnit protoAdap = new AdapterImp_ProtocolUnit();
            protoAdap.setConfig(protoVo);
            ProtocolUnit protoUnit = ProtocolUnit.getInstance();
            protoUnit.setAdapter(protoAdap);
            protoUnit.start(obj -> {
            });
            units.add(protoUnit) ;
            
            ////////////////////////////////////////////////////////
            //支持模块: springHibernate和 线程池
            SupportUnitConfigVo supVo = new SupportUnitConfigVo() ;
            //短工作时长线程池,线程负责用时较短的工作任务
            supVo.short_maxThread = conf.getSetAttrPlusInt(doc, "config.support", "short_maxThread", null, -1, 1000, null) ;//池中最大线程数为所有CPU核数+1
            if(supVo.short_maxThread < 0){
                supVo.short_maxThread = -1 ;
            }
            supVo.short_minThread = conf.getSetAttrPlusInt(doc, "config.support", "short_minThread", null, -1, 100, null) ;//池中最小线程数
            if(supVo.short_minThread < 0){
                supVo.short_minThread = -1 ;
            }
            supVo.short_freeTimeout = conf.getSetAttrPlusInt(doc, "config.support", "short_freeTimeout", null, 1, 90, null) * 1000 ;//线程数空闲时长,若池中线程数量大于minThread,且有的线程空闲时长超过freeTimeout,则清除该线程,为了不清除,把minThread与maxThread设置相等
            supVo.short_busyTimeout = conf.getSetAttrPlusInt(doc, "config.support", "short_busyTimeout", null, 1, 10, null) * 1000 ;//线程不间断工作时长(单位为秒)超时限,认为线程已经了崩溃,将强制清除,短工作时长设置为5秒
            if(supVo.short_maxThread == 0 || supVo.short_minThread == 0){
                supVo.enableShortThreadPool = false ;
            }else{
                supVo.enableShortThreadPool = true ;
            }
 
            //长工作时长线程池,线程负责用时较长的工作任务
            supVo.long_maxThread = conf.getSetAttrInt(doc, "config.support", "long_maxThread", null, -1, 1000, null)  ;//池中最大线程数,若为-1,不受限制
            if(supVo.long_maxThread < 0){
                supVo.long_maxThread = -1 ;
            }
            supVo.long_minThread = conf.getSetAttrPlusInt(doc, "config.support", "long_minThread", null, -1, 100, null) ;//池中最小线程数
            if(supVo.long_minThread < 0){
                supVo.long_minThread = -1 ;
            }
            supVo.long_freeTimeout = conf.getSetAttrPlusInt(doc, "config.support", "long_freeTimeout", null, 1, 90, null) * 1000 ;//线程数空闲时长,若池中线程数量大于minThread,且有的线程空闲时长超过freeTimeout,则清除该线程
            supVo.long_busyTimeout = conf.getSetAttrInt(doc, "config.support", "long_busyTimeout", null, -1, 10, null) ;//线程不间断工作时长(单位为秒)超时限,若为-1,不受限制
            if(supVo.long_busyTimeout < 0){
                supVo.long_busyTimeout = -1 ;
            }
            if(supVo.long_maxThread == 0 || supVo.long_minThread == 0){
                supVo.enableLongThreadPool = false ;
            }else{
                supVo.enableLongThreadPool = true ;
            }
 
            supVo.showStartInfo = showStartInfo ;
            
            AdapterImp_SupportUnit supAdap = new AdapterImp_SupportUnit() ;
            supAdap.setConfig(supVo);
            SupportUnit supUnit = SupportUnit.getInstance() ;
            supUnit.setAdapter(supAdap);
            supUnit.start(obj -> {
            });
            units.add(supUnit) ;
            
                    
            /////////////////////////
            //资源模块
            ResourceUnitConfigVo resVo = new ResourceUnitConfigVo() ;
            //RTU日志文件存储目录(相对目录)
            resVo.rtuLogDir = conf.getSetAttrTxt(doc, "config.resource", "rtuLogDir", null, false, null) ;
            //RTU日志文件最大字节数(KB)
            resVo.rtuLogFileMaxSize = conf.getSetAttrPlusInt(doc, "config.resource", "rtuLogFileMaxSize", null, 10, 2000000, null) ;
            //RTU日志文件最大文件数
            resVo.rtuLogFileMaxCount = conf.getSetAttrPlusInt(doc, "config.resource", "rtuLogFileMaxCount", null, 1, 10, null) ; 
            
            //Rtu状态监视间隔(分钟)
            resVo.monitorInterval = conf.getSetAttrPlusInt(doc, "config.resource", "monitorInterval", null, 1, 5, null) ; 
            //Rtu状态存数据库间隔(分钟)
            resVo.saveDbInterval = conf.getSetAttrPlusInt(doc, "config.resource", "saveDbInterval", null, 5, 20, null) ;   
            //Rtu无数据上传达到此值,则认为不在线了(分钟)
            //注意:noUpDataLimitTime在元素config.protocol中
            //resVo.noUpDataLimitTime = conf.getSetAttrPlusInt(doc, "config.protocol", "noUpDataLimitTime", null, 30, 60, null) ;  
            AdapterImp_ResourceUnit resAdap = new AdapterImp_ResourceUnit() ;
            resAdap.setConfig(resVo);
            ResourceUnit resUnit = ResourceUnit.getInstance() ;
            resUnit.setAdapter(resAdap);
            //当前支持spring + hibernate
            resUnit.setSpringContext(SpringContextUtil.getApplicationContext());
 
            resUnit.start(obj -> {
            });
            units.add(resUnit) ;
 
            
            /////////////////
            //RMI模块 暂时不应用
            /*
            RmiConfigVo rmiVo = new RmiConfigVo();
            rmiVo.enable = conf.getSetAttrBoolean(doc, "config.rmi", "enable", null, null) ;
            if(rmiVo.enable){
                rmiVo.port = conf.getSetAttrPlusInt(doc, "config.rmi", "port", null, 100, 65535, null);
                rmiVo.context = conf.getSetAttrTxt(doc, "config.rmi", "context", null, false, null);
                rmiVo.showStartInfo = showStartInfo ;
                AdapterImp_RmiUnit rmiAdap = new AdapterImp_RmiUnit();
                rmiAdap.setConfig(rmiVo);
                RmiUnit rmiUnit = RmiUnit.getInstance();
                rmiUnit.setAdapter(rmiAdap);
                rmiUnit.start(obj -> {
                });
                RmiSvUrl = "[ip]:" + rmiVo.port + "/" + rmiVo.context ;
                units.add(rmiUnit) ;
            }
            */
 
 
            /////////////////
            //消息中心模块
            MsCenterConfigVo mscVo = new MsCenterConfigVo();
            mscVo.enable = conf.getSetAttrBoolean(doc, "config.msCenter", "enable", null, null) ;
            mscVo.notifyMsInterval = conf.getSetAttrPlusInt(doc, "config.msCenter", "notifyInterval", null, 1, 600, null) * 1000L ;
            mscVo.showStartInfo = showStartInfo ;
            AdapterImp_MsCenterUnit mscAdapt = new AdapterImp_MsCenterUnit();
            mscAdapt.setConfig(mscVo);
            MsCenterUnit mscUnit = MsCenterUnit.getInstance();
            mscUnit.setAdapter(mscAdapt);
            mscUnit.start(obj -> {
            });
            units.add(mscUnit) ;
 
 
            /////////////////
            //RTU远程升级模块
            UpgradeUnitConfigVo ugVo = new UpgradeUnitConfigVo();
            ugVo.enable = conf.getSetAttrBoolean(doc, "config.upgrade", "enable", null, null) ;
            ugVo.openNoUpgrade = conf.getSetAttrBoolean(doc, "config.upgrade", "openNoUpgrade", null, null) ;
            ugVo.lastOpenMaxGoOn = conf.getSetAttrPlusInt(doc, "config.upgrade", "lastOpenMaxGoOn", null, 5, 360000, null);
            ugVo.lastOpenMaxGoOn = ugVo.lastOpenMaxGoOn * 1000 ;//变成毫秒
            ugVo.noOneRtuUpgradeMaxDuration = conf.getSetAttrPlusInt(doc, "config.upgrade", "noOneRtuUpgradeMaxDuration", null, 5, 360000, null);
            ugVo.noOneRtuUpgradeMaxDuration = ugVo.noOneRtuUpgradeMaxDuration * 1000 ;//变成毫秒
            ugVo.runningAndIdleDuration = conf.getSetAttrPlusInt(doc, "config.upgrade", "runningAndIdleDuration", null, 5, 360000, null);
            ugVo.runningAndIdleDuration = ugVo.runningAndIdleDuration * 1000 ;//变成毫秒
            ugVo.failTryTimes = conf.getSetAttrPlusInt(doc, "config.upgrade", "failTryTimes", null, 0, 100, null);
            ugVo.ugMaxRtuAtOnce = conf.getSetAttrPlusInt(doc, "config.upgrade", "ugMaxRtuAtOnce", null, 0, 1000000, null);
            ugVo.rtuOffLineWaitDuration = conf.getSetAttrPlusInt(doc, "config.upgrade", "rtuOffLineWaitDuration", null, 1, 3600000, null);
            ugVo.rtuOffLineWaitDuration = ugVo.rtuOffLineWaitDuration * 1000;//变成毫秒
            ugVo.notifyStateInterval = conf.getSetAttrPlusInt(doc, "config.upgrade", "notifyStateInterval", null, 1, 300, null);
            ugVo.notifyStateInterval = ugVo.notifyStateInterval * 1000;//变成毫秒
            ugVo.notifyTimesAfterOver = conf.getSetAttrPlusInt(doc, "config.upgrade", "notifyTimesAfterOver", null, 0, null, null);
            ugVo.showStartInfo = showStartInfo ;
            AdapterImp_UpgradeUnit ugAdap = new AdapterImp_UpgradeUnit();
            ugAdap.setConfig(ugVo);
            UpgradeUnit ugUnit = UpgradeUnit.getInstance();
            ugUnit.setAdapter(ugAdap);
            ugUnit.start(obj -> {
            });
            units.add(ugUnit) ;
 
            /////////////////
            //RTU上行数据处理模块(任务树)
            RtuDataUnitConfigVo rducVo = new RtuDataUnitConfigVo();
            rducVo.resourceLoader = this.resourceLoader ;
            AdapterImp_RtuDataUnit rducAdap = new AdapterImp_RtuDataUnit();
            rducAdap.setConfig(rducVo);
            RtuDataUnit rducUnit = RtuDataUnit.getInstance();
            rducUnit.setAdapter(rducAdap);
            rducUnit.start(obj -> {
            });
            units.add(rducUnit) ;
 
 
 
            // ///////////////
            // 核心
            CoreUnitConfigVo coreConfVo = new CoreUnitConfigVo();
            coreConfVo.coreInterval = conf.getSetAttrPlusInt(doc, "config.core", "coreInterval", null, 1, 200, null).longValue() ;
            coreConfVo.queueWarnSize = ServerProperties.cacheUpDownDataWarnCount ;
            coreConfVo.queueMaxSize = ServerProperties.cacheUpDownDataMaxCount ;
            coreConfVo.showStartInfo = showStartInfo ;
            AdapterImp_CoreUnit coreAdap = new AdapterImp_CoreUnit();
            coreAdap.setConfig(coreConfVo);
            CoreUnit coreUnit = CoreUnit.getInstance();
            coreUnit.setAdapter(coreAdap);
            CoreUnit.addConstantTask(new RtuDownConstantTask());
            CoreUnit.addConstantTask(new FromRtuDataConstantTask());
            CoreUnit.addConstantTask(new FromRtuComResultConstantTask());
            CoreUnit.addConstantTask(new SendMsConstantTask());
            coreUnit.start(obj -> {
            });
            units.add(coreUnit) ;
 
 
            // ///////////////
            // TCP 模块
            TcpConfigVo tcpVo = new TcpConfigVo();
            tcpVo.enable = conf.getSetAttrBoolean(doc, "config.tcp", "enable", null, null) ;
            if(tcpVo.enable){    
                tcpVo.port = conf.getSetAttrPlusInt(doc, "config.tcp", "port", null, 100, 65535, null);
                tcpVo.processors = conf.getSetAttrPlusInt(doc, "config.tcp", "processors", null, 1, 100, null);
                tcpVo.idle = conf.getSetAttrPlusInt(doc, "config.tcp", "idle", null, 1, 20, null);// 10分钟
                tcpVo.showStartInfo = showStartInfo ;
                AdapterImp_TcpUnit tcpAdap = new AdapterImp_TcpUnit();
                tcpAdap.setConfig(tcpVo);
                TcpUnit tcpUnit = TcpUnit.getInstance();
                tcpUnit.setAdapter(tcpAdap);
                tcpUnit.start(obj -> {
                });
                TcpSvUrl = "[ip]:" + tcpVo.port ;
                units.add(tcpUnit) ;
            }    
        } catch (Exception e) {
            e.printStackTrace();
        }        
    }
    
 
}