「ArduBlock のカスタマイズ はじめて編」
https://qiita.com/nanbuwks/items/6bb036b5e915a5b24bd4
では、最低限の引き出しとブロックを作成しました。
ここでは、もう少し複雑なブロックを作成していきます。
ブロックの種類
<BlockGenus name="ESP32_SPIFF_INIT" kind="command" color="20 20 20" initlabel="bg.ESP32_SPIFF_INIT">
の、kind="command" というところで種類を規定します。
kind="command"
kind="data"
返り値を持つブロック
kind="function"
ブロックコネクタ
引数としてのブロックコネクタと返り値としてのブロックコネクタ
ここで、左側の< が返り値としてのブロックコネクタ、右側のギザギザが引数としてのブロックコネクタです。
実行例
src/main/resources/com/ardublock/block/ardublock.xml
内部の記述
<BlockGenus name="ultrasonic" kind="data" color="205 133 63" initlabel="bg.ultrasonic">
<description>
<text>Ultrasonic distance sensor</text>
</description>
<BlockConnectors>
<BlockConnector connector-type="number" connector-kind="plug" label="cm" />
<BlockConnector connector-type="number" connector-kind="socket" label="trigger pin">
<DefaultArg genus-name="pinListDigital_D11" label="D11" />
</BlockConnector>
<BlockConnector connector-type="number" connector-kind="socket" label="echo pin">
<DefaultArg genus-name="pinListDigital_D12" label="D12" />
</BlockConnector>
</BlockConnectors>
<Images>
<Image>
<FileLocation>com/ardublock/block/ultrasonic.png</FileLocation>
</Image>
</Images>
</BlockGenus>
connector-kind="plug"
が返り値のコネクタ、
connector-kind="socket"
が引数のコネクタ
コネクタの型
これらは、
src/main/src/resources/com/ardublock/block/ardublock.xml
の
<BlockConnectorShapes>
で上記以外も含め以下のように定義されている。
<BlockConnectorShapes>
<BlockConnectorShape shape-type="number" shape-number="1" />
<BlockConnectorShape shape-type="number-list" shape-number="2" />
<BlockConnectorShape shape-type="number-inv" shape-number="3" />
<BlockConnectorShape shape-type="boolean" shape-number="4" />
<BlockConnectorShape shape-type="boolean-list" shape-number="5" />
<BlockConnectorShape shape-type="boolean-inv" shape-number="6" />
<BlockConnectorShape shape-type="string" shape-number="7" />
<BlockConnectorShape shape-type="string-list" shape-number="8" />
<BlockConnectorShape shape-type="string-inv" shape-number="9" />
<BlockConnectorShape shape-type="poly" shape-number="10" />
<BlockConnectorShape shape-type="poly-list" shape-number="11" />
<BlockConnectorShape shape-type="poly-inv" shape-number="12" />
<BlockConnectorShape shape-type="proc-param" shape-number="13" />
<BlockConnectorShape shape-type="cmd" shape-number="14" />
<BlockConnectorShape shape-type="cmd1" shape-number="15" />
<BlockConnectorShape shape-type="cmd2" shape-number="16" />
<BlockConnectorShape shape-type="cmd3" shape-number="17" />
</BlockConnectorShapes>
ブロックに定義するプログラム
src/main/java/com/ardublock/translator/block/*.java
のお作法です。
Arduino IDE に渡るコード
public String toCode()
内に記述する
ブロックコネクタ
コネクタの型は多々あるが、java プログラム中では全て String で値が受け渡しされる。
TranslatorBlock tb = this.getRequiredTranslatorBlockAtSocket(n);
として、tb.toCode()
で n 番目の引数が String で取り出せる。
include 指定するコード
#include <hogehoge.h>
したいときは以下のように書く
translator.addHeaderFile("hogehoge.h");
setup ルーチン中に配置するコード
hagehage()
と配置したいときは以下のように書く
translator.addSetupCommand("hagehage()\n");
loop ルーチン中に配置するコード
mogmog();
と配置したいときは以下のように書く
return "mogmog();\n"
ファンクション定義などを行うコード
int fugafuga()
{
return(1)
}
と配置したいときは以下のように書く
translator.addDefinitionCommand("int fugafuga()\n{\nreturn(1)\n}\n");
ブロックに定義するプログラム内容例1
package com.ardublock.translator.block;
import com.ardublock.translator.Translator;
import com.ardublock.translator.block.TranslatorBlock;
import com.ardublock.translator.block.exception.SocketNullException;
import com.ardublock.translator.block.exception.SubroutineNotDeclaredException;
public class ESP32_SPIFF_INITBlock extends TranslatorBlock {
public ESP32_SPIFF_INITBlock(Long blockId, Translator translator, String codePrefix, String codeSuffix, String label)
{
super(blockId, translator, codePrefix, codeSuffix, label);
}
//@Override
public String toCode() throws SocketNullException, SubroutineNotDeclaredException
{
String ret = "";
//Deal with line and character positioning
translator.addHeaderFile("FS.h");
translator.addHeaderFile("SPIFF.h");
translator.addSetupCommand(" if(!SPIFFS.begin(true)){");
translator.addSetupCommand(" Serial.println(\"SPIFF Mount Failed\");");
translator.addSetupCommand(" return");
translator.addSetupCommand(" }");
return ret;
}
}
実行結果1
#include <FS.h>
#include <SPIFF.h>
void setup()
{
if(!SPIFFS.begin(true)){
Serial.println("SPIFF Mount Failed");
return
}
}
void loop()
{
}
ブロックに定義するプログラム内容例2
src/main/java/com/ardublock/translator/block/UltrasonicBlock.java
package com.ardublock.translator.block;
import com.ardublock.translator.Translator;
import com.ardublock.translator.block.exception.SocketNullException;
import com.ardublock.translator.block.exception.SubroutineNotDeclaredException;
public class UltrasonicBlock extends TranslatorBlock
{
public UltrasonicBlock(Long blockId, Translator translator, String codePrefix, String codeSuffix, String label)
{
super(blockId, translator, codePrefix, codeSuffix, label);
}
private final static String ultraSonicFunction = "int ardublockUltrasonicSensorCodeAutoGeneratedReturnCM(int trigPin, int echoPin)\n{\n long duration;\n pinMode(trigPin, OUTPUT);\n pinMode(echoPin, INPUT);\n digitalWrite(trigPin, LOW);\n delayMicroseconds(2);\n digitalWrite(trigPin, HIGH);\n delayMicroseconds(20);\n digitalWrite(trigPin, LOW);\n duration = pulseIn(echoPin, HIGH);\n duration = duration / 59;\n if ((duration < 2) || (duration > 300)) return false;\n return duration;\n}\n";
@Override
public String toCode() throws SocketNullException, SubroutineNotDeclaredException
{
String trigPin;
String echoPin;
TranslatorBlock translatorBlock = this.getRequiredTranslatorBlockAtSocket(0);
trigPin = translatorBlock.toCode();
translatorBlock = this.getRequiredTranslatorBlockAtSocket(1);
echoPin = translatorBlock.toCode();
translator.addSetupCommand("digitalWrite( " + trigPin + " , LOW );\n");
translator.addDefinitionCommand(ultraSonicFunction);
String ret = "\tardublockUltrasonicSensorCodeAutoGeneratedReturnCM( " + trigPin + " , " + echoPin + " )";
return codePrefix + ret + codeSuffix;
}
}
実行結果2
int _ABVAR_1_distance = 0 ;
int ardublockUltrasonicSensorCodeAutoGeneratedReturnCM(int trigPin, int echoPin)
{
long duration;
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(20);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
duration = duration / 59;
if ((duration < 2) || (duration > 300)) return false;
return duration;
}
void setup()
{
digitalWrite( 11 , LOW );
}
void loop()
{
_ABVAR_1_distance = ardublockUltrasonicSensorCodeAutoGeneratedReturnCM( 11 , 12 ) ;
}
ブロックに定義するプログラム内容例3
package com.ardublock.translator.block;
import com.ardublock.translator.Translator;
import com.ardublock.translator.block.TranslatorBlock;
import com.ardublock.translator.block.exception.SocketNullException;
import com.ardublock.translator.block.exception.SubroutineNotDeclaredException;
public class ESP32_WebAccessBlock extends TranslatorBlock {
public ESP32_WebAccessBlock(Long blockId, Translator translator, String codePrefix, String codeSuffix, String label)
{
super(blockId, translator, codePrefix, codeSuffix, label);
}
//@Override
public String toCode() throws SocketNullException, SubroutineNotDeclaredException
{
TranslatorBlock tb = this.getRequiredTranslatorBlockAtSocket(0);
String host = tb.toCode();
tb = this.getRequiredTranslatorBlockAtSocket(1);
String path = tb.toCode();
String ret = " WiFiClient socket;"
+ "const int httpPort = 80;\n"
+ "const char* host = "+host+";\n"
+ "if (!socket.connect(host, httpPort)) {\n"
+ " Serial.println(\"connection failed\");\n"
+ " return;\n"
+ "}\n"
+"\n"
+ "// We now create a URI for the request\n"
+ "String url = "+path+";\n"
+"\n"
+ "Serial.print(\"Requesting URL: \");\n"
+ "Serial.println(url);\n"
+"\n"
+ "// This will send the request to the server\n"
+ "socket.print(String(\"GET \") + url + \" HTTP/1.1\\r\\n\" +\n"
+ " \"Host: \" + host + \"\\r\\n\" +\n"
+ " \"Connection: close\\r\\n\\r\\n\");\n"
+ "unsigned long timeout = millis();\n"
+ "while (socket.available() == 0) {\n"
+ " if (millis() - timeout > 5000) {\n"
+ " Serial.println(\">>> Client Timeout !\");\n"
+ " socket.stop();\n"
+ " return;\n"
+ " }\n"
+ "}\n"
+"\n"
+ "// Read all the lines of the reply from server and print them to Serial\n"
+ "while(socket.available()) {\n"
+ " String line = socket.readStringUntil('\\r');\n"
+ " Serial.print(line);\n"
+ "}\n"
+"\n"
+ "Serial.println();\n"
+ "Serial.println(\"closing connection\");\n";
return ret;
}
}
実行結果3
void setup()
{
}
void loop()
{
WiFiClient socket;
const int httpPort = 80;
const char* host = "www.example.com";
if (!socket.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
// We now create a URI for the request
String url = "/test/example.html";
Serial.print("Requesting URL: ");
Serial.println(url);
// This will send the request to the server
socket.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (socket.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
socket.stop();
return;
}
}
// Read all the lines of the reply from server and print them to Serial
while(socket.available()) {
String line = socket.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("closing connection");
}
トラブルシューティング
Arduino IDE の Tools プルダウンに Ardublock が出現しない
Arduino を ターミナルから起動したり、ardublock-all.jar を実行したりして、出てくるエラーメッセージを確認して対処
java.util.MissingResourceException: Can't find resource for bundle java.util.PropertyResourceBundle, key bg.AKBONE_LEDPANEL
src/main/resources/com/ardublock/block/ardublock.properties に、bg.AKBONE_LEDPANEL=
の行が足りなかった