The developer driver framework will use your driver's write request to automatically update point values in your equipment when the value in the corresponding control point component changes from within Niagara AX. Please follow these steps to create a write-request for your driver.
While following the examples in this chapter, please replace the text jarFileName, yourDriver and yourCompany as previously described in the Preparation section):
Some protocols are designed so that one write message can update more than one data point in the equipment. Other protocols are designed with a one-to-one relationship between write messages and point values. The developer driver framework accommodates both of these scenarios.
To do this, create a text file named BYourDriverWriteRequest.java in the jarFileName/src/com/yourCompany/yourDriver/comm/req folder. Inside the text file, start with the following text:
package com.yourCompany.yourDriver.comm.req; import com.tridium.ddf.comm.req.*; import javax.baja.sys.*; public class BYourDriverWriteRequest extends BDdfWriteRequest { /*- class BYourDriverWriteRequest { } -*/ }
Inside the body of the toByteArray method, you will need to construct a Java byte array and return it. The next step will further describe how to do this.
To add the toByteArray method, add the following lines of text after the slotomatic comment of the class:
public byte[] toByteArray() { }
As mentioned during the lesson for day 1, frozen properties are a special kind of Niagara AX property on a Niagara AX component that you can easily access from Java source code. In subsequent chapters, you will make the class for the write parameters structure. For now, please assume that you have already created it.
Please recall that to create frozen properties on a component, you add a special comment just after the class statement in the Java file. After doing that, you will run a Niagara AX development utility called slotomatic that will parse the special comment and add some Java code to your file -- the Java code necessary to add the property to the Niagara AX component that the Java file defines. This automatically generated Java code includes a method (function) called getMyProperty (where myProperty is the name of the frozen property, as you would have declared in the special comment).
In light of all this discussion, please finish updating the toByteArray method to return a byte array that matches the description that your protocol document defined for the message that you chose to be the write request. Please follow this example as a guide:
public byte[] toByteArray() { // In the dev driver framework, all requests are automatically // Assigned a deviceId when they are created. In addition to the // DeviceId, write requests are automatically assigned an instance // Of a Write Parameters structure when they are // Created. The dev driver framework calls the toByteArray method // (function) after it creates the write request, therefore this // Particular request has already been assigned a device id and // a Write parameters structure. The deviceId will // Be an instance of BYourDriverDeviceId, the writeParameters // Structure will be an instance of BYourDriverWriteParameters, // That is how dev driver works! This happens automatically. BYourDriverDeviceId deviceId = (BYourDriverDeviceId)getDeviceId(); BYourDriverWriteParams writeParams = (BYourDriverWriteParams)getWriteParameters(); final byte SOH = 0x01; final byte EOT = 0x04; // In this hypothetical example, the protocol document // Indicates that all requests start with a hex 01 byte and // All requests end with a hex 04 byte. // After the hex 01, the protocol expects a number between // 0 and 255 to identify the device, followed by the ASCII // Characters "Write " or "Force Write" followed by one or more of the // following: // ao{X}={signed int} // do{X}=On // do{X}=Off // Where: // {X} = a sequence of ASCII digits '0'-'9' to identify which // analog or digital output to change. // // {signed int} = a sequence of ASCII digits '0'-'9' preceded // optionally by a minus sign // // If more than one of these sequences are present then they are // delimited by commas. // The message ends with a hex 04 terminator byte. // ByteArrayOuptutStream is a standard Java class in package java.io // Let's use it to help us build the byte array that we will return ByteArrayOutputStream bos = new ByteArrayOutputStream(); // Writes the hex 01 start character to bos, our Java stream of // bytes. bos.write(SOH); // Writes the unit number onto bos, our Java stream of bytes. bos.write(deviceId.getUnitNumber()); // Possibly writes the ASCII bytes for "force" followed by a space to // bos, our Java stream of bytes if (writeParams.getForceWrite()) { bos.write('f'); bos.write('o'); bos.write('r'); bos.write('c'); bos.write('e'); bos.write(' '); } // Writes the ASCII bytes for "write" followed by a space to // bos, our Java stream of bytes bos.write('w'); bos.write('r'); bos.write('i'); bos.write('t'); bos.write('e'); bos.write(' '); // Loops through all control points that are to be updated by this request. // The dev driver framework will try to coalesce all control points // Under a device that have equivalent write parameters into a single write // Request. You can get the array of these items by calling the method // named getWritableSource. It returns an array of IDdfWritable -- these // will be the proxy extensions of your driver's control points. IDdfWritable pointsToUpdate[] = getWritableSource(); for (int i=0; i<pointsToUpdate.length;i++) { // This is a good thing to check in case dev driver adds support for // Writing components that are not proxy extensions if (pointsToUpdate[i] instanceof BYourDriverProxyExt) { // Casts the IDdfWritable to BYourDriverProxyExt BYourDriverProxyExt updateProxy = (BYourDriverProxyExt)pointsToUpdate[i]; // Gets the read parameters structure, it helped BYourDriverReadRequest // know whether to read analog or digital. We can make optimal use of this // property by re-using it here also. BYourDriverReadParams proxyReadParams = (BYourDriverReadParams)updateProxy.getReadParameters(); // Gets the point id structure for the particular point. We previously // defined it to contain an offset. We can make optimal use of this offset // by re-using it here also. BYourDriverPointId proxyPointId = (BYourDriverPointId)updateProxy.getPointId(); // This boolean helps our logic remember whether the point is digital boolean digitalProxy=false; // The getRawValue method is available for your convenience to convert any // IDdfWritable among the writable source into a double precision value. double proxyValue = getRawValue(updateProxy); if (proxyReadParams.getTypeString().equalsIgnoreCase("analog")) { // If updating an analog output on the field-device bos.write('a'); bos.write('o'); digitalProxy=false; } else if (proxyReadParams.getTypeString().equalsIgnoreCase("digital")) { // Else, if updating a digital output on the field-device bos.write('d'); bos.write('o'); digitalProxy=true; } else // Sanity check throw new RuntimeException("Oops! Writing type string '"+ proxyReadParams.getTypeString()+"' is not supported."); // Writes the point index as a string bos.write(Integer.toString(proxyId.getOffset()).getBytes()); bos.write('='); // Writes the new value if (digitalProxy) // If the point is digital { if (proxyValue>0) // If the rawValue is greater than 0 { bos.write('o'); bos.write('n'); // Writes "on" } else // Else, rawValue must be 0 { // Writes "off" bos.write('o'); bos.write('f'); out.write('f'); } } // Else, the point is analog else // The Java Long.toString method outputs a sequence of ASCII digits bos.write(Long.toString(Math.round(proxyValue))) // Possibly preceded by '-' if(i+1<pointsToUpdate.length) // If not the last point in the loop bos.write(','); // Then this writes a comma } // End of if instanceof etc. } // End of for loop // Writes the byte that according to our hypothetical protocol, // Indicates the end of the message on the field-bus. bos.write(EOT); // Converts the stream of bytes in our Java stream of bytes into // An actual Java byte array and returns it. return bos.toByteArray(); }
To recap part of day 1's lesson, the developer driver framework calls the toByteArray method (function), transmits the resulting byte array onto the field-bus, looks for incoming data frames, and passes them to this method (until this method returns a response (not null), throws an exception, or times out.
Please implement the processReceive using the following Java code as a guide:
public BIDdfResponse processReceive(IDdfDataFrame recieveFrame) throws DdfResponseException { // We coded our hypothetical receiver such that received frames always have // at least 2 bytes. So lets not worry about checking for that String responseStatus = new String( // Constructs a string from bytes receiveFrame.getFrameBytes(), // In the receive frame buffer 2, // Starting at index 2, taking receiveFrame.getFrameSize()-3); // All chars except SOH, unitNbr, and EOT // According to our hypothetical protocol, the device responds 'OK' if the // Write succeeds. Any other string denies the write. In the event of a // Denial, the string itself describes the denial in plain English. if (responseStatus.equalsIgnoreCase("OK")) return new BYourDriverWriteResponse(); else throw new DdfResponseException("Equipment Nak - "+responseStatus); }
Copyright © 2000-2016 Tridium Inc. All rights reserved.