In this article, I'll show how to use a .NET wrapper for KlvLib library.
KlvLib SDK is a C++ library for encoding and decoding Klv data packets. If you need to use it in C#, here is how you can do that.
There is a KlvLibWr.dll wrapper ( available on request ) that will help us to do the job.
Let's assume we have to KLV encode a hypothetical MMS data packet. The MMS (MISB Minimum Metadata Set) consists of metadata elements taken from MISB Standard 0601.X to enable the minimum functionality required for both Discovery & Retrieval of source imagery and Situational Awareness Product for ISR mission accomplishment.
We'll use a sample data set from the MISB902 Standard, so it would be easy to check the results.
Tag | Name | Value | Interpretation | TLV Hex Bytes |
---|---|---|---|---|
2 | UNIX Time Stamp | 1231798102000000 | Mon Jan 12 2009 22:08:22 (UTC) | 02 08 00 04 60 50 58 4E 01 80 |
5 | Platform Heading Angle | 0x71C2 | 159.9744 Degrees | 05 02 71 C2 |
6 | Platform Pitch Angle | 0xFD3D | -0.4315251 Degrees | 06 02 FD 3D |
7 | Platform Roll Angle | 0x08B8 | 3.405814 Degrees | 07 02 08 B8 |
13 | Sensor Latitude | 0x5595B66D | 60.17682296 Degrees | 0D 04 55 95 B6 6D |
14 | Sensor Longitude | 0x5B5360C4 | 128.42675904 Degrees | 0E 04 5B 53 60 C4 |
15 | Sensor True Altitude | 0xC221 | 14190.72 Meters | 0F 02 C2 21 |
16 | Sensor Horizontal FoV | 0xCD9C | 144.5713 Degrees | 10 02 CD 9C |
17 | Sensor Vertical FoV | 0xD917 | 152.6436 Degrees | 11 02 D9 17 |
18 | Sensor Rel. Azimuth Angle | 0x724A0A20 | 160.71921147 Degrees | 12 04 72 4A 0A 20 |
19 | Sensor Rel. Elevation Angle | 0x87F84B86 | -168.79232483 Degrees | 13 04 87 F8 4B 86 |
20 | Sensor Rel. Roll Angle | 0x00000000 | 0.0 Degrees | 14 04 00 00 00 00 |
21 | Slant Range | 0x03830926 | 68590.98 Meters | 15 04 03 83 09 26 |
22 | Target Width | 0x1281 | 722.8199 Meters | 16 02 12 81 |
23 | Frame Center Latitude | 0xF101A229 | -10.54238863 Degrees | 17 04 F1 01 A2 29 |
24 | Frame Center Longitude | 0x14BC082B | 29.15789012 Degrees | 18 04 14 BC 08 2B |
25 | Frame Center Elevation | 0x34F3 | 3216.037 Meters | 19 02 34 F3 |
65 | UAS LDS Version | 0x02 | MISB Standard 0601.2 | 41 01 02 |
1 | Checksum | 0xC84C | 0xC84C | 01 02 C8 4C |
First, we add a reference to the KlvLibWr.dll to our project along with the corresponding using statement:
using KlvLibWr;
Next, let's define a KlvObject class:
class KlvObject { public byte Tag { get; set; } public object ValueObject { get; set; } public byte[] ValueBuf { get; set; } public KlvObject() { Tag = 0; ValueObject = null; ValueBuf = null; } public KlvObject(byte tag, object valueObject) { Tag = tag; ValueObject = valueObject; ValueBuf = (byte[])ValueObject; } }
and fill a list with with the items of this type.
// Fill KlvObjectList with data ( taken from MISB 0902 sample ) List<KlvObject> KlvObjectList = new List<KlvObject>(); KlvObjectList.Add(new KlvObject(0x2, new byte[] { 0x00, 0x04, 0x60, 0x50, 0x58, 0x4E, 0x01, 0x80 })); KlvObjectList.Add(new KlvObject(0x5, new byte[] { 0x71, 0xC2 })); KlvObjectList.Add(new KlvObject(0x6, new byte[] { 0xFD, 0x3D })); KlvObjectList.Add(new KlvObject(0x7, new byte[] { 0x08, 0xB8 })); KlvObjectList.Add(new KlvObject(0xD, new byte[] { 0x55, 0x95, 0xB6, 0x6D })); KlvObjectList.Add(new KlvObject(0xE, new byte[] { 0x5B, 0x53, 0x60, 0xC4 })); KlvObjectList.Add(new KlvObject(0xF, new byte[] { 0xC2, 0x21 })); KlvObjectList.Add(new KlvObject(0x10, new byte[] { 0xCD, 0x9C })); KlvObjectList.Add(new KlvObject(0x11, new byte[] { 0xD9, 0x17 })); KlvObjectList.Add(new KlvObject(0x12, new byte[] { 0x72, 0x4A, 0x0A, 0x20 })); KlvObjectList.Add(new KlvObject(0x13, new byte[] { 0x87, 0xF8, 0x4B, 0x86 })); KlvObjectList.Add(new KlvObject(0x14, new byte[] { 0x00, 0x00, 0x00, 0x00 })); KlvObjectList.Add(new KlvObject(0x15, new byte[] { 0x03, 0x83, 0x09, 0x26 })); KlvObjectList.Add(new KlvObject(0x16, new byte[] { 0x12, 0x81 })); KlvObjectList.Add(new KlvObject(0x17, new byte[] { 0xF1, 0x01, 0xA2, 0x29 })); KlvObjectList.Add(new KlvObject(0x18, new byte[] { 0x14, 0xBC, 0x08, 0x2B })); KlvObjectList.Add(new KlvObject(0x19, new byte[] { 0x34, 0xF3 })); KlvObjectList.Add(new KlvObject(0x41, new byte[] { 0x02 }));
Next, we'll put the code for creating a data buffer into a EncodeDataBuffer function, so we could later reuse it.
byte[] EncodeDataBuffer(List<KlvObject> KlvObjectList) { byte[] buf = null; CKlvEncoderWr klvEncoder = new CKlvEncoderWr(); klvEncoder.SetOuterKey("060E2B34020B01010E01030101000000"); // ASCII form // or in binary form: // klvEncoder.SetOuterKey(new byte[] { 0x06, 0x0E, 0x2B, 0x34, 0x02, 0x0B, 0x01, 0x01, 0x0E, 0x01, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00 }); klvEncoder.SetCheckSumKey("01"); // ASCII form // or in binary form: // klvEncoder.SetCheckSumKey(new byte[] { 0x01 }); if (KlvObjectList.Count > 0) { foreach (var klvObj in KlvObjectList) { klvEncoder.AddKlvItem(klvObj.Tag, klvObj.ValueBuf); } buf = klvEncoder.Encode(); } return buf; }
Now, if we call this method, providing the KlvObjectList array as an argument, we'll get back an encoded buffer:
// Encode Klv Buffer var dataBuffer = EncodeDataBuffer(KlvObjectList);
If we save this buffer and open it with KlvInspector, we'll see a properly formatted MISB 0601.X Klv packet:
The checksum is calculated automatically and set to 0xC8 4C, exactly like in the MISB 0902 standard sample.
Now, let's decode the buffer and see if we can get all our Klv items back (of course, you can load any other klv packet and decode it, but we're going to stick to the data we have).
All we have to do is create a KlvDecoder instance and call its Parse method, providing the buffer.
// Create decoder instance CKlvDecodeWr klvDecoder = new CKlvDecodeWr(); // Decode the data buffer and get the array of Klvs CKlvItem[] itemArr = klvDecoder.Parse(dataBuffer, true);
Now, if we examine the returned CKlvItem array, we'll see that all our original values are present there.
Ok, it was really easy to encode and decode a simple Klv packet, but what if we need something more complex? For example, in a real life scenario, you probably need to add some nested Klv data, like Security Metadata Set (defined by MISB 0102.X).
We're not going to discuss a MISB0102 standard here or how to create the Metadata Set buffer - you can use MISB0601Converter for this if you like. Just remember, if you're using KlvLib to create a nested buffer, you should make a separate instance of the encoder.
For the KlvLib, this data is just like any other data buffer. I used KlvInspector to create a sample buffer.
A binary buffer for the above data will be:
01 01 01 02 01 01 03 04 2F 2F 49 4C 04 04 54 65 73 74 0C 01 02 16 02 00 09.
It will have a length of 25 bytes.
So, lets create a new KlvObject with a key 48 (0x30) and length 25 (0x19), filling the value with the security metadata set. Add it to the existing array and encode the buffer.
byte[] secMetadatSetArr = new byte[] { 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x04, 0x2F, 0x2F, 0x49, 0x4C, 0x04, 0x4, 0x54, 0x65, 0x73, 0x74, 0x0C, 0x01, 0x02, 0x16, 0x02, 0x00, 0x09 }; KlvObjectList.Add(new KlvObject(0x30, secMetadatSetArr)); dataBuffer = EncodeDataBuffer(KlvObjectList);
Saving this buffer to a file and opening it with KlvInspector, will show a properly formatted MISB 0601.X Klv packet where in addition to our old data there is a nested Security Metadata Set.
Decoding it back is exactly the same as shown above.
That's it.
No Comments