Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DA 00 XX XX - get XX XX from machine #2

Open
ghost opened this issue Aug 1, 2019 · 61 comments
Open

DA 00 XX XX - get XX XX from machine #2

ghost opened this issue Aug 1, 2019 · 61 comments

Comments

@ghost
Copy link

ghost commented Aug 1, 2019

I dream make my own hardware compatible with RDWorks. Reading RD-file from SD-card is not a problem. But communication with RDWorks software is a problem. I noticed that I should response in the following way DA 01 XX XX <VALUE>. For example, when I press any button in RDWorks it's first send DA 00 05 7E. But I don't found information about this commands, anyone has decoded this?

@tatarize
Copy link

tatarize commented May 9, 2020

It's mentioned in Roger Clark's work:
http://www.rogerclark.net/network-aware-laser-cutter-security/

e.g. This seems to be the initial packet that is always sent by RDWorks
02:61:d4:89:0d:f7
to which the RDC6442G responds with
c6
and then sends a reply packet e.g.
d4:09:0d:f7:8f:a1:09:c3:89

Which suggests the right response is:
swizzled is: b'\xd4\x09\x0d\xf7\x8f\xa1\x09\xc3\x89'
And unswizzled:
b'\xDA\x01' + bytearray(array[2:4]) + b'\x06\x28\x01\x4a\x00'

The issue I'm having is that this it's not enough to trick RDWorks.

I added a basic RuidaServer to MeerK40t ( meerk40t/meerk40t@f98bd1a ). The idea being I can tell MeerK40t to open that port, pretend to be a RuidaServer then control my M2 Nano with RDWorks for whatever reason you'd have for doing that. But, RDWorks says that that answer is wrong, quickly shutting down with "connection error". @jnweiger can you post a full exchange of the the devices babbling through a ruidaproxy? At least enough to figure out this handshake.

@tatarize
Copy link

Figured it out. The required reply is certainly 0x65006500 for 0x05 0x7E. Most of the rest of the values you can just return 0.

@tatarize
Copy link

634XG uses 0x11 xor as the swizzle. But all of them fail at:
--> da000004
<-- da0100040000000000

Responding that 00 04 is equal to zero causes the program to terminate the connection. Goes through with 644XG, where it accepts 0 for that value. I have meerk40ts new version fully pretending to be a ruida device.

@tatarize
Copy link

@ghost I've decoded all the commands. Literally 100% of them. That command actually is Get Parameter "Card ID". Also decoded all the parameters, some of them I can't even get RDWorks to bother asking for. Most of them even weird ones just dutifully get put into the boxes. I told it my machine main board version was "MEERK40T" and it thought that was fine.

I can't, however, know what a good response to Get Machine Status should be for the other controllers and I don't know any other Card IDs that do not raise any objections.

https://edutechwiki.unige.ch/en/Ruida

@cortesegravacoes
Copy link

Hello, how are you? I have a laser RUIDA ... Can you help me to "decode" the RUIDA ACS android app? Thank you. Bruno Santos. Portugal.

@tatarize
Copy link

The link I gave there gives all the commands. The app there is just controlling the laser through the UDP packets. It's just doing what any program controlling the Ruida would do. MeerK40t now allows for a ruida server, which will decode all the commands. If you really wanted to see exactly the commands the app is using. Download a copy of the app, and MeerK40t. Tell the app your Ruida laser is located at the computer running the MeerK40t ruidaserver and it'll tell you exactly the commands it's using. D9 00 and D9 01 are the main commands for moving the x and y. But, it'll let you see all the various other commands its using, since MeerK40t interprets all that stuff.

