armadillo500fx に Android のっけて GPS デバイス認識させてみた

armadillo シリーズです。今度は BU-353 という GPS receiver なデータを Android な LocationService が取り込み可能にすべく手を入れてみます。

その前に

BU-353 というナニは基本的に USB serial なドライバでデータの取得は可能です。ので、以下のモジュールをカーネルに組み込んでおく必要あり。

  • CONFIG_USB_SERIAL
  • CONFIG_USB_SERIAL_GENERIC
  • CONFIG_USB_SERIAL_PL2303

上記モジュールが組み込まれたカーネルであれば GPS receiver からの出力を /dev/ttyUSB? というデバイスファイルから取得可能となります。
カーネルの作り方については前のエントリにありますので略。

前提

で、GPS receiver なんですが、基本的に GPS な衛星から情報を取得して色々な計算をした上で測位情報をナニするまではデバイスのお仕事で、後は標準化された形式なテキストを USB serial 経由でどんどん吐き出すだけな模様。
USB serial な情報を読み出す側はそのフォーマットを解析して測位情報にしてあげる必要がある訳です。が、Android のソースツリーの中にはそれらしいソースが見当らない。むむむ、と唸っていたらどこかで「DIY だかんね」という情報を発見。
まぢッスか、と言いつつ Google 先生にお伺いを立てていたら libfreerunner というライブラリがある、とのご託宣。これを使って USB serial から流れてくる情報を Android の LocationService が正しく認識できるようにすれば OK というのがこのエントリで盛り込む修正となります。

libfreerunner の取得など

GPS receiver を Android に認識させるための修正を以降で盛り込んでいきます。

BoardConfig.mk 修正

vendor/atmark-techno/armadillo500fx/BoardConfig.mk の末端に以下の二行を追加しておきます。

BOARD_HAVE_FREERUNNER_GPS := true
BOARD_GPS_LIBRARIES := libfreerunner_gps

上記については Android の make プロセスに対して

  • これより取得する libfreerunner とうライブラリを GPS 向けに使う事
  • GPS ライブラリの名前は libfreerunner_gps.so である事

を設定しています。

prelink-linux-arm.map 修正

以下の行を末端に追加します。

libfreerunner_gps.so    0x9A000000

Android の共有ライブラリはメモリの固定位置にロードされ、頻繁なロード、アンロードに伴なう負荷の軽減を図っています。上記ファイルについては、このマッピング情報を規定するものとなっています。

ソースツリーの取得

以下のコマンドにより、external 配下にソースツリーを展開します。

$ cd external
$ git clone git://gitorious.org/android-on-freerunner/freerunner_platform_hardware_hw.git

上記の操作にて external/freerunner_platform_hardware_hw というディレクトリが作成されます。

system.prop 修正

ソースを修正する前に vendor/atmark-techno/armadillo500fx/system.prop についても修正を盛り込んでおきます。diff 出力を以下に引用します。

 rild.libpath=/system/lib/libreference-ril.so
 rild.libargs=-d /dev/ttyS0
-wifi.interface = wlan0
+wifi.interface = ra0
 ro.config.sync = yes
 keyguard.no_require_sim=1

+ro.kernel.android.gps=ttyUSB0

修正点としては

  • wifi.interface プロパティの値を wlan0 から ra0 に変更
  • ro.kernel.android.gps プロパティの値を ttyUSB0 にする設定の追加

の二点となります。上記については無線 dongle 関連の設定も入っている旨、ご承知下さい。

ソースファイルの修正

修正対象は external/freerunner_platform_hardware_hw/gps/gps_freerunner.c となります。

まず freerunner_gps_set_position_mode 手続きについて、mode の判定を行なっているブロックをコメントアウトします。
以下にコメントアウト済みのソースコードを引用しておきます。

static int freerunner_gps_set_position_mode(GpsPositionMode mode, int fix_frequency)
{
    GpsState*  s = _gps_state;

    // only standalone supported for now.
/*
    if (mode != GPS_POSITION_MODE_STANDALONE)
        return -1;
*/

    if (!s->init || fix_frequency < 0) {         D("%s: called with uninitialized state !!", __FUNCTION__);         return -1;     }     s->fix_freq = fix_frequency;

    D("gps fix frquency set to %d secs", fix_frequency);

    return 0;
}

次は gps_dev_set_nmea_message_rate 手続きの修正です。このソースファイルにおいてはコマンド体系が異なるデバイスの制御を行なう形でコードが記述されておりますので、BU-353 という GPS receiver のコマンド体系に沿う形で修正を行ないます。

static void gps_dev_set_nmea_message_rate(int fd, char *msg, int rate)
{

  char buff[50];
  int i;
/*
  sprintf(buff, "$PUBX,40,%s,%d,%d,%d,0*", msg, rate, rate, rate);
*/

  sprintf(buff, "$PSRF103,%s,00,%02d,01*", msg, rate);

  i = strlen(buff);

  sprintf((buff + i), "%02x\r\n", gps_dev_calc_nmea_csum(buff));

  gps_dev_send(fd, buff);

  D("gps sent to device: %s", buff);

  return;

}

次は gps_dev_set_baud_rate 手続きですが、上記と同様となります。

static void gps_dev_set_baud_rate(int fd, int baud)
{

  char buff[50];
  int i, u;
/*
  for (u = 0; u < 3; ++u) {

    sprintf(buff, "$PUBX,41,%d,0003,0003,%d,0*", u, baud);
*/

  sprintf(buff, "$PSRF100,1,%d,8,1,0*", baud);

    i = strlen(buff);

    sprintf((buff + i), "%02x\r\n", gps_dev_calc_nmea_csum(buff));

    gps_dev_send(fd, buff);

    D("gps sent to device: %s", buff);
/*
  }
*/

  return;

}

修正はもう二箇所となります。gps_dev_set_message_rate 手続きが以下です。

static void gps_dev_set_message_rate(int fd, int rate)
{

  unsigned int i;

  char *msg[] = {
                 "00", /* GGA */
                 "01", /* GLL */
                 "02", /* GSA */
                 "03", /* GSV */
                 "04", /* RMC */
                 "05", /* VTG */
                 "08"  /* ZDA */
/*
                 "GGA", "GLL", "ZDA",
                 "VTG", "GSA", "GSV",
                 "RMC"
*/
                };

  for (i = 0; i < sizeof(msg)/sizeof(msg[0]); ++i) {
    gps_dev_set_nmea_message_rate(fd, msg[i], rate);
  }

  return;

}

最後に gps_dev_init 手続きですが、gps_dev_set_baud_rate 手続きの呼び出しを追加しています。

static void gps_dev_init(int fd)
{

  gps_dev_power(1);

  gps_dev_set_baud_rate(fd, 4800);

  usleep(1000*1000);

  // To set to STOP state
  gps_dev_stop(fd);

  return;

}

修正は以上となります。以下に参照したデバイスのマニュアルへのリンクを追記しておきます。

忘れてました

もう少し追加で修正が必要です。

init.armadillo500fx.rc

vendor/atmark-techno/armadillo500fx/init.armadillo500fx.rc についてちょっとした修正が必要です。
diff を以下に。

@@ -124,6 +129,9 @@ on boot
     hostname localhost
     domainname localdomain

+    chmod 0660 /dev/ttyUSB0
+    chown system system /dev/ttyUSB0

Android 上で /dev/ttyUSB0 の所有者が root になってて権限が 0600 な模様。このままでは Android なユーザがこのデバイスから情報を読み取れません。ので、起動時に無理矢理属性を変えている訳です。これが正しい方法かどうかは不明。

おわりに

本コンテンツの利用によって生じたいかなる損害も、著者は一切の責任をとることができませんので、自己責任での利用をお願いします。

avatar

About yamanetoshi

λ 好きだよ λ