2019年4月14日日曜日

PlatformIOのビルド時のコマンドでマクロの変数を定義する方法


背景

PlatformIOとは、ArduinoやESP32などの組み込み用マイコンのビルド環境の一つです。
マクロとは、c言語では「#」で始まる、プログラムのビルド時に解釈や計算される記述です。

マクロを使うと、デバッグ用の出力をするかしないかや、プログラムの機能の有効無効などを、プログラムの容量をそれほど増やさず切り替えられたりします。

自分は今まで、マクロをプログラム内部に記述したりコメントアウトしたりすることで切り替えていました。
しかし、PlatformIOには環境変数としてマクロを記述する方法があると分かったので、これを使うことでビルドコマンド実行時に設定を切り替えられるようになりました。

便利だと思うので、備忘録を兼ねて方法を共有します。

使ったもの

PlatformIO

背景でも説明した開発環境です。
PCにインストールしてください。

Installation

動作確認に利用したpythonとPlatformIOの バージョンはこちらです。
$ python --version
Python 2.7.15rc1
$ pio --version
PlatformIO, version 3.6.6

PlatformIOから書き込めるボード

Arduino Leonardoの互換機であるProMicroを利用しました。
(Leonardo向けの設定で書き込めます。)

販売ページ:
スイッチサイエンス
aliexpress(中国)

プログラムを作成

デバッグ用出力の切り替えとデバイスIDの埋め込みをマクロの「DEVICE_ID」と「DEBUG_PRINT」で切り替えられるプログラムを作ってみました。
デバッグ出力が有効の時にデバイスIDが定義されていなければ、「dummy_device_id」をデバイスIDとして定義するようにしています。

src/main.cpp
#include <Arduino.h>

#if defined(DEBUG_PRINT) && !defined(DEVICE_ID)
#define DEVICE_ID "dummy_device_id"
#endif

void setup() {
  Serial.begin(115200);
}

void loop() {
  Serial.println("hello");
  Serial.println(DEVICE_ID);
#ifdef DEBUG_PRINT
  Serial.println("debug print: " + String(millis()));
#endif
  delay(1000);
}

この記事の動作確認に使ったプログラムを含むプロジェクトはgithubで公開しています。

プロジェクト: asukiaaa/pio_macro_practice
プログラム: asukiaaa/pio_macro_practice/src/main.cpp

ビルド・アップロード時にマクロの変数を指定

デバイスIDを指定

先ほど紹介したプログラムは、何も意識せずにビルドするとデバイスIDが指定されていないためエラーが発生します。
pio run
src/main.cpp: In function 'void loop()':
src/main.cpp:16:18: error: 'DEVICE_ID' was not declared in this scope
Serial.println(DEVICE_ID);
^
*** [.pioenvs/leonardo/src/main.cpp.o] Error 1

下記のようにデバイスIDをマクロの変数として定義しながらコマンドを実行すると、ビルドが成功します。
具体的には、PLATFORMIO_BUILD_FLAGSビルドオプションを渡せるので、「DEVICE_ID」という変数名で「a_device_id」という文字列を定義しています。
PLATFORMIO_BUILD_FLAGS="-D DEVICE_ID=\\\"a_device_id\\\"" pio run

「-t upload」を付ければデバイスIDを指定しながらプログラムをアップロードできます。
PLATFORMIO_BUILD_FLAGS="-D DEVICE_ID=\\\"a_device_id\\\"" pio run -t upload

シリアル出力を見ると、コマンドで指定したデバイスIDが期待通りに扱われていることを確認できます。
pio device monitor -b 115200
hello
a_device_id

ビルドやアップロード時のコマンドで「\」が3つ連続で並んでいるのは、文字列に「\"」という文字を渡すために、「\」と「"」を「\」で文字として認識(エスケープ)させているためです。
PlatformIOの過去の対応で\は1つでも良くなったはずなのですが、3つでないと定義した文字列の変数名を呼び出そうとして、下記のようなエラーが出てしまいました。
PlatformIOが更新されたら「\」は3つでなく1つでも動くようになるかもしれません。
PLATFORMIO_BUILD_FLAGS="-D DEVICE_ID=\"a_device_id\"" pio run
src/main.cpp: In function 'void loop()':
<command-line>:0:11: error: 'a_device_id' was not declared in this scope
src/main.cpp:16:18: note: in expansion of macro 'DEVICE_ID'
Serial.println(DEVICE_ID);
^
Compiling .pioenvs/leonardo/FrameworkArduino/HardwareSerial0.cpp.o
*** [.pioenvs/leonardo/src/main.cpp.o] Error 1

デバッグ用の出力を有効化

下記のようにデバッグ出力を有効化する変数(DEBUG_PRINT)をマクロで定義しながらコマンドを実行すると、デバッグ用の情報(DEBUG_PRINTが定義された時だけ有効になるSerial.println)が出力されます。
PLATFORMIO_BUILD_FLAGS=-DDEBUG_PRINT pio run

「-D」と「DEBUG_PRINT」の間を開けたい場合は、変数の定義を文字列にすればスペースを空けられます。
PLATFORMIO_BUILD_FLAGS="-D DEBUG_PRINT" pio run

「-t upload」を付ければ、デバッグ出力を有効にしたプログラムをアップロードできます。
PLATFORMIO_BUILD_FLAGS="-D DEBUG_PRINT" pio run -t upload

シリアル出力を見ると、デバッグ出力時に設定されるデバイスIDと、デバッグ用の情報を確認できます。
pio device monitor -b 115200
hello
dummy_device_id
debug print: 4001
hello
dummy_device_id
debug print: 5001

デバイスIDの指定とデバッグ用出力の有効化を同時に実行

PLATFORMIO_BUILD_FLAGSに渡す文字列にスペースを空けることで複数のマクロを定義できます。
下記のコマンドで、デバイスIDを指定しつつ、デバッグ出力を有効にしてビルドできます。
PLATFORMIO_BUILD_FLAGS="-D DEVICE_ID=\\\"a_device_id\\\" -D DEBUG_PRINT" pio run

「-t upload」を付けると、アップロードできます。
PLATFORMIO_BUILD_FLAGS="-D DEVICE_ID=\\\"a_device_id\\\" -D DEBUG_PRINT" pio run -t upload

シリアル出力を見ると、指定したデバイスIDを扱っていることと、デバッグ用の情報を確認できます。
pio device monitor -b 115200
hello
a_device_id
debug print: 3001
hello
a_device_id
debug print: 4001

まとめ

PlatformIOのビルドやアップロード時のコマンドでマクロの変数を定義して、プログラムの挙動を変えられました。
デバイスIDをコマンドで変えたい時などに便利そうです。

参考

Environment variables
Build options
Defining variables on the command line breaks for strings.

0 件のコメント :