Then you'd make a similar app that just sends the same commands over UDP to the Ruida device. Basically writing your own Ruida controller software. Which isn't too hard to do. But, mostly you could interpret the app info with MeerK40t. ( https://github.com/meerk40t/meerk40t )

@cortesegravacoes
Copy link

Thanks for your reply, I am very grateful! But I take the opportunity to expose some doubts ... I am trying to communicate with RUIDA and ARDUINO , sending udp packages to RUIDA. The wireshark software says it does not recognize the IP RUIDA being broadcast. Can you explain why? Will I have to send a hexadecimal to get communication? I can't find my RUIDA's IP and Mac address anywhere on my LAN ... I wonder why? Thank you.

@cortesegravacoes
Copy link

Ohh!!! Camera?? Real time streaming?
How does it work?

@tatarize
Copy link

Basically in MeerK40t hit alt+F12 it'll start up the ruidaserver. Then you say whatever computer running it is a ruida device. It'll take any UDP data sent and parse out the hex into the data commands.

@tatarize
Copy link

It's built to control an Lhystudios M2 Nano controller. But, one of the things to do is to interpret other boards so I could use RDWorks or Lightburn to control the M2 device. So it does all the parsing for the Ruida device to make that easier.

@cortesegravacoes
Copy link

Basicamente, no MeerK40t, pressione alt + F12 e iniciará o ruidaserver. Então você diz que qualquer computador que esteja executando é um dispositivo ruida. Ele pega todos os dados UDP enviados e analisa o hexadecimal nos comandos de dados.

Sorry, I don't understand, or I didn't make myself understood. Can you tell how to communicate with RUIDA through ARDUINO? Directly from the arduino, not going through your RUIDA Server ... I loved your idea. Thanks, but as I've been doing this for 3 days, I didn't want to drop it, I would like to finally finish the communication, to really see how it is. How does RUIDA accept UDP? Because wireshark does not recognize the RUIDA IP ... Thank you.

@tatarize
Copy link

With an arduino you'd have to connect through the COM port it has. Which would also work. Ruida devices have a internet connection and process UDP. You would wireshark when you connect to the Ruida device with RDWorks or Lightburn. If not over the net, the other connection method is COM port.

https://stefan.schuermans.info/rdcam/pc_conn.html

Unlike the UDP since I can fake it and do the research I don't have much info on how you'd do arduino com port connection stuff.

@cortesegravacoes
Copy link

The interest would be to connect the arduino via Ethernet ... But for example, what is the 1 command sent to "activate" the RUIDA, that is, if you move the axes manually, in addition to the hex of the axes, first you have to go a hex to "activate" RUIDA, what is the hex that tells RUIDA that someone (arduino, PC, rpi) wants to connect to RUIDA?

@tatarize
Copy link

There's not actually much to activation. You can see the handshaking when connecting RDWorks to a the fake server. Mostly you don't need most of that handshake stuff. You can generally just tell it to move. Here's a typical jog command:

--> da00057e	(Get 05 7e (Card ID))
<-- b'\xda\x01\x05~\x06(\x01J\x00'     (Respond 05 7e (Card ID) = 1694524672 (0x65006500))
<-- cc     (checksum match)
--> da00057e	(Get 05 7e (Card ID))
<-- b'\xda\x01\x05~\x06(\x01J\x00'     (Respond 05 7e (Card ID) = 1694524672 (0x65006500))
<-- cc     (checksum match)
--> da000004	(Get 00 04 (IOEnable))
<-- b'\xda\x01\x00\x04\x00\x00\x00\x00\x00'     (Respond 00 04 (IOEnable) = 0 (0x00000000))
<-- cc     (checksum match)
--> da00057e	(Get 05 7e (Card ID))
<-- b'\xda\x01\x05~\x06(\x01J\x00'     (Respond 05 7e (Card ID) = 1694524672 (0x65006500))
<-- cc     (checksum match)
--> da000400	(Get 04 00 (Machine Status))
<-- b'\xda\x01\x04\x00\x00\x00\x00\x00\x16'     (Respond 04 00 (Machine Status) = 22 (0x00000016))
<-- cc     (checksum match)
--> da000026	(Get 00 26 (Axis Range 1, Get Frame X))
<-- b'\xda\x01\x00&\x00\x00\x13D\x00'     (Respond 00 26 (Axis Range 1, Get Frame X) = 320000 (0x0004e200))
<-- cc     (checksum match)
--> da000036	(Get 00 36 (Axis Range 2, Get Frame Y))
<-- b'\xda\x01\x006\x00\x00\r6`'     (Respond 00 36 (Axis Range 2, Get Frame Y) = 220000 (0x00035b60))
<-- cc     (checksum match)
--> da000021	(Get 00 21 (Axis Precision 1))
<-- b'\xda\x01\x00!\x00\x00\x00\x00\x00'     (Respond 00 21 (Axis Precision 1) = 0 (0x00000000))
<-- cc     (checksum match)
--> da000031	(Get 00 31 (Axis Precision 2))
<-- b'\xda\x01\x001\x00\x00\x00\x00\x00'     (Respond 00 31 (Axis Precision 2) = 0 (0x00000000))
<-- cc     (checksum match)
--> da00057e	(Get 05 7e (Card ID))
<-- b'\xda\x01\x05~\x06(\x01J\x00'     (Respond 05 7e (Card ID) = 1694524672 (0x65006500))
<-- cc     (checksum match)
--> da00057e	(Get 05 7e (Card ID))
<-- b'\xda\x01\x05~\x06(\x01J\x00'     (Respond 05 7e (Card ID) = 1694524672 (0x65006500))
<-- cc     (checksum match)
--> da000004	(Get 00 04 (IOEnable))
<-- b'\xda\x01\x00\x04\x00\x00\x00\x00\x00'     (Respond 00 04 (IOEnable) = 0 (0x00000000))
<-- cc     (checksum match)
--> da000020	(Get 00 20 (Axis Control Para 1))
<-- b'\xda\x01\x00 \x00\x00\x01\x00\x00'     (Respond 00 20 (Axis Control Para 1) = 16384 (0x00004000))
<-- cc     (checksum match)
--> c9020000030650	(Speed Laser 1 50.000000mm/s)
<-- cc     (checksum match)
--> c6017f7f	(Power 1 min=99.993896)
<-- cc     (checksum match)
--> c6217f7f	(Power 2 min=99.993896)
<-- cc     (checksum match)
--> c6027f7f	(Power 1 max=99.993896)
<-- cc     (checksum match)
--> c6227f7f	(Power 2 max=99.993896)
<-- cc     (checksum match)
--> d900007f7f7f3170	(Move Origin X: -10000.000000 (-20000.000000,0.000000))

Most of the rest of that stuff can be dropped. Maybe not the laser speed but the laser power stuff. That's just syncing it with RDWorks.

@cortesegravacoes
Copy link

What is "card ID" ? First connection to RUIDA?
Enable connection to RUIDA?
Does the raspberry pi 3 + handle 2 servers working? This and the other in java? How to find out the IP address and Mac address of RUIDA on the lan?

@tatarize
Copy link

CardID is something or other. If RDWorks doesn't get 0x65006500 back which is the same as it writes 6500 it will disconnect and refuse to continue. It's actually what this thread originally was asking. What is the proper response to that query. It's called CardID and the correct response is 6500 with that you can also return zero for most of the rest of the stuff and it doesn't worry too much about it. Ghost's original question was the reply to DA 00 05 7E which is really DA 01 65 00 65 00. I'm not actually sure what it means other than the listing as CardID.

@tatarize
Copy link

I think Ruida device itself gives you the IP address, somewhere. (I do not own a ruida device). You couldn't run MeerK40t's mock server and this one on the same IP because, by necessity, they use the same UDP port.

@cortesegravacoes
Copy link

But think with me ... RUIDA receives 057e asks for communication, then RUIDA responds 0400 to say it is waiting for something? It is? As for the raspberry pi, I have a Java server running on it 24 hours a day, I was thinking of adding your server more, the IP of the RPI being different from RUIDA, of course.! I don't know if the 2 will work at the same time ...
Obs... After hex, i used scramble and uncramble in ARDUINO code...

@cortesegravacoes
Copy link

Hello, I already installed your software on Windows, very good ... Congratulations ... Opening the server, you really see the commands, :), but in reality I can't get the machine to work with your software as shown on YouTube ... Like the Android app, you cannot connect to the virtual RUIDA IP. I wonder why? Thank you

