SEGA touch slider (837-15275 and 837-15330) protocol
Most of the information are from this writeup.
Logic analyzer captures
slider_cap.zip (sigrok format)
slider_cap.zip (original ZeroPlus ALC format)
init.sr [bootup(power-on).alc]
: Captured during initialization
{blue,green,red}.sr [led({blue,green,red}).alc]
: Captured after setting SERVICE MENU/OUTPUT TEST/TOUCH SLIDER LED {BLUE,GREEN,RED}
options to on.
Protocol
TX/RX follows standard Nu convention (RS232, 115200 8n1).
The packet is encoded in a JVS-esque coding scheme (with 0xff being the sync byte (SYNC) and the 0xfd being the escape byte (ESC)).
Each packet starts with a SYNC (0xff) byte and the decoded packet structure looks like:
Offset | Size | Field Name | Notes |
---|---|---|---|
0 | 1 | cmd |
Command/report type |
1 | 1 | argc |
Length of arguments/report body (should be n) |
2 | n | args /argv |
Arguments/report body |
n+2 | 1 | checksum |
Checksum |
- Arguments/report body can be empty (i.e. zero length).
- Length field represents the data length AFTER decoding or BEFORE encoding.
- The checksum is calculated by adding all NEGATED bytes between SYNC and the end of arguments/report body (both inclusive) and taking the lower 8 bits, or
checksum = (sum(packet_without_checksum) - 0xff) & 0xff
- To verify the checksum, simply add all bytes between SYNC and checksum (both inclusive) and check if the result is 0.
- In case of having SYNC/ESC in the packet, the byte is escaped by writing
ESC byte-1
(0xfd 0xfe
in case of0xff
and0xfd 0xfc
in case of0xfd
). To unescape, simply discard the ESC byte and add 1 to the escaped byte.
List of known commands/report types
Definition of directions:
- Output: Host to device
- Input: Device to host
See below for detailed formats of each command/report.
ID | Direction | Human Readable Form |
---|---|---|
0x01 | Input | SliderReport(values) |
0x02 | Output | LEDReport(brightness, led_brg) |
0x03 | Output | EnableSliderReport() |
0x04 | Output | DisableSliderReport() |
0x04 | Input | DisableSliderReport() |
0x09 | Output | Packet(cmd=0x09, args=(unk_0x0, unk_0x1)) |
0x09 | Input | Packet(cmd=0x09, args=None) |
0x0a | Output | Packet(cmd=0x0a, args=(unk_0x0, )) |
0x0a | Input | Packet(cmd=0x0a, args=None) |
0x10 | Input, Output | Reset() |
0xee | Input, Output | Exception(code0, code1) |
0xf0 | Output | GetHWInfo() |
0xf0 | Input | GetHWInfo(model, device_class, chip_pn, unk_0xe, fw_ver, unk_0x10, unk_0x11) |
Protocol description
All the offsets below will be offsets in decoded report body unless otherwise noted.
0x01 - SliderReport
Output: SliderReport()
Requests a single shot slider report (probably).
Input: SliderReport(values=(...))
Slider report.
For 15275, bytes are mapped according to the physical construction of the slider (left bytes on the left side, etc.). Also the values showed on the SERVICE MENU/INPUT TEST
starts from left side as well (0-31 being left to right).
0 1 ... 31
For 15330, the slider has an odd-even layout, with the electrode 0 located at the top right corner.
30 ... 2 0
31 ... 3 1
Report interval is about 12ms (83.3 FPS).
0x02 - LEDReport
Output: LEDReport(brightness, led_brg=((b, r, g), ...))
Set the LED overall brightness and color.
Offset | Size | Field Name | Notes |
---|---|---|---|
0x0 | 1 | brightness |
Slider brightness. (Probably between 0-63 as THL3504's global brightness control value is within this range.) |
0x1 + 3*led_index | 1 | led_brg[led_index][0] |
LED brightness (blue) |
0x2 + 3*led_index | 1 | led_brg[led_index][1] |
LED brightness (red) |
0x3 + 3*led_index | 1 | led_brg[led_index][2] |
LED brightness (green) |
(For reducing protocol overhead it may be desirable to avoid using SYNC and ESC as LED values.)
NOTE: For 15330, there are only 31 LEDs (16 for keys and 15 for key separators) and the index starts from the right hand side.
0x03 - EnableSliderReport
Output: EnableSliderReport()
Enables the slider report.
0x04 - DisableSliderReport
Output: DisableSliderReport()
Disable periodical input report from slider. Seen on 15330 and unconfirmed on 15275.
Input: DisableSliderReport()
Response. Seen on 15330 and unconfirmed on 15275.
0x09
Output: Packet(cmd=0x09, args=(0x0, 0x0, ))
(ff 09 02 00 00 f6
)
A request with unknown purpose. Seems to be only available on 15275.
Input: Packet(cmd=0x09, args=None)
(ff 09 00 f8
)
Response to the request, purpose unknown.
0x0a
Output: Packet(cmd=0x0a, args=(0x0, ))
(ff 0a 01 00 f6
)
A request with unknown purpose. Seems to be only available on 15275.
Input: Packet(cmd=0x0a, args=None)
(ff 0a 00 f7
)
Response to the request, purpose unknown.
0x10 - Reset
Output: Reset()
A reset request to the slider.
Input: Reset()
Sent by the slider as a response to the reset request.
NOTE: Sometimes (probably during initialization) the slider might not be responsive or return Exception(0xff, WRONG_CHECKSUM)
(ff ee 02 fd fe 01 11
). In this case simply retry after about every 100ms.
0xee - Exception
Input/Output: Exception(code0, code1)
Raise an exception.
Offset | Size | Field Name | Notes |
---|---|---|---|
0x0 | 1 | code0 | Seems to be always 0xff (?) |
0x1 | 1 | code1 | See below |
Possible code1 are listed below (extracted from code fragments in ongeki).
Value | Description |
---|---|
0x1 | Wrong checksum |
0x2 | Bus error |
0xed | Internal error |
0xf0 - GetHWInfo
Output: GetHWInfo()
Request for hardware information.
Input: GetHWInfo(model, device_class, chip_pn, unk_0xe, fw_ver, unk_0x10, unk_0x11)
Hardware information as seen in SERVICE MENU/GAME SYSTEM INFORMATION
.
Offset | Size | Field Name | Notes |
---|---|---|---|
0x0 | 8 | model |
8-bytes model number (after 837- ) (showed in the BD NUMBER field) |
0x8 | 1 | device_class |
Probably a magic number that identifies the device class. |
0x9 | 5 | chip_pn |
5-bytes chip part number |
0xe | 1 | unk_0xe |
Unknown |
0xf | 1 | fw_ver |
Firmware version (144) |
0x10 | 1 | unk_0x10 |
Unknown |
0x11 | 1 | unk_0x11 |
Unknown |
Below shows the difference in the GetHWInfo
response among different models of the slider.
Board type | Device Class | Model | Chip Part Number |
---|---|---|---|
Diva (837-15275) | 0xa0 |
b'15275 ' |
b'06687' |
Chunithm (CHU-2000) (837-15330) | 0xa0 (enforced) |
b'15330 ' |
b'06712' |
Initialization sequence (diva)
-
Output:
Reset()
(ff 10 00 f1
) -
Input:
Reset()
(ff 10 00 f1
) -
Output:
GetHWInfo()
(ff f0 00 11
) -
Input:
GetHWInfo(model=b'15275 ', device_class=0xa0, chip_pn=b'06687', unk_0xe=0xff, fw_ver=0x90, unk_0x10=0x00, unk_0x11=0x64)
(ff f0 12 31 35 32 37 35 20 20 20 a0 30 36 36 38 37 fd fe 90 00 64 fd fc
) -
Output:
EnableSliderReport()
(ff 03 00 fe
) -
Input:
SliderReport(values=(...))
(ff 01 20 <report> <sum>
) -
Output:
Packet(cmd=0x09, args=(0x0, 0x0, ))
(ff 09 02 00 00 f6
) -
Input:
Packet(cmd=0x09, args=None)
(ff 09 00 f8
) -
Output:
Packet(cmd=0x0a, args=(0x0, ))
(ff 0a 01 00 f6
) -
Input:
Packet(cmd=0x0a, args=None)
(ff 0a 00 f7
) -
Output:
SetLEDReport(brightness=0x3f, led_brg=((b, r, g), ...))
(ff 02 61 <brightness=0x3f> <led_brg> <sum>
)
After 11 the LED reports and the slider reports are periodically transmitted by host and the slider respectively.
Other commands and mysteries
(Glitched?) Commands
Output: Packet(cmd=0x0d, args=(brightness, led_brg=((b, r, g), ...)))
From alternate source. Also seem to work fine.
(0xd is 0x2 with all bits inverted. Coincidence?)
Input: Packet(cmd=0x0b, args=(values=(...)))
Looks a lot like SliderReport
but with all values being 0xfc or 0xfe. Some sort of threshold or just plainly glitched output?
DIP switch
Seems like there is a 4-bit DIP switch on the slider according to the manual. What is it used for?
(Unlike TN32MSEC0003S, 837-15275 is not individually addressable so it is likely not an address selector.)
(According to a recent update of original writeup, position 3 (SCL) and 4 (SDA) connects the two PSoC together via I2C. Setting both switches to OFF will isolate the I2C communication so both devices can be programmed separately via the ISSP header i.e. CN3 and 4. Position 1 and 2 are for controlling the I2C line pullups. So In order to use the programming mode all the switches must be set to OFF position, and for normal operations all the switch must be set to ON position)
Ping or reset?
The Ping()
command (0xf0
) took way too long than necessary (~8ms). Is it actually a reset command?
Both Chunithm and Ongeki labels 0xf0
as reset.
This comment has been minimized.
Command 0x0b probably isn't glitched, but I'm not sure what it is. I think there should be something similar at 0x06. It's like they're some kind of alternate scan (possibly triggered by sending 0x0c or 0x07), but I'd be cautious about sending stuff that might be for calibration to a device with no documentation.