Moshiboard
Moshiboard
The Moshiboard laser cutter board is a proprietary controller with proprietary software. In the case of Moshiboard this software is called `MoshiDraw`. Like most proprietary laser cutting software intended for a specific board it has significant disadvantages and the only open source solutions are attempts at reverse engineering.
USB Protocol
The USB plug on the board is connected directly to the CH341A communications chip and configured in parallel port (EPP19) mode. This gives it the same Vendor id and product id as other things like the M2 Nano.
The usb device is located at vendor 0x1a86 with a PID of 0x5512
Swizzling
Like many different boards there is some light swizzling for some bytes in this case the command bytes are swizzled. Half of the command byte has random data (random distribution) and the other half is control code. This gives us 4 bits of command code, 4 random bytes. The swizzling can actually thus be interpreted in several ways, but we'll put the first four bits as command and the last 4 bits as random.
- 0A 0E 1A 1E 4A 4E 51 53 59 5A 5B 5E 71 74 79 7B
- 00 01 03 04 09 0C 10 14 21 23 29 2B 40 44 50 54
- 55 57 5D 5F 75 77 7D 7F 8A 8E 9A 9E CA CE DA DE
- 05 07 0D 0F 25 27 2D 2F 80 84 90 94 C0 C4 D0 D4
- AA AE BA BE D5 D7 DD DF EA EE F5 F7 FA FD FE FF
- 15 17 1D 1F 35 37 3D 3F 88 8C 98 9C C8 CC D8 DC
- 45 47 4D 4F 65 67 6D 6F 82 86 92 96 C2 C6 D2 D6
- A2 A6 B2 B6 C5 C7 CD CF E2 E5 E6 E7 ED EF F2 F6
These are the 8 different code seen, in their 16 different forms. If we apply a swizzle to these:
def swizzle(b, b0, b1, b2, b3, b4, b5, b6, b7): return ((b >> 0) & 1) << b7 | ((b >> 1) & 1) << b6 | \ ((b >> 2) & 1) << b5 | ((b >> 3) & 1) << b4 | \ ((b >> 4) & 1) << b3 | ((b >> 5) & 1) << b2 | \ ((b >> 6) & 1) << b1 | ((b >> 7) & 1) << b0
def convert(q): if q & 1: return swizzle(q, 7, 6, 2, 4, 3, 5, 1, 0) else: return swizzle(q, 5, 1, 7, 2, 4, 3, 6, 0)
- ['50', '51', '52', '53', '54', '55', '56', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '8e']
- ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0c', '0d', '0e', '0f', '18']
- ['70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f']
- ['20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f']
- ['f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff']
- ['30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f']
- ['60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f']
- ['e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef']
Inverted Swizzling
CMD | 0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B | 0x0C | 0x0D | 0x0E | 0x0F |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0? | 0x00 | 0x01 | 0x40 | 0x03 | 0x10 | 0x21 | 0x50 | 0x23 | 0x04 | 0x09 | 0x44 | 0x0b | 0x14 | 0x29 | 0x54 | 0x2b |
0x1? | 0x08 | 0x11 | 0x48 | 0x13 | 0x18 | 0x31 | 0x58 | 0x33 | 0x0c | 0x19 | 0x4c | 0x1b | 0x1c | 0x39 | 0x5c | 0x3b |
0x2? | 0x80 | 0x05 | 0xc0 | 0x07 | 0x90 | 0x25 | 0xd0 | 0x27 | 0x84 | 0x0d | 0xc4 | 0x0f | 0x94 | 0x2d | 0xd4 | 0x2f |
0x3? | 0x88 | 0x15 | 0xc8 | 0x17 | 0x98 | 0x35 | 0xd8 | 0x37 | 0x8c | 0x1d | 0xcc | 0x1f | 0x9c | 0x3d | 0xdc | 0x3f |
0x4? | 0x02 | 0x41 | 0x42 | 0x43 | 0x12 | 0x61 | 0x52 | 0x63 | 0x06 | 0x49 | 0x46 | 0x4b | 0x16 | 0x69 | 0x56 | 0x6b |
0x5? | 0x0a | 0x51 | 0x4a | 0x53 | 0x1a | 0x71 | 0x5a | 0x73 | 0x0e | 0x59 | 0x4e | 0x5b | 0x1e | 0x79 | 0x5e | 0x7b |
0x6? | 0x82 | 0x45 | 0xc2 | 0x47 | 0x92 | 0x65 | 0xd2 | 0x67 | 0x86 | 0x4d | 0xc6 | 0x4f | 0x96 | 0x6d | 0xd6 | 0x6f |
0x7? | 0x8a | 0x55 | 0xca | 0x57 | 0x9a | 0x75 | 0xda | 0x77 | 0x8e | 0x5d | 0xce | 0x5f | 0x9e | 0x7d | 0xde | 0x7f |
0x8? | 0x20 | 0x81 | 0x60 | 0x83 | 0x30 | 0xa1 | 0x70 | 0xa3 | 0x24 | 0x89 | 0x64 | 0x8b | 0x34 | 0xa9 | 0x74 | 0xab |
0x9? | 0x28 | 0x91 | 0x68 | 0x93 | 0x38 | 0xb1 | 0x78 | 0xb3 | 0x2c | 0x99 | 0x6c | 0x9b | 0x3c | 0xb9 | 0x7c | 0xbb |
0xA? | 0xa0 | 0x85 | 0xe0 | 0x87 | 0xb0 | 0xa5 | 0xf0 | 0xa7 | 0xa4 | 0x8d | 0xe4 | 0x8f | 0xb4 | 0xad | 0xf4 | 0xaf |
0xB? | 0xa8 | 0x95 | 0xe8 | 0x97 | 0xb8 | 0xb5 | 0xf8 | 0xb7 | 0xac | 0x9d | 0xec | 0x9f | 0xbc | 0xbd | 0xfc | 0xbf |
0xC? | 0x22 | 0xc1 | 0x62 | 0xc3 | 0x32 | 0xe1 | 0x72 | 0xe3 | 0x26 | 0xc9 | 0x66 | 0xcb | 0x36 | 0xe9 | 0x76 | 0xeb |
0xD? | 0x2a | 0xd1 | 0x6a | 0xd3 | 0x3a | 0xf1 | 0x7a | 0xf3 | 0x2e | 0xd9 | 0x6e | 0xdb | 0x3e | 0xf9 | 0x7e | 0xfb |
0xE? | 0xa2 | 0xc5 | 0xe2 | 0xc7 | 0xb2 | 0xe5 | 0xf2 | 0xe7 | 0xa6 | 0xcd | 0xe6 | 0xcf | 0xb6 | 0xed | 0xf6 | 0xef |
0xF? | 0xaa | 0xd5 | 0xea | 0xd7 | 0xba | 0xf5 | 0xfa | 0xf7 | 0xae | 0xdd | 0xee | 0xdf | 0xbe | 0xfd | 0xfe | 0xff |
Moshiboard Commands
Since command bytes have 4 bits there can only be 16 of them.
Command | Length | Code | Parameters |
---|---|---|---|
Cut_XY_ABS | 1 | 0xF? | (2 byte ABS X) (2 byte ABS Y) |
Cut_X_ABS | 1 | 0xE? | (2 byte ABS X) |
UNKNOWN | 1 | 0xD? | unknown |
UNKNOWN | 1 | 0xC? | unknown |
Cut_Y_ABS | 1 | 0xB? | (2 byte ABS Y) |
UNKNOWN | 1 | 0xA? | unknown |
UNKNOWN | 1 | 0x9? | unknown |
UNKNOWN | 1 | 0x8? | unknown |
Move_XY_ABS | 1 | 0x7? | (2 byte ABS X) (2 byte ABS Y) |
Move_X_ABS | 1 | 0x6? | (2 byte ABS X) |
Header Start | 1 | 0x5? | (2 bytes unknown) |
UNKNOWN | 1 | 0x4? | unknown |
Move_Y_ABS | 1 | 0x3? | (2 byte ABS Y) |
Terminal Commands | 1 | 0x2? | nothing. (occurs in 6 bytes increments) |
UNKNOWN | 1 | 0x1? | unknown |
2nd Command For Jump | 0 | 0x0? | (2 bytes) (2 bytes) (2 bytes) |
Bitwise this implies our flags for our 4 data bytes are: Laser, X-Value, Unknown, Y-Value
Reverse engineering resources.
- The MeerK40t project has done some initial work reverse engineering the Moshiboard. https://github.com/meerk40t/moshi
Links
Official
Other Sources
- MeerK40t moshi project MeerK40t Moshi Project
- MeerK40t moshi wiki MeerK40t Moshi Wiki