mbed Phone Platform
Dependencies: ulaw mbed ConfigFile
Diff: Line.cpp
- Revision:
- 0:f18953137cb4
- Child:
- 1:0f82c574096f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Line.cpp Mon Dec 20 22:55:29 2010 +0000 @@ -0,0 +1,214 @@ +#include "Line.h" + +#define RING_ON FREQ +#define RING_OFF (FREQ * 3) +#define RING_PULSE (FREQ / 16) +#define TONE_DT (FREQ / 400) +#define TONE_RBT_ON FREQ +#define TONE_RBT_OFF (FREQ * 3) +#define TONE_BT_ON (FREQ / 2) +#define TONE_BT_OFF FREQ +#define HOOK_TIME FREQ +#define DIAL_TIME (FREQ / 2) + +const unsigned short tonetable[TONE_DT] = { + 0x7fff, 0x98f4, 0xaf78, 0xc156, 0xcccf, 0xd0c3, 0xcccf, 0xc156, 0xaf78, 0x98f4, + 0x7fff, 0x6709, 0x5085, 0x3ea7, 0x332e, 0x2f3a, 0x332e, 0x3ea7, 0x5085, 0x6709 +}; + +Line::Line (PinName p_line, PinName p_xline, PinName p_hook, AnalogOut p_dac) : line(p_line), xline(p_xline), hook(p_hook), dac(p_dac), dial(DIAL_SIZE) { + hook.mode(PullUp); + mode = ModeOff; + status = StatusOk; + dialtimer = 0; + dialcount = 0; + hooktimer = 0; + tonecount = 0; + hook_last = hook; +} + +/// 8KHz interrupt +void Line::poll () { + + switch (mode) { + case ModeRing: + ring(); + break; + + case ModeDT: + tone(DialTone); + break; + + case ModeRBT: + tone(RingBackTone); + break; + + case ModeDisconnect: + tone(BusyTone); + break; + + } + + if (hook) { + // off hook + if (hooktimer) hooktimer --; + + if (! hook_last) { + // dial trigger + dialtimer = DIAL_TIME; + dialcount ++; + } + } else { + // on hook + hooktimer = HOOK_TIME; + } + hook_last = hook; + + if (dialtimer) { + dialtimer --; + + if (dialtimer == 0 && dialcount && ! hook) { + // dial detected + dial.put(dialcount); + dialcount = 0; + } + } else { + dialcount = 0; + } +} + +/// change mode +int Line::enter (enum Mode newmode) { + + // cleanup + switch (mode) { + case ModeRing: + case ModeOff: + power(1); + break; + + case ModeDT: + case ModeRBT: + case ModeBT: + dac = 0x7fff; + break; + + } + + mode = newmode; + + switch (mode) { + case ModeReady: + // ready + power(1); + status = StatusOk; + break; + + case ModeDT: + case ModeRBT: + case ModeBT: + // tone + tonecount = 0; + status = StatusOk; + break; + + case ModeOff: + // suspend + power(0); + status = StatusOk; + break; + + default: + status = StatusOk; + break; + + } + + return 0; +} + +/// return status +int Line::scan (enum Scan type) { + + switch (type) { + case ScanMode: + return (int)mode; + + case ScanStatus: + return (int)status; + + case ScanHook: + return hooktimer ? HookOn : HookOff; + + case ScanDial: + char c; + if (! dial.get(c)) { + return c; + } + break; + + } + + return -1; +} + +/// controll power +void Line::power (int flg) { + if (flg > 0) { + xline = 0; + wait_ms(1); + line = 1; + } else + if (flg < 0) { + line = 0; + wait_ms(1); + xline = 1; + } else { + line = 0; + xline = 0; + } +} + +/// ring +void Line::ring () { + if (hook && tonecount < RING_ON) { + // off hook + switch (tonecount % RING_PULSE) { + case 0: + Line::power(0); + break; + case RING_PULSE / 10: + Line::power(-1); + break; + case RING_PULSE / 2: + Line::power(0); + break; + case RING_PULSE / 2 + RING_PULSE / 10: + Line::power(1); + break; + } + } + + tonecount ++; + if (tonecount >= RING_OFF) tonecount = 0; +} + +/// tone +void Line::tone (enum Tone type) { + if (! hook && ( type == DialTone || + (type == RingBackTone && tonecount < TONE_RBT_ON) || + (type == BusyTone && tonecount < TONE_BT_ON) ) ) { + // on hook + dac.write_u16(tonetable[tonecount % TONE_DT]); + } else { + // off hook + dac.write_u16(0x7fff); + } + + tonecount ++; + if ( (type == DialTone && tonecount >= TONE_DT) || + (type == RingBackTone && tonecount >= TONE_RBT_OFF) || + (type == BusyTone && tonecount >= TONE_BT_OFF) ) { + tonecount = 0; + } +}