Últimamente estoy actualizando Ardublock con este método.
Ardublock es una herramienta que transforma bloques gráficos en código para Arduino. Es muy sencillo de utilizar y permite a los principiantes empezar a programar sin necesidad de aprender la sintaxis un poco compleja de c.
Esta es una imagen de ejemplo de programa en Ardublock:
Cada bloque gráfico se transforma en una o más instrucciones en c para Arduino.
Ardublock está programado en java y tiene una serie de archivos de configuración para guardar todos los datos.
Cada vez que se añade un bloque para una nueva instrucción hay que modificar el código en varios puntos:
- Añadir en la sección de bloques la definición del bloque con sus entradas y su salida de datos (si es una función), el tipo de los datos y los comentarios que aparecen representados en el bloque.
- Añadir en la sección family si ese bloque pertenece a una familia de bloques emparentados. Por ejemplo los datos HIGH y LOW están emparentados entre sí y se puede transformar uno en otro pinchando en el bloque la flecha de opción.
- Añadir el nombre del bloque en el menú correspondiente para que aparezca al pinchar en el menú.
- Definir las variables con el texto que les corresponda. Por ejemplo la variable bc.integer se asociará al texto "Integer" y esa variable se utilizará en todos los bloques que utilicen números enteros.
- Código en java que genera las instrucciones en c correspondientes al bloque representado en Ardublock. Es el código "Traductor"
Cada vez que quiero añadir una nueva instrucción tengo que modificar estos 5 puntos diferentes, bastante repetitivos y muy sensibles a pequeños errores.
Después de modificar a mano el programa en varias ocasiones me he decidido a generarlo con plantillas. Esto me ha permitido 'limpiar' el programa, redefinir los nombres con más coherencia, eliminar algún error y espero que me sirva para reducir los errores de programación.
El programa de las plantillas es demasiado largo, pero pondré aquí algún ejemplo de los resultados.
Los datos están guardados en formato YAML. Adjunto una pequeña muestra.
Datos definidos en archivo YAML:# Code Blocks
Blocks:
- name: pc_ledWrite
parameter:
- {type: number, label: bc.pc_led, default: [number, '1']}
- {type: boolean, label: bc.pc_state, default: [digital-on, 'ON']}
return:
translator:
name: PcLedWrite
headers: ['PC42.h', 'Wire.h']
setup: ['pc.begin();']
code:
- 'return "pc.ledWrite(" + arg1 + ", " + arg2 + ");";'
properties:
bg.pc_ledWrite: Led Write
# Common properties
Properties:
bc.pc_led: Led
bc.pc_state: State
A partir de la pequeña muestra anterior se generan todos los siguientes bloques de código:
Bloque en archivo ardublock.xml: <BlockGenus name="pc_ledWrite" kind="command" color="160 0 0" initlabel="bg.pc_ledWrite">
<BlockConnectors>
<BlockConnector connector-type="number" connector-kind="socket" label="bc.pc_led">
<DefaultArg genus-name="number" label="1" />
</BlockConnector>
<BlockConnector connector-type="boolean" connector-kind="socket" label="bc.pc_state">
<DefaultArg genus-name="digital-on" label="ON" />
</BlockConnector>
</BlockConnectors>
</BlockGenus>
Familia: En este caso no se genera código, porque se trata de un solo bloque aislado.
Menú en archivo ardublock.xml: <BlockDrawerSets>
<BlockDrawerSet name="factory" type="stack" location="southwest" window-per-drawer="no" drawer-draggable="no">
<BlockDrawer button-color="160 0 0" name="bd.Picuino" type="factory">
<BlockGenusMember>pc_ledWrite</BlockGenusMember>
</BlockDrawer>
</BlockDrawerSet>
</BlockDrawerSets>
Variables en archivo ardublock.propertiesbg.pc_ledWrite=Led Write
bc.pc_led=Led
bc.pc_state=State
Código java en archivo PcLedWrite.java:package com.ardublock.translator.block;
import com.ardublock.translator.Translator;
import com.ardublock.translator.block.NumberBlock;
import com.ardublock.translator.block.TranslatorBlock;
import com.ardublock.translator.block.exception.BlockException;
import com.ardublock.translator.block.exception.SocketNullException;
import com.ardublock.translator.block.exception.SubroutineNotDeclaredException;
public class PcLedWrite extends TranslatorBlock {
public PcLedWrite(Long blockId, Translator translator, String codePrefix, String codeSuffix, String label) {
super(blockId, translator, codePrefix, codeSuffix, label);
}
@Override
public String toCode() throws SocketNullException, SubroutineNotDeclaredException {
translator.addHeaderFile("PC42.h");
translator.addHeaderFile("Wire.h");
translator.addSetupCommand("pc.begin();");
TranslatorBlock translatorBlock;
translatorBlock = this.getRequiredTranslatorBlockAtSocket(0);
String arg1 = translatorBlock.toCode();
translatorBlock = this.getRequiredTranslatorBlockAtSocket(1);
String arg2 = translatorBlock.toCode();
return "pc.ledWrite(" + arg1 + ", " + arg2 + ");";
}
}
Cada uno de los bloques se inserta automáticamente en su archivo correspondiente, de manera que todo el proceso es automático y solo resta compilar con maven y archivar el resultado.
Como puede verse, un pequeño fragmento de datos agrupa todo lo necesario para generar muchos bloques de código dispersos, que de otra forma sería más complejo generar. Cuando se tiene en cuenta que Ardublock dispone de cientos de bloques semejantes puede verse la ventaja de trabajar con plantillas.
Otro tipo de bloques mucho más parecidos entre sí se pueden generar con menos datos todavía.
Los datos siguientes definen de una sola vez 5 bloques distintos:
Definitions:
- pc3: &PICUINO_BEGIN [pc_begin, pc_dispBegin, pc_buzzBegin, pc_ledBegin, pc_keyBegin]
Blocks:
- name: *PICUINO_BEGIN
parameter:
return:
translator:
name: PcBegin
headers: ['PC42.h', 'Wire.h']
setup: ['pc.begin();']
code:
- 'String functionName = this.getTranslator().getBlock(blockId).getGenusName();'
- 'if (functionName == "pc_keyBegin")'
- ' return "pc.keyBegin();";'
- 'else if (functionName == "pc_ledBegin")'
- ' return "pc.ledBegin();";'
- 'else if (functionName == "pc_buzzBegin")'
- ' return "pc.buzzBegin();";'
- 'else if (functionName == "pc_dispBegin")'
- ' return "pc.dispBegin();";'
- 'else'
- ' return "pc.begin();";'
properties:
bg.pc_begin: Reset Panel
bg.pc_keyBegin: Reset Keys
bg.pc_ledBegin: Reset Leds
bg.pc_buzzBegin: Reset Buzzer
bg.pc_dispBegin: Reset Display
Un saludo.