/* ****************************************************************************
* PIC to Pi ユーティリティー
*
* Raspberry Pi GPIO access ルーチン
*
* [pi_gpio.h]
* [pi_gpio.c]
*
*   (gcc -c pi_gpio.c -o gpio.o)
*
*  void mode_set_3208(void);                    MCP3208で使用するpinのモードset
*  set_adc_channel(ch);                                 adc_channelをselectする
*
*  (uint32_t)data = read_adc_mcp3208(void);selectされたchから読み込む(12bit)
*
*                                                        2013.2.9 shellvalley
*******************************************************************************
関数名
<注意>
1. [wiringPiSetup()]をmaink関数で実行すること
2. pin番号はwiringPi-pin番号であり、PaspberryPiのgpioPin番号ではない

<gpioモードset>
        pinMode(pin,INPUT);                                     指定pinを入力モードにする
        pinMode(pin,OUTPUT);                                    指定pinを出力モードにする
         例:pinMode(GPIO7,OUTPUT);
//      mode_set_3208();                                        MCP3208で使用するpinのモードset

<gpio入出力関数>
        output_bit(pin,bit);                                    指定pinに0 or 1を出力する
        output_high(pin);                                       指定pinに1を出力する
        output_low(pin)                                         指定pinに0を出力する
                例:output_bit(GPIO7,data);

        input_bit(pin);
                例:input_bit(MISO);

<A-D変換関数 IC:MCP3208に対するspi制御>
        set_adc_channel(ch);                                    adc_channelをselectする
        (uint32_t)data = read_adc_mcp3208(void);selectされたchから読み込む(12bit)

########【pin番号とRaspberryPiのpinとの対応】###################################
        +-----------------------+-----------------------+------------------------------+
        |     RaspberryPi       |     w iringPi         |                              |
        |      pin番号          |     pin番号           |       Name                   |
        |     (ハード)        |    (ソフト)          |                              |
        +-----------------------+-----------------------+------------------------------+
        |       1               |       -               |       3.3V                   |
        |       2               |       -               |       5v                     |
        |       3               |       8               |       SDA                    |
        |       4               |       -               |       (DNC)                  |
        |       5               |       9               |       SCL                    |
        |       6               |       -               |       0v:GND                 |
        |       7               |       7               |       GPIO7                  |
        |       8               |       15              |       TxD                    |
        |       9               |       -               |       (DNC)                  |
        |       10              |       16              |       RxD                    |
        |       11              |       0               |       GPIO0                  |
        |       12              |       1               |       GPIO1                  |
        |       13              |       2               |       GPIO2                  |
        |       14              |       -               |       (DNC)                  |
        |       15              |       3               |       GPIO3                  |
        |       16              |       4               |       GPIO4                  |
        |       17              |       -               |       (DNC)                  |
        |       18              |       5               |       GPIO5                  |
        |       19              |       12              |       MOSI(MasterOutSleveIn) |
        |       20              |       -               |       (DNC)                  |
        |       21              |       13              |       MISO(MasterInSleveOut) |
        |       22              |       6               |       GPIO6                  |
        |       23              |       14              |       SCLK                   |
        |       24              |       10              |       CE0                    |
        |       25              |       -               |       (DNC)                  |
        |       26              |       11              |       CE1                    |
        +-----------------------+-----------------------+------------------------------+
######## A-Dコンバータ MCP3204/3208 (SPI 接続) ################################

        ・デバイスとの通信を開始するにはCS ラインをLow にする。
        ・CS ピンがLow の時にデバイスの電源が入れられた場合、通信を開始するには
         High にしてからLow に戻すことが必要。
        ・CS Low とDIN High で受け取る最初のクロックは開始ビットを形成。
        ・SGL/DIFF ビットが開始ビットに続き、シングルエンドまたは差動入力モードを
         使って変換を行うかどうかを決める。
        ・3つのビット(D0、D1、D2) は、入力チャンネル構成を選択するのに使われる。
        ・デバイスは、開始ビットを受け取った後、クロックの4 番目の上昇部で
         アナログ入力のサンプリングを開始する。
        ・サンプリング期間は開始ビットに続く5番目のクロックの下降部で終了する。

        +-----------+---+---+---+---------------+-----------------------+
        |制御bit選択|   |   |   | 入力構成      |    チャンネル選択     |
        |SINGLE/DIFF|D2 |D1 |D0 |               |                       |
        +-----------+---+---+---+---------------+-----------------------+
        |       1   |0  |0  |0  |シングルエンド |CH0                    |
        |       1   |0  |0  |1  |シングルエンド |CH1                    |
        |       1   |0  |1  |0  |シングルエンド |CH2                    |
        |       1   |0  |1  |1  |シングルエンド |CH3                    |
        |       1   |1  |0  |0  |シングルエンド |CH4                    |
        |       1   |1  |0  |1  |シングルエンド |CH5                    |
        |       1   |1  |1  |0  |シングルエンド |CH6                    |
        |       1   |1  |1  |1  |シングルエンド |CH7                    |
        |       0   |0  |0  |0  |差動           |CH0 = IN+   CH1 = IN-  |
        |       0   |0  |0  |1  |差動           |CH0 = IN    CH1 = IN+  |
        |       0   |0  |1  |0  |差動           |CH2 = IN+   CH3 = IN-  |
        |       0   |0  |1  |1  |差動           |CH2 = IN    CH3 = IN+  |
        |       0   |1  |0  |0  |差動           |CH4 = IN+   CH5 = IN-  |
        |       0   |1  |0  |1  |差動           |CH4 = IN    CH5 = IN+  |
        |       0   |1  |1  |0  |差動           |CH6 = IN+   CH7 = IN-  |
        |       0   |1  |1  |1  |差動           |CH6 = IN    CH7 = IN+  |
        +-----------+---+---+---+---------------+-----------------------+

###############################################################################
*/
// ############################################################################
// ############################################################################
//[pi_gpio.h]
// ############################################################################
// ############################################################################
#define SDA0    8       // rsp board pin:03(SDA0) pull-upされている
#define SCL0    9       // rsp board pin:05(SCL0) pull-upされている
#define GPIO7   7       // rsp board pin:07(GPIO7)
#define TXD     15      // rsp board pin:08(TxD)
#define RXD     16      // rsp board pin:10(RxD)
#define GPIO0   0       // rsp board pin:11(GPIO0)
#define GPIO1   1       // rsp board pin:12(GPIO1)
#define GPIO2   2       // rsp board pin:13(GPIO2)
#define GPIO3   3       // rsp board pin:15(GPIO3)
#define GPIO4   4       // rsp board pin:16(GPIO4)
#define GPIO5   5       // rsp board pin:18(GPIO5)
#define MOSI    12      // rsp board pin:19(MOSI)
#define MISO    13      // rsp board pin:21(MISO)
#define GPIO6   6       // rsp board pin:22(GPIO6)
#define SCLK    14      // rsp board pin:23(SCLK)
#define CE0     10      // rsp board pin:24(CE0)
#define CE1     11      // rsp board pin:26(CE1)

#define pin_03  8       // rsp board pin:03
#define pin_05  9       // rsp board pin:05
#define pin_07  7       // rsp board pin:07
#define pin_08  15      // rsp board pin:08
#define pin_10  16      // rsp board pin:10
#define pin_11  0       // rsp board pin:11
#define pin_12  1       // rsp board pin:12
#define pin_13  2       // rsp board pin:13
#define pin_15  3       // rsp board pin:15
#define pin_16  4       // rsp board pin:16
#define pin_18  5       // rsp board pin:18
#define pin_19  12      // rsp board pin:19
#define pin_21  13      // rsp board pin:21
#define pin_22  6       // rsp board pin:22
#define pin_23  14      // rsp board pin:23
#define pin_24  10      // rsp board pin:24
#define pin_26  11      // rsp board pin:26
// ###########################################################################
// ### RaspberryPI <-> PIC ccsc compiler #####################################
// ###########################################################################
#define output_bit(pin,bit)     digitalWrite(pin,bit)
#define output_high(pin)        digitalWrite(pin,1)
#define output_low(pin)         digitalWrite(pin,0)
#define input_bit(pin)          digitalRead(pin)
#define Wait_time               500
#define set_adc_channel(ch)     MCP3208_adc_ch=ch;

static uint8_t MCP3208_adc_ch=ch;

// ######## MCP3208 A-Dコンバータで使用 ######################################
#define spi_clk_1       output_bit(SCLK,1);usleep(Wait_time);
#define spi_clk_0       output_bit(SCLK,0);usleep(Wait_time);

// ###########################################################################
// ###########################################################################
//[pi_gpio.c]
// ###########################################################################
// ###########################################################################
//
// ######## include file #####################################################
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>

#include "pi_gpio.h"

// ######## MCP3208 A-Dコンバータで使用 ######################################
#define spi_clk_1       output_bit(SCLK,1);usleep(Wait_time);
#define spi_clk_0       output_bit(SCLK,0);usleep(Wait_time);
// ######## MCP3208 A-Dコンバータで使用 ######################################
static  uint8_t MCP3208_adc_ch;
static uint32_t SPI_IN_work[11];
static uint8_t  SPI_d2,SPI_d1,SPI_d0;        // spi contorol data
// ###########################################################################
static uint32_t read_adc_3208(void);
static void spi_data_input(uint8_t);

/*
static void mode_set_3208(void);
// ###########################################################################
void mode_set_3208(void){
    pinMode(MOSI , OUTPUT);        // rsp board pin:19(MOSI)SPI-MasterOutSleveIn
    pinMode(MISO , INPUT);         // rsp board pin:21(MISO)SPI-MasterInSleveOut
    pinMode(SCLK , OUTPUT);        // rsp board pin:23(SCLK)SPI-CLK
    pinMode(CE0  , OUTPUT);        // rsp board pin:24(CE0)SPI-CS
}
*/

// ###########################################################################
// #####AD変換データ12bit read #############################################
void spi_data_input(uint8_t no){
int16_t i;
    SPI_IN_work[no] = 0;
    for(i = 0 ; i < 11 ; i++){
        spi_clk_1;
        spi_clk_0;
        SPI_IN_work[no] |= input_bit(MISO);
        SPI_IN_work[no] <<= 1;                          // B11 read
    }
    SPI_IN_work[no] |= input_bit(MISO);
    usleep(Wait_time);
}
// ###########################################################################
int compare_int(const void *a, const void *b){
    return *(int*)b - *(int*)a;
}
// ###########################################################################
// ###########################################################################
// 6回read => sort => topと2番目の差が0x20以下なら1番目を返すを返す
// 6回でもNGならばretryの2回目をとっておき、5回retryしてもNGならば、sortして1番目を返す
// ###########################################################################
uint32_t read_adc_mcp3208(void){
    uint32_t        i,j,work[10];
    int16_t         retry = 5;
    if((MCP3208_adc_ch & 0x04)!=0)SPI_d2 = 1;
    else SPI_d2 = 0;
    if((MCP3208_adc_ch & 0x02)!=0)SPI_d1 = 1;
    else SPI_d1 = 0;
    if((MCP3208_adc_ch & 0x01)!=0)SPI_d0 = 1;
    else SPI_d0 = 0;

    while(1){
        for(i = 0 ; i < 6 ; i++){               // test
            output_bit(CE0  ,0);                   // CE0 : 1
            output_bit(MOSI ,1);                   // シングルエンド モード
            usleep(Wait_time);
            usleep(Wait_time);
            spi_clk_1;
            if(SPI_d2 != 0) output_bit(MOSI ,1);    // adc ch d2
            else            output_bit(MOSI ,0);    // adc ch d2
            spi_clk_0;
            spi_clk_1;
            spi_clk_0;
            spi_clk_1;
            if(SPI_d1 != 0) output_bit(MOSI ,1);    // adc ch d1
            else            output_bit(MOSI ,0);    // adc ch d1
            spi_clk_0;
            spi_clk_1;
            if(SPI_d0 != 0) output_bit(MOSI ,1);    // adc ch d0
            else            output_bit(MOSI ,0);    // adc ch d0
            spi_clk_0;
            spi_clk_1;
            output_bit(MOSI ,0);
            spi_clk_0;
            usleep(Wait_time);                      // A to D start
            usleep(Wait_time); 
            spi_clk_1;
            spi_clk_0;
            spi_clk_1;
            spi_clk_0;
            spi_data_input(i);                      // data input
            spi_clk_1;
            output_bit(CE0  ,1);                    // CE0 : 1
            spi_clk_0;
            usleep(Wait_time);
            usleep(Wait_time);
            usleep(Wait_time);
            usleep(Wait_time);
      }
      qsort(SPI_IN_work,6,sizeof(uint32_t),compare_int);
      j = SPI_IN_work[0] - SPI_IN_work[1];
//    j = SPI_IN_work[1] - SPI_IN_work[2];
      if(j < 0x20)return(SPI_IN_work[0]);
//    if(j < 0x20)return(SPI_IN_work[1]);
      if(retry < 0){
          qsort(work,5,sizeof(uint32_t),compare_int);
          return(work[1]);                           // 2番目を返す
      }
      else{
          work[retry] = SPI_IN_work[1];              // 2番目をとっておく
          --retry;
      }
   }
}
// ############################################################################