Making Furniture Interactive

October 2, 2007

Assignment 4 | 1-900

Filed under: Exercise 4: Four State Machines,Matt Thompson — Mattt Thompson @ 3:45 am

Long in coming, this is a phone that serves no other purpose than to be pleased. By circuit-bending a conventional land-line telephone, I was able to repurpose the ringer to play “Afternoon Delight” and the victory theme from Final Fantasy, which respectively entice and reward the enterprising user of this kinky phone.

Most of the state transfer is triggered on the software level, with the source of input being the state of the switch from the hook: you pick up the hook and the phone stops ringing and enters the arousal state, from which you get to the reward state by mashing on the hook.

Being as fragile as it was, I just wanted to get documentation of it working before trying to put it together and possibly losing everything. Anyway, below is the code for this mofo.

// 1-900
// 48-570 | Assignment 4
// Mattt Thompson

int ringerPin = 9;
int buzzerPin = 10;
int hookPin = 12;

#define SLEEP   1
#define ATTRACT 2
#define AROUSE  3
#define REWARD  4

int ringCount = 0;

int prevHookState = 0;
int currentHookState = 0;

float energy = 0;

#define SLEEP_DURATION  1000
#define RING_DURATION   1000

int state = SLEEP;

void setup()
{
  Serial.begin(9600);

  pinMode(ringerPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(hookPin, INPUT);
}

void loop()
{
  Serial.println(state);
  setState();
  switch(state)
  {
  case SLEEP:
    sleep();
    break;
  case ATTRACT:
    attract();
    break;
  case AROUSE:
    arouse();
    break;
  case REWARD:
    reward();
    break;
  default:
    // Nothing...
    break;
  }
}

void setState()
{
  if(! hookIsDepressed() || state == AROUSE)
  {
    if(buzzerIsSpent())
    {
      stopBloodyBuzzing();
      state = REWARD;
    }
    else
    {
     state = AROUSE;
    }
  }
  else
  {
    if(ringCount > 1)
    {
      ringCount = 0;
      state = SLEEP;
    }
    else
    {
      state = ATTRACT;
    }
  }
}

void sleep()
{
  delay(4000);
  state = ATTRACT;
}

void reward()
{
  energy = 0;
  victory();
  state = SLEEP;
}

void attract()
{
  ring();
}

void arouse()
{
  buzz();
}

boolean buzzerIsSpent()
{
  return energy > 250;
}

void buzz()
{
  currentHookState = digitalRead(hookPin);
  if(currentHookState != prevHookState)
  {
    energy += 1.0;
  }
  else
  {
    energy -= 0.4;
  }
  energy = constrain(energy, 0.0, 255);
  analogWrite(buzzerPin, energy);
}

void stopBloodyBuzzing()
{
 analogWrite(buzzerPin, 0);
}

boolean buzzerIsSpent()
{
  return energy > 250;
}

void buzz()
{
  currentHookState = digitalRead(hookPin);
  if(currentHookState != prevHookState)
  {
    energy += 1.0;
  }
  else
  {
    energy -= 0.4;
  }
  energy = constrain(energy, 0.0, 255);
  analogWrite(buzzerPin, energy);
}

void stopBloodyBuzzing()
{
 analogWrite(buzzerPin, 0);
}

/*
 * How to convert music notes into PWM signals:
 *
 * Note 	Frequency 	Period 	PW (timeHigh)
 * c 	        261 Hz 	        3830 	1915
 * d 	        294 Hz 	        3400 	1700
 * E (eb)	311 Hz	        3214 	1607
 * e 	        329 Hz 	        3038 	1519
 * f 	        349 Hz 	        2864 	1432
 * g 	        392 Hz 	        2550 	1275
 * a 	        440 Hz 	        2272 	1136
 * b 	        493 Hz 	        2028	1014
 *
 * Credit: D. Cuartielles from the example code. Brilliant stuff!
 */

#define RING    1
#define VICTORY 2

byte names[] = {'c', 'd', 'e', 'f', 'g', 'a', 'b', 'E'};
int tones[] = {1915, 1700, 1519, 1432, 1275, 1136, 1014, 1607};
byte ringMelody[]   = "2c2p2c2p4e2p4g2p2g1p2e1p2g1p2e2p4a2p4g2p6g8p8p8p8p8p8p";
byte victoryMelody[] = "2g1p2g1p2g1p6E3p5f3p3g1p2f3p5g8p8p8p8p8p8p";

int count1 = 0;
int count2 = 0;
int count3 = 0;
int MAX_COUNT = 24;
int statePin = LOW;

void play(byte melody[]) {
  ringCount++;
  digitalWrite(ringerPin, LOW);
  for (count1 = 0; count1 < MAX_COUNT; count1++) {
    statePin = !statePin;
    for (count3 = 0; count3 <= (melody[count1*2] - 48) * 30; count3++) {
      for (count2=0;count2<8;count2++) {
        if (names[count2] == melody[count1*2 + 1]) {
          digitalWrite(ringerPin,HIGH);
          delayMicroseconds(tones[count2]);
          digitalWrite(ringerPin, LOW);
          delayMicroseconds(tones[count2]);
        }
        if (melody[count1*2 + 1] == 'p') {
          // make a pause of a certain size
          digitalWrite(ringerPin, 0);
          delayMicroseconds(100);
        }
      }
    }
  }
}

void ring()
{
 play(ringMelody);
}

void victory()
{
 play(victoryMelody);
}

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: