Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

TS-code is like G-code but it goes up your butt.

#include"tscode.h"tscode_command_response_tcmd_callback(tscode_command_t*cmd, char*response, size_tresp_len) {
switch (cmd->type) {
caseTSCODE_VIBRATE_ON:
hardware_set_vibration_level(cmd->speed);
break;
default:
returnTSCODE_RESPONSE_FAULT;
}
returnTSCODE_RESPONSE_OK;
}
voidapp_main(void) {
for (;;) {
tscode_process_stream(stdin, stdout, cmd_callback);
yield();
}
}

About TS-code

There are T-codes and S-codes. T-codes control movement-based toys, and S-codes are System codes that either control metadata or basic system-level stuff. The majority of these have direct equivalents to G-code counterparts. When determining the control set to present for a TS-code enabled device, you should inspect its capabilities, which will return the capstring. The capstring can be decoded to figure out how to present a UI. Given this, in theory a generic control UI can be presented which operates any TS-code enabled device.

TS-code is extensible, where appropriate new commands can be added in to support future toys while maintaining backwards compatibility with devices that don't care about those features. Additionally, several commands accept a "C" parameter for Channel. The default channel is 0, but commands can target additional channels as needed to control multiple instances of similar things, such as devices with multiple vibrators or linear actuators or lube pumps.

TS-code Format

S70 "Hang on, have fun!" ' this will make the device show a message
S03 BV255 ' this sets vibration to byte value 255 (100%, full ON)
T0F60 ' start reciprocating at 60 RPM, note the leading 0 in command is optional
T0 C1 R100 I1000 ' reciprocate, channel 1, 100 RPM ramp to over 1000 ms
T22 ' program coordinate in percent (for next example)
T1X1.0F0.5 ' linear move X to 1.0 (percent, so 100%) at a rate of 0.5 (percent) / second
S07P300 ' lube mist pump on for 300 ms

Spaces in the commands are optional for readability and discarded by the parser. Parameters start with a letter. To that end, if the parser encounters a S or T token, the previous command's parsing is considered complete and pushed into the operation buffer or holding buffer.

Each command is sent one line at a time, and consists of a series of Letter + Digit combinations to specify the command and its parameters. The TS-code driver has two buffers: The operation buffer, and the holding buffer. In order to synch- ronize movements with realtime data and avoid latency of transmitting and parsing those commands, the S-codes S97-S99 can be used to begin/end a buffer block, and then excute the buffer block. On devices which support multiple buffers, S97 - Start Buffer can accept a Lxxx label, which can be used by S99 - Execute Buffer. The default buffer is S97 L00 which will be executed by S99 L00 or S97/S99 without arguments. The device capstring will indicate how many program buffers it supports.

Conflicting commands for the same channel will overwrite the previous command in the buffer by default. It is therefore advised to issue S116 - Wait for Operation commands if you intended to execute a series of commands which were intended to run one after the other. If you do not desire realtime operation, you can issue S118 - Start Queued Programming to instruct the device to weit until an operation is complete before executing the next command. To return to Realtime mode, use S117 - Start Realtime Programming.

TS-code Commands

T-codes

CMDNameSymbolArguments
T00Reciprocating MoveRECIPROCATING_MOVEC?, V
T01Linear MoveLINEAR_MOVEC?, X, Y, Z, F?
T02Clockwise Circular MoveCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T03Counter-clockwise Circular MoveCCW_CIRCULAR_MOVEC?, I, J, K, R, X, Y, Z, F?
T04DwellDWELLC?, V
T05Rotational MoveROTATIONAL_MOVEC?, X, Y, Z, F?
...
T17Select X-Y PlaneSELECT_XY_PLANEC?
T18Select X-Z PlaneSELECT_XZ_PLANEC?
T19Select Y-Z PlaneSELECT_YZ_PLANEC?
T20Program Unit: InchesPROGRAM_UNIT_INCH
T21Program Unit: Metric (Millimeter)PROGRAM_UNIT_METRIC
T22Program Unit: PercentagePROGRAM_UNIT_PERCENTAGE
T23Program Unit: BytePROGRAM_UNIT_BYTE
...
T28Return to Home PositionRETURN_HOME
...
T90Absolute ProgrammingPROGRAM_POSITION_ABSOLUTE
T91Relative (Incremental) ProgrammingPROGRAM_POSITION_RELARIVE

S-codes

CMDNameSymbolArguments
S00Program Stop (Immediate)HALT_IMMEDIATE
S01Sleep or Conditional StopCONDITIONAL_STOP
S02End of ProgramEND_OF_PROGRAM
S03Vibration OnVIBRATE_ON
S04Vibration PatternVIBRATE_PATTERN
S05Vibration OffVIBRATE_OFF
S06Default Channel SelectDEFAULT_CHANNEL_SETV
S07Lube Mist Pump ONLUBE_MIST_ON
S08Lube Flood Pump ONLUBE_FLOOD_ON
S09Lube Pump OFFLUBE_OFF
S10Air Out valve OpenAIR_OUT_OPEN
S11Air In Valve OpenAIR_IN_OPEN
S12Air Valve CloseAIR_CLOSE
...
S70Display a MessageDISPLAY_MESSAGE
...
S72Play a TonePLAY_TONE
...
S96Empty Program BufferBUFFER_EMPTY
S97Start Buffer ProgrammingBUFFER_START
S98End Buffer ProgrammingBUFFER_END
S99Execute Program BufferBUFFER_EXECUTE
...
S104Enable HeaterENABLE_HEATER
S105Get Heater TemperatureGET_HEATER_TEMP
S106Fan OnFAN_ON
S107Fan OffFAN_OFF
S108Cancel HeatingCANCEL_HEATING
S109Set Heater and WaitENABLE_HEATER_AND_WAIT
...
S113Ping / PongPING
S114Report Current PositionsGET_CURRENT_POSITIONS
S115Report Firmware and CapstringGET_CAPSTRINGS
S116Wait for MovementWAIT_MOVEMENT
S117Start Realtime ProgrammingSTART_REALTIME_PROGRAMMING
S118Start Queued ProgrammingSTART_QUEUED_PROGRAMMING
...
S150Set LED ColorSET_LED_COLOR
...
S199Exit TS-code ModeEXIT_TSCODE_MODE

? denotes an optional argument.

Capstrings

Using S115 will report back a capabilities string and firmware version, or capstring. This capstring will contain a number of tokens indicating which features and channels the device supports, as well as its ranges and limits.

About

G-code-esque driver for sex toys. Put Marlin in your butt, what can go wrong?

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages