9/10/2012

Let's Androidプログラミング

久々にブログ書いてみます。

いろいろあって、体調ぶち壊れて暫く冬眠してましたが、這い上がりぎみです。
最近はAndroidプログラミングに片足突っ込んでます。やってみるとなかなか面白いですなあ。

さしあたってOpenGLの立方体を傾きセンサーで傾かせるとか、ピンチイン、ピンチアウトで拡大縮小してグニグニ動くプログラム作ってみました。ちょっとかわええので、Youtubeにアップしました。



まだ、入門して一ヶ月と経ってないですが、これくらいのことは比較的簡単にできてしまうAndroid恐るべし。
豊富なセンサーやタッチ、カメラやマイクとかの入力を組み合わせれば、なんか面白いことができる予感するね。これ。

今回は実験的に行き当たりばったりで作ったので、ソースはぐちゃぐちゃなので、恥ずかしく載せませんが、またなんか面白いのできたらアップするかもしれません(未定)。


12/27/2011

Linux ハードウェア デバッグコマンド その2

昨日は力尽きたので、今日投稿するっす。
先週に引き続き、Linuxでユーザーランドからの物理メモリの読み書きコマンドです。
mmapを使って仮想メモリ経由で読み書きするようにしてみました。

例によってソースを晒しておきます。


/*
 * mem.c
 * ver.0.1:  Dec 26, 2011  S.Ishihara
 */


#include <stdio.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>




#define DEV_PATH "/dev/mem"


int
main(int argc, char *argv[])
{
    int             opt;
    extern char     *optarg;
    extern int      optind, opterr;
    int             width = 1;  /* default byte access */
    unsigned int    memaddr, wdata;
    unsigned int    pgoffset, pgaddr;
    unsigned int    pagesize = sysconf(_SC_PAGESIZE);
    unsigned char   *p;
    int             fd;


    while ((opt = getopt(argc, argv, "w:")) != -1) {
        if (opt == 'w') {
            width = atoi(optarg);
        } else {
            goto error;
        }
    }


    argc -= optind;
    argv += optind;


    fd = open(DEV_PATH, O_RDWR);
    if (fd <= 0) {
        fprintf(stderr, "open error: %s\n", DEV_PATH);
        return 1;
    }


    if (argc == 1) {
        /* Read Mem */
        memaddr  = strtoul(argv[0], NULL, 16);
        pgoffset = memaddr & (pagesize -1);
        pgaddr   = memaddr & ~(pagesize -1);
        p = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, pgaddr);
        if (p < 0) {
            fprintf(stderr, "mmap error\n");
            return 1;
        }
        if (width == 1) {
            printf("0x%08x: 0x%02x\n", memaddr, *(p + pgoffset));
        } else if (width == 2) {
            printf("0x%08x: 0x%04x\n", memaddr, *((unsigned short *)(p + pgoffset)));
        } else if (width == 4) {
            printf("0x%08x: 0x%08x\n", memaddr, *((unsigned int *)(p + pgoffset)));
        } else {
            goto error;
        }
    } else if (argc == 2) {
        /* Write Mem */
        memaddr  = strtoul(argv[0], NULL, 16);
        pgoffset = memaddr & (pagesize -1);
        pgaddr   = memaddr & ~(pagesize -1);
        p = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, fd, pgaddr);
        if (p < 0) {
            fprintf(stderr, "mmap error\n");
            return 1;
        }
        wdata  = strtoul(argv[1], NULL, 16);
        if (width == 1) {
            *(p + pgoffset) = (unsigned char)wdata;
        } else if(width == 2) {
            *((unsigned short *)(p + pgoffset)) = (unsigned short)wdata;
        } else if(width == 4) {
            *((unsigned int *)(p + pgoffset)) = (unsigned int)wdata;
        } else {
            goto error;
        }
    } else {
        goto error;
    }
    munmap(p, pagesize);
    close(fd);
    return 0;


error:
    printf("Usage: Mem [-w WIDTH] ADDRESS [DATA]\n"
            "Mem read or write.\n"
            "  -w        number of byte width. permit 1(default), 2, 4\n"
            "\n"
            "This command executable only root user.\n"
            "Mem address possible range 32bit.\n"
            "\n"
            "Examples:\n"
            "  Mem a0000               Read memory from address 0xa0000.\n"
            "  Mem a0000 31            Write memory address 0xa0000 to 0x31.\n"
            "  Mem -w4 20000 5a5a5a5a  Write memory address 0x20000 to 0x5a5a5a5a.\n"
            "\n");
    return 1;
}


試行錯誤しながら、ごそっと書いたので、冗長だったり、手抜きな部分もありますが、ぼちぼち動作するので、とりあえずよしとします。
目的としては、PCIデバイスのMMIOを直接読み書きしたいわけなんですが、あんまし真面目に動作確認できてないっす。使いながら確認してみます。

12/19/2011

Linux ハードウェア デバッグコマンド その1