@tatarize
Copy link

I wonder that too. I got a copy of the software for Android and I ran it and it didn't seem to even try to connect. It has my correct IP address and everything. There may be something different in the protocol like it's connecting to a different port somehow or doing something else, I might have to eavesdrop on the connection to figure out what's going on there. It should have been really easy, but somehow it's not connecting correctly. RDWorks works fine. The android app doesn't seem to do that.

@tatarize
Copy link

I ran wireshark on the PC connection for data from the tablet to catch the incoming packets and the only thing from the right location was:

615 26.034262 192.168.1.118 192.168.1.167 UDP 60 40207 → 50207 Len=1 0xC

In console.py the line 1653:
port = 50200

So I changed that to:

port = 50207

And... it crashed. Since it's sending 0xCC which is an ACK packet it, but over UDP packets always tended to require checksums.

Also, 0xCC is ACK in the clear, without any swizzling. I replied 0xCC to it, and it said "Success!". So that's apparently the login sequence there. But, the protocol for the UDP here is a bit different than elsewhere.

@tatarize
Copy link

The app has some specialty commands that are not actually seen elsewhere, and a different protocol on UDP 50207.

  • +X key down
    • \xa5P\x02
  • +X key up
    • \xa5Q\x02
  • -X key down
    • \xa5P\x01
  • -X key up
    • \xa5Q\x01
  • +Y key down
    • \xa5P\x03
  • +Y key up
    • \xa5Q\x03
  • -Y key down
    • \xa5P\x04
  • -Y key up
    • \xa5Q\x04
  • +Z key down
    • \xa5P\n
  • +Z key up
    • \xa5P\n
  • -Z key down
    • \xa5P\x0b
  • -Z key up
    • \xa5Q\x0b
  • +U key down
    • \xa5P\x0c
  • +U key up
    • \xa5Q\x0c
  • -U key down
    • \xa5P\r
  • -U key up
    • \xa5P\r
  • Speed
    • \xa5P\x11
  • Start/Pause
    • \xa5P\x06
  • Stop
    • \xa5P\t
  • Reset
    • \xa5PZ
  • Trace On/Off
    • \xa5P\x0f
  • ESC
    • \xa5P\x07
  • Laser Gate
    • \xa5P\x12
  • Pulse key down
    • \xa5P\x05
  • Pulse key down
    • \xa5Q\x05
  • Origin
    • \xa5P\x08
  • Frame
    • \xa5S\x00

Also, the Tablet sends \xce on regular intervals. I'm guessing it's a keep alive.

@tatarize
Copy link

The 0xA5 command sends doesn't have a known meaning since it's wasn't registered in the code for the PC version rdworks.

The commands are typically P (0x50), except for some commands which have a key-up command too which is Q (0x51). Except for "Frame" which is 0xA5 S (0x53) It then has a command index.

So if you sent your Ruida over UDP on port 50207 0xA5 0x50 0x01 then 0xA5 0x51 0x01 it would start moving +X then stop. 0x02 is -X. 0x03 is +Y, 0x04 is -Y. Etc.

There is also a blank spot for current location of the laser in the app since I never sent back the right data. To get that correct it might require actually snooping on traffic between the tablet and the the controller.

@tatarize
Copy link

Alright. Reverse Engineered most of that. Get a copy of the program circa 0.6.2 and the ruida server will also have a Ruida Jog Server which takes in those jog commands that the app sends out on port 50207. There's still an option on the Android device screen that says location and without capturing the app talking with the laser control, I'm not sure how that gets the information.

https://github.com/meerk40t/meerk40t/tree/0.6.2 (Added the jog server in just that branch).

--> a55006	(Interface Start/Pause)
<-- cc	(ACK)
--> a55009	(Interface Stop)
<-- cc	(ACK)
--> a5505a	(Interface Reset)
<-- cc	(ACK)
--> a5500f	(Interface Trace On/Off)
<-- cc	(ACK)
--> a55007	(Interface ESC)
<-- cc	(ACK)
--> a55012	(Interface Laser Gate)
<-- cc	(ACK)
--> a55005	(Interface Pulse Down)
<-- cc	(ACK)
--> a55105	(Interface Pulse Up)
<-- cc	(ACK)
--> a55008	(Interface Origin)
<-- cc	(ACK)
--> a55300	(Interface Frame)
<-- cc	(ACK)
--> a5500c	(Interface +U Down)
<-- cc	(ACK)
--> a5510c	(Interface +U Up)
<-- cc	(ACK)
--> a55003	(Interface +Y Down)
<-- cc	(ACK)
--> a55103	(Interface +Y Up)
<-- cc	(ACK)
--> a5500a	(Interface +Z Down)
<-- cc	(ACK)
--> a5510a	(Interface +Z Up)
<-- cc	(ACK)
--> a55001	(Interface -X Down)
<-- cc	(ACK)
--> a55101	(Interface -X Up)
<-- cc	(ACK)
--> a55011	(Interface Speed)
<-- cc	(ACK)
--> a55002	(Interface +X Down)
<-- cc	(ACK)
--> a55102	(Interface +X Up)
<-- cc	(ACK)
--> a5500d	(Interface -U Down)
<-- cc	(ACK)
--> a5510d	(Interface -U Up)
<-- cc	(ACK)
--> a55004	(Interface -Y Down)
<-- cc	(ACK)
--> a55104	(Interface -Y Up)
<-- cc	(ACK)
--> a5500b	(Interface -Z Down)
<-- cc	(ACK)
--> a5510b	(Interface -Z Up)
<-- cc	(ACK)

So that's enough to replicate the Android App for whatever you are planning to do with that info.

@cortesegravacoes
Copy link

Ohhh thank you for all work.

@cortesegravacoes
Copy link

Amazing

@cortesegravacoes
Copy link

Where are you from? :)

@tatarize
Copy link

California, US.

NP on the work, I reverse engineer a lot of stuff so it's a bit easy at this point.

@cortesegravacoes
Copy link

Corri o wireshark na conexão do PC para obter dados do tablet para capturar os pacotes recebidos e a única coisa no local certo era:

