mbed Phone Platform

Dependencies:   ulaw mbed ConfigFile

Line.cpp

Committer:
okini3939
Date:
2011-01-21
Revision:
6:bd62b12de751
Parent:
5:30e2847d241b

File content as of revision 6:bd62b12de751:

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

#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;
    hooktimer2 = 0;
    hook_last = hook;
}

/**
 * @brief 8KHz interrupt
 */
void Line::intr () {

    switch (mode) {
    case ModeRing:
        ring();
        break;

    case ModeDT:
        tone(DialTone);
        break;

    case ModeRBT:
        tone(RingBackTone);
        break;

    case ModeBT:
        tone(BusyTone);
        break;

    }

    if (hook) {
        // off hook
        if (hooktimer) hooktimer --;

        if (! hook_last && (dialcount > 0 || hooktimer2 >= DIAL_TIME)) {
            // dial trigger
            dialtimer = DIAL_TIME;
            dialcount ++;
            hooktimer2 = 0;
        }
    } else {
        // on hook
        hooktimer = HOOK_TIME;
        hooktimer2 ++;
    }
    hook_last = hook;

    if (dialtimer) {
        dialtimer --;

        if (dialtimer == 0 && dialcount && ! hook) {
            // dial detected
            dial.put(dialcount);
            dialcount = 0;
        }
    } else {
        dialcount = 0;
    }
}

void Line::poll () {
}

/**
 * @brief change mode
 * @param newmode mode of line
 * @retval 0 ok
 */
int Line::enter (enum Mode newmode) {

    // cleanup
    switch (mode) {
    case ModeRing:
    case ModeOff:
        power(1);
        break;

    case ModeDT:
    case ModeRBT:
    case ModeBT:
        dac.write_u16(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;
}

/**
 * @brief return status
 * @param type Type of status
 * @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;
}

/**
 * @brief power of line
 * @param flg 0:off, 1:on(positive), -1:on(negative)
 */
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 && (tonecount % RING_PULSE) < (RING_PULSE / 2)) ||
      (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;
    }
}