WiringPi を使わない I2C 送信

# はじめに
「[Raspberry Pi から Arduino へ I2C でデータを送る](https://qiita.com/iigura/items/034ef2fcf12bdb57fd63)」では WiringPiI2C を使用していましたが、本稿では pigpio を用いて I2C 経由でデータ送信をしてみます。

# I2C 関連の関数
基本的な使い方は以下の通りです：

0. gpioInitialize でラズパイの GPIO ライブラリを初期化します。
1. i2cOpen で対象アドレスへの通信路を確保し、
2. i2cWriteI2CBlockData で任意のバイト数からなるデータを送信し、
3. 必要であれば、再度 i2cWriteI2cBlockData でデータを送信し、
4. 全て送信完了となったら i2cClose で通信路を閉じる

各関数の使い方を以下に示します。

## gpioInitialize
引数は特にありませんので、gpioInitialize() で呼び出します。
正常に初期化されれば 0 以上の値が返ります。負の値が返ってきたら初期化に失敗しています。

## i2cOpen
pigpio.h でのプロトタイプ宣言は以下の通りです：

    int i2cOpen(unsigned i2cBuf,unsigned i2cAddr,unsigned i2cFlags);

i2cBuf には 1 を指定します（/dev/i2c-1 をつかうので）。
i2cAddr はデータを送信したい I2C デバイスに割り振られているアドレスです。
最後の i2cFlags ですが、特に現時点では何かフラグが用意されているわけではないので 0 を指定します。

エラーが発生しなければ 0 以上の値が帰ってきます。この戻り値はハンドルとして次の i2cWriteI2CBlockData() で使用されるので適当な変数に確保しておきましょう。

## i2cWriteI2CBlockData
pigpio.h でのプロトタイプ宣言は以下の通りです：

    int i2cWriteI2CBlockData(unsigned handle,unsigned i2cReg,char *buf, unsigned count);

第 1 引数の handle には i2cOpen の戻り値を与えます。i2cReg には I2C デバイスのレジスタ番号を、buf にはデータが格納されているデータバッファへのポインタ、count は送信するバイト数です。レジスタ 0x12 に 0xCA 0xFE 0xBA 0xBE の 4 バイトを送信するならば、

    char buf[4]={0xCA, 0xFE, 0xBA, 0xBE};
    i2cWriteI2CBlockData(handle,0x12,buf,4);

となります。

## i2cClose
プログラムの終了など、もうこれ以上、該当アドレスの I2C デバイスへデータを送信する必要がなくなったら通信路を閉じます。pigpio.h でのプロトタイプ宣言は、

    int i2cClose(unsigned handle);

で、引数には i2cOpen の戻り値として得られたハンドルを指定します。

## その他使用上の注意
ラズパイから、例えば I2C デバイス化した Arduino に送信する場合、休み無しで連続に送信すると、i2cWriteI2CBlockData() が送信失敗を報告することがあります。この場合は、wiringPi で用意されている delay 関数などを用いて、一息おいてからデータを送信する必要があります。

# ビルドに必要なライブラリについて
上記の関数を使用する場合、pigpio の他に pthread が必要となります。そのため、

    g++ ソースファイル名.cpp -lpigpio -lpthread

とすれば a.out が生成されます。

# これらの関数の使用例
以上の説明で使い方は分かると思いますが、念のため使用例として i2c-write というプログラムを示しておきます。これは、

    Usage: i2c-write i2cBus address reg data1 data2 ... dataN

というもので、i2cBus （ラズパイの場合は 1 を指定して /dev/i2c-1 ）を指定し、続いてターゲットの I2C デバイスに割り振られているアドレス、レジスタ値を 16 進数で指定し、その後任意の個数の 16 進数を 2 桁づつ書けば、それらのデータを I2C で送信するものです。

I2C 関連の pigpio ライブラリの参考例だけでなく、インスタレーション製作時のちょっとしたテストにも使用できるのではないかと思っています。

```C++:i2c-write.cpp
// g++ i2c-write.cpp -lpigpio -lpthread -o i2c-write

#include <stdio.h>
#include <pigpio.h>

int main(int argc,char *argv[]) {
    if(gpioInitialise()<0) {
        fprintf(stderr,"ERROR: can not initialize pigpio.\n");
        return -1;
    }
    if(argc<5) {
        fprintf(stderr,"Usage: i2c-write i2cBus address reg data1 data2 ... dataN\n");
        fprintf(stderr,"ex) send 0xCA 0xFE 0xDE 0xAD 0xBE 0xEF "
                       "to 0x04's register 0x12 via /dev/i2c-1.\n");
        fprintf(stderr,"    i2c-write 1 04 12 CA FE DE AD BE EF\n");
        return -1;
    }
    int device;
    sscanf(argv[1],"%d",&device);
    printf("device=/dev/i2c-%d\n",device);

    int i2cAddr;
    sscanf(argv[2],"%02x",&i2cAddr);
    printf("address=0x%02X (=%d)\n",i2cAddr,i2cAddr);

    int reg;
    sscanf(argv[3],"%02x",&reg);
    printf("register=0x%02X (=%d)\n",reg,reg);

    const int numOfBuf=argc-4;
    char buf[numOfBuf];
    printf("data to send: ");
    for(int i=4,j=0; i<argc; i++,j++) {
        int t;
        sscanf(argv[i],"%02x",&t);
        buf[j]=(unsigned char)t;
        printf("%02X ",t);
    }
    printf("\n");

    // Open
    int handle=i2cOpen(device,i2cAddr,0);
    if(handle<0) {
        fprintf(stderr,"ERROR: can not open I2C.\n");
        return -1;
    }

    // Send
    int result=i2cWriteI2CBlockData(handle,reg,buf,numOfBuf);
    if(result) {
        fprintf(stderr,"ERROR: can not send data.\n");
        fprintf(stderr,"result=%d\n");
        switch(result) {
            case PI_BAD_HANDLE: fprintf(stderr,"BAD HANDLE\n"); break;
            case PI_BAD_PARAM:  fprintf(stderr,"BAD PARAM\n");  break;
            case PI_I2C_WRITE_FAILED:
                fprintf(stderr,"WRITE FAILED\n");   break;
            default:    fprintf(stderr,"UNKNOWN\n");
        }
        return -1;
    }

    // Close
    if(i2cClose(handle)) {
        fprintf(stderr,"ERROR: can not close I2C.\n");
        return -1;
    }
    return 0;
}
```

# まとめ
本文書では、pigpio.h にて宣言されている I2C 関連の関数を紹介し、その使用方法についても解説しました。また、ビルド時に必要なライブラリや、これらの関数を用いたサンプルプログラム i2c-write についてもプログラムリストを掲載しました。

いつものように勘違いや当方の不勉強による間違いなどがありましたら、ご指摘いただければ幸いです。