Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
SEGA rhythm game slider protocol

SEGA touch slider (837-15275 and 837-15330) protocol

Most of the information are from this writeup.

Logic analyzer captures (sigrok format) (original ZeroPlus ALC format) [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.


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 of 0xff and 0xfd 0xfc in case of 0xfd). 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.


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.


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)

  1. Output: Reset() (ff 10 00 f1)

  2. Input: Reset() (ff 10 00 f1)

  3. Output: GetHWInfo() (ff f0 00 11)

  4. 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)

  5. Output: EnableSliderReport() (ff 03 00 fe)

  6. Input: SliderReport(values=(...)) (ff 01 20 <report> <sum>)

  7. Output: Packet(cmd=0x09, args=(0x0, 0x0, )) (ff 09 02 00 00 f6)

  8. Input: Packet(cmd=0x09, args=None) (ff 09 00 f8)

  9. Output: Packet(cmd=0x0a, args=(0x0, )) (ff 0a 01 00 f6)

  10. Input: Packet(cmd=0x0a, args=None) (ff 0a 00 f7)

  11. 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.

Copy link

somewhatlurker commented Dec 25, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.