Raspberry Pi getting data from MultiWii
Question: I have a Raspberry Pi 3B and a CRIUS All in One Pro (v2.0) MultiWii flight
controller. I'm using the MultiWii 2.4 version and the latest NOOBS. I was
able to set up both fine, and now I am trying to get the Raspberry Pi to
communicate with the MultiWii through a USB/Micro USB cable that connects the
two boards.

At the moment, the MultiWii isn't returning any data back, and I'm not sure
why. From what I can see, I have the protocol correct. I've looked at several
working code repos (written in Python of Java for Arduino), and have followed
the [MultiWii
documentation](http://www.multiwii.com/wiki/index.php?title=Multiwii_Serial_Protocol)
and read through the associated [forum
post](http://www.multiwii.com/forum/viewtopic.php?f=8&t=1516).

Here is the client code that I wrote.

    
    
    package com.jmace.MaceDrone.msp;
    
    
    import com.pi4j.io.serial.Baud;
    import com.pi4j.io.serial.DataBits;
    import com.pi4j.io.serial.FlowControl;
    import com.pi4j.io.serial.Parity;
    import com.pi4j.io.serial.Serial;
    import com.pi4j.io.serial.SerialConfig;
    import com.pi4j.io.serial.SerialDataEvent;
    import com.pi4j.io.serial.SerialDataEventListener;
    import com.pi4j.io.serial.SerialFactory;
    import com.pi4j.io.serial.StopBits;
    import java.io.IOException;
    import java.math.BigInteger;
    
    public class MultiWiiClient {
    
        private final Serial serial;
    
        //The preamble is defined by the protocol.
        //Every message must begin with the characters $M
        private static final String PREAMBLE = "$M";
        //Character that denotes information being passed to the MultiWii
        private static final char TO_MUTLIWII = '<';
        //Character that denotes information being requested from by the MultiWii
        private static final char FROM_MUTLIWII = '>';
    
        public MultiWiiClient(String usbPort) {
            SerialConfig config = new SerialConfig();
            config.device(usbPort)
                  .baud(Baud._115200)
                  .dataBits(DataBits._8)
                  .parity(Parity.NONE)
                  .stopBits(StopBits._1)
                  .flowControl(FlowControl.NONE);
    
            this.serial = SerialFactory.createInstance();
    
            serial.addListener(new SerialDataEventListener() {
                @Override
                public void dataReceived(SerialDataEvent event) {
                    try {
                        System.out.println("[HEX DATA]   " + event.getHexByteString());
                        System.out.println("[ASCII DATA] " + event.getAsciiString());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
    
            try {
                this.serial.open(config);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        public String sendRequest(MultiWiiRequest request) throws IllegalStateException, IOException {
            String message = createMessage(request.getId(), false, null);
            //////////////////////////////////////////////////////////////////////////////////
            System.out.println(message);
            System.out.println(String.format("%040x", new BigInteger(1, message.getBytes())));
            //////////////////////////////////////////////////////////////////////////////////
            return sendMessage(message);
        }
    
    
        public String sendCommand(MultiWiiCommand command, String payload) throws IllegalStateException, IOException {
            String message = createMessage(command.getId(), true, payload);
            return sendMessage(message);
        }
    
        /**
         * This method creates the message that will be sent to the MultiWii
         * 
         * Message format is as follows:
         * +--------+---------+----+-------+----+---+
         * |preamble|direction|size|command|data|crc|
         * +--------+---------+----+-------+----+---+
         * 
         * Preamble (2 bytes):
         *      Marks the start of a new message; always "$M"
         * 
         * Direction (1 byte):
         *      Either '<' for a command going to the MultiWii or '>' for
         *      information being requested from the MultiWii
         * 
         * Size (1 byte):
         *      The number of bytes in the payload
         * 
         * Command (1 byte):
         *      The message ID of the command, as defined in the protocol
         *      100's for requesting data, and 200's for requesting an action
         * 
         * Data (variable bytes):
         *      The data to pass along with the command
         * 
         * CRC (1 byte):
         *      Calculated with an XOR of the size, command, and each byte of data 
         */
        private String createMessage(int mutliWiiCommandnumber, boolean isCommand, String payload) {
            StringBuilder message = new StringBuilder(PREAMBLE);
            byte checksum=0;
    
            //Get the direction of the message
            if (isCommand) {
                message.append(TO_MUTLIWII);
            } else {
                message.append(FROM_MUTLIWII);
            }
    
            int datalength = (payload != null) ? payload.length() : 0;
    
            message.append((char) datalength);
            checksum ^= datalength;
    
            message.append((char) mutliWiiCommandnumber);
            checksum ^= ((int) mutliWiiCommandnumber);
    
            if (payload != null) {
                for (char c : payload.toCharArray()){ 
                    message.append(c);
                    checksum ^= (int) c;
                }
            }
    
            message.append((char) checksum);
            return message.toString();
        }
    
    
        private String sendMessage(String message) throws IllegalStateException, IOException {
            serial.write(message.getBytes());
    
            serial.flush();
            System.out.println("TESTING ------------------");
    
            return "";
        }
    
    }
    

I am using "/dev/ttyUSB0" to connect, which I confirmed is the correct
location and it seems to be working (no errors when I run it; and if I start
running and then disconnect the USB, it throws an exception because it lost
the connection).

When running, I get the following output (sending command 100, MSP_IDENT):

    
    
    $M>dd
    00000000000000000000000000244d3e006464
    TESTING ------------------
    

See [my Git
repo](https://github.com/jmace01/MaceDrone/tree/master/src/com/jmace/MaceDrone/msp)
for more code context.

EDIT: Fixed the checksum code in my post


Answer: It looks like it's all as it should be, though I can't see where you're
receiving the version byte back from the serial port. in sendMessage, you have
`return ""`.

Looking at your github repo, I see that sendMessage is a bit different.

    
    
        while (!serial.getCTS()) {
            try{
                Thread.sleep(100);
            } catch (Exception e) {}
        }
    
        StringBuilder response = new StringBuilder();
        while (serial.available() != 0) {
            response.append(serial.read());
        }
    

serial.getCTS() shouldn't be used as you disabled flow control when you
initialized the port in the constructor.

I'm guessing that CTS is here used as a way to detect when the other device
has finished processing the message and has responded.

It seems there's no guarantee that after seeing the CTS line go high, that
those bytes are actually available to be received; the CTS signal would only
mean that the device has finished sending them away to you. You may wish to
put another delay in after CTS goes high to ensure all bytes have indeed been
transmitted.

