aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Pd_firmware/Pd_firmware.pde202
-rw-r--r--arduino-help.pd98
-rw-r--r--arduino.pd59
3 files changed, 189 insertions, 170 deletions
diff --git a/Pd_firmware/Pd_firmware.pde b/Pd_firmware/Pd_firmware.pde
index 8a2de1d..ed4b1e0 100644
--- a/Pd_firmware/Pd_firmware.pde
+++ b/Pd_firmware/Pd_firmware.pde
@@ -1,24 +1,45 @@
-/* Arduino firmware aka Firmata
- * ------------------
+/* Copyright (C) 2006 Hans-Christoph Steiner
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ *
+ * -----------------------------
+ * Firmata, the Arduino firmware
+ * -----------------------------
*
- * It was designed to work with the Pd object [arduino]
- * which is included in Pd-extended. This firmware could
- * easily be used with other programs like Max/MSP, Processing,
- * or whatever can do serial communications.
+ * Firmata turns the Arduino into a Plug-n-Play sensorbox, servo
+ * controller, and/or PWM motor/lamp controller.
*
- * (copyleft) 2006 Hans-Christoph Steiner <hans@at.or.at>
- * @author: Hans-Christoph Steiner
+ * It was originally designed to work with the Pd object [arduino]
+ * which is included in Pd-extended. This firmware is intended to
+ * work with any host computer software package. It can easily be
+ * used with other programs like Max/MSP, Processing, or whatever can
+ * do serial communications.
+ *
+ * @authors: Hans-Christoph Steiner <hans@at.or.at> and Jamie Allen <jamie@heavyside.net>
* @date: 2006-05-19
- * @location: STEIM, Amsterdam, Netherlands
+ * @location: STEIM, Amsterdam, Netherlands and New York, NY
+ *
*/
-/* TODO
- *
- * - get digitalInput working
- * - add pulseIn functionality
- * - add software PWM for servos, etc
- * - redesign protocol to accomodate boards with more I/Os
- * - add cycle markers to mark start of analog, digital, pulseIn, and PWM
+/*
+ * TODO: get digitalInput working
+ * TODO: add pulseIn functionality
+ * TODO: add software PWM for servos, etc (servo.h or pulse.h)
+ * TODO: redesign protocol to accomodate boards with more I/Os
+ * TODO: add cycle markers to mark start of analog, digital, pulseIn, and PWM
*/
/* firmata protocol
@@ -29,7 +50,7 @@
/* computer->Arduino commands
* -------------------- */
- /* 128-129 // UNUSED */
+/* 128-129 // UNUSED */
#define SET_PIN_ZERO_TO_IN 130 // set digital pin 0 to INPUT
#define SET_PIN_ONE_TO_IN 131 // set digital pin 1 to INPUT
#define SET_PIN_TWO_TO_IN 132 // set digital pin 2 to INPUT
@@ -89,11 +110,11 @@
* 2 digitalOut 7-13 bitmask
*/
- /* two byte software PWM data format
+/* two byte PWM data format
* ----------------------
- * 0 get ready for digital input bytes (250/251)
+ * 0 get ready for digital input bytes (ENABLE_SOFTWARE_PWM/ENABLE_PWM)
* 1 pin #
- * 2 pulse width
+ * 2 duty cycle expressed as 1 byte (255 = 100%)
*/
@@ -116,12 +137,6 @@
* 14 analog input pin 11 from Arduino // byte 14
*/
-/*
- * CAUTION!! Be careful with the Serial Monitor, it could freeze
- * your computer with this firmware running! It outputs data
- * without a delay() so its very fast.
- */
-
#define TOTAL_DIGITAL_PINS 14
// for comparing along with INPUT and OUTPUT
@@ -180,8 +195,8 @@ void transmitDigitalInput(byte startPin) {
else {
digitalData = digitalRead(digitalPin);
}
-/* the next line probably needs to be re-thought (i.e. it might not work...) since my
- first attempt was miserably wrong. <hans@at.or.at> */
+ /* the next line probably needs to be re-thought (i.e. it might not work...) since my
+ first attempt was miserably wrong. <hans@at.or.at> */
transmitByte = transmitByte + ((2^i)*digitalData);
}
printByte(transmitByte);
@@ -219,20 +234,20 @@ void setPinMode(int pin, int mode) {
}
void setSoftPwm (int pin, byte pulsePeriod) {
- byte i;
-/* for(i=0; i<7; ++i) {
+ byte i;
+ /* for(i=0; i<7; ++i) {
mask = 1 << i;
if(digitalPinStatus & mask) {
- digitalWrite(i, inputData & mask);
+ digitalWrite(i, inputData & mask);
}
- }
- */
- //read timer type thing
-
- //loop through each pin, turn them on if selected
- //softwarePWMStatus
- //check timer type thing against pulsePeriods for each pin
- //throw pin low if expired
+ }
+ */
+ //read timer type thing
+
+ //loop through each pin, turn them on if selected
+ //softwarePWMStatus
+ //check timer type thing against pulsePeriods for each pin
+ //throw pin low if expired
}
void setSoftPwmFreq(byte freq) {
@@ -240,13 +255,13 @@ void setSoftPwmFreq(byte freq) {
void disSoftPwm(int pin) {
- //throw pin low
+ //throw pin low
}
-// -------------------------------------------------------------------------
-/* this function checks to see if there is data waiting on the serial port
+/* -------------------------------------------------------------------------
+ * this function checks to see if there is data waiting on the serial port
* then processes all of the stored data
*/
void checkForInput() {
@@ -257,7 +272,10 @@ void checkForInput() {
}
}
-// -------------------------------------------------------------------------
+/* -------------------------------------------------------------------------
+ * processInput() is called whenever a byte is available on the
+ * Arduino's serial port. This is where the commands are handled.
+ */
void processInput(byte inputData) {
int i;
int mask;
@@ -273,19 +291,19 @@ void processInput(byte inputData) {
switch(executeMultiByteCommand) {
case ENABLE_PWM:
case DISABLE_PWM:
- //PWM 0 on the board is PIN 9
- analogWrite(storedInputData[0] + 9, storedInputData[1]);
- break;
+ //PWM 0 on the board is PIN 9
+ analogWrite(storedInputData[0] + 9, storedInputData[1]);
+ break;
case ENABLE_SOFTWARE_PWM:
- setPinMode(storedInputData[0],SOFTPWM);
- setSoftPwm(storedInputData[0], storedInputData[1]);
- break;
+ setPinMode(storedInputData[0],SOFTPWM);
+ setSoftPwm(storedInputData[0], storedInputData[1]);
+ break;
case DISABLE_SOFTWARE_PWM:
- disSoftPwm(storedInputData[0]);
- break;
+ disSoftPwm(storedInputData[0]);
+ break;
case SET_SOFTWARE_PWM_FREQ:
- setSoftPwmFreq(storedInputData[0]);
- break;
+ setSoftPwmFreq(storedInputData[0]);
+ break;
}
executeMultiByteCommand = 0;
}
@@ -313,7 +331,7 @@ void processInput(byte inputData) {
}
else {
switch (inputData) {
- case SET_PIN_ZERO_TO_IN:
+ case SET_PIN_ZERO_TO_IN: // set digital pins to INPUT
case SET_PIN_ONE_TO_IN:
case SET_PIN_TWO_TO_IN:
case SET_PIN_THREE_TO_IN:
@@ -327,9 +345,9 @@ void processInput(byte inputData) {
case SET_PIN_ELEVEN_TO_IN:
case SET_PIN_TWELVE_TO_IN:
case SET_PIN_THIRTEEN_TO_IN:
- setPinMode(inputData - SET_PIN_ZERO_TO_IN, INPUT);
- break;
- case SET_PIN_ZERO_TO_OUT:
+ setPinMode(inputData - SET_PIN_ZERO_TO_IN, INPUT);
+ break;
+ case SET_PIN_ZERO_TO_OUT: // set digital pins to OUTPUT
case SET_PIN_ONE_TO_OUT:
case SET_PIN_TWO_TO_OUT:
case SET_PIN_THREE_TO_OUT:
@@ -343,45 +361,45 @@ void processInput(byte inputData) {
case SET_PIN_ELEVEN_TO_OUT:
case SET_PIN_TWELVE_TO_OUT:
case SET_PIN_THIRTEEN_TO_OUT:
- setPinMode(inputData - SET_PIN_ZERO_TO_OUT, OUTPUT);
- break;
- case DISABLE_DIGITAL_INPUTS: // all digital inputs off
- digitalInputsEnabled = false;
- break;
- case ENABLE_DIGITAL_INPUTS: // all digital inputs on
- digitalInputsEnabled = true;
- break;
- case DISABLE_ALL_ANALOG_INS: // analog input off
- case ENABLE_ONE_ANALOG_IN: // analog 0 on
- case ENABLE_TWO_ANALOG_INS: // analog 0,1 on
- case ENABLE_THREE_ANALOG_INS: // analog 0-2 on
- case ENABLE_FOUR_ANALOG_INS: // analog 0-3 on
- case ENABLE_FIVE_ANALOG_INS: // analog 0-4 on
- case ENABLE_SIX_ANALOG_INS: // analog 0-5 on
- analogInputsEnabled = inputData - DISABLE_ALL_ANALOG_INS;
- break;
+ setPinMode(inputData - SET_PIN_ZERO_TO_OUT, OUTPUT);
+ break;
+ case DISABLE_DIGITAL_INPUTS: // all digital inputs off
+ digitalInputsEnabled = false;
+ break;
+ case ENABLE_DIGITAL_INPUTS: // all digital inputs on
+ digitalInputsEnabled = true;
+ break;
+ case DISABLE_ALL_ANALOG_INS: // analog input off
+ case ENABLE_ONE_ANALOG_IN: // analog 0 on
+ case ENABLE_TWO_ANALOG_INS: // analog 0,1 on
+ case ENABLE_THREE_ANALOG_INS: // analog 0-2 on
+ case ENABLE_FOUR_ANALOG_INS: // analog 0-3 on
+ case ENABLE_FIVE_ANALOG_INS: // analog 0-4 on
+ case ENABLE_SIX_ANALOG_INS: // analog 0-5 on
+ analogInputsEnabled = inputData - DISABLE_ALL_ANALOG_INS;
+ break;
case ENABLE_PWM:
- waitForData = 2; // (pin#, dutyCycle)
- executeMultiByteCommand = inputData;
- break;
+ waitForData = 2; // 2 bytes needed (pin#, dutyCycle)
+ executeMultiByteCommand = inputData;
+ break;
case DISABLE_PWM:
- waitForData = 1; // pin#
- executeMultiByteCommand = inputData;
- break;
+ waitForData = 1; // 1 byte needed (pin#)
+ executeMultiByteCommand = inputData;
+ break;
case SET_SOFTWARE_PWM_FREQ:
- waitForData = 1; // pin#
- executeMultiByteCommand = inputData;
- break;
+ waitForData = 1; // 1 byte needed (pin#)
+ executeMultiByteCommand = inputData;
+ break;
case ENABLE_SOFTWARE_PWM:
- waitForData = 2; // (pin#, dutyCycle)
- executeMultiByteCommand = inputData;
- break;
+ waitForData = 2; // 2 bytes needed (pin#, dutyCycle)
+ executeMultiByteCommand = inputData;
+ break;
case DISABLE_SOFTWARE_PWM:
- waitForData = 1; // pin#
- executeMultiByteCommand = inputData;
- break;
- case OUTPUT_TO_DIGITAL_PINS: // bytes to send to digital outputs
- firstInputByte = true;
+ waitForData = 1; // 1 byte needed (pin#)
+ executeMultiByteCommand = inputData;
+ break;
+ case OUTPUT_TO_DIGITAL_PINS: // bytes to send to digital outputs
+ firstInputByte = true;
break;
}
}
@@ -423,7 +441,7 @@ void loop() {
for(analogPin=0; analogPin<analogInputsEnabled; ++analogPin) {
analogData = analogRead(analogPin);
// these two bytes get converted back into the whole number in Pd
- // the higher bits should be zeroed so that the 8th bit doesn't get set
+ // the higher bits should be zeroed so that the 8th bit doesn't get set
printByte(analogData >> 7); // bitshift the big stuff into the output byte
printByte(analogData % 128); // mod by 32 for the small byte
checkForInput();
diff --git a/arduino-help.pd b/arduino-help.pd
index 9c926ff..a719278 100644
--- a/arduino-help.pd
+++ b/arduino-help.pd
@@ -1,4 +1,4 @@
-#N canvas 525 22 658 550 10;
+#N canvas 157 22 662 554 10;
#X msg 156 146 open \$1;
#N canvas 162 133 534 384 serin 0;
#X obj 120 61 cnv 15 15 15 empty \$0-number-canvas 1 4 8 0 14 -233017
@@ -28,30 +28,30 @@
#X obj 408 289 tgl 15 0 empty empty changes 0 -6 0 8 -262144 -1 -1
0 1;
#X obj 278 29 hradio 15 1 0 14 empty empty empty 0 -6 0 8 -262131 -1
--1 11;
+-1 9;
#X obj 255 30 tgl 15 0 empty empty empty 0 -6 0 8 -262131 -1 -1 0 1
;
#X obj 355 292 tgl 15 0 empty empty all 0 -6 0 8 -262144 -1 -1 0 1
;
-#N canvas 100 289 630 349 decode 0;
+#N canvas 196 579 634 353 decode 0;
#X obj 241 26 inlet;
#X obj 46 189 & 1;
#X obj 72 189 & 2;
#X obj 98 189 & 4;
#X obj 46 213 tgl 15 0 empty empty 0 4 25 1 12 -262144 -1 -1 0 1;
-#X obj 72 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 2
+#X obj 72 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 2 2
;
#X obj 98 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 4
;
#X obj 124 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
8;
-#X obj 150 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+#X obj 150 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 16
16;
#X obj 182 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
32;
#X obj 215 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
64;
-#X obj 248 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+#X obj 248 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 128
128;
#X obj 287 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
256;
@@ -61,7 +61,7 @@
;
#X obj 409 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
2048;
-#X obj 453 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+#X obj 453 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 4096
4096;
#X obj 499 213 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
4;
@@ -117,12 +117,12 @@
#X msg 165 44 PWM2;
#X msg 129 44 PWM1;
#X msg 94 44 PWM0;
-#X obj 67 215 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 16383
-;
+#X obj 67 215 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 16383
+16383;
#X obj 67 178 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
#X obj 21 336 spigot 0;
-#X obj 64 307 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+#X obj 64 307 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
;
#X obj 21 358 route analog0 analog1 analog2 analog3 analog4 analog5
;
@@ -130,7 +130,7 @@
#X obj 487 428 print GARBAGE;
#X floatatom 430 488 6 0 0 0 - - -;
#X text 393 56 how many analogIns to enable:;
-#X obj 405 117 tgl 15 0 empty empty empty 0 -6 0 8 -257472 -1 -1 0
+#X obj 405 117 tgl 15 1 empty empty empty 0 -6 0 8 -257472 -1 -1 1
1;
#X text 428 116 enable/disable digitalIns;
#X msg 405 135 digitalIns \$1;
@@ -160,7 +160,6 @@
#X obj 400 444 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
1;
#X obj 367 483 print;
-#X msg 381 225 231 \, 20 \, 226 \, 213;
#X text 5 229 this will flash any pin set to output;
#N canvas 0 22 261 248 speed 0;
#X obj 21 41 inlet;
@@ -245,7 +244,7 @@ the CPU;
#X text 371 15 6;
#X text 327 15 3;
#X msg 255 71 outputMode \$2 \$1;
-#N canvas 485 91 566 347 sending 0;
+#N canvas 485 91 574 355 sending 0;
#X obj 142 285 outlet;
#X obj 129 84 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
;
@@ -306,53 +305,54 @@ bits of digital output values per byte.;
#X connect 22 0 16 0;
#X restore 10 258 pd sending digital outs;
#X obj 255 274 arduino 3;
-#X connect 0 0 62 0;
+#X msg 381 225 251 \, 9 \, 20 \, 142 \, 213;
+#X connect 0 0 61 0;
#X connect 1 0 0 0;
-#X connect 5 0 62 0;
-#X connect 7 0 44 2;
-#X connect 8 0 54 1;
-#X connect 9 0 54 0;
-#X connect 10 0 44 1;
+#X connect 5 0 61 0;
+#X connect 7 0 43 2;
+#X connect 8 0 53 1;
+#X connect 9 0 53 0;
+#X connect 10 0 43 1;
#X connect 12 0 18 0;
#X connect 13 0 6 0;
-#X connect 17 0 62 0;
+#X connect 17 0 61 0;
#X connect 18 0 17 0;
-#X connect 19 0 52 0;
-#X connect 20 0 52 0;
-#X connect 21 0 52 0;
-#X connect 22 0 62 0;
-#X connect 23 0 53 0;
+#X connect 19 0 51 0;
+#X connect 20 0 51 0;
+#X connect 21 0 51 0;
+#X connect 22 0 61 0;
+#X connect 23 0 52 0;
#X connect 24 0 26 0;
#X connect 25 0 24 1;
-#X connect 26 0 43 0;
-#X connect 26 1 43 1;
-#X connect 26 2 43 2;
-#X connect 26 3 43 3;
-#X connect 26 4 43 4;
-#X connect 26 5 43 5;
-#X connect 26 6 43 6;
+#X connect 26 0 42 0;
+#X connect 26 1 42 1;
+#X connect 26 2 42 2;
+#X connect 26 3 42 3;
+#X connect 26 4 42 4;
+#X connect 26 5 42 5;
+#X connect 26 6 42 6;
#X connect 27 0 11 0;
#X connect 27 0 29 0;
#X connect 27 0 38 0;
#X connect 27 1 28 0;
#X connect 31 0 33 0;
-#X connect 33 0 62 0;
-#X connect 34 0 62 0;
+#X connect 33 0 61 0;
+#X connect 34 0 61 0;
#X connect 35 0 34 0;
#X connect 38 0 40 0;
#X connect 39 0 38 1;
-#X connect 41 0 62 1;
-#X connect 43 0 46 0;
-#X connect 43 1 47 0;
-#X connect 43 2 48 0;
-#X connect 43 3 49 0;
-#X connect 43 4 50 0;
-#X connect 43 5 51 0;
-#X connect 43 6 27 0;
-#X connect 52 0 18 1;
-#X connect 53 0 22 0;
-#X connect 54 0 60 0;
-#X connect 60 0 62 0;
-#X connect 61 0 62 0;
-#X connect 62 0 24 0;
-#X connect 62 1 44 0;
+#X connect 42 0 45 0;
+#X connect 42 1 46 0;
+#X connect 42 2 47 0;
+#X connect 42 3 48 0;
+#X connect 42 4 49 0;
+#X connect 42 5 50 0;
+#X connect 42 6 27 0;
+#X connect 51 0 18 1;
+#X connect 52 0 22 0;
+#X connect 53 0 59 0;
+#X connect 59 0 61 0;
+#X connect 60 0 61 0;
+#X connect 61 0 24 0;
+#X connect 61 1 43 0;
+#X connect 62 0 61 1;
diff --git a/arduino.pd b/arduino.pd
index bff59ca..53ac978 100644
--- a/arduino.pd
+++ b/arduino.pd
@@ -1,4 +1,5 @@
-#N canvas 158 31 628 508 10;
+#N canvas 158 31 627 495 10;
+#X obj 504 -5 import flatspace;
#X text 414 457 released under the GNU GPL;
#X text 9 457 (C) Copyright 2006 Hans-Christoph Steiner <hans@at.or.at>
;
@@ -59,7 +60,7 @@
#X obj 126 425 outlet;
#X obj 494 241 outlet;
#X obj 11 66 comport \$1 9600;
-#N canvas 495 157 582 327 command 0;
+#N canvas 240 171 586 331 command 0;
#X obj 79 8 inlet;
#X obj 198 269 outlet;
#X obj 135 115 * 255;
@@ -74,7 +75,7 @@
#X obj 200 94 clip 0 6;
#X obj 263 94 clip 0 1;
#X obj 263 115 int;
-#N canvas 0 22 462 312 digital-out 0;
+#N canvas 0 22 466 316 digital-out 0;
#X obj 67 20 inlet;
#X obj 85 280 outlet;
#X obj 65 108 route float;
@@ -151,30 +152,30 @@
#X obj 443 -5 inlet;
#X text 382 -10 raw input;
#X text 48 -11 processed input;
-#X connect 2 0 4 0;
-#X connect 2 1 9 0;
-#X connect 3 0 2 0;
-#X connect 3 0 7 0;
-#X connect 4 0 5 0;
-#X connect 5 0 18 0;
-#X connect 5 1 6 1;
-#X connect 6 0 20 0;
-#X connect 7 0 18 1;
-#X connect 8 0 3 0;
-#X connect 8 1 15 0;
-#X connect 9 0 4 1;
-#X connect 10 0 14 0;
-#X connect 13 0 8 0;
-#X connect 13 0 12 0;
+#X connect 3 0 5 0;
+#X connect 3 1 10 0;
+#X connect 4 0 3 0;
+#X connect 4 0 8 0;
+#X connect 5 0 6 0;
+#X connect 6 0 19 0;
+#X connect 6 1 7 1;
+#X connect 7 0 21 0;
+#X connect 8 0 19 1;
+#X connect 9 0 4 0;
+#X connect 9 1 16 0;
+#X connect 10 0 5 1;
+#X connect 11 0 15 0;
+#X connect 14 0 9 0;
#X connect 14 0 13 0;
-#X connect 15 0 2 0;
-#X connect 16 0 6 0;
-#X connect 17 0 6 0;
-#X connect 18 0 19 0;
-#X connect 18 0 21 0;
-#X connect 19 0 18 1;
-#X connect 20 0 11 0;
-#X connect 21 0 16 0;
-#X connect 21 1 23 0;
-#X connect 23 0 17 0;
-#X connect 24 0 13 0;
+#X connect 15 0 14 0;
+#X connect 16 0 3 0;
+#X connect 17 0 7 0;
+#X connect 18 0 7 0;
+#X connect 19 0 20 0;
+#X connect 19 0 22 0;
+#X connect 20 0 19 1;
+#X connect 21 0 12 0;
+#X connect 22 0 17 0;
+#X connect 22 1 24 0;
+#X connect 24 0 18 0;
+#X connect 25 0 14 0;