今日は、Tx50の開発はお休みして、表題の件にちょっと時間を割くことにしました。

なんというか、本業のほうで、やっかいなデバッグをやることになりまして、
Linuxからハードウェアの状態を手軽に知る術が欲しくなって、コマンド作ることにしました。本業では結果を出すのに追われて、なかなか腰を据えてこういった開発補助ツールを作ることに時間が割けないわけです。

ユーザーランドからハードウェアに直接アクセスすることは、なにかと問題があったりで、本来ドライバを作るべきですが、開発段階でハードウェアの状態をちょっと確認したいというときは、さくっとコマンドで済ませたいところです。

というわけで、今回はユーザーランドから直接I/OとPCIのコンフィグレーション空間を読み書きできるコマンドを作成します。ホントは物理メモリとPCI Expressの拡張コンフィグレーション空間の読み書きコマンドも作りたかったんですが、時間が足りなかったので、それはまた今度にします。

で、おもむろにソースです。たぶん組み込み開発でLinux使ったプロジェクトのハード屋さんには、需要があるんじゃなかろうかと思いソースを晒しときます。(自分が会社からソースをゲットする目的もありますが)


/*
 * io.c
 * ver.0.1:  Dec 18, 2011  S.Ishihara
 */


#include <stdio.h>
#include <unistd.h>
#include <sys/io.h>


int
main(int argc, char *argv[])
{
    int             opt;
    extern char     *optarg;
    extern int      optind, opterr;
    int             width = 1;  /* default byte access */
    unsigned short  ioaddr;
    unsigned int    wdata;


    while ((opt = getopt(argc, argv, "w:")) != -1) {
        if (opt == 'w') {
            width = atoi(optarg);
        } else {
            goto error;
        }
    }


    argc -= optind;
    argv += optind;


    iopl(3);


    if (argc == 1) {
        /* Read I/O */
        ioaddr = strtoul(argv[0], NULL, 16);
        if (width == 1) {
            printf("0x%04x: 0x%02x\n", ioaddr, inb(ioaddr));
        } else if (width == 2) {
            printf("0x%04x: 0x%04x\n", ioaddr, inw(ioaddr));
        } else if (width == 4) {
            printf("0x%04x: 0x%08x\n", ioaddr, inl(ioaddr));
        } else {
            goto error;
        }
    } else if (argc == 2) {
        /* Write I/O */
        ioaddr = strtoul(argv[0], NULL, 16);
        wdata  = strtoul(argv[1], NULL, 16);
        if (width == 1) {
            outb(wdata, ioaddr);
        } else if(width == 2) {
            outw(wdata, ioaddr);
        } else if(width == 4) {
            outl(wdata, ioaddr);
        } else {
            goto error;
        }
    } else {
        goto error;
    }
    return 0;


error:
    printf("Usage: io [-w WIDTH] ADDRESS [DATA]\n"
            "I/O read or write.\n"
            "  -w        number of byte width. permit 1(default), 2, 4\n"
            "\n"
            "This command executable only root user.\n"
            "I/O address possible range 16bit.\n"
            "\n"
            "Examples:\n"
            "  io 3f8               Read I/O from address 0x3f8.\n"
            "  io 3f8 0x31          Write I/O address 0x3f8 to 0x31.\n"
            "  io -w4 cf8 80000000  Write I/O address 0xcf8 to 0x80000000 double word.\n"
            "\n");
    return 1;
}





/*
 * pci.c
 * ver.0.1:  Dec 18, 2011  S.Ishihara
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/io.h>

#define PCI_INDEX 0xcf8
#define PCI_DATA  0xcfc

unsigned char
pciRead8(unsigned char bus, unsigned char dev, unsigned char fnc, unsigned char reg)
{
    outl((1 << 31) + (bus << 16) + ((dev & 0x1f) << 11) +\
            ((fnc & 0x07) << 8) + (reg & ~(0x03)), PCI_INDEX);
    return inb(PCI_DATA + (reg & 0x03));
}

unsigned short
pciRead16(unsigned char bus, unsigned char dev, unsigned char fnc, unsigned char reg)
{
    outl((1 << 31) + (bus << 16) + ((dev & 0x1f) << 11) +\
            ((fnc & 0x07) << 8) + (reg & ~(0x03)), PCI_INDEX);
    return inw(PCI_DATA + (reg & 0x02));
}

unsigned int
pciRead32(unsigned char bus, unsigned char dev, unsigned char fnc, unsigned char reg)
{
    outl((1 << 31) + (bus << 16) + ((dev & 0x1f) << 11) +\
            ((fnc & 0x07) << 8) + (reg & ~(0x03)), PCI_INDEX);
    return inl(PCI_DATA);
}

void
pciWrite8(unsigned char bus, unsigned char dev, unsigned char fnc, unsigned char reg, unsigned char value)
{
    outl((1 << 31) + (bus << 16) + ((dev & 0x1f) << 11) +\
            ((fnc & 0x07) << 8) + (reg & ~(0x03)), PCI_INDEX);
    outb(value, PCI_DATA + (reg & 0x03));
}

void
pciWrite16(unsigned char bus, unsigned char dev, unsigned char fnc, unsigned char reg, unsigned short value)
{
    outl((1 << 31) + (bus << 16) + ((dev & 0x1f) << 11) +\
            ((fnc & 0x07) << 8) + (reg & ~(0x03)), PCI_INDEX);
    outw(value, PCI_DATA + (reg & 0x02));
}

void
pciWrite32(unsigned char bus, unsigned char dev, unsigned char fnc, unsigned char reg, unsigned int value)
{
    outl((1 << 31) + (bus << 16) + ((dev & 0x1f) << 11) +\
            ((fnc & 0x07) << 8) + (reg & ~(0x03)), PCI_INDEX);
    outl(value, PCI_DATA);
}


int
main(int argc, char *argv[])
{
    int             opt;
    extern char     *optarg;
    extern int      optind, opterr;
    int             width = 1;  /* default byte access */
    unsigned char   bus, dev, fnc, reg;
    unsigned int    wdata;

    while ((opt = getopt(argc, argv, "w:")) != -1) {
        if (opt == 'w') {
            width = atoi(optarg);
        } else {
            goto error;
        }
    }

    argc -= optind;
    argv += optind;

    iopl(3);

    if (argc == 4) {
        /* Read Pci */
        bus = strtoul(argv[0], NULL, 16);
        dev = strtoul(argv[1], NULL, 16);
        fnc = strtoul(argv[2], NULL, 16);
        reg = strtoul(argv[3], NULL, 16);
        if (width == 1) {
            printf("B:0x%02x/ D:0x%02x/ F:0x%02x/ R:0x%02x: 0x%02x\n",
                    bus, dev, fnc, reg, pciRead8(bus, dev, fnc, reg));
        } else if (width == 2) {
            printf("B:0x%02x/ D:0x%02x/ F:0x%02x/ R:0x%02x: 0x%04x\n",
                    bus, dev, fnc, reg, pciRead16(bus, dev, fnc, reg));
        } else if (width == 4) {
            printf("B:0x%02x/ D:0x%02x/ F:0x%02x/ R:0x%02x: 0x%08x\n",
                    bus, dev, fnc, reg, pciRead32(bus, dev, fnc, reg));
        } else {
            goto error;
        }
    } else if (argc == 5) {
        /* Write Pci */
        bus   = strtoul(argv[0], NULL, 16);
        dev   = strtoul(argv[1], NULL, 16);
        fnc   = strtoul(argv[2], NULL, 16);
        reg   = strtoul(argv[3], NULL, 16);
        wdata = strtoul(argv[4], NULL, 16);
        if (width == 1) {
            pciWrite8(bus, dev, fnc, reg, wdata);
        } else if(width == 2) {
            pciWrite16(bus, dev, fnc, reg, wdata);
        } else if(width == 4) {
            pciWrite32(bus, dev, fnc, reg, wdata);
        } else {
            goto error;
        }
    } else {
        goto error;
    }
    return 0;

error:
    printf("Usage: pci [-w WIDTH] BUS DEVICE FUNCTION REGISTER [DATA]\n"
            "Pci configuration space read or write.\n"
            "  -w        number of byte width. permit 1(default), 2, 4\n"
            "\n"
            "This command executable only root user.\n"
            "\n"
            "Examples:\n"
            "  pci 00 1f 00 00          Read pci from bus 0x00 dev 0x1f func 0x00 reg 0x00.\n"
            "  pci -w2 00 1f 00 10 500  Write pci bus 0x00 dev 0x1f func 0x00 reg 0x10 to 0x500.\n"
            "\n");
    return 1;
}


とりあえず、ばさっと書いただけで、細かく動作確認していなかったり、処理内容もちょっとエラー処理が手抜きぎみだったり、usageがカタコト英語だったりと、つっこみどころはありますが、まあ、個人利用レベルではなんとか使えそうな感じです。

*このブログをみて、プログラムを利用しようとしている方へ
    まったくもって、動作は保証しません。自己責任で使ってください。使用方法はコマンドのUsage参照
     バグに関する報告は歓迎します。それからプログラムの性格上、使いようによっては、
     簡単にシステムを破壊できてしまいます。I/OやPciコンフィグレーション空間について
     知識を有していない方は、使わないほうが懸命です。
     このプログラムを使ってあなたのPCや基板が燃えたり、レンガになっても責任は負いかねます。
   

ビルドはgccが使えるLinux環境で

$ gcc -o io io.c
$ gcc -o pci pci.c

って感じです。あれ、組み込みだとLinuxのファームにコンパイラ入ってなくて別の環境でビルドすることもあると思います。そんときにcライブラリの問題があったりするので、「-static」オプションをつけてビルドすることで、回避できることがあったりなかったりです。


ああ、明日もデバッグもりもりやります。