# \`IOStream\` buffering pitfalls when communicating to a device file

**URL:** <https://discourse.julialang.org/t/iostream-buffering-pitfalls-when-communicating-to-a-device-file/130071>\
**Category:** Maker\
**Tags:** ccall, raspberry-pi, io, i2c\
**Created:** [June 20, 2025, 7:22pm UTC](https://discourse.julialang.org/t/iostream-buffering-pitfalls-when-communicating-to-a-device-file/130071 "2025-06-20T19:22:20Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Yuan-Ru-Lin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuan-ru-lin/32/46068_2.png) [@Yuan-Ru-Lin](https://discourse.julialang.org/u/Yuan-Ru-Lin)\
**Post date:** [June 20, 2025, 7:22pm UTC](https://discourse.julialang.org/t/iostream-buffering-pitfalls-when-communicating-to-a-device-file/130071/1 "2025-06-20T19:22:20Z")

</div>

I was talking to an ADS1115 ADC over I²C via `/dev/i2c-1` on a Raspberry Pi 4.

My first attempt was using high-level `IOStream` APIs like `write(io, bytes)` and `read(io, n)`, and it worked but only for the first value. Every value afterward is somehow saturated i.e. they’re all `0xFFFF`.

```julia
const I2C_SLAVE::UInt16 = 0x0703
const ADS1115_ADDRESS::UInt8 = 0x48
const ADS1115_CONFIG_REG::UInt8 = 0x01
const ADS1115_CONVERSION_REG::UInt8 = 0x00

io = open("/dev/i2c-1", "r+")
_fd = fd(io)
ccall((:ioctl, "libc.so.6"), Cint, (Cint, Culong, Cint), _fd, I2C_SLAVE, ADS1115_ADDRESS)

write(io, UInt8[ADS1115_CONFIG_REG, 0b10100010, 0b00000011])
flush(io)
sleep(0.01)

write(io, UInt8[ADS1115_CONVERSION_REG])
flush(io)

while true
    data = read(io, 2)
    value = reinterpret(Int16, data[end:-1:begin])
    println(value)
    sleep(0.2)
end

# results:
# 
# 7328 (a random meaningful value)
# -1
# -1
# -1
# ...

```

I resolved the problem by `ccall`ing the low-level `read` in libc instead; that is, I modified the loop to be

```julia
data = Array{UInt8}(undef, 2)
while true
    ccall((:read, "libc.so.6"), Cint, (Cint, Ptr{UInt8}, Csize_t), _fd, v, nbuf)
    value = reinterpret(Int16, data[end:-1:begin])
    println(value)
    sleep(0.2)
end

# results:
# 
# 7328
# 7329
# 7328
# ...

```

I suspect that it’s because `IOStream` is buffered but lack relevant knowledge to dig deeper. I prefer sticking to high-level APIs as much as possible so I wonder if anyone can tweak the first example to make it work.

P.S. I tried `unsafe_read` but ended up with no luck.

---

<div class="post-metadata">

**Author:** ![stene](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stene/32/26044_2.png) [@stene](https://discourse.julialang.org/u/stene)\
**Post date:** [August 4, 2025, 9:26pm UTC](https://discourse.julialang.org/t/iostream-buffering-pitfalls-when-communicating-to-a-device-file/130071/2 "2025-08-04T21:26:32Z")

</div>

It’s much easier to use [GitHub - stensmo/WiringPi.jl: WiringPi in Julia](https://github.com/stensmo/WiringPi.jl)
