一直好奇niagara框架中串口是如何打开的,最近通过看源码,大致明白了,现记录如下
首先从BModbusAsyncNetwork这个类看起,在niagara help中查找没有源码,不过没关系,利用反编译看,重点代码如下
//BModbusAsyncNetwork是一个BIService
public void serviceStarted() throws Exception {
//必须看父类的实现
super.serviceStarted();
getNameSubscriber().subscribe(getSerialPortConfig());
getSerialPortConfig().setSerialHelperParent(this);
...
}
public void startComm() throws Exception {
if (getSerialPortConfig().getPortName().equals("none")) {
configFail("No port selected for Modbus communication.");
} else {
try {
//还是要看父类的实现
super.startComm();
configOk();
} catch (Exception e) {
configFail(new StringBuffer("Could not enable Modbus serial communication (").append(e).append(')').toString());
throw e;
}
}
...
}
//对父类抽象方法的重写
protected Comm makeComm() {
return new ModbusAsyncSerialComm(this);
}
回溯父类,其中BBasicNetwork比较重要(有niagara源码)
/**
* Builds the communication handler (Comm).
*/
public void serviceStarted()
throws Exception
{
buildComm();
}
/**
* Initializes the basic network with a new communication handler (Comm)
* for both the transmit and receive drivers. After creating
* a new Comm, this method calls initComm(Comm comm)
* with the new Comm to allow subclasses to perform any initialization
* (i.e. adding custom UnsolicitedMessageListeners for handling unsolicited received
* messages).
*/
private void buildComm()
throws Exception
{
comm = makeComm();
initComm(comm);
}
/**
* This method starts the Communication handler
* (Comm) if the network is not down/fault/out-of-service
* and the current Comm is not null.
*/
public void startComm()
throws Exception
{
if((!isDisabled()) && (!isFatalFault()) && (comm != null))
{
if (getLog().isTraceOn()) getLog().trace(getName() + " *** Starting Communication Handler ***");
comm.start();
if (getLog().isTraceOn()) getLog().trace(getName() + " *** Started Communication Handler ***");
}
}
/**
* Start the basic network. This starts the Communication handler
* (Comm) if the network is not down/fault/out-of-service.
*/
public void started()
throws Exception
{
super.started();
try
{
startComm();
}
catch (Exception e)
{
getLog().error("Could not start communication handler", e);
}
}
接下来要看comm.start(),comm是Comm对象(有niagara源码)其start()里主要调用了started(),对于BModbusAsyncNetwork,comm是ModbusAsyncSerialComm ,
protected boolean started() throws Exception {
try {
BISerialService bISerialService = (BISerialService) Sys.getService(BISerialService.TYPE);
this.serialPort = ((BModbusAsyncNetwork) getNetwork()).getSerialPortConfig().open(getNetwork().getName());
this.serialPort.enableReceiveTimeout(bISerialService.getMinTimeout());
this.in = this.serialPort.getInputStream();
this.out = this.serialPort.getOutputStream();
...
getSerialPortConfig()返回的是BSerialHelper对象(有niagara源码),其open()方法为
/**
* Opens the serial port and sets the port parameters.
* Returns the serial port as a BISerialPort.
*
* @param String owner - The name of the owner to set for the serial port.
*/
public BISerialPort open(String owner)
throws Exception
{
BISerialService platSvc = (BISerialService) Sys.getService(BISerialService.TYPE);
((BComponent)platSvc).lease(); // create a subscription to force the platform service to lazy-init
try
{
port = platSvc.openPort(getPortName(), owner);
}
可以看到是通过BISerialService来打开串口的,遇到接口就只能猜测一下了。。。还好,最终发现在我的电脑上是BSerialPortPlatformServiceWin64,它的父类BSerialPortPlatformService实现了该接口,openPort()的核心代码如下
public BISerialPort openPort(String paramString1, String paramString2)
throws PortNotFoundException, PortDeniedException
{
...
Object localObject = (BSerialPort)get(paramString1);
...
try
{
((BSerialPort)localObject).openPort();
return new BSerialPortHandle((BSerialPort)localObject);
}
...
}
get(paramString1)这个看上去比较奇怪,其实它是BComplex的方法(获得slot),这些BSerialPort是如何添加的能,这就要看它的抽象方法loadPortIdentifiers()了,这里看BSerialPortPlatformServiceWin64的实现
protected String[] loadPortIdentifiers()
throws Exception
{
...
Enumeration localEnumeration = CommPortIdentifier.getPortIdentifiers();
while (localEnumeration.hasMoreElements())
{
CommPortIdentifier localCommPortIdentifier1 = (CommPortIdentifier)localEnumeration.nextElement();
if (localCommPortIdentifier1.getPortType() == 1)
{
localVector.add(localCommPortIdentifier1);
}
}
...
BSerialPortWin64 localBSerialPortWin64 = new BSerialPortWin64(arrayOfCommPortIdentifier[j], j);
add(SlotPath.escape(arrayOfString[j]), localBSerialPortWin64, 3);
}
是不是很熟悉了,RxTx库哈哈,add()实现slot的动态添加