Combine two sketches (SimpleDMX and Firmata / SimpleMessageSystem)

Hey there!

My plan is to connect potmeters/spst pushbuttons to my Arduino Uno, to read these by Puredata Extended through SimpleMessageSystem/Firmata (on a Raspberry Pi, but writing and pre-testing happens on my Mac), and then to let Puredata send out DMX through a DmxSimple sketch. For this I have a Tinkerkit DMX shield.

I got everything to work separately, but I can't get to combine the different sketches.

To make my steps clear:
-I first tested to send DMX to a connected DMX light. I used the SerialToDmx sketch which is provided with the DmxSimple library. This is the sketch:

#include <DmxSimple.h>

void setup() {
  Serial.begin(9600);
  Serial.println("SerialToDmx ready");
  Serial.println();
  Serial.println("Syntax:");
  Serial.println(" 123c : use DMX channel 123");
  Serial.println(" 45w  : set current channel to value 45");
}

int value = 0;
int channel;

void loop() {
  int c;

  while(!Serial.available());
  c = Serial.read();
  if ((c>='0') && (c<='9')) {
    value = 10*value + c - '0';
  } else {
    if (c=='c') channel = value;
    else if (c=='w') {
      DmxSimple.write(channel, value);
      Serial.println();
    }
    value = 0;
  }
}

-I then tested to get input from potmeters/pushbuttons. This all works through either the SimpleAnalogFirmata and the SimpleDigitalFirmata sketches. (for some reason the StandardFirmata gave me problems, and the sketch is too much anyways for what I need) I combined these sketches without a problem too:

#include <Firmata.h>

//Digital
byte previousPIN[TOTAL_PORTS];  // PIN means PORT for input
byte previousPORT[TOTAL_PORTS];

//Analog
byte analogPin = 0;

//Digital
void outputPort(byte portNumber, byte portValue)
{
    // only send the data when it changes, otherwise you get too many messages!
    if (previousPIN[portNumber] != portValue) {
        Firmata.sendDigitalPort(portNumber, portValue); 
        previousPIN[portNumber] = portValue;
    }
}

void setPinModeCallback(byte pin, int mode) {
    if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), mode);
    }
}

void digitalWriteCallback(byte port, int value)
{
    byte i;
    byte currentPinValue, previousPinValue;

    if (port < TOTAL_PORTS && value != previousPORT[port]) {
        for(i=0; i<8; i++) {
            currentPinValue = (byte) value & (1 << i);
            previousPinValue = previousPORT[port] & (1 << i);
            if(currentPinValue != previousPinValue) {
                digitalWrite(i + (port*8), currentPinValue);
            }
        }
        previousPORT[port] = value;
    }
}
//Analog
void analogWriteCallback(byte Apin, int Avalue)
{
    if (IS_PIN_PWM(Apin)) {
        pinMode(PIN_TO_DIGITAL(Apin), OUTPUT);
        analogWrite(PIN_TO_PWM(Apin), Avalue);
    }
}



void setup()
{
    //Digital
    Firmata.setFirmwareVersion(0, 1);
    Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
    Firmata.attach(SET_PIN_MODE, setPinModeCallback);
    Firmata.begin(57600);
    //Analog
    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
}

void loop()
{
    //Digital
    byte i;

    for (i=0; i<TOTAL_PORTS; i++) {
        outputPort(i, readPort(i, 0xff));
    }

    while(Firmata.available()) {
        Firmata.processInput();
    }
    //Analog
    while(Firmata.available()) {
        Firmata.processInput();
    }
    // do one analogRead per loop, so if PC is sending a lot of
    // analog write messages, we will only delay 1 analogRead
    Firmata.sendAnalog(analogPin, analogRead(analogPin)); 
    analogPin = analogPin + 1;
    if (analogPin >= TOTAL_ANALOG_PINS) analogPin = 0;
}

This is what I got when I merged this Firmata sketch with the DMX sketch:

//Digital / Analog
#include <Firmata.h>
//DMX
#include <DmxSimple.h>


//Digital
byte previousPIN[TOTAL_PORTS];  // PIN means PORT for input
byte previousPORT[TOTAL_PORTS];

//Analog
byte analogPin = 0;

