Windowsでpyserial

2.5のインストーラーを落とす。
http://www.python.jp/pub/ftp.python.org/python/2.5/python-2.5.msi
msi形式なので、普通にインストールする。C\python25に入った。
んで、これはどうやって使うのかな?
だいぶ前に使ったけど、すっかり忘却。
アプリケーションメニューからIDLEを起動してみる。
IDLE1.2が起動した。
ふーん、普通にpythonのシェル環境だ。


https://sourceforge.net/projects/pywin32/
http://jaist.dl.sourceforge.net/sourceforge/pywin32/pywin32-210.win32-py2.5.exe
2.5対応のものを落とす。
これもWinインストーラーで楽。


http://pyserial.sourceforge.net/
http://sourceforge.net/project/showfiles.php?group_id=46487
http://downloads.sourceforge.net/pyserial/pyserial-2.2.win32.exe?use_mirror=jaist
http://jaist.dl.sourceforge.net/sourceforge/pyserial/pyserial-2.2.win32.exe
こいつもWinインストーラーがあるから楽。


ターゲットデバイスを挿す。
バイスマネージャで見ると、COM12とかになっている。
COM9までしかアクセスできない制限とかなかったっけ?
これはCOMで指定するデバイス名指定の制限で、デバイス番号でなら問題ないらしい。
IDLEで試す。

IDLE 1.2      
>>> import serial

>>> com = serial.Serial(
  port=11,
  baudrate=115200,
  bytesize=8,
  parity='N',
  stopbits=1,
  timeout=None,
  xonxoff=0,
  rtscts=0,
  writeTimeout=None,
  dsrdtr=None)
>>> print com.portstr
\\.\COM12

ハンドリングできているようだ。

>>> com.write("@HELLO")

では、どうも送信されていない風だ。応答が返らない。何が悪いのかな?

>>> print >>com, '@HELLO'

こっちなら大丈夫。
readlineするときには、timeoutがないと応答が返らない。

>>> com.timeout=0.5
>>> print >>com, '@HELLO'
>>> print com.readline()
@ACK□


>>> print >>com, '%\
00000000000000000000000000F8F898\
98F8F00000E0F838F8E00000F8F800F8\
F81818F8F000F8F80000F8F800F8F860\
606C600C00E0E000F8F8000000000000\
000000000000000000001F1F01031F1D\
001E1F0706071F1E001F1F001F1F1818\
1F0F00000010180F07000F1F18181818\
00080F07001F1F080600000000000000\
0000000000FFFEFEFEFEFEFEFEFEFEFF\
FEFEFEFEFEFEFEFEFEFFFEFEFEFEFEFE\
FEFEFEFFFEFEFEFEFEFEFEFEFEFFFEFE\
FEFEFEFEFEFEFE000000000000000000\
00001F1F1F1F1F1F1F1F1F1F1F1F1F1F\
1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F\
1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F\
1F1F1F1FF8F8C08C000C00383848484C\
4C4868381800080848C8A83818000000\
F8F80000000000000000000000000000\
00000000000000000000000000000000\
001F1F000103020011190F07010F1F11\
11090008181010111F0E0000001B1B00\
00000000000000000000000000000000\
0000000000000000000000000000FFFE\
FEFEFEFEFEFEFEFEFFFEFEFEFEFEFEFE\
FEFEFFFEFEFEFEFEFEFEFEFEFFFEFEFE\
FEFEFEFEFEFEFFFEFEFEFEFEFEFEFEFE\
FF000000000000000000001F1F1F1F1F\
1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F\
1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F\
1F1F1F1F1F1F1F1F1F1F1F1F1F1F0000\
0000000000000000'
>>> print com.readline()
@ACK□

画像の送信も問題なし。

>>> print >>com, '@LED,1,BLINK'
>>> print com.readline()
@ACK□


>>> print >>com, '@LED,1,FAST'
>>> print com.readline()
@ACK□


>>> print >>com, '@LED,1,OFF'
>>> print com.readline()
@ACK□


>>> print >>com, '@LED,1,ON'
>>> print com.readline()
@ACK□

LEDの制御もできる。

>>> print com.readline()
@SW,1□


>>> print com.readline()
@SW,2□

ボタンの結果も取れている。

>>> com.close()

閉じて終わり。
当たり前だけど、普通に使えるな。


書く前に念のためにcom.flush()しといたほうがいいかな。


サービスにする場合には、デバイスが接続されたCOMポート番号が取れないのがめんどくさいな。
tryで順番に開いて見て、開けたのはHELLOして返信チェックするのは乱暴かな?

WindowsでPILを使う

