1

I have this callback function in my Firmata sketch. It receives a string as a character array and does something with it. The problem is, that the string is being sent to the Arduino in T\0h\0i\0s\0 form - after each character there is a \0 terminator. As you can see, my function is switching the d13 LED on if the string incoming is COMMAND. I had tried to use several comparison methods:

  • strcmp(myString, "COMMAND") == 1;
  • myString == "COMMAND";
  • strcmp(myString, "COMMAND\0") == 1;
  • myString == "COMMAND\0";
  • strcmp(myString, "C\0O\0M\0 M\0A\0N\0D\0") == 1;
  • myString == "C\0O\0M\0 M\0A\0N\0D\0";
  • == with saving the COMMAND to a char array variable;
  • strcmp with saving the COMMAND to a char array variable;
  • last two things with converting both the incoming and the needed to a String instance;
  • comparing a String instance with a directly stated "COMMAND"...

Nothing works. How can I compare the strings workably?

Full Arduino sketch:

#include <Firmata.h>

void stringCallback(char *myString)
{
  if (strcmp(myString, "COMMAND") == 1) {
    digitalWrite(13, HIGH);
  }
  Firmata.sendString(myString);
}


void sysexCallback(byte command, byte argc, byte *argv)
{
  Firmata.sendSysex(command, argc, argv);
}

void setup()
{
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);
  Firmata.attach(STRING_DATA, stringCallback);
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.begin(57600);
  pinMode(13, INPUT);
}

void loop()
{
  while (Firmata.available()) {
    Firmata.processInput();
  }
}

Full code of the desktop program:

import pyfirmata, time

class CustomArduino(pyfirmata.Arduino):
    def __init__(self, port: str):
        pyfirmata.Arduino.__init__(self, port)
        self.iterator = pyfirmata.util.Iterator(self)
        self.iterator.start()

        self.add_cmd_handler(0x71, self.receiveString)


    def receiveString(self, *args, **kwargs):
        print(f'Raw: {args}\n'
              f'Received: {pyfirmata.util.two_byte_iter_to_str(args)}')


    def sendString(self, data):
        self.send_sysex(0x71, pyfirmata.util.str_to_two_byte_iter(data))


    def send_sysex(self, sysex_cmd, data=[]):
        """
        Sends a SysEx msg.
        :arg sysex_cmd: A sysex command byte
        : arg data: a bytearray of 7-bit bytes of arbitrary data
        """
        msg = bytearray([pyfirmata.pyfirmata.START_SYSEX, sysex_cmd])
        msg.extend(data)
        msg.append(pyfirmata.pyfirmata.END_SYSEX)
        self.sp.write(msg)


print('STRING TESTER\nPlease input your COM port: ', end = '')
myCom = str(input())
device = CustomArduino(myCom)

while True: 
    device.sendString(input('Send: '))
    time.sleep(1)

Strange detail: my Arduino is on the COM6 COM-port. If I connect it via my program and send com6 to the arduino, the D13 LED turns on!

1
  • Comments are not for extended discussion; this conversation has been moved to chat. – Majenko Feb 11 at 15:46
0

As @timemage stated, strcmp returns 0 for equal. Sincerely in the provided code, while you send a message, which contents are not COMMAND, the LED will be turned on.

To get what we need, we must compare strcmp return value with 0! If it equals, then the strings match, and your suggested code is being executed:

void stringCallback(char *myString)
{
  if (strcmp(myString, "COMMAND") == 0) {
    digitalWrite(13, HIGH);
  }
  Firmata.sendString(myString);
}
1
  • the strcmp function is 50 years old and documented in many places. a fix of your code is not a useful resource on a Q&A site – Juraj Feb 12 at 18:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.