Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to fill fields from left-to-right instead #88

Open
kamakazikamikaze opened this issue Nov 6, 2023 · 2 comments
Open

Add ability to fill fields from left-to-right instead #88

kamakazikamikaze opened this issue Nov 6, 2023 · 2 comments

Comments

@kamakazikamikaze
Copy link

According to the first comment of #7, fields are filled right-to-left.

This causes issues when instantiating a struct that must read data starting from the left.

For example, reading a Command Word from MIL-STD-1553 follows:

Address Transmit Sub-address Words
Bit range 0 - 4 5 6 - 10 11 - 15

Creating a representative struct with the help of bilge:

#[bitsize(16)]
#[derive(FromBits, DebugBits, PartialEq)]
struct Command {
    address: u5,
    transmit: bool,
    subaddress: u5,
    words: u5,
}

We can initialize the fields in proper order manually:

let cmd1: Command = Command::new(u5::new(5), true, u5::new(7), u5::new(3));
assert_eq!(u5::new(5), cmd1.address());
assert_eq!(true, cmd1.transmit());
assert_eq!(u5::new(7), cmd1.subaddress());
assert_eq!(u5::new(3), cmd1.words());

However, when reading the data from a stream in native ordering from the bus, the equivalent to the above would be 0b00101_1_00111_00011. Attempting to use this directly does not yield the desired result:

let cmd2: Command = Command::from(u16::new(0b00101_1_00111_00011));
assert_eq!(cmd1, cmd2);
thread 'test_command' panicked at 'assertion failed: `(left == right)`
  left: `Command { address: 5, transmit: true, subaddress: 7, words: 3 }`,
 right: `Command { address: 3, transmit: true, subaddress: 19, words: 5 }`'

Obviously the right-to-left parsing causes the mix-up. However fixing it client-side isn't quite straightforward. It's not a matter of endianness:

Address Transmit Sub-address Words Hex
Expected 00101 1 00111 00011 2C E3
Received 00011 1 10011 00101 1E 65

Swapping bytes (2CE3 -> E32C) would yield a drastically different result:

let cmd3: Command = Command::from(u16::from_be(0b00101_1_00111_00011));
assert_eq!(cmd1, cmd3);
thread 'test_command' panicked at 'assertion failed: `(left == right)`
  left: `Command { address: 5, transmit: true, subaddress: 7, words: 3 }`,
 right: `Command { address: 12, transmit: true, subaddress: 12, words: 28 }`'

We would instead need to pre-format data so that bilge can handle it:

let original: u16 = u16::new(0b00101_1_00111_00011);
let fixed: u16 = 
      (original & 0b11111) << 11
    | ((original & 0b11111_00000) >> 5) << 6
    | ((original & 0b1_00000_00000) >> 10) << 5
    | ((original & 0b11111_0_00000_00000) >> 11);
let cmd4: Command = Command::from(fixed);
assert_eq!(cmd1, cmd4);

This does not scale well as more structs are defined. Additionally, casting the struct to an integer is done right-to-left as well:

assert_eq!(original, cmd1);
thread 'test_command' panicked at 'assertion failed: `(left == right)`
  left: `11491`,
 right: `6629`',
Address Transmit Sub-address Words Hex
Expected 00101 1 00111 00011 2C E3
Received 00011 0 01111 00101 19 E5

Much of these issues could be resolved if there was an option to instead fill fields left-to-right. Perhaps something like #[derive(FromBitsLeftmost)]

@hecatia-elegua
Copy link
Owner

Thank you for the detailed writeup. Someone else wanted to switch the order too, since specs usually start with the top bits.
I just checked, and reversing the field definition works.
Can you try if that works and gives you valid values?

@vhdirk
Copy link

vhdirk commented Nov 21, 2023

A while back, I did something similar yet far more invasive. The idea was that any field could be regarded as either big or little endian. I have a protocol where both the order of the fields can change as well as the endianness of integers...

I started implementing this as a fork of modular-bitfield https://github.com/vhdirk/modular-bitfield, though I can't remember what state I left it in. Perhaps this could serve as inspiration?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants