Diskussion:Nova 35

Aus FabLab Region Nürnberg

Hardware

RDC6442G 4-axis Lasercontrol
Breakout Board

Protokollanalyse

UDP

  • The device listens on a fixed UDP port (DEST_PORT). IPaddress is configurable 172.16.18.11, netmask is 255.255.255.0 fixed, Gateway is configurable 172.16.20.134.
  • An RD file is transfered as payload, same commands and syntax as with USB-Serial or USB-MassStorage.
  • The payload is split in chunks with a well known maximum size (MTU). (The last packet is usually shorter)
  • There is no header, and no arbitration phase, but successful transmission of the first chunk indicates device ready.
  • Each chunk starts with a two byte checksum, followed by payload data. Length of the payload is implicit by the UDP datagram size. (Would not work with TCP)
  • Each chunk is acknowledged with a single byte response packet:
    • 0xc6 if all is well, The next chunk should be sent. A delay of 4 seconds was tested successfully.
    • 0x46 if error. TODO: Checksum error and/or busy? A running laser job does not cause a busy condition.
  • The first chunk should be retried when 0x46 was received. For subsequent chunks transmission should be aborted.
  • No pause is needed after the last chunk. The payload contains a terminator token.

Command line tool usage:

   wget https://github.com/jnweiger/ruida-laser/blob/master/udpsendruida.py
   python3 udpsendruida.py 192.168.1.100 thunder.rd


earlier analysis

  1. Capture mit Wireshark
  2. Datei > Paketdissektion exportieren > Als JSON
    • Packet summary line
      • Include column headings
    • Packet details:
      • As displayed
    • Packet Bytes
  3. some more pat foo

rdcam.py

This python code snippet is probably useful with wireshark. Please add details.

def send_command(payload):
    data=scramble_bytes(payload)
    checksum=sum(data)
    b1=checksum&0xff
    b0=(checksum>>8)&0xff
    return bytes([b0,b1])+data

def encode_number(n,l=5):
    res=[]
    while n>0:
        res.append(n&0x7f)
        n>>=7
    while len(res)<l:
        res.append(0)
    res.reverse()
    return bytes(res)

def decode_number(x):
    fak=1
    res=0
    for b in reversed(x):
        res+=fak*b
        fak*=0x80
    return res

def format_capture(c):
    for p in c:
        direction=p["_source"]['layers']['udp']['udp.port']=='50200'
        data=unscramble_packet(p,checksum=direction)
        line='-> ' if direction else '<- '
        line+=' '.join([bytes(x).hex() for x in split_messages(data)])
        print(line)

def split_messages(d):
    m=[]
    res=[m]
    for x in d:
        if x&0x80:
            m=[]
            res.append(m)
        m.append(x)
    return res
    


def unscramble_packet(p,checksum=False):
    string=p["_source"]["layers"]["data"]["data.data_raw"]
    if checksum:
        return list(bytes.fromhex(string[:4]))+unscramble_string(string[4:])
    else:
        return unscramble_string(string)

def unscramble_string(s):
    return [unscramble(b) for b in bytes.fromhex(s)]

def unscramble(b):
    res_b=b-1
    if res_b<0: res_b+=0x100
    res_b^=0x88
    fb=res_b&0x80
    lb=res_b&1
    res_b=res_b-fb-lb
    res_b|=lb<<7
    res_b|=fb>>7
    return res_b

def scramble(b):
    fb=b&0x80
    lb=b&1
    res_b=b-fb-lb
    res_b|=lb<<7
    res_b|=fb>>7
    res_b^=0x88
    res_b+=1
    if res_b>0xff:res_b-=0x100
    return res_b

def scramble_bytes(bs):
    return bytes([scramble(b) for b in bs])
def unscramble_bytes(bs):
    return bytes([unscramble(b) for b in bs])

Data format

  • Byte = 1 Bit Message Start Indicator + 7 Bit Payload
  • Only one message (checksum + command) can be sent per UDP package
  • Max UDP package size 1472 bytes including checksum; fragmented by simple cutting (even inside a command)

Checksum

2 Bytes - sum of scrambled message bytes; MSB first.

Checksum has to be send before message.

Network only USB does not have checksum.

Values

Value Lenght Description
ABSCOORD 5 Bytes absolute position relative to job origin in µm
RELCOORD 2 Bytes relative position in µm; signed (2s complement)
SPEED 5 Bytes speed in µm/s
POWER 2 Bytes power in 0,006103516% (100/2^14)
CSTRING variable zero terminated

Commands

Byte squence Description how sure we are
C6 01 <POWER> 1st laser source min power 99%
C6 21 <POWER> 2nd laser source min power 99%
C6 02 <POWER> 1st laser source max power 99%
C6 22 <POWER> 2nd laser source max power 99%
C9 02 <SPEED> movement and/or (not sure) cutting speed 80%
D9 00 02 <ABSCOORD> move X 99%
D9 00 03 <ABSCOORD> move Y 50%
D9 00 04 <ABSCOORD> move Z 50%
D9 00 05 <ABSCOORD> move U 50%
CC ACK from machine 99%
CD ERR from machine 99%
DA 00 XX XX get XX XX from machine 99%
DA 00 04 05 saved job count 99%
DA 01 XX XX <VALUE> response to DA 00 XX XX 99%
A8 <ABSCOORD> <ABSCOORD> Straight cut to absolute X Y; turn laser on with configured speed and power 99%
A9 <RELCOORD> <RELCOORD> Straight cut to relative X Y; turn laser on with configured speed and power 99%
E7 50 <ABSCOORD> <ABSCOORD> Bounding box top left? 30%
E7 51 <ABSCOORD> <ABSCOORD> Bounding box bottom right? 30%
E8 02 E7 01 <CSTRING> Set filename for following transfer (transfer needs to be done really quickly after this!) 90%
E8 01 XX XX Read filename number XX XX
88 <ABSCOORD> <ABSCOORD> straight move to absolute X Y as fast as possible; with laser off 99%
89 <RELCOORD> <RELCOORD> straight move to relative X Y as fast as possible; with laser off 80%