615 26.034262 192.168.1.118 192.168.1.167 UDP 60 40207 → 50207 Len = 1 0xC

No console.py da linha 1653:
port = 50200

Então eu mudei isso para:

port = 50207

E ... caiu. Como está enviando 0xCC, que é um pacote ACK, mas os pacotes UDP sempre tendem a exigir somas de verificação.

Além disso, 0xCC é ACK claro, sem qualquer swizzling. Eu respondi 0xCC e disse "Sucesso!". Então essa é aparentemente a sequência de login lá. Mas, o protocolo para o UDP aqui é um pouco diferente do que em outros lugares.

I understood that I don't need to swizzle on the Arduino and that the commands to be sent to RUIDA are without swizzling, do you agree?

O aplicativo possui alguns comandos especiais que na verdade não são vistos em outros lugares e um protocolo diferente no UDP 50207.

  • Tecla + X pressionada

    • \ xa5P \ x02
  • Tecla + X acima

    • \ xa5Q \ x02
  • Tecla -X pressionada

    • \ xa5P \ x01
  • Tecla -X

    • \ xa5Q \ x01
  • Tecla + Y pressionada

    • \ xa5P \ x03
  • Tecla + Y para cima

    • \ xa5Q \ x03
  • -Y tecla pressionada

    • \ xa5P \ x04
  • Tecla -Y

    • \ xa5Q \ x04
  • Tecla Z + pressionada

    • \ xa5P \ n
    • Tecla Z para cima
    • \ xa5P \ n
  • -Z tecla pressionada

    • \ xa5P \ x0b
  • Tecla -Z

    • \ xa5Q \ x0b
    • Tecla U pressionada
    • \ xa5P \ x0c
    • Tecla U para cima
    • \ xa5Q \ x0c
  • -U tecla para baixo

    • \ xa5P \ r
  • Tecla -U

    • \ xa5P \ r
  • Rapidez

    • \ xa5P \ x11
  • Iniciar / Pausar

    • \ xa5P \ x06
  • Pare

    • \ xa5P \ t
  • Redefinir

    • \ xa5PZ
  • Rastreamento ativado / desativado

    • \ xa5P \ x0f
  • ESC

    • \ xa5P \ x07
  • Laser Gate

    • \ xa5P \ x12
  • Tecla de pulso pressionada

    • \ xa5P \ x05
  • Tecla de pulso pressionada

    • \ xa5Q \ x05
  • Origem

    • \ xa5P \ x08
  • Quadro, Armação

    • \ xa5S \ x00

Além disso, o Tablet envia \xceregularmente. Eu estou supondo que é manter vivo.

Different UDP protocol?
As well?

@tatarize
Copy link

Yeah, the UDP is in the clear without checksum and without swizzle. It's also on port 50207 and replies are made to the sending port on port 40207.

If you make an app that sends a UDP from port 40207 to 50207 on the Ruida device and send one of those preset packets, it should duplicate the app functionality.

@tatarize
Copy link

Due to a leftover bug in MeerK40t I updated the version and this weird parsing protocol got added. So the regular 0.6.2 MeerK40t release with Alt + F12, will launch the ruida emulation server and parse the data from the android app.

@cortesegravacoes
Copy link

The adroid app works 5 stars, you see all the commands. 😉 But the physical RUIDA was not supposed to respond to MeerK40t also? Mine does not answer, it is, the USB is connected and says in operation ...

@tatarize
Copy link

I don't have a physical Ruida device. But, you want to emulate what the app is sending to the MeerK40t program. So you would do the same thing as the android app. Send a packet 0xCC to udp:50207 at the given IP address. Then send commands like 0xa55002 then 0xa55102, to the Ruida device. It won't know it's not the normal android app, so it should work perfectly fine just sending those commands. MeerK40t is just talking between the android app and the PC. So I can reverse engineer the protocol. I could likely write up a quick example app in python or something to control the ruida just like the app. It's understood well enough. MeerK40t doesn't talk to Ruida since I don't have one, and can't really troubleshoot it.

@cortesegravacoes
Copy link

Hi how are you?
Another question, how to access the RUIDA coordinates for the Android app?
Thank you!

@tatarize
Copy link

I don't know. At least not for the udp:50207 interface. It's pretty commonly done with the regular 50207 interface. The position is a just information request. However, for the other interface, this information is sent from the Ruida device to the App. I don't have a ruida device and thus I can't snoop on that part of the connection. If you're writing an app to do that, also make sure you log anything sent from the device to the app and look for coordinates. They are often 27 bit numbers in nanometers, but my guess is the ruida device replies the location to the 0xCE keepalive packet.

Without a ruida device I don't know what the command would be.

@cortesegravacoes
Copy link

Hello ... I'm here with a problem ... Something's not right! Maybe it's my mistake, but I don't see why, but maybe because of my misinterpretation of what he told me ... I'm trying to send commands from arduino to RUIDA physical and virtual ... It turns out that on ARDUINO's serial monitor when sending any command to RUIDA, I have the answer F, on the server I get an ACK message ... But on both sides it says that the sending of the arduino packages is 0 ... So I don't know what's going on ... Even sending 0xcc or whatever ... I'm sorry about all these questions, but I'm starting my adventure in the world of programming. 🙂

@cortesegravacoes
Copy link

cortesegravacoes commented Jul 21, 2020

I believe that me, not following the correct steps ... Will it be so? Arduino sends 0xcc RUIDA answers 0xcc ... And then? For example move X axis? Byte .... [] = {0xCC, 0xa5, 0x50, 0x02}? Or do I have to delete the first byte? And SWIZZLING? It is necessary? I am confused as to the correct sequence of commands. Can you help me please? It would be super easy for you! Thank you. [email protected]

@cortesegravacoes
Copy link

15953573798982335110805097593854

@tatarize
Copy link

Arduino sends 0xcc RUIDA answers 0xcc ... And then?

And then answers the rest of the commands with other commands.

For example move X axis? Byte .... [] = {0xCC, 0xa5, 0x50, 0x02}? Or do I have to delete the first byte?

You have to delete the first byte. The commands are alway above 0x80. That's how the Ruida command structure works.

And SWIZZLING? It is necessary?

It is typically done for the 50200 UDP channel, it is never done for your 50207 channel. Which does entirely different protocols.

I am confused as to the correct sequence of commands.

There will actually not be much of a sequence. UDP packets can arrive in basically any order so you can't really be quite sure of getting or not getting one. The only thing it should matter for is the 0xA5 0x50 0x02 arriving before the 0xA5 0x51 0x02 which would turn it off.

You only need to send a set of identical UDP packets. 0xCC gets a 0xCC reply so you know it's there. The physical ruida device likely has a reply somewhere that gives the current position. That has not been mapped out yet.

You send exactly the packet 0xA5 0x50 0x02 then 0xA5 0x51 0x02 and make it stop.

(image)

The image for some reason is being sent the value 0, which MeerK40t rightly says is not a command. All commands start above 0x80. And all the other values are always below that value. It's not sending a valid UDP packet from the arduino. But, when you do, MeerK40t will tell you what command you sent.

@cortesegravacoes
Copy link

https://edutechwiki.unige.ch/en/Ruida
Like this? In my case it would be 2.2 6442-s ...
Screenshot_20200716_233156

@cortesegravacoes
Copy link

cortesegravacoes commented Jul 22, 2020

Magic - 0x88

@tatarize
Copy link

If you're only using the udp port 50207 stuff there is no swizzling. The bytes are transmitted without any encoding changes. The 50207 stuff. Yes, that would use the swizzling on that page. That reminds me I should update that page with the 50207 protocol information.

@cortesegravacoes
Copy link

Yes I understood... But in this case, as I said before, the interest would be to send through port 50200 directly in the physical RUIDA ...

@tatarize
Copy link

Oh, yeah, in that case you'll need swizzling. The code from that site is great. I wrote it, in fact, it does the xor swap for the swizzle. But, yeah, for something more advanced than the connecting on 50207 and controlling it like that app, you'd need swizzling, and also the ability to write some of the common data structures. 14 bit numbers, 35 bit numbers, and the like. The formatting is such that because all commands are above 0x80. No data byte can use the highest bit, they all must be zero. And all the commands are listed in the MeerK40t source as well as on that webpage where I wrote some good documentation.

@cortesegravacoes
Copy link

received_1164331060589190
IMG_20200723_232336
Hi, I'm trying to send a sequence of bytes 0x5a, 0x51, 0x02 ... With Swizzling 0x2E, 0x59, 0x8B for port 50200. Making the checksum, the first 2 bytes, seen in the wireshark are 0, as they should be 0x01, 0x12 ... So RUIDA laser does not react ... Are you aware of this? Thank you...

@tatarize
Copy link

You mean 0xA5 not 0x5A. The distinction there is that the 0xA5 is higher than 0x80 and therefore a command.

The correct answer is [46, 89, 139] == 2E 59 8B, which is what you got there swizzled.

The other issue is that using the swizzled channels, I don't know if that's an actual command. The only place I saw A5 was on 50207. I do not know it is a command at 50200. You can load up a copy of RDWorks and send the output to MeerK40t and look at the commands it uses to move the laser around. It's actually completely different than the commands used from the android app.

You're trying to send the app data to the udp:50200 channel, but I've never seen that command set used. And when I decoded all the commands known to exist they weren't there. You'd really want to load up RDWorks and see what jogging to the right requires for that.

For that in RDWorks, through the swizzled channel I get:

--> da00057e	(Get 05 7e (Card ID))
<-- b'\xda\x01\x05~\x06(\x01J\x00'     (Respond 05 7e (Card ID) = 1694524672 (0x65006500))
<-- cc     (checksum match)
--> da000004	(Get 00 04 (IOEnable))
<-- b'\xda\x01\x00\x04\x00\x00\x00\x00\x00'     (Respond 00 04 (IOEnable) = 0 (0x00000000))
<-- cc     (checksum match)
--> da000020	(Get 00 20 (Axis Control Para 1))
<-- b'\xda\x01\x00 \x00\x00\x01\x00\x00'     (Respond 00 20 (Axis Control Para 1) = 16384 (0x00004000))
<-- cc     (checksum match)
--> c9020000030650	(Speed Laser 1 50.000000mm/s)
<-- cc     (checksum match)
--> c6017f7f	(Power 1 min=99.993896)
<-- cc     (checksum match)
--> c6217f7f	(Power 2 min=99.993896)
<-- cc     (checksum match)
--> c6027f7f	(Power 1 max=99.993896)
<-- cc     (checksum match)
--> c6227f7f	(Power 2 max=99.993896)
<-- cc     (checksum match)
--> d900007f7f7f3170	(Move Origin X: -10000.000000 (-10000.000000,0.000000))

You sent the command correctly with swizzling. So it didn't respond. Try that given set of command where you do IOEnable, and tell it to move X by 10mm. Also, keep in mind the UDP:50200 command to do that is: d900007f7f7f3170. But, it may take the IOEnable command and some others. I'm not sure the other commands are required. But, that's how RDWorks moves the laser around. So I'd emulate that rather than the app. For the app, I'd send that without swizzling on on the app's UDP:50207 channel.

@tatarize
Copy link

tatarize commented Jul 24, 2020

Also the wireshark data says 00002e598b and should have a checksum of 274 rather than 0. And should read 01122e598b. Dunno I'd fix the flawed checksum before giving up on the idea of the use of the 0xA5 command.

@cortesegravacoes
Copy link

Where will my mistake be?

@cortesegravacoes
Copy link

https://edutechwiki.unige.ch/en/Ruida
This command?

@cortesegravacoes
Copy link

From point 4.3.

@tatarize
Copy link

Get the checksum working correctly. You need to correctly give the checksum of the commands you are issuing. The 0xA5 commands might work through the UDP:50200 protocol, but you'd certainly need a correct checksum or it will just be discarded.

But, with a working sending data protocol. You should be able to duplicate some RDWorks commands and get some working control of the laser. From there you can add some commands and see what correctly works and what doesn't.

@cortesegravacoes
Copy link

So as I understand it, the Android app commands for physical RUIDA are "filtered / translated" with a different checksum? Even decompiling the Android app, is it not possible to access this checksun? So, the app has to know how to make this Cheksum so that the physical RUIDA realizes the correct checksum? Did I realize? Thank you.

@tatarize
Copy link

The app itself doesn't use a checksum or a swizzle. It transmits the commands without alteration, in plain text. You literally send 0xA5 0x50 0x01 as the whole and complete command. Just those 3 bytes on UDP:50207 and it does the operation. If you wanted to to transmit that using the communications protocol used on UDP:50200, you would need to apply the swizzling algorithm, and the append the checksum to the front of the operation.

The app would not need to make a checksum, and would not need to do a swizzle of the bytes. Since the App itself uses a different protocol on UDP:50207 which needs neither a checksum nor a swizzle algorithm.

@tatarize
Copy link

@cortesegravacoes Here. I figured it would be easier to see it in code. Here's code that you can run in python (requires pynput, pip install pynput) but will ask you for the ip address of your ruida device (this can either be the actual Ruida device, or MeerK40t pretending to be one). After giving the address for the ruida device you can use the WASD keys to control the device.

#!/usr/bin/env python

import socket
import sys
import threading
from pynput import keyboard


UDP_IP = "127.0.0.1"
UPD_SEND_PORT = 50207
UPD_RECV_PORT = 40207

