Function which will take multiple enums as parameters


#1

Hi, I’m trying to learn Rust and use it for embedded work.

I want to write a function which will take several generic parameters.
I have two problems:

  1. compiler won’t allow me to add something to the parameter, eg:
    let e = end + 1; will report:
    expected type parameter, found integral variable
    = note: expected type U
    found type {integer}

  2. Mixing enums with the problem mention above:
    write(reg, Register1Bits::DIVs, Register1Bits::DIVe, 0xBABA);
    write(reg, Register2Bits::Rs, Register2Bits::Re, 0xBABA);
    Now compiler will report:
    no implementation for Register1Bits + Register1Bits
    no implementation for Register2Bits + Register2Bits

So I need to (somehow) implement std::ops::Add for every enum I have.

What I’m trying to achive is this:
I have a struct for multiple HW memory mapped registers.
I have bits which are in that register in enums (which are called similiar to register, so there is bunch of these enums).
I want to create function which can write to all this registers (and will take enums as parameter, because it need to know where bit positions are)

How to achive that?

BTW, “+1” in code above is because (AFAIK):

  • Rust won’t allow enums members with same value (eg: Bit1End = 8, Bit2Stard = 8)
  • Range will not include the last number (eg: 0…8 will not include ‘8’)
    (there is ‘…’ but it’s experimental)

Is there a better way to do that?

Code:
https://is.gd/Ev2XV4


#2

I think that the bitflags crate may be better suited to your usecase:

https://docs.rs/bitflags/0.9.0/bitflags/index.html

The generated struct implements set operations like | and contains, and also allows for conversiosn to bits and from_bits.

edit: Could you explain what the write function is supposed to do? Trim the value to the range and then write? Or iterate? I don’t really get it.


#3

But with bitflags crate I can’t have the same “bits” in multiple register in mupltiple registers/structs/bitfields, eg:

bitflags!
{
	struct Register1: u32
	{
		const EN	= 1 << 0;
        }
}

bitflags!
{
	struct Register2: u32
	{
		const EN	= 8 << 0;
        }
}

I’m trying to write drivers for peripheral devices on bare metal MCU. For example, GPIO driver should look something like this:
https://is.gd/V443af
But I don’t know how to manage problems with gpio_write()

Also, is it possible to have read only bits? Something similar already exist, but for bytes or larger types (VolatileCell, RW, RO, WO).
How can I tell compiler to generate error when someone try to do something like this:

    gpio_write(gpioA.Reg2, Reg1::MODE, 0b11); // trying to write enum for Reg1 to Reg2

#4

You can use modules:

mod register1 {
    bitflags! {
        struct Type: u32 {
             const EN = 1 << 0;
        }
    }
}

I think you should define a single trait Register, instead of typing all those BitAnd in the gpio_write.

trait Register {
    type T: Copy + std::fmt::Debug + std::ops::BitAnd<Output=Self::T>;
    fn to_bits(&self) -> Self::T;
}

The type T should be “a backing storage type” for this register, eg. u32 or u16.
(If you assume that all registers are 32 bits, you don’t even need that T. But I guess some registers are 16 bits wide?)

Implement this on all your register types, and you can define your gpio_write as:

fn gpio_write<U: Register>(mut reg: RW<U::T>, mask: U, value: U)
{
	// this function should be able to write to any Gpio register (Reg1, Reg2, ...)
	let read = reg.read();
	let new = read & (value.to_bits() & mask.to_bits());
	reg.write(new);
}

This will error when using mask and value with different types.

Rust doesn’t really understand bits, but one solution I see is to have additional method on Register trait – write_mask, and then write_gpio can mask every write with that mask.

Also, I feel that a library that does the things you ask for already exists. There is a big thread about embedded development, you can try to find some links there or post some suggestions.


#5

Can you explain it a bit more?
I am a beginner in OO and Rust, this is the current state of the code
https://is.gd/LUUNpb

There was Zinc ioregs which seems to supported read only bits but the project is dead now.