This is a monster checkin that really should have been done a lot before,

but many of the changes are dependent on each other.  This checkin is an
intermediate version that is not complete and may not even compile, but I
don't dare sit on the changes any longer.

One of the major changes is the API for the state machine system which
has been changed a lot to facilitate some new features.  The most obvious
result of this is that some of the code in G3/fsm.c now needs to be
modified.  I hope this is a good change, although the syntax is
doubious as it makes heavy use of the C preprocessor and the state
machine functions really don't look like C functions any more.

Another important change is the HAL, which should make it easier to
make this code work on non-ISDN hardware.

Take care; much work remains.
This commit is contained in:
Morten Rolland 2000-10-28 18:18:54 +00:00
parent 08977969df
commit cc0fcaee0a
32 changed files with 2339 additions and 1263 deletions

201
G3/fsm.c
View File

@ -36,6 +36,8 @@
* handled by hardware directely.
*/
#include <stdio.h>
#include <ifax/types.h>
#include <ifax/G3/fax.h>
#include <ifax/G3/kernel.h>
@ -70,19 +72,19 @@
* this one.
*/
DEFGLOBALSTATE(fsm_wait_softsignal)
DEFGLOBALSTATE(do_hard_exit)
FSM_DEFSTATE(fsm_wait_softsignal)
FSM_DEFSTATE(do_hard_exit)
/* List states here that is called in a forward fashion (most of them) */
DEFSTATE(start_answer_incomming)
DEFSTATE(do_CED)
DEFSTATE(done_CED)
DEFSTATE(start_DIS)
DEFSTATE(do_DIS)
DEFSTATE(done_DIS)
DEFSTATE(hunt_for_DCS_or_DTC)
FSM_DEFSTATE(start_answer_incomming)
FSM_DEFSTATE(do_CED)
FSM_DEFSTATE(done_CED)
FSM_DEFSTATE(start_DIS)
FSM_DEFSTATE(do_DIS)
FSM_DEFSTATE(done_DIS)
FSM_DEFSTATE(hunt_for_DCS_or_DTC)
/* Jump to 'start_answer_incomming' when an incomming call is
@ -93,83 +95,78 @@ DEFSTATE(hunt_for_DCS_or_DTC)
void fax_initialize_fsm_incomming()
{
fax_setup_outgoing_DIS(); /* Prepare data-frames in 'fax' structure */
fax_setup_outgoing_NSF();
fax_setup_outgoing_CSI();
/* Prepare data-frames in 'fax' structure */
fax_setup_outgoing_DIS();
fax_setup_outgoing_NSF();
fax_setup_outgoing_CSI();
initialize_statemachines(); /* Reset all state-machines for a fresh start */
init_fsm(FSM_FAX_MAIN,start_answer_incomming); /* Get the main one going */
fsm_init(fax->statemachines,0,start_answer_incomming,100,fax);
ifax_connect(fax->silence,fax->rateconv7k2to8k0); /* Start off silent */
ifax_connect(fax->silence,fax->rateconv7k2to8k0); /* Start silent */
}
STATE(start_answer_incomming)
{
/* Stay silent for 0.2 seconds before outputing the CED */
FSMWAITJUMP(TIMER_AUX,ZEROPOINTTWOSECONDS,do_CED);
}
#define NEEDS_none /* No state-machine variables needed */
STATE(do_CED)
{
/* Output the CED sinus signal for 3.8 sec */
ifax_connect(fax->sinusCED,fax->rateconv7k2to8k0);
FSMWAITJUMP(TIMER_AUX,THREEPOINTEIGHTSECONDS,done_CED);
}
FSM_STATE(NEEDS_none,start_answer_incomming)
/* Stay silent for 0.2 seconds before outputing the CED */
FSMWAITJUMP(TIMER_AUX,ZEROPOINTTWOSECONDS,do_CED);
FSM_END
STATE(done_CED)
{
/* After the CED, wait 75ms and do the DIS */
ifax_connect(fax->silence,fax->rateconv7k2to8k0);
FSMWAITJUMP(TIMER_AUX,SEVENTYFIVEMILLISECONDS,start_DIS);
}
FSM_STATE(NEEDS_none,do_CED)
/* Output the CED sinus signal for 3.8 sec */
ifax_connect(fax->sinusCED,fax->rateconv7k2to8k0);
FSMWAITJUMP(TIMER_AUX,THREEPOINTEIGHTSECONDS,done_CED);
FSM_END
STATE(start_DIS)
{
/* When we hook up the HDLC+V.21 they go online and send FLAGs */
ifax_connect(fax->modulatorV21,fax->rateconv7k2to8k0);
ifax_connect(fax->encoderHDLC,fax->modulatorV21);
FSM_STATE(NEEDS_none,done_CED)
/* After the CED, wait 75ms and do the DIS */
ifax_connect(fax->silence,fax->rateconv7k2to8k0);
FSMWAITJUMP(TIMER_AUX,SEVENTYFIVEMILLISECONDS,start_DIS);
FSM_END
/* Keep sending FLAGs for one second before proceeding with real frames */
FSMWAITJUMP(TIMER_AUX,ONESECOND,do_DIS);
}
FSM_STATE(NEEDS_none,start_DIS)
/* When we hook up the HDLC+V.21 they go online and send FLAGs */
ifax_connect(fax->modulatorV21,fax->rateconv7k2to8k0);
ifax_connect(fax->encoderHDLC,fax->modulatorV21);
STATE(do_DIS)
{
/* After one second of FLAGs, we transmit the DIS (and optional frames) */
/* Keep sending FLAGs for one second before proceeding with frames */
FSMWAITJUMP(TIMER_AUX,ONESECOND,do_DIS);
FSM_END
if ( fax->NSFsize ) {
/* There is a NSF */
ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_TXFRAME,
fax->NSF,fax->NSFsize,255);
}
FSM_STATE(NEEDS_none,do_DIS)
/* After one second of FLAGs, we transmit the DIS etc. */
if ( fax->CSIsize ) {
/* There is a CSI */
ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_TXFRAME,
fax->CSI,fax->CSIsize,255);
}
if ( fax->NSFsize ) {
/* There is a NSF */
ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_TXFRAME,
fax->NSF,fax->NSFsize,255);
}
/* Assume there is a DIS (it better...) */
ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_TXFRAME,
fax->DIS,fax->DISsize,255);
if ( fax->CSIsize ) {
/* There is a CSI */
ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_TXFRAME,
fax->CSI,fax->CSIsize,255);
}
FSMJUMP(done_DIS);
}
/* Assume there is a DIS (it better...) */
ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_TXFRAME,
fax->DIS,fax->DISsize,255);
STATE(done_DIS)
{
/* Wait until the HDLC-frames has been transmitted before receiving */
if ( ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_IDLE) > 2 ) {
ifax_connect(fax->silence,fax->rateconv7k2to8k0);
FSMJUMP(hunt_for_DCS_or_DTC);
}
}
FSMJUMP(done_DIS);
FSM_END
STATE(hunt_for_DCS_or_DTC)
{
/* Stay online a little to flush buffers, then exit */
FSMWAITJUMP(TIMER_AUX,ONESECOND,do_hard_exit);
}
FSM_STATE(NEEDS_none,done_DIS)
/* Wait until the HDLC-frames has been transmitted before receiving */
if ( ifax_command(fax->encoderHDLC,CMD_HDLC_FRAMING_IDLE) > 2 ) {
ifax_connect(fax->silence,fax->rateconv7k2to8k0);
FSMJUMP(hunt_for_DCS_or_DTC);
}
FSM_END
FSM_STATE(NEEDS_none,hunt_for_DCS_or_DTC)
/* Stay online a little to flush buffers, then exit */
FSMWAITJUMP(TIMER_AUX,ONESECOND,do_hard_exit);
FSM_END
/**********************************************************************
@ -182,17 +179,15 @@ STATE(hunt_for_DCS_or_DTC)
* as well.
*/
GLOBALSTATE(fsm_wait_softsignal)
{
if ( softsignaled_clr(fsmself->arg) ) {
FSMRETURN;
}
}
FSM_GLOBAL_STATE(NEEDS_none,fsm_wait_softsignal)
if ( softsignaled_clr(FSMGETARG) ) {
FSMRETURN(0);
}
FSM_END
GLOBALSTATE(do_hard_exit)
{
exit(17);
}
FSM_GLOBAL_STATE(NEEDS_none,do_hard_exit)
exit(17);
FSM_END
#if 0
@ -226,14 +221,14 @@ void fax_initialize_fsm_outgoing()
}
STATE (start_sending_fax)
FSM_STATE (start_sending_fax)
{
one_shot_timer(TIMER_DIAL, THIRTYFIVESECONDS);
one_shot_timer(TIMER_AUX, THREESECONDS);
fsmself->state = A_CNG_sound;
}
STATE (A_CNG_silence)
FSM_STATE (A_CNG_silence)
{
if ( softsignaled(TIMER_AUX) ) {
ifax_connect(fax->sinusCNG,fax->rateconv7k2to8k0);
@ -252,7 +247,7 @@ STATE (A_CNG_silence)
}
}
STATE (A_CNG_sound)
FSM_STATE (A_CNG_sound)
{
if ( softsignaled(TIMER_AUX) ) {
ifax_connect(fax->silence,fax->rateconv7k2to8k0);
@ -271,7 +266,7 @@ STATE (A_CNG_sound)
}
}
//#if 0
/****************************************************************************
*
* Phase B, FIGURE 5-2a/T.30
@ -283,11 +278,11 @@ DEFSTATE(B_CNG_sound)
DEFSTATE(B_CNG_silence)
STATE (entry_PhaseB) {
FSM_STATE (entry_PhaseB) {
one_shot_timer(TIMER_T1, T1_TIME);
}
STATE (B_CNG_silence)
FSM_STATE (B_CNG_silence)
{
if ( softsignaled(TIMER_AUX) ) {
ifax_connect(fax->sinusCNG,fax->rateconv7k2to8k0);
@ -306,7 +301,7 @@ STATE (B_CNG_silence)
}
}
STATE (B_CNG_sound)
FSM_STATE (B_CNG_sound)
{
if ( softsignaled(TIMER_AUX) ) {
ifax_connect(fax->silence,fax->rateconv7k2to8k0);
@ -339,7 +334,7 @@ STATE (B_CNG_sound)
DEFSTATE (Entry_B)
STATE(Entry_B)
FSM_STATE(NEEDS_none,Entry_B)
{
softsignal(ACTION_HANGUP);
return_from_subroutine(fax);
@ -367,13 +362,13 @@ DEFSTATE(response_received_sg2_helper)
DEFSTATE(response_received_tdcn)
DEFSTATE(response_received_disconnect)
STATE(response_received)
FSM_STATE(NEEDS_none,response_received)
{
one_shot_timer(TIMER_T4,THREESECONDS);
fsmself->state = response_received_flag;
}
STATE(response_received_flag)
FSM_STATE(NEEDS_none,response_received_flag)
{
if ( softsignaled_clr(HDLCFLAGDETECTED) ) {
one_shot_timer(TIMER_SHUTUP,THREESECONDS);
@ -385,7 +380,7 @@ STATE(response_received_flag)
}
}
STATE(response_received_raf)
FSM_STATE(NEEDS_none,response_received_raf)
{
if ( softsignaled_clr(HDLCFRAMERECEIVED) ) {
@ -425,7 +420,7 @@ STATE(response_received_raf)
fsmself->state = response_received_sg1;
}
STATE(response_received_sg1)
FSM_STATE(NEEDS_none,response_received_sg1)
{
if ( softsignaled(V21CARRIEROK ) ) {
fsmself->state = response_received_raf;
@ -438,7 +433,7 @@ STATE(response_received_sg1)
}
}
STATE(response_received_sg2)
FSM_STATE(NEEDS_none,response_received_sg2)
{
if ( softfignaled(V21CARRIEROK) ) {
if ( softsignaled(TIMER_SHUTUP) )
@ -450,7 +445,7 @@ STATE(response_received_sg2)
fsmself->state = response_received_sg2_helper;
}
STATE(response_received_sg2_helper)
FSM_STATE(NEEDS_none,response_received_sg2_helper)
{
if ( softsignaled(V21CARRIEROK) ) {
fsmself->state = response_received_sg2;
@ -463,13 +458,13 @@ STATE(response_received_sg2_helper)
}
}
STATE(response_received_tdcn)
FSM_STATE(NEEDS_none,response_received_tdcn)
{
/* Transmit a disconnect line command */
fsmself->state = response_received_disconnect;
}
STATE(response_received_disconnect)
FSM_STATE(NEEDS_none,response_received_disconnect)
{
softsignal(ACTION_HANGUP);
return_from_subroutine(fax);
@ -499,11 +494,11 @@ DEFSTATE(command_received_sg2_helper)
DEFSTATE(command_received_disconnect)
STATE (command_received){
FSM_STATE (command_received){
fsmself->state = command_received_flag;
}
STATE (command_received_flag)
FSM_STATE (command_received_flag)
{
if ( softsignaled_clr(HDLCFLAGDETECTED) ) {
one_shot_timer(TIMER_T2,SIXSECONDS); ?????
@ -516,7 +511,7 @@ STATE (command_received_flag)
}
STATE (command_received_raf) {
FSM_STATE (command_received_raf) {
if ( softsignaled_clr(HDLCFRAMERECEIVED) ) {
@ -554,7 +549,7 @@ STATE (command_received_raf) {
* transmission) or a runaway remote fax that keeps sending.
*/
STATE(command_received_sg1) {
FSM_STATE(NEEDS_none,command_received_sg1) {
if ( softsignaled(V21CARRIEROK) ) {
if ( softsignaled(TIMER_AUX) ) { // 0.2 seconds
@ -574,7 +569,7 @@ STATE(command_received_sg1) {
}
STATE(command_received_sg2) {
FSM_STATE(NEEDS_none,command_received_sg2) {
if ( softsignaled(V21CARRIEROK) ) {
if ( softsignaled(TIMER_AUX) ) { // 0.2 seconds
@ -592,7 +587,7 @@ STATE(command_received_sg2) {
STATE(command_received_disconnect)
FSM_STATE(NEEDS_none,command_received_disconnect)
{
softsignal(ACTION_HANGUP);
return_from_subroutine(fax);

View File

@ -29,6 +29,7 @@
#include <ifax/module.h>
#include <ifax/types.h>
#include <ifax/misc/regmodules.h>
#include <ifax/misc/statemachine.h>
#include <ifax/G3/fax.h>
#include <ifax/G3/fsm.h>
#include <ifax/modules/signalgen.h>
@ -86,9 +87,14 @@ void initialize_G3fax(ifax_modp linedriver)
/* The HDLC-encode is used both by the "binary coded signal"
* and high-speed fax transfers.
*/
fax->encoderHDLC = ifax_create_module(IFAX_ENCODER_HDLC);
/* The G3 fax-machine code needs a statemachine for the protocol
* handeling.
*/
fax->statemachines = fsm_allocate(1);
fsm_setup(fax->statemachines,0,2048);
ifax_connect(fax->rateconv7k2to8k0,linedriver);

View File

@ -36,5 +36,5 @@ struct G3fax *fax;
void fax_run_internals(void)
{
run_statemachines();
fsm_run(fax->statemachines);
}

View File

@ -6,7 +6,7 @@ SUBDIRS = lib misc modules G3 highlevel
MODULES = misc/misc.a modules/modules.a G3/g3.a lib/isdnlib.a \
highlevel/highlevel.a
PROGRAMS = v21_softmodem amodemd #test
PROGRAMS = amodemd # v21_softmodem test
all: subdirs $(PROGRAMS)

108
amodemd.c
View File

@ -4,7 +4,7 @@
Fax program for ISDN.
Initial startup of daemon 'amodemd' - contains main() etc.
Copyright (C) 1999 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Copyright (C) 1999-2000 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -60,24 +60,41 @@
#include <ifax/misc/pty.h>
#include <ifax/highlevel/commandparse.h>
static struct IsdnHandle *ih;
static struct PtyHandle *ph;
static struct ModemHandle *mh;
/* Parse command-line arguments and bail out with an error message if
* something is wrong.
/*
* Parse command-line arguments and bail out with an error message if
* something is wrong. Variables 'argc' and 'argv' must be set prior
* to calling these functions (e.g. initialized by 'main').
*/
static int argc, argn;
static char **argv, **arg;
static void usage(void)
{
fprintf(stderr,"Usage: %s [-D] [-c <config-file>]\n",progname);
exit(1);
}
static void parse_arguments(int argc, char **argv)
static int option(const char *option, int num)
{
int t;
if ( strcmp(argv[argn],option) )
return 0;
if ( argn + num <= argc ) {
arg = argv + argn;
return 1;
}
usage();
return 0; /* Silence compiler */
}
static void parse_arguments(void)
{
if ( argc > 0 && argv[0] != 0 ) {
progname = rindex(argv[0],'/');
if ( progname != 0 ) {
@ -87,65 +104,60 @@ static void parse_arguments(int argc, char **argv)
}
}
t = 1;
while ( t < argc ) {
argn = 1;
while ( argn < argc ) {
if ( !strcmp("-c",argv[t]) ) {
t++;
if ( t >= argc )
usage();
config_file = argv[t];
t++;
if ( option("-c",2) ) {
config_file = arg[1];
continue;
}
if ( !strcmp("-D",argv[t]) ) {
t++;
if ( option("-D",1) ) {
run_as_daemon = 1;
continue;
}
usage();
}
}
/*
* The main loop of the entire program. All concurrent operations are
* scheduled from here. The inner select function takes care of waiting
* for input/output, and all other parts of the system is designed to
* cooperate with this inner loop.
*
* No part of the system can be allowed to block, as this will stall the
* main loop, and thus possible stall some other important part of the
* system (like the DSP chain or AT command parser).
*
* The main loop will only exit in case of an unrecoverable error.
*/
static void main_loop(void)
{
fd_set rfd, wfd;
fd_set rfd, wfd, efd;
int maxfd, rc;
struct timeval delay;
printf("Main loop....\n");
ifax_dprintf(DEBUG_INFO,"Entering main loop\n");
for (;;) {
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
maxfd = -1;
/* Watch the ISDN-line for more incomming samples */
FD_SET(ih->fd,&rfd);
maxfd = ih->fd + 1;
/* Watch the pty for incomming AT-commands or data */
hh->prepare_select(hh,&maxfd,&rfd,&wfd,&efd);
pty_prepare_select(ph,&maxfd,&rfd,&wfd);
delay.tv_sec = 0;
delay.tv_usec = 500000;
/* Do the actual waiting (sleeping). When this select
* system call is made, the rest of the system can run when
* using the real-time scheduler.
*/
rc = select(maxfd, &rfd, (fd_set *)0, (fd_set *)0, &delay);
rc = select(maxfd, &rfd, &wfd, &efd, &delay);
pty_service_read(ph);
rc = IsdnService(ih);
if ( rc == ISDN_RINGING ) {
pty_write(ph,"\nRING\n\n",7);
#if 0
/* Not gotten far enough for testing this yet... */
if ( IsdnAnswer(ih) ) {
setup_incomming();
handle_call();
}
#endif
}
hh->service_select(hh,&rfd, &wfd, &efd);
modeminput(mh,ph);
@ -156,11 +168,19 @@ static void main_loop(void)
/* Startup point for 'amodemd' - parse args, initialize and off we go */
void main(int argc, char **argv)
void main(int ac, char **av)
{
parse_arguments(argc,argv);
argc = ac;
argv = av;
parse_arguments();
read_configuration_file();
if ( hh == 0 ) {
ifax_dprintf(DEBUG_LAST,"No hardware device configured\n");
exit(1);
}
if ( run_as_daemon )
start_daemon();
@ -175,10 +195,10 @@ void main(int argc, char **argv)
ph = pty_initialize("/dev/ptyp9");
mh = modem_initialize();
ih = IsdnInit(isdn_device,isdn_msn);
linedriver = ifax_create_module(IFAX_LINEDRIVER);
ifax_command(linedriver,CMD_LINEDRIVER_ISDN,ih);
ifax_command(linedriver,CMD_LINEDRIVER_ISDN,hh);
/* ifax_command(linedriver,CMD_LINEDRIVER_AUDIO); */
/* ifax_command(linedriver,CMD_LINEDRIVER_RECORD,"modem.dat"); */

View File

@ -398,6 +398,53 @@ int do_fth(struct ModemHandle *mh, struct PtyHandle *ph,
int do_dial(struct ModemHandle *mh, struct PtyHandle *ph,
char *prebuf,char **postbuf,mdmcmd *cmd)
{
#define MAXDIALDIGITS 64
char dialnum[MAXDIALDIGITS];
int t;
char c;
t = 0;
while ( t < (MAXDIALDIGITS-1) ) {
c = **postbuf;
if ( c >= '0' && c <= '9' ) {
dialnum[t++] = c;
*postbuf++;
continue;
}
if ( c == 'w' || c == 'W' || c == ',' ) {
*postbuf++;
continue;
}
break;
}
dialnum[t] = '\0';
if ( !last_command(mh,ph) ) /* Should be last command on line */
return 1;
if ( dialnum[0] == '\0' ) /* A simple ATD(T) should give OK */
return 1;
/* We have a valid ATD command; we have to test if all is well
* (not allready online....) and initialize the correct mode
* and signalling chain.
*/
/* FIXME: Check for online allready here */
/* The following function initializes timers, signalling chain
* etc. depending on the mode of the modem. Currently, we only
* opt for Fax class one support, and maybe 300 bit/s data.
*/
setup_call(mh);
#if 0
/* This is a hack by becka it seems, disable it for now */
char *dummy="+FRH=3";

View File

@ -33,20 +33,22 @@
#define _G3_FAX_H
struct G3fax {
ifax_modp linedriver;
ifax_modp rateconv7k2to8k0;
ifax_modp sinusCED;
ifax_modp sinusCNG;
ifax_modp silence;
ifax_modp scrambler;
ifax_modp modulatorV21;
ifax_modp modulatorV29;
ifax_modp encoderHDLC;
ifax_modp linedriver;
ifax_modp rateconv7k2to8k0;
ifax_modp sinusCED;
ifax_modp sinusCNG;
ifax_modp silence;
ifax_modp scrambler;
ifax_modp modulatorV21;
ifax_modp modulatorV29;
ifax_modp encoderHDLC;
ifax_modp fskd, dehdlc, faxctrl;
ifax_modp fskd, dehdlc, faxctrl;
ifax_uint8 DIS[32], CSI[32], NSF[32];
int DISsize, CSIsize, NSFsize;
struct StateMachinesHandle *statemachines;
ifax_uint8 DIS[32], CSI[32], NSF[32];
int DISsize, CSIsize, NSFsize;
};
extern struct G3fax *fax;

29
include/ifax/constants.h Normal file
View File

@ -0,0 +1,29 @@
/* $Id$
******************************************************************************
Fax program for ISDN.
Constant values used throughout, esp. math constants not defined by ANSI
Copyright (C) 2000 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
#define IFAX_PI 3.14159265358979323846

View File

@ -30,4 +30,5 @@
extern char *progname; /* Name of executable/program */
extern int run_as_daemon; /* nonzero if running as daemon */
extern ifax_modp linedriver; /* Common linedriver */
extern ifax_modp linedriver; /* Common linedriver */
extern struct HardwareHandle *hh; /* Phone line */

View File

@ -0,0 +1,119 @@
/* $Id$
******************************************************************************
Fax program for ISDN.
Copyright (C) 1999 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
#ifndef _HARDWARE_DRIVER_H
#define _HARDWARE_DRIVER_H
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <ifax/types.h>
typedef enum {
UNKNOWN=0, /* Unknown, uninitialized status */
INITIALIZING=1, /* Initialization in progress */
FAILED=2, /* Initialization or other failed */
IDLE=3, /* All is well, ready to do work */
RINGING=4, /* Someone is calling us */
CALLING=5, /* We are calling someone else */
ONLINE=6, /* We have a voice connection established */
BUSY=7, /* Remote end was busy */
NOANSWER=8 /* Remote end didn't answer the phone */
} hardware_state_t;
typedef enum {
ISDN /* Use /dev/ttyI* devices for ISDN line access */
} hardware_type_t;
struct HardwareHandle {
void *private; /* Driver specific private data */
hardware_type_t type; /* Type of hardware driver */
hardware_state_t state; /* Status of hardware right now */
int read_size, write_size; /* Next read/write sizes expected */
/* If an error is encountered in the hardware driver or some of
* the modules it uses, the 'error' variable will be non-zero to
* indicate this, and an error message in 'errormsg'.
*/
int error;
char errormsg[128];
/* Set up all three fd_set used in a select for the hardware
* driver. The 'maxfd' is increased to the max fd-value used by
* the hardware driver (if it is smaller initially).
*/
void (*prepare_select)(struct HardwareHandle *hh,
int *maxfd, fd_set *r, fd_set *w, fd_set *e);
/* Call this function right after the select in order to service
* the hardware driver. All fd_set used in the select must be
* supplied in case the hardware driver needs to inspect them.
*/
void (*service_select)(struct HardwareHandle *hh,
fd_set *r, fd_set *w, fd_set *e);
/* This service function must be called after all the read and
* write operations on the hardware has been performed. This is
* used to clean up, flush buffers etc. (or nothing at all).
*/
void (*service_readwrite)(struct HardwareHandle *hh);
/* Call this function to *initialize* dialling a given number.
* The dialing operation may have to be carried out over a longer
* time interval, which means the work must be done in the
* 'service_select' routine (DTMF generation, wait for answer etc.)
*/
void (*dial)(struct HardwareHandle *hh, char *number);
/* Force a hangup. The hangup may not happen immediately, but
* carried out on subsequent calls to 'service_select'.
*/
void (*hangup)(struct HardwareHandle *hh);
/* Read a number of samples from the hardware driver.
*/
void (*read)(struct HardwareHandle *hh, ifax_uint8 *samples);
/* Write a number of (16-bit signed) samples to the hardware driver.
*/
void (*write)(struct HardwareHandle *hh, ifax_sint16 *samples);
/* Supply the hardware driver with configuration parameters.
*/
void (*configure)(struct HardwareHandle *hh, char *param, char *value);
/* After the driver has been configured, it must be initialized before
* it can be used properly (used in select loops).
*/
void (*initialize)(struct HardwareHandle *hh);
};
struct HardwareHandle *hardware_allocate(char *hardware);
#endif

View File

@ -0,0 +1,61 @@
/* $Id$
******************************************************************************
Fax program for ISDN.
Implement a ring buffer for use by pty, isdn etc. code to handle I/O.
Copyright (C) 1999 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
#ifndef _MISC_IOBUFFER_H
#define _MISC_IOBUFFER_H
#include <ifax/types.h>
#include <ifax/misc/malloc.h>
struct IOBuffer {
ifax_uint32 fp, dp, size, total;
ifax_uint8 *data;
int debug_buffer_idx;
enum {
FILLUPDATE = 1,
WRITE = 2
} debug;
char descr[32];
};
struct IOBuffer *iobuffer_allocate(int size, char *devinfo);
void iobuffer_fill_segment(struct IOBuffer *iob, ifax_uint8 **dst, int *len);
void iobuffer_fill_update(struct IOBuffer *iob, int size, char *info);
void iobuffer_fill(struct IOBuffer *iob, ifax_uint8 *src, int size);
void iobuffer_drain_segments(struct IOBuffer *iob,
ifax_uint8 **src1, int *len1,
ifax_uint8 **src2, int *len2);
void iobuffer_drain_update(struct IOBuffer *iob, int size);
int iobuffer_drain(struct IOBuffer *iob, ifax_uint8 *dst, int size);
int iobuffer_read(struct IOBuffer *iob, int fd);
int iobuffer_write(struct IOBuffer *iob, int fd);
void iobuffer_reset(struct IOBuffer *iob);
#endif

View File

@ -30,13 +30,28 @@
*/
#include <time.h>
#include <ifax/misc/hardware-driver.h>
#include <ifax/misc/iobuffer.h>
#include <ifax/misc/timers.h>
#define ISDNTXBUF_SIZE 512
#define ISDNRECBUF_SIZE 512
#define ISDNMAXLNE_SIZE 256
#define ISDNERRMSG_SIZE 128
#define ISDNDEVNME_SIZE 64
#define ISDNMSN_SIZE 64
#define ISDNWRITE_TMP 512
#define ISDNATCMD_SIZE 256
#define ISDNATRESULT_SIZE 512
#define ISDNATPARSE_SIZE 128
#define ISDNATPARSE_SIZE_MIN 32
#define ISDNTTY_ETX 0x03
#define ISDNTTY_DLE 0x10
#define ISDNTTY_DC4 0x14
#if 0
#define ISDNTXBUF_SIZE 512
#define ISDNRECBUF_SIZE 512
#define ISDNMAXLNE_SIZE 256
#define ISDN_SLEEPING -1
#define ISDN_RINGING -2
@ -45,34 +60,32 @@
#define ISDN_BUSY -5
#define ISDN_NOANSWER -6
#define ISDNTTY_ETX 0x03
#define ISDNTTY_DLE 0x10
#define ISDNTTY_DC4 0x14
#define TTYIMODE_CMDOFFLINE 0
#define TTYIMODE_CMDONLINE 1
#define TTYIMODE_AUDIO 2
#endif
struct IsdnHandle {
int fd; /* Filedescriptor of ISDN device */
int error; /* Nonzero if error (errormsg valid) */
int mode; /* Which mode the tty is in */
int ringing; /* Nonzero to indicate ringing */
int recbufrp, recbufwp, recbufsize; /* Receive buffer characteristics */
char cmdresult[ISDNMAXLNE_SIZE+2]; /* Result of command */
char errormsg[ISDNERRMSG_SIZE+2]; /* Detailed error description */
char devname[ISDNDEVNME_SIZE]; /* Name of ISDN-device */
char remotemsn[ISDNMSN_SIZE]; /* Remote phone-number */
time_t start_time, end_time; /* Timing characteristics for call */
ifax_uint8 recbuf[ISDNRECBUF_SIZE+1]; /* Receive buffer array */
ifax_uint8 txbuf[ISDNTXBUF_SIZE+ISDNTXBUF_SIZE];
int fd; /* ISDN device */
struct StateMachinesHandle *smh; /* Statemachine */
struct IOBuffer *incomming_buffer;
struct IOBuffer *outgoing_buffer;
int at_idx; /* Current char of at_cmd */
unsigned int messages; /* Accumulated messages */
/* int at_cmd_ok; */ /* nonzero => AT command ok */
time_t start_time, end_time; /* Call timing info */
int request_dial; /* Nonzero => Start dialing */
int request_hangup; /* Force hangup of call */
int request_answer; /* Accept incomming call */
int indication_ringing; /* Inncomming call detected */
char device[ISDNDEVNME_SIZE]; /* Name of ISDN-device */
char ourmsn[ISDNMSN_SIZE]; /* Our MSN */
char dialmsn[ISDNMSN_SIZE]; /* Diel this number */
char remotemsn[ISDNMSN_SIZE]; /* Incomming call MSN */
char at_cmd[ISDNATCMD_SIZE]; /* Current AT-command */
char at_result[ISDNATRESULT_SIZE]; /* Result of AT-command */
char at_tmp[ISDNATRESULT_SIZE]; /* Temp storage for result */
ifax_uint8 tmp_write[ISDNWRITE_TMP]; /* Use for DLE insertion */
};
extern struct IsdnHandle *IsdnInit(char *, char *);
extern int IsdnService(struct IsdnHandle *);
extern int IsdnAnswer(struct IsdnHandle *);
extern int IsdnDial(struct IsdnHandle *, char *, int);
extern int IsdnReadSamples(struct IsdnHandle *, ifax_sint16 *, int);
extern void IsdnWriteSamples(struct IsdnHandle *, ifax_sint16 *, int);
extern void IsdnShortSleep(int);
void isdn_allocate(struct HardwareHandle *hh);

View File

@ -4,7 +4,7 @@
Fax program for ISDN.
Statemachine management functions
Copyright (C) 1999 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Copyright (C) 1999-2000 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -26,46 +26,178 @@
******************************************************************************
*/
#define STATEMACHINESTACKSIZE 16
#define MAXSTATEMACHINES 64
/* How deep the stack trace in a state machine can be */
#define FSM_CALL_DEPTH 16
/* Max number of direct (immediate) state-jumps can be allowed
* before we have to pre-empt the state-machine to avoid lock-ups.
*/
#define MAXSEQSTATEJUMPS 64
/* Maximum size of (source-code) function names and filename for states */
#define FSM_FUNCIDENT_MAX 64
/* Defines for each single state machine */
struct statemachine;
typedef void (*fsm_t)(struct statemachine *);
struct statemachine {
void (*state)(struct statemachine *);
void (*stack[STATEMACHINESTACKSIZE])(struct statemachine *);
int stackpointer, arg;
struct statemachine *next;
fsm_t state; /* Next state to call */
void *private; /* Pointer a private memory segment */
struct statemachine *next; /* Next statemachine on run-chain */
char lastfunc[128]; /* Name of last state/function */
int lastfunc_count; /* Number of wakeups for last state */
int lastsp; /* Last value of stackpointer (for debug) */
int debug; /* Nonzero if debugging wanted */
int maxloops; /* Max number of states without yielding */
/* We need a stack and local variables to be flexible */
int sp, return_value;
fsm_t stack[FSM_CALL_DEPTH];
int arg[FSM_CALL_DEPTH];
char stack_file[FSM_CALL_DEPTH][FSM_FUNCIDENT_MAX];
char stack_function[FSM_CALL_DEPTH][FSM_FUNCIDENT_MAX];
void *stackdata;
void *stackframe[FSM_CALL_DEPTH];
int stackframesize[FSM_CALL_DEPTH];
};
#define STATE(x) \
static void x(struct statemachine *fsmself)
/* A collection of state machines are contained in the following
* handle, allocated by allocate_statemachines(count);
*/
struct StateMachinesHandle {
struct statemachine *fsm, *running;
};
#define GLOBALSTATE(x) \
void x(struct statemachine *fsmself)
/* The following macros may be defined for state-call tracking. Define
* FSM_DEBUG_STATES to get the debugging info.
*/
#undef _FSMDECL_DEBUG
#undef _FSMEXIT_DEBUG
#define DEFSTATE(x) \
static void x(struct statemachine *fsmself);
#ifdef FSM_DEBUG_STATES
#define _FSMDECL_DEBUG void *_fsmdebug = \
_fsm_debug_entry(fsmself,__FUNCTION__);
#define _FSMEXIT_DEBUG _fsm_debug_exit(_fsmdebug);
#else
#define _FSMDECL_DEBUG
#define _FSMEXIT_DEBUG
#endif
#define DEFGLOBALSTATE(x) \
extern void x(struct statemachine *fsmself);
#define FSMJUMP(x) \
{ fsmself->state = x; return; }
/* Define the macros used to define and manipulate the states of the
* statemachines.
*/
#define FSMCALLJUMP(c,j) \
{ fsmself->state=c; fsmself->stack[fsmself->stackpointer++]=j; return; }
#define FSM_GLOBAL_STATE(decl,state) \
void state(struct statemachine *fsmself) \
{ \
decl _FSMDECL_DEBUG
#define FSMRETURN \
{ fsmself->state=fsmself->stack[--fsmself->stackpointer]; return; }
#define FSM_STATE(decl,state) static FSM_GLOBAL_STATE(decl,state)
#define FSMWAITJUMP(t,d,s) \
{ one_shot_timer(t,d); fsmself->arg=t; FSMCALLJUMP(fsm_wait_softsignal,s) }
#define FSM_END _FSMEXIT_DEBUG }
extern void initialize_statemachines(void);
extern void init_fsm(int, void (*)(struct statemachine *));
extern void kill_fsm(int);
extern void run_statemachines(void);
#define FSM_DEFSTATE(x) \
static void x(struct statemachine *fsmself);
#define FSM_DEFSTATE_GLOBAL(x) \
extern void x(struct statemachine *fsmself);
#define FSM_SETUPFRAME (fsmself->stackframe[fsmself->sp])
#define FSM_ALLOCFRAME(size) \
do { \
if ( fsmself->stackframesize[fsmself->sp] == 0 ) { \
fsmself->stackframesize[fsmself->sp] = size; \
} \
} while (0)
/* These are for backward compatibility only
#define DEFSTATE(x) FSM_DEFSTATE(x)
#define DEFGLOBALSTATE(x) FSMDEF_DEFSTATE_GLOBAL(x)
*/
#define FSMJUMP(x) \
do { \
fsmself->state = x; \
return; \
} while (0)
#define _FSMSETPOS \
do { \
sprintf(fsmself->stack_file[fsmself->sp],"%s:%d", \
__FILE__,__LINE__); \
} while (0)
#define FSMCALLJUMP(c,j,a) \
do { \
fsmself->state = c; \
fsmself->stack[fsmself->sp] = j; \
fsmself->arg[fsmself->sp+1] = (a); \
fsmself->stackframe[fsmself->sp+1] = (void *) \
(((char *)fsmself->stackframe[fsmself->sp]) \
+ fsmself->stackframesize[fsmself->sp]); \
_FSMSETPOS; \
fsmself->sp++; \
fsmself->stackframesize[fsmself->sp] = 0; \
return; \
} while (0)
#define FSMRETURN(val) \
do { \
fsmself->sp--; \
fsmself->state = fsmself->stack[fsmself->sp]; \
fsmself->return_value = val; \
return; \
} while (0)
#define FSMRETVAL (fsmself->return_value)
#define FSMGETARG (fsmself->arg[fsmself->sp])
#define FSMYIELD return
#define FSMWAITJUMP(timer,delay,state) \
do { \
one_shot_timer(timer,delay); \
FSMCALLJUMP(fsm_wait_softsignal,state,timer); \
} while (0)
/* Help debug state machine problems by dumping the state-machine stack */
#define FSM_DUMPSTACK \
do { \
int t; \
_FSMSETPOS; \
fsmself->stack[fsmself->sp] = fsmself->state; \
for ( t=fsmself->sp; t >= 0; t-- ) { \
printf("#%d %p in %s at %s\n", \
fsmself->sp - t, \
fsmself->stack[t], \
fsmself->stack_function[t], \
fsmself->stack_file[t]); \
} \
} while (0)
struct StateMachinesHandle *fsm_allocate(int count);
void fsm_init(struct StateMachinesHandle *smh, int num, fsm_t state,
int maxloops, void *p);
void fsm_setup(struct StateMachinesHandle *smh, int fsmnum, int stacksize);
void fsm_kill(struct StateMachinesHandle *smh, int fsmnum);
void fsm_run(struct StateMachinesHandle *smh);
/* Internal to FSM system (debugging) */
void *_fsm_debug_entry(struct statemachine *fsmself, char *function_name);
void _fsm_debug_exit(void *dummy);
/* FIXME: With the advent of independent sets of state machines, the
* following defines and their uses should be moved outside of this file,
* and split up into several independent state machine systems:
*/
/* All running state-machines are identified by an integer number.
* Allocation of state-machines are as follows:
*/

View File

@ -26,6 +26,12 @@
******************************************************************************
*/
#ifndef _IFAX_MISC_TIMERS_H
#define _IFAX_MISC_TIMERS_H
#include <sys/time.h>
#include <unistd.h>
#include <ifax/types.h>
#define MAX_TIMERS 10
@ -33,3 +39,12 @@
extern void reset_timers(void);
extern void decrease_timers(ifax_sint32);
extern void one_shot_timer(int, ifax_sint32);
typedef struct {
struct timeval expires;
} hard_timer_t;
void hard_timer_init(hard_timer_t *ht, ifax_uint32 sec, ifax_uint32 usec);
int hard_timer_expired(hard_timer_t *ht);
#endif

View File

@ -7,7 +7,7 @@
#define CMD_LINEDRIVER_WORK 0x01
#define CMD_LINEDRIVER_AUDIO 0x02
#define CMD_LINEDRIVER_ISDN 0x03
#define CMD_LINEDRIVER_HARDWARE 0x03
#define CMD_LINEDRIVER_LOOPBACK 0x04
#define CMD_LINEDRIVER_RECORD 0x05

View File

@ -1,12 +1,15 @@
LDFLAGS=-lm
CFLAGS=-O2 -g -Wall -pedantic -I../include
CFLAGS=-O2 -ggdb -Wall -pedantic -ansi -I../include
LIBOBJS = bitreverse.o debug.o int2alaw.o module.o sincos.o isdn.o g711.o \
LIBOBJS = bitreverse.o debug.o int2alaw.o module.o sincos.o g711.o \
rate-7k2-8k-1.o atan.o atantbl.o sqrt.o sqrttbl.o alaw.o \
rate-8k-7k2-1.o
all: isdnlib.a
%.o: %.c
$(CC) $(CFLAGS) -c $<
isdnlib.a: $(LIBOBJS)
$(AR) rcs $@ $^

View File

@ -1,13 +1,18 @@
CFLAGS=-O2 -g -Wall -pedantic -I../include
CFLAGS=-ggdb -Wall -pedantic -ansi -I../include
OBJECTS = globals.o readconfig.o watchdog.o environment.o \
regmodules.o malloc.o isdnline.o timers.o softsignals.o \
statemachine.o pty.o
statemachine.o pty.o hardware-driver.o iobuffer.o
all: misc.a
all: misc.a test
misc.a: $(OBJECTS)
$(AR) rcs $@ $^
test: $(OBJECTS) misc.a
$(CC) $(CFLAGS) -o test test.c misc.a ../lib/alaw.o ../lib/debug.o
%.o: %.c
$(CC) $(CFLAGS) -c $^
clean:
rm -f $(OBJECTS) misc.a *~
rm -f $(OBJECTS) misc.a *~ test

View File

@ -28,7 +28,9 @@
#include <ifax/module.h>
#include <ifax/misc/globals.h>
#include <ifax/misc/hardware-driver.h>
char *progname = "amodemd";
int run_as_daemon = 0;
ifax_modp linedriver;
struct HardwareHandle *hh = 0;

94
misc/hardware-driver.c Normal file
View File

@ -0,0 +1,94 @@
/* $Id$
******************************************************************************
Fax program for ISDN.
Implement an abstraction layer for telephone line access.
Copyright (C) 1999 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
/* This file defines an API for accessing a phone line using a generic
* interface. This is called a HAL in Windows speak - a hardware
* abstraction layer. The reasons for having such an API is to make it
* easy to support new and/or strange devices.
*
* A device is initialized by first allocating the HardwareHandle for
* the hardware driver by calling the allocate function with the proper
* device type specified (ISDN, soundcard, WinModems etc.).
* Allocating the HardwareHandle is only the first step; it needs to
* be configured and initialized with device dependant configuration
* parameters before it can be used.
*
* Configuration parameters should be passed to the various drivers verbatim
* from the configuration files in order to minimize impact to the whole system
* when a new driver or options are added (ie. only the driver has to be
* changed/added).
*
* After the configuration process has finished, the initialize function
* is called to initialize the device and make it avilable. If the device
* can't be made available, a descriptive error should be returned.
*
* Example configuration sequence for an ISDN device:
*
* hh = hardware_allocate("isdn");
* rc = hh->configure(hh,"msn","5551234");
* rc = hh->configure(hh,"device","/dev/ttyI5");
* rc = hh->initialize(hh);
*
* The 'hardware_allocate' will return zero if the device couldn't be
* initialized (Ie. there is no such hardware supported).
*
* The above example configuration could be specified in the configuration
* file as:
*
* hardware = isdn
* isdn-msn = 5551234
* isdn-device = /dev/ttyI5
*/
#include <ifax/misc/malloc.h>
#include <ifax/misc/isdnline.h>
#include <ifax/misc/hardware-driver.h>
struct HardwareHandle *hardware_allocate(char *hwclass)
{
struct HardwareHandle *hh;
hh = ifax_malloc(sizeof(*hh),"Hardware driver instance");
hh->state = UNKNOWN;
hh->read_size = hh->write_size = 0;
hh->error = 0;
hh->errormsg[0] = '\0';
if ( !strcmp(hwclass,"isdn") ) {
/* ISDN is our primary goal and first target */
hh->type = ISDN;
isdn_allocate(hh);
return hh;
}
/* Check for more supported hardware here */
free(hh); /* Failed, no such hardware supported */
return 0;
}

340
misc/iobuffer.c Normal file
View File

@ -0,0 +1,340 @@
/* $Id$
******************************************************************************
Fax program for ISDN.
Implement a ring buffer for use by pty, isdn etc. code to handle I/O.
Copyright (C) 1999 Morten Rolland [Morten.Rolland@asker.mail.telia.com]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
/* This utility modules helps to implement asynchronous I/O using a ring
* buffer for queueing, and various service functions for doing non-blocking
* read and write on the buffer. Functions exists to fill and drain the
* buffer.
*
* Usage:
*
* struct IOBuffer *iob = iobuffer_allocate(int size);
* ....
*/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ifax/misc/iobuffer.h>
#include <ifax/debug.h>
struct IOBuffer *iobuffer_allocate(int size, char *devinfo)
{
struct IOBuffer *iob;
iob = ifax_malloc(sizeof(*iob),"IOBuffer instance");
iob->data = ifax_malloc(size,"IOBuffer data");
iob->total = size;
iobuffer_reset(iob);
strcpy(iob->descr,devinfo);
iob->debug = FILLUPDATE | WRITE;
return iob;
}
void iobuffer_reset(struct IOBuffer *iob)
{
iob->fp = iob->dp = iob->size = 0;
}
/* The debugging functions needs the following buffer to get things
* right and good looking. The debug_buffer holds the current line
* of debugging output, while the previous_prefix holds the prefix of
* the current debug buffer, so the buffer can be flushed when a
* different prefix is specified.
*/
static char debug_buffer[128];
static char previous_prefix[64] = { '\0', };
static int debug_idx, debug_any = 0;
static void iodump_flush(void)
{
if ( debug_any )
ifax_dprintf(DEBUG_DEBUG,"%s\n",debug_buffer);
strcpy(debug_buffer,previous_prefix);
debug_idx = strlen(debug_buffer);
debug_any = 0;
}
static void iodump(char *prefix, ifax_uint8 *log, int size)
{
char item[8], *i;
ifax_uint8 c;
int itemlen;
static char *ctrl[33] = {
"NUL","\\001","\\002","ETX","\\004","\\005","\\006","\\007",
"\\010","\\011","\\n","\\013","\\014","\\r","\\016","\\017",
"DLE","\\021","\\022","\\023","\\024","\\025","\\026","\\027",
"\\030","\\031","\\032","ESC","\\034","\\035","\\036","\\037",
"SPC"
};
if ( strcmp(previous_prefix,prefix) ) {
/* Flush previous debug-output with different prefix */
strcpy(previous_prefix,prefix);
iodump_flush();
}
while ( size > 0 ) {
c = *log++, size--;
if ( c < 33 ) {
i = ctrl[c];
} else if ( c < 127 ) {
item[0] = c;
item[1] = '\0';
i = item;
} else {
sprintf(item,"\\%03o",(int)c);
i = item;
}
itemlen = strlen(i);
if ( debug_idx + itemlen > 79 ) {
/* Needs flushing */
iodump_flush();
}
debug_buffer[debug_idx] = ' ';
strcpy(&debug_buffer[debug_idx+1],i);
debug_idx += itemlen + 1;
debug_any = 1;
}
}
void iobuffer_fill_segment(struct IOBuffer *iob, ifax_uint8 **dst, int *len)
{
if ( iob->size >= iob->total ) {
/* No space available */
*dst = 0;
*len = 0;
return;
}
*dst = &iob->data[iob->fp];
if ( iob->fp < iob->dp ) {
*len = iob->dp - iob->fp;
return;
}
*len = iob->total - iob->fp;
}
void iobuffer_fill_update(struct IOBuffer *iob, int size, char *info)
{
char prefix[128];
if ( info != 0 ) {
strcpy(prefix,iob->descr);
strcat(prefix,info);
}
if ( iob->fp < iob->total ) {
/* Didn't wrap around */
if ( info != 0 )
iodump(prefix,&iob->data[iob->fp],size);
iob->fp += size;
iob->size += size;
} else {
/* Did wrap, split logging in two */
if ( info != 0 ) {
iodump(prefix,&iob->data[iob->fp],iob->total-iob->fp);
iob->fp = iob->fp + size - iob->total;
iob->size += size;
iodump(prefix,&iob->data[0],iob->fp);
}
}
iodump_flush();
}
void iobuffer_fill(struct IOBuffer *iob, ifax_uint8 *src, int size)
{
int chunk;
ifax_uint8 *dst;
if ( size <= 0 )
return;
while ( size > 0 ) {
iobuffer_fill_segment(iob,&dst,&chunk);
if ( chunk == 0 ) {
/* Oops, we couldn't get all to fit in buffer! */
break;
}
if ( size < chunk )
chunk = size;
memcpy(dst,src,chunk);
src += chunk;
size -= chunk;
iobuffer_fill_update(iob,chunk," FILL:");
}
}
void iobuffer_drain_segments(struct IOBuffer *iob,
ifax_uint8 **src1, int *len1,
ifax_uint8 **src2, int *len2)
{
if ( iob->size == 0 ) {
/* No data in buffer at all */
*src1 = 0, *len1 = 0;
*src2 = 0, *len2 = 0;
return;
}
if ( iob->dp < iob->fp ) {
/* One continous segment */
*src1 = &iob->data[iob->dp];
*len1 = iob->fp - iob->dp;
*len2 = 0;
return;
}
/* Two segments */
*src1 = &iob->data[iob->dp];
*len1 = iob->total - iob->dp;
*src2 = &iob->data[0];
*len2 = iob->fp;
}
void iobuffer_drain_update(struct IOBuffer *iob, int size)
{
iob->size -= size;
iob->dp += size;
if ( iob->dp >= iob->total )
iob->dp -= iob->total;
}
int iobuffer_drain(struct IOBuffer *iob, ifax_uint8 *dst, int size)
{
int len1, len2, total;
ifax_uint8 *src1, *src2;
iobuffer_drain_segments(iob,&src1,&len1,&src2,&len2);
if ( len1 == 0 )
return 0;
if ( size < len1 ) {
memcpy(dst,src1,size);
return size;
}
memcpy(dst,src1,len1);
dst += len1;
total = len1;
size -= len1;
if ( size > 0 ) {
if ( size < len2 ) {
memcpy(dst,src2,size);
total += size;
} else {
memcpy(dst,src2,len2);
total += len2;
}
}
return total;
}
int iobuffer_read(struct IOBuffer *iob, int fd)
{
int rc, total = 0;
ifax_uint8 *dst;
int size;
for (;;) {
iobuffer_fill_segment(iob,&dst,&size);
if ( size == 0 )
break;
rc = read(fd,dst,size);
if ( rc < 0 ) {
if ( errno == EAGAIN )
break;
if ( errno == EINTR )
continue;
printf("Errno1=%d (%s)\n",errno,strerror(errno));
exit(69);
}
total += rc;
}
iobuffer_fill_update(iob,total," READ:");
return total;
}
int iobuffer_write(struct IOBuffer *iob, int fd)
{
char prefix[64];
int rc, total = 0;
ifax_uint8 *src1, *src2;
int len1, len2;
for (;;) {
iobuffer_drain_segments(iob,&src1,&len1,&src2,&len2);
if ( len1 == 0 )
break;
rc = write(fd,src1,len1);
if ( rc < 0 ) {
if ( errno == EAGAIN )
break;
if ( errno == EINTR )
continue;
printf("Errno2=%d (%s)\n",errno,strerror(errno));
exit(69);
}
if ( iob->debug & WRITE ) {
strcpy(prefix,iob->descr);
strcat(prefix," WRITE:");
iodump(prefix,src1,rc);
}
total += rc;
iobuffer_drain_update(iob,rc);
}
if ( iob->debug & WRITE )
iodump_flush();
return total;
}

File diff suppressed because it is too large Load Diff

View File

@ -32,12 +32,12 @@
* port.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/timeb.h>
#include <sys/time.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
@ -391,12 +391,10 @@ void pty_service_read(struct PtyHandle *ph)
if ( logsize1 < chunk )
goto all_ok;
if ( ph->rx.wp >= PTY_BUFFERSIZE )
ph->rx.wp = 0;
ph->rx.wp = 0;
if ( (chunk = PTY_BUFFERSIZE - ph->rx.size) == 0 )
goto all_ok;
ph->rx.wp = 0;
log2 = &ph->rx.buffer[ph->rx.wp];
logsize2 = read(ph->ptyfd,log2,chunk);
if ( logsize2 < 0 ) {
@ -492,7 +490,7 @@ void pty_printf(struct PtyHandle *ph, char *format, ... )
char tmp[PTY_PRINTF_MAXSIZE+4];
va_start(args,format);
vsnprintf(tmp, PTY_PRINTF_MAXSIZE, format, args);
vsprintf(tmp, format, args);
va_end(args);
pty_write(ph,tmp,strlen(tmp));

View File

@ -37,6 +37,8 @@
#include <ifax/misc/readconfig.h>
#include <ifax/misc/globals.h>
#include <ifax/misc/malloc.h>
#include <ifax/misc/hardware-driver.h>
#ifndef DEFAULT_CONFIG_FILE
@ -47,10 +49,6 @@
#define DEFAULT_PID_FILE "/var/run/amodemd.pid"
#endif
#ifndef DEFAULT_ISDN_DEVICE
#define DEFAULT_ISDN_DEVICE "/dev/ttyI5"
#endif
#ifndef DEFAULT_WATCHDOG_TIMEOUT
#define DEFAULT_WATCHDOG_TIMEOUT 0
#endif
@ -59,10 +57,6 @@
#define DEFAULT_REALTIME_PRIORITY 0
#endif
#ifndef DEFAULT_ISDN_MSN
#define DEFAULT_ISDN_MSN "5551234"
#endif
#ifndef DEFAULT_COUNTRY
#define DEFAULT_COUNTRY "47"
#endif
@ -73,8 +67,6 @@
char *config_file = DEFAULT_CONFIG_FILE;
char *pid_file = DEFAULT_PID_FILE;
char *isdn_device = DEFAULT_ISDN_DEVICE;
char *isdn_msn = DEFAULT_ISDN_MSN;
char *subscriber_id = "";
char *home_country = DEFAULT_COUNTRY;
char *int_prefix = DEFAULT_INT_PREFIX;
@ -85,27 +77,41 @@ int do_lock_memory = 1;
#define MAXCFGLINE 128
static int cmd_nmatch(char *cmd, char **pp, int count)
{
char *c = cmd, *p = *pp;
while ( count-- ) {
if ( tolower(*c) != tolower(*p) )
return 0;
c++, p++;
}
*pp = p;
return 1;
}
static int cmd_match(char *cmd, char **pp)
{
char *c, *p;
c = cmd;
p = *pp;
char *c = cmd, *p = *pp;
while ( *c && *p ) {
if ( tolower(*c) != tolower(*p) )
return 0;
c++, p++;
}
while ( *c && *p ) {
if ( tolower(*c) != tolower(*p) )
return 0;
c++, p++;
}
if ( *c )
return 0;
if ( *c )
return 0;
*pp = p;
*pp = p;
return 1;
return 1;
}
static void skip_assignment(char **pp)
{
char *p = *pp;
@ -159,7 +165,7 @@ static char *get_string(char **pp)
if ( *p == '"' ) {
start = p + 1;
stop = index(start,'"');
stop = strrchr(start,'"');
if ( stop == 0 ) {
fprintf(stderr,"%s: Missing terminating \" in string in config file\n",
progname);
@ -181,6 +187,21 @@ static char *get_string(char **pp)
return string;
}
static char *get_param_string(char **pp)
{
int length = 0;
char *string, *p = *pp, *start = *pp;
while ( *p != '=' && !isspace(*p) )
length++, p++;
string = ifax_malloc(length+1,"Parameter string for configure");
strncpy(string,start,length);
string[length] = '\0';
return string;
}
static void end_line(char **pp)
{
char *p = *pp;
@ -196,121 +217,144 @@ static void end_line(char **pp)
void read_configuration_file(void)
{
FILE *cfg;
char *p, *tmp;
char buffer[MAXCFGLINE+4];
FILE *cfg;
char *p, *tmp;
char buffer[MAXCFGLINE+4];
char hwprefix[32], *hardware, *param, *value;
if ( (cfg=fopen(config_file,"r")) == 0 ) {
fprintf(stderr,"%s: Unable to read config file '%s'\n",
progname,config_file);
exit(1);
}
for (;;) {
if ( fgets(buffer,MAXCFGLINE,cfg) == 0 )
break;
p = buffer;
while ( isspace(*p) )
p++;
if ( *p == '#' )
continue;
if ( cmd_match("pidfile",&p) ) {
skip_assignment(&p);
pid_file = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("isdn-device",&p) ) {
skip_assignment(&p);
isdn_device = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("isdn-msn",&p) ) {
skip_assignment(&p);
isdn_msn = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("country",&p) ) {
skip_assignment(&p);
home_country = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("international-prefix",&p) ) {
skip_assignment(&p);
int_prefix = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("watchdog-timer",&p) ) {
skip_assignment(&p);
watchdog_timeout = get_int(&p);
end_line(&p);
if ( watchdog_timeout < 0 ) {
fprintf(stderr,"%s: Watchdog timer must be positive or zero\n",
progname);
exit(1);
}
continue;
}
if ( cmd_match("realtime-priority",&p) ) {
skip_assignment(&p);
realtime_priority = get_int(&p);
end_line(&p);
if ( realtime_priority < 0 || realtime_priority > 99 ) {
fprintf(stderr,"%s: Real-Time priority must be in range 0-99\n",
progname);
exit(1);
}
continue;
}
if ( cmd_match("lock-memory",&p) ) {
skip_assignment(&p);
do_lock_memory = get_int(&p);
end_line(&p);
if ( do_lock_memory < 0 || do_lock_memory > 1 ) {
fprintf(stderr,"%s: 'lock-memory' must be 0 or 1 in config file\n",
progname);
exit(1);
}
continue;
}
if ( cmd_match("subscriber-identification",&p) ) {
skip_assignment(&p);
subscriber_id = get_string(&p);
end_line(&p);
if ( strlen(subscriber_id) > 20 ) {
fprintf(stderr,"%s: subscriber-identification more than 20 chars\n",
progname);
exit(1);
}
tmp = subscriber_id;
while ( *tmp ) {
if ( *tmp != '+' && *tmp != ' ' && (*tmp < '0' || *tmp > '9') ) {
fprintf(stderr,"%s: subscriber-identification illegal char '%c'\n",
progname,*tmp);
exit(1);
if ( (cfg=fopen(config_file,"r")) == 0 ) {
fprintf(stderr,"%s: Unable to read config file '%s'\n",
progname,config_file);
exit(1);
}
tmp++;
}
continue;
}
}
fclose(cfg);
for (;;) {
if ( fgets(buffer,MAXCFGLINE,cfg) == 0 )
break;
p = buffer;
while ( isspace(*p) )
p++;
if ( *p == '#' )
continue;
if ( cmd_match("hardware",&p) ) {
skip_assignment(&p);
hardware = get_string(&p);
end_line(&p);
if ( hh != 0 ) {
fprintf(stderr,"%s: Multiple hardware defs\n",
progname);
exit(1);
}
hh = hardware_allocate(hardware);
if ( hh == 0 ) {
fprintf(stderr,"%s: Unknown hw '%s'\n",
progname,hardware);
exit(1);
}
strcpy(hwprefix,hardware);
strcat(hwprefix,"-");
continue;
}
if ( hh != 0 && cmd_nmatch(hwprefix,&p,strlen(hwprefix) ) ) {
param = get_param_string(&p);
skip_assignment(&p);
value = get_string(&p);
end_line(&p);
hh->configure(hh,param,value);
free(param);
free(value);
continue;
}
if ( cmd_match("pidfile",&p) ) {
skip_assignment(&p);
pid_file = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("country",&p) ) {
skip_assignment(&p);
home_country = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("international-prefix",&p) ) {
skip_assignment(&p);
int_prefix = get_string(&p);
end_line(&p);
continue;
}
if ( cmd_match("watchdog-timer",&p) ) {
skip_assignment(&p);
watchdog_timeout = get_int(&p);
end_line(&p);
if ( watchdog_timeout < 0 ) {
fprintf(stderr,"%s: Watchdog timer must be positive or zero\n",
progname);
exit(1);
}
continue;
}
if ( cmd_match("realtime-priority",&p) ) {
skip_assignment(&p);
realtime_priority = get_int(&p);
end_line(&p);
if ( realtime_priority < 0
|| realtime_priority > 99 ) {
fprintf(stderr,"%s: Real-Time priority must be in range 0-99\n",
progname);
exit(1);
}
continue;
}
if ( cmd_match("lock-memory",&p) ) {
skip_assignment(&p);
do_lock_memory = get_int(&p);
end_line(&p);
if ( do_lock_memory < 0 || do_lock_memory > 1 ) {
fprintf(stderr,"%s: 'lock-memory' must be 0 or 1 in config file\n",
progname);
exit(1);
}
continue;
}
if ( cmd_match("subscriber-identification",&p) ) {
skip_assignment(&p);
subscriber_id = get_string(&p);
end_line(&p);
if ( strlen(subscriber_id) > 20 ) {
fprintf(stderr,"%s: subscriber-identification more than 20 chars\n",
progname);
exit(1);
}
tmp = subscriber_id;
while ( *tmp ) {
if ( *tmp != '+' && *tmp != ' ' && (*tmp < '0' || *tmp > '9') ) {
fprintf(stderr,"%s: subscriber-identification illegal char '%c'\n",
progname,*tmp);
exit(1);
}
tmp++;
}
continue;
}
}
fclose(cfg);
}

View File

@ -30,84 +30,164 @@
* as viewed/defined by this file is simply a collection of functions
* that gets called in a certain way, and that manipulates its state
* through the macros in the corresponding include-file.
*
* State machines are grouped together into "state machine groups".
* Before a state machine can be used, it has to be allocated, along
* with its possible co-working state-machines, and initialized.
* This is done like:
*
* smh = allocate_statemachines(number_of_statemachines,stacksize);
* allocate_statemachine_stack(smh, 0, 1024);
* allocate_statemachine_stack(smh, 2, 128);
* fsm_init(smh, 0, init_state_fsm0, 100, &globals[x]);
* fsm_init(smh, 1, init_state_fsm1, 10, some_handle);
* fsm_init(smh, 2, init_state_fsm2, 25, private_data);
* ...
* run_statemachines(smh);
*
*/
#include <ifax/misc/statemachine.h>
#include <strings.h>
#include <ifax/types.h>
#include <ifax/debug.h>
#include <ifax/misc/malloc.h>
#include <ifax/misc/statemachine.h>
/* Max number of direct (immediate) state-jumps can be allowed
* before we have to pre-empt the state-machine to avoid lock-ups.
*/
#define MAXSEQSTATEJUMPS 16
static struct statemachine fsm_state[MAXSTATEMACHINES], *running;
void initialize_statemachines(void)
struct StateMachinesHandle *fsm_allocate(int count)
{
int t;
int t;
struct StateMachinesHandle *smh;
running = 0;
for ( t = 0; t < MAXSTATEMACHINES; t++ ) {
fsm_state[t].state = 0;
}
smh = ifax_malloc(sizeof(*smh), "State machine set instance");
smh->running = 0;
smh->fsm = ifax_malloc(count * sizeof(*smh->fsm),
"State machine instances");
for ( t = 0; t < count; t++ ) {
smh->fsm[t].state = 0;
smh->fsm[t].next = 0;
smh->fsm[t].stackdata = 0;
}
return smh;
}
void init_fsm(int machineid, void (*startstate)(struct statemachine *))
void fsm_setup(struct StateMachinesHandle *smh, int machineid, int size)
{
/* Link into 'running' chain if previously not active */
if ( fsm_state[machineid].state == 0 ) {
fsm_state[machineid].next = running;
running = &fsm_state[machineid];
}
fsm_state[machineid].stackpointer = 0;
fsm_state[machineid].state = startstate;
if ( smh->fsm[machineid].stackdata != 0 )
free(smh->fsm[machineid].stackdata);
smh->fsm[machineid].stackdata = ifax_malloc(size,"FSM stack data");
}
void kill_fsm(int machineid)
void fsm_init(struct StateMachinesHandle *smh, int machineid,
fsm_t init_state, int maxloops, void *private)
{
struct statemachine *previous, *kill = &fsm_state[machineid];
/* Link into 'running' chain if previously not active */
if ( smh->fsm[machineid].state == 0 ) {
smh->fsm[machineid].next = smh->running;
smh->running = &smh->fsm[machineid];
}
fsm_state[machineid].state = 0;
/* Setup stack */
smh->fsm[machineid].sp = 0;
smh->fsm[machineid].private = private;
smh->fsm[machineid].stackframe[0] = smh->fsm[machineid].stackdata;
smh->fsm[machineid].stackframesize[0] = 0;
if ( running == kill ) {
running = running->next;
return;
}
/* Set state to wake up in */
smh->fsm[machineid].state = init_state;
strcpy(smh->fsm[machineid].lastfunc,"(init)");
smh->fsm[machineid].lastfunc_count = 0;
previous = running;
while ( previous->next != 0 ) {
if ( previous->next == kill ) {
previous->next = previous->next->next;
return;
}
}
return; /* Shouldn't get here, actually */
/* Misc */
smh->fsm[machineid].debug = 1;
smh->fsm[machineid].maxloops = maxloops;
}
void run_statemachines(void)
void fsm_kill(struct StateMachinesHandle *smh, int machineid)
{
void (*prev)(struct statemachine *);
struct statemachine *current;
int t;
struct statemachine *previous, *kill;
for ( current = running; current != 0; current = current->next ) {
kill = &smh->fsm[machineid];
smh->fsm[machineid].state = 0;
for ( t=0; t < MAXSEQSTATEJUMPS; t++ ) {
prev = current->state;
(current->state)(current);
if ( current->state == prev )
goto next_fsm;
}
if ( smh->running == kill ) {
smh->running = smh->running->next;
kill->next = 0;
return;
}
/* Something probably has gone very wrong, print a warning */
ifax_dprintf(DEBUG_SEVERE,"State-machine %d run-away\n",
current-fsm_state);
next_fsm: ;
}
previous = smh->running;
for (;;) {
if ( previous->next == kill ) {
previous->next = previous->next->next;
kill->next = 0;
return;
}
/* Trying to kill a fsm not running will cause SEGV here... */
previous = previous->next;
}
}
void fsm_run(struct StateMachinesHandle *smh)
{
fsm_t prev;
struct statemachine *run;
int t;
for ( run = smh->running; run != 0; run = run->next ) {
for ( t=0; t < run->maxloops; t++ ) {
prev = run->state;
run->state(run);
if ( run->state == prev )
goto next_fsm;
}
/* Something probably has gone very wrong, print a warning */
ifax_dprintf(DEBUG_SEVERE,"State-machine run-away\n");
next_fsm: ;
}
}
void *_fsm_debug_entry(struct statemachine *fsmself, char *function_name)
{
int t;
char spaces[80];
if ( !fsmself->debug )
return 0;
strcpy(fsmself->stack_function[fsmself->sp],function_name);
if ( strcmp(fsmself->lastfunc, function_name) ) {
/* We have jumped to a new function */
spaces[0] = '\0';
for ( t=0; t < 8 && t < fsmself->lastsp; t++ )
strcat(spaces," ");
ifax_dprintf(DEBUG_DEBUG,"FSM %s%s (%d) -> %s\n",spaces,
fsmself->lastfunc, fsmself->lastfunc_count,
function_name);
strcpy(fsmself->lastfunc, function_name);
fsmself->lastfunc_count = 1;
fsmself->lastsp = fsmself->sp;
return 0;
}
if ( fsmself->lastfunc_count++ > 10000 ) {
ifax_dprintf(DEBUG_WARNING,"FSM stuck at %s?\n",
fsmself->lastfunc);
}
return 0;
}
void _fsm_debug_exit(void *dummy)
{
}

View File

@ -45,38 +45,68 @@
#include <ifax/misc/softsignals.h>
static struct {
ifax_sint32 current_value;
ifax_sint32 initial_value;
ifax_sint32 current_value;
ifax_sint32 initial_value;
} timers[MAX_TIMERS];
void one_shot_timer(int timer_num, ifax_sint32 delay)
{
timers[timer_num].current_value = delay;
timers[timer_num].initial_value = 0;
softsignaled_clr(timer_num);
timers[timer_num].current_value = delay;
timers[timer_num].initial_value = 0;
softsignaled_clr(timer_num);
}
void reset_timers(void)
{
int t;
int t;
for ( t=0; t < MAX_TIMERS; t++ ) {
timers[t].current_value = 0;
timers[t].initial_value = 0;
}
for ( t=0; t < MAX_TIMERS; t++ ) {
timers[t].current_value = 0;
timers[t].initial_value = 0;
}
}
void decrease_timers(ifax_sint32 dec)
{
int t;
for ( t=0; t < MAX_TIMERS; t++ ) {
if ( timers[t].current_value > 0 ) {
timers[t].current_value -= dec;
if ( timers[t].current_value <= 0 ) {
softsignal(t);
if ( timers[t].initial_value > 0 )
timers[t].current_value += timers[t].initial_value;
}
}
}
int t;
for ( t=0; t < MAX_TIMERS; t++ ) {
if ( timers[t].current_value > 0 ) {
timers[t].current_value -= dec;
if ( timers[t].current_value <= 0 ) {
softsignal(t);
if ( timers[t].initial_value > 0 )
timers[t].current_value +=
timers[t].initial_value;
}
}
}
}
void hard_timer_init(hard_timer_t *ht, ifax_uint32 sec, ifax_uint32 usec)
{
gettimeofday(&ht->expires,(struct timezone *)0);
ht->expires.tv_sec += sec;
ht->expires.tv_usec += usec;
if ( ht->expires.tv_usec > 1000000 ) {
ht->expires.tv_sec++;
ht->expires.tv_usec -= 1000000;
}
}
int hard_timer_expired(hard_timer_t *ht)
{
struct timeval now;
gettimeofday(&now,(struct timezone *)0);
if ( now.tv_sec < ht->expires.tv_sec )
return 0;
if ( now.tv_sec > ht->expires.tv_sec )
return 1;
if ( now.tv_usec >= ht->expires.tv_usec )
return 1;
return 0;
}

View File

@ -1,5 +1,10 @@
LDFLAGS=-lm
CFLAGS=-O2 -g -Wall -pedantic -I../include
# Use this for development
CFLAGS=-ggdb -Wall -pedantic -ansi -I../include -Dinline=
#Use this for production
# CFLAGS=-O4 -Wall -pedantic -I../include
MODULES = send_to_audio.o pulsegen.o sinegen.o replicate.o \
scrambler.o modulator-V29.o fsk_demod.o fsk_mod.o \
@ -14,5 +19,8 @@ all: modules.a
modules.a: $(MODULES) $(HELPERS)
$(AR) rcs $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $<
clean:
rm -f $(MODULES) modules.a *~

View File

@ -62,7 +62,7 @@ typedef struct {
*/
void decode_serial_destroy(ifax_modp self)
{
decode_serial_private *priv=(decode_serial_private *)self->private;
/* decode_serial_private *priv=(decode_serial_private *)self->private; */
free(self->private);
@ -90,7 +90,7 @@ int decode_serial_handle(ifax_modp self, void *data, size_t length)
currconf=*dat++;
priv->sampcount++;
// printf("%d,%d\n",currbit,currconf);
/* printf("%d,%d\n",currbit,currconf); */
if (currconf<10) continue;
@ -120,8 +120,8 @@ int decode_serial_handle(ifax_modp self, void *data, size_t length)
result|=priv->lastbits[x+1]<<x;
parity^=priv->lastbits[x+1];
}
// for (x=0;x<priv->bitnum;x++)
// printf("%d%s",priv->lastbits[x], (x==0 || x==8) ? " " : "");
/* for (x=0;x<priv->bitnum;x++)
printf("%d%s",priv->lastbits[x], (x==0 || x==8) ? " " : ""); */
priv->bitnum=-1;
switch(priv->parity) {
case PAR_NONE: parity=0;break;
@ -131,7 +131,7 @@ int decode_serial_handle(ifax_modp self, void *data, size_t length)
case PAR_ZERO: parity=(0!=priv->lastbits[8]);break;
}
hlpres=result;
// printf(" %c\n",result);
/* printf(" %c\n",result); */
if (parity==0 && self->sendto)
ifax_handle_input(self->sendto,&hlpres,1);
}

View File

@ -35,7 +35,7 @@
#include <sys/times.h>
#include <ifax/ifax.h>
#include <ifax/modules/decode_hdlc.h>
//#include <ifax/modules/faxcontrol.h>
#include <ifax/modules/faxcontrol.h>
#define MAXLENGTH 1024
@ -248,7 +248,7 @@ int faxcontrol_construct(ifax_modp self,va_list args)
self->handle_input =faxcontrol_handle;
self->command =faxcontrol_command;
// priv->baud=va_arg(args,int);
/* priv->baud=va_arg(args,int); */
priv->length=0; /* Init to 0 bytes in queue */
return 0;

View File

@ -43,6 +43,7 @@
#include <sys/times.h>
#include <ifax/ifax.h>
#include <ifax/alaw.h>
#include <ifax/constants.h>
/* Turn on to generate a big bunch of debugging code.
*/
@ -149,7 +150,7 @@ static void init_four_help(fskdemod_private *priv,four_help *hlp,int depth,int f
ftptr=hlp->fasttable;
for(x=0;x<hlp->stdepth/256;x++)
{
sinval=sin(x*2.0*M_PI*(double)freq/(double)priv->sps);
sinval=sin(x*2.0*IFAX_PI*(double)freq/(double)priv->sps);
for(y=0;y<256;y++)
*ftptr++=((int)(sinval*532610.0*wala2sint[y])) >>
((sizeof(int)-sizeof(char))*8);

View File

@ -36,6 +36,7 @@
#include <stdarg.h>
#include <sys/times.h>
#include <ifax/ifax.h>
#include <ifax/constants.h>
/* Turn on to generate a big bunch of debugging code.
*/
@ -53,7 +54,7 @@ typedef struct {
*/
void fskmod_destroy(ifax_modp self)
{
fskmod_private *priv=(fskmod_private *)self->private;
/* fskmod_private *priv=(fskmod_private *)self->private; */
free(self->private);
@ -77,7 +78,7 @@ int fskmod_handle(ifax_modp self, void *data, size_t length)
priv->currphase+= *input++ ? priv->p1 : priv->p2 ;
dat=int2alaw((int)(0.62*2147483647.0*sin(priv->currphase)));
// dat=linear2ulaw((short)(25000.0*sin(priv->currphase)));
/* dat=linear2ulaw((short)(25000.0*sin(priv->currphase))); */
#if 0
ifax_dprintf(DEBUG_DEBUG,"Phases: %8.5f %11d %5d %11d %11d\n",sin(priv->currphase),
(int)(2147483647.0*sin(priv->currphase)),
@ -102,8 +103,8 @@ int fskmod_construct(ifax_modp self,va_list args)
priv->f1 =va_arg(args,int);
priv->f2 =va_arg(args,int);
priv->p1 =(double)2.0*M_PI * (double)priv->f1 / SAMPLES_PER_SECOND ;
priv->p2 =(double)2.0*M_PI * (double)priv->f2 / SAMPLES_PER_SECOND ;
priv->p1 =(double)2.0*IFAX_PI*(double)priv->f1 / SAMPLES_PER_SECOND;
priv->p2 =(double)2.0*IFAX_PI*(double)priv->f2 / SAMPLES_PER_SECOND;
priv->currphase=0.0;
ifax_dprintf(DEBUG_DEBUG,"Phases : %f %f\n",priv->p1,priv->p2);

View File

@ -105,7 +105,7 @@ typedef struct {
int dsp_fd; /* File-descriptor for audio-monitoring */
int rec_fd; /* File-descriptor for recording */
struct IsdnHandle *ih; /* Handle for the ISDN interface */
struct HardwareHandle *hh; /* Handle for the phone interface */
int loopback; /* Nonzero if software loopback enabled */
ifax_sint32 dsp_rx_volume; /* Audio-monitoring Rx-level */
ifax_sint32 dsp_tx_volume; /* Audio-monitoring Tx-level */
@ -302,8 +302,8 @@ static int linedriver_command(ifax_modp self, int cmd, va_list cmds)
priv->dsp_fd = init_audio();
break;
case CMD_LINEDRIVER_ISDN:
priv->ih = va_arg(cmds,struct IsdnHandle *);
case CMD_LINEDRIVER_HARDWARE:
priv->hh = va_arg(cmds,struct HardwareHandle *);
break;
case CMD_LINEDRIVER_LOOPBACK:

View File

@ -25,9 +25,11 @@
******************************************************************************
*/
#include <stdarg.h>
#include <math.h>
#include <ifax/ifax.h>
#include <ifax/constants.h>
typedef struct {
@ -79,7 +81,7 @@ int sinegen_construct(ifax_modp self,va_list args)
self->command =sinegen_command;
frequency=va_arg(args,int);
priv->step=2.0*M_PI*(double)frequency/SAMPLES_PER_SECOND;
priv->step=2.0*IFAX_PI*(double)frequency/SAMPLES_PER_SECOND;
priv->currphase=0.0;
return 0;