⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lm.c

📁 Linmodem is soft modem source code for embedded system
💻 C
字号:
/*  * The Generic Linux Soft Modem *  * Copyright (c) 1999,2000 Fabrice Bellard. * Copyright (c) 1999 Pavel Machek * * This code is released under the GNU General Public License version * 2. Please read the file COPYING to know the exact terms of the * license. *  * This implementation is totally clean room. It was written by * reading the ITU specification and by using basic signal processing * knowledge.   */#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/time.h>#include <signal.h>#include "lm.h"#include "v34.h"#include "v90.h"#define DEBUGint lm_debug = 0;int debug_state = 0;/* default parameters */static LinModemConfig default_lm_config = {    pulse_dial: 0,    dtmf_level: -9,     dtmf_digit_length: 150,    dtmf_pause_length: 100,    available_modulations: V8_MOD_V21 | V8_MOD_V23,};/* fifo handling */void sm_init_fifo(struct sm_fifo *f, u8 *buf, int size){    f->sptr = buf;    f->eptr = buf + size;    f->wptr = f->rptr = f->sptr;    f->size = 0;    f->max_size = size;}void sm_flush(struct sm_fifo *f){    f->wptr = f->rptr = f->sptr;    f->size = 0;}int sm_size(struct sm_fifo *f){    return f->size;}void sm_put_bit(struct sm_fifo *f, int v){    if (f->size < f->max_size) {        *f->wptr++ = v;        if (f->wptr == f->eptr) f->wptr = f->sptr;        f->size++;    }}/* put bits, from MSB to LSB */void sm_put_bits(struct sm_fifo *f, int v, int n){    int i;    for(i=n-1;i>=0;i--) {        sm_put_bit(f, (v >> i) & 1);    }}int sm_peek_bit(struct sm_fifo *f){    if (f->size > 0)	return *f->rptr;    else	return -1;}int sm_get_bit(struct sm_fifo *f){    int v;        if (f->size > 0) {        f->size--;        v = *f->rptr++;        if (f->rptr == f->eptr) f->rptr = f->sptr;        return v;    } else {        /* fifo empty */        return -1;    }}/* return -1 if not enough bits */int sm_get_bits(struct sm_fifo *f, int n){    int v,i;    if (f->size < n)        return -1;    v = 0;    for(i=n-1;i>=0;i--) {        v |= (sm_get_bit(f) << i);    }    return v;}/* timer handling *//* note: the current time handling is horrible because we use a global   state which is initialized when entering in sm_process() */static unsigned int sim_time;/* current time, in samples */int sm_time(void){    return sim_time;}/* delay is in ms */void sm_set_timer(struct sm_timer *t, int delay){    t->timeout = sm_time() + (delay * 8000) / 1000;}/* return 1 if timer expired */int sm_check_timer(struct sm_timer *t){    long timeout;        timeout = sm_time();    return (timeout >= t->timeout);}/*    Main modem state machine. It handles the dialing & rings, and then   call the corresponding protocol handlers.   */char *sm_states_str[] = {#define TAG(s) #s ,#include "lmstates.h"};static int dtmf_get_digit(void *opaque){    struct sm_state *sm = opaque;    if (sm->dtmf_ptr < sm->dtmf_len) {        return sm->call_num[sm->dtmf_ptr++];    } else {        return -1;    }}static void dtmf_put_digit(void *opaque, int digit){    printf("DTMF: got digit '%c'\n", digit);}void sm_process(struct sm_state *sm, s16 *output, s16 *input, int nb_samples){    /* XXX: time hack */    sim_time = sm->time;    /* modulation */    switch(sm->state) {    case SM_DTMF_DIAL_WAIT:    case SM_DTMF_DIAL_WAIT1:        DTMF_mod(&sm->dtmf_tx, output, nb_samples);        break;    default:        memset(output, 0, nb_samples * sizeof(s16));        break;    }    /* demodulation */    switch(sm->state) {    case SM_TEST_RING2:        DTMF_demod(&sm->dtmf_rx, input, nb_samples);        break;    }    /* write state transition */    if (lm_debug) {        if (sm->state != sm->debug_laststate) {            sm->debug_laststate = sm->state;            printf("%s: state: %s\n", sm->name, sm_states_str[sm->state]);        }    }    switch(sm->state) {                /* nothing to do (except waiting for a connection) */    case SM_IDLE:        break;    case SM_GO_ONHOOK:        {            sm->hw->set_offhook(sm->hw_state, 0);            sm->state = SM_IDLE;        }        break;        /* calling modem */    case SM_CALL:        {            sm->calling = 1;            sm->hangup_request = 0;            sm->state = SM_DTMF_DIAL;            sm->hw->set_offhook(sm->hw_state, 1);	    sm_set_timer(&sm->dtmf_timer, 2000);        }        break;    case SM_DTMF_DIAL:        if (sm->hangup_request) {            sm->state = SM_GO_ONHOOK;        } else if (sm_check_timer(&sm->dtmf_timer)) {            DTMF_mod_state *p = &sm->dtmf_tx;            sm->dtmf_ptr = 0;            sm->dtmf_len = strlen(sm->call_num);            p->get_digit = dtmf_get_digit;            p->opaque = sm;            p->dtmf_level = sm->lm_config->dtmf_level;             p->digit_length_ms = sm->lm_config->dtmf_digit_length;             p->digit_pause_ms = sm->lm_config->dtmf_pause_length;            DTMF_mod_init(p);            sm->state = SM_DTMF_DIAL_WAIT;        }        break;    case SM_DTMF_DIAL_WAIT:        {            if (sm->dtmf_ptr >= sm->dtmf_len) {                /* wait some time after dialing */                sm_set_timer(&sm->dtmf_timer, 1000);                sm->state = SM_DTMF_DIAL_WAIT1;             }        }        break;    case SM_DTMF_DIAL_WAIT1:        {            if (sm_check_timer(&sm->dtmf_timer)) {                /* start of V8 */                V8_init(&sm->u.v8_state, 1, sm->lm_config->available_modulations);                sm->state = SM_V8;            }        }        break;        /* answer modem */        /* wait 2 sec until ring detected (for simulation only) */        /* we try to recognize the DTMF value for fun :-) */    case SM_TEST_RING:        {            sm->calling = 0;            sm->dtmf_rx.opaque = sm;            sm->dtmf_rx.put_digit = dtmf_put_digit;            DTMF_demod_init(&sm->dtmf_rx);            sm_set_timer(&sm->ring_timer, 5000);             sm->state = SM_TEST_RING2;        }        break;    case SM_TEST_RING2:        {            if (sm_check_timer(&sm->ring_timer)) {                sm->state = SM_RECEIVE;            }        }        break;        /* entry point to receive a connection */    case SM_RECEIVE:        {            sm->calling = 0;            sm->hangup_request = 0;            sm->hw->set_offhook(sm->hw_state, 1);            V8_init(&sm->u.v8_state, 0, sm->lm_config->available_modulations);            sm->state = SM_V8;        }        break;        /* V8 handling (both calling & receive) */    case SM_V8:        {            int ret;            if (sm->hangup_request) {                printf("ddezde\n");                sm->state = SM_GO_ONHOOK;            } else {                ret = V8_process(&sm->u.v8_state, output, input, nb_samples);                switch(ret) {                case V8_MOD_HANGUP:                    sm->state = SM_GO_ONHOOK;                    break;                case V8_MOD_V21:                    V21_init(&sm->u.v21_state, sm->calling,                             serial_get_bit, serial_put_bit, sm);                    sm->state = SM_V21;                    break;                case V8_MOD_V23:                    V23_init(&sm->u.v23_state, sm->calling,                             serial_get_bit, serial_put_bit, sm);                    sm->state = SM_V23;                    break;                }            }        }        break;        /* V21 handling (both calling & receive) */    case SM_V21:        {            int ret;            ret = V21_process(&sm->u.v21_state, output, input, nb_samples);            if (ret || sm->hangup_request)                sm->state = SM_GO_ONHOOK;        }        break;        /* V23 handling (both calling & receive) */    case SM_V23:        {            int ret;            ret = V23_process(&sm->u.v23_state, output, input, nb_samples);            if (ret || sm->hangup_request)                sm->state = SM_GO_ONHOOK;        }        break;    }    /* XXX: time hack */    sm->time = sim_time + nb_samples;}/* * Send a dial request. */int lm_start_dial(struct sm_state *s, int pulse, const char *number){    if (s->state != SM_IDLE)        return -1;    s->pulse_dial = pulse;    strcpy(s->call_num, number);    s->state = SM_CALL;    return 0;}/* * Send a receive request (for example to respond to a ring) */int lm_start_receive(struct sm_state *s){    if (s->state != SM_IDLE)        return -1;    s->state = SM_RECEIVE;    return 0;}/*  * disconnect the modem */int lm_hangup(struct sm_state *s){    if (s->state == SM_IDLE)        return -1;    s->hangup_request = 1;    return 0;}/*  * return a simplified state of the modem. */enum lm_get_state_val lm_get_state(struct sm_state *s){    switch(s->state) {    case SM_IDLE:        return LM_STATE_IDLE;    case SM_V21:    case SM_V23:         return LM_STATE_CONNECTED;    default:        return LM_STATE_CONNECTING;    }}void lm_init(struct sm_state *sm, struct sm_hw_info *hw, const char *name){    memset(sm, 0, sizeof(*sm));    sm->hw = hw;      /* pretty name */    strcpy(sm->name, name);        /* init fifos */    sm_init_fifo(&sm->tx_fifo, sm->tx_fifo_buf, SM_FIFO_SIZE);    sm_init_fifo(&sm->rx_fifo, sm->rx_fifo_buf, SM_FIFO_SIZE);        /* we open the hardware driver */    sm->hw_state = malloc(sizeof(struct lm_interface_state));     sm->hw_state->sm = sm;    sm->hw->open(sm->hw_state);        sm->debug_laststate = -1;    sm->state = SM_IDLE;    /* config */    sm->lm_config = &default_lm_config;}void sigusr1_debug(int dummy){    printf( "<<<Debugging signal came>>>\n" );    debug_state = 1;}void help(void){    printf("Linux Generic Software Modem\n"           "Copyright (c) 1999, 2000 Fabrice Bellard\n"           "\n"           "usage: lm [options]"           "Test options:\n"           "-v : verbose mode (additive)\n"           "-s : modem test with the line simulator\n"           "-m mod: test the modulation 'mod'. 'mod' can be:\n"           "        v21, v23, v22, v34, v90\n"           "\n"           "Sound card support\n"           "-t : use sound card as modem\n"           "\n"           "LTmodem support:\n"           "-a : test answer mode with ltmodem\n"           "-c command: use 'command' as modem driver\n"           "-d number: dial 'number'\n"           );}enum {    MODE_NONE,    MODE_LINESIM,    MODE_V21TEST,    MODE_V22TEST,    MODE_V23TEST,    MODE_V34TEST,    MODE_V90TEST,    MODE_LTMODEM_CALL,    MODE_LTMODEM_ANSWER,    MODE_SOUNDCARD,};extern char *modem_command, *dial_number;int main(int argc, char **argv){    int c, mode, calling;        signal(SIGUSR1, sigusr1_debug);        mode = MODE_NONE;    calling = 0;    for(;;) {        c = getopt(argc, argv, "hvstrac:d:m:");        if (c == -1) break;        switch(c) {        case 'v':          lm_debug++;          break;	case 'm':            if (!strcasecmp(optarg, "v21"))                mode = MODE_V21TEST;            else if (!strcasecmp(optarg, "v22"))                mode = MODE_V22TEST;            else if (!strcasecmp(optarg, "v23"))                mode = MODE_V23TEST;            else if (!strcasecmp(optarg, "v34"))                mode = MODE_V34TEST;            else if (!strcasecmp(optarg, "v90"))                mode = MODE_V90TEST;            else {                fprintf(stderr, "incorrect modulation: '%s'\n", optarg);                exit(1);            }	    break;        case 's':            mode = MODE_LINESIM;            break;        case 't':            mode = MODE_SOUNDCARD;            break;            /* LTmodem options */	case 'c':	    modem_command = optarg;	    break;        case 'r':            break;	case 'a':	/* "Answer" mode */            mode = MODE_LTMODEM_ANSWER;	    break;	case 'd':	/* Dial given number and exit mode */            mode = MODE_LTMODEM_CALL;	    dial_number = optarg;	    break;        default:            help();            exit(1);        }    }    if (mode == MODE_NONE) {        help();        exit(1);    }    srandom(0); /* we want a deterministic test */    dsp_init();    V34_static_init();    switch(mode) {    case MODE_V21TEST:        FSK_test(0);        break;    case MODE_V22TEST:        V22_test();        break;    case MODE_V23TEST:        FSK_test(1);        break;    case MODE_V34TEST:        V34_test();        break;    case MODE_V90TEST:        V90_test();        break;    case MODE_LINESIM:        break;    case MODE_LTMODEM_CALL:    case MODE_LTMODEM_ANSWER:        break;    case MODE_SOUNDCARD:        soundcard_modem();        break;    }    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -