2013/10/13

[rpi]画面に何か出してみよう (1)

Raspbian、というのが私が使っているOSの名称のようだ。
SSHが使えるのが便利だから、これを使っていくことにしよう。

「画面に何か出してみよう」と書いたものの、Raspbianが入ったSDカードを入れると、HDMIから文字が出力されるので、既に何かは出ていると思う。
終了~。

・・・では面白味がないので、自分の意思で何か出してみることにする。


きっと、画面出力用に何かライブラリがあると思うが、ここは基本に返ってフレームバッファを使うことにする。

私の認識では、フレームバッファってのはVRAMみたいなもので、ここにデータを書くとOSというかドライバが上手に画面へ転送してくれるというものだ。

では、試しに。

$ ls /dev/fb*
/dev/fb0

フレームバッファは/dev/fb0みたいだ。
ここに何か転送してみる。
/etc/bash.bashrcというファイルがあるので、これを使おう。

$ cat /etc/bash.bashrc

これをたたくと、コンソールに文字がずらずら出たと思う。
では、これをフレームバッファに出力してみよう。

$ cat /etc/bash.bashrc > /dev/fb0

画面の左上に、ゴミが表示されたんじゃないかと思う。
bash.bashrcの中身がフレームバッファに書き込まれたので、それをドライバが出力してくれたのだ。

bash.bashrcはテキストファイルだけれども、それはテキストかどうかを人間が決めただけであって、コンピュータからすると「データが入ったファイル」に過ぎない。
だから、ゴミっぽいものが表示されるのだ。

じゃあ、画像ファイルならよいかというと、そうでもない。
「/usr/share/lxde/wallpapers/lxde_green.jpg」というファイルがあると思うので、それで試してみよう。

$ cat /usr/share/lxde/wallpapers/lxde_green.jpg > /dev/fb0

ゴミの量が増えたと思う。
画像ファイルも、所詮は取り決めた形式で収められたデータに過ぎず、コンピュータからすると「データが入ったファイル」なのだ。


じゃあどうしたら思い通りに表示できるかというと、コンピュータが期待する形式でデータを出力すればよい。

画面にゴミが出ていると思うので、一度クリアしておこう。

$ clear

では、もう一度bash.bashrcをコンソールに出力してみよう。

$ cat /etc/bash.bashrc

画面に文字がずらずら出たことだろう。
では、今度はフレームバッファの内容をファイルに保存してみよう。

$ cat /dev/fb0 > screenshot.raw
$ ls -l screenshot.raw
-rw-r--r-- 1 pi pi 3548160 Oct 13 01:16 screenshot.raw

うちだとこんな感じになったが、ファイルサイズは人によって違うと思う。
では、もう一度画面をクリア。

$ clear

そして、さっきのファイルをフレームバッファに出力。

$ cat screenshot.raw > /dev/fb0

bash.bashrcの出力などが画面に表示されたんじゃないかと思う。
フレームバッファの出力していた内容をファイルに保存し、それをもう一度出力し直したから当然と言えば当然なのだが、そういうことなのだ。

もうちょっとだけ実践をしておこう。

$ fbset
mode "1680x1050"
    geometry 1680 1050 1680 1050 16
    timings 0 0 0 0 0 0 0
    rgba 5/11,6/5,5/0,0/16
endmode

これがうちの画面サイズだ。
では、さっきのscreenshot.rawファイルサイズ(3548160byte)を考えていこう。
きっと、画面サイズの定数倍になってるはずだ。

3548160 / 1680 = 2112

・・・ならんやん。
私の予想では、さっきのfbsetの結果に「16」って出てるから、1ピクセルが16bit=2byteなんだろうと思ったのだ。
だから、1680 x 1050 x 2、になるはずだったのだ。
うーん。


調べてみよう。
Raspberry Piのいいところは、セルフコンパイルができるところだな。
調査にはもってこいだ。

fbtest.c

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FB      "/dev/fb0"
#define WIDTH   (1680)
#define PP      (2)
int main(int argc, const char *argv[])
{
        int fb;
        int loop;
        const data[] = { 0xff };
        fb  = open(FB, O_RDWR);
        if(fb == -1) {
                perror("cannot open fb.");
                return -1;
        }
        for(loop = 0; loop < WIDTH * PP; loop++) {
                write(fb, data, 1);
        }
        return 0;
}

$ gcc -o fbtest fbtest.c
$ ./fbtest

うん、画面の一番上に、白い線がぴーっと1ラインだけ引かれた。
何をするプログラムだったかというと、0xFFというデータを 1680x2バイト分フレームバッファに書き込むものだったのだ。
もし1ピクセルが2バイト以上であれば、線は右端まで届かずに終わっただろうし、横幅が1680ピクセルじゃなかったら、はみ出して次の行に表示されるなり短いなりしただろう。

じゃあ、次。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FB      "/dev/fb0"
#define WIDTH   (1680)
#define HEIGHT  (1050)
#define PP      (2)
int main(int argc, const char *argv[])
{
        int fb;
        int loop;
        const data[] = { 0xff };
        const empty[] = { 0x00 };
        fb  = open(FB, O_RDWR);
        if(fb == -1) {
                perror("cannot open fb.");
                return -1;
        }
/*
        for(loop = 0; loop < WIDTH * PP; loop++) {
                write(fb, data, 1);
        }
*/
        for(loop = 0; loop < HEIGHT; loop++) {
                int loop2;
                for(loop2 = 0; loop2 < PP; loop2++) {
                        write(fb, data, 1);
                }
                lseek(fb, (WIDTH - 1) * PP, SEEK_CUR);
        }
        return 0;
}

左端に白い線が出たと思う。
2byteだけ0xFFを書き、(横幅-1) x 2byteだけスキップ、という動作を高さ分だけ繰り返すプログラムだ。
これはこれで、間違っていなさそうだ。

 

つまり、/dev/fb0で保存したサイズが実画面よりも大きい、ということでいいのかな。
横幅は変わらなさそうだから、

3548160 / 1680 / 2 = 1056

つまり、実画面は1050ピクセルだが、保存は1056ピクセル分行っている、ということか。
あるいは何か別の用途で使ってるメモリなのか。

まあ、あまり気にしないでおこう。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。