//Digital
void outputPort(byte portNumber, byte portValue)
{
    // only send the data when it changes, otherwise you get too many messages!
    if (previousPIN[portNumber] != portValue) {
        Firmata.sendDigitalPort(portNumber, portValue); 
        previousPIN[portNumber] = portValue;
    }
}

void setPinModeCallback(byte pin, int mode) {
    if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), mode);
    }
}

void digitalWriteCallback(byte port, int Dvalue)
{
    byte i;
    byte currentPinValue, previousPinValue;

    if (port < TOTAL_PORTS && Dvalue != previousPORT[port]) {
        for(i=0; i<8; i++) {
            currentPinValue = (byte) Dvalue & (1 << i);
            previousPinValue = previousPORT[port] & (1 << i);
            if(currentPinValue != previousPinValue) {
                digitalWrite(i + (port*8), currentPinValue);
            }
        }
        previousPORT[port] = Dvalue;
    }
}
//Analog
void analogWriteCallback(byte Apin, int Avalue)
{
    if (IS_PIN_PWM(Apin)) {
        pinMode(PIN_TO_DIGITAL(Apin), OUTPUT);
        analogWrite(PIN_TO_PWM(Apin), Avalue);
    }
}



void setup()
{
    //Digital
    Firmata.setFirmwareVersion(0, 1);
    Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
    Firmata.attach(SET_PIN_MODE, setPinModeCallback);
    Firmata.begin(57600);
    //Analog
    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
    //DMX
    //Serial.begin(9600);
    Serial.println("SerialToDmx ready");
    Serial.println();
    Serial.println("Syntax:");
    Serial.println(" 123c : use DMX channel 123");
    Serial.println(" 45w  : set current channel to value 45");
}

//DMX
//int value = 0;
//int channel;

void loop()
{
    //Digital
    byte i;

    for (i=0; i<TOTAL_PORTS; i++) { //now it reads digital pins starting at pin 0 right? Because DMX goes over pin 3.
    outputPort(i, readPort(i, 0xff));
    }

    while(Firmata.available()) {
        Firmata.processInput();
    }
    //Analog
    while(Firmata.available()) {
        Firmata.processInput();
    }
    // do one analogRead per loop, so if PC is sending a lot of
    // analog write messages, we will only delay 1 analogRead
    Firmata.sendAnalog(analogPin, analogRead(analogPin)); 
    analogPin = analogPin + 1;
    if (analogPin >= TOTAL_ANALOG_PINS) analogPin = 0;
    
    //DMX
//    int c;
//    while(!Serial.available());
//    c = Serial.read();
//    if ((c>='0') && (c<='9')) {
//      value = 10*value + c - '0';
//    } else {
//      if (c=='c') channel = value;
//      else if (c=='w') {
//        DmxSimple.write(channel, value);
//        Serial.println();
//      }
//      value = 0;
//  }
}

As you can see I made some of the DMX lines into comments using '//', because I was testing to see where the two sketches had problems. Right now as it is, I can get data from the Analog and Digital pins, but when I 'uncomment' more lines of the DMX sketch, my data will not be received anymore. I thought it had to do with Serial.begin(9600) and Firmata.begin(57600). As far as I understand that is the speed the devices are talking on the serial connection. This might give some problems. I also realized that both sketches are trying to use the same pins. As far as I understand DmxSimple comunicates to my DMX Shield over digital pin 3.

I then sought a solution in trying another Sketch/Library to read the pins for Pure Data. I found the SimpleMessageSystem library with the Arduino2PD sketch and Pure Data patch. This also worked perfect with my pots and buttons, this is the sketch:

#include <SimpleMessageSystem.h>

char firstChar; 
char secondChar;

void setup()
{
  Serial.begin(115200);
}


void loop()
{ 
  
  
   if (messageBuild()) { // Checks to see if the message is complete 
      firstChar = messageGetChar(); { // Gets the first word as a character 

     if (firstChar = 'r') { // Checking for the character 'r' 
          secondChar = messageGetChar(); // Gets the next word as a character 
          if (firstChar = 'd') // The next character has to be 'd' to continue 
               messageSendChar('d');  // Echo what is being read 

       for (int i=0;i<=5;i++) { 
       messageSendInt(analogRead(i)); // Read analog pins 0 to 5
          }

       for (int m=2;m<=12;m++) { 
       messageSendInt(digitalRead(m)); // Read digital pins 2 to 12, 13 is onboard LED on Arduino NG
          }
            
       messageEnd(); // Terminate the message being sent 
       
          
                    } 
      }
   }
}

