Bottleというフレームワークを試してみた(1)

Flaskよりもさらに軽いPython上のフレームワークで Bottle というのがあるということで、試してみました。

参考にさせていただいたのはこちら(とても参考になる)です。

まずは環境構築。いつものように LinuxMint19 Mate 64bit 上にPythonの仮想環境で準備します。

~/python$ python3 -m venv BottleTest
~/python$ cd BottleTest/
~/python/BottleTest$ source bin/activate
(BottleTest) ~/python/BottleTest$ pip install --upgrade pip
(BottleTest) ~/python/BottleTest$ pip install bottle

これだけ。

おためし用のソースを用意します。

#!/usr/bin/env python3

from bottle import route, run

@route('/hello')
def hello():
    return "Hello World!"

run(host='localhost', port=8080, debug=True, reloader=True)

実行してみます。(コンソール出力も含んでます)

(BottleTest) ~/python/BottleTest$ python3 quickstart.py 
Bottle v0.12.18 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

127.0.0.1 - - [08/Mar/2020 15:02:04] "GET / HTTP/1.1" 404 720
127.0.0.1 - - [08/Mar/2020 15:02:04] "GET /favicon.ico HTTP/1.1" 404 742
127.0.0.1 - - [08/Mar/2020 15:02:16] "GET /hello HTTP/1.1" 200 12

表示してみた感じはこんな感じ。

たしかに簡単です。

VLANを追加

今度は一つのインタフェースにIPアドレスを降るのではなく、VLANタグを追加して、そこにIPアドレスを振ってみます。

まずはインタフェースの状態を確認。今回はPC側でUSBで増設したインタフェースに対して試してみます。インタフェース名の下6桁やMACアドレスなどは掲載時にXXに置換しています。

$ ip -s -d addr show dev enx384b76XXXXXX
3: enx384b76XXXXXX: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 38:4b:76:XX:XX:XX brd ff:ff:ff:ff:ff:ff promiscuity 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
    inet 192.168.0.253/24 brd 192.168.0.255 scope global noprefixroute enx384b76XXXXXX
       valid_lft forever preferred_lft forever
    inet6 fe80::XXXX:XX:XXXX:XXXX/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
    RX: bytes  packets  errors  dropped overrun mcast   
    4170690    14491    0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    3975503    37565    0       0       0       0

VLANを作成してみます

$ sudo ip link add link enx384b76XXXXXX name vlan100 type vlan id 100

結果を確認します(関係ないインタフェースの情報は削除しています)

$ ip -s -d addr show
3: enx384b76XXXXXX: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 38:4b:76:XX:XX:XX brd ff:ff:ff:ff:ff:ff promiscuity 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
    inet 192.168.0.253/24 brd 192.168.0.255 scope global noprefixroute enx384b76XXXXXX
       valid_lft forever preferred_lft forever
    inet6 fe80::XXXX:XX:XXXX:XXXX/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
    RX: bytes  packets  errors  dropped overrun mcast   
    4170690    14491    0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    3978513    37579    0       0       0       0       
7: vlan100@enx384b76XXXXXX: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 38:4b:76:XX:XX:XX brd ff:ff:ff:ff:ff:ff promiscuity 0 
    vlan protocol 802.1Q id 100 <REORDER_HDR> numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
    RX: bytes  packets  errors  dropped overrun mcast   
    0          0        0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    0          0        0       0       0       0

IPアドレスを割り振ってみます。

$ sudo ip addr add 192.168.1.253/24 brd 192.168.1.255 dev vlan100

結果を確認します。

$ ip -s -d addr show dev vlan100
7: vlan100@enx384b76XXXXXX: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 38:4b:76:XX:XX:XX brd ff:ff:ff:ff:ff:ff promiscuity 0 
    vlan protocol 802.1Q id 100 <REORDER_HDR> numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
    inet 192.168.1.253/24 brd 192.168.1.255 scope global vlan100
       valid_lft forever preferred_lft forever
    RX: bytes  packets  errors  dropped overrun mcast   
    0          0        0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    0          0        0       0       0       0

この状態だとインタフェースがDOWNのままなので、起動します。

$ sudo ip link set dev vlan100 up

結果を確認します。

$ ip -s -d addr show dev vlan100
7: vlan100@enx384b76XXXXXX: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 38:4b:76:XX:XX:XX brd ff:ff:ff:ff:ff:ff promiscuity 0 
    vlan protocol 802.1Q id 100 <REORDER_HDR> numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 
    inet 192.168.1.253/24 brd 192.168.1.255 scope global vlan100
       valid_lft forever preferred_lft forever
    inet6 fe80::XXXX:XXXX:XXXX:XXX/64 scope link 
       valid_lft forever preferred_lft forever
    RX: bytes  packets  errors  dropped overrun mcast   
    0          0        0       0       0       0       
    TX: bytes  packets  errors  dropped carrier collsns 
    3181       23       0       0       0       0

この状態では、192.168.0.0/24 にアクセスするとタグ無しで、192.168.1.0/24 にアクセスすると VLANID=100 の802.1Qタグありで通信することになります。

次に、その先のスイッチの設定です。ここではTP-LINKのTL-SG105Eを使っています。

PC側でVLANなしのアドレスの方で192.168.0.253/24を振っているので、こちらを使ってこのスイッチのデフォルトIPアドレスの場合の管理画面へ http://192.168.0.1 にアクセスして admin/admin(初期パスワードの場合)でログインします。

802.1Q VLANの設定で、VLAN ID 100を設定して、このPCが繋がっているポート5をTagged Ports に、その先で Raspberry Pi が繋がっているポート1をUnttaged Ports に設定します。

設定後は上記のような感じです。画面の上半分は設定を行う画面で、VLAN IDのところに設定対象のVLAN IDを入れてから、各ポートの設定内容にチェックをして「Add/Modify」を押して使います。
下半分が設定状況で、VLAN IDが100の行を見ると、Member Ports が 1,5 で、Tagged Ports が 5、Unttaged Ports が 1になっています。ですので、ポート5には802.1Qタグが付いた状態で、ポート1には802.1Qタグがない状態で通信することがわかります。
これだけではダメで、ポート1のPVIDを100に設定して、Raspberry Piとの通信時に使うポート1の通信時に802.1Qタグの付け外しをさせます。

これで、Raspberry Piにpingを打つと帰ってくるようになります。

$ ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.07 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.435 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.517 ms
^C
--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2031ms
rtt min/avg/max/mdev = 0.435/0.676/1.077/0.286 ms

もちろん、SSHでもログインできます。同様のことは Raspberry Pi でもできると思いますが、ip コマンドを使った設定は再起動で失われてしまいます。

永続的に使うには・・・NetworkManegerでやるのが簡単でした・・・。というか、はじめからLinuxMintには入ってた・・・。

以下は設定後のスクリーンショットです。説明いらないくらい簡単のような。

シェル上でも

$ export LANG=jp_JP.UTF-8
$ nmtui

こんな感じで設定できるし、楽ちんです。

で、tuiでできるということは、Raspberry Pi でもsshでログインして、

$ sudo apt-get install network-manager
$ sudo systemctl enable NetworkManager.service
$ sudo systemctl start NetworkManager.service
$ export LANG=ja_JP.UTF-8
$ nmtui

で、

という感じで設定ができてしまいます。

追加できるモジュール?もこんなにたくさん。

$ sudo apt list Network*
Listing... Done
network-config/stable 0.2-2 all
network-manager-config-connectivity-debian/stable 1.14.6-2+deb10u1 all
network-manager-dev/stable 1.14.6-2+deb10u1 armhf
network-manager-fortisslvpn-gnome/stable 1.2.8-2 armhf
network-manager-fortisslvpn/stable 1.2.8-2 armhf
network-manager-gnome/stable 1.8.20-1.1 armhf
network-manager-iodine-gnome/stable 1.2.0-3 armhf
network-manager-iodine/stable 1.2.0-3 armhf
network-manager-l2tp-gnome/stable 1.2.10-1 armhf
network-manager-l2tp/stable 1.2.10-1 armhf
network-manager-openconnect-gnome/stable 1.2.4-2 armhf
network-manager-openconnect/stable 1.2.4-2 armhf
network-manager-openvpn-gnome/stable 1.8.10-1 armhf
network-manager-openvpn/stable 1.8.10-1 armhf
network-manager-pptp-gnome/stable 1.2.8-2 armhf
network-manager-pptp/stable 1.2.8-2 armhf
network-manager-ssh-gnome/stable 1.2.10-1 armhf
network-manager-ssh/stable 1.2.10-1 armhf
network-manager-strongswan/stable 1.4.4-2 armhf
network-manager-vpnc-gnome/stable 1.2.6-2 armhf
network-manager-vpnc/stable 1.2.6-2 armhf
network-manager/stable,now 1.14.6-2+deb10u1 armhf [installed]
networkd-dispatcher/stable 2.0-2 all
networking-bagpipe-doc/stable 9.0.0-2 all
networking-bgpvpn-doc/stable 9.0.0-1 all
networking-mlnx-common/stable 1:13.1.0-2 all
networking-mlnx-eswitchd/stable 1:13.1.0-2 all

一つのNICに複数のIPアドレスを割り振る

わけあって、linux上で一つのNICに複数のIPアドレスを振る必要あって調べました。

最近は ifconfig ではなくて、ip addr が推奨っぽいので、併せて試してみました。

IPアドレスを追加

$ sudo ifconfig eth0:1 192.168.10.1 netmask 255.255.255.0

もしくは

$ sudo ifconfig eth0:1 192.168.10.1/24

でもOKのようだ。

IPアドレスを削除

$ sudo ifconfig eth0:1 down

IPアドレスを確認

$ ifconfig eth0:1

IPアドレスを ip addr で確認

$ ip addr show

IPアドレスを削除

$ sudo ip addr del 192.168.10.1/24 dev eth0

eth0:1 に設定したものもこれで削除できる。

IPアドレスを追加

$ sudo ip addr add 192.168.10.1/24 dev eth0

指定したサブネットの中で生きてるIPアドレスだけを探す

指定したIPアドレス帯の中で生きているIPアドレスだけを知りたいことがあります。こんな時に使えるのが fping コマンドなのですが、オプション指定がめんどくさいです。でも仕方ないのでメモ。

インストールは

$ sudo apt-get install fping

実行する際は

$ fping -g 192.168.1.0/24 -a -q

-g オプションで検索するネットワークアドレスを指定、-a オプションで生きてるアドレスを表示、-q で検索中の表示を黙らせる。そんなところです。

実行するとこんな感じです。

$ fping -g 192.168.1.0/24 -a -q
192.168.1.1
192.168.1.2
192.168.1.253
192.168.1.254
$

古いRaspberry Piをインターネットラジオに

100円ショップのダイソーへ行ったら、300円でアンプ付きのスピーカーが売っていましたので買ってきました。まあ、300円なりの音なのですが、音質にこだわりのまったくない自分には十分です。

で、余っている古いRaspberry Piと組み合わせてBGM用のインターネットラジオにしてみました。

Raspberry Piには基本SSHでアクセスするので、CLIで動く受信プログラムが必要で、少し調べてみると、pyradioというのがあるようで、これをインストールしてみました。

残念ながら apt-get ではインストールできないようで、ソースからインストールすることになりますが、ドキュメントに沿っていけば以下のような手順になりますが、非常に簡単です。記載しているのはほぼ入力するコマンドだけ、実際には大量に表示が出ます。初代Raspberry Piではさすがに遅くて時間がかかりますが、特に問題なく終わりました。

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install mplayer python-setuptools git sed screen
$ git clone https://github.com/coderholic/pyradio.git
$ cd pyradio
$ git fetch --all --tags --prune
Fetching origin
$ git tag
0.1
0.4
0.6.0
0.7.0
0.7.1
0.7.2
0.7.3
0.7.4
0.7.5
0.7.6
0.7.6.1
0.7.6.2
0.7.7
0.7.8
0.7.9
0.8.0
0.8.1
0.8.2
0.8.3
0.8.4
0.8.5
0.8.6
0.8.7
0.8.7.1
$ git checkout tags/0.8.7.1 -b 0.8.7.1
Switched to a new branch '0.8.7.1'
$ devel/build_install_pyradio

終了したら、

$ pyradio -u mplayer

でコマンドラインから起動するとインターネットラジオ局のリストが表示されるので、カーソルキーで選んで Enter キーを押すと再生されます。

正直、あまり局数は多くないですが、自分には十分です。

Windows10にPython3環境を構築(3)

Python仮想環境上でサンプルプログラムをexe化してみます。

まず、pipをインストールします。

(sample) D:\Python3\sample>python -m ensurepip --default-pip
Looking in links: c:\Users\tomok\AppData\Local\Temp\tmphubv8k11
Requirement already satisfied: setuptools in d:\python3\sample\lib\site-packages (41.2.0)
Collecting pip
Installing collected packages: pip
Successfully installed pip-19.2.3

(sample) D:\Python3\sample>python -m pip install --upgrade pip
Collecting pip
  Using cached https://files.pythonhosted.org/packages/54/0c/d01aa759fdc501a58f431eb594a17495f15b88da142ce14b5845662c13f3/pip-20.0.2-py2.py3-none-any.whl
Installing collected packages: pip
  Found existing installation: pip 19.2.3
    Uninstalling pip-19.2.3:
      Successfully uninstalled pip-19.2.3
Successfully installed pip-20.0.2

(sample) D:\Python3\sample>

次に、pyinstaller をインストールします。

D:\Python3\sample>pip install pyinstaller

適当なソースコードを用意して保存します。

#
print('Hello Windows Python')

exe化して実行してみます。

(sample) D:\Python3\sample>pyinstaller hello.py --onefile
(sample) D:\Python3\sample>dist\hello.exe
Hello Windows Python

(sample) D:\Python3\sample>

ということで、サンプルプログラムは無事に(?)exe化できました。

Windows10にPython3環境を構築(2)

次に、ソースコードを書く環境を作ります。

Visual Studio Codeを試してみたいところですが、今回は簡単に入る Geany を試してみます。

公式サイトから「Download Geany 1.36」をクリックして、ダウンロードページに移行します。

GPGのシグネチャと鍵があるので、検証します・・・が、Windowsでやるのは面倒なので、Raspberry PiにSSHでログインしてダウンロードと検証を行いました。検証方法はこちらを参考にさせていただきました。それにしても、最近のWindows10は標準でSSHクライアントが入っていたり、mDNSに対応していたりで便利になっています。検証が終わったら、Windows側にSCPでコピーしてきます。

D:\>ssh pi@white.local
pi@white:~ $ mkdir TEMP
pi@white:~ $ cd TEMP
pi@white:~/TEMP $ wget https://download.geany.org/geany-1.36_setup.exe
pi@white:~/TEMP $ wget https://download.geany.org/geany-1.36_setup.exe.sig
pi@white:~/TEMP $ wget https://download.geany.org/eht16-pubkey.txt
pi@white:~/TEMP $ gpg --import < eht16-pubkey.txt
gpg: key 579347E6C71A77FA: 4 signatures not checked due to missing keys
gpg: /home/pi/.gnupg/trustdb.gpg: trustdb created
gpg: key 579347E6C71A77FA: public key "Enrico Tröger <enrico.troeger@uvena.de>" imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: no ultimately trusted keys found
pi@white:~/TEMP $ gpg --verify geany-1.36_setup.exe.sig geany-1.36_setup.exe
gpg: Signature made Sat 28 Sep 2019 22:32:20 JST
gpg:                using RSA key 51A0918FEF3439066BEB87F4579347E6C71A77FA
gpg: Good signature from "Enrico Tröger <enrico.troeger@uvena.de>" [unknown]
gpg:                 aka "Enrico Tröger <eht16@fsfe.org>" [unknown]
gpg:                 aka "Enrico Tröger <enrico@xfce.org>" [unknown]
gpg:                 aka "Enrico Tröger <enrico@geany.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 51A0 918F EF34 3906 6BEB  87F4 5793 47E6 C71A 77FA
pi@white:~/TEMP $ exit
logout
Connection to white.local closed.

D:\>scp pi@white.local:~/TEMP/geany-1.36_setup.exe .
pi@white.local's password:
geany-1.36_setup.exe                                               100%   15MB   3.0MB/s   00:05

D:\>

SCPでコピーが完了したら、ファイルをダブルクリックしてインストーラを起動、インストールします。インストールが完了して Geany を起動するとこんな感じです。

無事にインストールが完了しました。

Windows10にPython3環境を構築(1)

Windows10(64bit)にPython3の環境を構築しました。その際のメモです。

まずは何よりPython3本体のインストールです。以前はPython2.7とPython3を共存させるインストールのしかたをしていましたが、Python2.7のサポートは今年の1月1日に終了していますので、Python3一本で行きます。
(・・・と思ったら、Python2.7のサポート終了は4月に延期されてる??

インストールするバージョンについては、最新版は3.8系ですがPyinstallerを使いたいので、Pyinstallerが対応している3.7系をインストールします。32bitか64bitかですが、Pyinstallerで持っていく先が稀に32bitの可能性はあるかもしれないのですが、それでも今回は64bitにしてみます。

あと、Python仮想環境の構築は venv を使うのではなく Anaconda を使うのが流行りのようなのですが、AnacondaでPyinstallerを使うと生成されるexeファイルが巨大化するという話をたくさん見かけるので、Anacondaは使わずに素の venv で仮想化してみます。(Anacondaは使ったことがないので、そのうちまずLinuxで使ってみることにします)

ということで、まずはWindows版セットアップに関する公式ガイドを読みます。このガイドをみると32bit版と64bit版は共存できそうな雰囲気ですので、両方インストールしてみます。Python公式サイトのWindows版ダウンロードページからPython3.7系の最新版であるPython3.7.6のWindows x86-64 executable installer と Windows x86-64 executable installerをダウンロードしてきてそれぞれ実行します。

それぞれインストーラを起動したら「Install Now」をクリックすると、勝手にインストールが進みます。Setup was successful という表示が出ると、下のほうに「Disable path length limit」という表示があります。これはWindowsのパスの長さの260文字制限を解除するレジストリ設定を行ってくれるもののようです。単独で使う分にはいいのですが、Pyinstallerで持ち出すことを考えると、今回は設定しないことにして、「Close」をクリックします。

完了したら、コマンドプロンプトを開いて起動してみます。

D:\>py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()

D:\>py -3.7-32
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 18 2019, 23:46:00) [MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> quit()

D:\>

ということで、64bit版、32bit版それぞれのインストールが確認できました。

引き続き、仮想環境を作ってみます。

D:\>mkdir Python3
D:\>cd Python3
D:\Python3>py -m venv sample
D:\Python3>cd sample
D:\Python3\sample>Scripts\activate
(sample) D:\Python3\sample>python
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

実際には途中でコマンドプロンプト内がクリアされますが、上記のような感じになります。

Longan NanoでUSB CDC転送(まだまだ)

Longan NanoでUSBのCDC転送にチャレンジしてみました。CDCで転送ができるとUSBケーブル一本でコンソール出力できる可能性があるからです。

で、まだまだまだまだ道のりは遠いですが、とりあえずライブラリのサンプルプログラムを無理やり動かしてCDC転送はできました。

まず、Platform IOで通常通り、プロジェクト作成します。デバイスは sipeed longan nanoです。

サンプルプログラムについてはGD32VF103_Firmware_Library_V1.0.1の中のExamples/USBFS/USB_Device/CDC_ACMの下にあるものを使用しました。

Sourceディレクトリの中の以下のファイルをプロジェクトディレクトリのsrcの下に放り込みました。

  • app.c
  • cdc_acm_core.c
  • gd32vf103_hw.c
  • gd32vf103_it.c
  • system_gd32vf103.c

同じく、Includeディレクトリの中の以下のファイルをプロジェクトディレクトリのincludeの下に放り込みました。

  • cdc_acm_core.h
  • gd32vf103_it.h
  • gd32vf103_libopt.h
  • usb_conf.h
  • usbd_conf.h

さらに、ドライバは、GD32VF103_Firmware_Library_V1.0.1/Firmware/GD32VF103_usbfs_driverの下にあるものを同様に

Sourceディレクトリの中の以下のファイルをプロジェクトディレクトリのsrcの下に放り込みました。ファイル名に usbh を含むもの、および dev_usb_host.c はホストモードのドライバっぽく、コンパイル中にエラーになるので外しました。

  • drv_usb_core.c
  • drv_usb_dev.c
  • drv_usbd_int.c
  • usbd_core.c
  • usbd_enum.c
  • usbd_transc.c

同じく、Includeディレクトリの中の以下のファイルをプロジェクトディレクトリのincludeの下に放り込みました。同様にファイル名に usbh を含むもの、および dev_usb_host.h は外しました。

  • drv_usb_core.h
  • drv_usb_dev.h
  • drv_usb_hw.h
  • drv_usb_regs.h
  • drv_usbd_int.h
  • usb_ch9_std.h
  • usbd_core.h
  • usbd_enum.h
  • usbd_transc.h

platformio.iniは以下のように編集しました。

[env:sipeed-longan-nano]
platform = https://github.com/sipeed/platform-gd32v.git
board = sipeed-longan-nano
framework = gd32vf103-sdk
upload_protocol = dfu
build_flags = -D USE_USB_FS -D__packed=

ソースコードの中で FIFO のサイズに関するマクロ定義の揺れがあるようで、今回は usb_conf.h を以下のように修正しました。

修正前は以下のような感じ。

#ifdef USB_FS_CORE
    #define RX_FIFO_FS_SIZE                         128
    #define TX0_FIFO_FS_SIZE                        64
    #define TX1_FIFO_FS_SIZE                        128
    #define TX2_FIFO_FS_SIZE                        0
    #define TX3_FIFO_FS_SIZE                        0
#endif /* USB_FS_CORE */

修正後は以下のようにかく定義の頭に USB_ を追加したものを入れています。

#ifdef USB_FS_CORE
//    頭に USB_ を追加
    #define RX_FIFO_FS_SIZE                         128
    #define USB_RX_FIFO_FS_SIZE                         128
    #define TX0_FIFO_FS_SIZE                        64
    #define USB_TX0_FIFO_FS_SIZE                        64
    #define TX1_FIFO_FS_SIZE                        128
    #define USB_TX1_FIFO_FS_SIZE                        128
    #define TX2_FIFO_FS_SIZE                        0
    #define USB_TX2_FIFO_FS_SIZE                        0
    #define TX3_FIFO_FS_SIZE                        0
    #define USB_TX3_FIFO_FS_SIZE                        0
#endif /* USB_FS_CORE */

これでビルドして書き込んでやると、dmesgに以下のように出力されて、/dev/ttyACM0 として認識されました。

[ 3666.200001] usb 2-1: USB disconnect, device number 2
[ 3666.511918] usb 2-1: new full-speed USB device number 3 using uhci_hcd
[ 3666.732800] usb 2-1: New USB device found, idVendor=28e9, idProduct=018a, bcdDevice= 1.00
[ 3666.732804] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 3667.146893] cdc_acm 2-1:1.0: ttyACM0: USB ACM device
[ 3667.148475] usbcore: registered new interface driver cdc_acm
[ 3667.148476] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters

$ sudo screen /dev/ttyACM0 9600

で screen で接続するとエコーバックされました。

wireshark でモニタするために公式ページの説明にそってセットアップします。

$ groups $USER
xxx : xxx adm cdrom sudo dip plugdev lpadmin sambashare
$ sudo adduser $USER wireshark
ユーザー `xxx' をグループ `wireshark' に追加しています...
ユーザ xxx をグループ wireshark に追加
完了。
$ sudo dpkg-reconfigure wireshark-common
$ sudo modprobe usbmon
$ sudo setfacl -m u:$USER:r /dev/usbmon*
$ sudo wireshark 
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'

screenコマンドで接続したまま、usbmon0を選択してキャプチャして、キーボードで適当にカチャカチャ打ってエコーバックされるのを確認したあと、キャプチャを停止します。結果を見ますが、キーボード入力に伴うINTERRUPT転送が見えて鬱陶しいので、表示フィルタを以下のように設定してBULK転送のみが見えるようにします。

usb.transfer_type == 0x3

設定すると、以下のような感じになりました。

キーボードで「B」を入力してそれがホスト(host)からLongan Nano(6.13.3)へ送られたときのキャプチャです。カーソルのあるところが送信されたデータ(0x42)です。

それに対してエコーバックが帰ってきたのが以下です。

データが戻ってきているのがわかります。

とりあえず、CDCでエコーバックされるサンプルは動いたのですが、該当部分のソースを見ると、

    while (1) {
        if (USBD_CONFIGURED == USB_OTG_dev.dev.cur_status) {
            if (1 == packet_receive && 1 == packet_sent) {
                packet_sent = 0;
                /* receive datas from the host when the last packet datas have sent to the host */
                cdc_acm_data_receive(&USB_OTG_dev);
            } else {
                if (0 != receive_length) {
                    /* send receive datas */
                    cdc_acm_data_send(&USB_OTG_dev, receive_length);
                    receive_length = 0;
                }
            }
        }
    }

ということで、パケットバッファのデータを取り出さずにそのまま返送しているっぽいです。これをUSBシリアルっく使えるようにするにはもうひとひねり必要そうです。

 

久しぶりにLongan Nano

久しぶりにLongan Nanoを触ります。

LinuxをLinuxMint18.3に更新したので、再度Platform IOの環境から構築し直します。手順は、前回のこれこれと同じ。

Lチカまで確認できたら、GitHubにあるサンプルプログラムを動かしてみます。まずは、ZIPでダウンロードしてきて展開します。

