Skip to content

Instantly share code, notes, and snippets.

@PhilOwen
Last active January 7, 2017 14:46
Show Gist options
  • Save PhilOwen/1c6a9090875c6b51c8c8e862b1aa9e15 to your computer and use it in GitHub Desktop.
Save PhilOwen/1c6a9090875c6b51c8c8e862b1aa9e15 to your computer and use it in GitHub Desktop.
Cは古いが役に立つ(C#編)

Raspberry Pi 2のI2Cデバイスを、C#から使ってみる。
C標準のopenread/writeといった低レベル関数を、 DllImportすることでC#から使えるようにしている。 こういうとき、C#だとCとの相互運用性が 意外と考えられていて、なかなか役に立つ。

DllImportでは、Cの関数に整数などのプリミティブはもちろん、 プリミティブの配列や文字列やポインタも渡して戻せる。 構造体も、多少手間がかかるがやりとりできる。 (ただし、ポインタを使うときは、unsafeキーワードが必要。 ちょっと特殊なので注意)

また、Cのヘッダ内の定数などはC#に自動で取り込んでくれないので、 自分で調べてC#コードに直打ちした。 RasPiのlibcの型とC#の型の対応も、 自力で調べればわかる。

  • Cのunsigned char -> C#のbyteByte
  • Cのint -> C#のint(Int32)
  • Cのunsigned long -> C#のuint(UInt32)

.Net FrameworkはWindows向けなので、 Raspbianでは使えないが、代わりにMonoが使える。 コンパイラのコマンドはmcs。

aptitude install mono-mcs
mcs I2CController.cs I2CReader.cs
./I2CController.exe

で実行できる。

using System;
class I2CController {
static void Main() {
string i2cFilename = "/dev/i2c-1";
int i2cAddress = 0x68;
try
{
var reader = I2CReader.Open(i2cFilename, i2cAddress);
byte x = reader.GetDataAt(0x80);
Console.WriteLine(x);
}
catch (Exception e) {
Console.WriteLine(e);
}
}
}
using System.IO;
using System.Runtime.InteropServices;
class I2CReader {
const string LIBC = "libc.so.6";
[DllImport(LIBC)]
extern static int open(string pathname, int flag);
[DllImport(LIBC)]
extern static int ioctl(int fd, uint request, int arg);
[DllImport(LIBC)]
extern static int write(int file, byte[] buffer, int count);
[DllImport(LIBC)]
extern static int read(int file, byte[] buffer, int length);
const int O_RDWR = 2;
const int I2C_SLAVE = 1795;
private readonly int file;
public static I2CReader Open(string pathname, int i2cAddress)
{
int fd = open(pathname, O_RDWR);
if (fd < 0)
throw new IOException("open failed: " + fd.ToString());
int iRet = ioctl(fd, I2C_SLAVE, i2cAddress);
if (iRet < 0)
throw new IOException("ioclt failed: " + iRet.ToString());
return new I2CReader(fd);
}
public byte GetDataAt(byte address)
{
byte[] buff = { address };
int wRet = write(file, buff, buff.Length);
if (wRet != buff.Length)
throw new IOException("write failed: " + wRet.ToString());
int rRet = read(file, buff, buff.Length);
if (rRet != buff.Length)
throw new IOException("read failed: " + rRet.ToString());
return buff[0];
}
private I2CReader(int file)
{
this.file = file;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment