Dies Aliquanti

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

IniFile再び

まえに、iniFileを読むためのRubyのクラスを実装したのを書いたけれど、ちょっと直しました。以前のものは、指定した、セクション、キーが存在しない場合、""を返すようにしていたのですが、Rubyっぽく、nilを返すようにしました。

 iniH = IniFile.new( fileSpec)

でファイルから読み、

 hash = iniH[ section名 ]

でセクション全体をハッシュで返します。セクションがない場合、nilが返ります。
セクションの有無を確認の上、キーにアクセスするには、

 raise "NO section" if ! iniH[ セクション名 ]
 value = iniH[セクション名][キー名]

のようにします。
新たにセクション、キーを指定して値を追加する場合には、

 (iniH[ セクション名] || iniH[ セクション名] = Hash.new)[key名] = 値

みたいになります。ほとんどパズルみたいなので、[], []=を定義しなおしてみました。これで、

 val = iniH[ セクション名, キー名]

 と書くことができます。目的とするセクションや、キーがない場合はnilが返ります。
 また、

 iniH[ セクション名、 キー名 ] = value

という、書き方ができます。この場合、指定したセクションが存在しない場合は、新たにセクションを追加し、キーにvalueを関連付けます。

それよりも嵌ったのは、正規表現で、キーと値の抽出は、/(.*)=(.*)/ではなく、/(.*?)=(.*)/,つまり最短一致にしておかないとちょっと動作がまずそうです。

#
# (c)2009 BO
#   inifile
#
 
class IniFile < Hash
  @@ReComment = /^#/
  @@ReSection =/\[(.*)\]/
  @@ReKeyValue =/(.*?)=(.*)/
  def initialize( fileSpec = nil )
    if fileSpec
      File::open( fileSpec) {|f|
        sectionName = ""
        while line = f.gets
          if line =~ @@ReComment  # skip a line
          elsif line =~ @@ReSection
            sectionName = $1.strip
          elsif line =~ @@ReKeyValue
            self[ sectionName,  $1.strip] = $2.strip if sectionName != ""
          end
        end # while
      }
    end
  end #def initialize( fileSpec = nil )

  def write2File( fileSpec )
    fp = File.open( fileSpec ,'w')
    fp.print to_s()
    fp.close
  end #def write2File( filespec )

  def to_s
    str = String.new
    self.each_key{ |section|
      str += "[#{section}]\n"
      if self[section]
        self[section].each_key{|key|
          str += "#{key}=#{self[section][key]}\n" if self[section][key]
        }
      end
    }
    str
  end #def to_s

  def []( section, *rest)
    return super(section) if rest.length == 0
    key=rest[0]
    self[section] ? self[section][key]  : nil
  end # def []( section, *rest)

  def []=( section, *rest )
    if rest.length == 1
      hash = rest[0]
      return super( section, hash)
    elsif rest.length == 2
      key, val = rest[0], rest[1]
      return (self[section] || super(section, Hash.new))[ key ]= val
    else
      raise "invalid number of param"
    end
  end #def []=( section, *rest )
end # class IniFile



スポンサーサイト

iEPGクラス再び、RubyでPVRを作ろう!その15

暫くぶりのPVRの話ですが、実は全体の実装も大体終わり、αバージョンみたいなものは動き始めています。もちろん、不具合もあって直さなければならないのですが、全体を見直すと、Rubyっぽくないというのもある一方で、ダサダサなところもあって書き直したりしてます。

まずは、録画情報を管理するIEPGDクラスですが、いろいろアホなことをやっていたのをなおしたら、結構すっきりしました(たぶん)。いままでの実装は恥さらしですが、気を取りなおして行きましょう。

IEPGDクラス
iepg/iepgd番組情報を管理するクラス。v1/v2とも対応しているが、両方のクラスをmixして使うことは、(少なくとも今のところ)できません。Hashクラスを継承していて、iepg情報の「ヘッダ部のフィールド名(文字列)」を「key」、「フィールドの値」を「value」として実装している。ただし、メモ部も内部的には、フィールド名"_memo:"のヘッダ部の情報として扱っている。
[例]
iepgd = IEPGD.new
iepgd["program-title:"]="連続テレビ小説つばさ" # 番組名をセット

その他、番組開始、終了時刻はリードオンリーメンバー変数(Timeクラス)@timeStart, @timeEndでアクセス可能。時刻に関するヘッダ部のフィールドを変更した場合は、自動的にこれらの変数もアップデートされる。

メソッド
to_s( format = nil )
引数formatの指定が省略された場合は、複数の行からなる文字列を返す。この文字列はiepgd情報を含む。引数format(Stringクラス)を指定した場合は、要約モードとしてiepgd情報の要約を文字列として返す。format文字列は、iepgd情報の各フィールドをplace holderを通じて指定する。place folderは”%<フィールド名>"であらわされる。このほか、%D,%eDは開始、終了時刻の年月日をYYYYMMDD形式で、%T,%eTは開始、終了時刻の時刻をHHMM形式であらわす。%%は%自身をあらわす。
[例]
iepgd = IEPGD.new
iepgd["program-title:"]="連続テレビ小説つばさ"
p iepgd.to_s("%%_%program-title:") # => "%_連続テレビ小説つばさ"

sameProgram?( other )
=~( other )
IEPGクラスotherとselが同じ番組の場合、trueをそうでなければfalseを返す。selfとotherは同じバージョン(version1/iepg形式、version2/iepgd形式)でなければならず、異なるバージョンの場合、例外がraiseされる。version1同士の場合は、"station:”、"program-title:"の各フィールドおよび、番組開始日時、時刻が一致した場合同じ番組とみなされる。version2同士の場合は、"station-name:"、"program-id:"が一致した場合同じ番組とみなされる。

クラスメソッド
IEPG.File2Array( filespec )
filespecで与えられたファイルから、iepgd情報を読み、IEPGDクラスのインスタンスのArrayを返す。
iepgd情報は、複数の番組情報を含む場合があるので、Arrayを返す仕様になっている。

その他のメソッドはおおむね下請け。

あらら、文字数制限ををオーバーしてしまったみたいなので、ソースはこちら



iEPGクラス再び、RubyでPVRを作ろう!その15の2

ということで、ソースコード
 

#
# iEPGD Class
# (c) 2008-09 B.O
# re-written
# to support V1 and V2 of iEPG
# for V1 reference , http://350ml.net/labo/iepg.html
# thanks to "AKINO Yoh, 350ml.net"
#
require 'set'
class IEPG < Hash
# keywords
@@Header = "Content-type:"
@@V1SingleContent = "x-tv-program-info"
@@V2SingleContent = "x-tv-program-digital-info"
@@V1MultiContent = "x-multi-tv-program-info"
@@V2MultiContent = "x-multi-tv-program-digital-info"
@@V1Mandatory = [ "version:", "station:", "start:", "end:" ]
@@V1Axuary = [ "year:", "month:" , "date:", "program-title:",
"program-subtitle:", "performer:", "genre:" , "subgenre:" ]
@@V2Mandatory = [ "version:", "station:", "station-name:",
"program-title:", "program-id:", "start:", "end:" ]
@@V2Axuary = [ "year:", "month:" , "date:", "genre-1:", "subgenre-1:",
"program-subtitle:", "performer:", "genre:" , "subgenre:" ]

@@Memo = "_memo:" # adding memo section, needs to be
@@OneDay = 24*60*60
@@KeywordTimeRelated = Set[ "year:", "month:", "date:", "start:", "end:"]
attr_reader :timeStart, :timeEnd

# member method
def initialize
#self.default = ""
@timeStart = Time.now
@timeEnd = Time.now
end #def initialize

def to_s( format = nil )
if format != nil #summary mode
str = String.new( format )
for key, value in self
str.gsub!( /%#{key}/, value )
end
str.gsub!( /%D/ ,@timeStart.strftime("%Y%m%d"))
str.gsub!( /%eD/, @timeEnd.strftime("%Y%m%d"))
str.gsub!( /%T/, @timeStart.strftime("%H%M"))
str.gsub!( /%eT/, @timeEnd.strftime("%H%M"))
str.gsub!( /%%/, "%")
return str
end

#to reproduce .tvipd file single content mode
keywords = [ @@Header ] + ( ( self[ "version:" ] == "1" ) ?
( @@V1Mandatory + @@V1Axuary ) :
( @@V2Mandatory + @@V2Axuary ) )
keywordsInSelf = self.keys
s = ""
keywords.each {|key|
s += key + (self[ key ] || "") +"\n"
keywordsInSelf.delete( key )
}
# if there are anything else in hash, put them for safty sake, except _memo:
keywordsInSelf.each {|key|
if( key != @@Memo )
s += key + self[ key ] +"\n"
keywordsInSelf.delete( key )
end
}
# handle memo section
s += "\n" + (self[ @@Memo ] || "") +"\n"
end # to_s

def <=>( other )
self.timeStart <=> other.timeStart
end #def <=>( other )

def sameProgram?( other )
if (var = self[ "version:"]) != other[ "version:"]
raise __FILE__ + __LINE__.to_s + "Error mixed versions"
end
if ver == "2"
format = "%station:%program-id:"
else
format = "%station:%program-title:%D%T"
end
return self.to_s( format ) == other.to_s( format )
end #def sameProgram?( other )

def []=(key, value)
tmp = super
if( @@KeywordTimeRelated.include?( key ) )
timeNow = Time.now
year = self[ "year:" ] || timeNow.year
month = self[ "month:" ] || timeNow.month
day = self[ "date:" ] || timeNow.day
start_time = self[ "start:" ] || "0:0"
end_time = self[ "end:" ] || "0:0"

_start = start_time.split(":")
_end = end_time.split(":")
@timeStart = Time.local( year, month, day, _start[0], _start[1] )
@timeEnd = Time.local( year, month, day, _end[0], _end[1] )
if @timeEnd <= @timeStart
@timeEnd += @@OneDay
end
end
tmp
end
#
# class methods
#
def IEPG.File2Array( filespec )
f = open( filespec )
s = f.read
f.close
lines = s.split(/$/)
lines.each {|line| line.strip! }
IEPG.Lines2Array( lines )
end #def IEPG.File2Array( filespec )

def IEPG.Lines2Array( lines )
if lines[0] =~ /^Content-type: *application\/#{@@V1SingleContent}|#{@@V2SingleContent}/ # single content
if ( (tmp = IEPG::fromLines( lines )) != nil )
return [ tmp ]
end
elsif lines[0] =~ /^Content-type: *application\/#{@@V1MultiContent}|#{@@V2MultiContent}/ # multi contents
ar = Array.new
i, boundary = catch :found_boundary do
for i in 1..( lines.length() -1 ) # find boundary string
throw(:found_boundary,[i, $1.strip]) if lines[i] =~ /^boundary:(.*)$/
end
raise __FILE__ + __LINE__.to_s + "Error boundary cannot be found"
end # catch

for i in (i+1)..( lines.length() -1 )
break if lines[i] =~ /^#{boundary}/
end
s=i
for i in (i+1)..( lines.length() -1 )
if lines[i] =~ /^#{boundary}/
if (tmp = IEPG::fromLines( lines[(s+1)..(i-1)] ))
ar << tmp
end
s=i
return ar if lines[i] =~ /^#{boundary}--/ # really end
end
end #for
raise __FILE__ + __LINE__.to_s + "Error, maybe no BOUNDARY's end"
end #elsif lines[0] =~ /^Content-type: *appl...
raise __FILE__ + __LINE__.to_s + "Error, unexpected file format"
end # def IEPG.Lines2Array( inlines )

# read one iEPGd from lines
# return a iEPGd
def IEPG.fromLines( lines)
if !( lines[0] =~ /^#{@@Header} *(.*)$/ ) # checking 1st line
raise __FILE__ + __LINE__.to_s + "Error unexpected format :" + lines[0]
end
contentType = $1.strip
if !(contentType =~ /application\/#{@@V1SingleContent}|#{@@V2SingleContent}/ )
raise __FILE__ + __LINE__.to_s + "Error unexpected content type:" + lines[0]
end
#check charset
contentType =~ /charset=(.*)/
if (charset = $1.strip) != "shift_jis"
raise __FILE__ + __LINE__.to_s + "Error unexpected charset type:" + charset
end
tmp = IEPG.new
for i in 0..( lines.length() -1 )
break if !(lines[i] =~ /(.*?:)(.*)/ )
tmp[ "#{$1.strip}" ] = $2.strip
end #for
# check memo section
if lines[i].strip == ""
if (i = i +1 ) <= lines.length() -1
tmp[ @@Memo ] = lines[i..-1].join("\n")
end
end
# set year, month and date, if missing
now=Time.now
for key, value in { "year:" => "%Y", "month:" => "%m", "date:" => "%d" }
tmp[key] = tmp[key] || now.strftime( value )
end
tmp
end #def fromLines( lines)

end #class IEPG < Hash


#--------------------------------------------------------------

 



D945GSEJT,ACアダプタでubuntu8.10運用中 HDD熱いの続き

HDDの暑さ対策で、FANの配置を変えてみたが、

/dev/sda: Hitachi HDT725050VLA360: 54°C
/dev/sdb: WDC WD10EACS-00ZJB0: 53°C

室温は37℃(!)なので、室温+17℃と+16℃。ん~、せめて+15℃以下に抑えたい。FANをもう少し高速のものにするしかないか…


D945GSEJT,ACアダプタでubuntu8.10運用中 HDD熱い

ハードディスクの温度が高い(触診)のは前に書きましたが、ツールを使って測定してみました。室温は31℃(これはこれで問題だが)

$ sudo hddtemp /dev/sd?
/dev/sda: Hitachi HDT725050VLA360: 55°C
/dev/sdb: WDC WD10EACS-00ZJB0: 54°C


orz ケースを開けっ放しにして数時間ほって置いて再測定

$ sudo hddtemp /dev/sd?
/dev/sda: Hitachi HDT725050VLA360: 51°C
/dev/sdb: WDC WD10EACS-00ZJB0: 46°C


orz さすがにこれはまずいんではないだろうか。とりあえず、ケースの蓋を開けっ放しにして、週末に対策しよう。。。



「なにやってるの?」

MintInbag

ブルーの方は、紙袋に入ってご満悦の様子。ブラウンの方は「なにやってるの?」

にゃんこ達は生後8ヶ月になりました。一日の行動は、

寝てる…25%
イタズラをする…25%
甘える…25%
ご飯を食べる…10%
ウンチをする…10%

と優雅な生活をしております。。。



D945GSEJT,ACアダプタで動してみる

ACアダプタで動作させてみました。データブックでみると50~60WクラスのACアダプタを想定しているようです。今回は秋月電子の12V5Aのアダプタ を使ってみました。
M/B側のDCジャックは外径5.5mm内径2.5mmタイプなので残念ながらこのままでは適合しません。外径5.5mm内径2.5mmタイプのプラグは 一般的なようなので、秋葉原の部品屋さんでも見つけることはできるでしょう。今回はM/Bを買いに行った時間がちょっと遅くて部品屋さんがしまっていたの と、この手のDCプラグは普通は5Aとかを流すことを前提には作られていないような気がするので変換ケーブルを作りました。同じく秋月電子で売っているDCジャックパネル取り付けタイプもあります) とこんなこともあろうか(笑)と買っておいた、12Vの延長ケーブル

【★人気商品】アイネックス PX-007 ATX12V用電源延長ケーブル
を途中で切って、半田付けして写真のようなケーブルを作ってみました。
powercable早速使ってみます。3.5インチHDD2台でも問題はないです。ACアダプタはそこそこ熱を持ちますが、ケースの外に置けるので放熱の点では有利ですね。PC本体の熱はほとんど感じられなくなりました。

もっとも、D945GSEJT上のCPU、MCHの温度はかなりですし、HDDも触った感じでは50℃近いのではないかと思いますので、ケースファンはゆっくりとですが廻しています。

ということで、とりあえず結果は上々。中長期的な信頼性はまた別ですが、しばらくこれで運用してみます。

(2009/6/10追記)
こちらの方によれば、秋月の口径変換器、もとい変換アダプタが使えるとのこと。これならお手軽ですね。そういえば、部品箱の中に転がっていたような…



D945GSEJT、ubuntuでNASの性能は?

今のところ、順調に動作してます。ubuntu8.10でSambaを動作させて、事実上NASとして動かしてます。もともと、このM/Bを選んだ理由のひとつがGbit-LAN I/Fです。そこで、どれくらい性能が出てるのか調べてみました。いままで、C2D E7200で動作させてましたが、単純にCPUパワーの比較だと、1/10位でしょうか?

ネットワークマウントしたドライブの性能をHDBENCHで、計ってみました。あまり厳密な測定ではないので、そのつもりで見てみてください。なお、LANは1Gです。

D945GSEJT(SATAはAHCI)
***** FDBENCH Ver 1.02 (C)2003-2007 ep82kazu *****
Drive V:\
Drive Size 100MB

  Disk  Read Write  RRead RWrite (KByte/s)
 29870 26743 44560  24179  23998

  Copy    2k   32k  256k   10MB (Operations/min)
 12607 27666 16020  6444    300

  Copy    2k   32k  256k   10MB (Kbyte/Sec)
 15276   615  5702 18380  36408

C2D E7200+GC45FC
***** FDBENCH Ver 1.02 (C)2003-2007 ep82kazu *****
Drive V:\
Drive Size 100MB

  Disk  Read Write  RRead RWrite (KByte/s)
 54396 48901 74418  41457  52810

  Copy    2k   32k  256k   10MB (Operations/min)
 30835 66546 39960 16254    582

  Copy    2k   32k  256k   10MB (Kbyte/Sec)
 32582  1479 14214 46284  68353

参考、ローカルディスク(WD WD5000AACS-0)、G965+C2Q6600

***** FDBENCH Ver 1.02 (C)2003-2007 ep82kazu *****
Drive W:\
Drive Size 100MB

  Disk  Read Write  RRead RWrite (KByte/s)
 40566 63563 63602   5984  29115

  Copy    2k   32k  256k   10MB (Operations/min)
 35592 75636 48846 17334    552

  Copy    2k   32k  256k   10MB (Kbyte/Sec)
 33334  1681 17375 49356  64925

まあ、大雑把に言って、C2D E7200の場合の50%強くらいですね。思ったよりいいです。ローカルディスクの例は5400rpmの省電力タイプですが、C2D E7200の場合とほとんど同じ。C2D E7200の場合はNASとしては、非常によいと見ることもできます。

ついでに、ubuntuの上で、VM PlayerでWindowsXPを動かして見ましたが、これはかなり厳しい…ubuntuから直接使うより、LAN上の別のPCからリモートデスクトップでログオンする方がやや快適です。

さて、またしても浮いてしまったE7200はWindows7 RCでも入れようかな・・・



D945GSEJT、NICの問題解決しました。

Ubuntu8.10でネットワークに繋がらない問題はやっと解決しました。
このページhttp://www.jamesonwilliams.com/hardy-r8168の内容が大変参考になりました。
基本的には、に書いたようにRealtekのサポートページからソースコードを拾ってきて、makeする必要があります。上のリンクでは、11.0というバージョンですが、私が拾ってきたのは12.0です。また、上のリンクの、

echo "nblacklist r8169n"...

は、正しくは

echo "blacklist r8169n"…

だと思います。

ubuntu上でfirefoxを使う分には、ちょっとかったるいな、という程度の性能ですが、Netbookってそういうものなのでしょう。H264 H/Wエンコーディングでのハイビジョン録画×2とMPEG2-TSでのハイビジョン録画(Regza)をやってみてますが、 今のところ問題なし。もう少し、様子を見てみます。

 



D945GSEJT、NICでハマリ中 

(2009/06/06 解決しました )

Ububtu8.10でNICがうまく認識できない件の続きです。D945GSEJTのNICはRealtkのRTL8111D(正確にはD(L)またはDP)というものが使われています。多くのATOM搭載M/Bが100MのNICしか搭載していないところ、これが1Gです。まあ、それが今回このM/Bを買った一番の理由ですが…
ネットを調べたりした結果、linuxで本来は、r8168というドライバを使わなければならないところを、r8169というドライバが間違って入る、というわりとポピュラーな問題のようです。

Realtekのダウンロードセンターには、8111D用のLinuxのドライバがあるので、これを拾ってきて、readmeにしたがってインストールしてみました(しかし、シロウトの私にmakeとかさせるかなぁ…)。

うまくつながった!と喜んだのもつかの間、rebootしたらやっぱりダメ… orz
不思議なことに、もう一度まったく同じ手順を踏んでも今度はうまくいきません(ナゼだー!)。ログファイルをみるとやっぱり、r8169と認識されているようです。
readmeを見ると、/etc/modprobe.conf(Plug&Play用の設定ファイルですかね?)を編集する、と書かれていますが、ubuntu8.10にはこんなファイルありません。。。orz

日和って、XP入れちゃおうかな・・・まだ、続く・・・



FC2Ad

まとめ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。