Skip to content

Instantly share code, notes, and snippets.

@mpflaga
Last active January 23, 2022 15:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpflaga/b93d8375a10af06143b2 to your computer and use it in GitHub Desktop.
Save mpflaga/b93d8375a10af06143b2 to your computer and use it in GitHub Desktop.
Sketch to daisy chain Arduino Mega's from a PC running Vixen, as to get infinite Cue's.
/*
This sketch is used with Vixen Sequence to allow Arduino's to be daisy chained.
see for details.
http://stackoverflow.com/questions/27172147/arduino-serial-communcation-with-vixen
*/
#define FIRST_IN_CHAIN 1 // set this to 1 for the first in Chain
#define SIZE_OF_ARRAY(X) (sizeof(X)/sizeof(X[0])) //total length divided by length of one element
// As specified in Vixen's General Serial Port Setup "Send a Text Footer"
#define VIXEN_END_OF_TEXT 'E'
#if (FIRST_IN_CHAIN == 1)
#define SERIALIN Serial
#else
#define SERIALIN Serial2
#endif
// General GPIO used to output Cues
uint8_t pins[] = {3,4,5,6,7,8,9,10,11,12,13,\
// not used SerialX ports
// 14,15, \ // TXD3/RXD3
// 16,17, \ // TXD2/RXD2
// 18,19, \ // TXD1/RXD1
// 20,21, \ // SDA/SCL
22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53};
void setup() {
SERIALIN.begin(9600);
Serial3.begin(9600);
// initialize cue pins OFF and Output
for (uint8_t pin = 0; pin < SIZE_OF_ARRAY(pins); pin++) {
digitalWrite(pins[pin], LOW);
pinMode(pins[pin], OUTPUT);
}
}
void loop()
{
// get first 43 cues for this Arduino
for (uint8_t pin = 0; pin < SIZE_OF_ARRAY(pins); pin++) {
while(!SERIALIN.available()); // wait for some data.
char c = SERIALIN.read();
if(c == VIXEN_END_OF_TEXT) {
return;
}
else if(c > 0x00) {
digitalWrite(pins[pin], HIGH);
}
else {
digitalWrite(pins[pin], LOW);
}
}
// read from port 0, send to port 1:
while(1) {
while(!SERIALIN.available()) ; // wait for next data.
char c = SERIALIN.read();
if(c == VIXEN_END_OF_TEXT) {
// when Carriage Return is received Exit while and wait for new frame
break;
}
else {
// echo byte on to the next stage
Serial3.write(c);
}
}
}
@mpflaga
Copy link
Author

mpflaga commented Nov 28, 2014

The typical example that appears to be proliferated for Arduino's receiving from Vixen. Is scary in that it does not frame the Start or End of the stream of cues. Rather it requires the stream to be and stay synchronized, being dependent upon the length. This will work until ONE byte is lost. Then everything will be out of sync until reset and restarted. Something you will not want to do with multiple Arduino's.

Now this is not perfect and since I don't have a Vixen and such set up it has not been proven. However, it does compile and appears it should work fine.

In general it appears that Vixen sends out the stream of bytes of Cue's terminating the frame with a Carriage Return or possibly Line Feed. So the above sketch listens for the first 43 cues and applies them to the local pins. Then echos the remainder out Serial3 to the next Arduino, until a CR or LF is received denoting the end of Frame. At which point it starts over. Note the cue's locally applied are not echo'ed, this means the next Arduino will again act on the first 43 cues and echo the remained until the chain is exhausted. It is required that the last unit get all 43. So if the total count is short it then that last unit will not properly continue. (Something for the future. Or it may be best to pad a few extra on the end of the Vixen's output.)

Note the use of

while(!SERIALIN.available()); // wait for some data.

Which is effectively "wait while there is no data to be read" or wait until there is something. These are Blocking (meaning the code is stuck) until something is received. Whereas it is expected that Vixen will periodically be sending the stream of cues. And even if ONE CR/LF is missed the next frame will have it, so that the code will autonomously resynchronize.

Also worth noting the pins to cue definition is more flexible. If you want to possible use 47 cues, un-comment:

// 18,19, \ // TXD1/RXD1
// 20,21, \ // SDA/SCL

the code will automatically resize. Or comment out other pins if used for other purposes.

To summarize the first unit is compiled with FIRST_IN_CHAIN defined as 1. This causes the lead ArduinoMega to receive the data from Serial port attached to the PC running Vixen. The remaining Mega's are compiled with FIRST_IN_CHAIN defined as 0. Where the Serial3 of the preceding unit is connected to the next units Serial2. It is possible to drive into Serial. Where it is simpler to reserve Serial for debugging and such.

And don't forget to connect a common ground along with RxD and TxD.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment