0

I have some code originally written in Python that I'm trying to convert to C#. It will be running on Linux.

The Python code, however, opens a file and then sends some Linux specific ioctl commands to the open file.

class i2c(object):
   def __init__(self, device, bus):
      self.fr = io.open("/dev/i2c-"+str(bus), "rb", buffering=0)
      self.fw = io.open("/dev/i2c-"+str(bus), "wb", buffering=0)
      # set device address
      fcntl.ioctl(self.fr, I2C_SLAVE, device)
      fcntl.ioctl(self.fw, I2C_SLAVE, device)
   def write(self, bytes):
      self.fw.write(bytes)
   def read(self, bytes):
      return self.fr.read(bytes)
   def close(self):
      self.fw.close()
      self.fr.close()

I do not know, with C#, how to deal with both an open file and also send ioctl commands to said file. I assume I'd open the file for reading and writing using a normal FileStream. So far all I have is the declaration for using the C standard library like so:

public class IoCtl
{
    [DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
    private static extern int Command(int descriptor, UInt32 request, IntPtr data);

    // Equivalent of fcntl.ioctl()?

    // Write?

    // Read?

    // What happens with disposing the file? Do I need to write a destructor?
}

So I have two questions:

  • How do I correctly implement file access with ioctl using C#?
  • What is the procedure for closing/disposing of said file that is using ioctl? Still the usual using statement?
user9993
  • 5,833
  • 11
  • 56
  • 117

1 Answers1

2

Mono provides access to ioctl, native file descriptors, locks, etc.. via the Mono.Unix.Native namespace, add a reference to the Mono.Posix assembly to access it.

I am shooting from memory here, so you might (will) need to fill out the implementation if you want to use Syscall.fcntl, Syscall.read, Syscall.write:

*nixy way of doing it:

class i2c
{
    const int I2C_SLAVE = 0x0703;
    const int I2C_SLAVE_FORCE = 0x0706;

    int fd_write;
    int fd_read;
    string i2c_bus_file;

    public i2c (int device, String bus)
    {
        i2c_bus_file = String.Format ("/dev/i2c-{0}", bus);
        fd_write = Syscall.open (i2c_bus_file, OpenFlags.O_WRONLY, FilePermissions.DEFFILEMODE);
        // need to check Syscall.GetLastError()
        fd_read = Syscall.open (i2c_bus_file, OpenFlags.O_RDONLY, FilePermissions.DEFFILEMODE);
        // need to check Syscall.GetLastError()

        // I2C_SLAVE or I2C_SLAVE_FORCE if already in use...
        Syscall.fcntl (fd_read, I2C_SLAVE, device);
        // need to check Syscall.GetLastError()
        Syscall.fcntl (fd_write, I2C_SLAVE, device);
        // need to check Syscall.GetLastError()
    }

    public Errno write (byte[] data)
    {
        Syscall.write (fd_write, data, data.Length); 
        return Syscall.GetLastError ();
    }

    public Errno read (ref byte[] data)
    {
        Syscall.read (fd_read, data, data.Length);
        return Syscall.GetLastError ();
    }

    public void close ()
    {
        Syscall.close (fd_write);
        Syscall.close (fd_read);
    }
}

C#-ish way, is that a thing? ;-)

    public FileStream getI2CStream(byte address, String bus)
    {
        var i2c_bus_file = String.Format ("/dev/i2c-{0}", bus);
        FileStream result = File.Open(i2c_bus_file, FileMode.Open);
        Syscall.fcntl(result.SafeFileHandle.DangerousGetHandle().ToInt32(), address);
        return result;
    }
SushiHangover
  • 73,120
  • 10
  • 106
  • 165