ラベル Python の投稿を表示しています。 すべての投稿を表示
ラベル Python の投稿を表示しています。 すべての投稿を表示

2016年5月9日月曜日

BBC micro:bitのMicroPythonをnRF51822で使う(オンライン編)

*** 注意:メモリ不足によりBLEは使えません ***
https://microbit-micropython.readthedocs.io/en/latest/ble.html

実行したいプログラムをBBC micro:bitのMicroPython new projectで入力します。
Hello,World表示、LEDチカチカなら次のようなプログラムになります。


Downloadボタンを押すとバイナリファイル(拡張子HEX)をダウンロードしますのでnRF51822に書込みます。
mbed HRM1017のようなマイコンならドラッグアンドドロップで簡単に書込みが出来るでしょう。

USBシリアル変換をP0.24(送信),P0.25(受信)に繋ぎます。ボーレートは115200bpsに設定します。
例えば、トラ技ライタの場合は次のようになります。
TG-LPC11U35-501nRF51822
p10(P0_18)TGT_TX(P0.24)
p9(P0_19)TGT_RX(P0.25)

nRF51822をリセットするとプログラミングが実行されます。
終了するプログラムなら対話モードに移行します。
無限ループに入っていても、CTRL-Cでプログラムを強制停止させて対話モードに移行できます。
CTRL-Dでプログラムを再実行できます。

micro:bitのようにLEDマトリックスを持っているのであればmicrobit.displayモジュールが使えます。

ドキュメント
https://microbit-micropython.readthedocs.org

ドキュメントに載っているpin0,pin1,pin2等はmicro:bitでの端子名P0,P1,P2等であって、nRF51822のピン名称ではないのに注意。
対応は次のようになります。
MicroPython(micro:bit)nRF51822
pin0 PAD1P0.3
pin1 PAD2P0.2
pin2 PAD3P0.1
pin3 COL1P0.4
pin4 BTN_AP0.17
pin5 COL2P0.5
pin6 ROW2P0.14
pin7 ROW1P0.13
pin8 PIN18P0.18
pin9 ROW3P0.15
pin10 COL3P0.6
pin11 BTN_BP0.26
pin12 PIN20P0.20
pin13 SCKP0.23
pin14 MISOP0.22
pin15 MOSIP0.21
pin16 PIN16P0.16
pin19 SCLP0.0
pin20 SDAP0.30
microbit-dal/inc/core/MicroBitComponent.h
bbcmicrobit/micropython
https://github.com/bbcmicrobit/micropython

(2016/5/9)
---


2015年8月14日金曜日

LPC812エミュレータの試作



LPC812(Cortex-M0+,V6Mアーキテクチャ)のエミュレータを試作してみました。
とりあえず、mbed_blinky(Lチカ)のバイナリを動かすまでは出来ました。

mbed LPC1768で動作します:https://developer.mbed.org/users/va009039/code/emu812/

pythonでの検証
まずは、動作速度は関係なく、V6Mアーキテクチャを理解するためにpythonで書き初めました。
ステップ実行のレジスタやメモリアクセスの様子をログに残すようにして、他の言語で書いたものと機械的に比較して間違いを検出しやすくするようにします。

大まかな動作は次のとおりです。
プログラムカウンタが指すアドレスから命令を取り出す。
ジャンプテーブルで命令の上位バイトから256通りに分岐します。
命令をデコードしてレジスタにアクセスするための添字を求めます。
演算(データ処理)またはデータ転送をします。

ゼロフラグ(Z)、符号フラグ(N)は演算結果から求める事はできる。
キャリーフラグ(C )、オーバーフローフラグ(V)はどうするのだろうと調べてみたら、演算前の最上位ビットと演算後の最上位ビットから求める事ができるのがわかりました。
ADD Rd,Rn,Rm のそれぞれRd,Rn,Rmの最上位ビットからテーブルを引いています。

ADD Rd,#imm レジスタとイミディエートとの演算、ADD Rd,Rn レジスタとレジスタの演算を共通化するためにイミディエート用の仮のレジスタを作りました。
命令をデコードしたときにイミディエートの値をR[17]に入れます。
つまり、 R0 = R1 + #imm は R0 = R1 + R17 に換えて演算処理に渡します。

演算結果を求めるのでなくてフラグの結果だけを知りたい比較命令CMPと減算命令SUBを共通化します。
比較命令を Rd = Rn - Rm に共通化するために 命令のデコードでRd をR[18]に書き換えて演算結果を捨てるようにします。

pythonでのLPC810エミュレータです:https://bitbucket.org/va009039/emu810


C++への半自動変換
pythonで書いたプログラムをC++に書きなおすのですが同じような作業の繰り返しなので簡単な文字列置換のプログラムを作ってC++へまとめて変換します。
pythonでは冗長なselfでのメソッド変数へのアクセスは文字列置換には好都合です。
ジャンプテーブルの自動作成のために命令範囲をコメントとして書いています。同じ形式の関数名にして抽出しやすいようにしています。
変換に作ったプログラムです: conv.py

ペリフェラル
初期設定を進めるためにPLLがロックしたとみなすステータスを返すようにします。
wait()タイマーはMRTを使っているので適当な間隔でTIMER0を進めます。
GPIOはDIRレジスタをみて出力だけをホストMCUに渡すようにしています。
LPC1114版も作ってみました: https://developer.mbed.org/users/va009039/code/emu1114/

参考文献
(2015/8/14)
---

2014年6月15日日曜日

Nucleo F401REでpython-on-a-chipを動かす



python-on-a-chipオンラインコンパイラで使っているバーチャルマシンはmbedライブラリで構築されているので
mbedのプラットフォームならターゲットを比較的容易に追加する事が出来ます。

Nucleo F401REの追加例。

バーチャルマシン

p14p/pinname.py でピン名称テーブルの作成。PinName.h
ヒープサイズ、ユーザのバイトコードの開始アドレスの設定。main.cpp
Nucleo F401REはAnalogOutクラスが無かったのでダミークラスとして追加。main_nat.cpp
mbedオンラインでコンパイルしてバーチャルマシンのバイナリーを作成。pymite_F401RE.bin

オンラインコンパイラ

ターゲットのメニューに ST Nucleo F401RE を追加。pymbed_bt_ace.html
ターゲットに f401re を追加。pymbed.py

ソースコード:
https://code.google.com/p/python-on-a-chip/ バーチャルマシン本体
http://mbed.org/users/va009039/code/pymite/ オンラインコンパイラ用のバーチャルマシン
https://bitbucket.org/va009039/pymbed/ オンラインコンパイラ

(2014/6/15)
---

2014年2月8日土曜日

LPC1114FN28専用のISP書込みPythonスクリプト

LPC1114FN28専用のもPythonで作ってみました。
ターゲットのMCUのチェックとか、フラッシュROM容量のチェックは全然してないので、
他のMCUでもそのまま、或いは僅かな修正で動かすことができるでしょう。

LPC800シリーズとの違いはUUエンコードでバイナリーデータを送るところだけです。
・Write to RAMコマンドの後にUUエンコートしたテキストを送る。
・20行毎にバイナリーデータのチェックサムを送る。
・チェックサムがあっていれば OK が返ってきます。

USBシリアル変換はFRDM-KL25Zをmbedインターフェースにしてシリアル通信を使っています。
半二重通信らしくエコーの改行コードを受け取れない時があります。
LPC810の時は特に障害にならなかったので微妙な送受信のタイミングの違いがあるのかもしれません。
たぶん、USBシリアル変換の専用機なら問題ないのでしょう。

実行例:


参考:
LPC111x/LPC11C1x ユーザーマニュアル

ソースコード:

(2014/2/8)
---

2014年2月7日金曜日

LPC810専用のISP書込みPythonスクリプト

LP800シリーズのISP(In-System Programming)を理解するために
Python + pySerial でフラッシュ書込みスクリプトを作ってみました。

Write to RAMコマンドはLPC1114シリーズとは違い、バイナリーデータを変換しないで送るだけです。
ユーザマニュアルには "OK" が返ってくるように書いてあるが、試してみたところ何も返ってこなかった。

使用例:
c:\python27\python lpc81isp.py lpc810_helloworld_LPC812.bin --port=COM27

参考:
LPC800 User manual

ソースコード:

(2014/2/7)
---

2013年9月5日木曜日

pyOCDのflash_lpc11u24.pyをLPC1114FN28で使う

以前、pyOCDのflash_lpc11u24.pyを使ってLPC1114FN28にフラッシュ書き込みをしようとしていたが、
eraseAllでハングアップしていた。HALTに戻らない。

RAM容量の都合でSPスタックポインタの設定が間違っていたようでした。

修正箇所:
'begin_stack' : 0x10001000,
           ↓
 'begin_stack' : 0x10001000-32,
RAMの上位32バイトをIAPが使うので避ける。


上の動作例ではpyOCDでも使えるようにCMSIS-DAPを修正して、
vid=0x0d28, pid=0x0204、DAPベンダーコマンドID_DAP_Vendor0(0x80)にboard id 1040~を返して、
LPC11U24に接続したように見せかけて、flash_lpc11u24.pyを呼び出してフラッシュ書き込みをしています。

(2013/9/5)
---

2013年5月4日土曜日

USBトークン、データCRCの計算

CRCの理論はよくわかってないが、テストが通るからたぶん計算方法はあっていると思う。

8.3.5.1 Token CRCs
8.3.5.2 Data CRCs


# coding:utf-8
# test_crc5usb.py 2013/5/3
#
import unittest

def crc5usb(data):
    assert(data >= 0 and data <= 0x3ff)
    r = data ^ 0x1f
    for _ in range(11): # 11bit
        if r & 1:
            r = (r>>1) ^ 0x14
        else:
            r = r>>1
    return r ^ 0x1f


class Test_crc5usb(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_80_2d_00_10(self): # SYNC SETUP
        u16 = 0x00 | 0x10<<8
        self.assertEqual(u16&0x7f, 0)     # ADDR=0x0
        self.assertEqual((u16>>7)&0xf, 0) # ENDP=0x0
        self.assertEqual(u16>>11, 0x02)   # CRC5=0x02
        r = crc5usb(u16&0x3ff)
        self.assertEqual(r, 0x02)   # CRC5

    def test_80_69_87_d8(self): # SYNC IN
        u16 = 0x87 | 0xd8<<8
        self.assertEqual(u16&0x7f, 7)     # ADDR=0x7
        self.assertEqual((u16>>7)&0xf, 1) # ENDP=0x1
        self.assertEqual(u16>>11, 0x1b)   # CRC5=0x1b
        r = crc5usb(u16&0x3ff)
        self.assertEqual(r, 0x1b)   # CRC5

    def test_80_00_10(self):
        u16 = 0x00 | 0x10<<8
        self.assertEqual(u16&0x7f, 0)     # ADDR=0x0
        self.assertEqual((u16>>7)&0xf, 0) # ENDP=0x0
        self.assertEqual(u16>>11, 0x02)   # CRC5=0x02
        r = crc5usb(u16&0x3ff)
        self.assertEqual(r, 0x02)   # CRC5

if __name__=="__main__":
    unittest.main()

# coding:utf-8
# test_crc16usb.py 2013/5/3
#
import unittest

def crc16usb(data):
    r = 0xffff
    for d in data:
        r ^= d
        for _ in range(8):
            if r & 1:
                r = (r>>1) ^ 0xa001
            else:
                r = (r>>1)
    return r ^ 0xffff

class Test_crc16usb(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_00_00_ff_00_2bbe(self):
        data = [0x00, 0x00, 0xff, 0x00]
        r = crc16usb(data)
        self.assertEqual(r, 0x2bbe)

    def test_00_ff_00_00_ebcf(self):
        data = [0x00, 0xff, 0x00, 0x00]
        r = crc16usb(data)
        self.assertEqual(r, 0xebcf)

    def test_None_0000(self):
        data = []
        r = crc16usb(data)
        self.assertEqual(r, 0x0000)

    def test_80_06_00_01_00_00_40_00_94dd(self):
        data = [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00]
        r = crc16usb(data)
        self.assertEqual(r, 0x94dd)

    def test_12_01_10_01_00_00_00_08_7711(self):
        data = [0x12, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00, 0x08]
        r = crc16usb(data)
        self.assertEqual(r, 0x7711)

    def test_58_04_07_00_00_00_01_02_487f(self):
        data = [0x58, 0x04, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02]
        r = crc16usb(data)
        self.assertEqual(r, 0x487f)

    def test_00_01_8f3f(self):
        data = [0x00, 0x01]
        r = crc16usb(data)
        self.assertEqual(r, 0x8f3f)

if __name__=="__main__":
    unittest.main()


(2013/5/4)
---

2013年4月25日木曜日

pywinusbの使用例

デバッグアダプタのLEDを点滅するだけのプログラム。LEDチカチカです。
よくわからないが、パソコンによってはHIDデバイスとして見えない場合がある。
もちろん、UV4からは見えます。

# USBDAP.py 2013/4/25
import pywinusb.hid

class USBDAP:
    def __init__(self, pname="CMSIS-DAP"):
        self.dev = None
        for dev in pywinusb.hid.find_all_hid_devices():
            if dev.product_name.find(pname) >= 0:
                self.dev = dev
                break
        assert(self.dev)
        self.dev.open()
        self.dev.set_raw_data_handler(self.rx_handler)
        reports = dev.find_output_reports()
        assert(len(reports) == 1)
        self.report = reports[0]

    def close(self):
        if self.dev:
            self.dev.close()

    def rx_handler(self, data):
        self.recv_data = data[1:]

    def write(self, data):
        assert(len(data) >= 0 and len(data) <= 64)
        data += [0]*(64-len(data))
        self.recv_data = None
        self.report.send([0] + data)

    def read(self):
        while self.recv_data == None:
            pass
        return self.recv_data

if __name__=="__main__":
    import time
    dap = USBDAP("KL25Z CMSIS-DAP")
    for _ in range(10):
        dap.write([1,1,1]) # LED ON
        dap.read()
        time.sleep(0.2)
        dap.write([1,1,0]) # LED OFF
        dap.read()
        time.sleep(0.2)
    dap.close()

(2013/4/25)
---

2013年4月24日水曜日

pywinusbのインストール

mbedのUSBHIDで作成したソフトのデバッグ・テストのためにpywinusbをインストールする。

pywinusb
https://github.com/rene-aguirre/pywinusb
pywinusb-master.zip

ZIPファイルを展開して setup.py install を実行する。
c:\python27\python setup.py install

Setuptools or Distribute packages are required. のエラーメッセージなら
予め setuptools をインストールしておく。
https://pypi.python.org/pypi/setuptools
setuptools-0.6c11.win32-py2.7.exe

動作確認。コマンドラインでパソコンに接続されているHIDを表示する。
import pywinusb.hid
pywinusb.hid.core.show_hids()


(2013/4/24)
---

2013年4月19日金曜日

patch.py(仮題)

手作業で差分からファイルを作るのは辛いのでpythonで書いてみました。
ZIPファイルを全部展開する必要はなくて、必要なファイルだけに差分を適用して書き出します。

使用例:
c:\python27\python patch.py AN11321.zip < diff.txt


# patch.py 2013/4/19
import zipfile
import sys
import re
import copy

def patch(fromarc, diff):
    from_zip = zipfile.ZipFile(fromarc)
    assert(from_zip)
    tolines = {}
    for line in diff:
        if line.find("--- ") == 0:
            fromfile = line[4:].rstrip()
            assert(fromfile in from_zip.namelist())
            with from_zip.open(fromfile, 'U') as f:
                fromlines = f.readlines()
        elif line.find("+++ ") == 0:
            tofile = line[4:].rstrip()
            tolines[tofile] = copy.deepcopy(fromlines)
            print "%s <- %s" % (tofile, fromfile)
        elif line.find("@@ ") == 0:
            m = re.search(r"@@\s+\-(\d+),(\d+)\s+\+(\d+),(\d+)", line)
            assert(m)
            from_pos = int(m.group(1)) - 1
            to_pos = int(m.group(3)) - 1
        elif line.find(" ") == 0:
            assert(line[1:] == fromlines[from_pos])
            from_pos += 1
            assert(line[1:] == tolines[tofile][to_pos])
            to_pos += 1
        elif line.find("+") == 0:
            line2 = line[1:]
            tolines[tofile].insert(to_pos, line[1:])
            to_pos += 1
        elif line.find("-") == 0:
            assert(line[1:] == fromlines[from_pos])
            from_pos += 1
            assert(line[1:] == tolines[tofile][to_pos])
            del tolines[tofile][to_pos]
        else:
            assert(0)

    for tofile in tolines:
        with open(tofile, "w") as f:
            f.writelines(tolines[tofile])

if __name__ == '__main__':
    fromarc = sys.argv[1]
    diff = sys.stdin.readlines()
    patch(fromarc, diff)


(2013/4/19)
---

zipfileとdifflibの使用例

ZIPファイル間で差分を作りたかったのでPythonのdifflibとzipfileを使ってみました。

# mydiff.py 2013/4/19
import zipfile
import difflib
import os.path
import sys

def mydiff(fromarc, toarc, n=3):
    to_zip = zipfile.ZipFile(toarc)
    from_zip = zipfile.ZipFile(fromarc)

    fromto = []
    for t in to_zip.namelist():
        name,ext = os.path.splitext(t)
        s = t
        if ext == ".cpp":
            s = name + ".c"
        for f in from_zip.namelist():
            if f.endswith(s):
                fromto.append([t,f])

    for ft in fromto:
        tofile,fromfile = ft
        with to_zip.open(tofile, 'U') as f:
            tolines = f.readlines()
        with from_zip.open(fromfile, 'U') as f:
            fromlines = f.readlines()
        diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, n=n)
        sys.stdout.writelines(diff)

if __name__ == '__main__':
    fromarc = "AN11321.zip"
    toarc   = "pms-CMSIS-DAP.zip"
    mydiff(fromarc, toarc, n=3)

(2013/4/19)
---

2013年3月16日土曜日

FRDM-KL25Zでpython-on-a-chipを動かす(2)


python-on-a-chip(pymite)でLEDチカチカ以上にどのくらいのプログラミングが書けるか試してみました。

FRDM-KL25Zに載っている加速度センサMMA8451QをmbedライブラのI2Cクラスで直接呼ぶようにpythonクラスを作ったのだが、ヒープサイズが12Kバイト(0x3000)ではメモリ不足で動かなかった。
14Kバイト(0x3800)に増やしてやっと動きました。これ以上はシステムでもRAMを使っているので増やせないようです。
pymiteがどのようにヒープを使っているのはわかってないです。
ヒープサイズと残量は、
import sys
print sys.heap()
で見ることが出来ます。

http://mbed.org/users/va009039/code/pymite/wiki/FRDM-MMA8451Q

タッチセンサーは直接ポートを操作しているようなので、mbedライブラリでTSISensorクラスを呼ぶようにしました。
この場合は、簡潔にプログラミングが書けます。

http://mbed.org/users/va009039/code/pymite/wiki/FRDM_TSI

(2013/3/15)
---

2013年3月14日木曜日

mbedアプリケーションボードのLCDを使う


python-on-a-chip(pymite)のmbedライブラリの動作確認とAceコードエディタの使い勝手のテストを兼ねてmbedアプリケーションボードのLCDを使ってみました。
C++のLCDクラスライブラリを使わずに、pythonでクラスを作って直接mbedライブラリのSPIクラスを使っています。もちろん、LCDへのコマンドやデータの送り方等はC++のを参考にしました。フォントは以前使っていた美咲フォントの8x4サイズのを使っています。

C++のLCDクラスライブラリではLCDに書き込むためにbufferを用意しているが、
pymiteで なにげなくリストで buffer = [0]*512 で確保すると途端にメモリ不足になります。
ループを回すのに for i in range(128): もリストを作るのでメモリ不足になりやすいです。

Aceコードエディタはインデントで折り畳めるので1つのソースファイルでも結構書けそうです。
ただし、コンパイルエラーでWebページをリロードすると折り畳んだのが開いてしまうので、
Webアプリでは工夫の必要があります。

以下、pymiteで書いたコードです。
http://mbed.org/users/va009039/code/pymite/wiki/app-board-LCD
バイトコードのサイズは6,276バイトになりました。

その他に温度センサLM75BとRGB-LEDのもpymiteで書いてみました。
これでI2CとPwmOutのライブラリの動作確認が出来ました。
http://mbed.org/users/va009039/code/pymite/wiki/app-board-LM75B
http://mbed.org/users/va009039/code/pymite/wiki/app-board-RGB

(2013/3/14)
---

2013年3月13日水曜日

FRDM-KL25Zでpython-on-a-chipを動かす(1)


mbed環境に新しく加わったFRDM-KL25Z は flash128Kバイト,ram16Kバイト と意外と容量があるので
python-on-a-chip(pymite)を動かしてみました。

ヒープサイズ、mbedライブラリのピンネーム(pinName)の違いを、
TARGET_LPC1768, TARGET_KL25Z
で条件コンパイル出来るように修正して共通のプログラムにしました。

KL25Zでコンパイルすると mbed LPC1768 に比べて少しバイナリサイズが大きくなっているが、
これは条件コンパイルのpinNameの文字列テーブルの違いが大きいのかもしれないので、純粋にプロセッサM0+とM3の違いなのかはわからないです。
FlashRAM
KL25ZLPC1768KL25ZLPC1768
code72.8KB71.8KB0.4KB0.4KB
libraries22.1KB22.7KB0.3KB0.4KB
total94.9KB94.5KB0.7KB0.7KB
codeにはユーザ実行とライブラリのバイトコードに確保した32KBが含まれています。

実行速度は比較していない。

以下、KL25Zにも対応したpython-on-a-chip本体と上の動画でGAEで動いているコードです。
http://mbed.org/users/va009039/code/pymite/
https://bitbucket.org/va009039/pymbed

(2013/3/13)
---

2013年3月9日土曜日

python-on-a-chipのPython2.7対応について

新機能の実現はともかくとして、python-on-a-chip(pymite) の vm が Python2.7 のバイトコードで動けば、
現在、Google App Engine(GAE) の Python2.5 で動いているオンラインコンパイラを Python2.7 で動かせるので対応してみました。

src/vm/inter.h
バイトコード表を変更する。typedef enum PmBcode_e を入れ替える。
同じ名前のオペコードでも値が違うのがあります。

src/vm/inter.c
Python2.6 まで使われていた JUMP_IF_FALSE, JUMP_IF_TRUE のバイトコード実行の実装を削除する。

Python2.7 から使われるようになった JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP,POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE のバイトコード実行の実装を追加する。
引数 target がIP(インストラクションポインタ)相対値ではなくて、絶対値であることに注意。
例:

#ifdef HAVE_PYTHON27
            case JUMP_IF_FALSE_OR_POP:
                t16 = GET_ARG();
                if (obj_isFalse(TOS))
                {
                    PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16;
                }
                else
                {
                    --PM_SP;
                }
                continue;


LIST_APPEND を引数付きに修正する。python2.6 までは TOS,TOS1 をポップしていたが、 python2.7からは TOS だけをポップすればいいようです。しかし、リスト内包表記 (list comprehension) で式は評価されるが、作ったリストが空になるのはよくわからないです。

#ifdef HAVE_PYTHON27
            case LIST_APPEND:
                t16 = GET_ARG();
                C_ASSERT(t16 >= 2); 
                retval = list_append((*(PM_SP - t16)), TOS);
                PM_SP--;
                continue;


pmImgCreator.py がブラックリスト方式でバイトコードをフィルタしているのでわからないが、Python2.6 までのプログラムを動かすのに必要な追加のバイトコードがあるのかもしれない。
一応、LEDチカチカのプログラムは動いています。

(2013/3/9)
---

2013年3月3日日曜日

GAEでpython-on-a-chipオンラインコンパイラの試作


python-on-a-chip(pymite)でpythonコードを変更するたびに mbed の C++コンパイラを通すのは面倒なので、オンラインで直接実行ファイルを作れるか試してみました。

Google App Engine(GAE) で作ったWEBサイトでpythonコードを入力。
compileコンパイルボタンを押すと、pmImgCreator.py でバイトコードに変換、実行ファイルのバイトコードを入れ換えて、パソコンにダウンロードさせる。
mbedにドラッグアンドドロップで実行します。

厳密にテストしてはないのですが、python2.5 の pmImgCreator.py で作るバイトコードは動くようです。
そのために GAE では 2.7 が使えるのに、あえて python2.5 で動かしています。
jinjia2 はGAEローカル開発環境では動くが、オンライン環境では 2.7 が必要で、旧テンプレートエンジンを使用しなければならない。
簡単にWEBサイトを作るために、jQuery Mobile を使用しているのだが、ファイルのダウンロードはうまくいかない。
フォームでは ajax をディセーブルにする必要があります。

GAEでの試作例サイト:
http://pymbed.appspot.com/
GAEでの実行コード:
https://bitbucket.org/va009039/pymbed
python-on-a-chip実行ファイル作成のコード:
http://mbed.org/users/va009039/code/pymite/
mbedコンパイラへのインポートを助けるためのバッチファル make.bat:
http://mbed.org/users/va009039/code/pymite/wiki/makebat
オフラインコンパイルのためのバッチファイル compile.bat:
http://mbed.org/users/va009039/code/pymite/wiki/compilebat

(2013/3/3)
---

2013年3月1日金曜日

pythonのバイトコード命令の比較(2)

ドキュメントにバイトコード命令の説明があったので比較。

pymite での実装 interp.c interp.h を見てみると、
引数 は GET_ARG()、TOS[-i] は STACK(i)、バイトコードカウンタは PM_IP、
スタックのポップは PM_SP-- に相当するらしい。

stdlib src/__bi.py を 2.7 でコンパイルしてみたところ、i=2 LIST_APPEND(2) だけが使われている。
2.6 ではスタック2個取り除いているが、2.7 では1個TOSだけを取り除く意味なのかわからないです。


Python2.5 : 30.10.1 Pythonバイトコード命令
Python2.6 : 31.12.1. Pythonバイトコード命令

LIST_APPEND list.append(TOS1, TOS)を呼びます。リスト内包表記を実装するために使われます。

JUMP_IF_FALSE(delta) TOSが偽ならば、deltaだけバイトコードカウンタを増加させます。TOSは変更されません。

Python2.7 : 31.12.1. Python バイトコード命令

LIST_APPEND(i) list.append(TOS[-i], TOS)を呼びます。リスト内包表記を実装するために使われます。要素が取り除かれる間、リストオブジェクトはスタックに残るので、ループの反復をさらに行えます。

JUMP_IF_FALSE_OR_POP(target) TOS が偽ならば、バイトコードカウンタを target に設定し、TOS はスタックに残されます。そうでない (TOS が真) なら、TOS はポップされます。


(2013/3/1)
---

2013年2月27日水曜日

python-on-a-chipを構築してみた

python-on-a-chipから clone、
pymite-09.tar.gz をダウンロードして展開。
展開したフォルダーの /src/platform/mbed に移動。
mbed.py の TextLCDクラスを削除。
以下のバッチファイル make.bat を実行。
pymite.zip が出来上がるので mbed のオンラインコンパイラにインポート。
既存の main.cpp は削除、コンパイルして mbed で実行。
パソコンで ipm.py を実行すると、Python の対話モードで動いた。

エラーが発生すると止まってしまう。mbed固有のライブラリの使い方がまだわかってないです。
 
vmが一度出来てしまうと、usrlib_img[]のバイトコードを差し替えれるようにすれば、わざわざ再コンパイルしなくてもいいと思う。

Windowsインストーラ付き:
python2.6 : http://www.python.org/download/releases/2.6.6/
pySerial2.5 : http://sourceforge.net/projects/pyserial/

rem make.bat 2013/2/27
set PYTHON26=c:\python26\python.exe
IF NOT EXIST %PYTHON26% GOTO exit

set TOOLS=../../tools/
set LIB=../../lib/
set VM=../../vm/

set PMIMGCREATOR=%TOOLS%pmImgCreator.py
IF NOT EXIST %PMIMGCREATOR% GOTO exit
set PMGENPMFEATURES=%TOOLS%pmGenPmFeatures.py
IF NOT EXIST %PMIMGCREATOR% GOTO exit
set PMSTDLIB_SOURCES=%LIB%__bi.py %LIB%dict.py %LIB%list.py %LIB%string.py %LIB%sys.py
set PMSTDLIB_SOURCES=%PMSTDLIB_SOURCES% %LIB%ipm.py
set SOURCE_IMG=pmstdlib_img.cpp
set SOURCE_NAT=pmstdlib_nat.cpp
set ZIP=pymite.zip

IF NOT EXIST pmfeatures.py GOTO exit
%PYTHON26% %PMGENPMFEATURES% pmfeatures.py > pmfeatures.h
IF ERRORLEVEL 1 GOTO exit

%PYTHON26% %PMIMGCREATOR% -c -u -f pmfeatures.py -o main_img.cpp --native-file=main_nat.cpp main.py mbed.py
IF ERRORLEVEL 1 GOTO exit

IF NOT EXIST %LIB%__bi.py GOTO exit
%PYTHON26% %PMIMGCREATOR% -c -s -f pmfeatures.py --memspace=flash -o %SOURCE_IMG% --native-file=%SOURCE_NAT% %PMSTDLIB_SOURCES%
IF ERRORLEVEL 1 GOTO exit

IF NOT EXIST %VM%pm.h GOTO exit
set SCRIPT="ds=['./','%VM%'];
set SCRIPT=%SCRIPT%es=['*.h','*.c','*.cpp'];import zipfile;import glob;import os;z=zipfile.ZipFile('%ZIP%','w');
set SCRIPT=%SCRIPT%[[[z.write(f,os.path.basename(f)) for f in glob.glob(d+e)] for e in es] for d in ds];
set SCRIPT=%SCRIPT%z.close()"
%PYTHON26% -c %SCRIPT%
IF ERRORLEVEL 1 GOTO exit

%PYTHON26% -c "import zipfile;z=zipfile.ZipFile('%ZIP%','r');z.printdir()"
IF ERRORLEVEL 1 GOTO exit

ECHO SUCCESS!!! PLEASE IMPORT %ZIP%

:exit
EXIT/B

(2013/2/27)
---

2013年2月26日火曜日

pythonのバイトコード命令の比較(1)

Python-on-a-Chip(p14p) pymite の pmImgCreator.py が python のバージョンを 2.6 に制限していたので各 python のバイトコードの命令を比較してみた。

2.5 から 2.6 は STORE_MAP が追加されただけだが、

2.6 から 2.7 へは BUILD_MAP,LOAD_ATTR,COMPARE_OP,IMPORT_NAME,IMPORT_FROM はコード値の入れ替わり。
LIST_APPEND は引数付きに変更。
JUMP_IF_FALSE,JUMP_IF_TRUE は削除、同じコード値の JUMP_IF_FALSE_OR_POP,JUMP_IF_TRUE_OR_POP と互換性があるのかは不明。
そもそも命令名が同じでも全く同じ動作をするのかはまだ分かってないです。

全てのバージョンは dis.HAVE_ARGUMENT=90 です。

pymite は pmImgCreator.py だけを動かして読んでみただけ vm では動かしてないのだが、
2.7 ではイメージは出来るが、既存の vm との互換性がなくて動かないだろう。 2.5 なら動くかもしれない。

,pyMite(p14p),python2.5,python2.6,python2.7
18,LIST_APPEND,LIST_APPEND,LIST_APPEND,None
54,STORE_MAP,None,STORE_MAP,STORE_MAP
94,None,None,None,LIST_APPEND
104,BUILD_MAP,BUILD_MAP,BUILD_MAP,BUILD_SET
105,LOAD_ATTR,LOAD_ATTR,LOAD_ATTR,BUILD_MAP
106,COMPARE_OP,COMPARE_OP,COMPARE_OP,LOAD_ATTR
107,IMPORT_NAME,IMPORT_NAME,IMPORT_NAME,COMPARE_OP
108,IMPORT_FROM,IMPORT_FROM,IMPORT_FROM,IMPORT_NAME
109,None,None,None,IMPORT_FROM
111,JUMP_IF_FALSE,JUMP_IF_FALSE,JUMP_IF_FALSE,JUMP_IF_FALSE_OR_POP
112,JUMP_IF_TRUE,JUMP_IF_TRUE,JUMP_IF_TRUE,JUMP_IF_TRUE_OR_POP
114,None,None,None,POP_JUMP_IF_FALSE
115,None,None,None,POP_JUMP_IF_TRUE

以下、比較に使ったプログラムです。


rem opcmp.bat
c:\python27\python opdump.py > py27.py
c:\python26\python opdump.py > py26.py
c:\python25\python opdump.py > py25.py
c:\python26\python opcmp.py > opcmp.csv

# opdump.py
import dis
opname = dis.opname
for i in range(256):
    if opname[i][0] == "<":
        opname[i] = None
print "opname=" + str(opname)

# opcmp.py
import py27
import py26
import py25
import pmImgCreator
import dis

pic = pmImgCreator.PmImgCreator("pmfeatures.py")

print ",pyMite(p14p),python2.5,python2.6,python2.7"
for i in range(256):
    if len(set([pic.bcodes[i], py25.opname[i], py26.opname[i], py27.opname[i]])) > 1:
        print"%d,%s,%s,%s,%s" % (i, pic.bcodes[i], py25.opname[i], py26.opname[i], py27.opname[i])


(2013/2/26)
---

2013年1月23日水曜日

cosmのトリガーでメールを送る


cosmのトリガーHTTP POSTでGAEを叩いてメールを送っていたが、
メールの送り先をGAEの管理者に変更してみた。
管理者メールはGmailで登録しているので、フィルターで携帯電話に転送している。

センサーmbed → cosm → GAE → gmail → 携帯電話

15分間データの更新が無いとfrozenのトリガーがあるのでmbedが無反応になったのもわかります。


# cosmtrigger.py 2013/1/23
#coding: utf-8
import webapp2
from google.appengine.api import app_identity
from google.appengine.api import mail

class TriggerHandler(webapp2.RequestHandler):
    def post(self, param):
        json_str = self.request.get('body')
        mail.send_mail_to_admins(
              sender = "cosmtrigger@" + app_identity.get_application_id() + ".appspotmail.com",
              subject = "cosm trigger %s" % param, body = json_str)

app = webapp2.WSGIApplication([
    (r'/cosmtrigger/(.*)', TriggerHandler),
    ], debug=True)


(2013/1/23)
---