樹莓派做遙控豆瓣播放器(1)

Step 1, 紅外設置

樹莓派B+的紅外設置網上很多,簡單來說就是通過ssh連接到樹莓派之後,進行執行以下命令:“apt-get install lirc”. 如果一切順利,那麼這個時候可以參照之前的博客,樹莓派 紅外接收 RPi2 gpio chip not found lirc_rpi。如果和我一樣不幸遇到無法檢測到紅外設備的情況,也可以參照之前的博客進行troubleshooting。
當你成功錄製按鍵之後,接下來需要的是配置lircrc, 目錄是在/etc/lirc/lircrc 。這個文件的目的就是讓紅外lirc後臺程序運行時候,接收到每個按鍵會觸發什麼行爲。這個配置文件的編寫佔據了比較大的effort。現附上我的配置文件,再進行詳細解釋。

begin
    prog = irexec
    button = stop
    repeat = 2
    delay = 2
    config = /root/douban_fm/fifowrite.exe q
end

begin
    prog = irexec
    button = mute
    config = /root/douban_fm/fifowrite.exe m
end

begin
    prog = irexec
    button = next
    config = /root/douban_fm/fifowrite.exe n
end

begin
    prog = irexec
    button = pause
    config = /root/douban_fm/fifowrite.exe p
end

begin
    prog = irexec
    button = volume_up
    config = /root/douban_fm/fifowrite.exe o
end

begin
    prog = irexec
    button = volume_down
    config = /root/douban_fm/fifowrite.exe i
end

begin
    prog = irexec
    button = power
    repeat = 2 
    delay = 2 
    config = sudo sh /root/douban_fm/start_douban.sh
end

在這個配置文件中,比較重要的有三個部分:

1)fifowrite.exe

這個文件是用來和播放豆瓣的主程序進行通信的程序。將command寫入一個pipe文件中,然後播放主程序再通過一個fiforead.exe 程序進行讀取。涉及到的按鍵就是音量增,音量減,暫停,切歌,靜音以及退出。

fiforead.c

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>

int main()
{
    const char *fifo_name = "/root/douban_fm/my_fifo";
    int pipe_fd = -1;
    int data_fd = -1;
    int res = 0;
    const int open_mode = O_RDONLY;
    char buffer[2];
    int bytes_read = 0;
    int bytes_write = 0;

    memset(buffer, '\0', sizeof(buffer));

//    printf("Process %d opening FIFO O_RDINLY\n", getpid());
    pipe_fd = open(fifo_name, open_mode);
//    data_fd = open("DataFormFIFO.txt", O_WRONLY|O_CREAT, 0644);
//    printf("Process %d result %d\n", getpid(), pipe_fd);

    if(pipe_fd != -1)
    {
        do
        {
            res = read(pipe_fd, buffer, 1);
            if(res <= 0)
                break;
            printf("%s\n", buffer);
//            bytes_write = write(data_fd, buffer, res);
            bytes_read += res;
        }while(res > 0);
        close(pipe_fd);
//        close(data_fd);
    }
    else
        exit(EXIT_FAILURE);

//    printf("Process %d finished, %d bytes read\n", getpid(), bytes_read);
    exit(EXIT_SUCCESS);
}

fifowrite.c

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char* argv[])
{
    const char *fifo_name = "/root/douban_fm/my_fifo";
    int pipe_fd = -1;
    int data_fd = -1;
    int res = 0;
    const int open_mode = O_WRONLY;
    int bytes_sent = 0;
    char buffer[2];

    if(access(fifo_name, F_OK)==-1)
    {
        //PIPE file not exist
        //Create it
        res = mkfifo(fifo_name, 0777);
        if(res != 0)
        {
            fprintf(stderr, "Could not creat fifo %s\n", fifo_name);
            exit(EXIT_FAILURE);
        }
    }

//    printf("Process %d opening FIFO O_WRONLY\n", getpid());

    pipe_fd = open(fifo_name, open_mode);
//    data_fd = open("Data.txt", O_RDONLY);
//    printf("Process %d result %d\n", getpid(), pipe_fd);
    if(pipe_fd != -1)
    {
//        int bytes_read = 0;
//        bytes_read = read(data_fd, buffer, PIPE_BUF);
        buffer[0] = *argv[1];
        buffer[1] = '\0';
        res = write(pipe_fd, buffer, 1);
/*        while(bytes_read > 0)
        {
            res = write(pipe_fd, buffer, bytes_read);
            if(res == -1)
            {
                fprintf(stderr, "Write err on pipe\n");
                exit(EXIT_FAILURE);
            }
            bytes_sent +=res;
            bytes_read = read(data_fd, buffer, PIPE_BUF);
            buffer[bytes_read] = '\0';
        }*/
        close(pipe_fd);
//        close(data_fd);
    }
    else
        exit(EXIT_FAILURE);

//    printf("Process %d finished\n", getpid());
    exit(EXIT_SUCCESS);
}

把這兩段代碼在樹莓派中分別創建兩個.c 文件之後,執行命令:
gcc -o ./fifowrite.exe fifowrite.c -lm
gcc -o ./fiforead.exe fiforead.c -lm
這樣控制程序的命令就可以通過這段文件共享了。

2)start_douban.sh

這段shell做的工作就是在起進程之前先檢查系統中是否已經有播放程序在執行了。如果沒有就把程序起起來,如果有就退出。

#!/bin/bash

num=`ps aux|grep /root/douban_fm/play_douban.py|grep -v "grep"|wc -l`
if test $num -eq 0 ; 
then
    aplay /usr/share/scratch/Media/Sounds/Effects/Bubbles.wav 
    nohup /root/douban_fm/play_douban.py >> /root/mlog/douban_fm.log &
else
    exit
fi

在實際過程中遇到的問題是有可能遇到連擊或者紅外信號的連續發送導致在同一時間起了多個這樣的腳本,還是會導致多個播放程序在後臺啓動。一開始的解決方案是在shell中生成隨機數,讓其sleep幾秒鐘,由於sleep時間是隨機的,也就可以保證同時起的shell都會啓動播放程序。可參見Linux 實現隨機數多種方法。本人親測通過時間的方法獲取隨機數不成。之後的方法也沒有進行嘗試。這個問題究其根本就是紅外讀取信號的時候會在短時間內重複獲取信號。
這就是配置文件中第三部分要注意的。

3) repeat = 2 delay = 2

repeat 和delay的含義可以參見官方文檔lircrc 配置文件詳解
repeat
告訴程序如果key重複按鍵之後應該做什麼,如果設置成2 就是連按兩下會出發什麼動作。當默認是0的時候就會忽略重複按鍵。

好了,現在基本的外圍設置已經完成。接下來就是需要進行豆瓣播放程序的開發。詳見下一篇

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章