画面に表示する画像を作るのにPILを使うことにする。
落とす。
http://www.pythonware.com/products/pil/
http://effbot.org/downloads/PIL-1.1.6.win32-py2.5.exe
基本環境はpyserialを入れたのと同じ。
インストールはインストーラーがあるので楽。
IDLE起動。

>>> import Image
>>> im = Image.new("1", (122, 32), 1)
>>> im.show()

枠を作る。

>>> import ImageDraw, ImageFont
>>> draw = ImageDraw.Draw(im)
>>> font = ImageFont.truetype("C:\\Windows\\Fonts\\msgothic.ttc", 16)
>>> text = u"てすと"
>>> draw.text((0,0), text, font=font, fill=0)
>>> im.show()

あちゃ、化けている。u取っても同じ。
英語なら表示できている。
Windowsなので、フォントまわりはSJISなのかな?
0,0から書くと左が1ドット欠けているようだ。
あとは、ペーストする文字側のパレットのせいか、ビューアーのせいか、表示が2値になっていない。
# これはXPHomeのビューアーのせいだった。Win2kだとペイントで2値になっている。

>>> font = ImageFont.truetype("C:\\Windows\\Fonts\\msgothic.ttc", 16, index=0, encoding="unic")

indexは、複数フォントが入っているので、0はMSゴで、1はMSPゴだそうな。だとすると2はUIゴかな。
endordingではunicでunicodeを指定。省略しても問題なさそう。

>>> import Image, ImageDraw, ImageFont
>>> im = Image.new("1", (122, 32), 1)
>>> draw = ImageDraw.Draw(im)
>>> font = ImageFont.truetype("C:\WINNT\Fonts\msgothic.ttc", 16, index=0, encoding="unic")
>>> text = unicode('てすと', 'shift_jis')
>>> draw.text((0,0), text,  font=font, fill=0)
>>> im.show()

フォントパスは、環境をWin2kにしたので変更。このへんも互換性的にはやなところだ。
IDLEからなのでSJISで入力されているのだろうと想定したが、その通りだった。
これでちゃんと表示できた。ドット欠けもない。
フォントサイズを14にして、表示位置を少し調整すると、9文字は表示できた。

>>> text = unicode('愛しあってるかい!', 'shift_jis')
>>> draw.text((1,1), text,  font=font, fill=0)

LCDモジュールに文字を出す

メッセージとシリアルポートは決めうちだけど、とりあえず任意の文字を任意のサイズで表示できるようになった。

# coding: 'utf-8'

import Image, ImageDraw, ImageFont
import serial

com = serial.Serial(
  port=11,
  baudrate=115200,
  bytesize=8,
  parity='N',
  stopbits=1,
  timeout=None,
  xonxoff=0,
  rtscts=0,
  writeTimeout=None,
  dsrdtr=None)

com.timeout=0.5

#text1 = u'愛しあってるかい!'
#text2 = u'もうラブラブ☆★☆'
#text1 = u'今日はもう疲れたよ。'
#text2 = u'ノー残デーだし帰ろうよ。'
#text1 = u'え?定時過ぎからEMボードを'
#text2 = u'資料なしで見てと言われても。'
text1 = u'そんな仕事するなんて、'
text2 = u'北村さんもほんとに物好きね。'

im = Image.new("1", (122, 32), 1)
draw = ImageDraw.Draw(im)
font = ImageFont.truetype("C:\WINNT\Fonts\msgothic.ttc", 14, index=2, encoding="unic")
draw.text((1,1), text1,  font=font, fill=0)
font = ImageFont.truetype("C:\WINNT\Fonts\msgothic.ttc", 10, index=2, encoding="unic")
draw.text((1,18), text2,  font=font, fill=0)

serdata = []

dict = {'0000': '0',
	'0001': '1',
	'0010': '2',
	'0011': '3',
	'0100': '4',
	'0101': '5',
	'0110': '6',
	'0111': '7',
	'1000': '8',
	'1001': '9',
	'1010': 'A',
	'1011': 'B',
	'1100': 'C',
	'1101': 'D',
	'1110': 'E',
	'1111': 'F' }

def boxfilter(boxdata):
	box=boxdata
	im2=im.crop(box)
	im3=im2.transpose(Image.ROTATE_270)
	for y in range((im3.size[1])):
		row = []
		for x in range((im3.size[0])):
			value = im3.getpixel((x, y))
			if value == 0:
				row.append('1')
			else:
				row.append('0')
		data = ''.join(row)
		data1 = data[0:4]
		serdata.append(dict[data1])
		data2 = data[4:8]
		serdata.append(dict[data2])

boxfilter(( 0, 0, 61, 8))
boxfilter(( 0, 8, 61,16))
boxfilter(( 0,16, 61,24))
boxfilter(( 0,24, 61,32))
boxfilter((61, 0,122, 8))
boxfilter((61, 8,122,16))
boxfilter((61,16,122,24))
boxfilter((61,24,122,32))

print >>com, '@HELLO'
print >>com, '%'
print >>com, ''.join(serdata)

でも、なんかもう飽きてきたぞ(^^;。


Pythonで素人が実質数時間でできることが、どうしてVCだとできないのかな?
ふつーのPython使いの人なら、こんなの朝飯前で一日くらいで、仕様通りのものを作ってしまいそうな勢いだ。
組み込みではPILの重さとかが気になって、シェルスクリプトを選んだけど、Windowsマシンくらいのパワーがあれば、Pythonで十分実用になりそうだ。
このくらいわかれば、RSS出したり、メール通知したりするのは簡単だろうから、お金のある人は遊んでちょ。

あんまりなのでちと整理

# coding: 'utf-8'

import Image, ImageDraw, ImageFont
import serial
import time

com = serial.Serial(
	port=11,
	baudrate=115200,
	bytesize=8,
	parity='N',
	stopbits=1,
	timeout=None,
	xonxoff=0,
	rtscts=0,
	writeTimeout=None,
	dsrdtr=None)
com.timeout=0.5

dict = {'0000': '0', '0001': '1', '0010': '2', '0011': '3', 
		'0100': '4', '0101': '5', '0110': '6', '0111': '7', 
		'1000': '8', '1001': '9', '1010': 'A', '1011': 'B', 
		'1100': 'C', '1101': 'D', '1110': 'E', '1111': 'F' }

marks = [	( 0, 0, 61, 8), 
			( 0, 8, 61,16),
			( 0,16, 61,24),
			( 0,24, 61,32),
			(61, 0,122, 8),
			(61, 8,122,16),
			(61,16,122,24),
			(61,24,122,32)]

def makeimage(line1, line2):
	text1=line1
	text2=line2
	img = Image.new("1", (122, 32), 1)
	draw = ImageDraw.Draw(img)
	font = ImageFont.truetype("C:\WINNT\Fonts\msgothic.ttc", 14, index=2, encoding="unic")
	draw.text((1,1), text1,  font=font, fill=0)
	font = ImageFont.truetype("C:\WINNT\Fonts\msgothic.ttc", 10, index=2, encoding="unic")
	draw.text((1,18), text2,  font=font, fill=0)
	return img

def boxfilter(imd):
	im=imd
	serdata = []
	for i in marks:
		box=i
		im2=im.crop(box)
		im3=im2.transpose(Image.ROTATE_270)
		#im3.show()
		for y in range((im3.size[1])):
			row = []
			for x in range((im3.size[0])):
				value = im3.getpixel((x, y))
				if value == 0:
					row.append('1')
				else:
					row.append('0')
			#print ''.join(row)
			data = ''.join(row)
			data1 = data[0:4]
			serdata.append(dict[data1])
			data2 = data[4:8]
			serdata.append(dict[data2])
	return ''.join(serdata)

def printdata(senddata):
	sentdata=senddata
	print >>com, '%'
	print >>com, sentdata
	time.sleep(1)
	print >>com, '@HANTEN'
	time.sleep(1)

while 1:
	imd=makeimage(u'愛しあってるかい!', u'もうラブラブでっせ☆★☆')
	printdata(boxfilter(imd))

	imd=makeimage(u'え?定時過ぎなのに', u'EM板を資料ナシで見てって?')
	printdata(boxfilter(imd))

	imd=makeimage(u'今日はもう疲れたよ。', u'水曜はノー残デーだし帰ろうよ。')
	printdata(boxfilter(imd))

	imd=makeimage(u'そんな仕事するなんて、', u'北村さんもほんとに物好きね。')
	printdata(boxfilter(imd))

ずらずらならべて電光掲示板風に

してみたけど、文字によって画面生成負荷がばらつくのと、文字ごとに移動になると早すぎて視認性が悪い。
ちょっと追記して、電光掲示板モードを作った。

def makelineimage(line):
	text=line
	img = Image.new("1", (750, 32), 1)
	draw = ImageDraw.Draw(img)
	draw.text((1,1), text,  font=font3, fill=0)
	return img

def linefilter(imd):
	im=imd
	for i in range((im.size[0])):
		framedata=((0+i, 0, 122+i, 32))
		im2=im.crop(framedata)
		printdata(boxfilter(im2))

こんな風にループ内で呼ぶ。

	imd=makelineimage(u'       ☆朝日新聞ニュース☆ 今日未明、新潟で震度4の地震。')
	linefilter(imd)

ヌルヌルと動いて気持ち悪い。