概要
この記事では、Eclipse Kura の開発環境を構築し、“Serial Example” という実装例を実際に実装し、それをエミュレータ上で動作させるところまでを紹介します。
したがって、この記事の内容を実際に動作させるうえで、Raspberry Pi や BeagleBone Black などの組み込み用途向け PC は必要ありません。
しかし、実際にターミナルを通して通信し動作を確認するには、USB to RS-232C アダプタが2つ、そして RS-232C のクロスケーブル( null model )が1本、それぞれ必要です1)私が利用したケーブル類はこの記事の最後に紹介します。。Eclipse Kura のエミュレータと端末間での通信を実現するためです。
逆に言えば、端末と通信して動作確認をする必要がない場合は、それらはなくて構いません。その場合は、当然通信はできませんが、エミュレータ上で起動し、Web UIを通してコンフィギュレーションの変更を試すことができます。
注意点としては、Eclipse Kura のエミュレータは、現時点では Windows 用が提供されていないため、エミュレータを実行するには開発環境として Linux か MacOSX を使う必要があります。もちろん、Windows で VirtualBox などを使って仮想 Linux をホストする方法でも動作します2)この記事はそのような環境で記述しています。。
前提
Eclipse はすでにインストールされているものとして記述します3)この記事では Eclipse Luna SR2 を使っています。。
また、Eclipse Kura は、1.1.2 をベースに記述します。
手順
ワークスペースを作成する
まずは、“Kura Documentation” の “Getting Started”の内容を参考にしながら、Kura で動作させる Bundle を開発するために必要なワークスペースを作成しましょう。
「ワークスペースの作成」は、”Developer’s Workspace (with Web UI)”の中にある必要なプロジェクトをインポートするだけで完了です。”Developer’s Workspace (with Web UI)”は、“Kura のダウンロードページ”からダウンロードして入手できます4) Kura の 1.1.2 用”Developer’s Workspace (with Web UI)”は、これになります。
あらかじめ Kura 開発用のワークスペースを作成しておき、そのワークスペースにダウンロードした”Developer’s Workspace (with Web UI)”の中に含まれるプロジェクトをインポートします。インポートの方法は、“Getting Started”に記述されている次の手順で行います。
- File メニューの[import…]を選びます。
- Import ダイアログが開きますので、”Geeneral”の中の”Existing Projects into Workspace”を選び、[Next]を押します。
- “Select archive file”をチェックして、[Browse…]を押し、先ほどダウンロードしたzipファイル(“Developer’s Workspace (with Web UI)”) を選択します。すると、ダイアログは画像1のような状態になります。
- [Finish]を押しインポートします5)ここでは、とりあえず全てのプロジェクトをインポートしてしまいます。。すると、ワークスペースは画像2のような状態になります。
3つのプロジェクトでエラーが起きていますが、ここでは問題なしです。
参考までに、インポートしたそれぞれのプロジェクトは次のような位置づけになります(“Getting Started”より引用):
- org.eclipse.kura.api – This is the core Kura API.
- org.eclipse.kura.demo.heater – This is an example project that you can use as a starting point for creating your own bundle.
- org.eclipse.kura.emulator – This is the emulator project for running Kura within Eclipse (Linux/Mac only).
- target-definition – This is a set of required bundles that are dependencies of the APIs and Kura.
ワークスペースのセットアップ
インポートを終えたワークスペースでは、 target-definition プロジェクト以外、エラーが起きている状態になっているはずです。この原因は、それらのプロジェクトに対して、Eclipse プラグイン開発で必要となる Target Platform の設定が行われていないためです。
Target Platform の設定を行うために、Target Difinition を記述しているのが target-definition プロジェクトです6)このプロジェクトでは、Bundle を開発するのに必要な Platform を Equinox をベースにして Target Platform の記述が行われています。。
この記述をワークスペース内の関係するプロジェクト(ここでは、エラーになっているプロジェクト)に適用するには、target-definitionプロジェクトを開き、そこにある kura-equinox_3.8.1.target をダブルクリックして開き、その右上にある “Set as Target Platform” というリンクをクリックします(画像3参照)。
すると、ワークスペース内の各プロジェクトがリビルドされて、次の画像のようにエラーがなくなります。
これで、ワークスペースのセットアップは完了です。
“Serial Example”プロジェクトを実装する
ワークスペースのセットアップが終わったので、“Serial Example” の内容を参考にしながら、”Serial Example”プロジェクトを実装していきましょう。
プロジェクトの作成
では、”org.eclipse.kura.example.serial” という名前のプラグインプロジェクトを作成しましょう。
まず、File メニューの[New]->[Other…]を選びます。New ダイアログが開きますので、そこにある”Plug-in Development”の”Plug-in Project”を選び、[Next]を押します。
次に、”Project Name:”に “org.eclipse.kura.example.serial”と入力します。さらに、Target Platform 欄で、”an OSGi framework:”チェックし”standard”を選択し、[Next]を押します。
Properties 欄の”Execution Environment:”は”JavaSE-1.7″を選び、Options 欄の”Generate an activator, a Java class that controls the plug-in’s life cycle”のチェックを外し、[Finish]を押します。
[Finish]を押すと”Open Associated Perspective?”ダイアログが表示されますが、ここで[Yes]を選びます。すると、ワークスペースのパースペクティブが Plug-in Development に変わり、”org.eclipse.kura.example.serial”という名前のプロジェクトが新規に作成された状態になります。
ここで、”This plug-in is a singleton”をチェックしておきます。
”This plug-in is a singleton”をチェックすると MANIFEST.MF の Bundle-SymbolicName の末尾に”singleton:=true”が追加されます7)http://wiki.osgi.org/wiki/Bundle-SymbolicName。
”Activate this plug-in when one of its classes is loaded”をチェックすると、MANIFEST.MF に”Bundle-ActivationPolicy: lazy”が追加されます8)http://wiki.osgi.org/wiki/Bundle-ActivationPolicyが、 Bundle-Activator を設定していないのでこの記事ではチェックしないでおきます9)チェックしても何も変化がないと思われるためです。変化があるという方がいらっしゃれば是非ご指摘ください。。
“Automated Management of Dependencies”の設定
では、Manifest Editor を使って、Bundle が利用するプラグイン(Bundle)を登録しましょう。
まず、”org.eclipse.kura.example.serial”プロジェクトを開き、META-INF フォルダの中にある MANIFEST.MF をダブルクリックしてください。Manifest Editor によって開かれます。開いた直後は、Overview タブが選ばれた状態です。
次に、利用するプラグインを追加します。利用するプラグインの追加は、Dependencies タブで行います10)エディタの下部にあるタブグループに存在する。 ので、それをクリックしてください。次のような画面になります。
”Automated Management of Dependencies”セクションをクリックしてください。すると次のような画面になります。
[Add]を押して、次のプラグイン(Bundle)をひとつずつ追加していきます。
- org.eclipse.osgi.services
- slf4j.api
- org.eclipse.kura.api
- org.eclipse.equinox.io
これらのプラグインは、target-definition プロジェクトの中で管理されています11)commonまたはequinox_3.8.1フォルダの下にあります。。
その中から開発で利用するプラグインを”Automated Management of Dependencies”セクションで登録することで、その中に存在するクラスを使ってプログラムを記述することができるようになります。さらに、プラグイン(Bundle)としてパッケージ化する際、利用しているクラスのパッケージを”Required Plugin-ins”セクションまたは”Imported Packages”セクションに登録する必要があるのですが、”Automated Management of Dependencies”セクションにある”add dependencies”リンクを押すことで、”Required Plugin-ins”セクションまたは”Imported Packages”セクションにパッケージを自動で登録することができます12)この作業は後程行います。。
org.eclipse.kura.example.serial.SerialExample.java ファイルを作成する
“Serial Example”にある次のコードをそのまま利用して、org.eclipse.kura.example.serial.SerialExample.java ファイルを作成してください。
package org.eclipse.kura.example.serial; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Future; import java.util.concurrent.ScheduledThreadPoolExecutor; import org.osgi.service.component.ComponentContext; import org.osgi.service.io.ConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SerialExample implements ConfigurableComponent { private static final Logger s_logger = LoggerFactory.getLogger(SerialExample.class); private static final String SERIAL_DEVICE_PROP_NAME= "serial.device"; private static final String SERIAL_BAUDRATE_PROP_NAME= "serial.baudrate"; private static final String SERIAL_DATA_BITS_PROP_NAME= "serial.data-bits"; private static final String SERIAL_PARITY_PROP_NAME= "serial.parity"; private static final String SERIAL_STOP_BITS_PROP_NAME= "serial.stop-bits"; private ConnectionFactory m_connectionFactory; private CommConnection m_commConnection; private InputStream m_commIs; private OutputStream m_commOs; private ScheduledThreadPoolExecutor m_worker; private Future<?> m_handle; private Map<String, Object> m_properties; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setConnectionFactory(ConnectionFactory connectionFactory) { this.m_connectionFactory = connectionFactory; } public void unsetConnectionFactory(ConnectionFactory connectionFactory) { this.m_connectionFactory = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext, Map<String,Object> properties) { s_logger.info("Activating SerialExample..."); m_worker = new ScheduledThreadPoolExecutor(1); m_properties = new HashMap<String, Object>(); doUpdate(properties); s_logger.info("Activating SerialExample... Done."); } protected void deactivate(ComponentContext componentContext) { s_logger.info("Deactivating SerialExample..."); // shutting down the worker and cleaning up the properties m_handle.cancel(true); m_worker.shutdownNow(); //close the serial port closePort(); s_logger.info("Deactivating SerialExample... Done."); } public void updated(Map<String,Object> properties) { s_logger.info("Updated SerialExample..."); doUpdate(properties); s_logger.info("Updated SerialExample... Done."); } // ---------------------------------------------------------------- // // Private Methods // // ---------------------------------------------------------------- /** * Called after a new set of properties has been configured on the service */ private void doUpdate(Map<String, Object> properties) { try { for (String s : properties.keySet()) { s_logger.info("Update - "+s+": "+properties.get(s)); } // cancel a current worker handle if one if active if (m_handle != null) { m_handle.cancel(true); } //close the serial port so it can be reconfigured closePort(); //store the properties m_properties.clear(); m_properties.putAll(properties); //reopen the port with the new configuration openPort(); //start the worker thread m_handle = m_worker.submit(new Runnable() { @Override public void run() { doSerial(); } }); } catch (Throwable t) { s_logger.error("Unexpected Throwable", t); } } private void openPort() { String port = (String) m_properties.get(SERIAL_DEVICE_PROP_NAME); if (port == null) { s_logger.info("Port name not configured"); return; } int baudRate = Integer.valueOf((String) m_properties.get(SERIAL_BAUDRATE_PROP_NAME)); int dataBits = Integer.valueOf((String) m_properties.get(SERIAL_DATA_BITS_PROP_NAME)); int stopBits = Integer.valueOf((String) m_properties.get(SERIAL_STOP_BITS_PROP_NAME)); String sParity = (String) m_properties.get(SERIAL_PARITY_PROP_NAME); int parity = CommURI.PARITY_NONE; if (sParity.equals("none")) { parity = CommURI.PARITY_NONE; } else if (sParity.equals("odd")) { parity = CommURI.PARITY_ODD; } else if (sParity.equals("even")) { parity = CommURI.PARITY_EVEN; } String uri = new CommURI.Builder(port) .withBaudRate(baudRate) .withDataBits(dataBits) .withStopBits(stopBits) .withParity(parity) .withTimeout(1000) .build().toString(); try { m_commConnection = (CommConnection) m_connectionFactory.createConnection(uri, 1, false); m_commIs = m_commConnection.openInputStream(); m_commOs = m_commConnection.openOutputStream(); s_logger.info(port+" open"); } catch (IOException e) { s_logger.error("Failed to open port " + port, e); cleanupPort(); } } private void cleanupPort() { if (m_commIs != null) { try { s_logger.info("Closing port input stream..."); m_commIs.close(); s_logger.info("Closed port input stream"); } catch (IOException e) { s_logger.error("Cannot close port input stream", e); } m_commIs = null; } if (m_commOs != null) { try { s_logger.info("Closing port output stream..."); m_commOs.close(); s_logger.info("Closed port output stream"); } catch (IOException e) { s_logger.error("Cannot close port output stream", e); } m_commOs = null; } if (m_commConnection != null) { try { s_logger.info("Closing port..."); m_commConnection.close(); s_logger.info("Closed port"); } catch (IOException e) { s_logger.error("Cannot close port", e); } m_commConnection = null; } } private void closePort() { cleanupPort(); } private void doSerial() { if (m_commIs != null) { try { int c = -1; StringBuilder sb = new StringBuilder(); while (m_commIs != null) { if (m_commIs.available() != 0) { c = m_commIs.read(); } else { try { Thread.sleep(100); continue; } catch (InterruptedException e) { return; } } // on reception of CR, publish the received sentence if (c==13) { s_logger.debug("Received serial input, echoing to output: " + sb.toString()); sb.append("\r\n"); String dataRead = sb.toString(); //echo the data to the output stream m_commOs.write(dataRead.getBytes()); //reset the buffer sb = new StringBuilder(); } else if (c!=10) { sb.append((char) c); } } } catch (IOException e) { s_logger.error("Cannot read port", e); } finally { try { m_commIs.close(); } catch (IOException e) { s_logger.error("Cannot close buffered reader", e); } } } } }
これだけだとエラーになるはずですので、次の3行を任意の import 文のそばに加えてください。
import org.eclipse.kura.comm.CommConnection;
import org.eclipse.kura.comm.CommURI;
import org.eclipse.kura.configuration.ConfigurableComponent;
OSGI-INF/component.xml Fileを作成する
では、上で作成した SerialExample クラスを Bundle(Component) として定義しましょう。
Package Explorer上13)通常 Eclipse の左側に配置されるツリービュー形式のビューですね。にある”org.eclipse.kura.example.serial”プロジェクトを右クリックして[New]→[Other…]を選択します。
Newダイアログが開きますので、そこで”Plug-in Development”の中の”Component Definition”を選び[Next]を押します。
その画面で次の画像のように設定します。
注意:Component Definition Information セクションの”Name:”を必ず”org.eclipse.kura.example.serial.SerialExample” と設定してください。
設定したら[Finish]を押します。すると次のような component.xml が開かれた状態になります。
このタブでは、基本的な設定をします。
まず、Component セクションでは SerialExample で実装した Activator として振る舞うためのメソッドを設定します。具体的には、Activate に activate、 Deactivateにdeactivate, Modifiedにupdated 14)なぜか、このメソッドだけ modified ではなく updated になっているのでご注意を。をそれぞれ設定します。
次に、今回作成するBundleは、コンフィグレーション可能ですので Options セクションの”Configuration Policy:”を”require”に設定します15)実際には、この設定をしなくても、KuraのWeb UI でコンフィグレーションができました。一方、”ignore”に設定することで、それができなくなりました。。
”This component is immediately activated”は、この時点ではチェックできませんので、のちほどチェックのために戻ってきます。
次に、Properties セクションにプロパティを追加することで、service.pid16)persistent identifier or PIDを登録します。
[Add Property…]を押して、Name:に”service.pid”、Values:に”org.eclipse.kura.example.serial.SerialExample”と設定します。
設定を終えた画面は、次の画像のようになります。
[OK]を押して登録します。
次に、Services タブを押してください。次のような画面になります。
このタブの Referenced Services セクションに参照するサービスとして ConnectionFactory インターフェースを登録し、Provided Services セクションに提供するサービスのインターフェースとして SerialExample クラスを登録します。
まず、Referenced Services セクションへの登録です。[Add]を押して開いたダイアログの中の”Select entiries:”の中に “ConnectionFactory” と入力し、org.eclipse.osgi.services_*.jarの中にある方のそれを選択します。次のような画面になります。
[OK]を押すとダイアログが閉じますので、今登録したアイテムを選択し、[Edit…]を押します。するとReferenced Serviceダイアログが開きます。そのダイアログの中の”Bind:”に “setConnectionFactory”、そして”Unbind:”に “unsetConnectionFactory” と入力してください17)どちらのメソッドも SerialExample クラスで定義されています。それらと対応付けをしています。。
[OK]を押すとダイアログが閉じます。
次に、Provided Services セクションにある[Add…]を押します。SelectType ダイアログが開きます。その中の”Matching items”リストにある”SerialExample”を選択します。
[OK]を押すとダイアログが閉じます。
ここで再度、Overview タブに移り、先ほど後回しにした”This component is immediately activated”をチェックしておきます。
さて、Source タブを開くと今までに設定した内容をみることができます。次のようになっているはずです。
<?xml version="1.0" encoding="UTF-8"?> <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" configuration-policy="require" deactivate="deactivate" immediate="true" modified="updated" name="org.eclipse.kura.example.serial.SerialExample"> <implementation class="org.eclipse.kura.example.serial.SerialExample"/> <property name="service.pid" type="String" value="org.eclipse.kura.example.serial.SerialExample"/> <reference bind="setConnectionFactory" cardinality="1..1" interface="org.osgi.service.io.ConnectionFactory" name="ConnectionFactory" policy="static" unbind="unsetConnectionFactory"/> <service> <provide interface="org.eclipse.kura.example.serial.SerialExample"/> </service> </scr:component>
同様の内容であれば保存し、次の作業に進みましょう。
注意:保存をすると、設定した値のいくつかが元の空っぽな状態になってしまう場合があります18)たぶんバグでしょうね。。特に、Activate と Deactivate、Modified のそれぞれに値が空っぽになることが多いです。次の設定に進む前にきちんと設定されているかを確認してください。
コンフィグレーションの為の設定を行う
SerialExample クラスは、ConfigurableComponent インターフェースを実装しています。このインターフェースを実装すると Kura の Web UI でコンフィグレーションをすることが可能になります。簡単に言えば、Web UI を通してプロパティを変更することで、Bundle の振る舞い変更することができるようになります。
ここで行う設定は、そのようなプロパティにどのようなものがあるかを Web UI に伝えるための記述になります。
残念なことに、この設定を行うエディタは今のところ存在しないようです。
というわけで、“Serial Example”にある次のコードをそのまま利用して、OSGI-INF/metatype/org.eclipse.kura.example.serial.SerialExample.xml というファイルを作成してください19)Component.xml の scr:component の name 属性で記述した値と同じ名前である必要があります。。
<?xml version="1.0" encoding="UTF-8"?> <MetaData xmlns="http://www.osgi.org/xmlns/metatype/v1.2.0" localization="en_us"> <OCD id="org.eclipse.kura.example.serial.SerialExample" name="SerialExample" description="Example of a Configuring KURA Application echoing data read from the serial port."> <!-- <Icon resource="http://sphotos-a.xx.fbcdn.net/hphotos-ash4/p480x480/408247_10151040905591065_1989684710_n.jpg" size="32"/> --> <AD id="serial.device" name="serial.device" type="String" cardinality="0" required="false" description="Name of the serial device (e.g. /dev/ttyS0, /dev/ttyACM0, /dev/ttyUSB0)."/> <AD id="serial.baudrate" name="serial.baudrate" type="String" cardinality="0" required="true" default="9600" description="Baudrate."> <Option label="9600" value="9600"/> <Option label="19200" value="19200"/> <Option label="38400" value="38400"/> <Option label="57600" value="57600"/> <Option label="115200" value="115200"/> </AD> <AD id="serial.data-bits" name="serial.data-bits" type="String" cardinality="0" required="true" default="8" description="Data bits."> <Option label="7" value="7"/> <Option label="8" value="8"/> </AD> <AD id="serial.parity" name="serial.parity" type="String" cardinality="0" required="true" default="none" description="Parity."> <Option label="none" value="none"/> <Option label="even" value="even"/> <Option label="odd" value="odd"/> </AD> <AD id="serial.stop-bits" name="serial.stop-bits" type="String" cardinality="0" required="true" default="1" description="Stop bits."> <Option label="1" value="1"/> <Option label="2" value="2"/> </AD> </OCD> <Designate pid="org.eclipse.kura.example.serial.SerialExample"> <Object ocdref="org.eclipse.kura.example.serial.SerialExample"/> </Designate> </MetaData>
作成し終えたら、その XML ファイルをバイナリ―に含めるために、META-INF/MANIFEST.MF をダブルクリックして開き、Build タブを選び、そこの Binary Build セクションで今作成した XML ファイルを次のようにチェックしておきます。
すべてを保存しておきましょう。ここまで来たら、あと一歩です。
MANIFEST.MF に Imported-Packagesの設定を行う
では、 “Automated Management of Dependencies”の設定で書いたように、自動的にImported-Packagesの設定を行いましょう。
META-INF/MANIFEST.MF をダブルクリックして開き、Dependenciesタブを選択してください。次のようになっているはずです。
”Automated Management of Dependencies”セクションの “Analyze code and add dependencies to the MANIFEST.MF via:”欄の”Import-Package”をチェックして、”add dependencies”というリンクをクリックしてください。
すると、”Imported Packages”セクションにクラス実装で利用しているパッケージの一覧が自動で挿入されるはずです。一覧は、次のようになっているでしょう。
次の二つについては、最新の版が使われるように、[Properties…]を押して、それぞれ、Mininum Version を1.0、Maximum Versionを2.0として、利用可能な版の範囲を指定してもよいでしょう20)そのように設定しなくても動作します。。
- org.eclipse.kura.comm
- org.eclipse.kura.configuration
エミュレーターで実行する
いよいよエミュレータで実行してみます。
エミュレータは、org.eclipse.kura.emulatorプロジェクトの”src/main/resources”の下にある次の何れかを使って実行します。
- Linux用: Kura_emulator_linux.launch
- MacOSX用: Kura_emulator_OSX.launch
実行する時に、注意してほしいのは、このSerialExampleプロジェクトは、実行時に “org.eclipse.kura.core.comm”プラグインを利用するという点です。そのため、実行は、Kura_emulator_*.launchを右クリック、[Run As]-> [Run Configurations…]で行います。
[Run Configurations…]をクリックすると次のような画面になると思います。
この画面の”type filter text”というボックスに”org.eclipse.kura.core.comm”と入力し、一覧に残った”org.eclipse.kura.core.comm”をチェックします。次のような画面になるでしょう。
[Run]を押して実行してみます。
Consoleが現れ次のようなログが出るはずです。
15:14:53,203 [Start Level Event Dispatcher] INFO Server:253 - jetty-8.1.3.v20120522
15:14:53,280 [Start Level Event Dispatcher] INFO AbstractConnector:333 - Started SelectChannelConnector@0.0.0.0:8080
15:14:53,382 [Component Resolve Thread] INFO SerialExample:57 - Activating SerialExample...
15:14:53,391 [Component Resolve Thread] INFO SerialExample:95 - Update - objectClass: [Ljava.lang.String;@65868c45
15:14:53,392 [Component Resolve Thread] INFO SerialExample:95 - Update - service.pid: org.eclipse.kura.example.serial.SerialExample
15:14:53,392 [Component Resolve Thread] INFO SerialExample:95 - Update - component.name: org.eclipse.kura.example.serial.SerialExample
15:14:53,392 [Component Resolve Thread] INFO SerialExample:95 - Update - component.id: 6
15:14:53,394 [Component Resolve Thread] INFO SerialExample:130 - Port name not configured
15:14:53,396 [Component Resolve Thread] INFO SerialExample:62 - Activating SerialExample... Done.
15:14:53,432 [Component Resolve Thread] INFO SystemServiceImpl:122 - Loaded URL kura.properties: file:/home/gougi/workspace/org.eclipse.kura.emulator/src/main/resources/kura.properties
15:14:53,433 [Component Resolve Thread] INFO SystemServiceImpl:173 - Did not locate a kura_custom.properties file in null
15:14:53,435 [Component Resolve Thread] INFO SystemServiceImpl:269 - Kura has net admin? false
15:14:53,435 [Component Resolve Thread] INFO SystemServiceImpl:272 - Kura has web interface? true
15:14:53,435 [Component Resolve Thread] INFO SystemServiceImpl:275 - Kura version? 0.7.1
15:14:53,436 [Component Resolve Thread] INFO SystemServiceImpl:285 - Kura home directory is /tmp/kura_emulator_base/
15:14:53,436 [Component Resolve Thread] INFO SystemServiceImpl:292 - Kura snapshots directory is /tmp/kura/snapshots
15:14:53,443 [Component Resolve Thread] INFO SystemServiceImpl:299 - Kura tmp directory is /tmp/kura/tmp
15:14:53,444 [Component Resolve Thread] INFO SystemServiceImpl:303 - Kura version 0.7.1 is starting
Framework is running in emulation mode
osgi> 15:14:53,573 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:154 - activate...
15:14:53,575 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:173 - Trackers being opened...
15:14:53,584 [Start Level Event Dispatcher] INFO ConfigurableComponentTracker:67 - Opening ServiceTracker
15:14:53,588 [Start Level Event Dispatcher] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.example.serial.SerialExample
15:14:53,588 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.example.serial.SerialExample by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:53,870 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.example.serial.SerialExample with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@75bbc027 ...
15:14:53,870 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.example.serial.SerialExample.
15:14:53,994 [Start Level Event Dispatcher] INFO HsqlDbServiceImpl:90 - activate...
15:14:53,994 [Start Level Event Dispatcher] INFO HsqlDbServiceImpl:167 - Opening database with url: jdbc:hsqldb:file:/tmp/kura/data/db/data;hsqldb.lock_file=false;
15:14:54,638 [Start Level Event Dispatcher] INFO ConfigurableComponentTracker:71 - Getting ServiceReferences
15:14:54,640 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:63 - Opening ComponentMetaTypeBundleTracker...
15:14:54,709 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport
15:14:54,739 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport
15:14:54,739 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.data.DataService
15:14:54,767 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.data.DataService
15:14:54,768 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.ssl.SslManagerService
15:14:54,773 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.ssl.SslManagerService
15:14:54,792 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.example.serial.SerialExample
15:14:54,798 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.example.serial.SerialExample
15:14:54,798 [ConfigurationListener Event Queue] INFO ConfigurationServiceImpl:225 - ConfigurationEvent for tracked ConfigurableComponent with pid: org.eclipse.kura.example.serial.SerialExample
15:14:54,799 [ConfigurationListener Event Queue] INFO ConfigurationServiceImpl:347 - Writing snapshot - Getting component configurations...
15:14:54,801 [ConfigurationListener Event Queue] INFO ConfigurationServiceImpl:750 - Writing snapshot - Saving /tmp/kura/snapshots/snapshot_1433657694800.xml...
15:14:54,899 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.cloud.CloudService
15:14:54,915 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.cloud.CloudService
15:14:54,916 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.cloud.app.command.CommandCloudApp
15:14:54,923 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.cloud.app.command.CommandCloudApp
15:14:54,944 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.clock.ClockService
15:14:54,975 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.clock.ClockService
15:14:54,975 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.position.PositionService
15:14:54,985 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.position.PositionService
15:14:54,986 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:1087 - Merging configuration for pid: org.eclipse.kura.watchdog.WatchdogService
15:14:54,995 [Start Level Event Dispatcher] INFO ComponentMetaTypeBundleTracker:131 - Seeding updated configuration for pid: org.eclipse.kura.watchdog.WatchdogService
15:14:55,028 [ConfigurationListener Event Queue] INFO ConfigurationServiceImpl:765 - Writing snapshot - Saving /tmp/kura/snapshots/snapshot_1433657694800.xml... Done.
15:14:55,124 [Start Level Event Dispatcher] INFO Console:134 - activate...
15:14:55,461 [Start Level Event Dispatcher] INFO FileServlet:82 - Servlet org.eclipse.kura.web.server.servlet.FileServlet initialized
15:14:55,463 [Start Level Event Dispatcher] INFO FileServlet:90 - DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD: 10240
15:14:55,463 [Start Level Event Dispatcher] INFO FileServlet:91 - DiskFileItemFactory: using size threshold of: 10240
15:14:55,466 [Start Level Event Dispatcher] INFO Console:166 - postInstalledEvent() :: posting KuraConfigReadyEvent
15:14:55,471 [Start Level Event Dispatcher] INFO SslManagerServiceImpl:88 - activate...
15:14:55,473 [Start Level Event Dispatcher] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.ssl.SslManagerService
15:14:55,473 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.ssl.SslManagerService by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:55,475 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.ssl.SslManagerService with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@21632ef6 ...
15:14:55,475 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.ssl.SslManagerService.
15:14:55,485 [Start Level Event Dispatcher] INFO MqttDataTransport:139 - Activating...
15:14:55,499 [Start Level Event Dispatcher] INFO MqttDataTransport:823 - Creating a new client instance
15:14:55,499 [Start Level Event Dispatcher] INFO MqttDataTransport:870 - Using memory persistence for in-flight messages
15:14:55,522 [Start Level Event Dispatcher] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport
15:14:55,523 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:55,526 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@261becde ...
15:14:55,527 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport.
15:14:55,537 [Start Level Event Dispatcher] INFO DataServiceImpl:94 - Activating...
15:14:55,545 [Start Level Event Dispatcher] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.data.DataService
15:14:55,546 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.data.DataService by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:55,549 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.data.DataService with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@574a4c06 ...
15:14:55,549 [Start Level Event Dispatcher] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.data.DataService.
15:14:55,555 [Start Level Event Dispatcher] INFO CloudCallServiceImpl:78 - Activating...
15:14:55,556 [Component Resolve Thread (Bundle 7)] INFO SerialExample:77 - Updated SerialExample...
15:14:55,556 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - objectClass: [Ljava.lang.String;@1c77308f
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.parity: none
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.data-bits: 8
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - service.pid: org.eclipse.kura.example.serial.SerialExample
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - component.name: org.eclipse.kura.example.serial.SerialExample
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - component.id: 6
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.baudrate: 9600
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.stop-bits: 1
15:14:55,558 [Component Resolve Thread (Bundle 7)] INFO SerialExample:130 - Port name not configured
15:14:55,567 [Component Resolve Thread (Bundle 7)] INFO SerialExample:80 - Updated SerialExample... Done.
15:14:55,584 [Component Resolve Thread (Bundle 7)] INFO CloudServiceImpl:169 - activate...
15:14:55,588 [Component Resolve Thread (Bundle 7)] INFO Cloudlet:87 - Getting CloudApplicationClient for CONF-V1...
15:14:55,592 [Component Resolve Thread (Bundle 7)] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.cloud.CloudService
15:14:55,592 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.cloud.CloudService by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:55,595 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.cloud.CloudService with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@4aaf45e4 ...
15:14:55,595 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.cloud.CloudService.
15:14:55,609 [Component Resolve Thread (Bundle 7)] INFO CommandCloudApp:73 - Bundle CMD-V1 has started with config!
15:14:55,609 [Component Resolve Thread (Bundle 7)] INFO CommandCloudApp:79 - updated...: org.eclipse.equinox.internal.ds.impl.ReadOnlyDictionary@57c6aea8
15:14:55,610 [Component Resolve Thread (Bundle 7)] INFO Cloudlet:87 - Getting CloudApplicationClient for CMD-V1...
15:14:55,610 [Component Resolve Thread (Bundle 7)] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.cloud.app.command.CommandCloudApp
15:14:55,610 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.cloud.app.command.CommandCloudApp by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:55,613 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.cloud.app.command.CommandCloudApp with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@6debe75c ...
15:14:55,613 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.cloud.app.command.CommandCloudApp.
15:14:55,617 [Component Resolve Thread (Bundle 7)] INFO ClockServiceImpl:58 - Activate. Current Time: Sun Jun 07 15:14:55 JST 2015
15:14:55,622 [Component Resolve Thread (Bundle 7)] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.clock.ClockService
15:14:55,622 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.clock.ClockService by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:55,641 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.clock.ClockService with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@54e95ded ...
15:14:55,641 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.clock.ClockService.
15:14:55,649 [Component Resolve Thread (Bundle 7)] INFO ConfigurableComponentTracker:118 - Adding ConfigurableComponent org.eclipse.kura.watchdog.WatchdogService
15:14:55,650 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:553 - Registration of ConfigurableComponent org.eclipse.kura.watchdog.WatchdogService by org.eclipse.kura.core.configuration.ConfigurationServiceImpl@4a1521bf...
15:14:55,651 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:564 - Registering org.eclipse.kura.watchdog.WatchdogService with ocd: org.eclipse.kura.core.configuration.metatype.Tocd@75821b23 ...
15:14:55,652 [Component Resolve Thread (Bundle 7)] INFO ConfigurationServiceImpl:571 - Registration Completed for Component org.eclipse.kura.watchdog.WatchdogService.
15:14:56,545 [HouseKeeperTask] INFO HouseKeeperTask:44 - HouseKeeperTask started.
15:14:56,545 [HouseKeeperTask] INFO HouseKeeperTask:48 - HouseKeeperTask: Check store...
15:14:56,553 [HouseKeeperTask] INFO HouseKeeperTask:53 - HouseKeeperTask: Delete confirmed messages...
15:14:56,572 [HouseKeeperTask] INFO HouseKeeperTask:63 - HouseKeeperTask: Performing store checkpoint with defrag...
15:14:56,647 [HouseKeeperTask] INFO HouseKeeperTask:67 - HouseKeeperTask ended.
15:15:39,585 [qtp1010545336-21] INFO /:1947 - org.eclipse.kura.web.server.GwtDeviceServiceImpl: Trying www resource2: /www/denali/AAC68F551702B7B015A9BD9B6C88670D.gwt.rpc
15:15:40,103 [qtp1010545336-25] INFO /:1947 - org.eclipse.kura.web.server.GwtComponentServiceImpl: Trying www resource2: /www/denali/5C5C0F0F8A760B67FBBFAA6B2AFE9880.gwt.rpc
このログの中に次のような箇所があれば、正常に動作しています。
15:14:55,556 [Component Resolve Thread (Bundle 7)] INFO SerialExample:77 - Updated SerialExample...
15:14:55,556 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - objectClass: [Ljava.lang.String;@1c77308f
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.parity: none
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.data-bits: 8
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - service.pid: org.eclipse.kura.example.serial.SerialExample
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - component.name: org.eclipse.kura.example.serial.SerialExample
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - component.id: 6
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.baudrate: 9600
15:14:55,557 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.stop-bits: 1
15:14:55,558 [Component Resolve Thread (Bundle 7)] INFO SerialExample:130 - Port name not configured
15:14:55,567 [Component Resolve Thread (Bundle 7)] INFO SerialExample:80 - Updated SerialExample... Done.
ここで、Kuraを実行しているホストの 8080ポートに接続してみましょう。ログインは、admin / admin で行います。すると次のような画面になります。
Servicesの欄に、SerialExampleがあることを確認し、クリックしてください。次のような画面になるでしょう。
Eclipse Kuraのエミュレータと端末の間での通信を試す
Eclipse Kuraのエミュレータと端末間での通信を試すには、エミュレーターを起動する前に、USB to RS-232C アダプタを二つ接続し、それをクラスケーブルでつないだ上で、先に掲載した画面27にある serial.device に、USB to RS-232C アダプタの一方のデバイスファイルを設定し、[Apply]を押します。
serial.deviceの設定に成功すると次のようなログが出力されます。
15:40:28,786 [Component Resolve Thread (Bundle 7)] INFO SerialExample:77 - Updated SerialExample... 15:40:28,786 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - component.name: org.eclipse.kura.example.serial.SerialExample 15:40:28,786 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.baudrate: 9600 15:40:28,786 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.device: /dev/ttyUSB0 15:40:28,786 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - objectClass: [Ljava.lang.String;@12bb913b 15:40:28,787 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.parity: none 15:40:28,787 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.stop-bits: 1 15:40:28,787 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - service.pid: org.eclipse.kura.example.serial.SerialExample 15:40:28,787 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - serial.data-bits: 8 15:40:28,787 [Component Resolve Thread (Bundle 7)] INFO SerialExample:95 - Update - component.id: 6 15:40:29,022 [Component Resolve Thread (Bundle 7)] INFO SerialExample:160 - /dev/ttyUSB0 open 15:40:29,024 [Component Resolve Thread (Bundle 7)] INFO SerialExample:80 - Updated SerialExample... Done.
うまく設定ができたなら、もう一方のデバイスファイルに対して screen または minicom などのコマンドを通して端末から接続してみます。うまくつながったなら、端末から入力した文字列がリターンを押す度にエコーバックされます。
ちなみに、USB to RS-232C アダプタとクロスケーブルは、次の商品を使いました。
- Plugable® USB‐9ピンRS232シリアルアダプター (Prolific社製 PL2303HX Rev Dチップセット採用) × 2
- ELECOM RS-232Cシリアルリバース D-Sub9ピンメス – D-Sub9ピンメス 1.5m C232R-915 × 1
補足1:Ubuntuで開発している場合
例えば、開発にUbuntu 21)VirtualBoxなどの上で動いていても同じを使っていて、既にシリアルケーブルが繋がっていない状況ならば、恐らく、新規に接続したUSB to RS-232C アダプタは、 /dev/ttyUSB0 と /dev/ttyUSB1 として認識されますので、その一方を設定してください。
Ubuntuでは、端末側のコマンドとして、私が試した限り、screen コマンド と minicom の両方でうまくいっています。
注意点としては、udevの設定が必要なことです。私は次のように設定しました。
40-permissions.rulesを新規に作成 % sudo gedit /etc/udev/rules.d/40-permissions.rules 以下を記述 SUBSYSTEM=="tty", KERNEL=="ttyUSB[0-9]", GROUP="dialout", MODE="0666" リロード %sudo udevadm control --reload-rules
補足2:WindwosでVirtualBoxを動かしそこで Ubuntuをホストしている時に USB to RS-232C アダプタを接続するためのVirtualBox側の設定
次のように、Windows側で認識してる二つのUSB to RS-232C アダプタを登録しただけで、ホストしているUbuntu側で認識され、Kuraから利用できました。
あとがき
随分長い記事になってしまって、後半息切れしました。
実際にやってみて、不明な所やうまく行かないところなどあれば、コメント欄で気軽にご質問してくださればと思います。
この記事の続きとして、今回作成した Bundle を BeagleBone Black にデプロイして動かすあたりの記事を後日書く予定です。
Footnotes
↩1 | 私が利用したケーブル類はこの記事の最後に紹介します。 |
---|---|
↩2 | この記事はそのような環境で記述しています。 |
↩3 | この記事では Eclipse Luna SR2 を使っています。 |
↩4 | Kura の 1.1.2 用”Developer’s Workspace (with Web UI)”は、これになります |
↩5 | ここでは、とりあえず全てのプロジェクトをインポートしてしまいます。 |
↩6 | このプロジェクトでは、Bundle を開発するのに必要な Platform を Equinox をベースにして Target Platform の記述が行われています。 |
↩7 | http://wiki.osgi.org/wiki/Bundle-SymbolicName |
↩8 | http://wiki.osgi.org/wiki/Bundle-ActivationPolicy |
↩9 | チェックしても何も変化がないと思われるためです。変化があるという方がいらっしゃれば是非ご指摘ください。 |
↩10 | エディタの下部にあるタブグループに存在する。 |
↩11 | commonまたはequinox_3.8.1フォルダの下にあります。 |
↩12 | この作業は後程行います。 |
↩13 | 通常 Eclipse の左側に配置されるツリービュー形式のビューですね。 |
↩14 | なぜか、このメソッドだけ modified ではなく updated になっているのでご注意を。 |
↩15 | 実際には、この設定をしなくても、KuraのWeb UI でコンフィグレーションができました。一方、”ignore”に設定することで、それができなくなりました。 |
↩16 | persistent identifier or PID |
↩17 | どちらのメソッドも SerialExample クラスで定義されています。それらと対応付けをしています。 |
↩18 | たぶんバグでしょうね。 |
↩19 | Component.xml の scr:component の name 属性で記述した値と同じ名前である必要があります。 |
↩20 | そのように設定しなくても動作します。 |
↩21 | VirtualBoxなどの上で動いていても同じ |