3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

1. シリアルポート

Arduino、マイコンボードやUSBシリアル変換器をUSBポートに差し込むと、シリアルポートにそれぞれ現れます。

% alias lsu
lsu='ls /dev/cu.*'

% lsu
/dev/cu.Bluetooth-Incoming-Port	/dev/cu.usbserial-0001
/dev/cu.usbmodem1101		/dev/cu.usbserial-2120
/dev/cu.usbmodem13301		/dev/cu.wchusbserial2120
/dev/cu.usbmodemHIDEF1		/dev/cu.wlan-debug

一部ですが、↓ざっとこんな感じです。

  • マイコン系
シリアルポート 内容 
/dev/cu.usbmodemHIDEF1 自作プログラマブルテンキー(ATMega32U4 ネイティブUSB)常時接続
/dev/cu.usbmodemC7FD1ADFA7491 自作ボード(ESP32-S3 ネイティブUSB) CircuitPython REPL
/dev/cu.usbmodem0000000000001 RP2040 Dev Board (USB CDC)
/dev/cu.usbmodem13201 Raspberry Pi Pico Micropython REPL
/dev/cu.usbmodem12401 Seeed Studio XIAO RP2040
/dev/cu.usbmodem21201 Adafruit Feather nRF52840
  • Arduino系
シリアルポート 内容 
/dev/cu.usbmodem11101 Arduino Uno R3
/dev/cu.usbmodem11201 Arduino Uno R4 Minia
/dev/cu.usbserial-1140 Arduino Nano 互換機(Atmega328p、CH340C)
  • USBシリアル変換器
シリアルポート 内容 
/dev/cu.wchusbserial53250003491 ESP32ダウンローダ(WCH CH9102F)
/dev/cu.usbmodemBC5C61321D8E2 Wch-Link(旧式)(WCH CH549G)
/dev/cu.usbmodem8D568F0612342 Wch-LinkE-R0-1v3(WCH CH32V305FBP6)
/dev/cu.usbmodem05581 USB Console Stub(HOLTEK HT43B534-2)
/dev/cu.usbserial-120 USB-TTL変換モジュール(WCH CH340C)

もちろんですが、接続するUSBポートを変えると、数字部分が変化します。

WindowsOSCOMxx が、短くてうらやましい。。。

2. 複数あるシリアルポートを簡単に選びたい

screenコマンドや、esptoolmpremoteampyなどのコマンドで、接続しているマイコンのシリアルポートを指定する必要があるが、毎回lsコマンドを叩いてシリアルポートを確認して入力するのが面倒なので、一覧から選択できるchooserialコマンド(choose serial)を作成した。

% chooserial
1: /dev/cu.usbmodem1101
2: /dev/cu.usbmodem13301
3: /dev/cu.usbserial-0001
4: /dev/cu.usbserial-2120
5: /dev/cu.wchusbserial2120
Choose device number (1-5);5<enter>
/dev/cu.wchusbserial2120        

プロンプトは、stderrに出力し、番号入力で選ばれたシリアルポートをstdoutに(改行無しで)出力します。
選択可能なシリアルポートが1つしかない場合は、プロンプトせず、そのポートを返します。
また、writeモードでダミーopenすることで、他で使用中のシリアルポートを選択肢から除外します。

使用例
% esptool.py --chip auto --port `chooserial` flash_id
1: /dev/cu.usbmodem1101
2: /dev/cu.usbmodem13301
3: /dev/cu.usbserial-0001
4: /dev/cu.usbserial-2120
5: /dev/cu.wchusbserial2120
Choose device number (1-5);2
esptool.py v4.6.2
Serial port /dev/cu.usbmodem13301
Connecting...
Detecting chip type... ESP32-S3
Chip is ESP32-S3 (revision v0.1)
Features: WiFi, BLE
Crystal is 40MHz
MAC: xx:xx:xx:xx:xx:xx
Uploading stub...
Running stub...
Stub running...
Manufacturer: c8
Device: 4018
Detected flash size: 16MB
Flash type set in eFuse: quad (4 data lines)
Hard resetting via RTS pin...
不正入力時の再プロンプト
% screen `chooserial` 115200
1: /dev/cu.usbmodem1101
2: /dev/cu.usbmodem13301
3: /dev/cu.usbserial-0001
4: /dev/cu.usbserial-2120
5: /dev/cu.wchusbserial2120
Choose device number (1-5);6
Choose device number (1-5);x
Choose device number (1-5);?
1: /dev/cu.usbmodem1101
2: /dev/cu.usbmodem13301
3: /dev/cu.usbserial-0001
4: /dev/cu.usbserial-2120
5: /dev/cu.wchusbserial2120
Choose device number (1-5);2

ESP-NOW Recv Ready!

(Ctrl-A Ctrl-K)
[screen is terminating]
%

シェルの機能でtabキーによるパス名補完があるが、それでもchooserialコマンドに慣れると、圧倒的に楽です。

3. ソースコード

C++で作りました。

chooserial.cpp
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
vector<string> lsu;
void promptN() {
    fprintf(stderr, "Choose device number (1-%d);", lsu.size());
}
void prompt() {
    int n = 1;
    for (const auto& s: lsu) {
        cerr << n++ << ": " << s << endl;
    }
    promptN();
}
const int BUF = 256;
char buf[BUF];
int run(string cmd) {
    FILE *fp;
    fp = popen(cmd.c_str(), "r");
    if (!fp) {
        cerr << "popen error" << endl;
        return -1;
    }
    while (fgets(buf, BUF, fp)) {
        buf[strlen(buf) - 1] = '\0'; //remove last '\n'
        lsu.push_back(string(buf));
    }
    pclose(fp);

    for (auto it = lsu.begin(); it != lsu.end();) {
        //filter starts_with("cu.")
        if (it->substr(0, 3).compare("cu."))
            it = lsu.erase(it);
        else {
            *it = "/dev/" + *it;
            //dummy open 
            FILE *fp = fopen(it->c_str(), "w");
            if (fp) ++it, fclose(fp);
            else it = lsu.erase(it);
        }
    }
    //for (const auto& s: lsu) cout << s << endl; //for debug
    return lsu.size();
}
int strToi(const string s, int defaultValue = 0) {
    int result;
    try {
        result = stoi(s);
    } catch (invalid_argument& e) {
        return defaultValue;
    }
    return result;
}
int main(void) {
    switch (run("ls /dev")) {
    case -1: //fallthrough
    case 0: cout << "NO_DEVICES"; return -1;
    case 1: cout << lsu[0]; return 0;
    default: break;
    }

    prompt();
    int n = -1;
    do {
        if (fgets(buf, BUF, stdin)) {
            if (buf[0] == '?') { prompt(); continue; }
            if ((n = strToi(string(buf), -1)) >= 0) {
                if (n < 1 || lsu.size() < n) n = -1;
            }
        }
        if (n == -1) promptN();
    } while (n == -1);
    
    cout << lsu[n - 1];
    return 0;
}
compile & linkage
% c++-13 chooserial.cpp -o chooserial

コマンド名chooserialが長いと思う貴方は、どうぞ短い名前を付けてご利用ください。


関連リンク;

以上

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?