3

I'm trying to emulate Lego EV3 brick connection via wifi. First I found the repo and rewrote it a bit in C# so now I have this:
LabVIEW.cs

public class LabVIEW
{
    public string Serial { get; set; }
    public UInt16 Port { get; set; }
    public string? Name { get; set; }
    public string Protocol { get; set; }


    public LabVIEW() 
    {
        Serial = "001612345678";
        Port = 5555;
        Name = "EV3-rcv";
        Protocol = "EV3";
    }

    public void SpawnConnectThread()
    {
        var udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
        var localIP = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
        udpSocket.Bind(localIP);
        udpSocket.ReceiveTimeout = 10000;
        udpSocket.EnableBroadcast = true;

        var task = Task.Run(() =>
        {
            var sendStr = string.Format(
                "Serial-Number: {0}\r\nPort: {1}\r\nName: {2}\r\nProtocol: {3}\r\n",
                Serial, Port, Name, Protocol
            );
            var remoteIP = new IPEndPoint(IPAddress.Parse("127.255.255.255"), 3015);
            Console.WriteLine(sendStr);
            while (true)
            {
                byte[] toSend = Encoding.UTF8.GetBytes(sendStr);
                int sentAmount = udpSocket.SendTo(toSend, remoteIP);
                if (sentAmount == toSend.Length)
                {
                    byte[] recvBuff = new byte[64];
                    udpSocket.Receive(recvBuff, 0, 64, SocketFlags.None, out SocketError err);
                    if (err != SocketError.Success)
                    {
                        continue;
                    }

                    Console.WriteLine(Encoding.UTF8.GetString(recvBuff));
                }
                Task.Delay(5000);
            }
        });
    }

    public Socket Connect()
    {
        IPAddress localAddr = IPAddress.Parse("127.0.0.1");
        TcpListener server = new TcpListener(localAddr, Port);
        server.Start();
        var sct = server.AcceptSocket();
        byte[] recvBuff = new byte[64];
        sct.Receive(recvBuff);
        Console.WriteLine(Encoding.UTF8.GetString(recvBuff));
        byte[] toSend = Encoding.UTF8.GetBytes("Accept:EV340\r\n\r\n");
        sct.Send(toSend);
        return sct;
    }
}

And the Main part:

public class Program
{
    public static void Main(string[] args)
    {
        var lv = new LabVIEW();
        lv.SpawnConnectThread();
        var conn = lv.Connect();


        while (true)
        {
            if (conn.Available > 0)
            {
                byte[] buff = conn.ReadLVReply();
                Console.WriteLine(ByteArrayToString(buff));
                if (buff[4] == 0x80 || buff[4] == 0x81)
                {
                    // No response expected
                    continue;
                }
            }

            Thread.Sleep(300);
        }
    }

    public static string ByteArrayToString(byte[] ba)
    {
        StringBuilder hex = new StringBuilder(ba.Length * 2);
        foreach (byte b in ba)
            hex.AppendFormat("{0:x2} ", b);
        return hex.ToString();
    }
}

And some extensions for sockets:

public static class SocketExtensions
{
    public static void SendLVReply(this Socket sct, byte[] dataIn)
    {
        byte[] data = null;
        ushort length = (ushort)dataIn.Length;
        data = new byte[length + 2];
        data[0] = (byte)(length & 0x00ff);
        data[1] = (byte)((length & 0xff00) >> 2);
        Array.Copy(dataIn, 0, data, 2, dataIn.Length);
        sct.Send(data);
    }

    public static byte[] ReadLVReply(this Socket sct)
    {
        byte[] lengthBytes = new byte[2];
        byte[] data = new byte[0];
        int expectedlength = 0;

        sct.Receive(lengthBytes);
        expectedlength = (ushort) (0x0000 | lengthBytes[0] | (lengthBytes[1] << 2));
        if(expectedlength > 0){
            data = new byte[expectedlength];
            sct.Receive(data);
        }
        return data;
    }
}

So what is the problem? The brick is successfully visible in Lego Mindstorms editor (or something, I don't know what it is) but when I click to connect to it, the error appears: enter image description here
I saw that I received something weird to my buffer after establishing a connection (it was weird because there is nothing in the document about the bytes). So I decided to take a real EV3 brick and check out what are they sending to each other. Using RawCap and opening the result through WireShark I saw that they are "messaging" a lot sending each other different things like the version of firmware on the brick, the name of the brick, the location of my project and so on. Here are the bytes:

after the brick sent "Accept:EV340\r\n\r\n". The PC sends to the brick this
14 00 01 00 00 18 00 8f 60 c0 0c 83 bb 69 17 65 60 d3 0d 14 64 0a
and the brick replies with this
1b 00 01 00 02 5a e5 c5 51 45 56 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
and so on

As I said before - there is nothing about it in the communication document.
And I want to say one more thing. If I use the C# library to control the real EV3 brick - there is none of this strange communication after establishing.
So now the question. Is there a way to control or ignore these messages from the Lego Mindstorms editor?

1 Answer 1

5

There are two types of commands. "System" commands and "Direct" command. The document that you linked lists all of the system commands but only gives examples of direct commands and does not exhaustively list all of the direct commands. Direct commands are any valid bytecodes to be interpreted directly by the VM running on the EV3, so to completely emulate the EV3, you will need to recreate the full lms2012 VM.

You can find more documentation on the bytecodes used in direct commands at http://ev3.fantastic.computer/doxygen/bytecodes.html (this is documentation from the official LEGO source code that has been built and published by a fan). Beware that the documentation isn't always 100% accurate - you should always check the source code to see how things are actually implemented as well.

There is a machine-readable file of all bytecodes in YAML format at https://github.com/ev3dev/lmsasm/blob/master/bytecodes/data/ev3.yml. This is useful if you want to automatically generate code instead of manually implementing all of the bytecodes.

1
  • Thank You so much for the reply. Honestly, I wasn't expecting that this is so difficult. I found the repo and as I undestand the lms2012 folder is only required for me. By now I only want to understand the way of replying the Lego Mindstorms Editor to its strange requests. My main idea is only to reverse engineer the c# library so I would accept only direct commands (like move "the" motor with "the" speed) Oct 2 at 6:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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