Logo Search packages:      
Sourcecode: acfax version File versions  Download package

fax_funcs.c

/*
    ACfax - Fax reception with X11-interface for amateur radio
    Copyright (C) 1995-1998 Andreas Czechanowski, DL4SDC

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    andreas.czechanowski@ins.uni-stuttgart.de
*/
    
/* fax_funcs.c - all fax-specific functions should be placed here.
 *           This file depends on neary everything; It calls the hardware-
 *           specific setup, the filter setup, and needs some X11-
 *           variables for writing into the canvas.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "x_image.h"
#include <X11/Intrinsic.h>
#include "sblaster.h"
#include "mod_demod.h"
#include "widgets.h"
#include "fax_funcs.h"

/* some variables that are allowed to be global */
int   lpm;        /* lines per minute */
int     ixoc;           /* number of pixels of one scan-line / PI */
int   devi;       /* deviation in Hz (+/- of middle) */
int     mod_mode;       /* can be MOD_FM or MOD_AM */
int     aptstart;       /* possible APT start values */
int     aptstop;        /* possible APT stop values */
int   aptdur;           /* apt duration in millisecs (for transmitting) */
int   vertical;   /* vertical or horizontal line direction */
int     right2left;     /* boolean indicating reverse line writing direction */
int     bot2top;        /* boolean indicating reverse line stacking direction */
int   invphase;   /* polarity of phase-in-signal to use */
int   invimage;   /* inverse colormap usage */
/* and the private variables */
int   fax_inited = 0;   /* if fax_init was called */
unsigned canwid;  /* width of the Pixmap to draw in */
unsigned canhei;  /* height of the Pixmap */
int   sxpos, sypos;     /* current coordinates of received/xmitted data */
int   pixpos, linepos; /* current coordinates of received/xmitted data */
int   imline;           /* currently processed line of XImage */
void  (*update_area)(XImage *, int, int, int, int, unsigned, unsigned);
      /* called to copy XImage to Pixmap and update the window-area required */
void  (*mode_notify)(int); /* notifies main program of changes of fax_state */
int   mcolor;           /* color-mode selected */
int   dmaxval;    /* number of usable grayscale-values - 1 */
int   compval;    /* comparator value for APT-counter */
int   flip;       /* flipping of green and blue parts of the colormap */
int   rotate;           /* rotation of the colormap */
int     fax_state;      /* one of FAX_APT, FAX_PHAS or FAX_RX */
char  *core_dta;  /* storage for raw demodulated data (accumulating) */
char  *core_start;      /* start of core for image-processing */
char  *core_wptr; /* pointer to next written element in core_dta */
char  *core_maxptr;     /* pointer beyond the last element in core_dta */
void  (*disp_func)(int); /* pointer to function displaying the data-stream */
int   (*save_func)(int, int);
                  /* pointer to function saving image to file */
void  (*fax_tx_func)(int); /* pointer to function transmitting image */
int   disp_locked;      /* flag indicating that disp_func should not be called
                     from fax_rx_backgnd */
int   save_locked;      /* same as above for save_func */
void    (*apt_notify)(int); /* pointer to function evaluating APT frequency */
unsigned smplf;         /* number of samples per second << 16 */
unsigned smpl_line;     /* number of samples per line << 16 */
unsigned hsmpl_sec;     /* half the number of samples per second */
int     aptncmax;       /* maximum "empty" points in an APT-line */
int   phstate = 0;      /* state (0=waiting, 1=active) of phase-finder */
int   phlines;    /* number of recognized phase-lines */
unsigned hsmpl_line;    /* half the number of samples per line */
int   phposa[24]; /* phase position A (middle of line) */
int   phposb[24]; /* phase position B (edges of line) */
int   phsdir[24]; /* phase direction (beginning or end of line) */
int   phaseavg;   /* average phase position calculated */
char  *demod_ptr; /* pointer to raw demodulated data */
int   demod_cnt;  /* number of decoded points per call */
char  *mod_ptr;   /* pointer to raw data being modulated */
char  *mod_end;   /* pointer to first byte behind end of modulator-space */
FILE  *fsfile;    /* file pointer of current save-file */
char  faxsavename[256]; /* current name of save-file */
char  *saveline;  /* storage for 1 image-line in save_func */
XtAppContext      mainapp; /* main app.context (needed for interv.timer) */
XtIntervalId      chstime; /* for the repetitive called background function */
XtInputId   dspxid = 0; /* for the background function when using select() */
XEvent      event;            /* event needed to form the XtAppMainLoop */
unsigned twidth;  /* width of transmitted image */
unsigned theight; /* height of transmitted image */
int   tx_phlines; /* number of phase-in lines to be transmitted */
char  *timg_ptr;  /* array holding image to be transmitted (pixel oriented) */
FILE  *ftfile;    /* pointer to file-struct for transmission */

/*
 * init_fax initializes the "core"-space where the raw decoded data resides.
 * This practice is not very nice to memory-limited systems, but has the
 * advantage of being able to back up from nearly any setup-error (including
 * wrong lpm, IOC, direction and color-mode but excluding tuning-errors)
 */
void init_fax(void)
{
  if (fax_inited) return;
  fprintf(stderr, "initializing FAX procedures and alloc'ing core-space\n");
  lpm = 120;
  ixoc = 288;
  devi = 400;
  mod_mode = MOD_FM | FIL_MIDL;
  dmaxval = 63;
  compval = dmaxval >> 1;
  core_dta = malloc(CORESIZE);
  core_start = core_dta;
  core_wptr = core_dta;
  core_maxptr = core_dta + COREMAX;
  interface_init(&demod_ptr, &demod_cnt);
  setup_mode(mod_mode, dmaxval, devi, &smplf);
  hsmpl_sec = smplf >> 17;
  aptncmax = hsmpl_sec / 25;
  mod_end = demod_ptr + demod_cnt;
  mod_ptr = demod_ptr;
  fprintf(stderr, "smplf = %08x (16.16), demod_cnt = %d\n", smplf, demod_cnt);
  disp_func = decode_fax_gray;
  fax_tx_func = transmit_fax_gray;
  save_func = save_fax_gray;
  fsfile = NULL;
  saveline = NULL;
  apt_notify = apt_control;
  chstime = (XtIntervalId) 0;

  timg_ptr = NULL;
  ftfile = NULL;

  fax_inited = 1;
}

/* exit_fax frees the core_dta space, so that other program-parts may
   allocate memory without having a dead-space overhead.
*/
void exit_fax(void)
{
  if (!fax_inited) return;
  free(core_dta);
  fax_inited = 0;
}

/*
 * setup_fax sets up all the variables for FAX-reception and transmission.
 * s_lpm : lines per minute (no change if set to 0)
 * s_ixoc: IOC to use (pixels per line = PI * IOC) (no change if set to 0)
 * mode  : fax-specific mode setings such as writing direction and order,
 *       phase-in polarity and grayscale or color-mode
 * s_devi: deviation to use for FM (no change if set to 0)
 * s_modem : (de-)modulator-specific settings as filter to use, AM or FM 
 */
void setup_fax(int s_lpm, int s_ixoc, unsigned mode,
      Widget toplevel, unsigned width, unsigned height,
      int s_devi, unsigned s_modem)
{
  unsigned id;
  unsigned filter, mmode;
  void (*old_func)(int);

  /* be sure initialisation is done */
  init_fax();

  mainapp = XtWidgetToApplicationContext(toplevel);
  /* if size is given or has changed, re-create X-images */
  if ((width) || (height)) {
    if (width)
      canwid = width;
    if (height)
      canhei = height;
    create_images(toplevel, canwid, canhei);
  }
  /* check if the (de-)modulator needs readjustment */
  filter = s_modem & FIL_MASK;
  mmode = s_modem & MOD_BITS;
  if ((filter) || (mmode) || (s_devi)) {
    fprintf(stderr, "setting filter & mmode = 0x%04x\n", (filter | mmode));
    if (s_devi) {
      if (s_devi < 100) s_devi = 100;
      if (s_devi > 1200) s_devi = 1200;
      devi = s_devi;
    }
    setup_mode((filter | mmode), dmaxval, s_devi, &smplf);
    hsmpl_sec = smplf >> 17;
    aptncmax = hsmpl_sec / 25;
    if (filter)
    {
      mod_mode = (~FIL_MASK & mod_mode) | filter;
    }
    if (mmode)
    {
      mod_mode = (~MOD_BITS & mod_mode) | mmode;
    }
  }

  if (s_lpm) {
    if (s_lpm < 60) s_lpm = 60;
    if (s_lpm > 500) s_lpm = 500;
    lpm = s_lpm;
    fprintf(stderr, "changing lpm to %d\n", lpm);
  }
  if (s_ixoc) {
    if (s_ixoc < 60) s_ixoc = 60;
    if (s_ixoc > 600) s_ixoc = 600;
    ixoc = s_ixoc;
    fprintf(stderr, "changing ioc to %d\n", ixoc);
  }
  if ((id = mode & FAX_POL)) {
    if (id == FAX_CNOR) {
      invimage = 0;
    } else {
      invimage = 1;
    }
    fprintf(stderr, "setting invimage mode to %d\n", invimage);
  }
  if ((id = mode & FAX_CFLS)) {
    if (id == FAX_CUNFL)  {
      flip = 0;
    } else {
      flip = 1;
    }
    fprintf(stderr, "setting color-flip to %d\n", flip);
  }
  if ((id = mode & FAX_CROTS)) {
    switch(id) {
      case FAX_CROT0:
      rotate = 0;
      break;
      case FAX_CROT1:
      rotate = 1;
      break;
      case FAX_CROT2:
      rotate = 2;
      break;
    }
    fprintf(stderr, "setting color-rotation to %d\n", rotate);
  }
  if ((id = mode & FAX_DIR)) {
    if (id & FAX_TOP2BOT)
      bot2top = 0;
    else if (id & FAX_BOT2TOP)
      bot2top = 1;

    if (id & FAX_LEF2RIG)
      right2left = 0;
    else if (id & FAX_RIG2LEF)
      right2left = 1;

    fprintf(stderr, "changing direction to h=%d, v=%d\n", right2left, bot2top);
  }
  if ((id = mode & FAX_ROT)) {
    if (id == FAX_HOR) {
      vertical = 0;
    } else {
      vertical = 1;
    }
    fprintf(stderr, "selecting %s direction\n",
       (vertical) ? "vertical" : "horizontal");
  }
  if ((id = mode & FAX_PHS)) {
    if (id == FAX_PWHT) {
      invphase = 1;
    } else {
      invphase = 0;
    }
    fprintf(stderr, "phase inversion mode = %d\n", invphase);
  }
  if ((id = mode & FAX_CMODE)) {
    switch (id) {
      case FAX_GRAY:
      mcolor = 0;
      break;
      case FAX_COLOR:
      mcolor = 1;
      break;
    }
    fprintf(stderr, "receive mode is %s\n", (mcolor) ? "color" : "grayscale");
  }
  /* now, all modifications to variables are done.
     some recomputations are to be done dependant on what has changed... */
  if (mode & FAX_CMODS)
    if (mcolor) {
      fill_cmap_col(invimage, flip, rotate);
    } else {
      fill_cmap_gray(invimage);
    }
  if ((mode & (FAX_DIR | FAX_ROT | FAX_CMODE | FAX_CMODS))
      || (s_ixoc) || (s_lpm) || (width) || (height)
      || (s_modem & MOD_BITS)) {
    if (mcolor) {
      disp_func = decode_fax_gray;
      save_func = save_fax_gray;
    } else {
      disp_func = decode_fax_gray;
      save_func = save_fax_gray;
    }
    /* recomputations are done in disp_func() */
    fprintf(stderr, "initializing disp_func\n");
    disp_func(D_CPINIT | D_WDINIT | D_LDINIT);
    /* now call function to re-create picture */
#if stillneeded   /* the disp_func should lock itself */
    old_func = disp_func;
    disp_func = NULL;
    fprintf(stderr, "calling disp_func to re-display image\n");
    old_func(D_ALLOWX);
    disp_func = old_func;
#else
    fprintf(stderr, "calling disp_func to re-display image\n");
    disp_func(D_ALLOWX);
#endif
  }
  if ((mmode) && (dspxid != 0))
  {
    /* re-initiate data reception, because changing the modulation mode
     * (and thus changing the sample rate) requires the data stream to
     * stop. [Later, this should be RX or TX depending on what we do] */
    fax_rx_backgnd((XtPointer) NULL, &dspfd, (XtInputId *) NULL);
  }
}

/* enable FAX reception: set auto-initializing background function */
void receive_on(void)
{
#ifndef DSP_SELECT
  if (chstime != (XtIntervalId) 0) return;
#endif
  fax_state = FAX_APT;
  mode_notify(fax_state);
#ifdef DSP_SELECT
  dspxid = XtAppAddInput(mainapp, dspfd, (XtPointer) XtInputReadMask,
            fax_rx_backgnd, (XtPointer) NULL);
  fprintf(stderr, "dspxid from XtAppAddInput is %ld\n", dspxid);
  /* initiate the reading of data. Once started, it is called by
   * XtAppMainLoop() which uses select() to listen on dspfd. */
  fax_rx_backgnd((XtPointer) NULL, &dspfd, &dspxid);
#else
  chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
#endif
}

void receive_off(void)
{
#ifdef DSP_SELECT
  XtRemoveInput(dspxid);
  dspxid = (XtInputId) 0;
#else
  XtRemoveTimeOut(chstime);
#endif
  interface_stop();
  chstime = (XtIntervalId) 0;
}

#ifdef DSP_SELECT
/* this is the reception routine triggered upon input from DSP device */
void fax_rx_backgnd(XtPointer client_data, int *source, XtInputId *xid)
#else
/* this is the reception routine which calls itself after 250ms */
void fax_rx_backgnd(XtPointer client_data, XtIntervalId *xid)
#endif
{
  int space;

/*
  if (init_rx) {
    init_rx = 0;
    core_wptr = core_dta;
  }
*/
/*
  fprintf(stderr, "receiving data\n");
*/
  /* get the input samples and demodulate the input data stream */
  do_receive();

  /* update the signal-level scrollbar display */
  set_sigdisplay((double)rx_level / 255.0);

  /* always watch for APT frequencies */
/*
  fprintf(stderr, "decoding APT\n");
*/
  decode_apt(0);

  /* if we are in the phasing state, compute the phase-position */
  if (fax_state == FAX_PHAS)
    sync_phase(0);

  /* copy the data into the core_dta array and advance the write-pointer */
  if (fax_state == FAX_RX) {
    space = core_maxptr - core_wptr;
    if (space >  demod_cnt)
      space = demod_cnt;
    memcpy(core_wptr, demod_ptr, space);
    core_wptr += space;
  }

#ifdef DSP_SELECT
  /* we don't need to retrigger ourself - do nothing */
#else
  /* add a new timeout to call this function again */
/*
  printf("adding new timeout\n");
*/
  chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
#endif

  /* if disp_func is set, call that function (e.g. main FAX decoder loop) */
  if ((disp_func) && !(disp_locked)) {
/*
    fprintf(stderr, "calling disp_func\n");
*/
    disp_func(0);
  }
  /* if save_func is set (saving of received image enabled), call function */
  if ((save_func) && !(save_locked)) {
/*
    fprintf(stderr, "calling save_func\n");
*/
    save_func(F_DOSAVE, 0);
  }
}

/*
 * grayscale FAX decoding main routine.
 * init is used to control the behavior and initialize some internal
 * variables. It is bit-wise coded as follows :
 *  D_CPINIT : initialize read-pointer to start of core-buffer
 *  D_WDINIT : initialize x-position to the start-value
 *  D_LDINIT : initialize y-position to the start-value
 *  D_ALLOWX : periodically call XtAppProcessEvent during processing
 *    (requires that this function is NOT called from fax_rx_backgnd !)
 */
void decode_fax_gray(int init)
{
  XtInputMask msk;

#ifdef FAST8BIT
  static char *imptr;
  static char *imptinit;
  static int  impinc;
#endif

  /* pointer to sample-point for current pixel and current start-of-line */
  static char *core_line, *core_pix;
  /* sample-values per line or per pixel-value, 16bit int, 16bit frac */
  static unsigned inc_pix, inc_line;
  /* current index to pixel or line in sample-array, 16bit int, 16bit frac */
  static unsigned idx_pix, idx_line, idx_p0;
  /* increment between actual and previous pixel/line position */
  static unsigned ipix, iline;
  /* pixel-in-line-position start/increment/end */
  static int pixinit, pixinc, pixend;
  /* line-in-image-position start/increment/end, max. line of XImage */
  static int lineinit, lineinc, lineend, imgmax;
  static int (*put_pix)(struct _XImage *, int, int, unsigned long);

  if (init & D_INITS) {
    /* smpl_line is the number of core_dta points per line << 16 */
    smpl_line = 60.0 / lpm * smplf;
    if (vertical) {
      inc_pix = smpl_line / canhei;
      inc_line = (int)(ixoc * PI * 65536.0 / canhei); 
      imgmax = DEFWIDTH;
      put_pix = verimag->f.put_pixel;
    } else {
      inc_pix = smpl_line / canwid;
      inc_line = (int)(ixoc * PI * 65536.0 / canwid); 
      imgmax = DEFHEIGHT;
      put_pix = horimag->f.put_pixel;
    }
    if (!(vertical) && (right2left)) {
      pixinit = canwid - 1;
      pixinc = -1;
      pixend = -1;
#ifdef FAST8BIT
      imptinit = horimag->data + canwid - 1;
      impinc = -1;
#endif
    } else
    if ((vertical) && (bot2top)) {
      pixinit = canhei - 1;
      pixinc = -1;
      pixend = -1;
#ifdef FAST8BIT
      imptinit = verimag->data + (canhei - 1) * verimag->bytes_per_line;
      impinc = -verimag->bytes_per_line;
#endif
    } else {
      pixinit = 0;
      pixinc = 1;
      pixend = (vertical) ? canhei : canwid;
#ifdef FAST8BIT
      imptinit = (vertical) ? verimag->data : horimag->data;
      impinc = (vertical) ? verimag->bytes_per_line : 1;
#endif
    }
    /* initialize the line-advance variables and pointers */
    if (!(vertical) && (bot2top)) {
      lineinit = canhei - DEFHEIGHT;
      lineinc = -1;
      lineend = -1;
    } else
    if ((vertical) && (right2left)) {
      lineinit = canwid - DEFWIDTH;
      lineinc = -1;
      lineend = -1;
    } else {
      lineinit = 0;
      lineinc = 1;
      lineend = (vertical) ? canwid : canhei;
    }

    if (init & D_WDINIT) {
      pixpos = pixinit;
    }

    if (init & D_LDINIT) {
      linepos = lineinit;
      if ((!(vertical) && (bot2top)) || ((vertical) && (right2left)))
      imline = imgmax - 1;
      else
      imline = 0;
    }
#ifdef FAST8BIT
    if ((init & D_LDINIT) || (init & D_WDINIT)) {
      imptr = imptinit + impinc * pixpos;
      if (vertical)
      imptr += imline;
      else
      imptr += horimag->bytes_per_line * imline; 
    }
#endif

    if (init & D_CPINIT) {
      /* initialize the fractional index pointers */
      idx_pix = idx_line = idx_p0 = 0;
      core_pix = core_line = core_start;
      ipix = iline = 0;
    }
    fprintf(stderr,"initialisation done :\n"
      "pixinit = %d, pixinc = %d, pixend = %d\n"
      "lineinit = %d, lineinc = %d, lineend = %d\n"
      "imline = %d, imgmax = %d\n",
      pixinit, pixinc, pixend,
      lineinit, lineinc, lineend,
      imline, imgmax);
      
    disp_locked = 0;
    return;
  }
  if (init & D_ALLOWX) {
    printf("redrawing from %d, %d, corepos = %d\n", pixpos, linepos, core_pix - core_dta);
  }
  disp_locked = 1;
  do {
    /* if it is better to wait for more data, cancel function and wait
       until it is called next time */
    if (core_pix >= core_wptr)
      break;

    /* enter a new brightness-value (0..63) into core_dta */

#ifdef FAST8BIT
    *imptr = coltab[*(unsigned char *)core_pix];
    imptr += impinc;
#else
    if (vertical)
      put_pix(verimag, imline, pixpos, coltab[*(unsigned char *)core_pix]);
    else
      put_pix(horimag, pixpos, imline, coltab[*(unsigned char *)core_pix]);
#endif

    /* shift the x-position, and if we have reached the end... */
    pixpos += pixinc;
    if (pixpos == pixend) {
      /* re-start from left border */
      pixpos = pixinit;
      /* now we have one more complete line, copy it from core_dta to the
       horimag (an Ximage). Use fast methode by advancing pointers */

      /* check if we wave filled up all lines of horimag, or if we just
       have got as many lines that we can complete the picture. */
      imline += lineinc;
      if ((imline == imgmax) || (imline < 0) || (linepos + imline == lineend)) {
      while ((init & D_ALLOWX) && ((msk = XtAppPending(mainapp)))) {
        XtAppProcessEvent(mainapp, msk);
      }
      if (vertical)
        if (right2left) {
          update_area(verimag, 0, 0, linepos, 0, (DEFWIDTH-1) - imline, canhei);
        } else {
          update_area(verimag, 0, 0, linepos, 0, imline, canhei);
        }
      else
        if (bot2top) {
          update_area(horimag, 0, 0, 0, linepos, canwid, (DEFHEIGHT-1) - imline);
        } else {
          update_area(horimag, 0, 0, 0, linepos, canwid, imline);
        }
      if (((vertical) && (right2left)) || (!(vertical) && (bot2top))) {
        imline = imgmax - 1;
        linepos -= imgmax;
        if (linepos < 0)
          linepos = lineinit;
      } else {
        imline = 0;
        linepos += imgmax;
        if (linepos >= lineend)
          linepos = 0;
      }
      }

#ifdef FAST8BIT
      if (vertical)
      imptr = imptinit + imline;
      else
      imptr = imptinit + horimag->bytes_per_line * imline;
#endif

      idx_line += inc_line;
      iline = (idx_line >> 16) & 0xffff;
      idx_line &= 0xffff;
      core_line += iline * ((smpl_line >> 16) & 0xffff);

      /* we must also initialize the pixel-counters here ! */
      idx_p0 += iline * (smpl_line & 0xffff);
      core_line += (idx_p0 >> 16) & 0xffff;
      core_pix = core_line;
      idx_p0 &= 0xffff;
      idx_pix = idx_p0;
      ipix = 0;

      /* jump over the stuff below... */
      continue;
    }
    /* shift the sample-point (16 bits integer, 16 bits fractional part) */
    idx_pix += inc_pix;
    ipix = (idx_pix >> 16) & 0xffff;
    core_pix += ipix;
    idx_pix &= 0xffff;
  } while (1);
  if (init & D_FLUSHIMG) {
    if (vertical)
      if (right2left) {
        update_area(verimag, 0, 0, linepos, 0, (DEFWIDTH-1) - imline, canhei);
      } else {
        update_area(verimag, 0, 0, linepos, 0, imline, canhei);
      }
    else
      if (bot2top) {
        update_area(horimag, 0, 0, 0, linepos, canwid, (DEFHEIGHT-1) - imline);
      } else {
        update_area(horimag, 0, 0, 0, linepos, canwid, imline);
      }
  }
  disp_locked = 0;
}

/*
 * this function should be used by the main program to initiate saving
 * of an image. If name is not given, it is constructed of date and time.
 */
int save_faxfile(char *name, int width)
{
  time_t tp; 
  char date[16];  /* string to build date for automatic savefile-name */

  /* check if save-file is already open */
  if (fsfile)
    return SAVE_BUSY;
  /* if no name is given, generate autosave-filename from date and time */
  if (name) {
    strcpy(faxsavename, name);
  } else {
    time(&tp);
    strftime(date, 14, "%m.%d-%H:%M", localtime(&tp));
    sprintf(faxsavename, "%s/faxsave_%s.pgm", FAX_SAVEDIR, date);
  }
  return save_func(F_OPEN, width);
}

/* properly close the save-file */
void close_faxsave(void)
{
  if (!(fsfile))
    return;
  save_func(F_GETDIM, 0);
  save_func(F_DOSAVE, 0);
  save_func(F_CLOSE, 0);
}

/*
 * fax-image saving function, writes grayscale ppm-images (pgm).
 * The image cannot be rotated, only flipped in writing-direction.
 * init defines the action to be done :
 * F_DOSAVE : save image if file is opened, close when completed
 * F_OPEN : open file, faxsavename contains the name and width the width
 *        of the image. If width is not given, the best resolution is taken
 *        (width = PI * IOC)
 * F_CLOSE : close file and adjust data in header to actual values
 * F_GETDIM : get dimensions and parameters of image into internal variables
 * the filename must previously be put into faxsavename.
 */ 
int save_fax_gray(int init, int width)
{
  XtInputMask msk;
  /* width and height of saved image */
  static unsigned swidth, sheight;
  static char *ldptr, *ldpinit, *ldpend;
  static int ldpinc;
  /* end of picture in core-space */
  static char *save_wptr = NULL;
  /* pointer to sample-point for current pixel and current start-of-line */
  static char *core_line, *core_pix;
  /* sample-values per line or per pixel-value, 16bit int, 16bit frac */
  static unsigned inc_pix, inc_line;
  /* current index to pixel or line in sample-array, 16bit int, 16bit frac */
  static unsigned idx_pix, idx_line, idx_p0;
  /* increment between actual and previous pixel/line position */
  static unsigned ipix, iline;
  /* pixel-in-line-position start/increment/end */
/*
  static int pixinit, pixinc, pixend;
*/
  /* line-in-image-position start/increment/end, max. line of XImage */
/*
  static int lineinit, lineinc, lineend, imgmax;
*/
  /* whether the writing-direction must be reversed */
  static int flip;
  int pos;

  if (init == F_OPEN) {
    /* close "old" file first */
    if (fsfile)
      save_fax_gray(F_CLOSE, 0);
     if (width > 0)
      swidth = width;
    else
      swidth = (ixoc * PI) + 0.5;
    fsfile = fopen(faxsavename, "wb");
    if (!(fsfile)) {
      return SAVE_NPERM;
    }
    fprintf(stderr, "save file \"%s\", %d pix/line\n", faxsavename, swidth);
    fputs("P5\nxxxxx\nyyyyy\n63\n", fsfile);
    /* allocate space for the one line */
    saveline = malloc(swidth + 4);
    /* do not initialize too much here, the user may change parameters
    of the picture while receiving... */
    save_wptr = NULL;
    return SAVE_OK;
  } else if (init == F_CLOSE) {
    if (!(fsfile))
      return SAVE_OK; /* no save-file open, doesn't matter */
    fprintf(stderr,"closing savefile\n");
    pos = ftell(fsfile);
    sheight = sypos;
    rewind(fsfile);
    fprintf(fsfile, "P5\n%05u\n%05u\n", swidth, sheight);
    fseek(fsfile, pos, SEEK_SET);
    fclose(fsfile);
    fsfile = NULL;
    if (saveline)
      free(saveline);
    save_wptr = NULL;
    return SAVE_OK;
  } else if (init == F_GETDIM) {
    if (!(fsfile))
      return SAVE_NFILE; /* no save-file open, can't get dimensions */
    /* now initialize all the variables... */
    fprintf(stderr, "getting image settings...");
    inc_pix = smpl_line / swidth;
    inc_line = (int)(ixoc * PI * 65536.0 / swidth); 
    idx_pix = idx_line = idx_p0 = 0;
    core_pix = core_line = core_start;
    save_wptr = core_wptr;
    ipix = iline = 0;
    flip = (vertical) ? 1 : 0;
    if (bot2top) flip ^= 1;
    if (right2left) flip ^= 1;
    if (flip) {
      ldpinit = saveline + (swidth - 1);
      ldpinc = -1;
      ldpend = saveline - 1;
    } else {
      ldpinit = saveline;
      ldpinc = 1;
      ldpend = saveline + swidth;
    }
    ldptr = ldpinit;
    sypos = 0;
    sheight = 0;
    return SAVE_OK;
  }
  /* no open save-file, or variables not initialized, so return */
  if (!(fsfile) || !(save_wptr)) return SAVE_NFILE;
  save_locked = 1;
  fprintf(stderr,"saving image...");
  while (core_pix < save_wptr) {
    if (invimage)
      *ldptr = dmaxval - *(unsigned char *)core_pix;
    else
      *ldptr = *(unsigned char *)core_pix;
    ldptr += ldpinc;
    if (ldptr == ldpend) {
      ldptr = ldpinit;
      sypos++;
      fwrite(saveline, swidth, 1, fsfile);

      while ((msk = XtAppPending(mainapp))) {
      XtAppProcessEvent(mainapp, msk);
      }
      idx_line += inc_line;
      iline = (idx_line >> 16) & 0xffff;
      idx_line &= 0xffff;
      core_line += iline * ((smpl_line >> 16) & 0xffff);

      /* we must also initialize the pixel-counters here ! */
      idx_p0 += iline * (smpl_line & 0xffff);
      core_line += (idx_p0 >> 16) & 0xffff;
      core_pix = core_line;
      idx_p0 &= 0xffff;
      idx_pix = idx_p0;
      ipix = 0;

      /* jump over the stuff below... */
      continue;
    }
    idx_pix += inc_pix;
    ipix = (idx_pix >> 16) & 0xffff;
    core_pix += ipix;
    idx_pix &= 0xffff;
  }
  fprintf(stderr,"done.\n");
  save_locked = 0;
  return SAVE_OK;
}

/* called when save-function has terminated writing */
void faxsave_complete(int init)
{
   /* this makes save_func call itself recursively, but should not hurt */
   save_func(F_CLOSE, 0);
}

/*
 * wait for a phasing signal, keep track of the phase-pulses, and preset
 * core_start on end of the phase_signal. This is done by correlating the
 * digitized gray-values (reduced to 1 or 0) with two sawtooth-signals,
 * each with a periode of one scan line, and one of them shifted by a
 * half scan-line against the other. This lets us find the position of
 * the phase-pulse relative to our scan-line. Lines are recognized as
 * phase-in-lines when they contain at most 3/32 and at least 1/32 of values
 * that are above (or below for inverse phase) the middle of the gray-scale.
 */
void sync_phase(int init)
{
  /* run counters, count pixels per line (16bit int, 16bit frac) */
  static int phsarc, phsbrc;
  /* accumulators for the integration */
  static int phsaacc = 0, phsbacc = 0;
  /* these are counted up until limit to form the sawtooth-signal */
  static int phsainc, phsbinc;
  /* number of sample-points processed */
  static int npoints = 0;
  /* number of points having the right level (black) for a sync pulse */
  static int nphpts = 0;
  /* minimum/maximum  number of black points per line that must be present */
  static int minphpts, maxphpts;
  static char done = 0;
  char *dtaptr;
  int pcnt;
  int i,j;

  dtaptr = demod_ptr;
  pcnt = demod_cnt;
  if (init) {
    phstate = 0;
    hsmpl_line = smpl_line >> 17;
    phsaacc = phsbacc = 0;
    phsarc = smpl_line;
    phsbrc = smpl_line >> 1;
    phsainc = - hsmpl_line;
    phsbinc = 0;
    minphpts = (smpl_line >> 16) >> 5;
    maxphpts = minphpts * 3;
    nphpts = 0;
    phlines = 0;
    done = 0;
    core_wptr = core_dta;
    core_start = core_dta;
    fprintf(stderr, "initialized sync-phase-detector\n");
    return;
  }

  while (pcnt > 0) {
      if ((!(invphase) && *dtaptr > compval) ||
         ((invphase) && *dtaptr < compval)) {
      phsaacc += phsainc;
      phsbacc += phsbinc;
      nphpts++;
      }
      phsainc++;
      phsbinc++;
      npoints++;
      dtaptr++;
      pcnt--;
      phsarc -= 65536;
      if (phsarc <= 0) {
      done = 1; /* this indicates the end-of-line */
      phsarc += smpl_line;
      phsainc = - hsmpl_line;
      }
      phsbrc -= 65536;
      if (phsbrc <= 0) {
      phsbrc += smpl_line;
      phsbinc = - hsmpl_line;
      }
      if (done) {
#if (DEBUG & DBG_SYN)
      fprintf(stderr, "got line with %d of %d points phase-value\n",
            nphpts, npoints);
#endif
      /* check if it was probably a phase-in line */
      if (nphpts < maxphpts && nphpts > minphpts) {
        if (phlines < 24) {
          /* use the accumulator with the lower absolute-value */
          if (abs(phsaacc) < abs(phsbacc)) {
            i = phsaacc / nphpts;
#if (DEBUG & DBG_SYN)
            fprintf(stderr, "sync line %d: A=%d\n", phlines, i);
#endif
            phposa[phlines] = i;
            if (i < 0)
            phsdir[phlines] = 1; /* left half */
            else
            phsdir[phlines] = 0; /* right half */
          } else {
            i = phsbacc / nphpts;
#if (DEBUG & DBG_SYN)
            fprintf(stderr, "sync line %d: B=%d\n", phlines, i);
#endif
            phposb[phlines] = i;
            if (i < 0)
            phsdir[phlines] = 2; /* right half */
            else
            phsdir[phlines] = 3; /* left half */
          }
          if (phstate == 0) { /* first sync line */
            phstate = 1;
          } else if (phstate == 1) { /* any sync line */
          }
          phlines++;
        } else { /* phlines >= 24 */
          /* ignore any further sync-lines... */
        }
      } else {
        /* no sync line, we are still waiting for one or they have passed */
        if (phstate == 0) {
          /* no sync line yet - just wait ?! */
        } else if (phstate == 1) {
          /* now begin to compute the ultimate sync-position */
          j = 0;
          /* count the lines in the left half */
          for (i=0; i<phlines; i++) {
            if (phsdir[i] & 1) j++;
          }
          phaseavg = 0;
          if (j > (phlines >> 1)) { /* more points in the left half */
#if (DEBUG & DBG_SYN)
            fprintf(stderr, "calculating for left half...\n");
#endif
            for (i=0; i<phlines; i++)
            if (phsdir[i] & 2)
              phaseavg += phposb[i] - hsmpl_line;
            else
              phaseavg += phposa[i];
          } else { /* more points in the right half */
#if (DEBUG & DBG_SYN)
            fprintf(stderr, "calculating for right half...\n");
#endif
            for (i=0; i<phlines; i++)
            if (phsdir[i] & 2)
              phaseavg += phposb[i] + hsmpl_line;
            else
              phaseavg += phposa[i];
          }
          phaseavg /= phlines;
          phaseavg += hsmpl_line;
#if (DEBUG & DBG_SYN)
          fprintf(stderr, "phase average = %d\n", phaseavg);
#endif
          /* now prepare the core_start pointer for reception */
          /* calculate difference from sync-pos to end of line */
          j = (smpl_line >> 16);
          i = demod_cnt - pcnt + phaseavg;
          if (i > j)
            i -= j;
          /* start decoding at the beginning of the core */
          core_wptr = core_dta;
          core_start = core_dta + i;
          /* now enter the real reception mode. When returning into the
            fax_rx_backgnd, fax_state is set to FAX_RX so that the data
            we just processed can also be used for the picture. */
          fax_rx_start(1);
          /* no more data to process */
          return;
        }
      } /* if (sync_line_detected) */
      /* re-initialize the both accumulators and sample-point counters */
      phsaacc = 0;
      phsbacc = 0;
      npoints = 0;
      nphpts = 0;
      done = 0;
      } /* if (done) */
  } /* while (pcnt > 0) */
}

/*
 * calculate the APT frequency by counting low->high->low transitions.
 * not very nice, but it works :-S . This funcion always computes the
 * APT for 0.5 seconds, independant from demod_cnt, which can be very
 * high on systems that use a large block-size for the audio-devide.
 * After each calculation, apt_notify() is called with the frequency as
 * argument.
 */
void decode_apt(int dummy)
{
  /* how many transitions (half-waves) we have counted */
  static int apthws = 0;
  /* how many consecutive points were on one side of the comparator-value */ 
  static int aptncact = 0;
  /* the phase (black or white) we processed last time */
  static int phs = 0;
  static int npoints = 0;
  char *dtaptr;
  int pcnt;

  dtaptr = demod_ptr;
  pcnt = demod_cnt;
  /* If we have to start with the "black" phase, do it before the main-loop
     starts. This prevents us from ugly goto's (shudder) */
  if (phs) {
    while (pcnt) {
      pcnt--;
      if (++npoints >= hsmpl_sec) {
      apt_notify(apthws);
      apthws = 0;
      npoints = 0;
      }
      if (*(unsigned char *)dtaptr++ <= compval) {
      if (aptncact > aptncmax)
        apthws = 0;
      else
        apthws++;
      break;
      }
      aptncact++;
    }
  }
  while (pcnt > 0) {
    aptncact = 0;
    while (pcnt) {
      pcnt--;
      if (++npoints >= hsmpl_sec) {
#if (DEBUG & DBG_APT)
      fprintf(stderr,"APT freq. pos = %d\n", apthws);
#endif
      apt_notify(apthws);
      apthws = 0;
      npoints = 0;
      }
      if (*(unsigned char *)dtaptr++ > compval) {
      if (aptncact > aptncmax)
        apthws = 0;
      else
        apthws++;
      break;
      }
      aptncact++;
    }
    aptncact = 0;
    while (pcnt) {
      pcnt--;
      if (++npoints >= hsmpl_sec) {
#if (DEBUG & DBG_APT)
      fprintf(stderr,"APT freq. neg = %d\n", apthws);
#endif
      apt_notify(apthws);
      apthws = 0;
      npoints = 0;
      }
      if (*(unsigned char *)dtaptr++ <= compval) {
      if (aptncact > aptncmax)
        apthws = 0;
      else
        apthws++;
      break;
      }
      aptncact++;
    }
  }
  /* now mark the phase for the next call... */
  if (*(unsigned char *)(dtaptr-1) <= compval)
    phs = 0;
  else
    phs = 1;
}

void apt_control(int aptfrq)
{
  static int cnt;
/*
  fprintf(stderr, "apt_control: %d\n", aptfrq);
*/
  switch (fax_state) {
    /* wait for one of the valid APT frequencies */
    case FAX_APT:
      if (abs(aptfrq - aptstart) < 2) {
        if (++cnt >= 2) fax_rx_phase(1);
      } else {
        cnt = 0;
      }
      break;
    /* here, a new start or a stop (interrupt) may occur */
    case FAX_PHAS:
    case FAX_RX:
      if (abs(aptfrq - aptstop) < 2) {
        if (++cnt >= 2) fax_rx_stop(1);
      } else {
        cnt = 0;
      }
      break;
  }
}

void fax_rx_start(int internal)
{
  fprintf(stderr,"starting fax reception\n");
  /* if we come from phasing, initialize disp_func */
  if (fax_state == FAX_PHAS)
    disp_func(D_CPINIT | D_WDINIT | D_LDINIT);
  fax_state = FAX_RX;
  if (internal)
    mode_notify(fax_state);
}

void fax_rx_phase(int internal)
{
  fprintf(stderr,"entering phase-in mode\n");
  sync_phase(1);
  fax_state = FAX_PHAS;
  if (internal)
    mode_notify(fax_state);
}

void fax_rx_stop(int internal)
{
  fprintf(stderr,"stopping fax reception\n");
  fax_state = FAX_APT;
  /* flush rest of image (in horimag/verimag) */
  disp_func(D_FLUSHIMG);
  /* get current image-parameters for saving */
  save_func(F_GETDIM, 0);
  save_func(F_DOSAVE, 0);
  save_func(F_CLOSE, 0);
  if (internal)
    mode_notify(fax_state);
}

/*
 * this function is called by the callback-function of the Canvas-widget
 * to move the picture in writing-direction, when phasing in has failed
 * or was missed. px and py contain the coordinates of the button-press.
 */
void shift_fax_coords(unsigned px, unsigned py)
{
  void (*old_func)();
  unsigned tmp_pos;

  fprintf(stderr, "coords = %d, %d\n", px, py);
  old_func = disp_func;
  disp_func = NULL;
  if (vertical) {
    if (bot2top)
      tmp_pos = smpl_line / canhei * (canhei - py);
    else
      tmp_pos = smpl_line / canhei * py;
  } else {
    if (right2left)
      tmp_pos = smpl_line / canwid * (canwid - px);
    else
      tmp_pos = smpl_line / canwid * px;
  }
  core_start += (tmp_pos >> 16);
  tmp_pos = (smpl_line >> 16);
  if (core_start - core_dta > tmp_pos)
    core_start -= tmp_pos;
  old_func (D_CPINIT | D_WDINIT | D_LDINIT);
  old_func (D_ALLOWX);
  disp_func = old_func;
}

/*
 * this function is called by the callback-function of the Canvas-widget
 * to re-adjust the sampling frequency to correct the line-shifting
 * caused by slightly deadjusted samling frequency.
 */
void correct_fax_azimut(int dx, int dy)
{
  void (*old_func)();
  int flip;
  int df;

  fprintf(stderr, "coords = %d, %d\n", dx, dy);
  flip = 0;
  if (right2left) flip ^= 1;
  if (bot2top) flip ^= 1;
  if (vertical) {
    df = (smplf * (double)dy) / (dx * PI * ixoc);
  } else {
    df = (smplf * (double)dx) / (dy * PI * ixoc);
  }
  if (flip) df = -df;
  smplf += df;
  fprintf(stderr, "delta freq.=%2.3f smplf=%4.3f\n",
      (double)df / 65536.0, (double)smplf / 65536.0);
  tune_frequency(smplf);

  old_func = disp_func;
  disp_func = NULL;
  old_func (D_CPINIT | D_WDINIT | D_LDINIT);
  old_func (D_ALLOWX);
  disp_func = old_func;
}

/*----------------------- FAX transmission --------------------------*/

void fax_tx_stop(int internal)
{
  fprintf(stderr,"stopping FAX-transmission\n");
  if (internal)
    mode_notify(fax_state);
}

void fax_tx_start(int internal)
{
  fprintf(stderr,"transmitting image\n");
  fax_state = FATX_TX;
  fax_tx_func(D_WDINIT | D_LDINIT);
  if (internal)
    mode_notify(fax_state);
}

void fax_tx_apta(int internal)
{
  fprintf(stderr,"transmitting APT-start\n");
  transmit_apt(APTX_ISTART);
  fax_state = FATX_APTA;
  if (internal)
    mode_notify(fax_state);
}

void fax_tx_aptb(int internal)
{
  fprintf(stderr,"transmitting APT-stop\n");
  transmit_apt(APTX_ISTOP);
  fax_state = FATX_APTB;
  if (internal)
    mode_notify(fax_state);
}

void fax_tx_phase(int internal)
{
  fprintf(stderr,"entering TX-phase-in mode\n");
  transmit_phase(1);
  fax_state = FATX_PHAS;
  if (internal)
    mode_notify(fax_state);
}

int load_txfile(char *name)
{
  char line[80];
  char lctab[256];
  char *pline, *sp;
  int ncols;
  int color;
  char *cp;
  int i,j;

  if (timg_ptr)
    free(timg_ptr);
  if ((ftfile = fopen(name, "rb")) == NULL) {
    perror("open_txfile");
    return -1;
  }
  if (fgets(line, 79, ftfile) == NULL) {
    perror("read_format");
    return -1;
  }
  if (!strcmp(line, "P5\n"))
    color = 0;
  else if (!strcmp(line, "P6\n"))
    color = 1;
  else
    return -2; /* unrecognized format */
  if (color)
    return -3; /* not yet supported */
  do {
    if (fgets(line, 79, ftfile) == NULL) {
      perror("read_header");
      return -1;
    }
  } while (*line == '#');
  twidth = atoi(line);
  if (fgets(line, 79, ftfile) == NULL) {
    perror("read_header");
    return -1;
  }
  theight = atoi(line);
  if (fgets(line, 79, ftfile) == NULL) {
    perror("read_header");
    return -1;
  }
  timg_ptr = malloc(twidth*theight);
  pline = malloc(twidth);
  if (!(timg_ptr) || !(pline)) {
    if (timg_ptr) free(timg_ptr);
    if (pline) free(pline);
    perror("alloc_txmem");
    return -4;
  }
  ncols = atoi(line) + 1;
  if (ncols > 256)
    return -3;
  for (i=0; i<ncols; i++)
    lctab[i] = (64 * i) / ncols;
  cp = timg_ptr;
  for (i=0; i<theight; i++) {
    if (fread(pline, twidth, 1, ftfile) != 1) {
      perror("read_pixmap");
      free(timg_ptr);
      free(pline);
      return -5;
    }
    sp = pline;
    for (j=0; j<twidth; j++)
      *cp++ = lctab[*(unsigned char *)sp++];
  }
  free(pline);
  fclose(ftfile);
  return 0;
}

/*
 * Fax-transmission background-routine :
 * This works a little different from the receiving-routine.
 * Transmission-data is not stored in a core-space, it is
 * transmitted directly out of the image-memory. Every function
 * called here must keep track of the pointer in the decptr-space
 * and give back control if the task is done or the pointer has reached
 * the end of the buffer.
 */
#ifdef DSP_SELECT
void fax_tx_backgnd(XtPointer client_data, int *source, XtInputId *xid)
#else
void fax_tx_backgnd(XtPointer client_data, XtIntervalId *xid)
#endif
{
  int space;

  /* if we are in the phasing state, compute the phase-position */
  if (fax_state == FATX_APTA)
    transmit_apt(0);

  if (fax_state == FATX_PHAS)
    transmit_phase(0);

  if (fax_state == FATX_TX)
    fax_tx_func(0);

  if (fax_state == FATX_APTB)
    transmit_apt(0);

#ifdef DSP_SELECT
#else
  /* add a new timeout to call this function again */
/*
  printf("adding new timeout\n");
*/
  chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
#endif

  /* if disp_func is set, call that function (e.g. main FAX decoder loop) */
  if ((disp_func) && !(disp_locked)) {
/*
    fprintf(stderr, "calling disp_func\n");
*/
    fax_tx_func(0);
  }
/*
  fprintf(stderr, "transmitting data\n");
*/
  do_transmit();
}

void transmit_fax_gray(int init)
{
  /* pointer to sample-point for current pixel and current start-of-line */
  static char *timg_line, *timg_pix;
  /* sample-values per line or per pixel-value, 16bit int, 16bit frac */
  static unsigned inc_pix, inc_line, inc_p0;
  /* current index to pixel or line in sample-array, 16bit int, 16bit frac */
  static unsigned idx_pix, idx_line, idx_p0;
  /* increment between actual and previous pixel/line position */
  static unsigned ipix, iline;
  /* pixel-in-line-position start/increment/end */
  static int pixinit, pixinc, pixend;
  /* line-in-image-position start/increment/end, max. line of XImage */
  static int lineinit, lineinc, lineend, imgmax;
  static int (*put_pix)(struct _XImage *, int, int, unsigned long);
  /* bytes per line or per pixel, depends on direction (hor, vert, r2l, b2t) */
  static int bytes_per_line, bytes_per_pixel;

  if (init & D_INITS) {
    /* smpl_line is the number of core_dta points per line << 16 */
    smpl_line = 60.0 / lpm * smplf;
    if (vertical) {
      inc_pix = smpl_line / theight;
      inc_line = (int)(ixoc * PI * 65536.0 / theight); 
      imgmax = DEFWIDTH;
      put_pix = verimag->f.put_pixel;
      bytes_per_pixel = twidth;
      bytes_per_line = 1;
    } else {
      inc_pix = smpl_line / twidth;
      inc_line = (int)(ixoc * PI * 65536.0 / twidth); 
      imgmax = DEFHEIGHT;
      put_pix = horimag->f.put_pixel;
      bytes_per_pixel = 1;
      bytes_per_line = twidth;
    }
    if (!(vertical) && (right2left)) {
      pixinit = twidth - 1;
      pixinc = -1;
      pixend = -1;
      bytes_per_pixel = -bytes_per_pixel;
    } else
    if ((vertical) && (bot2top)) {
      pixinit = theight - 1;
      pixinc = -1;
      pixend = -1;
      bytes_per_pixel = -bytes_per_pixel;
    } else {
      pixinit = 0;
      pixinc = 1;
      pixend = (vertical) ? theight : twidth;
    }
    /* initialize the line-advance variables and pointers */
    if (!(vertical) && (bot2top)) {
        lineinit = theight - 1;
        lineinc = -1;
        lineend = -1;
      bytes_per_line = -bytes_per_line;
    } else
    if ((vertical) && (right2left)) {
        lineinit = twidth - 1;
        lineinc = -1;
        lineend = -1;
      bytes_per_line = -bytes_per_line;
    } else {
        lineinit = 0;
        lineinc = 1;
        lineend = (vertical) ? twidth : theight;
    }
  }


  if (init) {
    timg_line = timg_ptr;
    /* twidth, theight, timg_ptr */
    if (vertical) {
      inc_pix = 65536.0 * theight * lpm / ((60.0/65536.0) * smplf);
      inc_line = 65536.0 * theight / (PI * ixoc);
    } else {
      inc_pix = 65536.0 * twidth * lpm / ((60.0/65536.0) * smplf);
      inc_line = 65536.0 * twidth / (PI * ixoc);
    }
      if (right2left) {
      pixinc = -1;
      timg_line += (twidth - 1);
      } else {
      pixinc = 1;
      }
      if (bot2top) {
      pixinc = -twidth;
      timg_line += (theight - 1) * twidth;
      } else {
      pixinc = twidth;
      }
      timg_pix = timg_line;
    inc_p0 = 0;
    return;
  }
  while (mod_ptr < mod_end) {
    *mod_ptr++ = *timg_pix;

    pixpos += pixinc;
    if (pixpos == pixend) {
      pixpos = pixinit;
      linepos += lineinc;
      if (linepos == lineend) {
      /* we have transmitted the entire picture ! */
      break;
      }
      idx_line += inc_line;
      iline = (idx_line >> 16) & 0xffff;
      idx_line &= 0xffff;
      timg_pix += bytes_per_pixel;
      timg_pix += iline * twidth; /* twidth == bytes_per_line */
      continue; /* jump over stuff below */
    }
    idx_pix += inc_pix;
    ipix = (idx_pix >> 16) & 0xffff;
    idx_pix &= 0xffff;
    timg_pix += ipix * bytes_per_pixel;
  }
  fax_tx_aptb(1);
}

/*
 * transmit an APT-tone. This function returns if either the pointer to
 * decptr reaches the end of the buffer or the duration is reached.
 * init can have the following values :
 * APTX_ISTART: initialize for aptstart-frequency
 * APTX_ISTOP:    initialize for apt stop-frequency
 * 0:       start/continue transmission
 */
void transmit_apt(int init)
{
  XtInputMask msk;
  static int acc = 0;
  static int ap_inc;
  static int dur;

  if (init == APTX_ISTART) {
    ap_inc = 4.294967296e6 * aptstart / (double) smplf;
    dur = (smplf >> 16) * aptdur / 1000;
    return;
  } else if (init == APTX_ISTOP) {
    ap_inc = 4.294967296e6 * aptstop / (double) smplf;
    dur = (smplf >> 16) * aptdur / 1000;
    return;
  }
  while ((dur > 0) && (mod_ptr < mod_end)) {
      acc += ap_inc;
      if (acc & 0x8000)
      *mod_ptr = dmaxval;
      else
      *mod_ptr = 0;
      mod_ptr++;
      dur--;
  }
  if (mod_ptr >= mod_end)
    mod_ptr = demod_ptr;
  if (dur <= 0) {
      if (fax_state == FATX_APTA)
      fax_tx_phase(1);
      else
      fax_tx_stop(1);
  }
}

/*
 * transmit the phase-in signal for the image, which consists of 95% black
 * and 5% white (or inverted if invphase is set). These 5% have to appear
 * as one half to both the left and right margin of the image. The phase
 * where we start is not important, but where we stop and give control
 * to the function transmitting the contents of the loaded image.
 * tx_phlines determines the number of lines for phasing, after which
 * a line with 100% white is intersected to start the receiver.
 * if init is set, variables are initialized and the function returns.
 */
void transmit_phase(int init)
{
  static int inc_pix;
  static int idx_pix;
  static int idx_min, idx_max;
  static int txlines;

  if (init) {
    inc_pix = lpm * (double) smplf / 60;
    idx_min = 1638;
    idx_max = 63807;
    idx_pix = 0x8000;
    txlines = tx_phlines + 1;
    return;
  }
  while ((txlines >= 0) && (mod_ptr < mod_end)) {
    idx_pix += inc_pix;
    if (idx_pix > 63807 || idx_pix < 1638)
     *mod_ptr = (invphase ? 0 : dmaxval);
    else
     *mod_ptr = (invphase ? dmaxval : 0);
    mod_ptr++;
    if (idx_pix > 0xffff)
      txlines--;
    idx_pix &= 0xffff;
  }
  if (mod_ptr >= mod_end)
    mod_ptr = demod_ptr;
  if (txlines <= 0)
    fax_tx_start(1);
}

Generated by  Doxygen 1.6.0   Back to index