print("Ruida IP:")
for line in sys.stdin:
    UDP_IP = line.rstrip()
    break


class UDPSock(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind((UDP_IP, UPD_RECV_PORT))
        self.start()

    def run(self):
        while True:
            data, addr = self.sock.recvfrom(1024)
            print("Received message: %s" % data)

    def upd_send(self,message):
        self.sock.sendto(message, (UDP_IP, UPD_SEND_PORT))


class KeyPresses:
    def __init__(self, sock):
        self.sock = sock
        self.down = False
        with keyboard.Listener(
                on_press=self.on_press,
                on_release=self.on_release) as listener:
            listener.join()

    def on_press(self, keypress):
        if self.down:
            return
        self.down = True
        print("Down: %s" % keypress)
        try:
            key = keypress.char
        except AttributeError:
            return
        if key == 'e':
            self.sock.upd_send(b'\xCE')  # KeepAlive
        elif key == 'a':
            self.sock.upd_send(b'\xA5\x50\x01')  # -X
        elif key == 'd':
            self.sock.upd_send(b'\xA5\x50\x02')  # +X
        elif key == 's':
            self.sock.upd_send(b'\xA5\x50\x04')  # -Y
        elif key == 'w':
            self.sock.upd_send(b'\xA5\x50\x03')  # +Y

    def on_release(self, keypress):
        if not self.down:
            return
        self.down = False
        print("Up: %s" % keypress)
        try:
            key = keypress.char
        except AttributeError:
            return
        if key == 'a':
            self.sock.upd_send(b'\xA5\x51\x01')  # -X
        elif key == 'd':
            self.sock.upd_send(b'\xA5\x51\x02')  # +X
        elif key == 's':
            self.sock.upd_send(b'\xA5\x51\x04')  # -Y
        elif key == 'w':
            self.sock.upd_send(b'\xA5\x51\x03')  # +Y


KeyPresses(UDPSock())

You should be able to tell from this, that it's just emulating the App. It has no checksum or swizzling done on the input. It's only sending a couple static packets to control the device.

I also added a key 'e' to send the 0xCE command. If the actual physical device returns something other than 0xCC like the position of the device's laser head, please tell me what it say. It will print out any responses from the device.

@cortesegravacoes
Copy link

Hello, thanks! I made a code in C ++ on the Arduino ide ... I happen to be trying to send the bytes 0xda, 0x50, 0x05, 0x7e(first command of comunitation) .... Doing the checksum first and then Swizzling, sending to the 50200 virtual RUIDA port I get f6 saying no is command, but the virtual RUIDA sends c6 ... Wireshark gives a 5 byte udp packet to 0 ... I don't know where I'm failing. Because I read this link that I sent earlier in another message, that the checksum would be done first and then Swizzling. Right?

@cortesegravacoes
Copy link

received_702891380268416
This image represents a simple click on the rd works joystick to move X simply 10 mm ... These are all commands. Reading that RUIDA doesn't need a handshake, I don't understand what the card ID is ...

@tatarize
Copy link

The checksum is on the swizzled data. To reverse it you do swizzle and then calculate the checksum. The Ruida device is going to check the if the sum is correct before changing the bytes. There's no reason to process the data if the sum is wrong.

@tatarize
Copy link

In python the check is calculated:

        data = sent_data[2:1472]
        checksum_check = (sent_data[0] & 0xFF) << 8 | sent_data[1] & 0xFF
        checksum_sum = sum(data) & 0xFFFF

The first 2 bytes are cut off the front of the packet, This is combined together to give me a 16 bit number. And the checksum sum is the sum of the swizzled bytes. So if you're on the other side of this and you're making the packet. You need to take the data you are sending to the ruida device, you need to swizzle all the bytes. Then you need to calculate the checksum and append it to the front of the data. And that's your packet.

My code for MeerK40t is acting like the Ruida device. If you want to make code that controls the Ruida device you do the commands in reverse order. This means swizzle, sum, then appending the sum to the front of the packet as a header.

@tatarize
Copy link

I think Card ID is like serial number or something. I solved all the commands and properties, but I don't actually know what they all mean. I do know that if RDWorks isn't told that that CardID value is 0x6500 (0x65006500 14 bit data is always repeated twice) it says there's a communication problem and dies. It's actually what ghost's original question was asking in the first post of this thread.

@wallahi06
Copy link

Hi how are you? Another question, how to access the RUIDA coordinates for the Android app? Thank you!

Hi! I know its a bit late but the coordinates are sent regulary so just listen for all UDP-packets beside teh ACK response and there you have your coordinates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants