diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-09-19 06:25:42 +0200 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2024-09-19 06:25:42 +0200 |
| commit | 7ceb2589d901a13b8a65df134b5325ef4c6fd6a9 (patch) | |
| tree | e78dddd38460fee2905c205389ffad986e42a554 /zig-tlv-encoding/main.zig | |
| parent | 865ee53ab70b06a5f8e03b7cb1433e6b9e97cd35 (diff) | |
| download | probe-7ceb2589d901a13b8a65df134b5325ef4c6fd6a9.tar.gz | |
Added TLV encoding example in Zig
Diffstat (limited to 'zig-tlv-encoding/main.zig')
| -rw-r--r-- | zig-tlv-encoding/main.zig | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/zig-tlv-encoding/main.zig b/zig-tlv-encoding/main.zig new file mode 100644 index 0000000..d7e2809 --- /dev/null +++ b/zig-tlv-encoding/main.zig @@ -0,0 +1,97 @@ +// TLV format: https://devopedia.org/tlv-format +// Real world example: https://www.rfc-editor.org/rfc/rfc8609 +// Cool article: https://www.huy.rocks/everyday/12-11-2022-zig-using-zig-for-advent-of-code + +// Dummy TLV spec for encoding Linux devicei information +// +// Packet specification +// 1byte ... Tag +// 2bytes ... Length +// unknown ... Value +// +// Available tags: { 0x00 = vendor_name, 0x01 = model_name } +// Packet presented as a struct: Packet{ .vendor_name, .model_name } +// This assumes that the max value length can be 255. +// +// Test data from `lsusb` (`lscpu`): +// Bus 002 Device 003: ID 046d:086b Logitech, Inc. BRIO 4K Stream Edition +// Bus 001 Device 009: ID 3434:0350 Keychron Keychron V5 +// Bus 001 Device 006: ID 2433:b200 ASETEK [NZXT Kraken X60] +// Bus 001 Device 005: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver + +const std = @import("std"); + +const TLVTag = enum(u8) { + VENDOR_NAME = 0x00, + MODEL_NAME = 0x01, +}; + +const TLVPacket = struct { + tag: TLVTag, + length: u8, + value: std.ArrayList(u8), + + pub fn printEncoded(self: *TLVPacket) void { + std.debug.print("\t", .{}); + std.debug.print("{X:0>2}-", .{@intFromEnum(self.tag)}); + std.debug.print("{X:0>2}-", .{self.length}); + + for (self.value.items) |val| { + std.debug.print("{X:0>2}", .{val}); + } + + std.debug.print("\n", .{}); + } +}; + +const TLVPayload = struct { + packets: std.ArrayList(TLVPacket), + allocator: std.mem.Allocator, + + pub fn init(allocator: std.mem.Allocator) TLVPayload { + return TLVPayload{ + .packets = std.ArrayList(TLVPacket).init(allocator), + .allocator = allocator, + }; + } + + pub fn deinit(self: *TLVPayload) void { + for (self.packets.items) |*packet| { + packet.value.deinit(); + } + self.packets.deinit(); + } + + pub fn append(self: *TLVPayload, tag: TLVTag, message: []const u8) !void { + var value = try std.ArrayList(u8).initCapacity(self.allocator, message.len); + try value.appendSlice(message); + + try self.packets.append(.{ + .tag = tag, + .length = @intCast(message.len), + .value = value, + }); + } +}; + +test "Create TLV payload manually" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + + var payload = TLVPayload.init(gpa.allocator()); + defer payload.deinit(); + + try payload.append(.VENDOR_NAME, "Logitech, Inc."); + try payload.append(.MODEL_NAME, "BRIO 4K Stream Edition"); + + std.debug.print("Capacity: {d}\n", .{payload.packets.capacity}); + + for (payload.packets.items) |*packet| { + std.debug.print("Tag: {}, Length: {d}\n", .{ packet.tag, packet.length }); + packet.printEncoded(); + } +} + +pub fn main() void { + std.debug.print("Use `make test` or `zig test main.zig` instead.\n", .{}); +} |
