I’m implementing part of the CANopen protocol.
As part of the protocol you can transfer data of a size from 1 to 4 bytes.
pub const DataSetSize = enum(u2) {
four_octets = 0x00,
three_octets = 0x01,
two_octets = 0x02,
one_octet = 0x03,
};
pub const SDOClientExpedited = packed struct(u128) {
sdo_header: SDOHeaderClient,
data: u32,
pub fn downloadInitiate(
index: u16,
subindex: u8,
data: std.BoundedArray(u8, 4),
) !SDOClientExpedited {
if (data.len == 0) {
return error.InvalidParameterDataEmpty;
}
const size: DataSetSize = blk: {
if (data.len == 1) {
break :blk DataSetSize.one_octet;
} else if (data.len == 2) {
break :blk DataSetSize.two_octets;
} else if (data.len == 3) {
break :blk DataSetSize.three_octets;
} else if (data.len == 4) {
break :blk DataSetSize.four_octets;
}
};
// data is not guaranteed to be zeroed
var data_buf = std.mem.zeroes([4]u8);
@memcpy(data_buf[0..data.len], data.slice());
return SDOClientExpedited{
.sdo_header = .{
.size_indicator = true,
.transfer_type = .expedited,
.data_set_size = size,
.command = .initiate_download_request,
.index = index,
.subindex = subindex,
},
.data = @bitCast(data_buf),
};
}
};
How do I fix the following issues I have with the above code:
- The function returns an error, but I think this can be expressed without errors.
Some constraints:
- I want to use a packed struct to assist serialization of this binary protocol. This means the data field of the struct cannot be an array.
- I want to provide this function because I want to express constraints on the possible combinations of values for the fields of the header. The header need to be setup correctly and I don’t want to remember details about these fields when using this struct later.