#define F_CPU 1000000 #include #include #include #define TIMER_SNAPSHOT_MS() ((ticks << 8) | TCNT0) #define DIAL_DELAY 4500 // How much time to allow for dialing (ms) #define DEB_DELAY 2 // Debounce delay // Variable declarations volatile int call_recipient; // The recipient of the phone call volatile int caller; // The caller volatile int dial_var; // The number of pulses received by the caller phone volatile uint32_t ticks; volatile uint32_t DialTimeSnapshot; volatile uint32_t DebounceSnapshot; /* Interrupt service routine to keep track of time */ ISR(TIMER0_OVF_vect) { ticks++; return; } /* Interrupt service routine for pulse dialing sensing * Increments dial_var for each pulse received */ ISR(PCINT_vect) { if ((TIMER_SNAPSHOT_MS() - DebounceSnapshot) >= DEB_DELAY) { dial_var++; DebounceSnapshot = TIMER_SNAPSHOT_MS(); } return; } /* Initialise I/O ports */ void ioinit(void) { // Setup outputs DDRB |= (1 << PB4); // Ringer output for telephone 1 DDRB |= (1 << PB5); // Ringer output for telephone 2 DDRB |= (1 << PB6); // Ringer output for telephone 3 DDRB |= (1 << PB7); // Ringer output for telephone 4 DDRD |= (1 << PD0); // Voice path activation output for telephone 1 DDRD |= (1 << PD1); // Voice path activation output for telephone 2 DDRD |= (1 << PD2); // Voice path activation output for telephone 3 DDRD |= (1 << PD3); // Voice path activation output for telephone 4 DDRD |= (1 << PD4); // Special function 6 DDRD |= (1 << PD5); // Special function 5 DDRD |= (1 << PD6); // Special function 7 DDRA |= (1 << PA0); // Special function 8 DDRA |= (1 << PA1); // Special function 9 // Make sure no telephone is ringing, nor connected to the voice path // and that all special function outputs are off PORTB &= ~ _BV(4); // Ringer output for telephone 1 PORTB &= ~ _BV(5); // Ringer output for telephone 2 PORTB &= ~ _BV(6); // Ringer output for telephone 3 PORTB &= ~ _BV(7); // Ringer output for telephone 4 PORTD &= ~ _BV(0); // Voice path activation output for telephone 1 PORTD &= ~ _BV(1); // VOice path activation output for telephone 2 PORTD &= ~ _BV(2); // Voice path activation output for telephone 3 PORTD &= ~ _BV(3); // Voice path activation output for telephone 4 PORTD &= ~ _BV(4); // Special function 6 PORTD &= ~ _BV(5); // Special function 5 PORTD &= ~ _BV(6); // Special function 7 PORTA &= ~ _BV(0); // Special function 8 PORTA &= ~ _BV(1); // Special function 9 // Enable internal pull-ups PORTB |= _BV(0); // Off-hook detection, and pulse dialing for telephone 1 PORTB |= _BV(1); // Off-hook detection, and pulse dialing for telephone 2 PORTB |= _BV(2); // Off-hook detection, and pulse dialing for telephone 3 PORTB |= _BV(3); // Off-hook detection, and pulse dialing for telephone 4 // Enable interrupts for PB0-PB3 (offhook, and pulse dialing detection) GIMSK |= _BV(PCIE); sei(); // Reset variables caller = 0; call_recipient = 0; dial_var = 0; DialTimeSnapshot = 0; DebounceSnapshot = 0; return; } /* Initiate the timer */ void timer_init(void) { TCCR0B = _BV(CS02) | _BV(CS00); /* set prescaler to use clock/1024 */ TIMSK = _BV(TOIE0); /* enable the overflow interrupt */ ticks = 0; } // Ring the telephone void ring(int times, int phone) { int i; for(i=0;i 0) { _delay_ms(DIAL_DELAY); PCMSK &= ~ _BV(PCINT0); PCMSK &= ~ _BV(PCINT1); PCMSK &= ~ _BV(PCINT2); PCMSK &= ~ _BV(PCINT3); call_recipient = dial_var / 2; dial_var = 0; } // If a telephone has dialed a number associated with another phone if ((call_recipient > 0) && (call_recipient < 5)) { // As long the recipient doesn't answer, and the caller doesn't give up while ((PINB & _BV(-1 + call_recipient)) && !(PINB & _BV(-1 + caller))) { // Ring the phone ring(2, call_recipient); _delay_ms(500); } // Check if both parties are still on the line if (!(PINB & _BV(-1 + call_recipient)) && !(PINB & _BV(-1 + caller))) { // Both parties are on the line // Provide a short delay _delay_ms(300); // Then connect the call PORTD |= _BV(-1 + caller); _delay_ms(100); PORTD |= _BV(-1 + call_recipient); } // Wait for the call to be over while (!(PINB & _BV(-1 + call_recipient)) && !(PINB & _BV(-1 + caller))) { _delay_ms(1); } // Then disconnect the call _delay_ms(500); PORTD &= ~ _BV(-1 + caller); _delay_ms(100); PORTD &= ~ _BV(-1 + call_recipient); } else if (call_recipient == 6) { /* If the dialled number is any of the special functions, * activate/deactivate the corresponding GPIO output. * When dealing with numbers greater than 9, remember, * call_recipient contains a count of pulses. Thus, * if 51 was dialled, call_recipient would contain * the value of 5 + 1, thus 6, and NOT 51. The digit 0 * is equal to 10 pulses */ PORTD |= _BV(5); } else if (call_recipient == 15) { PORTD &= ~ _BV(5); } else if (call_recipient == 7) { PORTD |= _BV(4); } else if (call_recipient == 16) { PORTD &= ~ _BV(4); } else if (call_recipient == 8) { PORTD |= _BV(6); } else if (call_recipient == 17) { PORTD &= ~ _BV(6); } else if (call_recipient == 9) { PORTA |= _BV(0); } else if (call_recipient == 18) { PORTA &= ~ _BV(0); } else if (call_recipient == 10) { PORTA |= _BV(1); } else if (call_recipient == 19) { PORTA &= ~ _BV(1); } // Reset the variables caller = 0; call_recipient = 0; } // We will never get here return 0; }