Skip to content

Commit 178adb3

Browse files
setup for PyPI
1 parent 43779b3 commit 178adb3

File tree

5 files changed

+413
-0
lines changed

5 files changed

+413
-0
lines changed
 

‎pypi/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__pycache__
2+
*~
3+
.*~
4+
build/
5+
dist/
6+
pyuart.egg-info/

‎pypi/Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#Time-stamp: <2023-06-05 17:00:34 hamada>
2+
3+
wheel:
4+
python3 setup.py bdist_wheel
5+
6+
7+
clean:
8+
rm -rf build pyuart.egg-info dist
9+
10+
test.upload:
11+
twine upload --repository testpypi dist/*
12+
13+

‎pypi/README.md

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# pyuart
2+
3+
## 概要
4+
5+
UARTデバッグをpythonスクリプトで行うためのモジュールです。これまで
6+
Tera-termやArduino IDEコンソールなどでライトウェイトにUARTデバッグをし
7+
ていた人が、リモートデバッグ環境を構築したり、並列UART高負荷耐久テスト
8+
等々、もう少し突っ込んだUARTデバッグをしたい時に効果を発揮するはずです。
9+
10+
## 動作環境
11+
12+
動作確認済みの実機環境
13+
- Python 3.10.6
14+
- PC
15+
- CPU: Intel Core i7-12700
16+
- OS: Ubuntu 22.04.2 LTS
17+
- Raspberry Pi 4 Model B Rev 1.5
18+
- CPU: BCM2835
19+
- OS: Ubuntu 22.04.2 LTS
20+
- USB-TTL converter
21+
- QinHeng Electronics CH340 serial converter
22+
- Future Technology Devices International, Ltd FT232 Serial (UART) IC
23+
24+
## 前提
25+
26+
```1 Byte == 1 Octet == 8 bit```
27+
28+
## Installation
29+
30+
```
31+
make setup
32+
make chmod
33+
```
34+
35+
OSS公開後には以下のインストール方法が使える予定
36+
```
37+
pip install pyuart
38+
```
39+
40+
```make chmod```は環境依存です。/dev/serial/* やlsusbなど駆使してUSB-TTL converterデバイスを探しましょう。
41+
詳細はMakefileを読むと理解の助けになるでしょう。
42+
43+
44+
## サンプル
45+
46+
```aelib/uart```モジュールの操作方法のサンプルコードを以下にメモしておきます。
47+
このサンプルを見るだけで動かすことができるはずですが、詳細な説明は後日記載する予定です。
48+
49+
50+
### 例1: 1 octetづつTx(送信)したい場合
51+
52+
```:test_tx.py
53+
from aelib import uart
54+
55+
u0 = uart.uart(dev='/dev/ttyUSB0', baudrate = 115200, timeout = 15)
56+
u0.open()
57+
58+
u0.tx(1)
59+
u0.tx(2)
60+
u0.tx(77)
61+
62+
u0.close()
63+
64+
```
65+
66+
### 例2: 1 octetづつRx(受信)したい場合
67+
68+
```:test_rx.py
69+
from aelib import uart
70+
71+
u0 = uart.uart(dev='/dev/ttyS0', baudrate = 115200, timeout = 240)
72+
u0.open()
73+
74+
for data in u0.rx():
75+
print (data)
76+
77+
u0.close()
78+
79+
```
80+
81+
※: rx()メソッドはジェネレータです。
82+
83+
### 例3: ファイルをTx(送信)したい場合
84+
85+
```:sample.tx.file.py
86+
from aelib import uart
87+
88+
u0 = uart.uart(dev='/dev/ttyUSB0', baudrate = 115200, timeout = 15)
89+
u0.open()
90+
91+
u0.tx_file(filename = '/tmp/file.bin')
92+
93+
u0.close()
94+
95+
```
96+
97+
### 例4: ファイルをRx(受信)したい場合
98+
99+
```sample.rx.file.py
100+
from aelib import uart
101+
102+
u0 = uart.uart(dev='/dev/ttyUSB0', baudrate = 115200, timeout = 15)
103+
u0.open()
104+
105+
u0.rx_file(filename = './recv.bin', n_byte = 1048576)
106+
107+
u0.close()
108+
109+
```
110+
111+
**ファイルRxでの注意事項**
112+
113+
UARTを使ったデータ通信では受け取るファイルのサイズは上位プロトコル層で定義しておかなければファイルサイズを事前に知ることができません。
114+
そのため上位プロトコルを定義していない本モジュールでは、ファイルのRx(受信)実行時に受信ファイルサイズをn_byteで指定する必要があります。
115+
上記のサンプル例では ```n_byte = 1048576```を指定しています。これは1MB(1048576 Byte)のファイルを受信することを指定しています。
116+
117+
(なお、この文章では```1 octet = 1 byte```を仮定しています)
118+
119+
120+
121+
### 例5: 並列Txの実行 (MPI利用)
122+
123+
```mpi.tx.py
124+
#!/usr/bin/env python3
125+
from mpi4py import MPI
126+
from aelib import uart
127+
128+
comm = MPI.COMM_WORLD
129+
proc_id = comm.Get_rank()
130+
nproc = comm.Get_size()
131+
hostname = MPI.Get_processor_name()
132+
133+
devfile = "/dev/ttyUSB%d" % proc_id
134+
print(devfile, flush=True)
135+
136+
u0 = uart.uart(dev=devfile, baudrate = 115200, timeout = 15)
137+
u0.open()
138+
u0.tx(123)
139+
140+
u0.close()
141+
142+
```
143+
144+
並列実行は```make mpirun```や以下のようにmpirunコマンドを使います。
145+
```
146+
mpirun -np 4 --oversubscribe mpi.tx.py
147+
```
148+
149+
150+
151+
152+
## 注意
153+
154+
Ubuntu 22ではCH341チップを使ったUSB-serialコンバーターはそのままでは動きません。
155+
```
156+
sudo apt remove brltty
157+
```
158+
にてbrlttyを削除してから使用しましょう。
159+
160+
161+
[参考|https://stackoverflow.com/questions/70123431/why-would-ch341-uart-is-disconnected-from-ttyusb]
162+
163+
```
164+
For Ubuntu 22.04 the simplest solution is to remove the package brltty
165+
via sudo apt remove brltty, since its unnecessary unless you're using
166+
a braille e-reader, however unsure if it could cause errors later on.
167+
```
168+
169+
## 参考
170+
171+
### ubuntu22 PCでの/dev/serialの一例
172+
173+
```
174+
arkedge@ci01:~/git/pyuart$ ls -l /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0
175+
lrwxrwxrwx 1 root root 13 4月 30 14:58 /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 -> ../../ttyUSB0
176+
```
177+

‎pypi/pyuart/uart.py

+182
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
#!/usr/bin/env python3
2+
3+
__author__ = "ArkEdge Space Inc."
4+
5+
import struct
6+
import serial
7+
import time
8+
import math
9+
import binascii
10+
import pprint
11+
12+
13+
def get_baudrate_list():
14+
return [1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 11520000, 1500000, 20000]
15+
16+
17+
def byte2int(i_byte, i_endian = 'big'):
18+
return int.from_bytes(i_byte, i_endian)
19+
20+
def int2byte(i_int, i_endian = 'big'):
21+
n_octet = math.ceil(math.log2(i_int)/8.0)
22+
print ("n_octet: %d" % n_octet)
23+
return i_int.to_bytes(n_octet, i_endian)
24+
25+
'''
26+
array conversion: int -> byte
27+
array is list in python
28+
'''
29+
def convArrayInt2Byte(array_int):
30+
array_byte = []
31+
for data_i in array_int:
32+
array_byte.append(bytes([0xff & data_i]))
33+
return array_byte
34+
35+
'''
36+
array conversion: byte -> int
37+
array is list in python
38+
'''
39+
def convArrayByte2Int(array_byte):
40+
array_int = []
41+
for _b in array_byte:
42+
_x = struct.unpack('1B', _b)
43+
array_int.append(_x[0])
44+
return array_int
45+
46+
def readFileBin(filename = '__dump__.img'):
47+
with open(filename, mode='rb') as f:
48+
_content = f.read() # list of Integers, not Bytes !
49+
print ('file: %s, size: %d-bytes' % (filename, len(_content)))
50+
51+
# conversion: int -> byte
52+
_array_bytes = []
53+
for _ci in _content:
54+
_array_bytes.append(bytes([_ci]))
55+
56+
return _array_bytes
57+
58+
def writeFileBin(filename = 'tmp.img', data = []):
59+
with open(filename, mode='wb') as f:
60+
for cb in data:
61+
f.write(cb)
62+
63+
byte_order = 'big'
64+
65+
uart_settings = {
66+
'dev': '/dev/ttyUSB0',
67+
'baudrate': 115200, #9600, # 9600, 115200
68+
'timeout': 10,
69+
}
70+
71+
class uart:
72+
73+
def __init__(self, dev=uart_settings['dev'], baudrate=uart_settings['baudrate'], timeout=uart_settings['timeout'], byte_order=byte_order):
74+
self.dev = dev
75+
self.baudrate = baudrate
76+
self.timeout = timeout
77+
self.byte_order = byte_order
78+
79+
def open(self):
80+
self.uart_device = serial.Serial(self.dev, self.baudrate, timeout=self.timeout)
81+
82+
def close(self):
83+
self.uart_device.close()
84+
85+
'''
86+
tx: transfer 1 octet
87+
'''
88+
def tx(self, x_int):
89+
_x_byte = bytes([0xFF & x_int])
90+
return self.uart_device.write(_x_byte)
91+
92+
93+
'''
94+
rx_primitive: receive 1 octet
95+
'''
96+
def rx_primitive(self):
97+
98+
rx_byte = self.uart_device.read(1)
99+
100+
ret = {
101+
'byte': rx_byte,
102+
'int': 0,
103+
'isValid': False,
104+
}
105+
106+
if len(rx_byte) > 0:
107+
rx_int = struct.unpack('1B', rx_byte)[0]
108+
ret = {
109+
'byte': rx_byte,
110+
'int': rx_int,
111+
'is_valid': True,
112+
}
113+
114+
return ret
115+
116+
'''
117+
rx: receive N octets forerver
118+
'''
119+
def rx(self):
120+
121+
while True:
122+
rx_data = self.rx_primitive()
123+
if True == rx_data['is_valid']:
124+
yield rx_data['int']
125+
126+
def __testTx(self, data=0x6162636465666768696a6b6c6d6e6f707172737475767778797a):
127+
_eot = 0x04
128+
data = data << 16 | 0x0D0A # <CR><LF>
129+
data = 0x6465
130+
data_byte = int2byte(data, byte_order)
131+
self.uart_device.write(data_byte)
132+
if False:
133+
print("0x%x" % byte2int(data_byte, byte_order))
134+
time.sleep(1.0)
135+
136+
def tx_file(self, filename = '/tmp/tran.img'):
137+
data_tx = readFileBin(filename = filename)
138+
139+
n_byte = len(data_tx)
140+
progress_tick = int(math.ceil(n_byte / 20.0))
141+
142+
t0 = time.time()
143+
for i, _b in enumerate(data_tx):
144+
self.uart_device.write(_b)
145+
if 0 == (i % progress_tick):
146+
print('=>', end='', flush=True)
147+
t = time.time() - t0
148+
bw = n_byte/t
149+
print("")
150+
print(": End UART-Tx")
151+
print("--------------------------------")
152+
print("BandWidth: %f KByte/sec" % (bw/1024.))
153+
print("--------------------------------")
154+
return {
155+
'n_byte': n_byte,
156+
'wallclocktime': t,
157+
'bandwidth': bw,
158+
}
159+
160+
161+
def rx_file(self, filename = '/tmp/recv.img', n_byte = 1048576):
162+
progress_tick = int(math.ceil(n_byte / 20.0))
163+
data_rx = []
164+
data_rx_byte = []
165+
for i in range(n_byte):
166+
rx_byte = self.uart_device.read(1)
167+
rx_int = struct.unpack('1B', rx_byte)[0]
168+
data_rx.append(rx_int)
169+
data_rx_byte.append(rx_byte)
170+
171+
if 0 == i % progress_tick:
172+
print ('=>', end = '', flush = True)
173+
174+
writeFileBin(filename = filename, data = data_rx_byte)
175+
176+
print("\n: End UART-Rx")
177+
178+
179+
180+
def diag(self):
181+
pprint.pprint(vars(self))
182+
return vars(self)

‎pypi/setup.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from setuptools import setup
2+
from codecs import open
3+
from os import path
4+
5+
here = path.abspath(path.dirname(__file__))
6+
7+
8+
with open(path.join(here, 'README.md'), encoding='utf-8') as f:
9+
long_description = f.read()
10+
11+
setup(
12+
name='pyuart', # パッケージ名(プロジェクト名)
13+
packages=['pyuart'], # パッケージ内(プロジェクト内)のパッケージ名をリスト形式で指定
14+
15+
version='0.0.1', # バージョン
16+
17+
license='MIT', # ライセンス
18+
19+
install_requires=['pyserial'], # pip installする際に同時にインストールされるパッケージ名をリスト形式で指定
20+
21+
author='Tsuyoshi Hamada', # パッケージ作者の名前
22+
author_email='hamada@arkedgespace.com', # パッケージ作者の連絡先メールアドレス
23+
24+
url='https://github.com/arkedge/pyuart', # パッケージに関連するサイトのURL(GitHubなど)
25+
26+
description='a simple UART library for python3', # パッケージの簡単な説明
27+
long_description='pyuart', # PyPIに'Project description'として表示されるパッケージの説明文
28+
long_description_content_type='text/markdown', # long_descriptionの形式を'text/plain', 'text/x-rst', 'text/markdown'のいずれかから指定
29+
keywords='pyuart uart', # PyPIでの検索用キーワードをスペース区切りで指定
30+
31+
classifiers=[
32+
'License :: OSI Approved :: MIT License',
33+
'Programming Language :: Python :: 3.10',
34+
], # パッケージ(プロジェクト)の分類。https://pypi.org/classifiers/に掲載されているものを指定可能。
35+
)

0 commit comments

Comments
 (0)
Please sign in to comment.