Platform IOで新規プロジェクトを作成します。プロジェクト作成時には、ボード名は「Sipeed Longan Nano」を選択します。(Sipeed Longan Nano Lite)

作成したら、ダウンロードしてきたサンプルプログラムのgd32v_lcdディレクトリの中のincludeとsrcディレクトリの中身をvscodeのプロジェクトディレクトリのincludeとsrcディレクトリにそれぞれドラッグ&ドロップします。フォルダごとコピーしてworkspaceに追加するか聞いてくるので、「Copy Folders」を選択してコピーします。

platformio.ini を選択して編集します。

[env:sipeed-longan-nano-lite]
platform = https://github.com/sipeed/platform-gd32v.git
framework = gd32vf103-sdk
board = sipeed-longan-nano-lite
upload_protocol = dfu

下の方のチェックマークと右向き矢印でビルドと書き込みができました。画像のファイルの方は put_into_tf_card フォルダの中身を microSD に書き込んで、基板に挿入しておくと、リセットでロゴと動画が再生されました。

さて、やりたいのはデモプログラムを動かすことではありません。せっかくLCDといろんなI/Oがついているボードですから、工作に使いたい。そこで、まずはLCDとUARTを動かしたいところです。

で、いろんなところを参考に・・・というかパクらせてもらいながら作ったのが下記の main.c 。

#include "lcd/lcd.h"
#include "gd32v_pjt_include.h"
#include <stdio.h>
#include <string.h>

void init_uart0(void)
{	
	/* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* connect port to USARTx_Tx */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    /* connect port to USARTx_Rx */
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

	/* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_hardware_flow_rts_config(USART0, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(USART0, USART_CTS_DISABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_enable(USART0);

//    usart_interrupt_enable(USART0, USART_INT_RBNE);
}

int main(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOC);
    gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1|GPIO_PIN_2);

    init_uart0();

    Lcd_Init();			// init OLED
    LCD_Clear(BLACK);
    BACK_COLOR=BLACK;

    LEDR(1);
    LEDG(1);
    LEDB(1);

    LCD_ShowString(24,  0, (u8 *)("Hello World !!"), WHITE);
    LCD_ShowString(24, 16, (u8 *)("Hello World !!"), BLUE);
    LCD_ShowString(24, 32, (u8 *)("Hello World !!"), RED);
    LCD_ShowString(24, 48, (u8 *)("Hello World !!"), GREEN);
    LCD_ShowString(24, 64, (u8 *)("Hello World !!"), GBLUE);
    Draw_Circle(120,40,25,RED);
    LCD_DrawLine(120,0,130,80,BLUE);
    LCD_DrawRectangle(120,40,159,79,GREEN);
    LCD_Fill(130,20,150,30,MAGENTA);
    int c = 0;
    u8 buf[16];
    while (1)
    {
        sprintf(buf,"%d ",c);
        LCD_ShowString(24,  0, buf, WHITE);
        LCD_ShowString(24, 16, buf, BLUE);
        LCD_ShowString(24, 32, buf, RED);
        LCD_ShowString(24, 48, buf, GREEN);
        LCD_ShowString(24, 64, buf, GBLUE);
        LEDR_TOG;
        delay_1ms(20);
        LEDG_TOG;
        delay_1ms(20);
        LEDB_TOG;
        delay_1ms(20);
        usart_printf("COUNT = %d\r\n",c++);
    }
}

int _put_char(int ch)
{
    usart_data_transmit(USART0, (uint8_t) ch );
    while ( usart_flag_get(USART0, USART_FLAG_TBE)== RESET){
    }

    return ch;
}

#include <stdarg.h>
void usart_printf(const char *fmt, ...) {
    char buf[100];
    va_list args;
    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);

    char *p = buf;
    while( *p != '\0' ) {
        _put_char(*p);
        p++;
    }
}


まずは情報源。

LCDライブラリの使い方はこちらのページこちらのページを参考にさせていただきました。UARTの使い方はこちらを参考に、ライブラリのサンプルを見ながら試行錯誤しました。

ライブラリのサンプルなどは http://dl.sipeed.com/LONGAN/Nano/ の下のSDKの下にあるようです。ただ、現時点では基本的なものしかないような感じ。そうはいっても、参考にはなりそうです。UARTもできれば割り込みで動かしたいので、必要な情報はそれなりにありそうです。

今日はこのあたりまで。手探りだと時間がかかりますね・・・。