├── PCB ├── Bot_2257.JPG ├── Schematic.JPG ├── Top_2257.JPG ├── Print_2257.JPG ├── Protogasme PT2257_small.gif ├── Protogasme PT2257 Asample2.png ├── Gerber_PCB_Protogasme_PT2257.zip └── Bom.md ├── Protogasme for E-Stim.JPG ├── estim_audio └── Progasme_edge.mp3 ├── Source ├── pt2257.h ├── pt2257.cpp └── protogasm_code_PT2257_3.ino └── README.md /PCB/Bot_2257.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/PCB/Bot_2257.JPG -------------------------------------------------------------------------------- /PCB/Schematic.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/PCB/Schematic.JPG -------------------------------------------------------------------------------- /PCB/Top_2257.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/PCB/Top_2257.JPG -------------------------------------------------------------------------------- /PCB/Print_2257.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/PCB/Print_2257.JPG -------------------------------------------------------------------------------- /Protogasme for E-Stim.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/Protogasme for E-Stim.JPG -------------------------------------------------------------------------------- /PCB/Protogasme PT2257_small.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/PCB/Protogasme PT2257_small.gif -------------------------------------------------------------------------------- /PCB/Protogasme PT2257 Asample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/PCB/Protogasme PT2257 Asample2.png -------------------------------------------------------------------------------- /PCB/Gerber_PCB_Protogasme_PT2257.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puste1/Protogasme-for-E-Stim/HEAD/PCB/Gerber_PCB_Protogasme_PT2257.zip -------------------------------------------------------------------------------- /estim_audio/Progasme_edge.mp3: -------------------------------------------------------------------------------- 1 | https://mega.nz/folder/20gVzIpC#nlOQyXik_vZPjckEVrgJLg 2 | 3 | The files is Big and small !!! 4 | Please, remember to import into your own account and then download) 5 | This is so my quota does not get used up! 6 | -------------------------------------------------------------------------------- /Source/pt2257.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef pt2257_h 4 | #define pt2257_h 5 | //---------------------------------------------------------- 6 | class PT2257 { 7 | public: 8 | PT2257(); 9 | void init(); 10 | void set_volume(uint8_t db); 11 | void set_volume_left(uint8_t db); 12 | void set_volume_right(uint8_t db); 13 | void mute(bool st); 14 | void off(); 15 | private: 16 | }; 17 | //---------------------------------------------------------- 18 | #endif 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Protogasme-for-E-Stim 2 | This Board is created from https://github.com/night-howler/protogasm 3 | 4 | It has been change to use E-Stim in instead of using a motor. 5 | 6 | ![image](https://github.com/puste1/Protogasme-for-E-Stim/blob/2e44da04a47f2ec9632a36b34d55d26fad5b9140/Protogasme%20for%20E-Stim.JPG) 7 | 8 | The Arduino code is a modified version of night-howler code and is modiefied by Skier23 at https://milovana.com/
9 | https://github.com/Edging-Machines/Edging-Machines/blob/973bf4184f7a196d41e8062bba745538e7ff2416/Protogasm/protogasm_BetterAlgorithm.ino 10 | 11 | And all the efford to have this created is lot of help from https://discord.com/channels/ 12 | 13 | Thanks to Skier23 for devellop a better algoritme for this board.
14 | Se more at Skier23 Github https://github.com/Edging-Machines/Edging-Machines 15 | 16 | The added code I have used to change volume in 79-0 dB is from
17 | https://www.kn34pc.com/spr/arduino_pt2257.html
18 | You have to download this code to get this compiled to Arduino UNO V3. pt2257_v0.3.zip 19 | -------------------------------------------------------------------------------- /PCB/Bom.md: -------------------------------------------------------------------------------- 1 | | Part# | Value | Description | Mouser | Amazon | 2 | | ----- | -------------- | -------------------------------------------- | ---------------------- | ----------------------------------------| 3 | | C1 | 0.1uF | CAPACITOR, American symbol | 80-C320C104K5R | https://www.amazon.com/dp/B007SVHFXO | 4 | | C2-6 | 5 x 10uF | CAPACITOR, American symbol | UFW1H100MDD1TA | https://www.amazon.com/dp/B007SVHFXO | 5 | | U1 | Arduino Uno | Arduino Uno R3 | | | 6 | | U2 | PT2257 | Volume Control IC | | https://www.amazon.com/dp/B082FMSNQG | 7 | | U3 | MPX5050GP | Integrated Silicon Pressure Sensor | 841-MPX5050GP | https://www.amazon.com/dp/B005T5KNDK | 8 | | U4 | 3.5MM Jack | 3.5MM 5PIN FEMALE STEREO AUDIO JACK PCB Mount| | https://www.amazon.com/dp/B07MVW8PQN | 9 | | R1+7 | 2 x 4.7K | RESISTOR, American symbol | 660-MF1/4DC4701F | https://www.amazon.com/dp/B003UC4FSS | 10 | | R2 | 10K | Trimmer Potentiometer | 652-3306P-1-103 | https://www.amazon.com/dp/B00SWK15KE | 11 | | R3-6 | 4 x 100K | RESISTOR, American symbol | 660-MF1/4DC1003F | https://www.amazon.com/dp/B003UC4FSS | 12 | | SW1 | Rotary encoder | ALPS rotary Encoder EC12E series with switch | 652-PEC11R-4115F-S18 | https://www.amazon.com/dp/B0197X1UZY | 13 | | -- | NEOPIXEL RING | Adafruit 24 RGB LED Neopixel Ring | | https://www.amazon.com/dp/B00K9M3WXG | 14 | | -- | DIP8 | IC & Component Sockets 8 PIN Optional | 575-11041308410010 | https://www.amazon.com/dp/B07H3V9DSF | 15 | | -- | Screw 3 Pol | Fixed Terminal Blocks WR-TBL Optional | 710-691103110003 | https://www.amazon.com/dp/B06ZYN7R2B | 16 | -------------------------------------------------------------------------------- /Source/pt2257.cpp: -------------------------------------------------------------------------------- 1 | // Electronic Volume Controller, IC PT2257, v0.3 2 | // 2.10.2018, Arduino IDE v1.8.7, LZ2WSG, KN34PC 3 | //---------------------------------------------------------- 4 | #include 5 | #include 6 | #include "pt2257.h" 7 | // _____ 8 | // LIN -| ^ |- RIN 9 | // LOUT -| |- ROUT 10 | // GND -| |- VDD 11 | // SDA -|_____|- SCL 12 | 13 | #define PT2275_ADDR 0x44 // I2C address 14 | #define PT2275_OFF 0b11111111 // Off 15 | #define PT2275_MUTE 0b01111000 // Mute 16 | #define LR_ATT_1 0b11010000 // L & R channels attenuation -1dB 17 | #define LR_ATT_10 0b11100000 // L & R channels attenuation -10dB 18 | #define L_ATT_1 0b10100000 // L-channel attenuation -1dB 19 | #define L_ATT_10 0b10110000 // L-channel attenuation -10dB 20 | #define R_ATT_1 0b00100000 // R-channel attenuation -1dB 21 | #define R_ATT_10 0b00110000 // R-channel attenuation -10dB 22 | //---------------------------------------------------------- 23 | PT2257::PT2257() { 24 | } 25 | //---------------------------------------------------------- 26 | void PT2257::init() { 27 | Wire.begin(); 28 | } 29 | //---------------------------------------------------------- 30 | void PT2257::set_volume(uint8_t db) { 31 | Wire.beginTransmission(PT2275_ADDR); 32 | Wire.write(LR_ATT_10 | (db / 10)); 33 | Wire.write(LR_ATT_1 | (db % 10)); 34 | Wire.endTransmission(); 35 | } 36 | //---------------------------------------------------------- 37 | void PT2257::set_volume_left(uint8_t db) { 38 | Wire.beginTransmission(PT2275_ADDR); 39 | Wire.write(L_ATT_10 | (db / 10)); 40 | Wire.write(L_ATT_1 | (db % 10)); 41 | Wire.endTransmission(); 42 | } 43 | //---------------------------------------------------------- 44 | void PT2257::set_volume_right(uint8_t db) { 45 | Wire.beginTransmission(PT2275_ADDR); 46 | Wire.write(R_ATT_10 | (db / 10)); 47 | Wire.write(R_ATT_1 | (db % 10)); 48 | Wire.endTransmission(); 49 | } 50 | //---------------------------------------------------------- 51 | void PT2257::mute(bool st) { 52 | Wire.beginTransmission(PT2275_ADDR); 53 | Wire.write(PT2275_MUTE | st); 54 | Wire.endTransmission(); 55 | } 56 | //---------------------------------------------------------- 57 | void PT2257::off() { 58 | Wire.beginTransmission(PT2275_ADDR); 59 | Wire.write(PT2275_OFF); 60 | Wire.endTransmission(); 61 | } 62 | -------------------------------------------------------------------------------- /Source/protogasm_code_PT2257_3.ino: -------------------------------------------------------------------------------- 1 | // Protogasm Code, forked from Nogasm Code Rev. 3 2 | /* Drives a vibrator and uses changes in pressure of an inflatable buttplug 3 | * to estimate a user's closeness to orgasm, and turn off the vibrator 4 | * before that point. 5 | * A state machine updating at 60Hz creates different modes and option menus 6 | * that can be identified by the color of the LEDs, especially the RGB LED 7 | * in the central button/encoder knob. 8 | * 9 | * [Red] Manual Vibrator Control 10 | * [Blue] Automatic vibrator edging, knob adjusts orgasm detection sensitivity 11 | * [Green] Setting menu for maximum vibrator speed in automatic mode 12 | * [White] Debubbing menu to show data from the pressure sensor ADC 13 | * [Off] While still plugged in, holding the button down for >3 seconds turns 14 | * the whole device off, until the button is pressed again. 15 | * 16 | * Settings like edging sensitivity, or maximum motor speed are stored in EEPROM, 17 | * so they are saved through power-cycling. 18 | * 19 | * In the automatic edging mode, the vibrator speed will linearly ramp up to full 20 | * speed (set in the green menu) over 30 seconds. If a near-orgasm is detected, 21 | * the vibrator abruptly turns off for 15 seconds, then begins ramping up again. 22 | * 23 | * The motor will beep during power on/off, and if the plug pressure rises above 24 | * the maximum the board can read - this condition could lead to a missed orgasm 25 | * if unchecked. The analog gain for the sensor is adjustable via a trimpot to 26 | * accomidate different types of plugs that have higher/lower resting pressures. 27 | * 28 | * Motor speed, current pressure, and average pressure are reported via USB serial 29 | * at 115200 baud. Timestamps can also be enabled, from the main loop. 30 | * 31 | * There is some framework for more features like an adjustable "cool off" time 32 | * other than the default 15 seconds, and options for LED brightness and enabling/ 33 | * disabling beeps. 34 | * 35 | * Note - Do not set all the LEDs to white at full brightness at once 36 | * (RGB 255,255,255) It may overheat the voltage regulator and cause the board 37 | * to reset. 38 | * 39 | * Added E-Stim Support for PT2257 Board 40 | */ 41 | //=======Libraries=============================== 42 | #include 43 | #include 44 | #include "FastLED.h" 45 | #include "pt2257.h" 46 | 47 | //=======Hardware Setup=============================== 48 | //LEDs 49 | #define NUM_LEDS 24 50 | #define LED_PIN 10 51 | #define LED_TYPE WS2812B 52 | #define COLOR_ORDER GRB 53 | #define BRIGHTNESS 50 //Subject to change, limits current that the LEDs draw 54 | 55 | //Encoder 56 | #define ENC_SW 5 //Pushbutton on the encoder 57 | Encoder myEnc(3, 2); //Quadrature inputs 58 | #define ENC_SW_UP HIGH 59 | #define ENC_SW_DOWN LOW 60 | 61 | //Motor 62 | #define MOTPIN 9 63 | 64 | // PT2257 Audio 65 | PT2257 pt2257; 66 | 67 | //Pressure Sensor Analog In 68 | #define BUTTPIN A0 69 | // Sampling 4x and not dividing keeps the samples from the Arduino Uno's 10 bit 70 | // ADC in a similar range to the Teensy LC's 12-bit ADC. This helps ensure the 71 | // feedback algorithm will behave similar to the original. 72 | #define OVERSAMPLE 4 73 | #define ADC_MAX 1023 74 | 75 | //=======Software/Timing options===================== 76 | #define FREQUENCY 60 //Update frequency in Hz 77 | #define LONG_PRESS_MS 600 //ms requirements for a long press, to move to option menus 78 | #define V_LONG_PRESS_MS 2500 //ms for a very long press, which turns the device off 79 | 80 | //Update/render period 81 | #define period (1000/FREQUENCY) 82 | #define longBtnCount (LONG_PRESS_MS / period) 83 | 84 | int sensitivity = 0; //orgasm detection sensitivity, persists through different states 85 | 86 | //=======State Machine Modes========================= 87 | #define MANUAL 1 88 | #define AUTO 2 89 | #define OPT_SPEED 3 90 | #define OPT_RAMPSPD 4 91 | #define OPT_BEEP 5 92 | #define OPT_PRES 6 93 | 94 | 95 | //Button states - no press, short press, long press 96 | #define BTN_NONE 0 97 | #define BTN_SHORT 1 98 | #define BTN_LONG 2 99 | #define BTN_V_LONG 3 100 | 101 | 102 | uint8_t state = MANUAL; 103 | //=======Global Settings============================= 104 | #define MOT_MAX 255 // Motor PWM maximum 105 | #define MOT_MIN 1 // Motor PWM minimum. It needs a little more than this to start. 20 > 1 for E-stim PT2257 106 | 107 | CRGB leds[NUM_LEDS]; 108 | 109 | int volume = 79; 110 | int sensitivityThreshold = 500; 111 | long pressure = 0; 112 | long arousal = 0; 113 | long previousPressure = 0; 114 | //int bri =100; //Brightness setting 115 | int rampTimeS = 30; //Ramp-up time, in seconds 116 | #define DEFAULT_PLIMIT 600 117 | #define MAX_PLIMIT 1000 118 | int pLimit = DEFAULT_PLIMIT; //Limit in arousal before the vibrator turns off 119 | int maxSpeed = 255; //maximum speed the motor will ramp up to in automatic mode 120 | float motSpeed = 0; //Motor speed, 0-255 (float to maintain smooth ramping to low speeds) 121 | long lastUpdate = 0; 122 | long peakStart = 0; 123 | 124 | //=======EEPROM Addresses============================ 125 | //128b available on teensy LC 126 | #define BEEP_ADDR 1 127 | #define MAX_SPEED_ADDR 2 128 | #define SENSITIVITY_ADDR 3 129 | //#define RAMPSPEED_ADDR 4 //For now, ramp speed adjustments aren't implemented 130 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 131 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 132 | 133 | //=================================================================================== 134 | //======= Motor Beep 135 | //=================================================================================== 136 | //Beep out tones over the motor by frequency (1047,1396,2093) may work well 137 | void beep_motor(int f1, int f2, int f3){ 138 | analogWrite(MOTPIN, 0); 139 | tone(MOTPIN, f1); 140 | delay(250); 141 | tone(MOTPIN, f2); 142 | delay(250); 143 | tone(MOTPIN, f3); 144 | delay(250); 145 | noTone(MOTPIN); 146 | analogWrite(MOTPIN,motSpeed); 147 | } 148 | 149 | //=================================================================================== 150 | //======= Setup 151 | //=================================================================================== 152 | void setup() { 153 | pinMode(ENC_SW, INPUT); //Pin to read when encoder is pressed 154 | digitalWrite(ENC_SW, HIGH); // Encoder switch pullup 155 | 156 | // Init PT2257 Volume Audio for E-stim 157 | pt2257.init(); 158 | 159 | //digitalWrite(MOTPIN, LOW);//Make sure the motor is off 160 | pt2257.set_volume(79); // Make sure E-stim is off 161 | 162 | analogReference(EXTERNAL); 163 | 164 | // Classic AVR based Arduinos have a PWM frequency of about 490Hz which 165 | // causes the motor to whine. Change the prescaler to achieve 31372Hz. 166 | sbi(TCCR1B, CS10); 167 | cbi(TCCR1B, CS11); 168 | cbi(TCCR1B, CS12); 169 | 170 | pinMode(MOTPIN,OUTPUT); //Enable "analog" out (PWM) 171 | 172 | pinMode(BUTTPIN,INPUT); //default is 10 bit resolution (1024), 0-3.3 173 | 174 | digitalWrite(MOTPIN, LOW);//Make sure the motor is off 175 | 176 | delay(3000); // 3 second delay for recovery 177 | 178 | Serial.begin(115200); 179 | 180 | FastLED.addLeds(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); 181 | // limit power draw to .6A at 5v... Didn't seem to work in my FastLED version though 182 | //FastLED.setMaxPowerInVoltsAndMilliamps(5,DEFAULT_PLIMIT); 183 | FastLED.setBrightness(BRIGHTNESS); 184 | 185 | //Recall saved settings from memory 186 | sensitivity = EEPROM.read(SENSITIVITY_ADDR); 187 | maxSpeed = min(EEPROM.read(MAX_SPEED_ADDR),MOT_MAX); //Obey the MOT_MAX the first power cycle after chaning it. 188 | beep_motor(1047,1396,2093); //Power on beep 189 | } 190 | 191 | //=================================================================================== 192 | //======= LED Drawing Functions 193 | //=================================================================================== 194 | 195 | //Draw a "cursor", one pixel representing either a pressure or encoder position value 196 | //C1,C2,C3 are colors for each of 3 revolutions over the 13 LEDs (39 values) 197 | void draw_cursor_3(int pos,CRGB C1, CRGB C2, CRGB C3){ 198 | pos = constrain(pos,0,NUM_LEDS*3-1); 199 | int colorNum = pos/NUM_LEDS; //revolution number 200 | int cursorPos = pos % NUM_LEDS; //place on circle, from 0-12 201 | switch(colorNum){ 202 | case 0: 203 | leds[cursorPos] = C1; 204 | break; 205 | case 1: 206 | leds[cursorPos] = C2; 207 | break; 208 | case 2: 209 | leds[cursorPos] = C3; 210 | break; 211 | } 212 | } 213 | 214 | //=================================================================================== 215 | //Draw a "cursor", one pixel representing either a pressure or encoder position value 216 | //=================================================================================== 217 | void draw_cursor(int pos,CRGB C1){ 218 | pos = constrain(pos,0,NUM_LEDS-1); 219 | leds[pos] = C1; 220 | } 221 | 222 | //Draw 3 revolutions of bars around the LEDs. From 0-39, 3 colors 223 | void draw_bars_3(int pos,CRGB C1, CRGB C2, CRGB C3){ 224 | pos = constrain(pos,0,NUM_LEDS*3-1); 225 | int colorNum = pos/NUM_LEDS; //revolution number 226 | int barPos = pos % NUM_LEDS; //place on circle, from 0-12 227 | switch(colorNum){ 228 | case 0: 229 | fill_gradient_RGB(leds,0,C1,barPos,C1); 230 | //leds[barPos] = C1; 231 | break; 232 | case 1: 233 | fill_gradient_RGB(leds,0,C1,barPos,C2); 234 | break; 235 | case 2: 236 | fill_gradient_RGB(leds,0,C2,barPos,C3); 237 | break; 238 | } 239 | } 240 | 241 | //Provide a limited encoder reading corresponting to tacticle clicks on the knob. 242 | //Each click passes through 4 encoder pulses. This reduces it to 1 pulse per click 243 | int encLimitRead(int minVal, int maxVal){ 244 | if(myEnc.read()>maxVal*4)myEnc.write(maxVal*4); 245 | else if(myEnc.read() 0){ 262 | volume = (255 - motSpeed) / 10.625; 263 | } else { 264 | volume = 79; // Set Volume to -79 dB Mute 265 | } 266 | pt2257.set_volume(volume); 267 | 268 | 269 | //gyrGraphDraw(avgPressure, 0, 4 * 3 * NUM_LEDS); 270 | int presDraw = map(constrain(arousal, 0, pLimit),0,pLimit,0,NUM_LEDS*3); 271 | draw_bars_3(presDraw, CRGB::Green,CRGB::Yellow,CRGB::Red); 272 | draw_cursor(knob, CRGB::Red); 273 | } 274 | 275 | //=================================================================================== 276 | // Automatic edging mode, knob adjust sensitivity. 277 | //=================================================================================== 278 | void run_auto() { 279 | arousal *= 0.99; 280 | 281 | static float motIncrement = 0.0; 282 | motIncrement = ((float)maxSpeed / ((float)FREQUENCY * (float)rampTimeS)); 283 | int knob = encLimitRead(0,(3*NUM_LEDS)-1); 284 | sensitivity = knob*4; //Save the setting if we leave and return to this state 285 | //Reverse "Knob" to map it onto a pressure limit, so that it effectively adjusts sensitivity 286 | pLimit = map(knob, 0, 3 * (NUM_LEDS - 1), 1, MAX_PLIMIT); //set the limit of arousal before the vibrator turns off 287 | if (pressure < previousPressure) 288 | { 289 | if (pressure > peakStart) 290 | { 291 | if (pressure - peakStart >= sensitivityThreshold / 10) 292 | { 293 | arousal += pressure - peakStart; 294 | } 295 | 296 | } 297 | peakStart = pressure; 298 | } 299 | previousPressure = pressure; 300 | 301 | if (arousal > pLimit) 302 | { 303 | motSpeed = -.5*(float)rampTimeS*((float)FREQUENCY*motIncrement);//Stay off for a while (half the ramp up time) 304 | } 305 | else if (motSpeed < (float)maxSpeed) { 306 | motSpeed += motIncrement; 307 | } 308 | if (motSpeed > MOT_MIN) { 309 | analogWrite(MOTPIN, (int) motSpeed); 310 | 311 | // Set Volume on E-stim From 24-0 dB 312 | if (motSpeed > 0){ 313 | volume = (255 - motSpeed) / 10.625; 314 | } else { 315 | volume = 79; 316 | } 317 | pt2257.set_volume(volume); 318 | 319 | } else { 320 | motSpeed = MOT_MIN; 321 | analogWrite(MOTPIN, 0); 322 | 323 | volume = 79; // Set Volume to -79 dB Mute 324 | pt2257.set_volume(volume); 325 | } 326 | 327 | int presDraw = map(constrain(arousal, 0, pLimit),0,pLimit,0,NUM_LEDS*3); 328 | draw_bars_3(presDraw, CRGB::Green,CRGB::Yellow,CRGB::Red); 329 | draw_cursor_3(knob, CRGB(50,50,200),CRGB::Blue,CRGB::Purple); 330 | } 331 | 332 | //=================================================================================== 333 | //Setting menu for adjusting the maximum vibrator speed automatic mode will ramp up to 334 | //=================================================================================== 335 | void run_opt_speed() { 336 | Serial.println("speed settings"); 337 | int knob = encLimitRead(0,NUM_LEDS-1); 338 | motSpeed = map(knob, 0, NUM_LEDS-1, 0., (float)MOT_MAX); 339 | analogWrite(MOTPIN, motSpeed); 340 | 341 | // Set Volume on E-stim From 24-0 dB 342 | if (motSpeed > 0){ 343 | volume = (255 - motSpeed) / 10.625; 344 | } else { 345 | volume = 79; // Set Volume to -79 dB Mute 346 | } 347 | pt2257.set_volume(volume); 348 | 349 | 350 | maxSpeed = motSpeed; //Set the maximum ramp-up speed in automatic mode 351 | //Little animation to show ramping up on the LEDs 352 | static int visRamp = 0; 353 | if(visRamp <= FREQUENCY*NUM_LEDS-1) visRamp += 16; 354 | else visRamp = 0; 355 | draw_bars_3(map(visRamp,0,(NUM_LEDS-1)*FREQUENCY,0,knob),CRGB::Green,CRGB::Green,CRGB::Green); 356 | } 357 | 358 | //=================================================================================== 359 | //Not yet added, but adjusts how quickly the vibrator turns back on after being triggered off 360 | //=================================================================================== 361 | void run_opt_rampspd() { 362 | Serial.println("rampSpeed"); 363 | } 364 | 365 | //=================================================================================== 366 | //Also not completed, option for enabling/disabling beeps 367 | //=================================================================================== 368 | void run_opt_beep() { 369 | Serial.println("Brightness Settings"); 370 | } 371 | 372 | //=================================================================================== 373 | //Simply display the pressure analog voltage. Useful for debugging sensitivity issues. 374 | //=================================================================================== 375 | void run_opt_pres() { 376 | int p = map(analogRead(BUTTPIN),0,ADC_MAX,0,NUM_LEDS-1); 377 | draw_cursor(p,CRGB::White); 378 | } 379 | 380 | //=================================================================================== 381 | //Poll the knob click button, and check for long/very long presses as well 382 | //=================================================================================== 383 | uint8_t check_button(){ 384 | static bool lastBtn = ENC_SW_DOWN; 385 | static unsigned long keyDownTime = 0; 386 | uint8_t btnState = BTN_NONE; 387 | bool thisBtn = digitalRead(ENC_SW); 388 | 389 | //Detect single presses, no repeating, on keyup 390 | if(thisBtn == ENC_SW_DOWN && lastBtn == ENC_SW_UP){ 391 | keyDownTime = millis(); 392 | } 393 | 394 | if (thisBtn == ENC_SW_UP && lastBtn == ENC_SW_DOWN) { //there was a keyup 395 | if((millis()-keyDownTime) >= V_LONG_PRESS_MS){ 396 | btnState = BTN_V_LONG; 397 | } 398 | else if((millis()-keyDownTime) >= LONG_PRESS_MS){ 399 | btnState = BTN_LONG; 400 | } 401 | else{ 402 | btnState = BTN_SHORT; 403 | } 404 | } 405 | 406 | lastBtn = thisBtn; 407 | return btnState; 408 | } 409 | 410 | //=================================================================================== 411 | //run the important/unique parts of each state. Also, set button LED color. 412 | //=================================================================================== 413 | void run_state_machine(uint8_t state){ 414 | switch (state) { 415 | case MANUAL: 416 | run_manual(); 417 | break; 418 | case AUTO: 419 | run_auto(); 420 | break; 421 | case OPT_SPEED: 422 | run_opt_speed(); 423 | break; 424 | case OPT_RAMPSPD: 425 | run_opt_rampspd(); 426 | break; 427 | case OPT_BEEP: 428 | run_opt_beep(); 429 | break; 430 | case OPT_PRES: 431 | run_opt_pres(); 432 | break; 433 | default: 434 | run_manual(); 435 | break; 436 | } 437 | } 438 | 439 | //=================================================================================== 440 | //Switch between state machine states, and reset the encoder position as necessary 441 | //Returns the next state to run. Very long presses will turn the system off (sort of) 442 | //=================================================================================== 443 | uint8_t set_state(uint8_t btnState, uint8_t state){ 444 | if(btnState == BTN_NONE){ 445 | return state; 446 | } 447 | if(btnState == BTN_V_LONG){ 448 | //Turn the device off until woken up by the button 449 | Serial.println("power off"); 450 | fill_gradient_RGB(leds,0,CRGB::Black,NUM_LEDS-1,CRGB::Black);//Turn off LEDS 451 | FastLED.show(); 452 | analogWrite(MOTPIN, 0); 453 | 454 | volume = 79; 455 | pt2257.set_volume(volume); // Set Volume to -79 dB Mute. 456 | 457 | beep_motor(2093,1396,1047); 458 | analogWrite(MOTPIN, 0); //Turn Motor off 459 | while(!digitalRead(ENC_SW))delay(1); 460 | beep_motor(1047,1396,2093); 461 | return MANUAL ; 462 | } 463 | else if(btnState == BTN_SHORT){ 464 | switch(state){ 465 | case MANUAL: 466 | myEnc.write(sensitivity);//Whenever going into auto mode, keep the last sensitivity 467 | motSpeed = 0; //Also reset the motor speed to 0 468 | return AUTO; 469 | case AUTO: 470 | myEnc.write(0);//Whenever going into manual mode, set the speed to 0. 471 | motSpeed = 0; 472 | EEPROM.update(SENSITIVITY_ADDR, sensitivity); 473 | return MANUAL; 474 | case OPT_SPEED: 475 | myEnc.write(0); 476 | EEPROM.update(MAX_SPEED_ADDR, maxSpeed); 477 | //return OPT_RAMPSPD; 478 | //return OPT_BEEP; 479 | motSpeed = 0; 480 | analogWrite(MOTPIN, motSpeed); //Turn the motor off for the white pressure monitoring mode 481 | volume = 79; 482 | pt2257.set_volume(volume); // Set Volume to -79 dB Mute. 483 | 484 | return OPT_PRES; //Skip beep and rampspeed settings for now 485 | case OPT_RAMPSPD: //Not yet implimented 486 | //motSpeed = 0; 487 | //myEnc.write(0); 488 | return OPT_BEEP; 489 | case OPT_BEEP: 490 | myEnc.write(0); 491 | return OPT_PRES; 492 | case OPT_PRES: 493 | myEnc.write(map(maxSpeed,0,255,0,4*(NUM_LEDS)));//start at saved value 494 | return OPT_SPEED; 495 | } 496 | } 497 | else if(btnState == BTN_LONG){ 498 | switch (state) { 499 | case MANUAL: 500 | myEnc.write(map(maxSpeed,0,255,0,4*(NUM_LEDS)));//start at saved value 501 | return OPT_SPEED; 502 | case AUTO: 503 | myEnc.write(map(maxSpeed,0,255,0,4*(NUM_LEDS)));//start at saved value 504 | return OPT_SPEED; 505 | case OPT_SPEED: 506 | myEnc.write(0); 507 | return MANUAL; 508 | case OPT_RAMPSPD: 509 | return MANUAL; 510 | case OPT_BEEP: 511 | return MANUAL; 512 | case OPT_PRES: 513 | myEnc.write(0); 514 | return MANUAL; 515 | } 516 | } 517 | else return MANUAL; 518 | } 519 | 520 | //=================================================================================== 521 | //======= Main Loop 522 | //=================================================================================== 523 | void loop() { 524 | static uint8_t state = MANUAL; 525 | //Run this section at the update frequency (default 60 Hz) 526 | if (millis() - period > lastUpdate) { 527 | 528 | pressure = analogRead(BUTTPIN); 529 | fadeToBlackBy(leds,NUM_LEDS,20); //Create a fading light effect. LED buffer is not otherwise cleared 530 | uint8_t btnState = check_button(); 531 | state = set_state(btnState,state); //Set the next state based on this state and button presses 532 | run_state_machine(state); 533 | FastLED.show(); //Update the physical LEDs to match the buffer in software 534 | 535 | //Alert that the Pressure voltage amplifier is railing, and the trim pot needs to be adjusted 536 | if(pressure > 4030)beep_motor(2093,2093,2093); //Three high beeps 537 | 538 | //Report pressure and motor data over USB for analysis / other uses. timestamps disabled by default 539 | //Serial.print(millis()); //Timestamp (ms) 540 | //Serial.print(","); 541 | Serial.print(motSpeed); //Motor speed (0-255) 542 | Serial.print(", "); 543 | Serial.print(volume); //E-stim Volume (24-0 dB) 544 | Serial.print(", "); 545 | Serial.print(pressure); //(Original ADC value - 12 bits, 0-4095) 546 | Serial.print(", "); 547 | Serial.println(constrain(100 * arousal/ (float)pLimit, 0, 100)); 548 | lastUpdate = millis(); 549 | } 550 | } 551 | --------------------------------------------------------------------------------