While following the examples in this chapter, please replace the text jarFileName, yourDriver and yourCompany as previously described in the Preparation section.
In this section, the tutorial will show you how to configure your driver to receive incoming messages from your field-bus. This is accomplished by analyzing the incoming data and recognizing the beginning and ending of messages. The beginning of incoming messages is usually determined by recoginzing a particular pattern of one or more bytes within the data the is being received. The exact pattern and circumstances differs for each protocol. Some protocols place a byte or series of bytes immediately follwoing the beginnig pattern that indicates the size of the incoming message. To determine the ending of an incoming message, some protocols will define this in terms of a length. As just mentioned, the length is sometimes transmitted just after the beginning sequence of bytes. Other protocols that do not include a length, count, or message size in the request feature another pre-defined sequence of bytes as the ending sequence. Some very simple protocols might state that all incoming messages are the same, fixed size.
Note: In Udp/Ip, incoming messages are automatically delivered to the software from the operating system. This is possible becauses Udp/Ip features the distinct notion of data packets, also known as datagrams. If your driver communicates over Udp/Ip then you probably will not need to define the incoming message structure. It is possible that a Udp/Ip driver will not need to define a custom receiver at all. Therefore, if your driver communicates over Udp/Ip then please skip this chapter and proceed to the next chpater.
Please consider whether you need to make your class extend BDdfSerialReceiver or BDdfTcpReceiver, declare the corresponding package (com.tridium.ddfSerial.comm.* or com.tridium.ddfIp.tcp.comm.*) among your import statements, and change the extends clause accordingly in your file (to extend either BDdfSerialReceiver or BDdfTcpReceiver).
To do this, create a text file named BYourDriverReceiver.java in the jarFileName/src/com/yourCompany/yourDriver/comm folder. Inside the text file, start with the text that follows.
package com.yourCompany.yourDriver.comm; import javax.baja.sys.*; import com.tridium.ddf.comm.*; import com.tridium.ddfSerial.comm.*; // This would import com.tridium.ddfIp.tcp.comm.* // if the protocol was Tcp/Ip based. public class BYourDriverReceiver extends BDdfSerialReceiver // This would extend "BDdfTcpReceiver" if the protocol { // was Tcp/Ip based /*- class BYourDriverReceiver { } -*/ }
NOTE: This example extends BDdfSerialReceiver so it imports com.tridium.ddfSerial.comm*. In your case, if you choose to extend BDdfTcpReceiver then you should import com.tridium.ddfIp.tcp.comm.* instead.
NOTE: The multi-line comment that immediately follows the Java class declaration is an empty Niagara slotomatic declaration.
ADVANCED TOPIC: The rest of this example works best for protocols whose data frames have a definite, identifiable beginning and ending sequence of characters (bytes). If your protocol document does not have such a notion of data frames, then you will need to override the protected IDdfDataFrame doReceiveFrame() throws Exception method, read raw data directly from your driver's field bus, analyze the data, and return an IDdfDataFrame. The doReceiveFrame method is called in a tight loop. In fact, by default, the doReceiveFrame calls the following method that should make it convenient in the event that the driver protocol supports definite, identifiable data frames.
NOTE: This is an advanced topic that will be discussed in an appendix in a future version of this documentation.
Here is an example that would frame up receive messages in our hypothetical protocol where receive messages start with a hex 02 byte.
package com.yourCompany.yourDriver.comm; import javax.baja.sys.*; import com.tridium.ddf.comm.*; import com.tridium.ddfSerial.comm.*; // This would import com.tridium.ddfIp.tcp.comm.* // if the protocol was Tcp/Ip based. public class BYourDriverReceiver extends BDdfSerialReceiver // This would extend "BDdfTcpReceiver" if the protocol { // was Tcp/Ip based /*- class BYourDriverReceiver { } -*/ public int isStartOfFrame(IDdfDataFrame frameSoFar) { if (frameSoFar.getFrameBytes()[0]==0x02) return YES; else return NO; } }
We understand that chances are, your protocol is much more complicated than this. However, the general principle still applies no matter how complicated the protocol is (provided that it still features the notion of data frames). Analyze the given frame and return YES if the bytes that are in the frame so far are the beginning sequence of frames in your protocol, NO if not, or MAYBE if you need more bytes before being able to decide either way.
After your isStartOfFrame method returns YES, the isCompleteFrame method is then called for every byte that is received. Return true if the data in the fame looks like a completed, receive frame in your protocol. Return false if you need more data. If all of a sudden, you decide that the data in the frame is invalid, return true for now (the checkFrame method (that you may also override) will take care of that scenario.
package com.yourCompany.yourDriver.comm; import javax.baja.sys.*; import com.tridium.ddf.comm.*; import com.tridium.ddfSerial.comm.*; // This would import com.tridium.ddfIp.tcp.comm.* // if the protocol was Tcp/Ip based. public class BYourDriverReceiver extends BDdfSerialReceiver // This would extend "BDdfTcpReceiver" if the protocol { // was Tcp/Ip based /*- class BYourDriverReceiver { } -*/ public int isStartOfFrame(IDdfDataFrame frameSoFar) { if (frameSoFar.getFrameBytes()[0]==0x02) return YES; else return NO; } public boolean isCompleteFrame(IDdfDataFrame frameSoFar) { // This returns true if the last valid byte is 0x04. // Keep in mind, Java arrays start at index 0. // There is one caveat in the hypothetical protocol, the // Length of the response is always greater than 2 bytes. // This allows for the second byte to be 0x04 as necessary, // To indicate that the response came from unit 0x04 return frameSoFar.getFrameSize()>2 && // Length must be more than 2 frameSoFar.getFrameBytes()[frameSoFar.getFrameSize()-1]==0x04; // Frame must end with 0x04 } }
package com.yourCompany.yourDriver.comm; import javax.baja.sys.*; import com.tridium.ddf.comm.*; import com.tridium.ddfSerial.comm.*; // This would import com.tridium.ddfIp.tcp.comm.* // if the protocol was Tcp/Ip based. public class BYourDriverReceiver extends BDdfSerialReceiver // This would extend "BDdfTcpReceiver" if the protocol { // was Tcp/Ip based /*- class BYourDriverReceiver { } -*/ public int isStartOfFrame(IDdfDataFrame frameSoFar) { if (frameSoFar.getFrameBytes()[0]==0x02) return YES; else return NO; } public boolean isCompleteFrame(IDdfDataFrame frameSoFar) { // This returns true if the last valid byte is 0x04. // Keep in mind, Java arrays start at index 0. // There is one caveat in the hypothetical protocol, the // Length of the response is always greater than 2 bytes. // This allows for the second byte to be 0x04 as necessary, // To indicate that the response came from unit 0x04 return frameSoFar.getFrameSize()>2 && // Length must be more than 2 frameSoFar.getFrameBytes()[frameSoFar.getFrameSize()-1]==0x04; // Frame must end with 0x04 } public boolean checkFrame(IDdfDataFrame frameSoFar) { return (frameSoFar.getFrameBytes()[0]==0x02) && (frameSoFar.getFrameBytes()[frameSoFar.getFrameSize()-1]==0x04); } }
Note that if your checkFrame method returns True, the developer driver framework will pass the received frame to the corresponding request, perhaps the one that you created in chapter 1. Also, your checkFrame method will likely be much more complicated than in this example. Most serial protocols will place a checksum, circular redundancy check (CRC), or longitudinal redundancy check (LRC) as one of the last bytes in the message. Your checkFrame method, in that case, would implement the same algorithm, recompute the checksum, CRC, or LRC, and verify that the result equals the checksum, CRC, or LRC that was received in the data frame. This is done to guarantee data integrity -- that no bytes have been corrupted during transmission (due to static, etc.)
Copyright © 2000-2014 Tridium Inc. All rights reserved.