rustserial-portraspberry-pi-zero

Why does using rppal's Uart to read a software-serial port on the Raspberry Pi not change the buffer?


I am trying to read a sensor off of a software serial port (ttySOFT0) on the Raspberry Pi. I am using soft_uart to get my serial interface.

The code is:

let mut port = Uart::with_path("/dev/ttySOFT0", 9_600, Parity::None, 8, 1).unwrap();
let mut buffer = [0u8; 9];
let command = [0xFFu8, 0x01u8, 0x86u8, 0, 0, 0, 0, 0, 0x79u8];
port.write(&command)
    .expect("Could not write to the serial port");
port.read(&mut buffer)
    .expect("Could not read from the serial port");
let mhz19_high = buffer[2] as u32;
let mhz19_low = buffer[3] as u32;
let reading = mhz19_high * 256u32 + mhz19_low;
println!("{:?}", buffer);

The return value of the port.write() function is 0 but I expected to write 9 bytes. With sudo I write 9 bytes, but the buffer stays [0, 0, 0, 0, 0, 0, 0, 0, 0].

This uses the rppal crate. I hadn't any luck with the serial or serial2 crates either.

There are no errors from the .expect(...). I am sure that there isn't a problem with the soft_uart driver as it works with sudo in Python:

ser = serial.Serial('/dev/ttySOFT0')
packet = bytearray()
packet.append(0xFF)
packet.append(0x01)
packet.append(0x86)
packet.append(0x00)
packet.append(0x00)
packet.append(0x00)
packet.append(0x00)
packet.append(0x00)
packet.append(0x79)
ser.write(packet)
res = ser.read(9)
reading_co2 = res[2]*256+res[3]

Solution

  • The documentation for Uart::read states (emphasis mine):

    read operates in one of four (non)blocking modes, depending on the settings configured by set_read_mode. By default, read is configured as non-blocking.

    The same applies to Uart::write / set_write_mode.

    Non-blocking means that if there is no data available, the call will return immediately with whatever data is available at that instant. Serial protocols are generally pretty slow compared to the rest of your computer, so this is a common occurrence.

    You will need to adapt your code to handle this. A simple solution is to use set_read_mode / set_write_mode to make the calls blocking.

    Another (better?) solution may involve retrying the read and write calls with delays until the buffer is sufficiently full.