//

*****************************************************************************************

// Program name : world_clock.c

// Description  : World_clock by Raspberry Pi Zero WH

// Author       : Yoshio Kato

// Start date   : 15th.Apr.2019

// Compile      : cc -o world_clock world_clock.c -l wiringPi

// Excution     : sudo ./world_clock

//*****************************************************************************************

#include <wiringPi.h>      //wiringPiヘッダーファイルをインクルード

#include <time.h>          //timeヘッダーファイルをインクルード

#include <stdio.h>         //stdioiヘッダーファイルをインクルード

#include <stdlib.h>        //stdlibヘッダーファイルをインクルード  "system"

char offset_time[20] = {9,1,2,2,10,-10,-5,-5,2,-3,8,2,2,-7,2,-4,3,-7,10,2} ;   //UTCとの差

//  0-9  London,Paris,Berlin,Sydney,Honolulu,Mexico City,NewYork,Cairo,Buenos Aires,

// 10-19 Ulaanbaatar,Oslo,Copenhagen,San Francisco,Zurich,Detroit, Nairobi, Vancouver,Melbourne, Roma

#define a   8    // a セグメント GPIO

#define b  14    // b セグメント GPIO

#define c  18    // c セグメント GPIO

#define d  23    // d セグメント GPIO

#define e  24    // e セグメント GPIO

#define f  25    // f セグメント GPIO

#define g  15    // g セグメント GPIO

#define shutdown_sw   26                    //シャットダウンスイッチのGPIO

#define add10_sw      11             //+10スイッチのGPIO

char digit_gpio[4] = {21,16,12,20} ;        //デジット選択 GPIO D1,D2,D3,D4

char thumbwheel_sw_gpio[4] = {2,3,4,17} ;   // サムホイールスィッチ GPIO

char segment[10][8] ={{a,b,c,d,e,f,0,0},    //0のセグメントデータ

                      {b,c,0,0,0,0,0,0},    //1のセグメントデータ

                      {a,b,d,e,g,0,0,0},    //2のセグメントデータ

                      {a,b,c,d,g,0,0,0},    //3のセグメントデータ

                      {b,c,f,g,0,0,0,0},    //4のセグメントデータ

                      {a,c,d,f,g,0,0,0},    //5のセグメントデータ

                      {a,c,d,e,f,g,0,0},    //6のセグメントデータ

                      {a,b,c,f,0,0,0,0},    //7のセグメントデータ

                      {a,b,c,d,e,f,g,0},    //8のセグメントデータ

                      {a,b,c,d,f,g,0,0}} ;  //9のセグメントデータ

time_t timer ;

struct tm *tim ;     //構造体の設定

 

//*****************************************************************************************

//  初期設定処理

//*****************************************************************************************

int init(){

     int i ;

     if(wiringPiSetupGpio() == -1)          //wiringPiの設定 戻り値が-1の時はエラー

          return(-1) ;                      //エラーリターン

     for(i=0; i<4; i++){                    //デジット、サムホイールスイッチのGPIO設定

          pinMode(digit_gpio[i],OUTPUT) ;                 //デジットのGPIOを出力

          pinMode(thumbwheel_sw_gpio[i],INPUT) ;          //サムホイールスイッチのGPIOを入力

          pullUpDnControl(thumbwheel_sw_gpio[i],PUD_UP) ; //サムホイールスイッチのGPIOをプルアップ

     }

     for(i=0; i<7;i++)

          pinMode(segment[8][i],OUTPUT) ;    //各セグメントのGPIOを出力

     pinMode(shutdown_sw,INPUT) ;            //シャットダウンスイッチのGPIOを入力

     pullUpDnControl(shutdown_sw,PUD_UP) ;   //シャットダウンスイッチのGPIOをプルアップ

     pinMode(add10_sw,INPUT) ;               //add10スイッチのGPIOを入力

     pullUpDnControl(add10_sw,PUD_UP) ;      //add10スイッチをプルアップ

     return(1) ;

}

 

//*****************************************************************************************

// サムホイールスイッチの読み込み

//*****************************************************************************************

int read_sw_value(){

     int i ;

     int data = 0 ;

     for(i=0 ;i<4; i++)               //サムホイールスイッチから4ビット読み込む

          data = (data << 1) | !(digitalRead(thumbwheel_sw_gpio[i])) ;

     if(digitalRead(add10_sw) == 0)   //add10_swがonならば10を加える

          data += 10 ;                //data=data + 10

     return(data) ;                   //読み込んだデータを返す

}

 

//*****************************************************************************************

//  7セグメント表示器を消去

//*****************************************************************************************

void erase_7seg_led(){

     int i ;

     for(i=0; i<7; i++)

          digitalWrite(segment[8][i],1) ;  //a~gセグメントを5V

     for(i=0; i<4; i++)

          digitalWrite(digit_gpio[i],0) ;  //デジット1~4を0V

}

 

//*****************************************************************************************

//  指定したデジットに数字を表示

//*****************************************************************************************

void display_data(char dgt, char time_data){

     int i =0 ;

     erase_7seg_led() ;                   //全ての表示を消去

     while(segment[time_data][i] != 0)    //数字を構成するデータが0出ない間繰り返す

          digitalWrite(segment[time_data][i++],0) ;  //対応するセグメントを0V

     digitalWrite(digit_gpio[dgt],1) ;    //指定したデジットを5V 数字が表示

     delay(4) ;                           //4ms時間をおく

}

 

//*****************************************************************************************

//  時と分の表示

//*****************************************************************************************

void display(){

     display_data(0,tim->tm_hour /10) ;       //時を10で割り商をデジット1へ表示

     display_data(1,tim->tm_hour %10) ;       //時を10で割り余りをデジット1へ表示

     display_data(2,tim->tm_min /10) ;        //分を10で割り商をデジット1へ表示

     display_data(3,tim->tm_min % 10) ;       //分を10で割り余りをデジット1へ表示 

}

 

//*****************************************************************************************

//  メイン

//*****************************************************************************************

int main(){

     char count = 60 ;                        //表示回数カウンター用

     char i ;                                 //UTCとの差分用

     if(init() == -1)                         //初期設定処理をコール

          return(-1) ;                        //初期設定処理でエラー発生ならば終了

     while(digitalRead(shutdown_sw) != 0){    //シャットダウンスイッチが押されていない間繰り返す

          if(count == 60){                    //60回(約1秒)表示したら時間を求める

               i = 24 + offset_time[read_sw_value()] ;  

                                              //サムホイールスイッチの値からUTCとの差を求める

               if(i >= 24)

                     i -= 24 ;                //その値が24より大きいときは24を引く

               time(&timer) ;

               tim = gmtime(&timer) ;             //現在時刻を求める

               tim->tm_hour = tim->tm_hour + i ;  //UTCとの差分で現地時刻にする

               if(tim->tm_hour >= 24)             //24を超えたら翌日なので24を引く

                    tim->tm_hour = tim->tm_hour -24 ;

               count = 0;

          }

          display() ;                       //表示処理をコール

          count++ ;                         //表示回数に1を加える

     }

     erase_7seg_led() ;                     //全ての表示を消去

     count = 0 ;

     while(digitalRead(shutdown_sw) == 0){  //shutdownスイッチがはなされるまでの間実行

          delay(100) ;                      //100msのdelay

          count ++ ;                        //100ms毎にcountをプラスする

     }

     if(count >= 30)                        //countが30(3秒)以上か

          system("sudo shutdown -h now") ;  //3秒以上なのでshutdownコマンドを実行し終了する

       else

          return(1) ;                       //shutdownではないのでOSへ戻る

}

 

//********************************** End of Program ******************************************