/**
 * @file i2c_subsystem.h
 *
 * \date 2012/09/01
 * @author: takemasa
 * @brief twiペリフェラルをマスターモードで使用する
 *
 */
#include <kernel.h>

#ifndef I2C_SUBSYSTEM_H_
#define I2C_SUBSYSTEM_H_

/**
 * \defgroup I2C_SUBSYSTEM  I2Cを使用するためのサブシステム
 * @details
 * i2c_subsystemは、LPC1768の内蔵I2Cペリフェラルを使用するための関数群である。この関数群はTOPPERS/ASP用に開発されており、CMSISの下位
 * ライブラリを使用して、割り込みを使ったポーリングなしの制御を実現している。タスクから呼び出された関数は割り込みハンドラとセマフォを使って
 * 通信しながら指定されたI2Cスレーブ・デバイスの制御を行う。また、関数群は排他制御されており、一つのi2Cペリフェラルを複数のタスクが同時に使用
 * しないよう保護されている。
 *
 * アプリケーションが使用するのは i2c_master_write(), i2c_master_read(), i2c_master_write_read() の三つの関数だけである。
 * この他にI2Cの初期化関数と割り込みISRがあるが、これらは TOPPERS/ASP のコンフィギュレーション・ファイルに記述されており、アプリケーション・
 * プログラマが直接呼び出してはならない。
 *
 * I2Cx ペリフェラルを使用する場合には、アプリケーションのコンフィギュレーションファイルから、i2cx_m.cfgファイルを読み込んでおく。
 * 例えば、I2C1を使いたいのであれば、i2c1_m.cfg ファイルを読み込む。i2c0_m.cfg から i2c2_m.cfg までのファイルがあり、
 * どのファイルをどの組み合わせでどの順番で読み込んでもかまわない。
 *
 * I2Cxペリフェラルの初期化は、cfgファイルによって記述されたイニシャライザが行う。また、割り込みISRもcfgファイルによって登録
 * される。このほか、ペリフェラル電源のオン、クロックの設定もイニシャライザ内部で完結している。
 *
 * I2Cxペリフェラルへのピンの割り当てが必要な場合は、アプリケーションで行う。
 *
 * なお、I2Cサブシステムは、イニシャライザ内部でCMSISの   SystemCoreClockUpdate() 関数を使用してCPUのクロック周波数を
 * 測定している。この関数が常に正しく動作するのはCPUが内部RCオシレータを使用する場合と、RTCの32768Hzクロックを使用する場合のみである。
 * 外部クリスタルを使ったメインオシレータを使用する場合は、クリスタルの共振周波数とCMSIS内部のクロック設定値をあわせてCMSISを再ビルド
 * しなければならない。
 */
/*@{*/

/**
 * @brief TWIデバイス制御関数への引き数値が間違っている。
 */
#define I2C_ERR_WRONGPARAM      0x40000
/**
 * @brief TWIデバイス制御関数へ指定した送受信データ長が長すぎる。
 */
#define I2C_ERR_TOOLONGBUFFER   0x20000
/**
 * @brief TWIデバイスがタイムアウトした。
 */
#define I2C_ERR_TIMEOUT     0x10000

extern void i2c_perror(UINT prio, const char *file, int line,
                    const char *expr, ER ercd) throw();

Inline ER
_i2c_perror(const char *file, int line, const char *expr, ER ercd)
{
    if (ercd < 0) {
        i2c_perror(LOG_ERROR, file, line, expr, ercd);
    }
    return(ercd);
}

#define i2ccall(s)  _t_perror(__FILE__, __LINE__, #s, (s))


/**
 * @brief i2cマスターモードの割り込みサービスルーチン
 * @details
 * この間数は、i2cをマスターモードとして使う際の割り込みサービスルーチン本体である。 i2c_master_read()等の関数と強調しながら
 * 動作する。データ転送が終わると、あらかじめ設定されたコールバックを呼び出してタスクに通知する。
 *
 * exinfには、コンフィギュレーションファイルのDEF_INHから値を与える
 */
void i2c0_master_handler(void);


/**
 * @brief i2cマスターモード動作用の初期化を行う
 * @param exinf ペリフェラル番号を渡す. TWI0なら0。
 * @details
 * この関数は i2c0_master_handler() が i2c_master_read() 等の関数と同期するためのセマフォの設定を行う。
 * 呼び出しは明示的に行わず、コンフィギュレーションファイルからATT_INIを使ってシステムに登録する。
 *
 */
void i2c_master_initialize(VP_INT exinf);


/**
 * @brief I2C マスター書き込み関数
 * @param peripheral マイコンのI2Cペリフェラルの番号。TWI0なら0
 * @param slave 7bitで表すI2Cペリフェラルの番号。bit0:6のみ使い、bit7以上は0にすること。
 * @param write_data ペリフェラルに書き込むデータ・バイト列
 * @param write_count ペリフェラルに書き込むデータの長さ。単位はバイト。最大254。
 * @return エラーがなければ0
 * @details
 * 引数 peripheral を使って、アドレス slave のI2Cデバイスに対する書き込みを行う関数。

 * この関数はブロッキング関数である。つまり、読み込みを開始すると、その終了まで待って
 * 帰ってくる。
 *
 * また、複数のタスクが同時にこの関数を呼んだ場合には、うち一つだけが関数を実行し、他のタスクは
 * 待ち状態になる。
 *
 * 返り値はTWI_ERROR_XXXXと、TWIペリフェラルの割り込みステータスのビット論理和である。
 * 正常終了ならオール0である。
 *
 */
int i2c_master_write( int peripheral, int slave, unsigned char write_data[], int write_count );

/**
 * @brief I2C マスター読み込み関数
 * @param peripheral マイコンのI2Cペリフェラルの番号。TWI0なら0
 * @param slave 7bitで表すI2Cペリフェラルの番号。bit0:6のみ使い、bit7以上は0にすること。
 * @param read_data ペリフェラルから読み込むデータ・バッファ
 * @param read_count ペリフェラルから読み込むデータの長さ。単位はバイト。最大254。
 * @return エラーがなければ0。処理がタイムアウトならば処理ステータス
 * @details
 * 引数 peripheral を使って、アドレス slave のI2Cデバイスからの読み込みを行う関数。

 * この関数はブロッキング関数である。つまり、読み込みを開始すると、その終了まで待って
 * 帰ってくる。
 *
 * また、複数のタスクが同時にこの関数を呼んだ場合には、うち一つだけが関数を実行し、他のタスクは
 * 待ち状態になる。
 *
 * 返り値はTWI_ERROR_XXXXと、TWIペリフェラルの割り込みステータスのビット論理和である。
 * 正常終了ならオール0である。
 *
 */
int i2c_master_read( int peripheral, int slave, unsigned char read_data[], int read_count);

/**
 * @brief I2C マスター書き込み読み込み関数
 * @param peripheral マイコンのI2Cペリフェラルの番号。TWI0なら0。
 * @param slave 7bitで表すI2Cペリフェラルの番号。bit0:6のみ使い、bit7以上は0にすること。
 * @param write_data ペリフェラルに書き込むデータ・バイト列
 * @param write_count ペリフェラルに書き込むデータの長さ。単位はバイト。最大254。
 * @param read_data ペリフェラルから読み込むデータ・バッファ
 * @param read_count ペリフェラルから読み込むデータの長さ。単位はバイト。最大254。
 * @return エラーがなければ0。
 * @details
 * 引数 peripheral を使って、アドレス slave のI2Cデバイスに対する書き込みを行う関数。
 *
 * この間数は、まず slave に対して write_data バッファから write_count 個のデータを
 * 書き込む。続いて I2C の repeated start を使って同じ slave に対する read_count個の
 * 読み出しを行う。
 *
 * この関数はブロッキング関数である。つまり、読み込みを開始すると、その終了まで待って
 * 帰ってくる。
 *
 * また、複数のタスクが同時にこの関数を呼んだ場合には、うち一つだけが関数を実行し、他のタスクは
 * 待ち状態になる。
 *
 * 返り値はTWI_ERROR_XXXXと、TWIペリフェラルの割り込みステータスのビット論理和である。
 * 正常終了ならオール0である。
 *
 */
int i2c_master_write_read( int peripheral, int slave, unsigned char write_data[], int write_count, unsigned char read_data[], int read_count );

/*@}*/

#endif /* I2C_SUBSYSTEM_H_ */
