<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>橋本商会 &#187; shokai</title>
	<atom:link href="http://shokai.org/blog/archives/author/shokai/feed" rel="self" type="application/rss+xml" />
	<link>http://shokai.org/blog</link>
	<description>なんか作ったりした記録を忘れないうちに書くblog</description>
	<lastBuildDate>Tue, 07 Sep 2010 13:08:58 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<atom:link rel="hub" href="http://pubsubhubbub.appspot.com/" />
			<item>
		<title>scansnapで自炊した本をkindleで読めるように補正する</title>
		<link>http://shokai.org/blog/archives/5327</link>
		<comments>http://shokai.org/blog/archives/5327#comments</comments>
		<pubDate>Tue, 07 Sep 2010 01:51:51 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[Automator]]></category>
		<category><![CDATA[javax.imageio]]></category>
		<category><![CDATA[JRuby]]></category>
		<category><![CDATA[Kindle]]></category>
		<category><![CDATA[画像処理]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5327</guid>
		<description><![CDATA[
最近新しく発売されたkindle黒が届いたが、scansnapで作ったPDFを入れてみたら文字がかすれて読めなくなって悲しかったので、なんとかするスクリプトをJRubyで作った。
http://github.com/s [...]]]></description>
			<content:encoded><![CDATA[<p>
最近新しく発売されたkindle黒が届いたが、scansnapで作ったPDFを入れてみたら文字がかすれて読めなくなって悲しかったので、なんとかするスクリプトをJRubyで作った。<br />
<a href="http://github.com/shokai/scansnap_adjust_images_kindle">http://github.com/shokai/scansnap_adjust_images_kindle</a>に連番画像の補正プログラムと、連番画像をPDFにまとめるautomatorアプリを置いておいた。<br />
JRuby1.5+Java1.5以上なら動くと思う。<br />
<br />
scansnapの設定は<a href="http://shokai.org/blog/archives/4999">橋本商会 » scansnapと裁断機を買って本を電子化しまくる</a>に書いたのと同じ。白黒ページはスーパーファインのグレースケールで取り込んでいる。<br />
<br />
文庫本を補正した場合こうなる。<br />
日本語の文庫本を読めるようにする事を目的に作ってるので、他の判型だとちょっとダメかも（理由は後述）<br />
<a href="http://www.flickr.com/photos/shokai/4963909034/" title="R0015336.JPG by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4110/4963909034_c84d464e01.jpg" width="375" height="500" alt="R0015336.JPG" /></a><br />
<br />
<br />
詳解OpenCVという本を、補正をかけずに表示したところ。<br />
文字の中でも線の細い部分だけが、kindle上でリサイズした時に消滅するので字が読めない<br />
<a href="http://www.flickr.com/photos/shokai/4963472917/" title="R0015339.JPG by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4145/4963472917_ed20d70e4a.jpg" width="500" height="375" alt="R0015339.JPG" /></a><br />
<br />
<br />
詳解OpenCVの同じページ補正するとこうなる。<br />
それなりに読めるが、線の密度とか計算せずに全て太らせているのでアルファベットや記号がところどころ融合して読みづらい。<br />
<a href="http://www.flickr.com/photos/shokai/4963472211/" title="R0015337.JPG by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4150/4963472211_ddb26d3139.jpg" width="500" height="375" alt="R0015337.JPG" /></a><br />
<br />
<br />
■やっている事<br />
scansnapで自炊した本をそのままkindleで表示するには色々問題がある。<br />
<ul>
  <li>kindleの解像度は800&#215;600だけど、画面内にページ位置等のUIが入るし画面を縦横回転させたり拡大縮小できるので、表示時にkindle上でリサイズされる。この時、線が細くて薄い部分が消滅してしまって、文字がかすれて読めなくなってしまう。</li>
  <li>scansnapで取り込んだままのPDFファイルでは、コントラストが弱くてとても読みづらい。</li>
  <li>ページの上下左右の余白が邪魔で、kindleに全画面表示した時に小さくなってしまう</li>
</ul>
<br />
kindle上でリサイズされる事を前提として、文字が消えてしまうような細い部分を太くしてやるしかない。<br />
しょうがないので、コントラストを上げたり、拡大縮小されるのを前提として先にアンチエイリアス？的な処理をしたり、余白を切り取ったり、リサイズしたりするようにした。<br />
上下左右を裁ち落とし→リサイズ→グレースケール化→2値化→黒の周りを#999999で太らせるという処理をしている。<br />
<br />
<br />
<br />
■画像を補整する<br />
<br />
まずPDFから連番画像に戻す。MacやLinuxなら、pdfimagesというツールを使うといい。<br />
<pre>
# for Mac<br />
% sudo port install pdfX<br />
<br />
# for Ubuntu<br />
% sudo apt-get install xpdf-utils<br />
<br />
# extract images<br />
% mkdir -p ~/tmp/mybook<br />
% pdfimages -j ~/Documents/book/mybook.pdf ~/tmp/mybook/<br />
</pre>
もしくはAcrobat Proを買って「書き出し」でもできる。<br />
<br />
<br />
補正する。githubから俺の作ったツールを持ってくる。<br />
<pre>
% git clone git://github.com/shokai/scansnap_adjust_images_kindle.git<br />
% cd scansnap_adjust_images_kindle<br />
</pre>
<br />
<br />
で、先ほど作った連番画像のディレクトリを元にして、補正した連番画像を作る<br />
<pre>
% jruby kindlize_images.rb -help<br />
% jruby kindlize_images.rb -i ~/tmp/mybook/ -o ~/tmp/mybook_kindle/ -w 1200 -h 1600 -cl 150 -cr 150 -ct 120 -cb 180 -t 240<br />
</pre>
出力ディレクトリは無ければ自動的に作成される。<br />
<br />
上はオライリーの本の場合の裁ち落とし。<br />
文庫の場合はこんなパラメータ<br />
<pre>
jruby kindlize_images.rb -i ~/tmp/mybook/ -o ~/tmp/mybook_kindle/ -w 1200 -h 1600 -cl 30 -cr 30 -ct 80 -cb 115 -t 220<br />
</pre>
<br />
<br />
作った連番画像をPDFに戻すには、cloneしたgitリポジトリ内のimages2pdf.appを使えばいい。MacのAutomator.appで作ったアプリ。<br />
Preview.appでもPDFのページを並べ替えたりできるが、連番ページを順番に入れる事はできなかったので作った。<br />
<br />
<br />
<br />
■問題点<br />
文字を太らせる処理は、1 pixelずつグレーで周りを塗っているだけなので、文字のサイズや密度を考慮していない。<br />
処理速度も遅い。300ページの本でも1時間近くかかる。まあ読む速度より遅くはないからいいや。もっとたくさんkindleに入れたくなったらC++でOpenCV使って書き直す。<br />
<br />
<br />
■ソース<br />
Javaのjavax.imageioをRubyから使うのが簡単な画像処理に便利なので、JRubyを使ってます<br />
<br />
<a href="http://github.com/shokai/scansnap_adjust_images_kindle/blob/master/kindlize_images.rb">kindlize_images.rb</a><br />
<pre class="prettyprint">
#!/usr/bin/env jruby<br />
# -*- coding: utf-8 -*-<br />
# ディレクトリ内の画像を全てkindleで読みやすいように2値化、アンチエイリアス、リサイズする<br />
# イラストも2値化されるので、小説などの文字ページ専用。<br />
require 'rubygems'<br />
require 'ArgsParser'<br />
require 'java'<br />
import 'java.lang.System'<br />
import 'javax.imageio.ImageIO'<br />
import 'java.awt.image.BufferedImage'<br />
import 'java.awt.image.WritableRaster'<br />
import 'java.awt.image.AffineTransformOp'<br />
import 'java.awt.geom.AffineTransform'<br />
import 'java.awt.Color'<br />
$KCODE = 'u'<br />
<br />
parser = ArgsParser.parser<br />
parser.bind(:width, :w, 'width')<br />
parser.bind(:height, :h, 'height')<br />
parser.bind(:input, :i, 'input')<br />
parser.bind(:output, <img src='http://shokai.org/blog/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> , 'output')<br />
parser.bind(:cleft, :cl, 'crop left (pixel)')<br />
parser.bind(:cright, :cr, 'crop right (pixel)')<br />
parser.bind(:ctop, :ct, 'crop top (pixel)')<br />
parser.bind(:cbottom, :cb, 'crop bottom (pixel)')<br />
parser.bind(:threshold, :t, 'threshold of binarize (0-255)')<br />
first, params = parser.parse(ARGV)<br />
<br />
if !parser.has_params([:width, :height, :input, <img src='http://shokai.org/blog/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> utput, :threshold]) or<br />
    parser.has_option(:help)<br />
  puts parser.help<br />
  puts 'e.g. jruby kindlize_images.rb -i /path/to/in_dir/ -o /path/to/out_dir/ -w 1200 -h 1600 -t 240'<br />
  puts 'e.g. jruby kindlize_images.rb -i /path/to/in_dir/ -o /path/to/out_dir/ -w 1200 -h 1600 -cleft 50 -cright 50 -ctop 80 -cbottom 100 -t 240'<br />
  exit 1<br />
end<br />
  <br />
p params<br />
WIDTH = params[:width].to_i<br />
HEIGHT = params[:height].to_i<br />
Dir.mkdir(params[:output]) unless File.exists? params[:output]<br />
params[:output] += '/' unless params[:output] =~ /\/$/<br />
<br />
Dir.glob(params[:input]+'*').each{|i|<br />
  puts i<br />
  begin<br />
    img = ImageIO.read(java.io.File.new(i))<br />
  rescue =&gt; e<br />
    STDERR.puts 'image load error'<br />
    STDERR.puts e<br />
    next<br />
  end<br />
  puts "size : #{img.width}x#{img.height}"<br />
  <br />
  if params[:cleft] or params[:cright] or params[:ctop] or params[:cbottom]<br />
    params[:cleft] = 0 unless params[:cleft]<br />
    params[:cright] = 0 unless params[:cright]<br />
    params[:ctop] = 0 unless params[:ctop]<br />
    params[:cbottom] = 0 unless params[:cbottom]<br />
    img = img.get_subimage(params[:cleft].to_i, params[:ctop].to_i,<br />
                           img.width-params[:cleft].to_i-params[:cright].to_i, <br />
                           img.height-params[:ctop].to_i-params[:cbottom].to_i)<br />
    puts "crop : #{img.width}x#{img.height}"<br />
  end<br />
<br />
  # リサイズ<br />
  if img.width.to_f/img.height &gt; WIDTH.to_f/HEIGHT # 指定されたWIDTH,HEIGHTよりも横長の画像<br />
    scale = WIDTH.to_f/img.width<br />
    img_resized = BufferedImage.new(WIDTH, (scale*img.height).to_i, img.type)<br />
  else # 縦長<br />
    scale = HEIGHT.to_f/img.height<br />
    img_resized = BufferedImage.new((scale*img.width).to_i, HEIGHT, img.type)<br />
  end<br />
  puts "scale : #{scale}"<br />
  AffineTransformOp.new(AffineTransform.getScaleInstance(scale, scale), nil).filter(img, img_resized)<br />
  puts "resized : #{img_resized.width}x#{img_resized.height}"<br />
<br />
  # 固定サイズ画像にはめこむ<br />
  img_frame = BufferedImage.new(WIDTH, HEIGHT, img.type)<br />
  graph = img_frame.graphics<br />
  graph.color = Color.new(255,255,255)<br />
  graph.fillRect(0, 0, WIDTH, HEIGHT)<br />
  if WIDTH &gt; img_resized.width<br />
    graph.drawImage(img_resized, (WIDTH-img_resized.width)/2, 0, nil)<br />
  else<br />
    graph.drawImage(img_resized, 0, (HEIGHT-img_resized.height)/2, nil)<br />
  end<br />
  puts "set in frame : #{img_frame.width}x#{img_frame.height}"<br />
  img = img_frame<br />
<br />
  # 2値化<br />
  for y in 0...img.height do<br />
    for x in 0...img.width do<br />
      pix = img.get_rgb(x, y)<br />
      r = pix &gt;&gt; 16 &amp; 0xFF<br />
      g = pix &gt;&gt; 8 &amp; 0xFF<br />
      b = pix &amp; 0xFF<br />
      gray = (r+g+b)/3<br />
      if gray &gt; params[:threshold].to_i<br />
        pix = 0xFFFFFF<br />
      else<br />
        pix = 0x000000<br />
      end<br />
      img.set_rgb(x, y, pix)<br />
    end<br />
  end<br />
  puts "binarize"<br />
<br />
  # 膨張<br />
  img_dilated = BufferedImage.new(img.width, img.height, img.type)<br />
  for y in 1...img.height-1 do<br />
    for x in 1...img.width-1 do<br />
      if img.get_rgb(x, y)&amp;0xFF == 0<br />
        img_dilated.set_rgb(x, y, 0x000000)<br />
      elsif img.get_rgb(x-1, y)&amp;0xFF == 0 or img.get_rgb(x+1, y)&amp;0xFF == 0 or<br />
          img.get_rgb(x, y-1)&amp;0xFF == 0 or img.get_rgb(x,y+1)&amp;0xFF == 0<br />
        img_dilated.set_rgb(x, y, 0x999999)<br />
      else<br />
        img_dilated.set_rgb(x, y, 0xFFFFFF)<br />
      end<br />
    end<br />
  end<br />
  img = img_dilated<br />
  puts "dilate"<br />
<br />
  out_name = i.split(/\//).last<br />
  out_type = 'bmp'<br />
  begin<br />
    ImageIO.write(img, out_type, java.io.File.new(params[:output]+out_name))<br />
    puts 'saved! =&gt; '+params[:output]+out_name<br />
  rescue =&gt; e<br />
    STDERR.puts 'image save error'<br />
    STDERR.puts e<br />
    next<br />
  end<br />
}<br />
</pre>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5327/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>26歳になったので</title>
		<link>http://shokai.org/blog/archives/5322</link>
		<comments>http://shokai.org/blog/archives/5322#comments</comments>
		<pubDate>Wed, 18 Aug 2010 10:12:56 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[Wikipedia]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5322</guid>
		<description><![CDATA[
8月15日に26歳になったので、新しい自分を探すためにtwitterのプロフィールを自動的に更新するようにした


人間以外にもなれる




ソースコードは全部githubに置いた
ランダムに適当な紹介文を取ってくる [...]]]></description>
			<content:encoded><![CDATA[<p>
<p>8月15日に26歳になったので、新しい自分を探すために<a href="http://twitter.com/shokai">twitterのプロフィール</a>を自動的に更新するようにした<br /><br />
<a href="http://www.flickr.com/photos/shokai/4903244203/" title="30ed9b71553d2f33922bc39e7368a008 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4121/4903244203_4bb03acf09.jpg" width="253" height="225" alt="30ed9b71553d2f33922bc39e7368a008" /></a></p>
<p><a href="http://www.flickr.com/photos/shokai/4904183134/" title="838d669e96f189702c3f9844965ace8e by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4135/4904183134_77a40b2fe2.jpg" width="247" height="244" alt="838d669e96f189702c3f9844965ace8e" /></a><br /></p>
<p>人間以外にもなれる<br /><br />
<a href="http://www.flickr.com/photos/shokai/4903239191/" title="eac518c56870949065eeeed905d34ae4 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4117/4903239191_61c18437a9.jpg" width="254" height="200" alt="eac518c56870949065eeeed905d34ae4" /></a></p>
<p><a href="http://www.flickr.com/photos/shokai/4903423129/" title="e85cb1527f60394255fe556f41cc3e62 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4140/4903423129_e74e2c5a3c.jpg" width="251" height="354" alt="e85cb1527f60394255fe556f41cc3e62" /></a></p>
<p><a href="http://www.flickr.com/photos/shokai/4903820452/" title="9c4c1cb1c6fadac1ff09f120b5585892 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4117/4903820452_2bd60a5065.jpg" width="264" height="276" alt="9c4c1cb1c6fadac1ff09f120b5585892" /></a></p>
<p><a href="http://www.flickr.com/photos/shokai/4903251901/" title="7d4fcd1cd71ba0e8693133439b4751eb by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4076/4903251901_af1e028e41.jpg" width="271" height="312" alt="7d4fcd1cd71ba0e8693133439b4751eb" /></a><br /></p>
<p>ソースコードは<a href="http://github.com/shokai/twitter-change-profile">全部githubに置いた</a><br /></p>
<p>ランダムに適当な紹介文を取ってくる<br /><br />
<a href="http://github.com/shokai/twitter-change-profile/blob/b04a978f51f173f8e9997b8f2f89984152061eb8/lib/wikipedia.rb">wikipedia.rb</a><br /><br />
<pre class="prettyprint"><br />
# -*- coding: utf-8 -*-<br /><br />
require 'rubygems'<br /><br />
require 'open-uri'<br /><br />
require 'uri'<br /><br />
require 'nokogiri'<br /><br />
require 'kconv'<br /><br />
require 'net/http'</p>
<p>class Wikipedia</p>
<p>  def initialize(agent_name)<br /><br />
    @agent_name = agent_name<br /><br />
  end</p>
<p>  def random<br /><br />
    get('特別:おまかせ表示')<br /><br />
  end<br /><br />
  <br /><br />
  def get(name)<br /><br />
    doc = Nokogiri::HTML open(URI.encode("http://ja.wikipedia.org/wiki/#{name}"), 'User-Agent' =&gt; @agent_name).read.toutf8<br /><br />
    <br /><br />
    title = doc.xpath('//title').first.text<br /><br />
    name = doc.xpath('//h1').first.text<br /><br />
    descriptions = doc.xpath('//div[@id="bodyContent"]//p').map{|i|i.text}<br /><br />
    {<br /><br />
      :title =&gt; title,<br /><br />
      :name =&gt; name,<br /><br />
      :descriptions =&gt; descriptions<br /><br />
    }<br /><br />
  end</p>
<p>end<br /><br />
</pre></p>
<p>このスクリプトをcronで定期的に実行して更新してる<br /><br />
<a href="http://github.com/shokai/twitter-change-profile/blob/1baaf76b52f9d377c39ce1ceb8c1edb232550f57/change-profile.rb">change-profile.rb</a><br /><br />
<pre class="prettyprint"><br />
#!/usr/bin/env ruby<br /><br />
# -*- coding: utf-8 -*-<br /><br />
require 'rubygems'<br /><br />
require 'twitter'<br /><br />
require 'yaml'<br /><br />
require File.dirname(__FILE__)+'/lib/wikipedia'<br /><br />
$KCODE = 'u'</p>
<p>begin<br /><br />
  conf = YAML::load open(File.dirname(__FILE__) + '/config.yaml')<br /><br />
rescue<br /><br />
  STDERR.puts 'config.yaml load error'<br /><br />
  exit 1<br /><br />
end</p>
<p>tw = Twitter::Base.new(Twitter::HTTPAuth.new(conf['name'], conf['pass']))<br /><br />
w = Wikipedia.new('shokai')<br /><br />
desc = nil<br /><br />
5.times do<br /><br />
  data = w.random<br /><br />
  <br /><br />
  desc = data[:descriptions].first<br /><br />
  desc.gsub!(/\[\d+\]/, '')<br /><br />
  tmp = desc.split(/(と?は)/)<br /><br />
  left = tmp.shift<br /><br />
  while left =~ /（[^）]+$/ do<br /><br />
    tmp.shift<br /><br />
    left = tmp.shift<br /><br />
  end<br /><br />
  desc = "#{conf['your_name']}#{tmp.join('')}".toutf8<br /><br />
  puts '-'*10<br /><br />
  print data[:name] + ' =&gt; '<br /><br />
  puts desc<br /><br />
  break if desc != conf['your_name']<br /><br />
end<br /><br />
exit if desc == nil or desc == conf['your_name']</p>
<p>tw.update_profile({'description' =&gt; desc})<br /><br />
</pre><br />
</p>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5322/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ZeroMQでOpenCV cvOpticalFlowのデータを配信する</title>
		<link>http://shokai.org/blog/archives/5311</link>
		<comments>http://shokai.org/blog/archives/5311#comments</comments>
		<pubDate>Wed, 11 Aug 2010 10:39:22 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[OpticalFlow]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[ZeroMQ]]></category>
		<category><![CDATA[画像処理]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5311</guid>
		<description><![CDATA[
1VQ9がZeroMQで遊んでたので、俺も橋本商会 » cvCalcOpticalFlowBMをZeroMQでpubしてみた。ZeroMQはなんか面倒な事を適当にやってくれるmessaging libraryで、色々な [...]]]></description>
			<content:encoded><![CDATA[<p>
1VQ9がZeroMQで遊んでたので、俺も<a href="http://shokai.org/blog/archives/4820">橋本商会 » cvCalcOpticalFlowBM</a>をZeroMQでpubしてみた。<a href="http://www.zeromq.org/">ZeroMQ</a>はなんか面倒な事を適当にやってくれるmessaging libraryで、色々な言語のバインディングが出ている。<br />
<br />
ZeroMQのpubはセンサーのデータとかを垂れ流しにするのに都合がよさそう。<br />
clientが何台いるかどうかを考えないで良いし、pub/subどちらが先に起動していても適当に接続処理をしてくれる。cookbookを見てるとmulticastやthread間通信にも使ってる。とりあえずセンサーデータ垂れ流しという用途に俺はよく使いそう。<br />
<br />
<br />
ソースコードは<a href="http://github.com/shokai/zeromq-study">githubに置いた</a>。<br />
他にも<a href="http://github.com/shokai/zeromq-study/tree/7ac74e64a0343ea87f55b94fb26baa29cf652668/count">単純なカウントアップのpub/sub両方をC++/C/Rubyで書いた（6種）</a>のと、<a href="http://github.com/shokai/zeromq-study/tree/7ac74e64a0343ea87f55b94fb26baa29cf652668/twitter-stream">twitterのstream APIをZMQ_PUBで中継する</a>のを作ってみた（解説：<a href="http://d.hatena.ne.jp/shokai/20100810/1281455530">zeromqインストール、twitter stream APIを中継 &#8211; 橋本詳解</a>）。特にstream APIのHUB的存在は便利。<br />
<br />
あと、<a href="http://mongrel2.org/">mongrel2</a>が<a href="http://nichol.as/zeromq-an-introduction">WebSocketやXMLSocketとZeroMQの接続をしてくれるようになる</a>らしくて期待してる。<br />
<br />
<br />
<br />
受信側<br />
<a href="http://github.com/shokai/zeromq-study/blob/d2f3e4f69881a517a9c0445372b7b366e0a74f7b/opticalflow/opticalflow_sub.rb">opticalflow_sub.rb</a><br />
<pre class="prettyprint">
#!/usr/bin/env ruby<br />
require 'rubygems'<br />
require 'zmq'<br />
<br />
ctx = ZMQ::Context.new<br />
sock= ctx.socket(ZMQ::SUB)<br />
sock.connect('tcp://127.0.0.1:5000')<br />
sock.setsockopt(ZMQ::SUBSCRIBE, 'opticalflow')<br />
<br />
loop do<br />
  puts sock.recv()<br />
end<br />
</pre>
<br />
<br />
送信側。これを適当なパソンコにUSBカメラ刺して動かしておけば、別のマシンから動きが取れる！!<br />
<a href="http://github.com/shokai/zeromq-study/blob/d2f3e4f69881a517a9c0445372b7b366e0a74f7b/opticalflow/opticalflow_pub.cpp">opticalflow_pub.cpp</a><br />
<pre class="prettyprint">
// http://opencv.jp/sample/optical_flow.html<br />
#include &lt;cv.h&gt;<br />
#include &lt;highgui.h&gt;<br />
#include &lt;cxcore.h&gt;<br />
#include &lt;ctype.h&gt;<br />
#include &lt;stdio.h&gt;<br />
#include &lt;iostream&gt;<br />
#include &lt;boost/format.hpp&gt;<br />
#include &lt;zmq.hpp&gt;<br />
<br />
using namespace std;<br />
using namespace boost;<br />
<br />
void detect_flow(IplImage *img, IplImage *img_p, IplImage *dst);<br />
zmq::context_t ctx(1);<br />
zmq::socket_t sock(ctx, ZMQ_PUB);<br />
<br />
int main(int argc, char* argv[]) {<br />
  IplImage *img = NULL;<br />
  CvCapture *capture = NULL;<br />
  capture = cvCreateCameraCapture(0);<br />
  //capture = cvCaptureFromAVI("test.mov");<br />
  if(capture == NULL){<br />
    cerr &lt;&lt; "capture device not found!!" &lt;&lt; endl;<br />
    return -1;<br />
  }<br />
<br />
  sock.bind("tcp://127.0.0.1:5000");<br />
<br />
  CvSize size = cvSize(320, 240);<br />
  IplImage *img_resized = cvCreateImage(size, IPL_DEPTH_8U, 3);<br />
  IplImage *img_gray = cvCreateImage(size, IPL_DEPTH_8U, 1);<br />
  IplImage *img_gray_p = cvCreateImage(size, IPL_DEPTH_8U, 1);<br />
  IplImage *img_dst = cvCreateImage(size, IPL_DEPTH_8U, 3);<br />
<br />
  char winNameCapture[] = "Capture";<br />
  cvNamedWindow(winNameCapture, CV_WINDOW_AUTOSIZE);<br />
  <br />
  while (1) {<br />
    img = cvQueryFrame(capture);<br />
    cvResize(img, img_resized);<br />
    cvCvtColor(img_resized, img_gray, CV_BGR2GRAY);<br />
    cvCopy(img_resized, img_dst);<br />
    detect_flow(img_gray, img_gray_p, img_dst);<br />
    cvShowImage(winNameCapture, img_dst);<br />
    cvCopy(img_gray, img_gray_p);<br />
    if (cvWaitKey(10) == 'q') break;<br />
  }<br />
  <br />
  cvReleaseCapture(&amp;capture);<br />
  cvDestroyWindow(winNameCapture);<br />
  <br />
  return 0;<br />
}<br />
<br />
void detect_flow(IplImage *src_img1, IplImage *src_img2, IplImage *dst_img){<br />
  int i, j, dx, dy, rows, cols;<br />
  int block_size = 24;<br />
  int shift_size = 10;<br />
  CvMat *velx, *vely;<br />
  CvSize block = cvSize(block_size, block_size);<br />
  CvSize shift = cvSize(shift_size, shift_size);<br />
  CvSize max_range = cvSize(50, 50);<br />
<br />
  rows = int(ceil (double (src_img1-&gt;height) / block_size));<br />
  cols = int(ceil (double (src_img1-&gt;width) / block_size));<br />
  velx = cvCreateMat(rows, cols, CV_32FC1);<br />
  vely = cvCreateMat(rows, cols, CV_32FC1);<br />
  cvSetZero(velx);<br />
  cvSetZero(vely);<br />
<br />
  cvCalcOpticalFlowBM(src_img1, src_img2, block, shift, max_range, 0, velx, vely);<br />
  string result_str = string("");<br />
  for (i = 0; i &lt; velx-&gt;width; i++) {<br />
    for (j = 0; j &lt; vely-&gt;height; j++) {<br />
      dx = (int)cvGetReal2D(velx, j, i);<br />
      dy = (int)cvGetReal2D(vely, j, i);<br />
      cvLine(dst_img, cvPoint(i * block_size, j * block_size),<br />
              cvPoint(i * block_size + dx, j * block_size + dy), CV_RGB(255, 0, 0), 1, CV_AA, 0);<br />
      if(dx != 0 || dy != 0){<br />
	result_str += str(format("[%d,%d,%d,%d]") % (i*block_size) % (j*block_size) % dx % dy);<br />
      }<br />
    }<br />
  }<br />
  if(result_str.size() &gt; 0){<br />
    result_str = str(format("opticalflow %s") % result_str);<br />
    cout &lt;&lt; result_str &lt;&lt; endl;<br />
    zmq::message_t msg(result_str.size()+1); // ZeroMQ<br />
    memcpy(msg.data(), result_str.c_str(), result_str.size()+1);<br />
    sock.send(msg);<br />
  }<br />
}<br />
</pre>
<br />
<br />
<pre>
g++ -O opticalflow_pub.cpp -o opticalflow_pub.bin -I/opt/local/include/opencv -lcv -lcvaux -lcxcore -lhighgui  -I/usr/local/include /usr/local/lib/libzmq.a<br />
</pre>
<br />
<br />
これで動いた座標とその方向 [x,y,dx,dy] が連続で送られてくる。<br />
<pre>
opticalflow [48,216,4,-29][72,216,0,-29][96,216,0,-29][264,216,-9,-29]<br />
opticalflow [48,216,4,-29][96,216,0,-29][120,216,0,-29][264,216,-9,-29]<br />
opticalflow [48,216,4,-29][96,168,0,10][96,192,-10,-20][96,216,0,-29][120,192,0,10][120,216,0,-29][144,216,0,-29][168,216,0,-29][192,48,-10,0][192,216,0,-29][216,216,0,-29][264,216,-9,-29]<br />
opticalflow [96,168,0,10][96,192,-10,-10][96,216,0,-29][120,168,0,10][120,192,0,10][120,216,0,-29][144,216,0,-29][168,48,0,10][168,96,0,10][168,216,0,-29][192,72,0,40][192,96,0,-30][192,216,0,-29][264,216,-9,-29]<br />
opticalflow [48,216,4,-29][96,168,0,10][96,216,0,-29][120,168,0,10][120,192,0,10][120,216,0,-29][144,216,0,-29][168,48,10,0][168,96,0,10][168,216,0,-29][192,96,0,-30][192,216,0,-29][264,216,-9,-29]<br />
</pre>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5311/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mongoid使ってみる</title>
		<link>http://shokai.org/blog/archives/5300</link>
		<comments>http://shokai.org/blog/archives/5300#comments</comments>
		<pubDate>Tue, 10 Aug 2010 14:12:55 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[mongoid]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5300</guid>
		<description><![CDATA[
mongo単体で使ってみててだいたい分かったので、mongoidというmapperを使ってみる。

mongoidの良いのは

  default値を入れておきたい場合も簡単に書ける。created_atとか。
  _ [...]]]></description>
			<content:encoded><![CDATA[<p>
mongo単体で使ってみててだいたい分かったので、mongoidというmapperを使ってみる。<br />
<br />
mongoidの良いのは<br />
<ul>
  <li>default値を入れておきたい場合も簡単に書ける。created_atとか。</li>
  <li>_idでdocumentを取り出すとき、素のmongoだとcollection.find_one(BSON::ObjectID(id))とかしないとならないけどmongoidだと_idに文字列でID入れればいい</li>
</ul>
とかがぱっと使ってみて思った。。<br />
そもそもこういうのmongoの機能にあるかもしれないけど。<br />
<br />
<br />
■ドキュメント<br />
<ul>
  <li><a href="http://d.hatena.ne.jp/shokai/20100709/1278649322">mongodbインストール &#8211; 橋本詳解</a> Macにインストールした</li>
  <li><a href="http://d.hatena.ne.jp/shokai/20100710/1278745488">Rubyからmongo使う &#8211; 橋本詳解</a></li>
  <li><a href="http://www.mongodb.org/display/DOCS/Ruby+Tutorial">Ruby Tutorial &#8211; MongoDB</a></li>
  <li><a href="http://api.mongodb.org/ruby/1.0.7/">MongoRuby-1.0.7</a> mongoドライバのドキュメント</li>
  <li><a href="http://d.hatena.ne.jp/babie/20100805/1280982678">ハンズオンで分かる MongoDB チュートリアル &#8211; ζ*’ワ’)ζ＜ちれすですの！</a> mongoのコンソールから使う</li>
  <li><a href="http://mongoid.org/docs/documents/">Mongoid Documentation: Documents</a> mongoid公式ドキュメント</li>
  <li><a href="http://d.hatena.ne.jp/babie/20100809/1281316973">Rails3 対応 MongoDB ORM、Mongoid 詳解―ドキュメント &#8211; ζ*’ワ’)ζ＜ちれすですの！</a> 公式ドキュメント翻訳中。すげー。</li>
</ul>
<br />
<br />
■インストール<br />
<pre>
sudo gem install mongoid<br />
</pre>
1.9.1を使う。&#8211;pre付けるとRails3対応の2.x系統が入る。<br />
<br />
<br />
■modelを作る<br />
適当にperson class作って、Mongoid::Documentにする<br />
<br />
person.rb<br />
<pre class="prettyprint">
require 'rubygems'<br />
<br />
class Person<br />
  include Mongoid::Document<br />
  field :fullname # 指定無しでtype=&gt;stringになる<br />
  field :username<br />
  field :age, :type =&gt; Integer<br />
  field :created_at, :type =&gt; DateTime, :default =&gt; Time.now<br />
end<br />
</pre>
string以外は型指定する。型はArray, BigDecimal, Boolean, Date, DateTime, Float, Integer, String, Symbol, Timeがある。<br />
→ <a href="http://mongoid.org/docs/documents/">Mongoid Documentation: Documents</a><br />
<br />
defaultで現在時刻を入れるようにした。<br />
<br />
<br />
■mongodbへ接続<br />
Mongoid.configureのブロック内で接続する。<br />
conf.masterに普通のmongoで接続してdbを指定した時の返り値(<a href="http://api.mongodb.org/ruby/1.0.7/Mongo/DB.html">Mongo::DB</a>オブジェクト)を与えれば、mongoidで使える。<br />
<pre class="prettyprint">
require&amp;nbsp;'rubygems'<br />
require&amp;nbsp;'mongoid'<br />
require&amp;nbsp;File.dirname(__FILE__)+'/person'<br />
<br />
Mongoid.configure&amp;nbsp;do&amp;nbsp;|conf|<br />
&amp;nbsp;&amp;nbsp;conf.master&amp;nbsp;=&amp;nbsp;Mongo::Connection.new('localhost',&amp;nbsp;27017).db('mongoid-test')<br />
end<br />
</pre>
<br />
<br />
<br />
■modelの操作<br />
新しいpersonオブジェクト作って保存<br />
<pre class="prettyprint">
person = Person.new(:fullname =&gt; 'sho hashimoto',<br />
                    :username =&gt; 'shokai',<br />
                    :age =&gt; 25)<br />
<br />
puts person.fullname<br />
puts person.age<br />
<br />
person.save<br />
</pre>
<br />
<br />
保存されてるか、mongoのコンソールで確かめる<br />
personで保存したら、自動的に複数形のpeopleになってた。ActiveRecordっぽい。<br />
<pre class="prettyprint">
% mongo<br />
MongoDB&amp;nbsp;shell&amp;nbsp;version:&amp;nbsp;1.4.4<br />
url:&amp;nbsp;test<br />
connecting&amp;nbsp;to:&amp;nbsp;test<br />
type&amp;nbsp;"help"&amp;nbsp;for&amp;nbsp;help<br />
&gt;&amp;nbsp;show&amp;nbsp;dbs<br />
admin<br />
chirpstream_shokai<br />
local<br />
mongoid-test<br />
people<br />
povietest<br />
test<br />
testdb<br />
&gt;&amp;nbsp;use&amp;nbsp;mongoid-test<br />
switched&amp;nbsp;to&amp;nbsp;db&amp;nbsp;mongoid-test<br />
&gt;&amp;nbsp;show&amp;nbsp;collections<br />
people<br />
system.indexes<br />
&gt;&amp;nbsp;db.people.find()<br />
{&amp;nbsp;"_id"&amp;nbsp;:&amp;nbsp;"4c61463c2f7306e9fe000001",&amp;nbsp;"created_at"&amp;nbsp;:&amp;nbsp;"Tue&amp;nbsp;Aug&amp;nbsp;10&amp;nbsp;2010&amp;nbsp;21:29:48&amp;nbsp;GMT+0900&amp;nbsp;(JST)",&amp;nbsp;"fullname"&amp;nbsp;:&amp;nbsp;"sho&amp;nbsp;hashimoto",&amp;nbsp;"username"&amp;nbsp;:&amp;nbsp;"shokai",&amp;nbsp;"age"&amp;nbsp;:&amp;nbsp;25&amp;nbsp;}<br />
{&amp;nbsp;"_id"&amp;nbsp;:&amp;nbsp;"4c614d652f73060653000001",&amp;nbsp;"created_at"&amp;nbsp;:&amp;nbsp;"Tue&amp;nbsp;Aug&amp;nbsp;10&amp;nbsp;2010&amp;nbsp;22:00:21&amp;nbsp;GMT+0900&amp;nbsp;(JST)",&amp;nbsp;"fullname"&amp;nbsp;:&amp;nbsp;"sho&amp;nbsp;hashimoto",&amp;nbsp;"username"&amp;nbsp;:&amp;nbsp;"shokai",&amp;nbsp;"age"&amp;nbsp;:&amp;nbsp;25&amp;nbsp;}<br />
</pre>
2回保存したから複数保存されてた<br />
<br />
<br />
■find<br />
探す。<a href="http://mongoid.org/docs/querying/">Mongoid Documentation: Querying</a>にqueryの書き方が載ってる。<br />
適当にユーザ名shokaiの最初の一件を取得して、表示する<br />
<pre class="prettyprint">
person = Person.first(:conditions =&gt; {:username =&gt; 'shokai'})<br />
puts person._id<br />
puts person.username<br />
puts person.created_at<br />
</pre>
<br />
他にも、全件とか色々な書き方ができる。<br />
<pre class="prettyprint">
person = Person.find(:first, :conditions =&gt; {:username =&gt; 'shokai'})<br />
person = Person.all(:conditions =&gt; {:username =&gt; 'shokai'}).first<br />
person = Person.first(:conditions =&gt; {:_id =&gt; '4c61463c2f7306e9fe000001'})<br />
</pre>
allで検索したら結果が1件しか無くても、collectionで返ってくる。eachで回せる。<br />
<br />
<br />
<br />
■modelに書いてない値を入れてみる<br />
modelにない、person.placeを入れてみる<br />
<pre class="prettyprint">
person = Person.new(:fullname =&gt; 'sho hashimoto',<br />
                    :username =&gt; 'shokai',<br />
                    :age =&gt; 25,<br />
                    :place =&gt; 'fujisawa')<br />
<br />
puts person.fullname<br />
puts person.age<br />
puts person.place<br />
<br />
person.save<br />
</pre>
普通に入ってた。このへんは複数人でやるときは何か考えないとならないな。<br />
でもクロールしてきた値とかを適当にどんどん入れてしまうのにはすごくいい。twitterのchirp streamとか。<br />
<br />
<br />
数値はlt,gtで大なり小なり条件指定できるらしい。<br />
あとmongodbは空間型があるはずだけどそれは使えないのかな？filedの型になかったけど。<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5300/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JRubyでglitch iconを作る(2)</title>
		<link>http://shokai.org/blog/archives/5291</link>
		<comments>http://shokai.org/blog/archives/5291#comments</comments>
		<pubDate>Thu, 05 Aug 2010 23:46:05 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[glitch]]></category>
		<category><![CDATA[glitchicon]]></category>
		<category><![CDATA[javax.imageio]]></category>
		<category><![CDATA[JRuby]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[Twitter]]></category>
		<category><![CDATA[画像処理]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5291</guid>
		<description><![CDATA[
プラグイン機構を採用し、ランダムにいろいろ作れるようにしてみた。
普通はjpegとかのバイナリを直接いじるみたいだけどよく分からないのでJRubyでjavax.imageioを使ってやっている。

ランダムに96個作っ [...]]]></description>
			<content:encoded><![CDATA[<p>
プラグイン機構を採用し、ランダムにいろいろ作れるようにしてみた。<br />
普通はjpegとかのバイナリを直接いじるみたいだけどよく分からないのでJRubyでjavax.imageioを使ってやっている。<br />
<br />
ランダムに96個作ってみて8&#215;12に敷き詰めてみたのがこれ。<br />
で、定期的にランダムに作って<a href="http://twitter.com/shokai">twitterのアイコンとしてアップロードしてる</a>。<br />
<a href="http://www.flickr.com/photos/shokai/4861585419/" title="montage96 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4123/4861585419_d3310346ec_b.jpg" width="694" height="1024" alt="montage96" /></a><br />
敷き詰めるのはImageMagickと一緒にインストールされるmontageコマンドでできる <a href="http://d.hatena.ne.jp/shokai/20100803/1280785691">montageコマンド &#8211; 橋本詳解</a><br />
<br />
ソースコードは全て<a href="http://github.com/shokai/glitchicon">githubに置いた</a>。<br />
<br />
<br />
■仕組み<br />
単機能モジュールをランダムに連結する事である程度ランダムな画像を生成できる。<br />
javax.imageio.BufferedImageのインスタンスを受け取り、少し加工して返すというJRubyのmoduleをプラグインとし、それらを<a href="http://github.com/shokai/glitchicon/blob/master/glitch.rb">Glitch</a>というclassがランダムに呼び出す。<br />
<br />
<br />
今のところプラグインは23種類ある。単体だとそれほど派手にはならない。<br />
<a href="http://www.flickr.com/photos/shokai/4862180974/" title="glitchicon montage by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4118/4862180974_296b734bd0.jpg" width="500" height="492" alt="glitchicon montage" /></a><br />
<br />
<br />
<br />
■プラグイン<br />
<a href="http://github.com/shokai/glitchicon/tree/master/plugins/">http://github.com/shokai/glitchicon/tree/master/plugins/</a>にある。<br />
pluginが動くルールはこれ。<br />
<ul>
  <li><a href="http://github.com/shokai/glitchicon/tree/master/plugins/">pluginsディレクトリ</a>の中に置いておく</li>
  <li>ファイル名末尾が.rbである</li>
  <li>JRubyのmoduleである</li>
  <li>ファイル名の先頭1文字を大文字にしたmodule名である</li>
  <li>BufferedImageを受け取って、同じサイズのBufferedImageを返す glitch(BufferedImage) というstatic methodを持つ</li>
  <li>受け取ったBufferedImageに対しては破壊的に処理しても、そうでなくてもいい</li>
</ul>
<br />
プラグインはBufferedImageの処理に集中できるように、他の事は<a href="http://github.com/shokai/glitchicon/blob/master/glitch.rb">glitch.rb</a>がやる。<br />
<br />
<br />
どのプラグインも簡単にできている。30行ぐらい。<br />
<br />
<a href="http://github.com/shokai/glitchicon/blob/master/plugins/drumroll_vertical.rb">drumroll_vertical</a>プラグインの場合（画像では一番左、下から2番目）<br />
<pre class="prettyprint">
#!/usr/bin/env&nbsp;jruby<br />
require&nbsp;'java'<br />
import&nbsp;'java.lang.System'<br />
import&nbsp;'javax.imageio.ImageIO'<br />
import&nbsp;'java.awt.image.BufferedImage'<br />
<br />
<br />
module&nbsp;Drumroll_vertical<br />
<br />
&nbsp;&nbsp;def&nbsp;Drumroll_vertical.glitch(img)<br />
&nbsp;&nbsp;&nbsp;&nbsp;img_result&nbsp;=&nbsp;BufferedImage.new(img.width,&nbsp;img.height,&nbsp;img.type)<br />
&nbsp;&nbsp;&nbsp;&nbsp;roll&nbsp;=&nbsp;0<br />
&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;x&nbsp;in&nbsp;0...img.width&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;roll&nbsp;=&nbsp;rand(img.height)&nbsp;if&nbsp;rand&nbsp;&gt;&nbsp;0.95<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;roll&nbsp;=&nbsp;0&nbsp;if&nbsp;rand&nbsp;&gt;&nbsp;0.95<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;y&nbsp;in&nbsp;0...img.height&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;img.get_rgb(x,&nbsp;y)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y2&nbsp;=&nbsp;y+roll<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y2&nbsp;-=&nbsp;img.height&nbsp;if&nbsp;y2&nbsp;&gt;&nbsp;img.height-1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img_result.set_rgb(x,&nbsp;y2,&nbsp;pix)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;img_result<br />
&nbsp;&nbsp;end<br />
<br />
end<br />
</pre>
ランダムに縦に区切って、ランダムにスロットのドラムみたいにずらす。<br />
<br />
<br />
色を反転させる<a href="http://github.com/shokai/glitchicon/blob/master/plugins/color_reverse.rb">color_reverse</a>プラグイン<br />
<pre class="prettyprint">
#!/usr/bin/env&nbsp;jruby<br />
require&nbsp;'java'<br />
import&nbsp;'java.lang.System'<br />
import&nbsp;'javax.imageio.ImageIO'<br />
import&nbsp;'java.awt.image.BufferedImage'<br />
<br />
<br />
module&nbsp;Color_reverse<br />
<br />
&nbsp;&nbsp;def&nbsp;Color_reverse.glitch(img)<br />
&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;y&nbsp;in&nbsp;0...img.height&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;x&nbsp;in&nbsp;0...img.width&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;img.get_rgb(x,&nbsp;y)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;pix&nbsp;&gt;&gt;&nbsp;16&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;=&nbsp;pix&nbsp;&gt;&gt;&nbsp;8&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;pix&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;256-r<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;=&nbsp;256-g<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;256-b<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;((r&nbsp;&lt;&lt;&nbsp;16)&amp;0xFF0000&nbsp;|&nbsp;(g&nbsp;&lt;&lt;&nbsp;8)&amp;0xFF00&nbsp;|&nbsp;b)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.set_rgb(x,y,&nbsp;pix)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;img<br />
&nbsp;&nbsp;end<br />
<br />
end<br />
</pre>
<br />
<br />
量子化した後に輪郭抽出する<a href="http://github.com/shokai/glitchicon/blob/master/plugins/quantize_contour.rb">quantize_contour</a><br />
<pre class="prettyprint">
#!/usr/bin/env&nbsp;jruby<br />
require&nbsp;'java'<br />
import&nbsp;'java.lang.System'<br />
import&nbsp;'javax.imageio.ImageIO'<br />
import&nbsp;'java.awt.image.BufferedImage'<br />
<br />
<br />
module&nbsp;Quantize_contour<br />
<br />
&nbsp;&nbsp;def&nbsp;Quantize_contour.glitch(img)<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;y&nbsp;in&nbsp;0...img.height&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;x&nbsp;in&nbsp;0...img.width&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;img.get_rgb(x,&nbsp;y)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;pix&nbsp;&gt;&gt;&nbsp;16&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;=&nbsp;pix&nbsp;&gt;&gt;&nbsp;8&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;pix&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gray&nbsp;=&nbsp;(r+g+b)/3<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;quant&nbsp;=&nbsp;gray&nbsp;&amp;&nbsp;0xC0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;((quant&nbsp;&lt;&lt;&nbsp;16)&amp;0xFF0000&nbsp;|&nbsp;(quant&nbsp;&lt;&lt;&nbsp;8)&amp;0xFF00&nbsp;|&nbsp;quant)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.set_rgb(x,&nbsp;y,&nbsp;pix)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;img_result&nbsp;=&nbsp;BufferedImage.new(img.width,&nbsp;img.height,&nbsp;img.type)<br />
&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;y&nbsp;in&nbsp;1...img.height-1&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;x&nbsp;in&nbsp;1...img.width-1&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;img.get_rgb(x,&nbsp;y)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;around&nbsp;=&nbsp;(img.get_rgb(x-1,y)+img.get_rgb(x+1,y)+img.get_rgb(x,y-1)+img.get_rgb(x,y+1))/4<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;around&nbsp;&lt;&nbsp;pix<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;0xFFFFFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img_result.set_rgb(x,&nbsp;y,&nbsp;pix)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;img_result<br />
&nbsp;&nbsp;end<br />
<br />
end<br />
</pre>
<br />
<br />
そんなかんじ。画像をいじるけど、元の画像を知っている人なら元画像を思い浮かべられる程度にglitchしたい。<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5291/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JRubyでglitch iconを作る</title>
		<link>http://shokai.org/blog/archives/5283</link>
		<comments>http://shokai.org/blog/archives/5283#comments</comments>
		<pubDate>Sun, 01 Aug 2010 19:44:15 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[glitch]]></category>
		<category><![CDATA[javax.imageio]]></category>
		<category><![CDATA[JRuby]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[画像処理]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5283</guid>
		<description><![CDATA[
こういうのをtwitter iconにしたかった



Twitter のアイコンの目を光らせるライフハック &#8211; 地獄の猫日記を参考にアニメgifを作った。末尾も3C2Cにした。

でもちょうど今日からtw [...]]]></description>
			<content:encoded><![CDATA[<p>
こういうのをtwitter iconにしたかった<br />
<img src="http://shokai.org/tmp/glitchicon.gif" /><img src="http://shokai.org/tmp/glitchicon2.gif" />
<br />
<br />
<a href="http://d.hatena.ne.jp/nokturnalmortum/20100702/1277999623">Twitter のアイコンの目を光らせるライフハック &#8211; 地獄の猫日記</a>を参考にアニメgifを作った。末尾も3C2Cにした。<br />
<br />
でもちょうど今日からtwitterがGIFアニメアイコンのチェックを厳しくしたらしく、最初の1フレームだけの静止アイコンになってしまう。<br />
既にアップされている他の人のアイコンを見ると、3C00002Cとかになってるのもあったけど色々ためしたけどやっぱりアップロードすると静止画像になる。<br />
<br />
<br />
画像を生成するスクリプト<br />
jrubyでjavax.imageioを使うと簡単。<br />
最後のあたりのコメントアウトしているconvertかffmpegどちらでも、アニメーションgifを作れる。<br />
glitchicon.rb<br />
<pre class="prettyprint">
#!/usr/bin/env&nbsp;jruby<br />
require&nbsp;'java'<br />
import&nbsp;'java.lang.System'<br />
import&nbsp;'javax.imageio.ImageIO'<br />
import&nbsp;'java.awt.image.BufferedImage'<br />
<br />
if&nbsp;ARGV.size&nbsp;&lt;&nbsp;2<br />
&nbsp;&nbsp;STDERR.puts&nbsp;'require&nbsp;:&nbsp;input&nbsp;file&nbsp;and&nbsp;output&nbsp;dir'<br />
&nbsp;&nbsp;STDERR.puts&nbsp;'jruby&nbsp;glitchicon.rb&nbsp;/path/to/img.jpg&nbsp;/path/to/out/'<br />
&nbsp;&nbsp;exit&nbsp;1<br />
end<br />
<br />
img_in&nbsp;=&nbsp;ImageIO.read(java.io.File.new(ARGV.shift))<br />
out_dir&nbsp;=&nbsp;ARGV.shift<br />
out_dir&nbsp;+=&nbsp;'/'&nbsp;unless&nbsp;out_dir&nbsp;=~&nbsp;/\/$/<br />
<br />
puts&nbsp;"#{img_in.width}x#{img_in.height}"<br />
<br />
for&nbsp;i&nbsp;in&nbsp;1..10<br />
&nbsp;&nbsp;img&nbsp;=&nbsp;BufferedImage.new(img_in.width,&nbsp;img_in.height,&nbsp;img_in.type);<br />
&nbsp;&nbsp;img.graphics.drawImage(img_in,&nbsp;0,&nbsp;0,&nbsp;nil)<br />
&nbsp;&nbsp;shifts&nbsp;=&nbsp;[0,0,0]<br />
&nbsp;&nbsp;for&nbsp;y&nbsp;in&nbsp;0...img.height&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;rand&nbsp;&gt;&nbsp;0.85<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shifts&nbsp;=&nbsp;shifts.map{|j|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j&nbsp;=&nbsp;rand(255)-128<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;x&nbsp;in&nbsp;0...img.width&nbsp;do<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;img.get_rgb(x,&nbsp;y)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;pix&nbsp;&gt;&gt;&nbsp;16&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;=&nbsp;pix&nbsp;&gt;&gt;&nbsp;8&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;pix&nbsp;&amp;&nbsp;0xFF<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;+=&nbsp;shifts[0]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;+=&nbsp;shifts[1]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;+=&nbsp;shifts[2]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;255&nbsp;if&nbsp;r&nbsp;&gt;&nbsp;255<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;=&nbsp;255&nbsp;if&nbsp;g&nbsp;&gt;&nbsp;255<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;255&nbsp;if&nbsp;b&nbsp;&gt;&nbsp;255<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r&nbsp;=&nbsp;0&nbsp;if&nbsp;r&nbsp;&lt;&nbsp;0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g&nbsp;=&nbsp;0&nbsp;if&nbsp;g&nbsp;&lt;&nbsp;0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;0&nbsp;if&nbsp;b&nbsp;&lt;&nbsp;0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pix&nbsp;=&nbsp;((r&nbsp;&lt;&lt;&nbsp;16)&amp;0xFF0000&nbsp;|&nbsp;(g&nbsp;&lt;&lt;&nbsp;8)&amp;0xFF00&nbsp;|&nbsp;b)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"#{r},#{g},#{b}"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img.set_rgb(x,y,&nbsp;pix)<br />
&nbsp;&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;out_name&nbsp;=&nbsp;"#{out_dir}#{i}.bmp"<br />
&nbsp;&nbsp;ImageIO.write(img,&nbsp;'bmp',&nbsp;java.io.File.new(out_name))<br />
&nbsp;&nbsp;puts&nbsp;out_name<br />
end<br />
<br />
puts&nbsp;`convert&nbsp;#{out_dir}*.bmp&nbsp;#{out_dir}out.gif`<br />
#puts&nbsp;`ffmpeg&nbsp;-y&nbsp;-i&nbsp;#{out_dir}%d.bmp&nbsp;-s&nbsp;100x100&nbsp;-pix_fmt&nbsp;rgb24&nbsp;-loop_output&nbsp;0&nbsp;-sameq&nbsp;#{out_dir}out.gif`<br />
<br />
open("#{out_dir}out.gif"){|gif|<br />
&nbsp;&nbsp;bytes&nbsp;=&nbsp;gif.read.unpack('H*')<br />
&nbsp;&nbsp;bytes&nbsp;=&nbsp;[bytes.first.gsub!(/3b$/,'3c2c')]<br />
&nbsp;&nbsp;open("#{out_dir}glitchicon.gif",'w+'){|out|<br />
&nbsp;&nbsp;&nbsp;&nbsp;out.write(bytes.pack('H*'))<br />
&nbsp;&nbsp;}<br />
}<br />
</pre>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5283/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PSoC &#8211; CY8C29466の14ビットADコンバータを内蔵マルチプレクサで切り替えて複数ピンで使う</title>
		<link>http://shokai.org/blog/archives/5272</link>
		<comments>http://shokai.org/blog/archives/5272#comments</comments>
		<pubDate>Wed, 28 Jul 2010 08:59:54 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[AD変換]]></category>
		<category><![CDATA[CY8C29466]]></category>
		<category><![CDATA[C言語]]></category>
		<category><![CDATA[PSoC]]></category>
		<category><![CDATA[PSoCDesigner]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[UART]]></category>
		<category><![CDATA[マルチプレクサ]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5272</guid>
		<description><![CDATA[
14ビットのADコンバータ1つと、AMUX4（4チャンネルアナログマルチプレクサ）を組み合わせると複数のピンからAD変換が使える。
というかPSoC Designer4.xでADCINC12を使っていた頃は、ADCIN [...]]]></description>
			<content:encoded><![CDATA[<p>
14ビットのADコンバータ1つと、AMUX4（4チャンネルアナログマルチプレクサ）を組み合わせると複数のピンからAD変換が使える。<br />
というかPSoC Designer4.xでADCINC12を使っていた頃は、ADCINC12を複数置くことができたのにPSoC Designer5.0では1つしか配置できなくて困った。<br />
でもよく考えたらマルチプレクサ使う方が自然だな。<br />
<br />
<br />
アナログブロックの接続<br />
マルチプレクサを切り替えるとPort0の0,2,4,6番ピンに接続できる<br />
<a href="http://www.flickr.com/photos/shokai/4836580419/" title="cfab931ebc6fd7a15179e8377e1a847c by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4131/4836580419_bd54c7567e.jpg" width="500" height="304" alt="cfab931ebc6fd7a15179e8377e1a847c" /></a><br />
<br />
<br />
ピン配置<br />
右上のADC以外は関係ない<br />
<a href="http://www.flickr.com/photos/shokai/4837186870/" title="e9c55cbf49c94421f1ef6f24400f6531 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4154/4837186870_88508c9306.jpg" width="438" height="500" alt="e9c55cbf49c94421f1ef6f24400f6531" /></a><br />
<br />
<br />
PGAの設定<br />
1.0倍で、AMUXがあるアナログマルチプレクサ1に接続する。<br />
<a href="http://www.flickr.com/photos/shokai/4837157512/" title="e838b8bcea333aaa21f7249301632629 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4110/4837157512_6f3b389252.jpg" width="441" height="142" alt="e838b8bcea333aaa21f7249301632629" /></a><br />
<br />
<br />
ADCINCの設定<br />
Negative Inputのソースは一応指定するが、GainをDisconnectedにすると使わないようにできる。<br />
<a href="http://www.flickr.com/photos/shokai/4837160624/" title="5f959013ed6c5d34154921a08c1cf097 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4151/4837160624_2a17d92549.jpg" width="441" height="203" alt="5f959013ed6c5d34154921a08c1cf097" /></a><br />
<br />
<br />
AMUX4の設定<br />
Interconnect Viewには表示されないけど、配置はされてる。アナログマルチプレクサ1として設定する。<br />
<a href="http://www.flickr.com/photos/shokai/4837155526/" title="ff18fb9db0458d481244adfc38113cfb by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4132/4837155526_c77be299d4.jpg" width="439" height="86" alt="ff18fb9db0458d481244adfc38113cfb" /></a><br />
<br />
<br />
AMUX4の他にも8もあるので、まあたくさん増やせる。<br />
<br />
<br />
UARTのTX8で、14bitADCINCの値を送る。<br />
TX8だけを使う設定は<a href="http://shokai.org/blog/archives/4519">橋本商会 ≫ PSoC &#8211; TX8モジュール</a>に書いた<br />
<pre class="prettyprint">
void&nbsp;wait(int&nbsp;n){<br />
&nbsp;&nbsp;&nbsp;&nbsp;while(n--);<br />
}<br />
<br />
//&nbsp;AMUX4_PORT0_0&nbsp;=&gt;&nbsp;0x00<br />
//&nbsp;AMUX4_PORT0_2&nbsp;=&gt;&nbsp;0x01<br />
//&nbsp;AMUX4_PORT0_4&nbsp;=&gt;&nbsp;0x02<br />
//&nbsp;AMUX4_PORT0_6&nbsp;=&gt;&nbsp;0x03<br />
int&nbsp;get_adc(BYTE&nbsp;amux_channel){<br />
&nbsp;&nbsp;&nbsp;&nbsp;AMUX4_InputSelect(amux_channel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;wait(10);<br />
&nbsp;&nbsp;&nbsp;&nbsp;ADCINC_GetSamples(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;while(!ADCINC_fIsDataAvailable());<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;ADCINC_iClearFlagGetData();<br />
}<br />
<br />
int&nbsp;ad;<br />
BYTE&nbsp;ad_pin;<br />
char&nbsp;buf[6];<br />
<br />
void&nbsp;main(void){<br />
&nbsp;&nbsp;&nbsp;&nbsp;M8C_EnableGInt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;AMUX4_Start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;PGA_1_Start(PGA_1_HIGHPOWER);<br />
&nbsp;&nbsp;&nbsp;&nbsp;ADCINC_Start(ADCINC_HIGHPOWER);<br />
&nbsp;&nbsp;&nbsp;&nbsp;TX8_Start(TX8_PARITY_NONE);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(;;){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(ad_pin&nbsp;=&nbsp;0;&nbsp;ad_pin&nbsp;&lt;&nbsp;4;&nbsp;ad_pin++){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ad&nbsp;=&nbsp;get_adc(ad_pin);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TX8_PutChar(ad_pin+'0');<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TX8_CPutString(":");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TX8_PutString(intToStr(ad,buf));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TX8_PutCRLF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</pre>
AMUX4を切り替えた直後にAD変換を開始するのがなんとなく嫌だった（物理的に回路が切り替わっているわけだし）ので、一瞬waitを入れてからAD変換するようにした。<br />
<br />
<br />
<br />
string.hのitoa関数がおかしいので代わりを作った<br />
<pre class="prettyprint">
//&nbsp;intの桁数を返す<br />
char&nbsp;getDigit(int&nbsp;n){<br />
&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;i&nbsp;=&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;while(n&gt;0){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n&nbsp;/=&nbsp;10;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;i;<br />
}<br />
<br />
//&nbsp;int-&gt;String変換<br />
//&nbsp;char&nbsp;buf[6]<br />
char&nbsp;*intToStr(int&nbsp;n,&nbsp;char&nbsp;*buf){&nbsp;//&nbsp;変換する数、作業領域<br />
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;i,&nbsp;digit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;digit&nbsp;=&nbsp;getDigit(n);&nbsp;//&nbsp;桁数<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(i&nbsp;=&nbsp;digit-1;&nbsp;i&nbsp;&gt;=&nbsp;0;&nbsp;i--){&nbsp;//&nbsp;intは最大5桁<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf[i]&nbsp;=&nbsp;n%10+'0';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;n&nbsp;/=&nbsp;10;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;buf[digit]&nbsp;=&nbsp;'\0';&nbsp;//&nbsp;行末<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;buf;<br />
}<br />
</pre>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5272/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenCVで画像サイズを求めるgearman workerをdaemontoolsで管理する</title>
		<link>http://shokai.org/blog/archives/5254</link>
		<comments>http://shokai.org/blog/archives/5254#comments</comments>
		<pubDate>Sun, 25 Jul 2010 16:02:54 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[gearman]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[json_builder.h]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5254</guid>
		<description><![CDATA[
OpenCVで画像のサイズを求めるgearman workerを作って、Rubyから呼ぶで作ったworkerをpreforkさせて、そいつらをdaemontoolsで管理できるようにした。あらかじめCPU個数+いくつか [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://shokai.org/blog/archives/4987">OpenCVで画像のサイズを求めるgearman workerを作って、Rubyから呼ぶ</a>で作ったworkerをpreforkさせて、そいつらをdaemontoolsで管理できるようにした。あらかじめCPU個数+いくつかforkしておくと、CPUが複数あるマシンを生かせるし、解析前にlibcurlで画像を取得している時のI/O待ちが少なくなって良い。（この記事のworkerはlibcurl使ってない版だけど）<br />
あと、返り値は自分で作った<a href="http://github.com/shokai/json_builder-cpp">json_builder.h</a>を使って返すようにした。<br />
<br />
なにげに大量の画像の中からダウンロード失敗した破損画像を見つけるのに重宝している。<br />
<br />
まずdaemontoolsをインストールしておく<br />
<ul>
  <li><a href="http://d.hatena.ne.jp/shokai/20100724/1279996402">Macにdaemontoolsインストール &#8211; 橋本詳解</a></li>
  <li><a href="http://d.hatena.ne.jp/shokai/20100725/1280014778">Ubuntu10.04にdaemontoolsインストール &#8211; 橋本詳解</a></li>
</ul>
gearmandもdaemontoolsで自動起動するようにしておく。<br />
<br />
<br />
daemontoolsで管理できるようにする。<br />
普通にforkしただけだと、daemontoolsでsvc -dしてプロセスを止めようとしてもforkした子プロセスの方が止まらない。<br />
<br />
Perlの場合の良い例があった。<br />
<a href="http://d.hatena.ne.jp/tokuhirom/20100201/1264989237">How to manage Gearman worker processes. &#8211; TokuLog 改メ tokuhirom’s blog</a><br />
<a href="http://search.cpan.org/~kazuho/Parallel-Prefork/lib/Parallel/Prefork.pm">Parallel::Prefork</a>を使っている。Parallel::Preforkのソースを読んでみたら、trap_signalsオプションで親プロセスがSIGTERMとSIGHUPをフックして、子プロセスにkillを送っていた。<br />
よく考えたら普通のforkで親が子を殺すというやつだった。<br />
<br />
<br />
Parallel::Preforkと同じ様にやる。<br />
forkした後親が子のpidのリストを持っておいて、SIGTERM/SIGHUPをフックして、子を全部killする処理を追加した。<br />
<br />
daemontoolsのrunスクリプトはこれ<br />
<pre class="prettyprint">
#!/bin/sh<br />
exec&nbsp;2&gt;&amp;1<br />
exec&nbsp;setuidgid&nbsp;sho&nbsp;/Users/sho/src/gearmand-study/imgsize/imgsizeWorker&nbsp;-s&nbsp;localhost&nbsp;-p&nbsp;7003&nbsp;--fork&nbsp;5<br />
</pre>
起動すると5個にプロセスが増える。親はdaemontoolsのsuperviseが管理してくれる。<br />
これでsvc -dとか-uとかすればまとめて起動終了するようになった。<br />
<br />
<a href="http://shokai.org/projects/gearman-study/index.cgi/file/6b0da8ba1769/imgsize/imgsizeWorker.cpp">imgsizeWorker.cpp</a><br />
<pre class="prettyprint">
//&nbsp;画像サイズを返すgearman&nbsp;worker<br />
#include&nbsp;&lt;stdio.h&gt;<br />
#include&nbsp;&lt;stdlib.h&gt;<br />
#include&nbsp;&lt;unistd.h&gt;<br />
#include&nbsp;&lt;signal.h&gt;<br />
#include&nbsp;&lt;string&gt;<br />
#include&nbsp;&lt;iostream&gt;<br />
#include&nbsp;&lt;cv.h&gt;<br />
#include&nbsp;&lt;highgui.h&gt;<br />
#include&nbsp;&lt;boost/program_options.hpp&gt;<br />
#include&nbsp;&lt;boost/regex.hpp&gt;<br />
#include&nbsp;&lt;boost/format.hpp&gt;<br />
#include&nbsp;&lt;boost/tuple/tuple.hpp&gt;<br />
#include&nbsp;&lt;boost/tuple/tuple_io.hpp&gt;<br />
#include&nbsp;&lt;boost/any.hpp&gt;<br />
#include&nbsp;&lt;libgearman/gearman.h&gt;<br />
#include&nbsp;"json_builder.h"<br />
<br />
using&nbsp;namespace&nbsp;boost;<br />
using&nbsp;namespace&nbsp;std;<br />
<br />
tuple&lt;int,&nbsp;int&gt;&nbsp;get_size(const&nbsp;string&amp;&nbsp;fileName);&nbsp;//&nbsp;画像のwidth,heightを返す<br />
map&lt;string,any&gt;&nbsp;imgsize(const&nbsp;string&amp;&nbsp;fileName);&nbsp;//&nbsp;gearman&nbsp;workerとしてclientに返すためのJSON&nbsp;Objectを作る<br />
void&nbsp;*job_imgsize(gearman_job_st&nbsp;*job,&nbsp;void&nbsp;*cb_arg,&nbsp;size_t&nbsp;*result_size,&nbsp;gearman_return_t&nbsp;*ret_ptr);<br />
void&nbsp;on_exit_signal(int&nbsp;sig);<br />
vector&lt;int&gt;&nbsp;pids;<br />
<br />
int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[])&nbsp;{<br />
&nbsp;&nbsp;program_options::options_description&nbsp;opts("options");<br />
&nbsp;&nbsp;opts.add_options()<br />
&nbsp;&nbsp;&nbsp;&nbsp;("help,h",&nbsp;"helpを表示")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("server,s",&nbsp;program_options::value&lt;string&gt;(),&nbsp;"gearmanサーバーのアドレス")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("port,p",&nbsp;program_options::value&lt;int&gt;(),&nbsp;"gearmanサーバーのport番号")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("fork",&nbsp;program_options::value&lt;int&gt;(),&nbsp;"preforkする数")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("test,t",&nbsp;program_options::value&lt;string&gt;(),&nbsp;"gearman&nbsp;worker単体テスト用query");<br />
&nbsp;&nbsp;program_options::variables_map&nbsp;argmap;<br />
&nbsp;&nbsp;program_options::store(parse_command_line(argc,&nbsp;argv,&nbsp;opts),&nbsp;argmap);<br />
&nbsp;&nbsp;program_options::notify(argmap);<br />
<br />
&nbsp;&nbsp;if(!argmap.count("help")){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(argmap.count("test")){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;"---test---"&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;gearman_param&nbsp;=&nbsp;argmap["test"].as&lt;string&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;json_builder::toJson(imgsize(gearman_param))&nbsp;&lt;&lt;&nbsp;endl;&nbsp;//&nbsp;単体でworkerとしてのテスト<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}else&nbsp;if(argmap.count("server")&nbsp;&amp;&amp;&nbsp;argmap.count("port")){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(argmap.count("fork")){<br />
	int&nbsp;i,&nbsp;pid;<br />
	for(i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;&nbsp;argmap["fork"].as&lt;int&gt;();&nbsp;i++){<br />
	&nbsp;&nbsp;pid&nbsp;=&nbsp;fork();<br />
	&nbsp;&nbsp;if(pid&nbsp;==&nbsp;0){&nbsp;//&nbsp;子プロセス<br />
	&nbsp;&nbsp;&nbsp;&nbsp;pids.clear();<br />
	&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
	&nbsp;&nbsp;}<br />
	&nbsp;&nbsp;else{&nbsp;//&nbsp;親プロセス<br />
	&nbsp;&nbsp;&nbsp;&nbsp;pids.push_back(pid);<br />
	&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;str(format("fork:%d&nbsp;-&nbsp;parent:%d&nbsp;child:%d")&nbsp;%&nbsp;<br />
			i&nbsp;%<br />
			getpid()&nbsp;%<br />
			pid)&nbsp;&lt;&lt;&nbsp;endl;<br />
	&nbsp;&nbsp;}<br />
	}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pids.size()&nbsp;&gt;&nbsp;0){&nbsp;//&nbsp;親プロセスの終了シグナルをフックする<br />
	signal(SIGTERM,&nbsp;on_exit_signal);<br />
	signal(SIGHUP,&nbsp;on_exit_signal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_st&nbsp;worker;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_create(&amp;worker);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;g_server&nbsp;=&nbsp;argmap["server"].as&lt;string&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;g_port&nbsp;=&nbsp;argmap["port"].as&lt;int&gt;();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;hostent&nbsp;*g_host&nbsp;=&nbsp;gethostbyname((char*)g_server.c_str());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;g_server_addr&nbsp;=&nbsp;str(format("%d.%d.%d.%d")&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[0]&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[1]&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[2]&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[3]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_add_server(&amp;worker,&nbsp;g_server_addr.c_str(),&nbsp;g_port);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_add_function(&amp;worker,&nbsp;"img_size",&nbsp;0,&nbsp;job_imgsize,&nbsp;NULL);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;str(format("---start&nbsp;worker&nbsp;(%s:%d)---")&nbsp;%<br />
		&nbsp;&nbsp;g_server_addr&nbsp;%&nbsp;g_port)&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(true)&nbsp;gearman_worker_work(&amp;worker);&nbsp;//&nbsp;workerとして待機<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;cerr&nbsp;&lt;&lt;&nbsp;"server,portが必要です"&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;cerr&nbsp;&lt;&lt;&nbsp;opts&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;return&nbsp;1;<br />
&nbsp;&nbsp;<br />
}<br />
<br />
//&nbsp;opencvで画像サイズを取得<br />
tuple&lt;int,&nbsp;int&gt;&nbsp;get_size(const&nbsp;string&amp;&nbsp;fileName){<br />
&nbsp;&nbsp;IplImage&nbsp;*img&nbsp;=&nbsp;cvLoadImage(fileName.c_str());<br />
&nbsp;&nbsp;if(!img){<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;make_tuple(-1,&nbsp;-1);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;width&nbsp;=&nbsp;img-&gt;width;<br />
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;height&nbsp;=&nbsp;img-&gt;height;<br />
&nbsp;&nbsp;&nbsp;&nbsp;cvReleaseImage(&amp;img);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;make_tuple(width,&nbsp;height);<br />
&nbsp;&nbsp;}<br />
}<br />
<br />
//&nbsp;画像サイズを取得してgearman&nbsp;serverに返すJSON&nbsp;Objectを作る<br />
map&lt;string,any&gt;&nbsp;imgsize(const&nbsp;string&amp;&nbsp;fileName){<br />
&nbsp;&nbsp;map&lt;string,any&gt;&nbsp;result_m;<br />
&nbsp;&nbsp;int&nbsp;width,&nbsp;height;<br />
&nbsp;&nbsp;tie(width,&nbsp;height)&nbsp;=&nbsp;get_size(fileName);<br />
&nbsp;&nbsp;if(width&nbsp;&gt;&nbsp;0&nbsp;&amp;&amp;&nbsp;height&nbsp;&gt;&nbsp;0){<br />
&nbsp;&nbsp;&nbsp;&nbsp;result_m["width"]&nbsp;=&nbsp;width;<br />
&nbsp;&nbsp;&nbsp;&nbsp;result_m["height"]&nbsp;=&nbsp;height;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;result_m["error"]&nbsp;=&nbsp;string("image&nbsp;load&nbsp;error");<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return&nbsp;result_m;<br />
}<br />
<br />
//&nbsp;gearman&nbsp;worker&nbsp;job<br />
void&nbsp;*job_imgsize(gearman_job_st&nbsp;*job,&nbsp;void&nbsp;*cb_arg,&nbsp;size_t&nbsp;*result_size,&nbsp;gearman_return_t&nbsp;*ret_ptr){<br />
&nbsp;&nbsp;string&nbsp;fileName&nbsp;=&nbsp;(char*)gearman_job_workload(job);<br />
&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;fileName&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;string&nbsp;result_str&nbsp;=&nbsp;json_builder::toJson(imgsize(fileName));<br />
&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;"&nbsp;=&gt;&nbsp;"&nbsp;&lt;&lt;&nbsp;result_str&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;char&nbsp;*result&nbsp;=&nbsp;(char*)strdup(result_str.c_str());<br />
&nbsp;&nbsp;*result_size&nbsp;=&nbsp;result_str.size();<br />
&nbsp;&nbsp;*ret_ptr&nbsp;=&nbsp;GEARMAN_SUCCESS;<br />
&nbsp;&nbsp;return&nbsp;result;<br />
}<br />
<br />
void&nbsp;on_exit_signal(int&nbsp;sig){<br />
&nbsp;&nbsp;for(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;pids.size();&nbsp;i++){<br />
&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;str(format("kill&nbsp;(pid:%d)")&nbsp;%&nbsp;pids[i])&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(kill(pids[i],&nbsp;SIGKILL)&nbsp;&lt;&nbsp;0){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cerr&nbsp;&lt;&lt;&nbsp;str(format("kill&nbsp;failed&nbsp;(pid:%d)")&nbsp;%&nbsp;pids[i])&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;exit(0);<br />
}<br />
</pre>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5254/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android &#8211; アプリの設定画面を作る</title>
		<link>http://shokai.org/blog/archives/5244</link>
		<comments>http://shokai.org/blog/archives/5244#comments</comments>
		<pubDate>Thu, 22 Jul 2010 20:06:46 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Intent]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5244</guid>
		<description><![CDATA[
画面遷移するアプリを作ったこと無かったのでやってみた。
AndroidではIntentで別のActivityを呼び出して画面遷移する。遷移ついでにIntentオブジェクトに値を入れて渡したり、返り値を受け取ったりする。 [...]]]></description>
			<content:encoded><![CDATA[<p>
画面遷移するアプリを作ったこと無かったのでやってみた。<br />
AndroidではIntentで別のActivityを呼び出して画面遷移する。遷移ついでにIntentオブジェクトに値を入れて渡したり、返り値を受け取ったりする。<br />
<br />
作った物はgithubに置いた<br />
<ul><li><a href="http://github.com/shokai/ActivitiesTest-android">shokai&apos;s ActivitiesTest-android at master &#8211; GitHub</a></li></ul>
<br />
<br />
■動作<br />
名前設定ボタンを押したらIntentで別のActivityに遷移して、そこで名前を設定する。保存(終了)すると前のActivityに戻る。もう一度やると、設定ActivityのEditTextの中身がさっき保存した値になっている。<br />
<a href="http://www.flickr.com/photos/shokai/4817057582/" title="device by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4123/4817057582_e9b4fac554.jpg" width="300" height="500" alt="device" /></a> <a href="http://www.flickr.com/photos/shokai/4816435391/" title="device2 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4114/4816435391_789df33ba9.jpg" width="300" height="500" alt="device2" /></a> <a href="http://www.flickr.com/photos/shokai/4816435421/" title="device3 by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4117/4816435421_2360e2099c.jpg" width="300" height="500" alt="device3" /></a><br />
<br />
<br />
<br />
■Activityを追加する<br />
<ol>
  <li>android.app.Activityを継承した新しいJavaクラスを追加する。ConfigActivity.javaにした。</li>
  <li>res/layout/ の中にレイアウト用XMLファイルを作る。既にあるmain.xmlをコピー&amp;リネームでいい。config.xmlにして<a href="http://github.com/shokai/ActivitiesTest-android/blob/master/res/layout/config.xml">中身を適当に編集</a>。</li>
  <li>レイアウトを.javaに読み込む。config.xmlを作った時点でresourceが更新されているので、onCreate関数の中で setContentView(R.layout.config); すればいい。<br />
</li>
  <li><a href="http://github.com/shokai/ActivitiesTest-android/blob/master/AndroidManifest.xml">AndroidManifest.xml</a>を編集、&lt;application&gt;&lt;/application&gt;の中に新しいActivity名を書く<br />
<pre class="prettyprint">
&lt;?xml&nbsp;version="1.0"&nbsp;encoding="utf-8"?&gt;<br />
&lt;manifest&nbsp;xmlns:android="http://schemas.android.com/apk/res/android"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;package="org.shokai"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;android:versionCode="1"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;android:versionName="1.0"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;application&nbsp;android:icon="@drawable/icon"&nbsp;android:label="@string/app_name"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;activity&nbsp;android:name=".MainActivity"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;android:label="@string/app_name"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;intent-filter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;action&nbsp;android:name="android.intent.action.MAIN"&nbsp;/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;category&nbsp;android:name="android.intent.category.LAUNCHER"&nbsp;/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/intent-filter&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/activity&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;activity&nbsp;android:name=".ConfigActivity"&nbsp;android:label="@string/app_name"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/activity&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/application&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;uses-sdk&nbsp;android:minSdkVersion="7"&nbsp;/&gt;<br />
<br />
&lt;/manifest&gt;&nbsp;<br />
</pre>
名前は .java ファイルの名前に合わせる。<br />
  </li>
</ol>
これでConfigActivityを呼び出す準備ができた。<br />
<br />
<br />
<br />
■ソースコード<br />
返り値が必要な場合はstartActivityForResultで呼び出す。第二引数の数値はrequest codeで、onActivityResultで返り値を受け取る時に同じ値が戻ってくるので本物かどうかチェックするのに使う。<br />
request codeは毎回違う値を生成した方がいいのかもしれない<br />
<a href="http://github.com/shokai/ActivitiesTest-android/blob/master/src/org/shokai/MainActivity.java">MainActivity.java</a><br />
<pre class="prettyprint">
package&nbsp;org.shokai;<br />
<br />
import&nbsp;android.app.Activity;<br />
import&nbsp;android.content.Intent;<br />
import&nbsp;android.os.Bundle;<br />
import&nbsp;android.view.View;<br />
import&nbsp;android.view.View.OnClickListener;<br />
import&nbsp;android.widget.*;<br />
<br />
public&nbsp;class&nbsp;MainActivity&nbsp;extends&nbsp;Activity&nbsp;implements&nbsp;OnClickListener{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Button&nbsp;buttonOpen;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Logger&nbsp;logger;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;TextView&nbsp;textViewName;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;String&nbsp;name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onCreate(Bundle&nbsp;savedInstanceState)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.onCreate(savedInstanceState);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setContentView(R.layout.main);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger&nbsp;=&nbsp;new&nbsp;Logger(this.getResources().getString(R.string.app_name));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;textViewName&nbsp;=&nbsp;(TextView)findViewById(R.id.TextViewName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buttonOpen&nbsp;=&nbsp;(Button)findViewById(R.id.ButtonOpen);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buttonOpen.setOnClickListener(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onClick(View&nbsp;arg0)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(arg0.getId()){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;R.id.ButtonOpen:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.v("click&nbsp;:&nbsp;ButtonOpen");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Intent&nbsp;it&nbsp;=&nbsp;new&nbsp;Intent(this,&nbsp;ConfigActivity.class);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(name&nbsp;!=&nbsp;null)&nbsp;it.putExtra("name",&nbsp;name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.startActivityForResult(it,&nbsp;1234);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;protected&nbsp;void&nbsp;onActivityResult(int&nbsp;reqCode,&nbsp;int&nbsp;resCode,&nbsp;Intent&nbsp;it)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.v("responseCode:"+resCode+",&nbsp;requestCode:"+reqCode);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(reqCode){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;1234:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setName(it.getStringExtra("name"));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;void&nbsp;setName(String&nbsp;name){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.textViewName.setText(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</pre>
<br />
<br />
onCreate関数内でgetIntent()すると、MainActivityから呼び出したIntentオブジェクトが手に入る。この中から値を取り出す。<br />
Intent.getStringExtra(key) も Intent.getExtras().getString(key) も同じ意味の関数だが、getExtras().getString(key) に存在しないkeyを与えると強制終了するので getStringExtra(key) の方を使った。こちらはnullが返ってくる。<br />
finish()するとMainActivityに戻るが、戻る時にsetResultしておいて値を戻す。setResultは終了コード的な意味で、MainActivityのonActivityResultの第二引数に入る。<br />
<a href="http://github.com/shokai/ActivitiesTest-android/blob/master/src/org/shokai/ConfigActivity.java">ConfigActivity.java</a><br />
<pre class="prettyprint">
package&nbsp;org.shokai;<br />
<br />
import&nbsp;android.app.Activity;<br />
import&nbsp;android.content.Intent;<br />
import&nbsp;android.view.View;<br />
import&nbsp;android.view.View.OnClickListener;<br />
import&nbsp;android.os.Bundle;<br />
import&nbsp;android.widget.*;<br />
<br />
public&nbsp;class&nbsp;ConfigActivity&nbsp;extends&nbsp;Activity&nbsp;implements&nbsp;OnClickListener{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;EditText&nbsp;editTextName;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Button&nbsp;buttonSave;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Logger&nbsp;logger;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onCreate(Bundle&nbsp;bundle){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;super.onCreate(bundle);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger&nbsp;=&nbsp;new&nbsp;Logger(this.getResources().getString(R.string.app_name));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setContentView(R.layout.config);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;editTextName&nbsp;=&nbsp;(EditText)findViewById(R.id.EditTextName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buttonSave&nbsp;=&nbsp;(Button)findViewById(R.id.ButtonSave);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buttonSave.setOnClickListener(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Intent&nbsp;it&nbsp;=&nbsp;getIntent();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;name&nbsp;=&nbsp;it.getStringExtra("name");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(name&nbsp;!=&nbsp;null)&nbsp;editTextName.setText(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;onClick(View&nbsp;v)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(v.getId()){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;R.id.ButtonSave:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.v("click&nbsp;:&nbsp;ButtonSave");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Intent&nbsp;it&nbsp;=&nbsp;new&nbsp;Intent();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;it.putExtra("name",&nbsp;this.editTextName.getText().toString());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.setResult(0,&nbsp;it);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.finish();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
}<br />
</pre>
<br />
<br />
■参考<br />
<ul>
  <li><a href="http://www.javadrive.jp/android/activity/index3.html">アクティビティの追加 &#8211; Activityを使った画面作成 &#8211; Android入門</a></li>
  <li><a href="http://d.hatena.ne.jp/hidecheck/20091202/1259767425">Androidで画面遷移 &#8211; hidecheckの日記</a></li>
  <li><a href="http://www.techfirm.co.jp/lab/android/transition.html">画面遷移 | テックファーム</a></li>
  <li><a href="http://android.roof-balcony.com/intent/intent/">Androidアプリで別のアクティビティを起動させる方法 | mucchinのAndroid戦記</a></li>
</ul>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5244/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PSoC CY8C29466のI2CHWモジュールで通信</title>
		<link>http://shokai.org/blog/archives/5230</link>
		<comments>http://shokai.org/blog/archives/5230#comments</comments>
		<pubDate>Tue, 20 Jul 2010 16:40:27 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[CY8C29466]]></category>
		<category><![CDATA[I2C]]></category>
		<category><![CDATA[PSoC]]></category>
		<category><![CDATA[PSoCDesigner]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[UART]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5230</guid>
		<description><![CDATA[
PSoC CY8C29466のI2Cモジュールを試した。
I2Cは2本の信号線の上にmaster/slaveの2種類のノードを合計100個以上載せて相互に通信できるプロトコル。動作速度が違う部品同士をより少ない結線数で [...]]]></description>
			<content:encoded><![CDATA[<p>
PSoC CY8C29466のI2Cモジュールを試した。<br />
I2Cは2本の信号線の上にmaster/slaveの2種類のノードを合計100個以上載せて相互に通信できるプロトコル。動作速度が違う部品同士をより少ない結線数で相互接続させる事を目的として、1992年にPhilipsが作って2004年に特許が切れている。今ではほとんどのマイコンにI2C通信をするモジュールがついているし、外部メモリやセンサーなどもI2Cで値を返す物がある。linuxのkernelにも入っていて(/usr/include/linux/i2c.hとか)マザーボード上の温度センサとかに使われているらしい。<br />
<br />
このへんに詳しく書いてある。<br />
<ul>
  <li><a href="http://www.picfun.com/c15.html">I2C通信の使い方</a></li>
  <li><a href="http://ja.wikipedia.org/wiki/I%C2%B2C">I²C &#8211; Wikipedia</a></li>
  <li><a href="http://www.nxp.com/acrobat_download/literature/9398/39340011_jp.pdf">I2Cバス仕様書日本語版(pdf)</a></li>
  <li><a href="http://www.eleki-jack.com/2007/04/1231.html">新連載　1、2、3線シリアル・インターフェース　（連載　第1回） (エレキジャック)</a></li>
  <li><a href="http://www.eleki-jack.com/2007/04/1232.html">1、2、3線シリアル・インターフェース　（連載　第2回） (エレキジャック)</a></li>
  <li><a href="http://www.cypress.com/?rID=3030">User Module Datasheet: I2C Hardware Block Data Sheet, I2CHW &#8211; Cypress Semiconductor</a></li>
</ul>
特に仕様書pdfはちゃんと読んでみたらかなり勉強になったのでオススメ。<br />
プログラムはCypress公式のUser Module Datasheetのp.39,40ものを参考にした。<br />
<br />
<br />
■作った物<br />
PSoC Designer 5.0+SP6で作ったプロジェクトまるごと<a href="http://github.com/shokai/i2c-uart-cy8c29466">githubに置いた</a>。<br />
<pre>
git clone git://github.com/shokai/i2c-uart-cy8c29466.git<br />
</pre>
で取得できる。<br />
<br />
<br />
3つ並んでいるPSoCマイコンのうち一番下がmasterで、上2つがslaveデバイス。デバイスが接続されている2つの線は2kΩの抵抗(1kΩ2つ)を介してVCCと接続されpull upされている。<a href="http://www.picfun.com/midi2c02.html">I2Cの接続構成とプルアップ抵抗</a>に適切なプルアップ抵抗の計算方法が書かれている。電源5Vで100kbpsか400kbpsなら2kΩ〜5kΩが最適値とのこと。<br />
<a href="http://www.flickr.com/photos/shokai/4811466957/" title="R0015277.JPG by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4080/4811466957_6841a296f6.jpg" width="375" height="500" alt="R0015277.JPG" /></a><br />
<br />
<br />
masterに付いているボタンを押すと、2つのslaveにLED点灯命令を送る。ボタンを離すと消灯する。<br />
<a href="http://www.flickr.com/photos/shokai/4811464283/" title="R0015274.JPG by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4081/4811464283_2b7ac459f5.jpg" width="500" height="375" alt="R0015274.JPG" /></a><br />
<br />
<br />
slave側のボタンは、それぞれmasterの2つのLEDの点灯/消灯に対応している。<br />
<a href="http://www.flickr.com/photos/shokai/4811464667/" title="R0015275.JPG by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4123/4811464667_70a5a3b556.jpg" width="500" height="375" alt="R0015275.JPG" /></a><br />
<a href="http://www.flickr.com/photos/shokai/4811465129/" title="R0015276.JPG by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4142/4811465129_521f689914.jpg" width="500" height="375" alt="R0015276.JPG" /></a><br />
<br />
<br />
masterはslaveをコントロールするだけでなく、I2Cとシリアル通信のブリッジになっている。<br />
slaveからのデータをslaveのアドレス名と共にUARTでパソコンに中継する。また、パソコンからmasterマイコンに&#8217;U'か&#8217;D'の文字を送る事と、masterは全slaveにLED点灯/消灯を送る。<br />
UARTとRS232Cのレベル変換にはADM3202を使った。<br />
<br />
<br />
だいたいそういう内容のビデオ<br />
<object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/K_mrn7w_NNA&amp;hl=ja_JP&amp;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/K_mrn7w_NNA&amp;hl=ja_JP&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object><br />
<br />
<br />
<br />
■デバイス設定<br />
master側。<br />
<a href="http://www.flickr.com/photos/shokai/4811481571/" title="I2C master device setting by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4116/4811481571_ff11dfb5cf.jpg" width="440" height="329" alt="I2C master device setting" /></a><br />
パソコンとのシリアル通信で9600bpsを作るためにVC1,VC3を設定している。動作電圧やCPUクロックなどはデフォルト値。<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4811485087/" title="I2C master I2CHW module setting by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4099/4811485087_b62e15f123.jpg" width="441" height="142" alt="I2C master I2CHW module setting" /></a><br />
single masterモードでモジュールを置いた。<br />
100kbpsでPORT1の5番と7番ピンをI2Cに使う。bufferはプログラム中で自分で用意したBYTE配列を使ってもらうように設定。<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4812110308/" title="I2C master UART module setting by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4117/4812110308_cebc318de5.jpg" width="437" height="298" alt="I2C master UART module setting" /></a><br />
シリアル通信で9600bpsが出るようにUARTモジュールを設定。<br />
<a href="http://shokai.org/blog/archives/1503">橋本商会 » PSoC – CY8C29466でUART受信割り込み</a>でくわしく書いた。<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4811487481/" title="I2C master Pinout setting by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4141/4811487481_76868554b1.jpg" width="442" height="390" alt="I2C master Pinout setting" /></a><br />
3つのLEDに使うピンは出力をStrongにして3V出るようにした。<br />
タクトスイッチにつなぐPort2の2番ピンは両エッジ入力割り込みを設定しつつ内部でプルアップして、ブレッドボード上でも100Ωの抵抗でプルダウンする。こうするとチャタリングが起きない。<br />
<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4812113076/" title="I2C master Pin layout by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4138/4812113076_80ba2fbd73.jpg" width="453" height="500" alt="I2C master Pin layout" /></a><br />
ピン配置図<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4812116700/" title="I2C master modules connection by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4102/4812116700_2cdced2f1b.jpg" width="500" height="265" alt="I2C master modules connection" /></a><br />
アナログブロックは使っていないので上の方だけ。<br />
UARTがPort2の4,5番ピンから出るように引き出した。<br />
<br />
<br />
<br />
slave側。<br />
<a href="http://www.flickr.com/photos/shokai/4812118072/" title="I2C slave device setting by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4118/4812118072_ee46cb4931.jpg" width="438" height="326" alt="I2C slave device setting" /></a><br />
Global Resourceは初期値のまま<br />
<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4812119504/" title="I2C slave I2CHW module setting by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4136/4812119504_f2b9e42c8c.jpg" width="439" height="176" alt="I2C slave I2CHW module setting" /></a><br />
I2CHWモジュールををslaveで置いた。速度はmasterに合わせる。<br />
slaveデバイスのアドレスは7bitだが、0&#215;00~0&#215;10までの16個のアドレスはプロトコルに予約されているので、0&#215;11からの112個が使える。<br />
今回はmasterのプログラムで0&#215;11~0&#215;20のデバイスがいるか確認しながら動作するようにしているので、アドレス17~32のどれかを使えばいい。<br />
<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4812121088/" title="I2C slave Pinout setting by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4102/4812121088_153c38dd35.jpg" width="462" height="386" alt="I2C slave Pinout setting" /></a><br />
masterと同じ様にLEDとタクトスイッチ用のピンを設定。LEDは1つだけ。<br />
<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4811498703/" title="I2C slave Pin layout by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4134/4811498703_426cfa5ecc.jpg" width="448" height="500" alt="I2C slave Pin layout" /></a><br />
<br />
<br />
<a href="http://www.flickr.com/photos/shokai/4812124826/" title="I2C slave modules connection by shokai, on Flickr"><img src="http://farm5.static.flickr.com/4094/4812124826_25c41c07df.jpg" width="500" height="256" alt="I2C slave modules connection" /></a><br />
なにも結線していない<br />
<br />
<br />
■プログラム<br />
master側<br />
slaveアドレス0&#215;11から0&#215;20までのデバイスに、順にTXバッファを書き込み、RXバッファに読み込む。送受信を待っている間、timeout_countをカウントアップし続けて、閾値以上になるとタイムアウトするようにしている。これで存在するかわからないslaveとやりとりできるし、動作中にslaveデバイスが増えても問題なくネットワークに参加させられる。<br />
<br />
UARTの受信やピン入力の検出は割り込みで処理している(<a href="http://shokai.org/blog/archives/1503">橋本商会 » PSoC – CY8C29466でUART受信割り込み</a>で書いた)のだが、I2Cはメインループの中で処理している。I/OからのイベントでUARTぐらいなら使ってもいいけど、16個のslaveとのやりとりを割り込みの中でやると多重割り込みが起こりやすいので、各ルーチンからbufferを読み書きしてそれを定期的にslaveと共有するという方式にした。<br />
本番ではdigital blockを1つ消費するだけで使える8bit Timerモジュールで定期的に回すようにすると良いと思う。<br />
<br />
<a href="http://github.com/shokai/i2c-uart-cy8c29466/blob/54a8031710cbe524da57a3e7689e707e99d20cb9/i2c_master/i2c_master/i2c_master/main.c">main.c</a><br />
<pre class="prettyprint">
//&nbsp;I2C-UART&nbsp;master<br />
//&nbsp;CY8C29466-24PXI(DIP&nbsp;Package)<br />
//&nbsp;PSoC&nbsp;Designer&nbsp;5.0&nbsp;+&nbsp;SP6<br />
//&nbsp;IMAGECRAFT&nbsp;C&nbsp;Compiler<br />
#include&nbsp;&lt;m8c.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;part&nbsp;specific&nbsp;constants&nbsp;and&nbsp;macros<br />
#include&nbsp;&lt;I2CHW_1Common.h&gt;<br />
#include&nbsp;&lt;I2CHW_1Mstr.h&gt;<br />
#include&nbsp;"PSoCAPI.h"&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;PSoC&nbsp;API&nbsp;definitions&nbsp;for&nbsp;all&nbsp;User&nbsp;Modules<br />
#define&nbsp;_BV(BIT)&nbsp;(1&lt;&lt;BIT)<br />
#define&nbsp;sbi(BYTE,BIT)&nbsp;(BYTE&nbsp;|=&nbsp;_BV(BIT))<br />
#define&nbsp;cbi(BYTE,BIT)&nbsp;(BYTE&nbsp;&amp;=&nbsp;~_BV(BIT))<br />
<br />
#define&nbsp;LED_ON()&nbsp;sbi(PRT2DR,&nbsp;0)&nbsp;//&nbsp;LED<br />
#define&nbsp;LED_OFF()&nbsp;cbi(PRT2DR,&nbsp;0)<br />
#define&nbsp;LED2_ON()&nbsp;sbi(PRT1DR,&nbsp;6)<br />
#define&nbsp;LED2_OFF()&nbsp;cbi(PRT1DR,&nbsp;6)<br />
#define&nbsp;LED3_ON()&nbsp;sbi(PRT1DR,&nbsp;4)<br />
#define&nbsp;LED3_OFF()&nbsp;cbi(PRT1DR,&nbsp;4)<br />
<br />
#define&nbsp;BTN_PORT&nbsp;PRT2DR&nbsp;//&nbsp;push&nbsp;button<br />
#define&nbsp;BTN_BIT&nbsp;_BV(2)<br />
<br />
#define&nbsp;BUF_SIZE&nbsp;8<br />
BYTE&nbsp;buf_tx[BUF_SIZE];&nbsp;//&nbsp;I2C&nbsp;buffer<br />
BYTE&nbsp;buf_rx[BUF_SIZE];<br />
BYTE&nbsp;status;&nbsp;//&nbsp;I2C&nbsp;status<br />
BYTE&nbsp;slave;&nbsp;//&nbsp;slave&nbsp;address<br />
#define&nbsp;I2C_TIMEOUT&nbsp;128&nbsp;//&nbsp;長時間応答が返ってこないslaveデバイスを無視する<br />
BYTE&nbsp;timeout_count,&nbsp;i;<br />
<br />
void&nbsp;main(void)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;M8C_EnableGInt;&nbsp;//&nbsp;enable&nbsp;global&nbsp;interrupt<br />
&nbsp;&nbsp;&nbsp;&nbsp;M8C_EnableIntMask(INT_MSK0,&nbsp;INT_MSK0_GPIO);<br />
&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CmdReset();&nbsp;//&nbsp;uart&nbsp;init<br />
&nbsp;&nbsp;&nbsp;&nbsp;UART_1_IntCntl(UART_1_ENABLE_RX_INT);&nbsp;//&nbsp;enable&nbsp;receive&nbsp;interrupt<br />
&nbsp;&nbsp;&nbsp;&nbsp;UART_1_Start(UART_1_PARITY_NONE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;LED_ON();<br />
&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CPutString("start");<br />
&nbsp;&nbsp;&nbsp;&nbsp;LED_OFF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_Start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_EnableMstr();<br />
&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_EnableInt();<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(;;){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(slave&nbsp;=&nbsp;0x11;&nbsp;slave&nbsp;&lt;&nbsp;0x21;&nbsp;slave++){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_bWriteBytes(slave,&nbsp;buf_tx,&nbsp;BUF_SIZE,&nbsp;I2CHW_1_CompleteXfer);&nbsp;//&nbsp;master-&gt;slave<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout_count&nbsp;=&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(;;){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(I2CHW_1_bReadI2CStatus()&nbsp;&amp;&nbsp;I2CHW_WR_COMPLETE&nbsp;||<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout_count++&nbsp;&gt;&nbsp;I2C_TIMEOUT)&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_ClrWrStatus();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_fReadBytes(slave,&nbsp;buf_rx,&nbsp;BUF_SIZE,&nbsp;I2CHW_1_CompleteXfer);&nbsp;//&nbsp;slave-&gt;master<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout_count&nbsp;=&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(;;){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(I2CHW_1_bReadI2CStatus()&nbsp;&amp;&nbsp;I2CHW_RD_COMPLETE&nbsp;||<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout_count++&nbsp;&gt;&nbsp;I2C_TIMEOUT)&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_ClrRdStatus();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(slave){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;0x11:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(buf_rx[0]&nbsp;==&nbsp;'u')&nbsp;LED2_OFF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(buf_rx[0]&nbsp;==&nbsp;'d')&nbsp;LED2_ON();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;0x12:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(buf_rx[0]&nbsp;==&nbsp;'u')&nbsp;LED3_OFF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(buf_rx[0]&nbsp;==&nbsp;'d')&nbsp;LED3_ON();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(!(UART_1_bReadTxStatus()&nbsp;&amp;&nbsp;UART_1_TX_BUFFER_EMPTY));&nbsp;//&nbsp;slaveからの受信データをシリアル通信出力<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CPutString("I2C:");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_1_PutSHexByte(slave);&nbsp;//&nbsp;slaveアドレス<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CPutString(",");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_1_PutString(buf_rx);&nbsp;//&nbsp;slaveからの受信データ<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_1_PutCRLF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;BUF_SIZE-1;&nbsp;i++)&nbsp;buf_rx[i]&nbsp;=&nbsp;'\0';&nbsp;//&nbsp;受信バッファを初期化<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
<br />
//&nbsp;UART受信割り込み<br />
#pragma&nbsp;interrupt_handler&nbsp;INT_UART_RX<br />
void&nbsp;INT_UART_RX(void){<br />
&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;recv_data;<br />
&nbsp;&nbsp;&nbsp;&nbsp;recv_data&nbsp;=&nbsp;UART_1_cGetChar();&nbsp;//&nbsp;read&nbsp;UART<br />
&nbsp;&nbsp;&nbsp;&nbsp;UART_1_PutChar(recv_data);&nbsp;//&nbsp;echo<br />
&nbsp;&nbsp;&nbsp;&nbsp;switch(recv_data){<br />
&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'U':<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LED_ON();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf_tx[0]&nbsp;=&nbsp;'A';&nbsp;//&nbsp;slaveにLED点灯を指示<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CPutString("LED:ON\r\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;'D':<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LED_OFF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf_tx[0]&nbsp;=&nbsp;'B';&nbsp;//&nbsp;slaveにLED消灯を指示<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CPutString("LED:OFF\r\n");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
//&nbsp;I/Oピン状態変化割り込み<br />
#pragma&nbsp;interrupt_handler&nbsp;INT_GPIO<br />
void&nbsp;INT_GPIO(void){<br />
&nbsp;&nbsp;if(BTN_PORT&nbsp;&amp;&nbsp;BTN_BIT){&nbsp;//&nbsp;ボタンが押されている時<br />
&nbsp;&nbsp;&nbsp;&nbsp;LED_ON();<br />
&nbsp;&nbsp;&nbsp;&nbsp;buf_tx[0]&nbsp;=&nbsp;'A';&nbsp;//&nbsp;slaveにLED点灯を指示<br />
&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CPutString("LED:ON\r\n");<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;LED_OFF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;buf_tx[0]&nbsp;=&nbsp;'B';&nbsp;//&nbsp;slaveにLED消灯を指示<br />
&nbsp;&nbsp;&nbsp;&nbsp;UART_1_CPutString("LED:OFF\r\n");<br />
&nbsp;&nbsp;}<br />
}<br />
</pre>
<br />
<br />
<br />
<br />
slave側<br />
slaveもmasterと同じ様にglobalにバッファを用意して、そこに適当に現在の状態を読み書きし、定期的にメインループ内でmasterと通信し共有している。この方が素直に書きやすい。<br />
LEDとボタンの状態を結びつける情報を1byte目に置いているが、それ以外の情報をやりとりする場合もシリアライズとかして通信するのではなく2byte目以降を使う方がいい。あくまで必要な変数を定期的に同期させられる、分散オブジェクト風に書いた方がすっきりする（PSoCのstring.hがおかしいという理由もあるけど）<br />
<br />
<br />
あと、ややこしいのがslaveなのでI2CHW_1_InitWrite関数を呼ぶとmasterからslaveへの書き込みが起こる。受信する。送信ではない。また、I2CHW_1_bReadI2CStatus() での状態チェックも、dataに使っている信号線1本の状態のチェックのためなので呼び出すタイミングがmasterと逆になる。このへんややこしいのであまり触りたくないから、通信は隔離された別ループでやってglobalに置いた共用bufferを同期させるという方法にした。<br />
<br />
<a href="http://github.com/shokai/i2c-uart-cy8c29466/blob/54a8031710cbe524da57a3e7689e707e99d20cb9/i2c_slave/i2c_slave/i2c_slave/main.c">main.c</a><br />
<pre class="prettyprint">
//&nbsp;I2C-UART&nbsp;slave<br />
//&nbsp;CY8C29466-24PXI(DIP&nbsp;Package)<br />
//&nbsp;PSoC&nbsp;Designer&nbsp;5.0&nbsp;+&nbsp;SP6<br />
//&nbsp;IMAGECRAFT&nbsp;C&nbsp;Compiler<br />
<br />
#include&nbsp;&lt;m8c.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;part&nbsp;specific&nbsp;constants&nbsp;and&nbsp;macros<br />
#include&nbsp;&lt;I2CHW_1Common.h&gt;<br />
#include&nbsp;"PSoCAPI.h"&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;PSoC&nbsp;API&nbsp;definitions&nbsp;for&nbsp;all&nbsp;User&nbsp;Modules<br />
#define&nbsp;_BV(BIT)&nbsp;(1&lt;&lt;BIT)<br />
#define&nbsp;sbi(BYTE,BIT)&nbsp;(BYTE&nbsp;|=&nbsp;_BV(BIT))<br />
#define&nbsp;cbi(BYTE,BIT)&nbsp;(BYTE&nbsp;&amp;=&nbsp;~_BV(BIT))<br />
<br />
#define&nbsp;LED_ON()&nbsp;sbi(PRT2DR,&nbsp;0)&nbsp;//&nbsp;LED<br />
#define&nbsp;LED_OFF()&nbsp;cbi(PRT2DR,&nbsp;0)<br />
#define&nbsp;BTN_PORT&nbsp;PRT2DR&nbsp;//&nbsp;push&nbsp;button<br />
#define&nbsp;BTN_BIT&nbsp;_BV(2)<br />
<br />
#define&nbsp;BUF_SIZE&nbsp;8<br />
BYTE&nbsp;buf_rx[BUF_SIZE];&nbsp;//&nbsp;I2C&nbsp;buffer<br />
BYTE&nbsp;buf_tx[BUF_SIZE]&nbsp;=&nbsp;{'x'};<br />
BYTE&nbsp;status;&nbsp;//&nbsp;I2C&nbsp;status<br />
<br />
void&nbsp;main(void)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;M8C_EnableGInt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;M8C_EnableIntMask(INT_MSK0,&nbsp;INT_MSK0_GPIO);<br />
&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_Start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_EnableSlave();<br />
&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_EnableInt();<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(;;){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status&nbsp;=&nbsp;I2CHW_1_bReadI2CStatus();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(status&nbsp;&amp;&nbsp;I2CHW_WR_COMPLETE){&nbsp;//&nbsp;master-&gt;slave<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_ClrWrStatus();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_InitWrite(buf_rx,&nbsp;BUF_SIZE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(status&nbsp;&amp;&nbsp;I2CHW_RD_COMPLETE){&nbsp;//&nbsp;slave-&gt;master<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_ClrRdStatus();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;I2CHW_1_InitRamRead(buf_tx,&nbsp;BUF_SIZE);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(buf_rx[0]&nbsp;==&nbsp;'A')&nbsp;LED_ON();&nbsp;//&nbsp;masterからの指示でLEDの点灯/消灯を切り替え<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(buf_rx[0]&nbsp;==&nbsp;'B')&nbsp;LED_OFF();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
<br />
#pragma&nbsp;interrupt_handler&nbsp;INT_GPIO<br />
void&nbsp;INT_GPIO(void){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(BTN_PORT&nbsp;&amp;&nbsp;BTN_BIT){&nbsp;//&nbsp;ボタンを押している時<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf_tx[0]&nbsp;=&nbsp;'d';&nbsp;//&nbsp;押下をmasterに通知<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf_tx[0]&nbsp;=&nbsp;'u';<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</pre>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5230/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