I thought this sketch had perfect capabilities to work together with the DmxSimple sketch, because here I can set to read the digital pins starting from 4 (it is reading here starting from pin 2), and also it uses the same boud rate in this sketch as the DMX sketch (although it advices to test higher rates later). But when I merged them together, it still won't work for both. (I will post the code of this merge in the next post, because otherwise this post exceeds the 9500 characters I can use)

I tried to read and understand the sketches, but the referred libraries seem so complicated, that with my limited programming knowledge, it's impossible for me to really understand what is happening.

Could anyone help me?

This is the combined sketch of SimpleDMX and Arduino2PD together. As you can see I disabled the last lines of code, if I 'uncomment' them I won't receive input from the pins anymore in Pure Data.

//SMS
#include <SimpleMessageSystem.h>
//DMX
#include <DmxSimple.h>

//SMS
char firstChar; 
char secondChar;

void setup()
{
  Serial.begin(9600);
  //DMX
  Serial.println("SerialToDmx ready");
  Serial.println();
  Serial.println("Syntax:");
  Serial.println(" 123c : use DMX channel 123");
  Serial.println(" 45w  : set current channel to value 45");
}

//DMX
int value = 0;
int channel;

void loop()
{ 

  //SMS
  if (messageBuild()) { // Checks to see if the message is complete 
    firstChar = messageGetChar(); 
    { // Gets the first word as a character 

        if (firstChar = 'rr') { // Checking for the character 'r' 
        secondChar = messageGetChar(); // Gets the next word as a character 
        if (firstChar = 'dd') // The next character has to be 'd' to continue 
          messageSendChar('dd');  // Echo what is being read 

        for (int ii=0;ii<=5;ii++) { 
          messageSendInt(analogRead(ii)); // Read analog pins 0 to 5
        }

        for (int mm=5;mm<=12;mm++) { 
          messageSendInt(digitalRead(mm)); // Read digital pins 5!! to 12, 13 is onboard LED on Arduino NG
        }

        messageEnd(); // Terminate the message being sent 


      } 
    }
  }
  //DMX
//  int c;
//  while(!Serial.available());
//  c = Serial.read();
//  if ((c>='0') && (c<='9')) {
//    value = 10*value + c - '0';
//  } 
//  else {
//    if (c=='c') channel = value;
//    else if (c=='w') {
//      DmxSimple.write(channel, value);
//      Serial.println();
//    }
//    value = 0;
//  }
}

Is there anyone familiar with merging scripts? Did I maybe not clarify my problem enough? Please tell me if so.

. I thought it had to do with Serial.begin(9600) and Firmata.begin(57600). As far as I understand that is the speed the devices are talking on the serial connection. This might give some problems. I also realized that both sketches are trying to use the same pins. As far as I understand DmxSimple comunicates to my DMX Shield over digital pin 3.

Yes basically that is your problem .

It matters not what speed they communicate at but both want to use the same pins and the same hardware resource.
You could try using software serial but basically I think you are out of your depth.
Firmata is designed for very simple tasks. If you want to do any real programming you must ditch it. It is harder to graft these two together than it is start and program up exactly what you need.

This might explain the lack of replies.

Cool, thanks. That's clear, I'm just gonna try to write something myself. What would be some first good steps do you recon? Looking into coding for Arduino? Any recommendations on books on this subject? How many hours would you recon that it would take for an experienced Arduino programmer to do something like this?

What would be some first good steps do you recon?

Look at the example programs under menu file -> examples in the IDE. Get a feel for the syntax of the language, change some things and see if you can predict what these changes will do before you make them.

Then get some LEDs and pots and start playing about and do a few tutorials.

Any recommendations on books on this subject

How about this:-

I do know the author, but it is a good book anyway. :slight_smile:

How many hours would you recon that it would take for an experienced Arduino programmer to do something like this?

Tricky - but no more than two.

Cool, thanks, I'm gonna start right away with it. If this doesn't work I'll go and buy a book. Thanks for the tip! I will find it out.. :slight_smile: