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:
parent
08977969df
commit
cc0fcaee0a
201
G3/fsm.c
201
G3/fsm.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -36,5 +36,5 @@ struct G3fax *fax;
|
|||
|
||||
void fax_run_internals(void)
|
||||
{
|
||||
run_statemachines();
|
||||
fsm_run(fax->statemachines);
|
||||
}
|
||||
|
|
2
Makefile
2
Makefile
|
@ -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
108
amodemd.c
|
@ -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"); */
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 $@ $^
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
1632
misc/isdnline.c
1632
misc/isdnline.c
File diff suppressed because it is too large
Load Diff
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 *~
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue