pinewell's farmer blog 農業と電子工作、ソフトウェア、バイク、車

2013年1月28日

RaspberryPiのリモコン化

Filed under: 副業,未分類 — pinewell @ 11:15 AM

さて、1月ももう終わり。
USBカメラ+motionでは安定して動作できなかったRaspberryPi。
使い道を模索していたのだが、リビングに置いてあるLS-GLをPiに置き換えようかと。
さらにどうせなら外部スイッチでの動作もさせたい。
ウチはAQUOSなのだが、本体に電源ボタンが無い(リモコンの電源)。
出かける際(本体の電源をオフにしても良いのだが)にリモコンを探してオフする必要がある。
テレビ近くにタクトスイッチを用意しておけばこれで解決。
さらに入力切替が気に入らない。ボタンを何度も押さなくてはならない。
幸いAQUOSにはPCと繋げるためのRS-232Cがあるのでこれを利用しない手はない。
LS-GL+KURO-RSの学習リモコンでは解決できなかったこれら課題をクリアしよう、と。

GPIOピンまず、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と入力切替が可能になった。

コメントはまだありません »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress