Went with a variant of this but used the init
method of the bounded array instead of modifying length directly (which provides an error on overflow).
var data = try std.BoundedArray(u8, data_max_size).init(data_length);
try reader.readNoEof(data.slice());
This was the full implementation:
pub const SDOServerNormal = struct {
mbx_header: MailboxHeader,
coe_header: CoEHeader,
sdo_header: SDOHeaderServer,
complete_size: u32,
data: std.BoundedArray(u8, data_max_size),
pub const data_max_size = max_mailbox_size - 16;
pub fn deserialize(buf: []const u8) !SDOServerNormal {
var fbs = std.io.fixedBufferStream(buf);
const reader = fbs.reader();
const mbx_header = try nic.packFromECatReader(MailboxHeader, reader);
const coe_header = try nic.packFromECatReader(CoEHeader, reader);
const sdo_header = try nic.packFromECatReader(SDOHeaderServer, reader);
const complete_size = try nic.packFromECatReader(u32, reader);
if (mbx_header.length < 10) {
return error.InvalidMbxHeaderLength;
}
const data_length: u16 = mbx_header.length -| 10;
var data = try std.BoundedArray(u8, data_max_size).init(data_length);
try reader.readNoEof(data.slice());
return SDOServerNormal{
.mbx_header = mbx_header,
.coe_header = coe_header,
.sdo_header = sdo_header,
.complete_size = complete_size,
.data = data,
};
}
pub fn serialize(self: *const SDOServerNormal, out: []u8) !usize {
var fbs = std.io.fixedBufferStream(out);
const writer = fbs.writer();
try nic.eCatFromPackToWriter(self.mbx_header, writer);
try nic.eCatFromPackToWriter(self.coe_header, writer);
try nic.eCatFromPackToWriter(self.sdo_header, writer);
try nic.eCatFromPackToWriter(self.complete_size, writer);
try writer.writeAll(self.data.slice());
return fbs.getWritten().len;
}
comptime {
assert(data_max_size == max_mailbox_size -
@divExact(@bitSizeOf(MailboxHeader), 8) -
@divExact(@bitSizeOf(CoEHeader), 8) -
@divExact(@bitSizeOf(SDOHeaderServer), 8) -
@divExact(@bitSizeOf(u32), 8));
}
};
test "serialize and deserialize sdo server normal" {
const expected = SDOServerNormal{
.mbx_header = .{
.length = 14, // 4 bytes of payload
.address = 0x0,
.channel = 0,
.priority = 0,
.type = .CoE,
.cnt = 2,
},
.coe_header = .{
.number = 0,
.service = .sdo_response,
},
.sdo_header = .{
.size_indicator = true,
.transfer_type = .normal,
.data_set_size = .four_octets,
.complete_access = false,
.command = .initiate_upload_response,
.index = 1234,
.subindex = 0,
},
.complete_size = 12345,
.data = try std.BoundedArray(u8, SDOServerNormal.data_max_size).fromSlice(&.{ 1, 2, 3, 4 }),
};
var bytes = std.mem.zeroes([max_mailbox_size]u8);
const byte_size = try expected.serialize(&bytes);
try std.testing.expectEqual(@as(usize, 6 + 2 + 12), byte_size);
const actual = try SDOServerNormal.deserialize(&bytes);
try std.testing.expectEqualDeep(expected, actual);
}