mbed Phone Platform

Dependencies:   ulaw mbed ConfigFile

IpLine.cpp

Committer:
okini3939
Date:
2011-01-05
Revision:
2:e37117117e79
Parent:
1:0f82c574096f
Child:
3:1d5dc4107558

File content as of revision 2:e37117117e79:

/** @file IpLine.cpp
 * @brief IP Line Controller (mbed Phone Platform)
 */

#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;
//    eth = new EthernetNetIf(IpAddr(192,168,10,200), IpAddr(255,255,255,0), IpAddr(0,0,0,0), IpAddr(0,0,0,0));
    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::intr () {
    char c;

    if (mode == ModeTalk && hook == HookOn) {
        // 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()));
        adbuf.put(adc.read_u16() >> 8);
    }

    if (timeout) {
        timeout --;

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

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

    Net::poll();

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

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

/// 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;
printf("(ack %d)\r\n", status);
        }

    } else
    if (packet.header.mode == ModeData && len > sizeof(struct ipline_header)) {
        // data

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

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

        switch (packet.header.mode) {
        case ModeRing:
            // ring --> onhook, dial
            if (mode == ModeReady) {
                dial.put(1);
                dial.put(10);
                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 = NET_RETRY;

      for (int i = 0; i < len; i ++) {
        printf(" %02x", ((char *)&packet)[i]);
      }
      printf("(R)\r\n");
    }
}


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

    if (! header->num) {
        header->num = packet_num;
        packet_num ++;
        if (packet_num >= 65536) packet_num = 1;
    }
    udpsock->sendto((char *)header, sizeof(struct ipline_header), &remote);
    memcpy(&last, header, sizeof(struct ipline_header));

    for (int i = 0; i < sizeof(struct ipline_header); i ++) {
        printf(" %02x", ((char *)header)[i]);
    }
    printf("(H)\r\n");
}

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

    if (! packet->header.num) {
        packet->header.num = packet_num;
        packet_num ++;
        if (packet_num >= 65536) packet_num = 1;
    }
    udpsock->sendto((char *)packet, sizeof(struct ipline_packet), &remote);
}

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

    mode = newmode;
    status = StatusOk;

    switch (mode) {
    case ModeReady:
        hook = HookOff;
        break;

    case ModeBT:
    case ModeDisconnect:
        hook = HookOff;
    case ModeRing:
    case ModeTalk:
        status = StatusNone;
        header.num = 0;
        header.target = remotetarget;
        header.mode = mode;
        header.status = status;
        send(&header);
        timeout = NET_RETRY;
        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);
}