Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
681 lines (528 sloc) 32.9 KB

ET-312 Programs and Modules

Introduction

This document contains notes about how programs and modules work. You need to be familiar with the memory layout and refer to ET312 Protocol Documentation.

Terminology

  • A Program is either a firmware or user uploaded program. Examples of Programs are “Waves”, “Phase 2”, “User 1”.
  • Each Program is made up of a number of Modules.
  • Each Module contains a variable number of Instructions.
  • The Instruction set is very limited, mostly just allowing certain memory operations.

Loading a Program (firmware Programs)

  • As a user you select a Program by name using the up/down buttons on the box
  • “calltable 18” is called with the Program number
  • The firmware will set up some defaults into the memory locations 0x80+ (channel A) and 0x180+ (channel B) that are the same for every Program
  • Module 1 is loaded for both channel A and channel B
  • The firmware has bit long a code switch statement for the Program to which Module or Modules get loaded
  • “calltable 22” is called for each Module
  • The Instructions from that Module are unpacked (yes, they are packed in a strange way) and parsed, one by one
  • “calltable 30” is called for each Instruction
  • Each Instruction will read or write or manipulate memory (specifically the 0x80+ and 0x180+ locations)
  • There is a bit of added complexity due to the ability to “Split” some Programs: an Instruction may relate to a channel A memory location but be modified to relate to a channel B memory location
  • There is a bit of additional hardcoding going on in the firmware to handle the “Random 1” mode and audio modes
  • Some other bits of code check the Program number or other flags and do hardcoded tweaks

The Modules do not stay running continuously, they are only used to do a setup of memory locations. Changes that then happen (like intensity changes, frequency changes) all take place based on the counters and timers and other memory settings.

Modules can however set up triggers that can cause Modules to get run at some later point, so for example a Module could set up one of the timers to run, and when the timer reaches some value it causes a different Module to then get loaded. The “Rhythm” mode for example cycles between three different Modules in this way.

The utility “module-decode.py” in this repo can be used to display the Instructions for a given Module, both the internal firmware ones, or the User ones by examining the memory of a connected box. Example decodes at Module 11:

$ python3 module-decode.py -i ../firmware/312-16-decrypted.bin -d ../../buttshock-protocol-docs/doc/et312-protocol.org -m 11 

Split Programs

Some Programs have the ability to be “Split”, where a different Program runs on channel A to channel B. This causes the Program loading code to be a little more complex for both cases.

Defaults and Module 1

Each time a new Program is started the default values get loaded, for both channel A and B these set:

  • Ramp: runs at rate 7 with step 1 using the 244Hz timer from 0x9c to 0xff, stopping at the end. This causes the Program to ramp up to full power over 3 seconds ( (0xff-0x9c) * 244/7 )
  • Intensity: static with value 0xff. If changed to use a timer, the defaults set the step to 1, rate to 1, and range 0xcd to 0xff, reversing at the maximum and minimum.
  • Frequency: changes with the value of the MA knob. If changed to use a timer, the default set the step to 1, rate to 1, and range 0x09 to 0x64 starting from 0x16, reversing at the maximum and minimum.
  • Width: static with value of the advanced paramer default. If changed to use a timer, the default set the step to 1, rate to 1, and range 0x32 to 0xc8 starting from 0x82, reversing at the maximum and minimum.

Module 1 is then always loaded for both channel A and B which just turns on the output gates:

memory[0090 *Channel A: Current Gate Value* (0x06)]=07
memory[0190 *Channel B: Current Gate Value* (0x06)]=07

See also: Main variables

Program “Waves” is Modules 11, 12

If you select Program “Waves” then the firmware loads Module 11:

memory[0086 *Multi Adjust Range Min* (0x0f)]=01
memory[0087 *Multi Adjust Range Max* (0xff)]=40
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=41
memory[00bb *Channel A: Current Width Modulation Increment* (0x01)]=02
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=41
memory[00b0 *Channel A: Current Frequency Modulation Max* (0x64)]=80
  • Sets the MA knob range from 0x01 to 0x40
  • A Intensity: static with value 0xff
  • A Frequency: changes in steps of 1, rate from MA knob (0x01-0x40), in the range 0x09 to 0x80, using the 244Hz timer, reversing at maximum and maximum.
  • A Width: changes in steps of 2, rate from MA knob (0x01-0x40), in the range 0x32 to 0xc8, using the 244Hz timer, reversing at minimum and maximum.

If the user is not using the Split mode, the firmware will then also load Module 11 for channel B, then Module 12 which together form these Instructions:

memory[01be *Channel B: Current Width Modulation Select* (0x04)]=41
memory[01bb *Channel B: Current Width Modulation Increment* (0x01)]=03
memory[01b5 *Channel B: Current Frequency Modulation Select* (0x08)]=41
memory[01b0 *Channel B: Current Frequency Modulation Max* (0x64)]=40
  • B Intensity: static with value 0xff
  • B Frequency: changes in steps of 1, rate from MA knob (0x01-0x40), in the range 0x09 to 0x40, using the 244Hz timer, reversing at maximum and maximum.
  • B Width: changes in steps of 3, rate from MA knob (0x01-0x40), in the range 0x32 to 0xc8, using the 244Hz timer, reversing at minimum and maximum.

Program “Stroke” is Modules 3, 4

If you select Program “Stroke” then the firmware loads Module 3:

memory[0086 *Multi Adjust Range Min* (0x0f)]=00
memory[0087 *Multi Adjust Range Max* (0xff)]=20
memory[00a9 *Channel A: Current Intensity Modulation Step* (0x01)]=02
memory[00aa *Channel A: Current Intensity Action at Min* (0xff)]=fe
memory[00ab *Channel A: Current Intensity Action at Max* (0xff)]=fe
memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=55
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=00
memory[00b7 *Channel A: Current Width Modulation Value* (0x82)]=ff
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=00
memory[0090 *Channel A: Current Gate Value* (0x06)]=05
  • Sets the MA knob range from 0x00 to 0x20
  • A Intensity: changes in steps of 2 over the range of minimum to 0xff, using the 244Hz timer. Rate is from the MA knob (0x00 to 0x20). Minimum is set to inverse of the advanced parameter default for Intensity. When reaching the maximum or minimum the output gate toggles and reverses direction.
  • A Frequency: static with value 0x16
  • A Width: static with value 0xff

If the user is not using the Split mode, the firmware will then also load Module 3 for channel B, then Module 4 which together form these Instructions:

memory[01a6 *Channel B: Current Intensity Modulation Min* (0xcd)]=e6
memory[01a9 *Channel B: Current Intensity Modulation Step* (0x01)]=01
memory[01aa *Channel B: Current Intensity Action at Min* (0xff)]=fe
memory[01ab *Channel B: Current Intensity Action at Max* (0xff)]=fe
memory[01ac *Channel B: Current Intensity Modulation Select* (0x00)]=41
memory[01b5 *Channel B: Current Frequency Modulation Select* (0x08)]=00
memory[01b7 *Channel B: Current Width Modulation Value* (0x82)]=d8
memory[01be *Channel B: Current Width Modulation Select* (0x04)]=00
memory[0190 *Channel B: Current Gate Value* (0x06)]=05

This sets up:

  • B Intensity: changes in steps of 1 over the range of 0xe6 to 0xff, using the 244Hz timer. Rate is from the MA knob. When reaching the maximum or minimum the output toggles and reverses direction.
  • B Frequency: static with value 0x16
  • B Width: static with value 0xd8

Program “Climb” is Modules 5-10

If you select Program “Climb” then the firmware loads Module 5:

memory[0086 *Multi Adjust Range Min* (0x0f)]=01
memory[0087 *Multi Adjust Range Max* (0xff)]=64
memory[00ae *Channel A: Current Frequency Modulation Value* (0x16)]=ff
memory[00b0 *Channel A: Current Frequency Modulation Max* (0x64)]=ff
memory[00b2 *Channel A: Current Frequency Modulation Step* (0x01)]=01
memory[00b3 *Channel A: Current Frequency Modulation Action Min* (0xff)]=06
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=41
  • Sets the MA range from 0x01-0x64
  • A Intensity: static with value 0xff.
  • A Width: set to the advanced paramer default.
  • A Frequency: changes in steps of 1, using the 244Hz timer, rate from the MA knob, starting at 0xff down to 0x09. When reaching the minimum will trigger Module 6

Module 6:

memory[00b2 *Channel A: Current Frequency Modulation Step* (0x01)]=02
memory[00ae *Channel A: Current Frequency Modulation Value* (0x16)]=ff
memory[00b3 *Channel A: Current Frequency Modulation Action Min* (0xff)]=07
  • Changes the Frequency step to 2, using the 244Hz timer, rate from the MA knob, starting at 0xff down to 0x09. When reaching the minimum triggers Module 7

Module 7:

memory[00b2 *Channel A: Current Frequency Modulation Step* (0x01)]=04
memory[00ae *Channel A: Current Frequency Modulation Value* (0x16)]=ff
memory[00b3 *Channel A: Current Frequency Modulation Action Min* (0xff)]=05
  • Changes the Frequency step to 4, using the 244Hz timer, starting at 0xff down to 0x09. When reaching the minimum triggers Module 5

If the user is not using the Split mode, the firmware will then also load Module 5 for channel B, then Module 8 which together form these Instructions:

memory[01ae *Channel B: Current Frequency Modulation Value* (0x16)]=ff
memory[01b0 *Channel B: Current Frequency Modulation Max* (0x64)]=ff
memory[01b2 *Channel B: Current Frequency Modulation Step* (0x01)]=01
memory[01b3 *Channel B: Current Frequency Modulation Action Min* (0xff)]=09
memory[01b5 *Channel B: Current Frequency Modulation Select* (0x08)]=41
  • B Intensity: static with value 0xff.
  • B Width: set to the advanced paramer default.
  • B Frequency: changes in steps of 1, using the 244Hz timer, rate from the MA knob, starting at 0xff down to 0x09. When reaching the minimum will trigger Module 9

Module 9:

memory[0085 when module loading determines which channels to set (0x03)]=02
memory[01b2 *Channel B: Current Frequency Modulation Step* (0x01)]=02
memory[01ae *Channel B: Current Frequency Modulation Value* (0x16)]=ff
memory[01b3 *Channel B: Current Frequency Modulation Action Min* (0xff)]=0a
  • B Frequency: changes in steps of 2, using the 244Hz timer, rate from the MA knob, starting at 0xff down to 0x09. When reaching the minimum will trigger Module 10

Module 10:

memory[0085 when module loading determines which channels to set (0x03)]=02
memory[01b2 *Channel B: Current Frequency Modulation Step* (0x01)]=05
memory[01ae *Channel B: Current Frequency Modulation Value* (0x16)]=ff
memory[01b3 *Channel B: Current Frequency Modulation Action Min* (0xff)]=08
  • B Frequency: changes in steps of 5, using the 244Hz timer, rate from MA knob, starting at 0xff down to 0x09. When reaching the minimum will trigger Module 8

Program “Combo” is Modules 13, 33

If you select Program “Combo” then the firmware loads Module 13:

memory[0086 *Multi Adjust Range Min* (0x0f)]=00
memory[0087 *Multi Adjust Range Max* (0xff)]=40
memory[009a *Channel A: Current Gate Select* (0x00)]=4a
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=02
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=26
  • Sets MA knob from 0x00 to 0x40
  • A Intensity: static with value 0xff.
  • A Frequency: Uses the 30.5Hz timer, step of 1, rate of 1, and range 0x09 to 0x64 starting from 0x16, reversing at the maximum and minimum.
  • A Width: Uses the 30.5Hz timer, step of 1, rate is advanced parameter default, and range min from advanced parameter default to 0xc8 starting from 0x82, reversing at the maximum and minimum.
  • A Gate: turns on and off using the 30.5Hz timer following the value of the MA knob (so up to 2 seconds on/2 seconds off)

If the user is not using the Split mode, the firmware will then also load Module 13 for channel B, then Module 33 which together form these Instructions:

memory[019a *Channel B: Current Gate Select* (0x00)]=4a
memory[01b2 *Channel B: Current Frequency Modulation Step* (0x01)]=02
memory[01b5 *Channel B: Current Frequency Modulation Select* (0x08)]=02
memory[01bb *Channel B: Current Width Modulation Step* (0x01)]=02
memory[01be *Channel B: Current Width Modulation Select* (0x04)]=26
  • B Intensity: static with value 0xff.
  • B Frequency: Uses the 30.5Hz timer, step of 2, rate of 1, and range 0x09 to 0x64 starting from 0x16, reversing at the maximum and minimum.
  • B Width: Uses the 30.5Hz timer, step of 2, rate is advanced parameter default, and range min from advanced parameter default to 0xc8 starting from 0x82, reversing at the maximum and minimum.
  • B Gate: turns on and off using the 30.5Hz timer following the value of the MA knob (so up to 2 seconds on/2 seconds off)

Program “Intense” is Modules 14, 2

If you select Program “Intense” then the firmware loads Module 14:

memory[0086 *Multi Adjust Range Min* (0x0f)]=09
  • MA knob between 0x0f and 0x09
  • A Intensity: static with value 0xff.
  • A Frequency: follows the value of the MA knob (0x0f to 0x09)
  • A Width: set to the advanced parameter default.

If the user is not using the Split mode, the firmware will then also load Module 14 for channel B, then Module 2 which together form these Instructions:

memory[0198 *Channel B: Current Gate OnTime* (0x3e)]=3f
memory[0199 *Channel B: Current Gate OffTime* (0x3e)]=3f
memory[019a *Channel B: Current Gate Select* (0x00)]=01
  • B Intensity: static with value 0xff.
  • B Frequency: follows the value of the MA knob (0x0f to 0x09)
  • B Width: set to the advanced parameter default.
  • B output will turn on and off using the 244Hz timer, on for 0x3f and off for 0x3f cycles (giving 2Hz)

Program “Rhythm” is Modules 15, 16, 17

If you select Program “Rhythm” then the firmware loads Module 15:

memory[0086 *Multi Adjust Range Min* (0x0f)]=01
memory[0087 *Multi Adjust Range Max* (0xff)]=17
memory[0095 *Next module timer max* (0xff)]=1f
memory[0095 *Next module timer max* (0xff)]=1f
memory[0096 *Next module flag* (0x00)]=02
memory[0097 *Next module number* (0x00)]=10
memory[009a *Channel A: Current Gate Select* (0x00)]=49
memory[00a5 *Channel A: Current Intensity Modulation Value* (0xff)]=e0
memory[00a6 *Channel A: Current Intensity Modulation Min* (0xcd)]=e0
memory[00a9 *Channel A: Current Intensity Modulation Step* (0x01)]=00
memory[00ab *Channel A: Current Intensity Action at Max* (0xff)]=fd
memory[00ab *Channel A: Current Intensity Action at Max* (0xff)]=fd
memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=01
memory[00b7 *Channel A: Current Width Modulation Value* (0x82)]=46
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=00
  • Set MA range from 0x01-0x17
  • Sets a timer using the 30.5Hz clock. Once it counts up to 0x1f (which will take 1 second) then Module 16 will be loaded
  • Intensity: Using the 244Hz timer, sets step to 0x00, rate to 0x01, starting at 0xe0 counting to 0xff then jumps back to 0xe0 again. Using a step of 0x00 however so the intensity will only change when another Module changes it.
  • Frequency: follows the value of the MA knob (0x01-0x17)
  • Width: static at 0x46

Module 15 triggers Module 16:

memory[0097 *Next module number* (0x00)]=11
memory[00a5 *Channel A: Current Intensity Modulation Value* (0xff)]^01
memory[00a5 *Channel A: Current Intensity Modulation Value* (0xff)]+=01
memory[00b7 *Channel A: Current Width Modulation Value* (0x82)]=b4
  • Timer restarts. Once it counts up to 0x1f (which will take 1 second) then Module 17 will be loaded
  • Width: changes to be static at 0xb4
  • Intensity: increases the current static value ( 0xe0 becomes 0xe2, 0xe2 becomes 0xe4 etc)

Module 16 triggers Module 17:

memory[0097 *Next module number* (0x00)]=10
memory[00b7 *Channel A: Current Width Modulation Value* (0x82)]=46
  • Timer restarts. Once it counts up to 0x1f (which will take 1 second ) then Module 16 will be loaded
  • Width: changes to be static at 0x46

Program “Audio 1” is Module 23

If you select Program “Audio 1” then the firmware loads Module 23. It also sets up a flag for other code that we’re in a mono audio mode (bit 6 of x83), and has hardcoded settings for the gate outputs (memory 0x90 and 0x190 set to 0x47, i.e. bit 6 is set).

Module 23 contains these Instructions:

memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=04
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=00
  • Intensity: static with value 0xff
  • Frequency: set to the value of the advanced parameter default
  • Width: static with the value 0x82

The main loop checks to see if bit 6 from x90 is set. If it is then it gets the value from the DAC (ADC7 - Audio Input Level A (Half Wave)), divides it by two and if the LSB was a 1 subtracts 0x53 then sets the A Intensity to that value, otherwise sets the Intensity to 0xff. It does the same for the B Channel using the value from the DAC (ADC6 - Audio Input Level B (Half Wave)).

Program “Audio 2” is Module 23

If you select Program “Audio 2” then the firmware also loads Module 23. Everything is the same as above for “Audio 1” except the flag for mono isn’t set.

Program “Audio 3” is Module 34

If you select Program “Audio 3” then the firmware loads Module 34. It also has hardcoded settings for the gate outputs (memory 0x90 and 0x190 to 0x67) and output control flags 0x83 (sets bit 2 of 0x83).

Module 34 contains these Instructions:

memory[00ae *Channel A: Current Frequency Modulation Value* (0x16)]=0a
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=00
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=00
  • Intensity: static with value 0xff
  • Frequency: static with value 0x0a
  • Width: static with tvalue 0x82

“Audio 3” Program also ends up setting up an interrupt based on Int 0/1 (Audio A/B digital inputs).

Program “Random 2” is Module 32

If you select Program “Random 2” then the firmware loads Module 32:

memory[008d Random Number Min]=01
memory[008e Random Number Max]=04
memory[01b2 *Channel B: Current Frequency Modulation Step* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[00a8 *Channel A: Current Intensity Modulation Rate* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[01a8 *Channel B: Current Intensity Modulation Rate* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[00b1 *Channel A: Current Frequency Modulation Rate* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[01b1 *Channel B: Current Frequency Modulation Rate* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[00ba *Channel A: Current Width Modulation Rate* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[01ba *Channel B: Current Width Modulation Rate* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=01
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=02
memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=02
memory[0196 *Next module flag* (0x00)]=03
memory[0197 *Next module number* (0x00)]=20
memory[008d Random Number Min]=05
memory[008e Random Number Max]=1f
memory[0195 *Next module timer max* (0xff)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
  • A Intensity: Using 30.5Hz timer, step to random between 1-4, rate to random between 1-4, and range 0xcd to 0xff, reversing at the maximum and minimum.
  • B Intensity: Using 30.5Hz timer, step to random between 1-4, rate to random between 1-4, and range 0xcd to 0xff, reversing at the maximum and minimum.
  • A Frequency: Using 30.5Hz timer, step to random between 1-4, rate to random between 1-4, and range 0x09 to 0x64 starting from 0x16, reversing at the maximum and minimum.
  • B Frequency: Using 30.5Hz timer, step to random between 1-4, rate to random between 1-4, and range 0x09 to 0x64 starting from 0x16, reversing at the maximum and minimum.
  • A Width: Using 244Hz timer, step to 0x01, rate to random between 1-4, and range 0x32 to 0xc8 starting from 0x82, reversing at the maximum and minimum.
  • B Width: Using 244Hz timer, step to 0x01, rate to random between 1-4, and range 0x32 to 0xc8 starting from 0x82, reversing at the maximum and minimum.
  • After a random time, using .953Hz timer between 0x05-0x1f (5-32 seconds), reload Module 32

Program “Toggle” is Modules 18, 19

If you select Program “Toggle” then the firmware loads Module 18:

memory[0086 *Multi Adjust Range Min* (0x0f)]=00
memory[0087 *Multi Adjust Range Max* (0xff)]=7f
memory[0096 *Next module flag* (0x00)]=02
memory[008c Module temporary byte store]=memory[020d *Current Multi Adjust Value / COMM_MULTI_AVG*]
memory[0095 *Next module timer max* (0xff)]=memory[008c Module temporary byte store]
memory[0097 *Next module number* (0x00)]=13
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=04
memory[00bf *Channel A: Current Width Modulation Timer* (0x00)]=04
memory[0090 *Channel A: Current Gate Value* (0x06)]=07
memory[0190 *Channel B: Current Gate Value* (0 when no output)]=06

The above runs for both Channel A then with memory modified for Channel B and causes:

  • MA range is 0x00-0x7f
  • A/B Intensity: static with value 0xff.
  • A/B Frequency: static at the advanced parameter default
  • A/B Width: static at the advanced parameter default
  • Channel A gate is turned on, Channel B gate is turned off
  • Sets the “Next Module timer” maximum to the value of the MA knob and to trigger Module 19, flag of 2 means use the 30.5Hz timer (since the maximum count is 0x7f this gives effective toggle time of between 0 and about 4 seconds)

Module 18 triggers Module 19:

memory[0085 when module loading determines which channels to set (0x03)]=01
memory[0090 *Channel A: Current Gate Value* (0x06)]=06
memory[0085 when module loading determines which channels to set (0x03)]=03
memory[0097 *Next module number* (0x00)]=12
memory[0190 *Channel B: Current Gate Value* (0 when no output)]=07
memory[008c Module temporary byte store]=memory[020d *Current Multi Adjust Value / COMM_MULTI_AVG*]
memory[0095 *Next module timer max* (0xff)]=memory[008c Module temporary byte store]
  • Channel A gate is turned off, Channel B gate is turned on
  • Sets the “Next Module timer” maximum to the value of the MA knob and to trigger Module 18

Program “Orgasm” is Modules 24-27

If you select Program “Orgasm” then the firmware loads Module 24:

memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=00
memory[00b7 *Channel A: Current Width Modulation Value* (0x82)]=32
memory[00bb *Channel A: Current Width Modulation Step* (0x01)]=04
memory[00ba *Channel A: Current Width Modulation Rate* (0x01)]=01
memory[00b8 *Channel A: Current Width Modulation Min* (0x32)]=32
memory[0085 when module loading determines which channels to set (0x03)]=01
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=01
memory[00bd *Channel A: Current Width Modulation Action Max* (0xff)]=19
memory[01be *Channel B: Current Width Modulation Select* (0x04)]=00
  • A/B Intensity: static with value 0xff
  • A/B Frequency: follows the value of the MA knob
  • A Width: Uses 244Hz timer, the default set the step to 4, rate to 1, and range starting 0x32 up to 0xc8, then triggers Module 25
  • B Width: static with the value 0x32

Module 24 triggers Module 25:

memory[0085 when module loading determines which channels to set (0x03)]=01
memory[00bb *Channel A: Current Width Modulation Step* (0x01)]=ff
memory[00bc *Channel A: Current Width Modulation Action Min* (0xff)]=1a
memory[01be *Channel B: Current Width Modulation Select* (0x04)]=01
memory[01bd *Channel B: Current Width Modulation Action Max* (0xff)]=ff
memory[0085 when module loading determines which channels to set (0x03)]=03
memory[00b8 *Channel A: Current Width Modulation Min* (0x32)]+=02
memory[00b8 *Channel A: Current Width Modulation Min* (0x32)]^02
  • Changes A Width to use 244Hz timer, step -1, rate 1, at minimum triggers Module 26
  • Changes B Width to use 244Hz timer, step 1, rate 1, range 0x32 to 0xc8, reverse at maximum and minimum
  • Increments the minimum Width for both channels by 4

Module 25 triggers Module 26:

memory[0085 when module loading determines which channels to set (0x03)]=01
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=00
memory[01bc *Channel B: Current Width Modulation Action Min* (0xff)]=1b
  • Changes A width to be static at whatever it was before
  • Changes B width so when reaches minimum triggers Module 27

Module 26 triggers Module 27:

memory[0085 when module loading determines which channels to set (0x03)]=01
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=01
memory[01be *Channel B: Current Width Modulation Select* (0x04)]=00
memory[00bb *Channel A: Current Width Modulation Step* (0x01)]=01
memory[01bb *Channel B: Current Width Modulation Step* (0x01)]=01
  • changes A width to use 244Hz timer again, step 1 (at maximum will trigger Module 25, at minimum will trigger Module 26)
  • changes B width to be static, sets step to 1 (at minimum will trigger Module 27)

Program “Torment” is Modules 28, 29, 30, 31

If you select Program “Torment” then the firmware loads Module 28:

memory[0085 when module loading determines which channels to set (0x03)]=03
memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=00
memory[00a5 *Channel A: Current Intensity Modulation Value* (0xff)]=b0
memory[0090 *Channel A: Current Gate Value* (0x06)]=06
memory[008d Random Number Min]=05
memory[008e Random Number Max]=18
memory[0195 *Next module timer max* (0xff)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[0196 *Next module flag* (0x00)]=03
memory[00ab *Channel A: Current Intensity Action at Max* (0xff)]=1c
memory[008d Random Number Min]=e0
memory[008e Random Number Max]=ff
memory[00a7 *Channel A: Current Intensity Modulation Max* (0xff)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[008d Random Number Min]=06
memory[008e Random Number Max]=3f
memory[00a8 *Channel A: Current Intensity Modulation Rate* (0x01)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[008d Random Number Min]=1d
memory[008e Random Number Max]=1f
memory[0197 *Next module number* (0x00)]=rand(memory[008d Random Number Min],memory[008e Random Number Max])
memory[00ab *Channel A: Current Intensity Action at Max* (0xff)]=ff
  • A/B Intensity: static at value 0xb0. But sets the Max to random between 0xe0 and 0xff and the rate to random between 0x06 and 0x3f
  • A/B Intensity: if reaches max then triggers Module 28
  • A/B Gate: turned off
  • Set the next module timer to a random number between 0x05 and 0x18, using the .953Hz timer (so 5-23 seconds). Module to be trigged is chosen at random, 29-31

Module 29 contains:

memory[0085 when module loading determines which channels to set (0x03)]=03
memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=01
memory[0090 *Channel A: Current Gate Value* (0x06)]=07
memory[00ab *Channel A: Current Intensity Action at Max* (0xff)]=1c
  • A/B Gate: turns on the gate
  • A/B Intensity: start ramping up from current value using 244Hz timer, step 1, rate 1, when reaches maximum load Module 28

Module 30 contains:

memory[0085 when module loading determines which channels to set (0x03)]=02
memory[01ac *Channel B: Current Intensity Modulation Select* (0x00)]=01
memory[0190 *Channel B: Current Gate Value* (0 when no output)]=07
memory[01ab *Channel B: Current Intensity Action at Max* (0xff)]=1c
  • B Gate: turns on the gate
  • B Intensity: start ramping up from current value using 244Hz timer, step 1, rate 1, when reaches maximum load Module 28

Module 31 contains:

memory[0085 when module loading determines which channels to set (0x03)]=01
memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=01
memory[0090 *Channel A: Current Gate Value* (0x06)]=07
memory[00ab *Channel A: Current Intensity Action at Max* (0xff)]=1c
  • A Gate: turns on the gate
  • A Intensity: start ramping up from current value using 244Hz timer, step 1, rate 1, when reaches maximum load Module 28

Program “Phase 1” is Modules 20 and 21

If you select Program “Phase 1” then the firmware loads Module 20. It also hardcodes the output control flags at 0x83 (to 0x5).

Module 20 contains these Instructions:

memory[0086 *Multi Adjust Range Min* (0x0f)]=01
memory[0087 *Multi Adjust Range Max* (0xff)]=20
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=04
memory[00be *Channel A: Current Width Modulation Select* (0x04)]=00
memory[00b7 *Channel A: Current Width Modulation Value* (0x82)]=7d
  • Sets MA range from 0x01-0x20
  • A Frequency: static at advanced parameter default
  • A Width: static at 0x7d
  • A Intensity: static at 0xff

For Channel B it loads Module 20 and then Module 21 causing:

memory[00b5 *Channel B: Current Frequency Modulation Select* (0x08)]=04
memory[00be *Channel B: Current Width Modulation Select* (0x04)]=00
memory[00b7 *Channel B: Current Width Modulation Value* (0x82)]=79
  • B Frequency: static at advanced parameter default
  • B Width: static at 0x79
  • B Intensity: static at 0xff

Program “Phase 2” is Modules 20 and 21 and 35

If you select Program “Phase 1” then the firmware loads Module 20 then 35. It also hardcodes the output control flags at 0x83. For Channel B it loads Module 20 then 21 then 35.

Module 35 contains these Instructions:

memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=25

Together this causes:

  • Sets MA range from 0x01-0x20
  • A/B Frequency: static at advanced parameter default
  • A Width: static at 0x7d
  • B Width: static at 0x79
  • A/B Intensity: Updates based on 244Hz timer, rate from advanced parameter default, step 1, from advanced parameter default minimum to 0xff, reversing at maximum and minimum.

Program “Phase 3” is Module 22

If you select Program “Phase 3” then the firmware loads Module 22. Module 22 contains these Instructions:

memory[0083 *Output Control Flags - COMM_CONTROL_FLAG* (0x00)]=08
memory[0190 *Channel B: Current Gate Value* (0 when no output)]=a0
memory[00ac *Channel A: Current Intensity Modulation Select* (0x00)]=01
memory[0086 *Multi Adjust Range Min* (0x0f)]=cd
memory[0087 *Multi Adjust Range Max* (0xff)]=d4
memory[00b5 *Channel A: Current Frequency Modulation Select* (0x08)]=04
memory[01ac *Channel B: Current Intensity Modulation Select* (0x00)]=09
  • TBD

Program “Random 1”

This is a special case. It sets the flag at 0x74 to 1 and does not load any additional Modules.

The main loop looks around 60 times a second at 0x74. If it’s a 1 we want to start Random 1 mode. Otherwise the code checks to see if it’s time to change to a new Random Program.

It then:

  • Picks a random number between 0x76 and 0x7b and store that in 0x74 (this is the current random Program selected, “Waves”, “Stroke”, “Climb”, “Combo”, “Intense”, or “Rhythm”).
  • Picks a random number between 0x14 and 0x78 adds it to the current master timer msb, which is used to determine how long before we change mode
  • Picks a random number between 0x8c and 0xb8 and stores in 0x184 (TBD: unknown)
  • Makes sure we’re still in Random 1 mode, and if so we select the program as determined above

Program to Module list

ProgramModules used
waves11 (A, B), 12 (B)
stroke3 (A, B), 4 (B)
climb5, 6, 7 (A, B), 8, 9, 10 (B)
combo13 (A, B), 33 (B)
intense14 (A, B), 2 (B)
rhythm15 (triggers load 16, 17)
audio23
audio334
random232 (triggers load 32 again)
toggle18 (triggers load 19)
orgasm24 (triggers load 25, 26, 27)
torment28 (triggers load 29, 30, 31)
phase120 (A, B), 21 (B)
phase220 (A, B), 21 (B), 35 (A,B)
phase322 (A, B)
random1special hardcoded