プログラムからインタラクティブモードを使う
プログラムから自動的にインタラクティブモードにアクセスする方法
インタラクティブモードはシリアルポートを利用するため、機械的に操作することもできます。
生産工程においては、インタラクティブモードを自動的に利用したい場面があるかもしれません。Python を使って設定値を読み出す例を紹介します。
インタラクティブモードの仕組み
初期状態では、TWELITE の RX
ポートは 115200bps 8N1 の設定で動作しています。インタラクティブモードに遷移するには、200msから1000ms程度の間隔で +
を3回入力します。インタラクティブモードの操作はASCII文字を入力するだけの処理であることから、インタラクティブモードに入ってしまえば、あとは自由にプログラム操作することができます。
実装例
Pythonによる設定値の読み出し
ここでは、シリアル通信アプリApp_Uart
を書き込んだTWELITEから、TWELITE R2/R3 を通じてシリアルIDと設定値を読み出すスクリプトを記載します。
TWELITE R2/R3 の識別とシリアルポートの取得、また TWELITE R2/R3 によるリセットピンの制御を行うために、tweliter
モジュールを利用しています。
pip install tweliter
スクリプト
Python 3.12 を使って実装しています。
get_serial_id_and_settings()
関数を再利用できます。
# -*- coding: utf-8 -*-
import time
import re
from tweliter import Tweliter # Mono Wireless module for TWELITE R devices
def get_serial_id_and_settings() -> tuple[str, dict[str, str]] | None:
"""
Get the serial ID and settings from the interactive mode of a TWELITE R device.
Returns:
tuple[str, dict[str, str]] | None:
A tuple containing:
- str: the serial ID (e.g., "0x82010079")
- dict[str, str]: the settings dictionary (e.g., {'a': '0x67720103', ...})
Returns None if the device cannot be accessed or the output is invalid.
Notes:
Example output from the interactive mode of an App_Uart device:
--- CONFIG/TWE UART APP V1-04-6/SID=0x82010079/LID=0x78 -- ---
a: set Application ID (0x67720103)
i: set Device ID (120=0x78)
c: set Channels (18)
x: set RF Conf (3)
r: set Role (0x0)
l: set Layer (0x1)
b: set UART baud (38400)
B: set UART option (8N1)
m: set UART mode (E)
k: set Tx Trigger (sep=0x0d0a, min_bytes=0 dly=0[ms])
h: set header format [;U;%t;%i;0x%A;%q;%s;<*;%X;\n]
C: set crypt mode (0)
o: set option bits (0x00000100)
---
S: save Configuration
R: reset to Defaults
"""
try:
with Tweliter(
type_filter=Tweliter.Type.TWELITE_R2 | Tweliter.Type.TWELITE_R3
) as liter:
# Reset the device
liter.reset_device()
# Get the serial port instance (pyserial)
ser = liter.get_serial_instance()
ser.timeout = 1.0
# Enter to the interactive mode
for _ in range(3):
ser.write("+")
time.sleep(0.3)
# Read the output
raw_output = ser.read_until(b"S:").decode("utf-8")
# Reset the device (Exit interactive mode)
liter.reset_device()
except IOError as e:
print(f"Couldn't open the device {e}")
return None
# Find the settings block in the output
filter_output = re.search(r"---(.*?)---(.*?)---", raw_output, re.DOTALL)
if filter_output:
information_line = filter_output.group(1)
settings_block = filter_output.group(2)
else:
print("No settings block found.")
return None
# Extract serial id from the information line
serial_id_match = re.search(r"SID=0x([0-9A-Fa-f]+)", information_line)
if serial_id_match:
serial_id = f"0x{serial_id_match.group(1)}"
else:
print("Serial ID not found.")
return None
# Extract key-value pairs (str,str) from the settings block
settings_dict = dict(
re.findall(r"^\s*(\w):.*?\(([^()]*)\)", settings_block, re.MULTILINE)
)
return serial_id, settings_dict
def main() -> None:
# Get the serial ID and settings from the device
result = get_serial_id_and_settings()
if result is None:
print("Failed to retrieve serial ID and settings.")
return
serial_id, settings = result
# Show the results
print(f"Serial ID: {serial_id}")
for id, value in settings.items():
match id:
case "a":
print(f"Application ID: {value}")
# case "i":
# print(f"Logical ID: {value}")
# case "c":
# print(f"Channel: {value}")
if __name__ == "__main__":
main()
解説
インタラクティブモードの出力を読み出す流れ
- TWELITE をリセットする
- リセットにより、インタラクティブモードに入るための初期状態に戻します。ここでのリセットは、TWELITE R2/R3 のリセットピン制御によって行います。
- シリアルポートのインスタンスを取得する
pyserial
により、PC 側から TWELITE のシリアル入出力にアクセスするためのインスタンスを取得します。このインスタンスを通じて、後続のコマンド送信やデータの読み出しを実行できます。
+
を3回入力する- 一定間隔(200〜1000ms)で
+
を3回送信することで、TWELITE はインタラクティブモードに遷移します。この方法はユーザー手動での操作と同様です。
- 一定間隔(200〜1000ms)で
- 保存コマンドの説明
S:
まで読み取る- インタラクティブモードでは、設定値が並んだあとに
S:
という保存コマンドの説明行が現れるため、そこまで読み取ることで一連の設定内容をすべて取得できます。
- インタラクティブモードでは、設定値が並んだあとに
- TWELITE をリセットする
- 読み出しが終わったら、再度リセットしてインタラクティブモードから通常モードに戻します。
with Tweliter(
type_filter=Tweliter.Type.TWELITE_R2 | Tweliter.Type.TWELITE_R3
) as liter:
# Reset the device
liter.reset_device()
# Get the serial port instance (pyserial)
ser = liter.get_serial_instance()
ser.timeout = 1.0
# Enter to the interactive mode
for _ in range(3):
ser.write("+")
time.sleep(0.3)
# Read the output
raw_output = ser.read_until(b"S:").decode("utf-8")
# Reset the device (Exit interactive mode)
liter.reset_device()
インタラクティブモードの出力を解釈する流れ
一行目と
---
に挟まれたブロックを抽出するre.search(r"---(.*?)---(.*?)---", raw_output, re.DOTALL)
により、インタラクティブモードの出力から設定全体の情報を2つの部分に分けて取り出します。最初のキャプチャグループは、シリアルIDなどが含まれる情報行(information_line
)、2つ目は設定項目が並ぶ設定値ブロック(settings_block
)です。re.DOTALL
により、改行を含む全文検索が可能になります。
一行目からシリアルIDを抽出する
re.search(r"SID=0x([0-9A-Fa-f]+)", information_line)
を使って、SID=0x
に続く16進数のID値(例:82010079
)を取得し、それを0x82010079
のような文字列に整形します。16進数は大文字小文字を区別せずに抽出されます。
ブロックからコマンドIDと値のペアを抽出する
re.findall(r"^\s*(\w):.*?\(([^()]*)\)", settings_block, re.MULTILINE)
を使って、設定値の各行からa: ... (値)
のような形式を対象に、コマンドID(1文字)と括弧内の値を取り出します。先頭の空白、コロン以降の任意文字列をスキップし、最初に見つかる括弧内の値のみを抽出します。re.MULTILINE
により、複数行に対応した検索ができます。
# Find the settings block in the output
filter_output = re.search(r"---(.*?)---(.*?)---", raw_output, re.DOTALL)
if filter_output:
information_line = filter_output.group(1)
settings_block = filter_output.group(2)
else:
print("No settings block found.")
return None
# Extract serial id from the information line
serial_id_match = re.search(r"SID=0x([0-9A-Fa-f]+)", information_line)
if serial_id_match:
serial_id = f"0x{serial_id_match.group(1)}"
else:
print("Serial ID not found.")
return None
# Extract key-value pairs (str,str) from the settings block
settings_dict = dict(
re.findall(r"^\s*(\w):.*?\(([^()]*)\)", settings_block, re.MULTILINE)
)
return serial_id, settings_dict