mbed Phone Platform

Dependencies:   ulaw mbed ConfigFile

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;
+	}
+}