diff --git a/README.md b/README.md index 73e3f99c..708f4ea2 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,11 @@ and is automatically generated. Here is a quick summary of config variables: |`post_orgasm_menu_lock`|Boolean|false|Deny access to menu starting after orgasm detected.| |`max_clench_duration_ms`|Int|3000|Duration the clench detector can raise arousal if clench detector turned on in edging session.| |`clench_time_threshold_ms`|Int|900|Threshold variable that is milliseconds counts to detect the start of clench.| +|`denials_count_to_orgasm`|Int|10|How many denials before permiting an orgasm, if this mode is chosen.| +|`milk_o_matic_rest_duration_minutes`|Int|60|How long to rest before restarting an other round of Denial_count edging.| +|`random_orgasm_triggers`|Boolean|false|Randomize Edge timer and Denial count to minimum of 1/2 of their values.| +|`post_orgasm_mode`|PostOrgasmMode|Timer|Timer, Denial_count and Milk-O-Matic. Random is a choice between Timer and Milk-o-matic. See documentation for more details.| +|`max_orgasms`|Int|4|Milk-o-matic maximum orgasms before turning off.| \* AzureFang refers to a common wireless technology that is blue and involves chewing face-rocks. However, the @@ -79,6 +84,14 @@ and is automatically generated. Here is a quick summary of config variables: |3|Enhancement|Vibrator speed ramps up as arousal increases, holding a peak for ramp_time.| |0|Global Sync|When set on secondary vibrators, they will follow the primary vibrator speed.| +### Post Orgasm Modes: +|ID|Name|Description| +|---|---|---| +|0|Denial_count|How many Denials before permiting an orgasm. Value set with - "Denials to permit orgasm" in the Orgasm Menu| +|1|Timer|How long to edge before permiting an orgasm. Value set with - "Edge Duration Minutes" in the Orgasm Menu| +|2|Milk_o_matic|Cycles in Denial_count mode after each orgasm. Repeats until max_orgasms reached| +|3|Random_mode|Random choice Timer or milk-o-matic before orgasm. For best result choose "Edge Duration Minutes" = 60 min and "Denials to permit orgasm" = 20. the idea is not knowing if you will have an 1 hours tease or multiple orgasm within that same 1 hour. Max_orgasms stops the session after it's reached.| + ### post_orgasm_duration_seconds: |Seconds|Description| |---|---| diff --git a/include/assets/config_help.h b/include/assets/config_help.h index b46c84d3..96ed5426 100644 --- a/include/assets/config_help.h +++ b/include/assets/config_help.h @@ -57,6 +57,11 @@ extern "C" { #define POST_ORGASM_MENU_LOCK_HELP _HELPSTR("Deny access to menu starting after orgasm detected.") #define MAX_CLENCH_DURATION_MS_HELP _HELPSTR("Duration the clench detector can raise arousal if clench detector turned on in edging session.") #define CLENCH_TIME_THRESHOLD_MS_HELP _HELPSTR("Threshold variable that is milliseconds counts to detect the start of clench.") +#define DENIALS_COUNT_TO_ORGASM_HELP _HELPSTR("How many denials before permiting an orgasm, if this mode is chosen.") +#define MILK_O_MATIC_REST_DURATION_MINUTES_HELP _HELPSTR("How long to rest before restarting an other round of Denial_count edging.") +#define RANDOM_ORGASM_TRIGGERS_HELP _HELPSTR("Randomize Edge timer and Denial count to minimum of 1/2 of their values.") +#define POST_ORGASM_MODE_HELP _HELPSTR("Timer, Denial_count and Milk-O-Matic. Random is a choice between Timer and Milk-o-matic. See documentation for more details.") +#define MAX_ORGASMS_HELP _HELPSTR("Milk-o-matic maximum orgasms before turning off.") #ifdef __cplusplus } diff --git a/include/config.h b/include/config.h index 0b914432..109a57b3 100644 --- a/include/config.h +++ b/include/config.h @@ -34,6 +34,13 @@ enum vibration_mode { RampStop = 1, Depletion = 2, Enhancement = 3, Pattern = 4, typedef enum vibration_mode vibration_mode_t; +// Post orgasm Modes +// See vibration_mode_controller.h for more. + +enum post_orgasm_mode { Denial_count = 0, Timer = 1, Milk_o_matic = 2, Random_mode = 3 }; + +typedef enum post_orgasm_mode post_orgasm_mode_t; + /** * Main Configuration Struct! * @@ -153,6 +160,21 @@ struct config { bool edge_menu_lock; // Deny access to menu starting after orgasm detected bool post_orgasm_menu_lock; + // Edging needed to permit orgasm (Max value if ramdom selected). + int denials_count_to_orgasm; + // milk_o_matic rest period in minutes before restart edge+orgasm + int milk_o_matic_rest_duration_minutes; + // random timer and denial_count to orgasm from set values. minimum is 1/2 + bool random_orgasm_triggers; + // how many orgasms before stopping in milk-o-matic + int max_orgasms; + + + // Timer : default original mode + // Edge_count will permit orgasm after # denial reached + // Milk-O-Matic will restart edge+orgasm indefenetly and randomly choose Timer or edge_count at each loop + // Random choose Timer or Edge_count at start of session + int post_orgasm_mode; //= Internal System Configuration (Update only if you know what you're doing) diff --git a/include/orgasm_control.h b/include/orgasm_control.h index 8e6ed2f0..3e45f13f 100644 --- a/include/orgasm_control.h +++ b/include/orgasm_control.h @@ -69,6 +69,7 @@ oc_bool_t orgasm_control_is_post_orgasm_reached(void); void orgasm_control_permit_orgasm(int seconds); void orgasm_control_lock_menu(oc_bool_t value); long orgasm_control_clench_detect(long p_check); +bool post_orgasm_mode_milk_o_matic(void); #ifdef __cplusplus } diff --git a/src/config.c b/src/config.c index 5a78e82e..6f72c6d5 100644 --- a/src/config.c +++ b/src/config.c @@ -50,7 +50,12 @@ CONFIG_DEFS { CFG_NUMBER(update_frequency_hz, 50); CFG_NUMBER(sensor_sensitivity, 128); CFG_BOOL(use_average_values, false); - + CFG_NUMBER(denials_count_to_orgasm, 10); + CFG_NUMBER(milk_o_matic_rest_duration_minutes, 10); + CFG_ENUM(post_orgasm_mode, post_orgasm_mode_t, Timer); + CFG_BOOL(random_orgasm_triggers, false); + CFG_NUMBER(max_orgasms, 4); + // Vibration Settings CFG_ENUM(vibration_mode, vibration_mode_t, RampStop); diff --git a/src/menus/orgasm_settings_menu.c b/src/menus/orgasm_settings_menu.c index 05a5c836..65b443ab 100644 --- a/src/menus/orgasm_settings_menu.c +++ b/src/menus/orgasm_settings_menu.c @@ -59,15 +59,90 @@ static const ui_input_numeric_t CLENCH_PRESSURE_SENSITIVITY_INPUT = { .input.help = CLENCH_PRESSURE_SENSITIVITY_HELP }; +void on_to_orgasm_select(const ui_input_select_option_t* option, int final, UI_INPUT_ARG_TYPE arg) { + post_orgasm_mode_t mode = (post_orgasm_mode_t)option->ival; + if (final) Config.post_orgasm_mode = mode; + on_config_save(mode, final, arg); +} + +static const ui_input_select_option_t post_orgasm_modes[] = { + { + .label = "Timer", + .ival = Timer, + .value = NULL, + }, + { + .label = "Denial count", + .ival = Denial_count, + .value = NULL, + }, + { + .label = "Random choice", + .ival = Random_mode, + .value = NULL, + }, + { + .label = "Milk-O-Matic", + .ival = Milk_o_matic, + .value = NULL, + }, +}; + +static const ui_input_select_t POST_ORGASM_MODE_INPUT = { + SelectInputValues( + "Orgasm Modes", + &Config.post_orgasm_mode, + &post_orgasm_modes, + sizeof(post_orgasm_modes) / sizeof(post_orgasm_modes[0]), + on_to_orgasm_select + ), + .input.help = POST_ORGASM_MODE_HELP, +}; + +static const ui_input_numeric_t DENIALS_COUNT_TO_ORGASM_INPUT = { + UnsignedInputValues("Denials to permit orgasm", &Config.denials_count_to_orgasm, "", on_config_save), + .max = 255, + .step = 1, + .input.help = DENIALS_COUNT_TO_ORGASM_HELP +}; + +static const ui_input_numeric_t MILK_O_MATIC_REST_DURATION_INPUT = { + UnsignedInputValues( + "Milk-o-matic resting duration", &Config.milk_o_matic_rest_duration_minutes, UNIT_MINUTES, on_config_save + ), + .max = 1440, + .step = 1, + .input.help = MILK_O_MATIC_REST_DURATION_MINUTES_HELP +}; + +static const ui_input_toggle_t RANDOM_ORGASM_TRIGGERS_INPUT = { + ToggleInputValues("Random Timer and Edge_count", &Config.random_orgasm_triggers, on_config_save), + .input.help = RANDOM_ORGASM_TRIGGERS_HELP +}; + +static const ui_input_numeric_t MAX_ORGASMS_INPUT = { + UnsignedInputValues( + "Milk-o-matic max orgasms", &Config.max_orgasms, "", on_config_save + ), + .max = 255, + .step = 1, + .input.help = MAX_ORGASMS_HELP +}; + static void on_open(const ui_menu_t* m, UI_MENU_ARG_TYPE arg) { + ui_menu_add_input(m, (ui_input_t*)&USE_POST_ORGASM_INPUT); ui_menu_add_input(m, (ui_input_t*)&EDGING_DURATION_INPUT); + ui_menu_add_input(m, (ui_input_t*)&DENIALS_COUNT_TO_ORGASM_INPUT); + ui_menu_add_input(m, (ui_input_t*)&POST_ORGASM_MODE_INPUT); ui_menu_add_input(m, (ui_input_t*)&CLENCH_TIME_TO_ORGASM_MS_INPUT); - ui_menu_add_input(m, (ui_input_t*)&USE_POST_ORGASM_INPUT); ui_menu_add_input(m, (ui_input_t*)&POST_ORGASM_DURATION_SECONDS_INPUT); ui_menu_add_input(m, (ui_input_t*)&EDGE_MENU_LOCK_INPUT); ui_menu_add_input(m, (ui_input_t*)&POST_ORGASM_MENU_LOCK_INPUT); ui_menu_add_input(m, (ui_input_t*)&CLENCH_DETECTOR_IN_EDGING_INPUT); ui_menu_add_input(m, (ui_input_t*)&CLENCH_PRESSURE_SENSITIVITY_INPUT); + ui_menu_add_input(m, (ui_input_t*)&MILK_O_MATIC_REST_DURATION_INPUT); + ui_menu_add_input(m, (ui_input_t*)&MAX_ORGASMS_INPUT); + ui_menu_add_input(m, (ui_input_t*)&RANDOM_ORGASM_TRIGGERS_INPUT); } DYNAMIC_MENU(ORGASM_SETTINGS_MENU, "Orgasm Settings", on_open); \ No newline at end of file diff --git a/src/orgasm_control.c b/src/orgasm_control.c index edba6b94..5384c303 100644 --- a/src/orgasm_control.c +++ b/src/orgasm_control.c @@ -67,20 +67,38 @@ static struct { oc_bool_t menu_is_locked; oc_bool_t detected_orgasm; int post_orgasm_duration_seconds; + uint8_t edge_count_to_orgasm; + post_orgasm_mode_t post_orgasm_mode; + uint8_t auto_edging_duration_minutes; + bool random_orgasm_triggers; + uint8_t orgasm_count; + event_handler_node_t* _h_orgasm; } post_orgasm_state; volatile static struct { - uint8_t orgasm_count; - event_handler_node_t* _h_orgasm; -} orgasm_state = { 0 }; + uint8_t denial_count; + event_handler_node_t* _h_denial; +} denial_state = { 0 }; + +static void _evt_orgasm_denial( + const char* evt, EVENT_HANDLER_ARG_TYPE eap, int eai, EVENT_HANDLER_ARG_TYPE hap +) { + denial_state.denial_count += 1; +} + +//volatile static struct { +// uint8_t orgasm_count; +// event_handler_node_t* _h_orgasm; +//} orgasm_state = { 0 }; static void _evt_orgasm_start( const char* evt, EVENT_HANDLER_ARG_TYPE eap, int eai, EVENT_HANDLER_ARG_TYPE hap ) { if ( orgasm_control_is_permit_orgasm_reached() ) { post_orgasm_state.detected_orgasm = ocTRUE; + post_orgasm_state.orgasm_count += 1; } - orgasm_state.orgasm_count += 1; + // if not permited then you got a ruined orgasm } #define update_check(variable, value) \ @@ -110,12 +128,15 @@ void orgasm_control_init(void) { output_state.output_mode = OC_MANUAL_CONTROL; output_state.vibration_mode = Config.vibration_mode; output_state.edge_time_out = 10000; - post_orgasm_state.clench_pressure_threshold = 4096; + post_orgasm_state.clench_pressure_threshold = 4096; running_average_init(&arousal_state.average, Config.pressure_smoothing); - orgasm_state.orgasm_count = 0; - if (orgasm_state._h_orgasm == NULL) { - orgasm_state._h_orgasm = + if (denial_state._h_denial == NULL) { + denial_state._h_denial = + event_manager_register_handler(EVT_ORGASM_DENIAL, &_evt_orgasm_denial, NULL); + } + if (post_orgasm_state._h_orgasm == NULL) { + post_orgasm_state._h_orgasm = event_manager_register_handler(EVT_ORGASM_START, &_evt_orgasm_start, NULL); } } @@ -256,6 +277,10 @@ static void orgasm_control_updateEdgingTime() { // Edging+Orgasm timer if (output_state.output_mode == OC_MANUAL_CONTROL) { post_orgasm_state.menu_is_locked = ocFALSE; post_orgasm_state.post_orgasm_duration_seconds = Config.post_orgasm_duration_seconds; + post_orgasm_state.edge_count_to_orgasm = Config.denials_count_to_orgasm; + post_orgasm_state.detected_orgasm = ocFALSE; + post_orgasm_state.post_orgasm_mode = Config.post_orgasm_mode; + post_orgasm_state.random_orgasm_triggers = Config.random_orgasm_triggers; return; } @@ -263,6 +288,27 @@ static void orgasm_control_updateEdgingTime() { // Edging+Orgasm timer if (output_state.output_mode != OC_ORGASM_MODE) { post_orgasm_state.auto_edging_start_millis = (esp_timer_get_time() / 1000UL); post_orgasm_state.post_orgasm_start_millis = 0; + post_orgasm_state.orgasm_count = 0; + + if ( post_orgasm_state.post_orgasm_mode == Random_mode ) { + post_orgasm_state.post_orgasm_mode = (random() % 2 + 1); + } + post_orgasm_state.edge_count_to_orgasm = denial_state.denial_count + Config.denials_count_to_orgasm; + post_orgasm_state.auto_edging_duration_minutes = Config.auto_edging_duration_minutes; + } else { + // Orgasm mode started + // Randomize timer and denial_count to orgasm. + if (post_orgasm_state.random_orgasm_triggers) { + // Only run once afer start of session + post_orgasm_state.random_orgasm_triggers = false ; + int min_count = round( Config.denials_count_to_orgasm / 2 ); + int min_edge_time = round( Config.auto_edging_duration_minutes / 2 ); + + post_orgasm_state.edge_count_to_orgasm = denial_state.denial_count + + min_count + rand() % (Config.denials_count_to_orgasm - min_count); + post_orgasm_state.auto_edging_duration_minutes = + min_edge_time + rand() % (Config.auto_edging_duration_minutes - min_edge_time ); + } } // Lock Menu if turned on. and in Edging_orgasm mode @@ -300,6 +346,7 @@ static void orgasm_control_updateEdgingTime() { // Edging+Orgasm timer output_state.motor_speed += 5; } else { update_check(output_state.motor_speed, Config.motor_max_speed); + _set_speed(output_state.motor_speed); } } @@ -314,20 +361,56 @@ static void orgasm_control_updateEdgingTime() { // Edging+Orgasm timer output_state.motor_speed = Config.motor_max_speed; } else { // Post_orgasm timer reached if (output_state.motor_speed > 0) { // Ramp down motor speed to 0 - output_state.motor_speed = output_state.motor_speed - 1; - } else { - post_orgasm_state.menu_is_locked = ocFALSE; - post_orgasm_state.detected_orgasm = ocFALSE; - output_state.motor_speed = 0; + update_check(output_state.motor_speed, output_state.motor_speed - 1 ) _set_speed(output_state.motor_speed); - orgasm_control_set_output_mode(OC_MANUAL_CONTROL); + } else { + if ( post_orgasm_mode_milk_o_matic() != true ) { + // post orgasm modes has finished. Turn off everything and return to manual mode + post_orgasm_state.menu_is_locked = ocFALSE; + post_orgasm_state.detected_orgasm = ocFALSE; + update_check(output_state.motor_speed, 0 ) + _set_speed(output_state.motor_speed); + orgasm_control_set_output_mode(OC_MANUAL_CONTROL); + } } } } - // Control output while motor control is paused - if (output_state.control_motor == OC_MANUAL_CONTROL) { - uint8_t speed = orgasm_control_get_motor_speed(); - _set_speed(speed); +} + +/** + * Detect if in milk-o-matic mode + * @return true if mode is still active, false if end of mode or not active + */ +bool post_orgasm_mode_milk_o_matic(void){ + // make sure you don't go over max orgasm count in milk-o-matic mode + if ( (post_orgasm_state.post_orgasm_mode == Milk_o_matic) && + (post_orgasm_state.orgasm_count < Config.max_orgasms)) { + + // The motor has been turnned off but this is Milk-O-Matic orgasm mode. Prepare for next round. + // now show that your in milk-o-matic mode. Usefull if you choose random post orgasm mode, you only find out after first post orgasm + eom_hal_set_encoder_rgb(255, 0, 127); + // now give a break before restarting edging + if (esp_timer_get_time() / 1000UL > post_orgasm_state.post_orgasm_start_millis + + post_orgasm_state.post_orgasm_duration_millis + + (Config.milk_o_matic_rest_duration_minutes * 60 * 1000)) { + // Rest period is finished. Reset variables for next round + post_orgasm_state.auto_edging_start_millis = (esp_timer_get_time() / 1000UL); + post_orgasm_state.post_orgasm_start_millis = 0; + post_orgasm_state.detected_orgasm = ocFALSE; + post_orgasm_state.menu_is_locked = ocFALSE; + // Set the new denial count limit to reach before next orgasm + // Randomize denial_count if turned on + if (Config.random_orgasm_triggers) { + // re-enable calculation of random for next round + post_orgasm_state.random_orgasm_triggers = true; + } else { + post_orgasm_state.edge_count_to_orgasm = denial_state.denial_count + Config.denials_count_to_orgasm; + } + orgasm_control_resume_control(); + } + return true; + } else { + return false; } } @@ -498,7 +581,7 @@ void orgasm_control_tick() { Config.sensitivity_threshold, post_orgasm_state.clench_pressure_threshold, post_orgasm_state.clench_duration_millis, - orgasm_state.orgasm_count + post_orgasm_state.orgasm_count ); // Write out to logfile, which includes millis: @@ -619,12 +702,23 @@ void orgasm_control_permit_orgasm(int seconds) { } oc_bool_t orgasm_control_is_permit_orgasm_reached() { - // Detect if edging time has passed - if ((esp_timer_get_time() / 1000UL) > (post_orgasm_state.auto_edging_start_millis + - (Config.auto_edging_duration_minutes * 60 * 1000))) { - return ocTRUE; + if (post_orgasm_state.post_orgasm_mode == Denial_count || + post_orgasm_state.post_orgasm_mode == Milk_o_matic) { + if (denial_state.denial_count >= post_orgasm_state.edge_count_to_orgasm) { +// if (denial_state.denial_count >= 1) { + + return ocTRUE; + } else { + return ocFALSE; + } } else { - return ocFALSE; + // Detect if edging time has passed + if ((esp_timer_get_time() / 1000UL) > (post_orgasm_state.auto_edging_start_millis + + (Config.auto_edging_duration_minutes * 60 * 1000))) { + return ocTRUE; + } else { + return ocFALSE; + } } }