さて、1月ももう終わり。
USBカメラ+motionでは安定して動作できなかったRaspberryPi。
使い道を模索していたのだが、リビングに置いてあるLS-GLをPiに置き換えようかと。
さらにどうせなら外部スイッチでの動作もさせたい。
ウチはAQUOSなのだが、本体に電源ボタンが無い(リモコンの電源)。
出かける際(本体の電源をオフにしても良いのだが)にリモコンを探してオフする必要がある。
テレビ近くにタクトスイッチを用意しておけばこれで解決。
さらに入力切替が気に入らない。ボタンを何度も押さなくてはならない。
幸いAQUOSにはPCと繋げるためのRS-232Cがあるのでこれを利用しない手はない。
LS-GL+KURO-RSの学習リモコンでは解決できなかったこれら課題をクリアしよう、と。
まず、raspiのGPIOポートの内、3V3POWERとGround、TXDとRXDを用いて、AQUOSとの通信を可能とする。
3.3Vのレベルなので、RS-232Cとの接続のために手元にあったADM3202ANを使用。AQUOSとはクロス結線。
とりあえず、コマンドを送って電源オフなりが出きることを確認。1段階クリア。
次に、タクトスイッチの取り付け。これは当初プレステのコントローラでもGPIOに接続してやろうかと
思ったのだが、Arduinoでの実験は成功したものの、raspiでの接続例は探しきれず断念。
部材は揃えたのでいつかやってやろうと思う。
タクトスイッチは6個。左画像の下の方のピンを使用した。GPIO7,8,9,10,11,25。
これを3.3V、10kオームの抵抗でプルアップして使用した。
ソフトウェア部はC library for Broadcom BCM 2835 as used in Raspberry Pi を使用して作成。
以下ソース。
#include <stdio.h> #include <stdlib.h> #include <bcm2835.h> #include <signal.h> #include <string.h> #include <strings.h> #include <termios.h> #include <unistd.h> #include <fcntl.h> #include <stdarg.h> #include <unistd.h> #include <syslog.h> #include <errno.h> //スイッチのピン定義 #define SW1 RPI_V2_GPIO_P1_26 #define SW2 RPI_V2_GPIO_P1_24 #define SW3 RPI_V2_GPIO_P1_21 #define SW4 RPI_V2_GPIO_P1_19 #define SW5 RPI_V2_GPIO_P1_22 #define SW6 RPI_V2_GPIO_P1_23 //スイッチコマンド #define SW1_CMD "\rPOWR0000\r" //POWER OFF #define SW2_CMD "\rIAVD1 \r" //入力切り替え1 #define SW3_CMD "\rIAVD2 \r" // 2 #define SW4_CMD "\rIAVD3 \r" #define SW5_CMD "\rIAVD4 \r" #define SW6_CMD "\rIAVD5 \r" #define BAUDRATE B9600 /* 通信速度の設定 */ #define MODEMDEVICE "/dev/ttyAMA0" /* デバイスファイルの指定:COM1 */ #define FALSE 0 #define TRUE 1 #define MC 4 /* 読み込む文字数 */ volatile int STOP=FALSE; static void log_write(char *fmt, ...); // 割り込みコールバック関数 void signal_callback_handler(int signum) { //printf("\ndetect key interrupt\n",signum); log_write("detect interrupt",signum); bcm2835_close(); printf("stop daemon",0); exit(0); } //シリアルへのコマンド送信 int sendcmd(int cmdno) { int fd, c, res, i; /* fd:ファイルディスクリプタ res:受け取った文字数 */ struct termios oldtio, newtio; /* 通信ポートを制御するためのインターフェイス */ char buf[255]; /* 受信文字を格納 */ if((fd=open(MODEMDEVICE, O_RDWR | O_NOCTTY))== -1){ /* O_RDWR:読み書き両用 O_NOCTTY:tty制御をしない */ perror(MODEMDEVICE); return(-1); } tcgetattr(fd, &oldtio); /* 現在のシリアルポートの設定を退避させる */ bzero(&newtio, sizeof(newtio)); /* 新しいポートの設定の構造体をクリア */ newtio.c_cflag= (BAUDRATE | CS8 | CLOCAL | CREAD); /* CRTSCTS:フロー制御有り CS8:8ビット、ノンパリティ、ストップビット1 * CLOCAL:モデムの状態信号を無視 CREAD:受信可能にする */ newtio.c_iflag=IGNPAR; /* IGNPAR:パリティエラーの文字は無視 */ newtio.c_oflag=0; /* rawモード */ newtio.c_lflag=0; /* 非カノニカル入力 */ newtio.c_cc[VTIME]=0; /* キャラクタ間タイマは未使用 */ newtio.c_cc[VMIN]=MC; /* MC文字受け取るまでブロックする */ tcflush(fd,TCIFLUSH); /* ポートのクリア */ tcsetattr(fd, TCSANOW, &newtio); /* ポートの設定を有効にする */ char strbuf[20]; switch (cmdno){ case 1: strcpy(strbuf,SW1_CMD); break; case 2: strcpy(strbuf,SW2_CMD); break; case 3: strcpy(strbuf,SW3_CMD); break; case 4: strcpy(strbuf,SW4_CMD); break; case 5: strcpy(strbuf,SW5_CMD); break; case 6: strcpy(strbuf,SW6_CMD); break; default: strcpy(strbuf,"\rPOWR0000\r"); } //コマンド送信 write(fd,strbuf,sizeof(strbuf)); tcsetattr(fd, TCSANOW, &oldtio); /* 退避させた設定に戻す */ close(fd); /* COM1のシリアルポートを閉じる */ return(0); } static void become_daemon(void) { int n; if (chdir("/")<0) { log_write("chdir(2) failed: %s",strerror(errno)); exit(0); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); n = fork(); if (n<0) log_write("fork(2) failed: %s",strerror(errno)); if (n !=0) _exit(0); if (setsid() <0) { log_write("setsid(2) failed: %s",strerror(errno)); _exit(0); } log_write("start daemon",0); } int main(int argc, char **argv) { //デーモン化を試みる。 openlog("remoteaquos",LOG_PID|LOG_NDELAY,LOG_DAEMON); become_daemon(); if (!bcm2835_init()) return 1; bcm2835_gpio_fsel(SW1, BCM2835_GPIO_FSEL_INPT); bcm2835_gpio_fsel(SW2, BCM2835_GPIO_FSEL_INPT); bcm2835_gpio_fsel(SW3, BCM2835_GPIO_FSEL_INPT); bcm2835_gpio_fsel(SW4, BCM2835_GPIO_FSEL_INPT); bcm2835_gpio_fsel(SW5, BCM2835_GPIO_FSEL_INPT); bcm2835_gpio_fsel(SW6, BCM2835_GPIO_FSEL_INPT); // VCCまでプルアップする bcm2835_gpio_set_pud(SW1, BCM2835_GPIO_PUD_UP); bcm2835_gpio_set_pud(SW2, BCM2835_GPIO_PUD_UP); bcm2835_gpio_set_pud(SW3, BCM2835_GPIO_PUD_UP); bcm2835_gpio_set_pud(SW4, BCM2835_GPIO_PUD_UP); bcm2835_gpio_set_pud(SW5, BCM2835_GPIO_PUD_UP); bcm2835_gpio_set_pud(SW6, BCM2835_GPIO_PUD_UP); signal(SIGINT, signal_callback_handler); //printf("press ^C to exit program ...\n"); while (1) { uint8_t sw_val1 = bcm2835_gpio_lev(SW1); uint8_t sw_val2 = bcm2835_gpio_lev(SW2); uint8_t sw_val3 = bcm2835_gpio_lev(SW3); uint8_t sw_val4 = bcm2835_gpio_lev(SW4); uint8_t sw_val5 = bcm2835_gpio_lev(SW5); uint8_t sw_val6 = bcm2835_gpio_lev(SW6); uint8_t value = sw_val1 +sw_val2 +sw_val3 +sw_val4 +sw_val5 +sw_val6; if (value != 6) { //何らかのスイッチが押されている。 log_write("read from pin: %d %d %d %d %d %d\n", sw_val1,sw_val2,sw_val3,sw_val4,sw_val5,sw_val6,0); if(sw_val1 == 0 ) { sendcmd(1); } if(sw_val2 == 0 ) { sendcmd(2); } if(sw_val3 == 0 ) { sendcmd(3); } if(sw_val4 == 0 ) { sendcmd(4); } if(sw_val5 == 0 ) { sendcmd(5); } if(sw_val6 == 0 ) { sendcmd(6); } } delay(50); // 0.005秒待つ } } static void log_write(char *fmt, ...) { va_list ap; va_start(ap, fmt); vsyslog(LOG_ERR,fmt,ap); va_end(ap); } |
gcc -o remoteaquos -l bcm2835 -lrt remoteaquos.c /usr/local/lib/libbcm2835.a
一応、デーモン化してログに出力するようにしている。
これでタクトスイッチで電源OFFと入力切替が可能になった。