diff --git a/src/libboard_artiq/src/drtioaux_proto.rs b/src/libboard_artiq/src/drtioaux_proto.rs index 62523d6..e2fee29 100644 --- a/src/libboard_artiq/src/drtioaux_proto.rs +++ b/src/libboard_artiq/src/drtioaux_proto.rs @@ -47,6 +47,7 @@ pub enum Packet { I2cReadRequest { destination: u8, busno: u8, ack: bool }, I2cReadReply { succeeded: bool, data: u8 }, I2cBasicReply { succeeded: bool }, + I2cSwitchSelectRequest { destination: u8, busno: u8, address: u8, mask: u8 }, SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, SpiWriteRequest { destination: u8, busno: u8, data: u32 }, @@ -152,6 +153,12 @@ impl Packet { 0x87 => Packet::I2cBasicReply { succeeded: reader.read_bool()? }, + 0x88 => Packet::I2cSwitchSelectRequest { + destination: reader.read_u8()?, + busno: reader.read_u8()?, + address: reader.read_u8()?, + mask: reader.read_u8()? + }, 0x90 => Packet::SpiSetConfigRequest { destination: reader.read_u8()?, @@ -301,6 +308,13 @@ impl Packet { writer.write_u8(0x87)?; writer.write_bool(succeeded)?; }, + Packet::I2cSwitchSelectRequest { destination, busno, address, mask } => { + writer.write_u8(0x88)?; + writer.write_u8(destination)?; + writer.write_u8(busno)?; + writer.write_u8(address)?; + writer.write_u8(mask)?; + }, Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { writer.write_u8(0x90)?; diff --git a/src/runtime/src/i2c.rs b/src/runtime/src/i2c.rs index b8c5bcf..de908f3 100644 --- a/src/runtime/src/i2c.rs +++ b/src/runtime/src/i2c.rs @@ -60,6 +60,29 @@ pub extern fn read(busno: i32, ack: bool) -> i32 { } } +pub extern fn switch_select(busno: i32, address: i32, mask: i32) { + if busno > 0 { + artiq_raise!("I2CError", "I2C bus could not be accessed"); + } + let ch = match mask { //decode from mainline, PCA9548-centric API + 0x00 => None, + 0x01 => Some(0), + 0x02 => Some(1), + 0x04 => Some(2), + 0x08 => Some(3), + 0x10 => Some(4), + 0x20 => Some(5), + 0x40 => Some(6), + 0x80 => Some(7), + _ => artiq_raise!("I2CError", "switch select supports only one channel") + }; + unsafe { + if (&mut I2C_BUS).as_mut().unwrap().pca954x_select(address as u8, ch).is_err() { + artiq_raise!("I2CError", "switch select failed"); + } + } +} + pub fn init() { let mut i2c = libboard_zynq::i2c::I2c::i2c0(); i2c.init().expect("I2C bus initialization failed"); diff --git a/src/runtime/src/kernel/api.rs b/src/runtime/src/kernel/api.rs index b05467a..1c55d3e 100644 --- a/src/runtime/src/kernel/api.rs +++ b/src/runtime/src/kernel/api.rs @@ -116,6 +116,7 @@ pub fn resolve(required: &[u8]) -> Option { api!(i2c_stop = i2c::stop), api!(i2c_write = i2c::write), api!(i2c_read = i2c::read), + api!(i2c_switch_select = i2c::switch_select), // Double-precision floating-point arithmetic helper functions // RTABI chapter 4.1.2, Table 2 diff --git a/src/satman/src/main.rs b/src/satman/src/main.rs index 69693a1..f8915d7 100644 --- a/src/satman/src/main.rs +++ b/src/satman/src/main.rs @@ -282,6 +282,23 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }) } } + drtioaux::Packet::I2cSwitchSelectRequest { destination: _destination, busno: _busno, address, mask } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); + ch = match mask { //decode from mainline, PCA9548-centric API + 0x00 => None, + 0x01 => Some(0), + 0x02 => Some(1), + 0x04 => Some(2), + 0x08 => Some(3), + 0x10 => Some(4), + 0x20 => Some(5), + 0x40 => Some(6), + 0x80 => Some(7), + _ => { return drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: false }); } + }; + let succeeded = i2c.pca954x_select(address, ch).is_ok(); + drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + } drtioaux::Packet::SpiSetConfigRequest { destination: _destination, busno: _busno, flags: _flags, length: _length, div: _div, cs: _cs } => {