IT

eyefiserver2

4月にTrusty化したML110G7でまだ十分に動作確認ができていなかったのが、昨年5月に導入、1月に改修したeyefiserver2。

先日Trusty化したGT110bではすんなり動いているように思っていたのだが、実はpyexiv2関連で発生したExceptionによってSOAPの応答が発行されず、電源が入る度にEye-Fiカードがアップロードを繰り返していた事が判明。

よくよく調べてみると、昨年5月のUbuntu 10.04ではlucidなpython-pyexiv2がバージョン 0.1.3だったので、APIはレガシーなpyexiv2.Imageやexif.readMetadataを使用する必要があったのだが、preciseなpython-pyexiv2以降はバージョン 0.3.2になっているのでpyexiv2関連のAPIはモダンなpyexiv2.ImageMetadataやexif.readに戻す必要があったという事だ。

*** eyefiserver.py.orig 2012-06-28 13:16:46.000000000 +0900
--- eyefiserver.py      2014-06-10 00:14:38.685191477 +0900
***************
*** 56,61 ****
--- 56,62 ----
  from datetime import datetime
  import ConfigParser
+ import re
  class Daemon:
      """
***************
*** 566,578 ****
      eyeFiLogger.debug("Using file_mode " + file_mode)
      eyeFiLogger.debug("Using dir_mode " + dir_mode)
!     tempDir = os.path.dirname(self.server.config.get('EyeFiServer','upload_dir'))
      imageTarPath = os.path.join(tempDir, imageTarfileName)
      eyeFiLogger.debug("Generated path " + imageTarPath)
-
      fileHandle = open(imageTarPath, 'wb')
      eyeFiLogger.debug("Opened file " + imageTarPath + " for binary writing")
--- 567,581 ----
      eyeFiLogger.debug("Using file_mode " + file_mode)
      eyeFiLogger.debug("Using dir_mode " + dir_mode)
!     tempDir = os.path.dirname(self.server.config.get('EyeFiServer','temp_dir'))
!     if not os.path.isdir(tempDir):
!       eyeFiLogger.info("Creating folder " + tempDir)
!       os.makedirs(tempDir)
      imageTarPath = os.path.join(tempDir, imageTarfileName)
      eyeFiLogger.debug("Generated path " + imageTarPath)
      fileHandle = open(imageTarPath, 'wb')
      eyeFiLogger.debug("Opened file " + imageTarPath + " for binary writing")
***************
*** 586,634 ****
      imageTarfile = tarfile.open(imageTarPath)
      for member in imageTarfile.getmembers():
!       #timezone = self.server.config.getint('EyeFiServer','timezone')
!       timezone = -7
        imageDate = datetime.fromtimestamp(member.mtime) - timedelta(hours=timezone)
        uploadDir = imageDate.strftime(self.server.config.get('EyeFiServer','upload_dir'))
-       eyeFiLogger.debug("Creating folder " + uploadDir)
        if not os.path.isdir(uploadDir):
            os.makedirs(uploadDir)
            if uid != 0 and gid != 0:
                 os.chown(uploadDir, uid, gid)
            if file_mode != "":
                 os.chmod(uploadDir, string.atoi(dir_mode))
!       f=imageTarfile.extract(member, uploadDir)
!       imagePath = os.path.join(uploadDir, member.name)
!       eyeFiLogger.debug("imamgePath " + imagePath)
        if uid != 0 and gid != 0:
!         os.chown(imagePath, uid, gid)
        if file_mode != "":
!         os.chmod(imagePath, string.atoi(file_mode))
!
!     eyeFiLogger.debug("Closing TAR file " + imageTarPath)
!     imageTarfile.close()
!     eyeFiLogger.debug("Deleting TAR file " + imageTarPath)
!     os.remove(imageTarPath)
      try:
          import pyexiv2
!         metadata = pyexiv2.ImageMetadata(imagePath)
!         metadata.read()
!         if 'Exif.Image.DateTime' in metadata.exif_keys:
!             d = metadata['Exif.Image.DateTime'].value
              seconds = time.mktime(d.timetuple())
              os.utime(imagePath, (seconds, seconds))
          else:
              eyeFiLogger.error("Could not find Exif.Image.DateTime field in EXIF information")
      except ImportError, e:
!         eyeFiLogger.error("pyexiv2 module not present. Could not read EXIF information.")
          if e.message != 'No module named pyexiv2':
              raise
      # Create the XML document to send back
      doc = xml.dom.minidom.Document()
--- 589,674 ----
      imageTarfile = tarfile.open(imageTarPath)
      for member in imageTarfile.getmembers():
!       timezone = self.server.config.getint('EyeFiServer','timezone')
!       # timezone = -7
        imageDate = datetime.fromtimestamp(member.mtime) - timedelta(hours=timezone)
        uploadDir = imageDate.strftime(self.server.config.get('EyeFiServer','upload_dir'))
        if not os.path.isdir(uploadDir):
+           eyeFiLogger.info("Creating folder " + uploadDir)
            os.makedirs(uploadDir)
            if uid != 0 and gid != 0:
                 os.chown(uploadDir, uid, gid)
            if file_mode != "":
                 os.chmod(uploadDir, string.atoi(dir_mode))
!       eyeFiLogger.debug("member.name " + member.name)
!       if re.match(r'^.+\.(LOG)$(?i)', member.name) is not None:
!           continue
!
!       extractFilePath = os.path.join(uploadDir, member.name)
!       if os.path.exists(extractFilePath):
!           eyeFiLogger.info(extractFilePath + " is exist.")
!           continue
!
!       f = imageTarfile.extract(member, uploadDir)
!       eyeFiLogger.info("extractFilePath " + extractFilePath)
        if uid != 0 and gid != 0:
!         os.chown(extractFilePath, uid, gid)
        if file_mode != "":
!         os.chmod(extractFilePath, string.atoi(file_mode))
!         seconds = time.mktime(imageDate.timetuple())
!         os.utime(extractFilePath, (seconds, seconds))
!       if re.match(r'^.+\.(JPE?G)$(?i)', member.name) is None:
!           continue
+       imagePath = extractFilePath;
+       eyeFiLogger.debug("imagePath " + extractFilePath)
          try:
              import pyexiv2
!             eyeFiLogger.debug("pyexiv2.Image: " + imagePath)
!             exif = pyexiv2.ImageMetadata(imagePath)
!             exif.read()
!             if 'Exif.Image.DateTime' in exif.exif_keys:
!                 d = exif['Exif.Image.DateTime'].value
                  seconds = time.mktime(d.timetuple())
                  os.utime(imagePath, (seconds, seconds))
              else:
                  eyeFiLogger.error("Could not find Exif.Image.DateTime field in EXIF information")
          except ImportError, e:
!             eyeFiLogger.exception("pyexiv2 module not present. Could not read EXIF information.")
              if e.message != 'No module named pyexiv2':
                  raise
+         except Exception, e:
+             eyeFiLogger.exception(e.message)
+             raise
+
+     eyeFiLogger.debug("Closing TAR file " + imageTarPath)
+     imageTarfile.close()
+
+     eyeFiLogger.debug("Deleting TAR file " + imageTarPath)
+     os.remove(imageTarPath)
+
+ #    try:
+ #        import pyexiv2
+ #
+ #     eyeFiLogger.debug("pyexiv2.Image: " + imagePath)
+ #        exif = pyexiv2.Image(imagePath)
+ #        exif.readMetadata()
+ #        if 'Exif.Image.DateTime' in exif.exifKeys():
+ #            d = exif['Exif.Image.DateTime']
+ #            seconds = time.mktime(d.timetuple())
+ #            os.utime(imagePath, (seconds, seconds))
+ #        else:
+ #            eyeFiLogger.error("Could not find Exif.Image.DateTime field in EXIF information")
+ #    except ImportError, e:
+ #        eyeFiLogger.error("pyexiv2 module not present. Could not read EXIF information.")
+ #        if e.message != 'No module named pyexiv2':
+ #            raise
+
      # Create the XML document to send back
      doc = xml.dom.minidom.Document()
***************
*** 799,804 ****
--- 839,846 ----
    fileHandler.setFormatter(eyeFiLoggingFormat)
    eyeFiLogger.addHandler(fileHandler)
+   eyeFiLogger.setLevel(config.getint('EyeFiServer','loglevel'))
+   eyeFiLogger.info("Eye-Fi server started loglevel=" + str(config.getint('EyeFiServer','loglevel')))
    server_address = (config.get('EyeFiServer','host_name'), config.getint('EyeFiServer','host_port'))
***************
*** 839,844 ****
--- 881,888 ----
      config = ConfigParser.SafeConfigParser()
      config.read(configfile)
+     eyeFiLogger.setLevel(config.getint('EyeFiServer','loglevel'))
+     eyeFiLogger.info("Eye-Fi server reload loglevel=" + str(config.getint('EyeFiServer','loglevel')))
  class MyDaemon(Daemon):
    def run(self):

参考まで、Python系のライブラリパッケージ導入手順は

vpsもTrusty

2012年5月に導入したさくらのVPS。先日のGT110bに続いてTrusty化。

何はともあれVPSリモートコンソールから

root@vps:~# **apt-get install update-manager-core**
root@vps:~# **do-release-upgrade -d**

を投入する手順でトライしてみたが、やはり先日のGT110bと同様にCPAN/Perl絡みでエラーが量産される状況で環境を引き継ぐオンラインアップデートは不可。

というわけで、潔く再インストールを決断してVPSコントロールパネルから「OS再インストール」をポチッとな。「Ubuntu 14.04」を選択した後はガイダンスに従ってポチポチと一時間弱。

/home配下は無事に引き継げたので/etc/ssh/sshd_configのPort番号を22から**“ほにゃらら”**に変更PasswordAuthenticationはnoにPermitRootLoginはwithout-passwordのままでOKとし、

$ sudo service ssh restart

でsshdを再起動した後、remoteからのssh作業にスイッチ。

続いてお約束の設定変更。

$ sudo /usr/sbin/groupmod -n owner yano
$ sudo update-alternatives --config editor

で、グループ名とデフォルトエディタを変更。ついでにsudoでいちいちパスワードを打たなくていいようvisudoでNOPASSWDオプションを付与しておく。

yano ALL=(ALL) **NOPASSWD:** ALL

続いてaptをアップデートし、ntpやbuild-essentialを導入。

$ sudo apt-get update
$ sudo apt-get install ntp build-essential

インターネットマルチフィード時刻情報サービス:サービス詳細に倣って/etc/ntp.confのサーバをntp1~3.jst.mfeed.ad.jpに変更。

# Specify one or more NTP servers.
# Use servers from the NTP Pool Project. Approved by Ubuntu Technical Board
# on 2011-02-08 (LP: #104525). See http://www.pool.ntp.org/join.html for
# more information.
# server 0.ubuntu.pool.ntp.org
# server 1.ubuntu.pool.ntp.org
# server 2.ubuntu.pool.ntp.org
# server 3.ubuntu.pool.ntp.org
server ntp1.jst.mfeed.ad.jp
server ntp2.jst.mfeed.ad.jp
server ntp3.jst.mfeed.ad.jp
sudo /etc/init.d/ntp restart

今回はロケール設定は英語のままで。

本因坊秀策生誕 185 周年

本因坊秀策生誕 185 周年

本因坊秀策生誕 185 周年より

今日のGoogle Doodles、通称Googleロゴ。

ヒカルの碁でお馴染み…という枕もどうかと思うのだが、とにかく江戸時代の囲碁棋士である本因坊秀策だった。

センスが渋いなぁ…

【追記】ただ、国際的にはノルマンディー上陸作戦の決行日、通称D-Dayでしかも節目の70周年だったのに本因坊Doodleが世界で表示されて大変だったらしいとの事。

合掌。

参照

MdN Design Interactive http://www.mdn.co.jp/

ITライフハック http://itlifehack.jp/

ITmedia オルタナティブ・ブログ:海外速報部ログ http://blogs.itmedia.co.jp/burstlog/

Wikipedia http://ja.wikipedia.org/wiki/

Postfix設定見直し

GT110bのTrusty化作業で、cronやepgrecの予約タスクのエラーメールがSMTP送信されずにローカル配送されている事に気付いた。真っ先に疑ったiptablesのフィルタ設定は空っぽだったので、早速Postfixの設定ファイル/etc/postfix/main.cfをチェック。

宛先アドレスがroot@GT110b.bravotouring.comとなってホスト名を含む形になるのが問題なのはわかったが、VPSやML110G7と照らし合わせながら試行錯誤して落ち着いた結果が以下の通り。

# See /usr/share/postfix/main.cf.dist for a commented, more complete version
# Debian specific:  Specifying a file name will cause the first
# line of that file to be used as the name.  The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no
# appending .domain is the MUA's job.
append_dot_mydomain = no
# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h
readme_directory = no
# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
# ホスト名の設定
myhostname = GT110b.bravotouring.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
# ドメインの無いアドレスに付加する値の設定
myorigin = /etc/mailname
# ローカル配送するドメインを指定
mydestination = GT110b.bravotouring.com, localhost.bravotouring.com, , localhost
relayhost =
# メール中継が可能な IP アドレスを制限
mynetworks = 192.168.199.0/24 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
# メールボックスファイルの最大サイズ(単位は bye。 0 は無制限)
# mailbox_size_limit = 0
mailbox_size_limit = 51200000
recipient_delimiter = +
inet_interfaces = all

とはいえ、本質的には

IE11の互換性の変更点

何気にアクセスログ解析を見たところ、ブラウザ別アクセス数で"Mozilla/5.0"が1位になっているのに気付いた。

Netscapeシリーズかと思ったらそうではなく、昨年11月にリリースされた「Internet Explorer 11」で「ユーザーエージェント文字列が変更されたらしい。

**“compatible”とか“MSIE”というトークンが無くなる一方で“like Gecko”**トークンが追加されるという大胆な変更は、「今までのIEとは違う」という立ち位置を表すもので、Windows 8.1のInternet Explorer 11では

Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko

Windows 7のInternet Explorer 11では

Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko

となっているそうだ。

他にもIE11 の互換性の変更点が公開されているので、参考にされたい。

ついでに64bit版「Google Chrome」も出たよ。

参照

Windows デベロッパー センター http://msdn.microsoft.com/ja-JP/windows/

ITmedia PC USER http://www.itmedia.co.jp/pcuser/

ITmedia ニュース http://www.itmedia.co.jp/news/

窓の杜 http://www.forest.impress.co.jp/

Wikipedia http://ja.wikipedia.org/wiki/

TrustyとPT2

Ubuntu 14.04(Trusty Tahr)を入れたML110G7へのサーバ移行作業。

earthsoft PT2

アースソフト PT2

F-PLUGでBluetoothのペアリングが解除される問題が残っているものの、それ以外は特に問題無い事が確認出来たので全面的にML110G7へ移そうかと思ったのだが、ML110G7にはPCIスロットが全く無いのでPT2が浮いてしまう事に気付いた。

改めて整理するとGT110b自体は昨年2月にB75マザーGIGABYTE GA-B75M-D3Hへ喚装済み。という事はハード的にはUSB3.0やSATA3.0もReadyで、問題の根幹はOSであるUbuntu 10.04が古い事に尽きる。

とは言えアップデートに手間取ってGT110bを長時間止めるわけにもいかないのでML110G7へ移行すべしと相成ったわけだが、クリティカルなサービスはML110G7に移行してしまったので、改めてGT110bをアップデートしてみる事にする。

まずはML110G7の時と同じ手順で、ターミナルから

yano@GT110b:~$ **sudo apt-get install update-manager-core**
yano@GT110b:~$ **sudo do-release-upgrade -d**

を投入する手順でトライしてみたが、どうもCPAN/Perl絡みで残骸由来の不整合が残っている(俗に言う「腐った」状態)らしくエラー終了してしまった。

10.04からだと12.04、14.04と2段階上げなければならない事も考慮してオンラインアップグレードを諦め、CD-ROMからクリーンインストールを実施。欲張ったのが災いした区画設定のミスなどでやり直す羽目にも陥ったが、3度目の正直で無事導入完了。

なお、B75マザーGIGABYTE GA-B75M-D3Hでもbiosdevnameの問題が発生。/etc/default/grubのGRUB_CMDLINE_LINUX_DEFAULTに

# GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
**GRUB_CMDLINE_LINUX_DEFAULT**="nosplash biosdevname=0"
GRUB_CMDLINE_LINUX=""

と追記して、

$ sudo update-grub2

とする必要があった。

さてカードリーダーSCR3310-NTTComのインストールは

yano@GT110b:~$ **sudo apt-get install libccid pcsc-tools libpcsclite-dev pcscd**
yano@GT110b:~$ **sudo pcsc_scan**

でOK。pt3_drvもML110G7に展開したhttps://github.com/m-tsudo/pt3.gitのソースツリーをコピー&インストールして、

blacklist earth-pt1

と書いた/etc/modprobe.d/blacklist-earth-pt1.confを用意するだけでOKかと思いきや、

yano@GT110b:~$ **sudo modprobe pt3_drv**

とやっても/dev/pt3video?ができない問題に直面。

いろいろと調べてみてもよくわからなかったのだが、一晩置いてよく考えたらGT110bに実装しているのはPT3ではなくPT2なので、pt3_drvではなくpt1_drvが正解。いくらpt3_drvをロードしたところで/dev/pt3video?ができないのは当たり前というオチだった。

しかし、手元の

ホットシューカバー

2012年12月に調達したOLYMPUS PEN Lite E-PL5。

ホットシューカバー復活

PEN Lite E-PL5

なんだかんだで1年半になるものの、ストロボ撮影なんて数えるほどもしないので全く気付かなかったのだが、いつしか「ホットシューカバー」が無くなっていた。

機能的には全く問題無く、単に気分の問題だが…やっぱり気分がよろしくないので、速やかに調達しようと手配を試みたのだが、どういうわけかヨドバシやAmazonはおろか、本家オリンパスのオンラインショップですら取り扱いが無く、安そうな割に予想外に入手困難な代物である事に気付いた。

唯一取り扱いがあったのが、【楽天市場】カメラのミツバ。1個200円、メール便送料164円というのは決して手が出ない価格ではないのだが、何となくここで妥協したら「負け」のような気がしてカートに入れたところで、調査を再開。

一般に流通していない事を考えると、どうやら修理用の保守部品としてのみ存在するものと推察されるので、オリンパスサービスステーションに相談すれば手に入る可能性がありそうだ。

というわけで、ようやく平日の天神方面に出掛ける用事があったので、渡辺通りのオリンパスサービスステーション福岡に問合せて目論み通り調達に成功。

1個100円だったので、また紛失する可能性を考えて2個査収。税込216円で済んだのは作戦勝ちと言っていいだろう。

参照

オリンパスイメージング http://olympus-imaging.jp/

Wikipedia http://ja.wikipedia.org/wiki/

TrustyとIPMI

ようやく落ち着いたかに見えるgoto2048/fplug_for_linuxによる消費電力測定。

明るさや温度、湿度も測れるというので調子に乗っていろいろと試してみているのだが、実は激安と言えどもサーバグレードであるHP ProLiant ML110 G7には筐体内にも多数のセンサが実装されていて、HP Integrated Lights-Out 3 (iLO 3)でリモート監視できるようになっている。

「折角なのでこちらもゴニョゴニョできないかしらね…?」とグルグル調べてみたところ、何気にIntelligent Platform Management Interface (IPMI)と互換性がある事から、LinuxベースでもOpenIPMIによって取得できる事がわかったので、Kodai’s Blog: Ubuntu 9.10でML115のIPMIを利用するや【自宅サーバ構築】9. HP ProLiant ML110 G7で温度とFAN回転率解析: Pythonと自分 ~ a python lifeを参考にUbuntu 14.04(Trusty Tahr)ベースでトライした。

基本的には

yano@ML110G7:~$ sudo apt-get install openipmi ipmitool
yano@ML110G7:~$ sudo /etc/init.d/ipmievd start
yano@ML110G7:~$ sudo /etc/init.d/openipmi start

すれば良いだけなのだが、/dev/ipmi0がお馴染みの**“No such file or directory”**というエラーになった。

しかし、手動で

yano@ML110G7:~$ sudo modprobe ipmi_si
yano@ML110G7:~$ sudo modprobe ipmi_msghandler
yano@ML110G7:~$ sudo modprobe ipmi_poweroff
yano@ML110G7:~$ sudo modprobe ipmi_devintf
yano@ML110G7:~$ sudo modprobe ipmi_watchdog
yano@ML110G7:~$ sudo /etc/init.d/ipmievd start
yano@ML110G7:~$ sudo /etc/init.d/openipmi start

する分には大丈夫なのでよくよく調べてみると、

fplug_for_linux

先日導入したgoto2048/fplug_for_linux。

F-PLUG

F-PLUG

温度(Temperature)の応答メッセージが1バイト短い問題は、ひとまずデータの最後から2バイトに注目するように改修したのだが、やはり「1バイト短い」だけではなく別種別の応答が返ってくる事例もあってゴミデータっぽい値となっている事がわかった。

そういうわけで定石通り「SEOJクラスコード」が期待と違ったらリトライするようにしようかと思ったのだが、そこで温度(Temperature)の応答メッセージで「SEOJクラスコード」が漏れる問題に再び行く手を阻まれた。

もしかして、TIDが使われていない(常時ゼロ)のが問題なのではないか?というのも気になったので、カウントアップするTIDを載せてみたものの結果は変わらず。しかし、「SEOJクラスコード」が無くても「TIDがある」事で各情報の要求と応答メッセージが紐付けできるようになるので、fpstatusを下のように改修してみた。

#include <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include "fplug.h"
#undef  DEBUG
#define ENOTCONN_RETRY_MAX      10
#define MSG_RETRY_MAX           5
#define FPLUG_EXEC(fd,msg,buf)  fplug_exec((fd),(msg),sizeof((msg)),(buf),sizeof((buf)))
typedef unsigned char uchar;
static uint16_t tid = 0x0001;
void hunt_tid(uchar *buf)
{
    *(uint16_t *)&buf[2] = tid++;
}
typedef uchar uchar;
static void dump_message( char *mes, uchar *buf, int size  )
{
#ifdef DEBUG
    int cnt;
    printf( "%s", mes );
    for ( cnt=0; cnt<size; cnt++ ) {
        printf( "%02X,", buf[cnt] );
    }
    printf( "\n" );
#endif
    return;
}
int fplug_exec(int fd, uchar *req_msg, size_t req_len, uchar *res_buf, size_t bufsiz)
{
    struct timespec tmspec = { 0, 1000 * 1000 };
    int ret, i, j;
    uchar req_buf[BUFSIZ];
    memcpy(req_buf, req_msg, req_len);
    for (i = 0;i < MSG_RETRY_MAX; i++ ) {
        hunt_tid(req_buf);
        dump_message( "Command:", req_buf, req_len);
        for (ret = j = 0;j < ENOTCONN_RETRY_MAX; j++ ) {
            ret = write(fd, req_buf, req_len);
            if ( ret == req_len )
                break;
#ifdef DEBUG
printf("write()=%d,errno=%d\n", ret, errno);
#endif
            switch ( errno ){
            case ENOTCONN :
                tmspec.tv_nsec = 500 * 1000 * 1000;
                nanosleep(&tmspec, NULL);
                break;
            }
        }
        if ( ret <= 0 )
            break;
        tmspec.tv_sec = 0;
        tmspec.tv_nsec = 250 * 1000 * 1000;
        nanosleep(&tmspec, NULL);
        ret = read(fd, res_buf, bufsiz);
        if ( ret <= 0 )
            continue;
        dump_message( "read:", res_buf, ret );
        if (4 < ret && !memcmp(req_buf, res_buf, 4)){   // TID match
#ifdef DEBUG
printf("read()=%d,errno=%d\n", ret, errno);
#endif
            return ret;
        }
    }
    return -1;
}
int fplug_main( int fd, int mode )
{
    int cmd;
    int cnt;
    int ret;
    int i=0;
    uchar buf[BUFSIZ];
    uchar *szMode, szResult[BUFSIZ];
    time_t timer;
    struct tm *t;
    strcpy(szResult, "--");
    szMode = szResult;
    switch(mode) {
    case 'h':
        szMode = "FP_HUMID";
        for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, Humid, buf)); i++ ){
            uint16_t a = *(uint16_t *)&buf[ret-2];
            if ( 100 < a )
                continue;
            sprintf(szResult, "%d", a );
            break;
        }
        break;
    case 'i':
        szMode = "FP_ILLUM";
        for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, Illum, buf)); i++ ){
            uint16_t a = *(uint16_t *)&buf[ret-2];
            if ( 0xFFFD < a )
                continue;
            sprintf(szResult, "%d", a );
            break;
        }
        break;
    case 't':
        szMode = "FP_TEMP";
        for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, Temp, buf)); i++ ){
            int16_t a = *(int16_t *)&buf[ret-2];
            if ( a < -100 || 500 < a )
                continue;
            sprintf(szResult, "%.1f", (float)a / 10);
            break;
        }
        break;
    case 'w':
        szMode = "FP_WATT";
        for ( i = 0; i < MSG_RETRY_MAX && 0 < (ret = FPLUG_EXEC(fd, RWatt, buf)); i++ ){
            int16_t a = *(int16_t *)&buf[ret-2];
            if ( 2000 < a )
                continue;
            sprintf(szResult, "%.1f", (float)a / 10);
            break;
        }
        break;
    default:
        szMode = "FP_unknown";
        break;
    }
    printf( "%s=%s;", szMode, szResult);
}
int main(int argc, char *argv[])
{
    int fd;
    struct termios oldtio, newtio;
    char *cmd;
    if ( argc == 1 ) {
        printf("Usage: fpstatus <option>\n");
        return(0);
    }
    if ( *argv[1] == '-' ) argv[1]++;
    fd = open(SERIAL_PORT, O_RDWR);
    if ( fd < 0 ){
        perror("open(/dev/rfcomm0)");
        return 0;
    }
    tcgetattr( fd, &oldtio );
    newtio = oldtio;
    newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
    tcsetattr(fd, TCSANOW, &newtio);
    for ( cmd = argv[1]; cmd && *cmd; cmd++ )
        fplug_main(fd, *cmd);
    printf( "\n");
    tcsetattr(fd, TCSANOW, &oldtio);
    close(fd);
    return 0;
}

受信メッセージが期待する種別の応答でない場合は新しいTIDをアサインして要求からリトライする。5回送信しても期待する種別の応答が得られなかった場合、取得値は"–“となる。

楽天BOX

楽天で注文した商品を受け取れる宅配ロッカーが「なんば駅」と「関西大学」に登場という話。

通販商品の受け取り用ロッカー「楽天BOX」開始

Engadget 日本版より

「なんと関西大学に登場」ってどういう事かと思ったら、「なんば駅と関西大学に登場」だったのはさておき。

最寄り駅ならいざ知らず、わざわざ「なんば」から持って帰るメリットって一体…、楽天ブックス@コンビニ受取便でいいんじゃないの?と思ったのだが、楽天ブックスの商品に限らず楽天市場全体が対象となるのがメリットかな。

と思ったのだが、実は対応店舗は3店舗ほどに過ぎないという事なので、Amazon.co.jpのコンビニ受取はおろか楽天ブックス@コンビニ受取便以上にこぢんまりとした案件のようだ。orz

まずは、どれほどの利用者がいるのか興味深い。

参照

Engadget 日本版 http://japanese.engadget.com/

INTERNET Watch http://internet.watch.impress.co.jp/

【楽天市場】楽天BOX http://event.rakuten.co.jp/r-box/