JetSet Tutorial 2
by Helge Timenes
Last Updated: November 27th 2013
Executive Overview
Tutorial 1 showed the basics of using JetSet to design a code generator. The resulting code generator and the source files it produce are very simple, and probably not very real-life relevant. This tutorial builds on this by introducing complexities in the meta model, as well as additional requirements, which require changes and additions to the code generator. A few new JetSet Nodes are introduced beyond the basic ones we saw in tutorial 1.
Content
- Problem Description
- Modifying the JetSet
- Generating the Code Generator
- Testing the Code Generator
- Conclusions
1 Problem Description
For the purpose of this tutorial, we will use the following scenario: The meta-model given in tutorial 1 is changed such that it is possible to specify individual data items in each message. Data items can be either numeric or textual. Numeric data items can be Integers or single Bytes (see Listing 1 below, changes from tutorial 1 in red).
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema targetNamespace="http://jetset.sf.net/tutorial/icd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:icd="http://jetset.sf.net/tutorial/icd"> <xsd:simpleType name="DataTypeEnum"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="Byte"/> <xsd:enumeration value="Integer"/> </xsd:restriction> </xsd:simpleType> <xsd:complexType name="AbstractObject" abstract="true"> <xsd:attribute name="Id" type="xsd:ID" use="required"/> </xsd:complexType> <xsd:complexType name="AbstractDataItem" abstract="true"> <xsd:complexContent> <xsd:extension base="icd:AbstractObject"> <xsd:attribute name="Order" type="xsd:int" use="required"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="NumericDataItem"> <xsd:complexContent> <xsd:extension base="icd:AbstractDataItem"> <xsd:attribute name="DataType" type="icd:DataTypeEnum" use="required"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="TextDataItem"> <xsd:complexContent> <xsd:extension base="icd:AbstractDataItem"> <xsd:attribute name="Length" type="xsd:int" use="required"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="Message"> <xsd:complexContent> <xsd:extension base="icd:AbstractObject"> <xsd:sequence> <xsd:element name="DataItem" type="icd:AbstractDataItem" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="NetworkNode"> <xsd:complexContent> <xsd:extension base="icd:AbstractObject"> <xsd:sequence> <xsd:element name="OutputMessage" type="icd:Message" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:complexType name="Network"> <xsd:complexContent> <xsd:extension base="icd:AbstractObject"> <xsd:sequence> <xsd:element name="NetworkNode" type="icd:NetworkNode" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:extension> </xsd:complexContent> </xsd:complexType> <xsd:element name="Network" type="icd:Network"/> </xsd:schema>
Your job this time is to change the code generator so that it takes the following requirements into account (changes or additions in red):
- Use the C language
- Manage data buffers as char-arrays of length given by the sum of all the contained items:
- Numeric data items with data type Integer are four bytes long
- Numeric data items with data type Byte are one bytes long
- Text data items are as many bytes long as given by the "Length" attribute
- Provide accessor and mutator methods for each data item, except those with Id="Spare", that
- Handles conversion between byte array and the specified data item type
- Ensures that the data is read from / written to the correct slots in the buffer, derived from the DataType and Order attributes
- Provide pointer access to the data buffer
- Provide a method that returns the size of the data buffer in number of bytes
Modifying the JetSet
Meta Model
First we need to update the meta-model.- Paste the content of Listing 1 into the InterfaceDocumentStandard.xsd and save it or copy it from here.
- If your JetSet model is open in the eclipse editor, reload the meta model by right-clicking on the Document Root and selecting JetSet → Reload Meta Model. Otherwise, open it.
Preprocessing
Now we are ready to modify the JetSet. We'll start by adding some preprocessing nodes to collect information about the size of each data item. For this we will use Context Variable Nodes and Virtual Attribute Node- Right-click the OutputMessages node
- Select New Child → Iteration Node.
- Move the newly created Data Items node by dragging and dropping it so that it appears above the Message Handler C-File node.
- Right-click the Data Items node
- Select New Child → Subtype Filter Node.
- Right-click the Numeric Data Item node
- Select New Child → Context Collection Node.
- Click the ... button in the value field of the Key property.
-
Enter
DATA_ITEM_SIZE_BYTES
and click OK. - Click the ... button in the value field of the Value property.
- Select DataType in the Attribute pull-down and click Insert.
-
Modify the Java code between the
<%=
and%>
tags so that it reads<%=getValue("DataType").equals("Integer") ? "4" : "1"%>
and click OK.
Your project workspace should now look something similar to Figure 01 below.

- Firstly, we added an iteration
for all DataItems in Message do...
. - Secondly, as the DataItem type is abstract, we added a Subtype Filter Node to force the iteration to become
for all NumericDataItems in Message do...
. Notice that JetSet automatically set the filter on the NumericDataItem subtype of DataItem rather than TextDataItem. This simply because it was the first found in the meta model. It can be changed by modifying the Subtype Filter attribute of the node (as we will see soon). - Then we added a Context Variable Node which defines a local key/value variable that can be used later.
- Select the Numeric Data Item node.
- Press Ctrl + c (copy).
- Select the Data Items node.
- Press Ctrl + v (paste).
- Change the value of the Subtype Filter property of the lowermost NumericDataItem node from icd:NumericDataItem toicd:TextDataItem.
-
Edit the Value property of the Context Variable Node underneath the TextDataItem node so that it reads
<%=getValue("Length")%>
(Hint: delete all, select and insert "Length" attribute)
DATA_ITEM_SIZE_BYTES
get a value for all data items, both numeric and text.
We can now use this local variable to enhance the meta-model by defining a new attribute for the AbstractDataItem type that holds the size of each data item (regardless of subtype). For this we will use a Virtual Attribute Node.
- Right-click the Data Items node
- Select New Child → Virtual Attribute Node.
- Change the default value of the Attribute Name property from "NewAttribue" to "SizeBytes".
- Click the ... button in the value field of the Attribute Value property.
- Select Context Variable DATA_ITEM_SITE_BYTES in the Object pull-down and click Insert and then OK.
Your project workspace should now look something similar to Figure 2 below.

We are now able to capture the sizes of individual data items and store them in virtual attributes which behaves as if they were part of the model, even if they aren't. Now we need to sum up the sizes of all data items in each message.
- Right-click the OutputMessages node
- Select New Child → Virtual Attribute Node.
- Drag the new Message.NewAttribute node up such that it becomes the first child node below the Messages node.
- Change the default value of the Attribute Name property from "NewAttribue" to "SizeBytes".
- Change the default value of the Node Name property from "Message.SizeBytes" to "Message.SizeBytes (Initializer)".
- Click the ... button in the value field of the Attribute Value property.
- Enter a zero and click OK.
- Right-click the DataItems node
- Select New Child → Virtual Attribute Node.
- Change the default value of the Add To Class property from "This (AbstractDataItem)" to "Container 1 (Message)".
- Change the default value of the Attribute Name property from "NewAttribue" to "SizeBytes".
- Change the default value of the Node Name property from "Message.SizeBytes" to "Message.SizeBytes (Incrementer)".
- Click the ... button in the value field of the Attribute Value property.
-
Enter a the following text
<%=Integer.parseInt(getValue(getContainer(1), "SizeBytes")) + Integer.parseInt(getValue("SizeBytes"))%>
.
Your JetSet should now look like this (Figure 3):

