Moshiboard: Difference between revisions
(Created page with "= Moshiboard = The Moshiboard laser cutter board is a proprietary controller with proprietary software. In the case of Moshiboard this software is called `MoshiDraw`. Like mo...") |
No edit summary |
||
(2 intermediate revisions by the same user not shown) | |||
Line 5: | Line 5: | ||
== USB Protocol == | == USB Protocol == | ||
The usb device is located at vendor | 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 == | == 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 | 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. | ||
The algorithm from unswizzled to swizzled form is: | |||
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 swizzle( | 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) | |||
Note that each lowest bit triggers a different type of swizzle. So every other bit is swizzled in a different form. The last bit remains in the same position in both so these different swizzles perfectly intermingle. | |||
=== Swizzle LUT === | |||
= | {| class="wikitable" | ||
|- | |||
! 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 | |||
|- | |||
|} | |||
All commands will be referenced by the first 4 bits. The remaining 4 bits fit a random distribution. | |||
== Moshiboard Commands == | == Moshiboard Commands == | ||
Line 72: | Line 81: | ||
! Command !! Length !! Code !! Parameters | ! Command !! Length !! Code !! Parameters | ||
|- | |- | ||
| | | 2nd CMD For Jump || 0 || 0x0? || (2 bytes) (2 bytes) (2 bytes) | ||
|- | |||
| UNKNOWN || 1 || 0x1? || unknown | |||
|- | |- | ||
| | | Terminal Commands || 1 || 0x2? || nothing. (occurs in 6 bytes increments) | ||
|- | |- | ||
| | | Move_Y_ABS || 1 || 0x3? || (2 byte ABS Y) | ||
|- | |- | ||
| UNKNOWN || 1 || | | UNKNOWN || 1 || 0x4? || unknown | ||
|- | |- | ||
| | | Header Start || 1 || 0x5? || (2 bytes unknown) | ||
|- | |- | ||
| | | Move_X_ABS || 1 || 0x6? || (2 byte ABS X) | ||
|- | |- | ||
| | | Move_XY_ABS || 1 || 0x7? || (2 byte ABS X) (2 byte ABS Y) | ||
|- | |- | ||
| UNKNOWN || 1 || 0x8? || unknown | | UNKNOWN || 1 || 0x8? || unknown | ||
|- | |- | ||
| | | UNKNOWN || 1 || 0x9? || unknown | ||
|- | |- | ||
| | | UNKNOWN || 1 || 0xA? || unknown | ||
|- | |- | ||
| | | Cut_Y_ABS || 1 || 0xB? || (2 byte ABS Y) | ||
|- | |- | ||
| UNKNOWN || 1 || | | UNKNOWN || 1 || 0xC? || unknown | ||
|- | |- | ||
| | | UNKNOWN || 1 || 0xD? || unknown | ||
|- | |- | ||
| | | Cut_X_ABS || 1 || 0xE? || (2 byte ABS X) | ||
|- | |- | ||
| | | Cut_XY_ABS || 1 || 0xF? || (2 byte ABS X) (2 byte ABS Y) | ||
|- | |- | ||
|} | |} | ||
Bitwise this implies our flags for our 4 data bytes are: Laser, X-Value, Unknown, Y-Value | Bitwise this implies our flags for our 4 data bytes are: Laser, X-Value, Unknown, Y-Value | ||
Line 111: | Line 119: | ||
== Reverse engineering resources. == | == Reverse engineering resources. == | ||
* The MeerK40t project has done some initial work reverse engineering the Moshiboard. https://github.com/ | * The MeerK40t project has done some initial work reverse engineering the Moshiboard. https://github.com/meerk40t/moshi | ||
= Links = | = Links = |
Latest revision as of 06:35, 4 August 2020
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.
The algorithm from unswizzled to swizzled form is:
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)
Note that each lowest bit triggers a different type of swizzle. So every other bit is swizzled in a different form. The last bit remains in the same position in both so these different swizzles perfectly intermingle.
Swizzle LUT
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 |
All commands will be referenced by the first 4 bits. The remaining 4 bits fit a random distribution.
Moshiboard Commands
Since command bytes have 4 bits there can only be 16 of them.
Command | Length | Code | Parameters |
---|---|---|---|
2nd CMD For Jump | 0 | 0x0? | (2 bytes) (2 bytes) (2 bytes) |
UNKNOWN | 1 | 0x1? | unknown |
Terminal Commands | 1 | 0x2? | nothing. (occurs in 6 bytes increments) |
Move_Y_ABS | 1 | 0x3? | (2 byte ABS Y) |
UNKNOWN | 1 | 0x4? | unknown |
Header Start | 1 | 0x5? | (2 bytes unknown) |
Move_X_ABS | 1 | 0x6? | (2 byte ABS X) |
Move_XY_ABS | 1 | 0x7? | (2 byte ABS X) (2 byte ABS Y) |
UNKNOWN | 1 | 0x8? | unknown |
UNKNOWN | 1 | 0x9? | unknown |
UNKNOWN | 1 | 0xA? | unknown |
Cut_Y_ABS | 1 | 0xB? | (2 byte ABS Y) |
UNKNOWN | 1 | 0xC? | unknown |
UNKNOWN | 1 | 0xD? | unknown |
Cut_X_ABS | 1 | 0xE? | (2 byte ABS X) |
Cut_XY_ABS | 1 | 0xF? | (2 byte ABS X) (2 byte ABS Y) |
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