mbed Phone Platform

Dependencies:   ulaw mbed ConfigFile

IpLine.cpp

Committer:
okini3939
Date:
2010-12-26
Revision:
1:0f82c574096f
Child:
2:e37117117e79

File content as of revision 1:0f82c574096f:

#include "IpLine.h"


IpLine::IpLine (AnalogOut p_dac, AnalogIn p_adc) : dac(p_dac), adc(p_adc), dial(DIAL_SIZE), dabuf(DATA_SIZE * 4), adbuf(DATA_SIZE * 2) {
	EthernetErr r;

	mode = ModeOff;
	status = StatusOk;
	timeout = 0;
	packet_num = 0;
	dataskip = 0;

	// dhcp
	eth = new EthernetNetIf;
	r = eth->setup();
	if (r) {
		printf("Error %d in setup.\n", r);
		return;
	}

	udpsock = new UDPSocket;
	udpsock->setOnEvent(this, &IpLine::onLisnerEvent);
	udpsock->bind(Host(eth->getIp(), UDPPORT));
}

/// 8KHz interrupt
void IpLine::poll () {
	char c;

	if (mode == ModeTalk && hook) {
		// dac
		if (dabuf.available() < DATA_SIZE) {
			// down sample
			dabuf.get(c);
			dabuf.get(c);
			dac.write_u16(ulaw2pcm(c));
		} else
		if (dabuf.use() < DATA_SIZE) {
			// over sample
			if (dataskip) {
				dataskip = 0;
			} else {
				if (! dabuf.get(c)) {
					dac.write_u16(ulaw2pcm(c));
				} else {
//					dac.write_u16(gaussian());
				}
				dataskip = 1;
			}
		} else {
			// normal
			dabuf.get(c);
			dac.write_u16(ulaw2pcm(c));
		}

		// adc
		adbuf.put(pcm2ulaw(adc.read_u16()));
	}

	if (timeout) {
		timeout --;

		if (timeout == 0) {
			if (last.target) {
				// re-try
				send(last);
				timeout = FREQ;
				last.target = PhoneNone;
			} else {
				// timeout
				status = StatusNg;
			}
		}
	}
}

/// network
void IpLine::netpoll () {

	if (mode == ModeTalk && adbuf.use() >= DATA_SIZE) {
		// send
		struct ipline_packet packet;

		packet.len = adbuf.get(packet.data, sizeof(packet.data));
		if (packet.len > 0) {
			packet.header.target = remotetarget;
			packet.header.mode = ModeData;
			packet.header.status = StatusNone;
			send(packet);
		}
	}

	Net::poll();
}

/// recv packet
void IpLine::onLisnerEvent (UDPSocketEvent e) {
	int len;
	struct ipline_packet packet;
	Host recv;

	if (e != UDPSOCKET_READABLE) return;

	// get data
	len = udpsock->recvfrom((char *)&packet, sizeof(packet), &recv);

	if (packet.header.status != StatusNone) {
		// recv ack
		if (packet.header.num == last.num) {
			status = packet.header.status;
			timeout = 0;
		}

	} else
	if (packet.header.mode == ModeData) {
		// data

		dabuf.put(packet.data, packet.len);

	} else
	if (mode == ModeTalk && len > sizeof(struct ipline_header)) {
		// enter
		packet.header.status = StatusNg;

		switch (packet.header.mode) {
		case ModeRing:
			// ring --> onhook, dial
			if (mode == ModeReady) {
				dial.put(11);
				dial.put(packet.header.target);
				dial.put(12);
				hook = HookOn;
				remote = recv;
				packet.header.status = StatusOk;
			}
			break;
		case ModeBT:
		case ModeDisconnect:
			if (recv.getIp() == remote.getIp()) {
				hook = HookOff;
				packet.header.status = StatusOk;
			}
			break;
		case ModeTalk:
			if (recv.getIp() == remote.getIp()) {
				hook = HookOn;
				packet.header.status = StatusOk;
			}
			break;
		}

		// send ack
		send(packet.header);
		timeout = FREQ;
	}
}


/// send packet (header only)
void IpLine::send (struct ipline_header &header) {

	header.num = packet_num;
	udpsock->sendto((char *)&header, sizeof(header), &remote);
	memcpy(&last, &header, sizeof(last));

	packet_num ++;
	if (packet_num >= 65536) packet_num = 1;
}

/// send packet
void IpLine::send (struct ipline_packet &packet) {

	packet.header.num = packet_num;
	udpsock->sendto((char *)&packet, sizeof(packet), &remote);

	packet_num ++;
	if (packet_num >= 256) packet_num = 0;
}

/// change mode
int IpLine::enter (enum Mode newmode) {
	struct ipline_header header;

	mode = newmode;
	status = StatusOk;

	switch (mode) {
	case ModeReady:
		hook = HookOff;
		break;
	case ModeRing:
	case ModeTalk:
	case ModeBT:
	case ModeDisconnect:
		status = StatusNone;
		header.target = remotetarget;
		header.mode = mode;
		header.status = status;
		send(header);
		timeout = FREQ;
		break;
	}

	return 0;
}

/// return status
int IpLine::scan (enum Scan type) {

	switch (type) {
	case ScanMode:
		return mode;

	case ScanStatus:
		return status;

	case ScanHook:
		return hook;

	case ScanDial:
		char c;
		if (dial.get(c) == 0)
			return c;
		break;

	}

	return -1;
}

/// set target
void IpLine::settarget (enum PhoneType target, char *host) {
    int ip0, ip1, ip2, ip3;

	remotetarget = target;
	if (host[0] >= '0' && host[0] <= '9') {
		sscanf(host, "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3);
		remote.setIp(IpAddr(ip0, ip1, ip2, ip3));
		remote.setName(NULL);
	} else {
		remote.setIp(NULL);
		remote.setName(host);
	}
	remote.setPort(UDPPORT);
}