The first of the new virtual attribute nodes, Message.SizeBytes (Initializer), defines an attribute named "SizeBytes" for the type Message and, when the code generator is executed, initializes this attribute to zero for each message. The second new virtual attribute node, Message.SizeBytes (Incrementer), for each data item in the message, parses the current value of the Message.SizeBytes attribute, adds the value of the data item, and writes it back to Message.SizeBytes. Thus, when the code generator has iterated over all data items, we have the size of the message.
Now for the last bit of data gathering before we can begin changing the output: We need to know exactly where in the message each data item resides, so that we can read and write to the correct bytes in the buffer. For this, we simply add another virtual attribute, AbstractDataItem.OffsetBytes with value set equal to the message size before it is incremented for this data item (i.e. the corresponding Virtual Attribute Node must reside just before the Message.SizeBytes (Incrementer) node.
- Right-click the AbstractDataItem.SizeBytes node
- Select New Sibling → Virtual Attribute Node.
- Change the default value of the Attribute Name property from "NewAttribue" to "OffsetBytes".
- Click the ... button in the value field of the Attribute Value property.
- Select Container 1 (Message) in the Object pull-down and click Insert and then OK.
- Select SizeBytes in the Attribute pull-down, click Insert and then OK.
- Click on the DataItems node
- Click the ... button in the value field of the Sort Criteria property.
- Select Order in the Attribute pull-down, click Insert and then OK.
Your JetSet should now look like this (Figure 4):

Generating Content
Now we are equipped to implement the first requirement modified from Tutorial 1: Letting the data buffers arrays only be as long as given by the sum of all the contained items, instead of wastefully assigning 256 bytes per message regardless of content.
- Click the ... button in the value field of the Text property of the Message Text Node.
- Select the "256" part between the square brackets of the text in the array declaration.
-
Select SizeBytes in the Attribute pull-down and click Insert, such that the array declaration text becomes
static char Msg<%=getValue("Id")%>_Buffer[<%=getValue("SizeBytes")%>]
. -
Do the same for the "256" part in the return statement of the GetBufferSize method, so that it becomes
return <%=getValue("SizeBytes")%>;
Now for the new requirement: Data item accessor and mutator methods. For this we again need to iterate over all the data items in the message and use Subtype Filter Nodes to deal with the two different data item types. First we deal with numeric data items with data type equal to "Byte":
- Right-click the Message Text Node.
- Select New Sibling → Iteration Node.
- Click the ... button in the value field of the Condition Filter property of the new DataItems node.
- Select Id in the Attribute pull-down and click Insert.
-
Modify the inserted blue text so that it becomes
<%=!getValue("Id").equals("Spare")%>
and click OK. - Right-click the new DataItems node.
- Select New Child → Iteration Node.
- Right-click the new NumericDataItem node.
- Select New Child → Text Node.
- Rename the new NumericDataItem Text Node from "NumericDataItem" to "NumericDataItem - Byte".
- Click the ... button in the value field of the Condition property.
- Select DataType in the Attribute pull-down and click Insert.
-
Modify the inserted blue text so that it becomes
<%=getValue("DataType").equals("Byte")%>
and click OK. - Click the ... button in the value field of the Text property, paste the text in Listing 2 and click OK.
/* Data Item : <%=getValue("Id")%> Type : Numeric - Byte Offset : <%=getValue("OffsetBytes")%> Size : <%=getValue("SizeBytes")%> */ char Msg<%=getValue(getContainer(1), "Id")%>_Get<%=getValue("Id")%>(){ return Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=getValue("OffsetBytes")%>]; } void Msg<%=getValue(getContainer(1), "Id")%>_Set<%=getValue("Id")%>(char Value){ Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=getValue("OffsetBytes")%>] = Value; }
Your JetSet should now look like Figure 5 below:

Now for the Integers:
- Copy the NumericDataItem - Byte node and paste it underneath the NumericDataItem Subtype Filter Node.
- Rename the pasted node from "NumericDataItem - Byte" to "NumericDataItem - Integer".
-
Replace "Byte" with "Integer" in the value of the Condition property, so that it becomes
<%=getValue("DataType").equals("Integer")%>
and click OK. - Replace the value of the Text property with that given in Listing 3.
/* Data Item : <%=getValue("Id")%> Type : Numeric - Integer Offset : <%=getValue("OffsetBytes")%> Size : <%=getValue("SizeBytes")%> */ int Msg<%=getValue(getContainer(1), "Id")%>_Get<%=getValue("Id")%>(){ int Tmp; Tmp = (int)Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 0%>] << 24; Tmp = Tmp & (int)Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 1%>] << 16; Tmp = Tmp & (int)Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 2%>] << 8; Tmp = Tmp & (int)Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 3%>] << 0; return Tmp; } void Msg<%=getValue(getContainer(1), "Id")%>_Set<%=getValue("Id")%>(int Value){ Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 0%>] = (char)((0xFF000000 & Value) >> 24); Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 1%>] = (char)((0x00FF0000 & Value) >> 16); Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 2%>] = (char)((0x0000FF00 & Value) >> 8); Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=Integer.parseInt(getValue("OffsetBytes")) + 3%>] = (char)((0x000000FF & Value) >> 0); }
For the text data items we need a new Subtype Filter Node and an (unconditional) Text Node:
- Right-click the NumericDataItem node.
- Select New Sibling → Subtype Filter Node.
- Change the value of the Subtype Filter property from "icd:NumericDataItem" to "icd:TextDataItem".
- Right-click the new TextDataItems node.
- Select New Child → Text Node.
- Click the ... button in the value field of the Text property, paste the text in Listing 4 and click OK.
/* Data Item : <%=getValue("Id")%> Type : Text Offset : <%=getValue("OffsetBytes")%> Size : <%=getValue("SizeBytes")%> */ void Msg<%=getValue(getContainer(1), "Id")%>_Get<%=getValue("Id")%>(char* Value){ int Index; for(Index=0; Index<<%=getValue("Length")%>; Index++){ Value[Index] = Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=getValue("OffsetBytes")%> + Index]; } } void Msg<%=getValue(getContainer(1), "Id")%>_Set<%=getValue("Id")%>(char* Value){ int Index; for(Index=0; Index<<%=getValue("Length")%>; Index++){ Msg<%=getValue(getContainer(1), "Id")%>_Buffer[<%=getValue("OffsetBytes")%> + Index] = Value[Index]; } }
We have now completed the required changes to our Jetset model. It should now look like this (Figure 6):

4 Generating The Code Generator
Just as we saw in Tutorial 1 we can now generate the actual code generator and export it as a stand-alone java program:
- Right click on any node in the JetSet tree.
- Select JetSet → Export Stand-Alone Executable....
- Select a directory where you want the executable exported, for example C:\Temp\JetSetTutorial\.
- Click Ok
You now have a complete stand-alone code generator.
5 Testing the Code Generator
To test our code generator we need a slightly more interesting network model instance than the one we used in Tutorial 1. For instance the one given in Listing 5 below. You can get it here or simply copy from Listing 5. Save it to a local file on your hard drive, for instance C:\Temp\JetSetTutorial\InterfaceControlDocument.xml.
<?xml version="1.0" encoding="UTF-8"?> <icd:Network xmlns:icd="http://jetset.sf.net/tutorial/icd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Id="JetSetTutorialExmaple"> <NetworkNode Id="ControlComputer"> <OutputMessage Id="ActuatorCommands"> <DataItem xsi:type="icd:TextDataItem" Order="1" Id="Spare" Length="2"/> <DataItem xsi:type="icd:NumericDataItem" Order="2" Id="AileronCmd" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="3" Id="ElevatorCmd" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="4" Id="RudderCmd" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="5" Id="FlapsCmd" DataType="Byte"/> <DataItem xsi:type="icd:NumericDataItem" Order="6" Id="GearCmd" DataType="Byte"/> </OutputMessage> </NetworkNode> <NetworkNode Id="NavigationComputer"> <OutputMessage Id="SensorFusionData"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="HybridAltitude" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="2" Id="HybridAltitudeValid" DataType="Byte"/> </OutputMessage> <OutputMessage Id="PositionData"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="PositionX" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="2" Id="PositionY" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="3" Id="PositionValid" DataType="Byte"/> </OutputMessage> <OutputMessage Id="TimeData"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="UnixTimeSecs" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="2" Id="UnixTimeNanos" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="3" Id="UnixTimeValid" DataType="Byte"/> </OutputMessage> </NetworkNode> <NetworkNode Id="RadarAltimeter"> <OutputMessage Id="RadarData"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="RadarMode" DataType="Byte"/> <DataItem xsi:type="icd:NumericDataItem" Order="2" Id="RadarAlt" DataType="Integer"/> </OutputMessage> </NetworkNode> <NetworkNode Id="AirDataSensor"> <OutputMessage Id="AirData"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="AirTemperature" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="2" Id="AirPressure" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="3" Id="AirHumidity" DataType="Integer"/> </OutputMessage> </NetworkNode> <NetworkNode Id="InertialSensor"> <OutputMessage Id="InertialState"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="InertialMode" DataType="Byte"/> <DataItem xsi:type="icd:NumericDataItem" Order="2" Id="InertialAccelX" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="3" Id="InertialAccelY" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="4" Id="InertialAccelZ" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="5" Id="InertialPitchRate" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="6" Id="InertialRollRate" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="7" Id="InertialBankRate" DataType="Integer"/> </OutputMessage> </NetworkNode> <NetworkNode Id="GPS"> <OutputMessage Id="GpsLocation"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="LocationValid" DataType="Byte"/> <DataItem xsi:type="icd:TextDataItem" Order="2" Id="Spare" Length="3"/> <DataItem xsi:type="icd:NumericDataItem" Order="5" Id="GpsAltitude" DataType="Integer"/> <DataItem xsi:type="icd:TextDataItem" Order="6" Id="Spare" Length="4"/> <DataItem xsi:type="icd:TextDataItem" Order="3" Id="GpsLatitude" Length="12"/> <DataItem xsi:type="icd:TextDataItem" Order="4" Id="GpsLongitude" Length="12"/> <DataItem xsi:type="icd:NumericDataItem" Order="7" Id="GpsYear" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="8" Id="GpsDayOfYear" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="9" Id="GpsSecOfDay" DataType="Integer"/> </OutputMessage> <OutputMessage Id="GpsSatInfo"> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="GpsNumSatsTracked" DataType="Integer"/> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="GpsEgnosAvailable" DataType="Byte"/> <DataItem xsi:type="icd:NumericDataItem" Order="1" Id="GpsWaasAvailable" DataType="Byte"/> </OutputMessage> </NetworkNode> </icd:Network>
Though you can run the code generator from within eclipse, we will test it in stand-alone mode, using the batch file we generated in the last chapter.
- Open up a command prompt console (Windows users: Start → Run and enter "cmd.exe").
-
Change to the directory where the stand-alone executable and batch file was generated (e.g.
cd C:\Temp\JetSetTutorial\
). -
Trigger the code generator using the generated batch file with the name of the model file and name of directory where we want the output to be generated. For example
Tutorial InterfaceControlDocument.xml .
to generate our output in the current directory
If we have done everything right so far, you will notice that several files have appeared in the directory you specified as output directory. Its content should be similar to that shown in Listing 6 below. This is our generated C code, compliant to the requirements stated in section 1.
A few interesting points are worth mentioning:
- The buffer size has been reduced to 48 bytes
- Each data item has an accessor and a mutator method, except those with Id="Spare".
- The order of the accessor and a mutator methods corresponds to the order of the data items in the model, BUT.
- The data item offsets corresponds to that given by the "Order" attribute in the model, just as required.
/************************************************************* Data buffer handler for Message GpsLocation Produced by Network Node GPS *************************************************************/ /* Data buffer array */ static char MsgGpsLocation_Buffer[48]; /* Returns a pointer to the buffer array */ char* MsgGpsLocation_GetBuffer(){ return MsgGpsLocation_Buffer; } /* Returns the size of the data buffer */ int MsgGpsLocation_GetBufferSize(){ return 48; } /* Data Item : LocationValid Type : Numeric - Byte Offset : 0 Size : 1 */ char MsgGpsLocation_GetLocationValid(){ return MsgGpsLocation_Buffer[0]; } void MsgGpsLocation_SetLocationValid(char Value){ MsgGpsLocation_Buffer[0] = Value; } /* Data Item : GpsAltitude Type : Numeric - Integer Offset : 28 Size : 4 */ int MsgGpsLocation_GetGpsAltitude(){ int Tmp; Tmp = (int)MsgGpsLocation_Buffer[28] << 24; Tmp = Tmp & (int)MsgGpsLocation_Buffer[29] << 16; Tmp = Tmp & (int)MsgGpsLocation_Buffer[30] << 8; Tmp = Tmp & (int)MsgGpsLocation_Buffer[31] << 0; return Tmp; } void MsgGpsLocation_SetGpsAltitude(int Value){ MsgGpsLocation_Buffer[28] = (char)((0xFF000000 & Value) >> 24); MsgGpsLocation_Buffer[29] = (char)((0x00FF0000 & Value) >> 16); MsgGpsLocation_Buffer[30] = (char)((0x0000FF00 & Value) >> 8); MsgGpsLocation_Buffer[31] = (char)((0x000000FF & Value) >> 0); } /* Data Item : GpsLatitude Type : Text Offset : 4 Size : 12 */ void MsgGpsLocation_GetGpsLatitude(char* Value){ int Index; for(Index=0; Index<12; Index++){ Value[Index] = MsgGpsLocation_Buffer[4 + Index]; } } void MsgGpsLocation_SetGpsLatitude(char* Value){ int Index; for(Index=0; Index<12; Index++){ MsgGpsLocation_Buffer[4 + Index] = Value[Index]; } } /* Data Item : GpsLongitude Type : Text Offset : 16 Size : 12 */ void MsgGpsLocation_GetGpsLongitude(char* Value){ int Index; for(Index=0; Index<12; Index++){ Value[Index] = MsgGpsLocation_Buffer[16 + Index]; } } void MsgGpsLocation_SetGpsLongitude(char* Value){ int Index; for(Index=0; Index<12; Index++){ MsgGpsLocation_Buffer[16 + Index] = Value[Index]; } } /* Data Item : GpsYear Type : Numeric - Integer Offset : 36 Size : 4 */ int MsgGpsLocation_GetGpsYear(){ int Tmp; Tmp = (int)MsgGpsLocation_Buffer[36] << 24; Tmp = Tmp & (int)MsgGpsLocation_Buffer[37] << 16; Tmp = Tmp & (int)MsgGpsLocation_Buffer[38] << 8; Tmp = Tmp & (int)MsgGpsLocation_Buffer[39] << 0; return Tmp; } void MsgGpsLocation_SetGpsYear(int Value){ MsgGpsLocation_Buffer[36] = (char)((0xFF000000 & Value) >> 24); MsgGpsLocation_Buffer[37] = (char)((0x00FF0000 & Value) >> 16); MsgGpsLocation_Buffer[38] = (char)((0x0000FF00 & Value) >> 8); MsgGpsLocation_Buffer[39] = (char)((0x000000FF & Value) >> 0); } /* Data Item : GpsDayOfYear Type : Numeric - Integer Offset : 40 Size : 4 */ int MsgGpsLocation_GetGpsDayOfYear(){ int Tmp; Tmp = (int)MsgGpsLocation_Buffer[40] << 24; Tmp = Tmp & (int)MsgGpsLocation_Buffer[41] << 16; Tmp = Tmp & (int)MsgGpsLocation_Buffer[42] << 8; Tmp = Tmp & (int)MsgGpsLocation_Buffer[43] << 0; return Tmp; } void MsgGpsLocation_SetGpsDayOfYear(int Value){ MsgGpsLocation_Buffer[40] = (char)((0xFF000000 & Value) >> 24); MsgGpsLocation_Buffer[41] = (char)((0x00FF0000 & Value) >> 16); MsgGpsLocation_Buffer[42] = (char)((0x0000FF00 & Value) >> 8); MsgGpsLocation_Buffer[43] = (char)((0x000000FF & Value) >> 0); } /* Data Item : GpsSecOfDay Type : Numeric - Integer Offset : 44 Size : 4 */ int MsgGpsLocation_GetGpsSecOfDay(){ int Tmp; Tmp = (int)MsgGpsLocation_Buffer[44] << 24; Tmp = Tmp & (int)MsgGpsLocation_Buffer[45] << 16; Tmp = Tmp & (int)MsgGpsLocation_Buffer[46] << 8; Tmp = Tmp & (int)MsgGpsLocation_Buffer[47] << 0; return Tmp; } void MsgGpsLocation_SetGpsSecOfDay(int Value){ MsgGpsLocation_Buffer[44] = (char)((0xFF000000 & Value) >> 24); MsgGpsLocation_Buffer[45] = (char)((0x00FF0000 & Value) >> 16); MsgGpsLocation_Buffer[46] = (char)((0x0000FF00 & Value) >> 8); MsgGpsLocation_Buffer[47] = (char)((0x000000FF & Value) >> 0); }
6 Conclusion
Building upon the work we did in the JetSet Tutorial 1, we have seen some of the more advanced features of JetSet, such as
- Handling meta-model abstract types and type inheritance with Subtype Filter Nodes,
- Storage and retrieval of local variables with Context Variable Nodes,
- Extension of model and meta model with Virtual Attribute Nodes
- Making Text Nodes conditional by using the Condition property
- Filtering iterations using the Condition Filter property of Iteration Nodes
- Sorting of iterations using the Iteration Node Sort Criteria
JetSet also offers even more advanced features, such as recursion using GoTo Nodes, embedding external Java code with Java Extension Nodes, gathering data in Context Collection Nodes and using these with Iteration Nodes. This may be covered in a separate tutorial at some point. But then again, maybe it won't...
The JetSet model used to make this tutorial can be found here