~ubuntu-branches/debian/sid/acfax/sid

« back to all changes in this revision

Viewing changes to fax_funcs.c

  • Committer: Bazaar Package Importer
  • Author(s): Hamish Moffatt
  • Date: 2001-12-27 12:07:46 UTC
  • Revision ID: james.westby@ubuntu.com-20011227120746-iz2p5k757bcla8ov
Tags: upstream-981011
ImportĀ upstreamĀ versionĀ 981011

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    ACfax - Fax reception with X11-interface for amateur radio
 
3
    Copyright (C) 1995-1998 Andreas Czechanowski, DL4SDC
 
4
 
 
5
    This program is free software; you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation; either version 2 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    This program is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with this program; if not, write to the Free Software Foundation,
 
17
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 
 
19
    andreas.czechanowski@ins.uni-stuttgart.de
 
20
*/
 
21
    
 
22
/* fax_funcs.c - all fax-specific functions should be placed here.
 
23
 *               This file depends on neary everything; It calls the hardware-
 
24
 *               specific setup, the filter setup, and needs some X11-
 
25
 *               variables for writing into the canvas.
 
26
 */
 
27
 
 
28
#include <stdio.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <math.h>
 
32
#include <time.h>
 
33
#include "x_image.h"
 
34
#include <X11/Intrinsic.h>
 
35
#include "sblaster.h"
 
36
#include "mod_demod.h"
 
37
#include "widgets.h"
 
38
#include "fax_funcs.h"
 
39
 
 
40
/* some variables that are allowed to be global */
 
41
int     lpm;            /* lines per minute */
 
42
int     ixoc;           /* number of pixels of one scan-line / PI */
 
43
int     devi;           /* deviation in Hz (+/- of middle) */
 
44
int     mod_mode;       /* can be MOD_FM or MOD_AM */
 
45
int     aptstart;       /* possible APT start values */
 
46
int     aptstop;        /* possible APT stop values */
 
47
int     aptdur;         /* apt duration in millisecs (for transmitting) */
 
48
int     vertical;       /* vertical or horizontal line direction */
 
49
int     right2left;     /* boolean indicating reverse line writing direction */
 
50
int     bot2top;        /* boolean indicating reverse line stacking direction */
 
51
int     invphase;       /* polarity of phase-in-signal to use */
 
52
int     invimage;       /* inverse colormap usage */
 
53
/* and the private variables */
 
54
int     fax_inited = 0; /* if fax_init was called */
 
55
unsigned canwid;        /* width of the Pixmap to draw in */
 
56
unsigned canhei;        /* height of the Pixmap */
 
57
int     sxpos, sypos;   /* current coordinates of received/xmitted data */
 
58
int     pixpos, linepos; /* current coordinates of received/xmitted data */
 
59
int     imline;         /* currently processed line of XImage */
 
60
void    (*update_area)(XImage *, int, int, int, int, unsigned, unsigned);
 
61
        /* called to copy XImage to Pixmap and update the window-area required */
 
62
void    (*mode_notify)(int); /* notifies main program of changes of fax_state */
 
63
int     mcolor;         /* color-mode selected */
 
64
int     dmaxval;        /* number of usable grayscale-values - 1 */
 
65
int     compval;        /* comparator value for APT-counter */
 
66
int     flip;           /* flipping of green and blue parts of the colormap */
 
67
int     rotate;         /* rotation of the colormap */
 
68
int     fax_state;      /* one of FAX_APT, FAX_PHAS or FAX_RX */
 
69
char    *core_dta;      /* storage for raw demodulated data (accumulating) */
 
70
char    *core_start;    /* start of core for image-processing */
 
71
char    *core_wptr;     /* pointer to next written element in core_dta */
 
72
char    *core_maxptr;   /* pointer beyond the last element in core_dta */
 
73
void    (*disp_func)(int); /* pointer to function displaying the data-stream */
 
74
int     (*save_func)(int, int);
 
75
                        /* pointer to function saving image to file */
 
76
void    (*fax_tx_func)(int); /* pointer to function transmitting image */
 
77
int     disp_locked;    /* flag indicating that disp_func should not be called
 
78
                           from fax_rx_backgnd */
 
79
int     save_locked;    /* same as above for save_func */
 
80
void    (*apt_notify)(int); /* pointer to function evaluating APT frequency */
 
81
unsigned smplf;         /* number of samples per second << 16 */
 
82
unsigned smpl_line;     /* number of samples per line << 16 */
 
83
unsigned hsmpl_sec;     /* half the number of samples per second */
 
84
int     aptncmax;       /* maximum "empty" points in an APT-line */
 
85
int     phstate = 0;    /* state (0=waiting, 1=active) of phase-finder */
 
86
int     phlines;        /* number of recognized phase-lines */
 
87
unsigned hsmpl_line;    /* half the number of samples per line */
 
88
int     phposa[24];     /* phase position A (middle of line) */
 
89
int     phposb[24];     /* phase position B (edges of line) */
 
90
int     phsdir[24];     /* phase direction (beginning or end of line) */
 
91
int     phaseavg;       /* average phase position calculated */
 
92
char    *demod_ptr;     /* pointer to raw demodulated data */
 
93
int     demod_cnt;      /* number of decoded points per call */
 
94
char    *mod_ptr;       /* pointer to raw data being modulated */
 
95
char    *mod_end;       /* pointer to first byte behind end of modulator-space */
 
96
FILE    *fsfile;        /* file pointer of current save-file */
 
97
char    faxsavename[256]; /* current name of save-file */
 
98
char    *saveline;      /* storage for 1 image-line in save_func */
 
99
XtAppContext    mainapp; /* main app.context (needed for interv.timer) */
 
100
XtIntervalId    chstime; /* for the repetitive called background function */
 
101
XtInputId       dspxid = 0; /* for the background function when using select() */
 
102
XEvent  event;          /* event needed to form the XtAppMainLoop */
 
103
unsigned twidth;        /* width of transmitted image */
 
104
unsigned theight;       /* height of transmitted image */
 
105
int     tx_phlines;     /* number of phase-in lines to be transmitted */
 
106
char    *timg_ptr;      /* array holding image to be transmitted (pixel oriented) */
 
107
FILE    *ftfile;        /* pointer to file-struct for transmission */
 
108
 
 
109
/*
 
110
 * init_fax initializes the "core"-space where the raw decoded data resides.
 
111
 * This practice is not very nice to memory-limited systems, but has the
 
112
 * advantage of being able to back up from nearly any setup-error (including
 
113
 * wrong lpm, IOC, direction and color-mode but excluding tuning-errors)
 
114
 */
 
115
void init_fax(void)
 
116
{
 
117
  if (fax_inited) return;
 
118
  fprintf(stderr, "initializing FAX procedures and alloc'ing core-space\n");
 
119
  lpm = 120;
 
120
  ixoc = 288;
 
121
  devi = 400;
 
122
  mod_mode = MOD_FM | FIL_MIDL;
 
123
  dmaxval = 63;
 
124
  compval = dmaxval >> 1;
 
125
  core_dta = malloc(CORESIZE);
 
126
  core_start = core_dta;
 
127
  core_wptr = core_dta;
 
128
  core_maxptr = core_dta + COREMAX;
 
129
  interface_init(&demod_ptr, &demod_cnt);
 
130
  setup_mode(mod_mode, dmaxval, devi, &smplf);
 
131
  hsmpl_sec = smplf >> 17;
 
132
  aptncmax = hsmpl_sec / 25;
 
133
  mod_end = demod_ptr + demod_cnt;
 
134
  mod_ptr = demod_ptr;
 
135
  fprintf(stderr, "smplf = %08x (16.16), demod_cnt = %d\n", smplf, demod_cnt);
 
136
  disp_func = decode_fax_gray;
 
137
  fax_tx_func = transmit_fax_gray;
 
138
  save_func = save_fax_gray;
 
139
  fsfile = NULL;
 
140
  saveline = NULL;
 
141
  apt_notify = apt_control;
 
142
  chstime = (XtIntervalId) 0;
 
143
 
 
144
  timg_ptr = NULL;
 
145
  ftfile = NULL;
 
146
 
 
147
  fax_inited = 1;
 
148
}
 
149
 
 
150
/* exit_fax frees the core_dta space, so that other program-parts may
 
151
   allocate memory without having a dead-space overhead.
 
152
*/
 
153
void exit_fax(void)
 
154
{
 
155
  if (!fax_inited) return;
 
156
  free(core_dta);
 
157
  fax_inited = 0;
 
158
}
 
159
 
 
160
/*
 
161
 * setup_fax sets up all the variables for FAX-reception and transmission.
 
162
 * s_lpm : lines per minute (no change if set to 0)
 
163
 * s_ixoc: IOC to use (pixels per line = PI * IOC) (no change if set to 0)
 
164
 * mode  : fax-specific mode setings such as writing direction and order,
 
165
 *         phase-in polarity and grayscale or color-mode
 
166
 * s_devi: deviation to use for FM (no change if set to 0)
 
167
 * s_modem : (de-)modulator-specific settings as filter to use, AM or FM 
 
168
 */
 
169
void setup_fax(int s_lpm, int s_ixoc, unsigned mode,
 
170
        Widget toplevel, unsigned width, unsigned height,
 
171
        int s_devi, unsigned s_modem)
 
172
{
 
173
  unsigned id;
 
174
  unsigned filter, mmode;
 
175
  void (*old_func)(int);
 
176
 
 
177
  /* be sure initialisation is done */
 
178
  init_fax();
 
179
 
 
180
  mainapp = XtWidgetToApplicationContext(toplevel);
 
181
  /* if size is given or has changed, re-create X-images */
 
182
  if ((width) || (height)) {
 
183
    if (width)
 
184
      canwid = width;
 
185
    if (height)
 
186
      canhei = height;
 
187
    create_images(toplevel, canwid, canhei);
 
188
  }
 
189
  /* check if the (de-)modulator needs readjustment */
 
190
  filter = s_modem & FIL_MASK;
 
191
  mmode = s_modem & MOD_BITS;
 
192
  if ((filter) || (mmode) || (s_devi)) {
 
193
    fprintf(stderr, "setting filter & mmode = 0x%04x\n", (filter | mmode));
 
194
    if (s_devi) {
 
195
      if (s_devi < 100) s_devi = 100;
 
196
      if (s_devi > 1200) s_devi = 1200;
 
197
      devi = s_devi;
 
198
    }
 
199
    setup_mode((filter | mmode), dmaxval, s_devi, &smplf);
 
200
    hsmpl_sec = smplf >> 17;
 
201
    aptncmax = hsmpl_sec / 25;
 
202
    if (filter)
 
203
    {
 
204
      mod_mode = (~FIL_MASK & mod_mode) | filter;
 
205
    }
 
206
    if (mmode)
 
207
    {
 
208
      mod_mode = (~MOD_BITS & mod_mode) | mmode;
 
209
    }
 
210
  }
 
211
 
 
212
  if (s_lpm) {
 
213
    if (s_lpm < 60) s_lpm = 60;
 
214
    if (s_lpm > 500) s_lpm = 500;
 
215
    lpm = s_lpm;
 
216
    fprintf(stderr, "changing lpm to %d\n", lpm);
 
217
  }
 
218
  if (s_ixoc) {
 
219
    if (s_ixoc < 60) s_ixoc = 60;
 
220
    if (s_ixoc > 600) s_ixoc = 600;
 
221
    ixoc = s_ixoc;
 
222
    fprintf(stderr, "changing ioc to %d\n", ixoc);
 
223
  }
 
224
  if ((id = mode & FAX_POL)) {
 
225
    if (id == FAX_CNOR) {
 
226
      invimage = 0;
 
227
    } else {
 
228
      invimage = 1;
 
229
    }
 
230
    fprintf(stderr, "setting invimage mode to %d\n", invimage);
 
231
  }
 
232
  if ((id = mode & FAX_CFLS)) {
 
233
    if (id == FAX_CUNFL)  {
 
234
      flip = 0;
 
235
    } else {
 
236
      flip = 1;
 
237
    }
 
238
    fprintf(stderr, "setting color-flip to %d\n", flip);
 
239
  }
 
240
  if ((id = mode & FAX_CROTS)) {
 
241
    switch(id) {
 
242
      case FAX_CROT0:
 
243
        rotate = 0;
 
244
        break;
 
245
      case FAX_CROT1:
 
246
        rotate = 1;
 
247
        break;
 
248
      case FAX_CROT2:
 
249
        rotate = 2;
 
250
        break;
 
251
    }
 
252
    fprintf(stderr, "setting color-rotation to %d\n", rotate);
 
253
  }
 
254
  if ((id = mode & FAX_DIR)) {
 
255
    if (id & FAX_TOP2BOT)
 
256
      bot2top = 0;
 
257
    else if (id & FAX_BOT2TOP)
 
258
      bot2top = 1;
 
259
 
 
260
    if (id & FAX_LEF2RIG)
 
261
      right2left = 0;
 
262
    else if (id & FAX_RIG2LEF)
 
263
      right2left = 1;
 
264
 
 
265
    fprintf(stderr, "changing direction to h=%d, v=%d\n", right2left, bot2top);
 
266
  }
 
267
  if ((id = mode & FAX_ROT)) {
 
268
    if (id == FAX_HOR) {
 
269
        vertical = 0;
 
270
    } else {
 
271
        vertical = 1;
 
272
    }
 
273
    fprintf(stderr, "selecting %s direction\n",
 
274
         (vertical) ? "vertical" : "horizontal");
 
275
  }
 
276
  if ((id = mode & FAX_PHS)) {
 
277
    if (id == FAX_PWHT) {
 
278
        invphase = 1;
 
279
    } else {
 
280
        invphase = 0;
 
281
    }
 
282
    fprintf(stderr, "phase inversion mode = %d\n", invphase);
 
283
  }
 
284
  if ((id = mode & FAX_CMODE)) {
 
285
    switch (id) {
 
286
      case FAX_GRAY:
 
287
        mcolor = 0;
 
288
        break;
 
289
      case FAX_COLOR:
 
290
        mcolor = 1;
 
291
        break;
 
292
    }
 
293
    fprintf(stderr, "receive mode is %s\n", (mcolor) ? "color" : "grayscale");
 
294
  }
 
295
  /* now, all modifications to variables are done.
 
296
     some recomputations are to be done dependant on what has changed... */
 
297
  if (mode & FAX_CMODS)
 
298
    if (mcolor) {
 
299
      fill_cmap_col(invimage, flip, rotate);
 
300
    } else {
 
301
      fill_cmap_gray(invimage);
 
302
    }
 
303
  if ((mode & (FAX_DIR | FAX_ROT | FAX_CMODE | FAX_CMODS))
 
304
        || (s_ixoc) || (s_lpm) || (width) || (height)
 
305
        || (s_modem & MOD_BITS)) {
 
306
    if (mcolor) {
 
307
      disp_func = decode_fax_gray;
 
308
      save_func = save_fax_gray;
 
309
    } else {
 
310
      disp_func = decode_fax_gray;
 
311
      save_func = save_fax_gray;
 
312
    }
 
313
    /* recomputations are done in disp_func() */
 
314
    fprintf(stderr, "initializing disp_func\n");
 
315
    disp_func(D_CPINIT | D_WDINIT | D_LDINIT);
 
316
    /* now call function to re-create picture */
 
317
#if stillneeded /* the disp_func should lock itself */
 
318
    old_func = disp_func;
 
319
    disp_func = NULL;
 
320
    fprintf(stderr, "calling disp_func to re-display image\n");
 
321
    old_func(D_ALLOWX);
 
322
    disp_func = old_func;
 
323
#else
 
324
    fprintf(stderr, "calling disp_func to re-display image\n");
 
325
    disp_func(D_ALLOWX);
 
326
#endif
 
327
  }
 
328
  if ((mmode) && (dspxid != 0))
 
329
  {
 
330
    /* re-initiate data reception, because changing the modulation mode
 
331
     * (and thus changing the sample rate) requires the data stream to
 
332
     * stop. [Later, this should be RX or TX depending on what we do] */
 
333
    fax_rx_backgnd((XtPointer) NULL, &dspfd, (XtInputId *) NULL);
 
334
  }
 
335
}
 
336
 
 
337
/* enable FAX reception: set auto-initializing background function */
 
338
void receive_on(void)
 
339
{
 
340
#ifndef DSP_SELECT
 
341
  if (chstime != (XtIntervalId) 0) return;
 
342
#endif
 
343
  fax_state = FAX_APT;
 
344
  mode_notify(fax_state);
 
345
#ifdef DSP_SELECT
 
346
  dspxid = XtAppAddInput(mainapp, dspfd, (XtPointer) XtInputReadMask,
 
347
                fax_rx_backgnd, (XtPointer) NULL);
 
348
  fprintf(stderr, "dspxid from XtAppAddInput is %ld\n", dspxid);
 
349
  /* initiate the reading of data. Once started, it is called by
 
350
   * XtAppMainLoop() which uses select() to listen on dspfd. */
 
351
  fax_rx_backgnd((XtPointer) NULL, &dspfd, &dspxid);
 
352
#else
 
353
  chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
 
354
#endif
 
355
}
 
356
 
 
357
void receive_off(void)
 
358
{
 
359
#ifdef DSP_SELECT
 
360
  XtRemoveInput(dspxid);
 
361
  dspxid = (XtInputId) 0;
 
362
#else
 
363
  XtRemoveTimeOut(chstime);
 
364
#endif
 
365
  interface_stop();
 
366
  chstime = (XtIntervalId) 0;
 
367
}
 
368
 
 
369
#ifdef DSP_SELECT
 
370
/* this is the reception routine triggered upon input from DSP device */
 
371
void fax_rx_backgnd(XtPointer client_data, int *source, XtInputId *xid)
 
372
#else
 
373
/* this is the reception routine which calls itself after 250ms */
 
374
void fax_rx_backgnd(XtPointer client_data, XtIntervalId *xid)
 
375
#endif
 
376
{
 
377
  int space;
 
378
 
 
379
/*
 
380
  if (init_rx) {
 
381
    init_rx = 0;
 
382
    core_wptr = core_dta;
 
383
  }
 
384
*/
 
385
/*
 
386
  fprintf(stderr, "receiving data\n");
 
387
*/
 
388
  /* get the input samples and demodulate the input data stream */
 
389
  do_receive();
 
390
 
 
391
  /* update the signal-level scrollbar display */
 
392
  set_sigdisplay((double)rx_level / 255.0);
 
393
 
 
394
  /* always watch for APT frequencies */
 
395
/*
 
396
  fprintf(stderr, "decoding APT\n");
 
397
*/
 
398
  decode_apt(0);
 
399
 
 
400
  /* if we are in the phasing state, compute the phase-position */
 
401
  if (fax_state == FAX_PHAS)
 
402
    sync_phase(0);
 
403
 
 
404
  /* copy the data into the core_dta array and advance the write-pointer */
 
405
  if (fax_state == FAX_RX) {
 
406
    space = core_maxptr - core_wptr;
 
407
    if (space >  demod_cnt)
 
408
      space = demod_cnt;
 
409
    memcpy(core_wptr, demod_ptr, space);
 
410
    core_wptr += space;
 
411
  }
 
412
 
 
413
#ifdef DSP_SELECT
 
414
  /* we don't need to retrigger ourself - do nothing */
 
415
#else
 
416
  /* add a new timeout to call this function again */
 
417
/*
 
418
  printf("adding new timeout\n");
 
419
*/
 
420
  chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
 
421
#endif
 
422
 
 
423
  /* if disp_func is set, call that function (e.g. main FAX decoder loop) */
 
424
  if ((disp_func) && !(disp_locked)) {
 
425
/*
 
426
    fprintf(stderr, "calling disp_func\n");
 
427
*/
 
428
    disp_func(0);
 
429
  }
 
430
  /* if save_func is set (saving of received image enabled), call function */
 
431
  if ((save_func) && !(save_locked)) {
 
432
/*
 
433
    fprintf(stderr, "calling save_func\n");
 
434
*/
 
435
    save_func(F_DOSAVE, 0);
 
436
  }
 
437
}
 
438
 
 
439
/*
 
440
 * grayscale FAX decoding main routine.
 
441
 * init is used to control the behavior and initialize some internal
 
442
 * variables. It is bit-wise coded as follows :
 
443
 *  D_CPINIT : initialize read-pointer to start of core-buffer
 
444
 *  D_WDINIT : initialize x-position to the start-value
 
445
 *  D_LDINIT : initialize y-position to the start-value
 
446
 *  D_ALLOWX : periodically call XtAppProcessEvent during processing
 
447
 *      (requires that this function is NOT called from fax_rx_backgnd !)
 
448
 */
 
449
void decode_fax_gray(int init)
 
450
{
 
451
  XtInputMask msk;
 
452
 
 
453
#ifdef FAST8BIT
 
454
  static char *imptr;
 
455
  static char *imptinit;
 
456
  static int  impinc;
 
457
#endif
 
458
 
 
459
  /* pointer to sample-point for current pixel and current start-of-line */
 
460
  static char *core_line, *core_pix;
 
461
  /* sample-values per line or per pixel-value, 16bit int, 16bit frac */
 
462
  static unsigned inc_pix, inc_line;
 
463
  /* current index to pixel or line in sample-array, 16bit int, 16bit frac */
 
464
  static unsigned idx_pix, idx_line, idx_p0;
 
465
  /* increment between actual and previous pixel/line position */
 
466
  static unsigned ipix, iline;
 
467
  /* pixel-in-line-position start/increment/end */
 
468
  static int pixinit, pixinc, pixend;
 
469
  /* line-in-image-position start/increment/end, max. line of XImage */
 
470
  static int lineinit, lineinc, lineend, imgmax;
 
471
  static int (*put_pix)(struct _XImage *, int, int, unsigned long);
 
472
 
 
473
  if (init & D_INITS) {
 
474
    /* smpl_line is the number of core_dta points per line << 16 */
 
475
    smpl_line = 60.0 / lpm * smplf;
 
476
    if (vertical) {
 
477
      inc_pix = smpl_line / canhei;
 
478
      inc_line = (int)(ixoc * PI * 65536.0 / canhei); 
 
479
      imgmax = DEFWIDTH;
 
480
      put_pix = verimag->f.put_pixel;
 
481
    } else {
 
482
      inc_pix = smpl_line / canwid;
 
483
      inc_line = (int)(ixoc * PI * 65536.0 / canwid); 
 
484
      imgmax = DEFHEIGHT;
 
485
      put_pix = horimag->f.put_pixel;
 
486
    }
 
487
    if (!(vertical) && (right2left)) {
 
488
      pixinit = canwid - 1;
 
489
      pixinc = -1;
 
490
      pixend = -1;
 
491
#ifdef FAST8BIT
 
492
      imptinit = horimag->data + canwid - 1;
 
493
      impinc = -1;
 
494
#endif
 
495
    } else
 
496
    if ((vertical) && (bot2top)) {
 
497
      pixinit = canhei - 1;
 
498
      pixinc = -1;
 
499
      pixend = -1;
 
500
#ifdef FAST8BIT
 
501
      imptinit = verimag->data + (canhei - 1) * verimag->bytes_per_line;
 
502
      impinc = -verimag->bytes_per_line;
 
503
#endif
 
504
    } else {
 
505
      pixinit = 0;
 
506
      pixinc = 1;
 
507
      pixend = (vertical) ? canhei : canwid;
 
508
#ifdef FAST8BIT
 
509
      imptinit = (vertical) ? verimag->data : horimag->data;
 
510
      impinc = (vertical) ? verimag->bytes_per_line : 1;
 
511
#endif
 
512
    }
 
513
    /* initialize the line-advance variables and pointers */
 
514
    if (!(vertical) && (bot2top)) {
 
515
        lineinit = canhei - DEFHEIGHT;
 
516
        lineinc = -1;
 
517
        lineend = -1;
 
518
    } else
 
519
    if ((vertical) && (right2left)) {
 
520
        lineinit = canwid - DEFWIDTH;
 
521
        lineinc = -1;
 
522
        lineend = -1;
 
523
    } else {
 
524
        lineinit = 0;
 
525
        lineinc = 1;
 
526
        lineend = (vertical) ? canwid : canhei;
 
527
    }
 
528
 
 
529
    if (init & D_WDINIT) {
 
530
      pixpos = pixinit;
 
531
    }
 
532
 
 
533
    if (init & D_LDINIT) {
 
534
      linepos = lineinit;
 
535
      if ((!(vertical) && (bot2top)) || ((vertical) && (right2left)))
 
536
        imline = imgmax - 1;
 
537
      else
 
538
        imline = 0;
 
539
    }
 
540
#ifdef FAST8BIT
 
541
    if ((init & D_LDINIT) || (init & D_WDINIT)) {
 
542
      imptr = imptinit + impinc * pixpos;
 
543
      if (vertical)
 
544
        imptr += imline;
 
545
      else
 
546
        imptr += horimag->bytes_per_line * imline; 
 
547
    }
 
548
#endif
 
549
 
 
550
    if (init & D_CPINIT) {
 
551
      /* initialize the fractional index pointers */
 
552
      idx_pix = idx_line = idx_p0 = 0;
 
553
      core_pix = core_line = core_start;
 
554
      ipix = iline = 0;
 
555
    }
 
556
    fprintf(stderr,"initialisation done :\n"
 
557
        "pixinit = %d, pixinc = %d, pixend = %d\n"
 
558
        "lineinit = %d, lineinc = %d, lineend = %d\n"
 
559
        "imline = %d, imgmax = %d\n",
 
560
        pixinit, pixinc, pixend,
 
561
        lineinit, lineinc, lineend,
 
562
        imline, imgmax);
 
563
        
 
564
    disp_locked = 0;
 
565
    return;
 
566
  }
 
567
  if (init & D_ALLOWX) {
 
568
    printf("redrawing from %d, %d, corepos = %d\n", pixpos, linepos, core_pix - core_dta);
 
569
  }
 
570
  disp_locked = 1;
 
571
  do {
 
572
    /* if it is better to wait for more data, cancel function and wait
 
573
       until it is called next time */
 
574
    if (core_pix >= core_wptr)
 
575
      break;
 
576
 
 
577
    /* enter a new brightness-value (0..63) into core_dta */
 
578
 
 
579
#ifdef FAST8BIT
 
580
    *imptr = coltab[*(unsigned char *)core_pix];
 
581
    imptr += impinc;
 
582
#else
 
583
    if (vertical)
 
584
      put_pix(verimag, imline, pixpos, coltab[*(unsigned char *)core_pix]);
 
585
    else
 
586
      put_pix(horimag, pixpos, imline, coltab[*(unsigned char *)core_pix]);
 
587
#endif
 
588
 
 
589
    /* shift the x-position, and if we have reached the end... */
 
590
    pixpos += pixinc;
 
591
    if (pixpos == pixend) {
 
592
      /* re-start from left border */
 
593
      pixpos = pixinit;
 
594
      /* now we have one more complete line, copy it from core_dta to the
 
595
         horimag (an Ximage). Use fast methode by advancing pointers */
 
596
 
 
597
      /* check if we wave filled up all lines of horimag, or if we just
 
598
         have got as many lines that we can complete the picture. */
 
599
      imline += lineinc;
 
600
      if ((imline == imgmax) || (imline < 0) || (linepos + imline == lineend)) {
 
601
        while ((init & D_ALLOWX) && ((msk = XtAppPending(mainapp)))) {
 
602
          XtAppProcessEvent(mainapp, msk);
 
603
        }
 
604
        if (vertical)
 
605
          if (right2left) {
 
606
            update_area(verimag, 0, 0, linepos, 0, (DEFWIDTH-1) - imline, canhei);
 
607
          } else {
 
608
            update_area(verimag, 0, 0, linepos, 0, imline, canhei);
 
609
          }
 
610
        else
 
611
          if (bot2top) {
 
612
            update_area(horimag, 0, 0, 0, linepos, canwid, (DEFHEIGHT-1) - imline);
 
613
          } else {
 
614
            update_area(horimag, 0, 0, 0, linepos, canwid, imline);
 
615
          }
 
616
        if (((vertical) && (right2left)) || (!(vertical) && (bot2top))) {
 
617
          imline = imgmax - 1;
 
618
          linepos -= imgmax;
 
619
          if (linepos < 0)
 
620
            linepos = lineinit;
 
621
        } else {
 
622
          imline = 0;
 
623
          linepos += imgmax;
 
624
          if (linepos >= lineend)
 
625
            linepos = 0;
 
626
        }
 
627
      }
 
628
 
 
629
#ifdef FAST8BIT
 
630
      if (vertical)
 
631
        imptr = imptinit + imline;
 
632
      else
 
633
        imptr = imptinit + horimag->bytes_per_line * imline;
 
634
#endif
 
635
 
 
636
      idx_line += inc_line;
 
637
      iline = (idx_line >> 16) & 0xffff;
 
638
      idx_line &= 0xffff;
 
639
      core_line += iline * ((smpl_line >> 16) & 0xffff);
 
640
 
 
641
      /* we must also initialize the pixel-counters here ! */
 
642
      idx_p0 += iline * (smpl_line & 0xffff);
 
643
      core_line += (idx_p0 >> 16) & 0xffff;
 
644
      core_pix = core_line;
 
645
      idx_p0 &= 0xffff;
 
646
      idx_pix = idx_p0;
 
647
      ipix = 0;
 
648
 
 
649
      /* jump over the stuff below... */
 
650
      continue;
 
651
    }
 
652
    /* shift the sample-point (16 bits integer, 16 bits fractional part) */
 
653
    idx_pix += inc_pix;
 
654
    ipix = (idx_pix >> 16) & 0xffff;
 
655
    core_pix += ipix;
 
656
    idx_pix &= 0xffff;
 
657
  } while (1);
 
658
  if (init & D_FLUSHIMG) {
 
659
    if (vertical)
 
660
        if (right2left) {
 
661
          update_area(verimag, 0, 0, linepos, 0, (DEFWIDTH-1) - imline, canhei);
 
662
        } else {
 
663
          update_area(verimag, 0, 0, linepos, 0, imline, canhei);
 
664
        }
 
665
    else
 
666
        if (bot2top) {
 
667
          update_area(horimag, 0, 0, 0, linepos, canwid, (DEFHEIGHT-1) - imline);
 
668
        } else {
 
669
          update_area(horimag, 0, 0, 0, linepos, canwid, imline);
 
670
        }
 
671
  }
 
672
  disp_locked = 0;
 
673
}
 
674
 
 
675
/*
 
676
 * this function should be used by the main program to initiate saving
 
677
 * of an image. If name is not given, it is constructed of date and time.
 
678
 */
 
679
int save_faxfile(char *name, int width)
 
680
{
 
681
  time_t tp; 
 
682
  char date[16];        /* string to build date for automatic savefile-name */
 
683
 
 
684
  /* check if save-file is already open */
 
685
  if (fsfile)
 
686
    return SAVE_BUSY;
 
687
  /* if no name is given, generate autosave-filename from date and time */
 
688
  if (name) {
 
689
    strcpy(faxsavename, name);
 
690
  } else {
 
691
    time(&tp);
 
692
    strftime(date, 14, "%m.%d-%H:%M", localtime(&tp));
 
693
    sprintf(faxsavename, "%s/faxsave_%s.pgm", FAX_SAVEDIR, date);
 
694
  }
 
695
  return save_func(F_OPEN, width);
 
696
}
 
697
 
 
698
/* properly close the save-file */
 
699
void close_faxsave(void)
 
700
{
 
701
  if (!(fsfile))
 
702
    return;
 
703
  save_func(F_GETDIM, 0);
 
704
  save_func(F_DOSAVE, 0);
 
705
  save_func(F_CLOSE, 0);
 
706
}
 
707
 
 
708
/*
 
709
 * fax-image saving function, writes grayscale ppm-images (pgm).
 
710
 * The image cannot be rotated, only flipped in writing-direction.
 
711
 * init defines the action to be done :
 
712
 * F_DOSAVE : save image if file is opened, close when completed
 
713
 * F_OPEN : open file, faxsavename contains the name and width the width
 
714
 *          of the image. If width is not given, the best resolution is taken
 
715
 *          (width = PI * IOC)
 
716
 * F_CLOSE : close file and adjust data in header to actual values
 
717
 * F_GETDIM : get dimensions and parameters of image into internal variables
 
718
 * the filename must previously be put into faxsavename.
 
719
 */ 
 
720
int save_fax_gray(int init, int width)
 
721
{
 
722
  XtInputMask msk;
 
723
  /* width and height of saved image */
 
724
  static unsigned swidth, sheight;
 
725
  static char *ldptr, *ldpinit, *ldpend;
 
726
  static int ldpinc;
 
727
  /* end of picture in core-space */
 
728
  static char *save_wptr = NULL;
 
729
  /* pointer to sample-point for current pixel and current start-of-line */
 
730
  static char *core_line, *core_pix;
 
731
  /* sample-values per line or per pixel-value, 16bit int, 16bit frac */
 
732
  static unsigned inc_pix, inc_line;
 
733
  /* current index to pixel or line in sample-array, 16bit int, 16bit frac */
 
734
  static unsigned idx_pix, idx_line, idx_p0;
 
735
  /* increment between actual and previous pixel/line position */
 
736
  static unsigned ipix, iline;
 
737
  /* pixel-in-line-position start/increment/end */
 
738
/*
 
739
  static int pixinit, pixinc, pixend;
 
740
*/
 
741
  /* line-in-image-position start/increment/end, max. line of XImage */
 
742
/*
 
743
  static int lineinit, lineinc, lineend, imgmax;
 
744
*/
 
745
  /* whether the writing-direction must be reversed */
 
746
  static int flip;
 
747
  int pos;
 
748
 
 
749
  if (init == F_OPEN) {
 
750
    /* close "old" file first */
 
751
    if (fsfile)
 
752
      save_fax_gray(F_CLOSE, 0);
 
753
     if (width > 0)
 
754
      swidth = width;
 
755
    else
 
756
      swidth = (ixoc * PI) + 0.5;
 
757
    fsfile = fopen(faxsavename, "wb");
 
758
    if (!(fsfile)) {
 
759
      return SAVE_NPERM;
 
760
    }
 
761
    fprintf(stderr, "save file \"%s\", %d pix/line\n", faxsavename, swidth);
 
762
    fputs("P5\nxxxxx\nyyyyy\n63\n", fsfile);
 
763
    /* allocate space for the one line */
 
764
    saveline = malloc(swidth + 4);
 
765
    /* do not initialize too much here, the user may change parameters
 
766
    of the picture while receiving... */
 
767
    save_wptr = NULL;
 
768
    return SAVE_OK;
 
769
  } else if (init == F_CLOSE) {
 
770
    if (!(fsfile))
 
771
      return SAVE_OK; /* no save-file open, doesn't matter */
 
772
    fprintf(stderr,"closing savefile\n");
 
773
    pos = ftell(fsfile);
 
774
    sheight = sypos;
 
775
    rewind(fsfile);
 
776
    fprintf(fsfile, "P5\n%05u\n%05u\n", swidth, sheight);
 
777
    fseek(fsfile, pos, SEEK_SET);
 
778
    fclose(fsfile);
 
779
    fsfile = NULL;
 
780
    if (saveline)
 
781
      free(saveline);
 
782
    save_wptr = NULL;
 
783
    return SAVE_OK;
 
784
  } else if (init == F_GETDIM) {
 
785
    if (!(fsfile))
 
786
      return SAVE_NFILE; /* no save-file open, can't get dimensions */
 
787
    /* now initialize all the variables... */
 
788
    fprintf(stderr, "getting image settings...");
 
789
    inc_pix = smpl_line / swidth;
 
790
    inc_line = (int)(ixoc * PI * 65536.0 / swidth); 
 
791
    idx_pix = idx_line = idx_p0 = 0;
 
792
    core_pix = core_line = core_start;
 
793
    save_wptr = core_wptr;
 
794
    ipix = iline = 0;
 
795
    flip = (vertical) ? 1 : 0;
 
796
    if (bot2top) flip ^= 1;
 
797
    if (right2left) flip ^= 1;
 
798
    if (flip) {
 
799
      ldpinit = saveline + (swidth - 1);
 
800
      ldpinc = -1;
 
801
      ldpend = saveline - 1;
 
802
    } else {
 
803
      ldpinit = saveline;
 
804
      ldpinc = 1;
 
805
      ldpend = saveline + swidth;
 
806
    }
 
807
    ldptr = ldpinit;
 
808
    sypos = 0;
 
809
    sheight = 0;
 
810
    return SAVE_OK;
 
811
  }
 
812
  /* no open save-file, or variables not initialized, so return */
 
813
  if (!(fsfile) || !(save_wptr)) return SAVE_NFILE;
 
814
  save_locked = 1;
 
815
  fprintf(stderr,"saving image...");
 
816
  while (core_pix < save_wptr) {
 
817
    if (invimage)
 
818
      *ldptr = dmaxval - *(unsigned char *)core_pix;
 
819
    else
 
820
      *ldptr = *(unsigned char *)core_pix;
 
821
    ldptr += ldpinc;
 
822
    if (ldptr == ldpend) {
 
823
      ldptr = ldpinit;
 
824
      sypos++;
 
825
      fwrite(saveline, swidth, 1, fsfile);
 
826
 
 
827
      while ((msk = XtAppPending(mainapp))) {
 
828
        XtAppProcessEvent(mainapp, msk);
 
829
      }
 
830
      idx_line += inc_line;
 
831
      iline = (idx_line >> 16) & 0xffff;
 
832
      idx_line &= 0xffff;
 
833
      core_line += iline * ((smpl_line >> 16) & 0xffff);
 
834
 
 
835
      /* we must also initialize the pixel-counters here ! */
 
836
      idx_p0 += iline * (smpl_line & 0xffff);
 
837
      core_line += (idx_p0 >> 16) & 0xffff;
 
838
      core_pix = core_line;
 
839
      idx_p0 &= 0xffff;
 
840
      idx_pix = idx_p0;
 
841
      ipix = 0;
 
842
 
 
843
      /* jump over the stuff below... */
 
844
      continue;
 
845
    }
 
846
    idx_pix += inc_pix;
 
847
    ipix = (idx_pix >> 16) & 0xffff;
 
848
    core_pix += ipix;
 
849
    idx_pix &= 0xffff;
 
850
  }
 
851
  fprintf(stderr,"done.\n");
 
852
  save_locked = 0;
 
853
  return SAVE_OK;
 
854
}
 
855
 
 
856
/* called when save-function has terminated writing */
 
857
void faxsave_complete(int init)
 
858
{
 
859
   /* this makes save_func call itself recursively, but should not hurt */
 
860
   save_func(F_CLOSE, 0);
 
861
}
 
862
 
 
863
/*
 
864
 * wait for a phasing signal, keep track of the phase-pulses, and preset
 
865
 * core_start on end of the phase_signal. This is done by correlating the
 
866
 * digitized gray-values (reduced to 1 or 0) with two sawtooth-signals,
 
867
 * each with a periode of one scan line, and one of them shifted by a
 
868
 * half scan-line against the other. This lets us find the position of
 
869
 * the phase-pulse relative to our scan-line. Lines are recognized as
 
870
 * phase-in-lines when they contain at most 3/32 and at least 1/32 of values
 
871
 * that are above (or below for inverse phase) the middle of the gray-scale.
 
872
 */
 
873
void sync_phase(int init)
 
874
{
 
875
  /* run counters, count pixels per line (16bit int, 16bit frac) */
 
876
  static int phsarc, phsbrc;
 
877
  /* accumulators for the integration */
 
878
  static int phsaacc = 0, phsbacc = 0;
 
879
  /* these are counted up until limit to form the sawtooth-signal */
 
880
  static int phsainc, phsbinc;
 
881
  /* number of sample-points processed */
 
882
  static int npoints = 0;
 
883
  /* number of points having the right level (black) for a sync pulse */
 
884
  static int nphpts = 0;
 
885
  /* minimum/maximum  number of black points per line that must be present */
 
886
  static int minphpts, maxphpts;
 
887
  static char done = 0;
 
888
  char *dtaptr;
 
889
  int pcnt;
 
890
  int i,j;
 
891
 
 
892
  dtaptr = demod_ptr;
 
893
  pcnt = demod_cnt;
 
894
  if (init) {
 
895
    phstate = 0;
 
896
    hsmpl_line = smpl_line >> 17;
 
897
    phsaacc = phsbacc = 0;
 
898
    phsarc = smpl_line;
 
899
    phsbrc = smpl_line >> 1;
 
900
    phsainc = - hsmpl_line;
 
901
    phsbinc = 0;
 
902
    minphpts = (smpl_line >> 16) >> 5;
 
903
    maxphpts = minphpts * 3;
 
904
    nphpts = 0;
 
905
    phlines = 0;
 
906
    done = 0;
 
907
    core_wptr = core_dta;
 
908
    core_start = core_dta;
 
909
    fprintf(stderr, "initialized sync-phase-detector\n");
 
910
    return;
 
911
  }
 
912
 
 
913
  while (pcnt > 0) {
 
914
      if ((!(invphase) && *dtaptr > compval) ||
 
915
           ((invphase) && *dtaptr < compval)) {
 
916
        phsaacc += phsainc;
 
917
        phsbacc += phsbinc;
 
918
        nphpts++;
 
919
      }
 
920
      phsainc++;
 
921
      phsbinc++;
 
922
      npoints++;
 
923
      dtaptr++;
 
924
      pcnt--;
 
925
      phsarc -= 65536;
 
926
      if (phsarc <= 0) {
 
927
        done = 1; /* this indicates the end-of-line */
 
928
        phsarc += smpl_line;
 
929
        phsainc = - hsmpl_line;
 
930
      }
 
931
      phsbrc -= 65536;
 
932
      if (phsbrc <= 0) {
 
933
        phsbrc += smpl_line;
 
934
        phsbinc = - hsmpl_line;
 
935
      }
 
936
      if (done) {
 
937
#if (DEBUG & DBG_SYN)
 
938
        fprintf(stderr, "got line with %d of %d points phase-value\n",
 
939
                nphpts, npoints);
 
940
#endif
 
941
        /* check if it was probably a phase-in line */
 
942
        if (nphpts < maxphpts && nphpts > minphpts) {
 
943
          if (phlines < 24) {
 
944
            /* use the accumulator with the lower absolute-value */
 
945
            if (abs(phsaacc) < abs(phsbacc)) {
 
946
              i = phsaacc / nphpts;
 
947
#if (DEBUG & DBG_SYN)
 
948
              fprintf(stderr, "sync line %d: A=%d\n", phlines, i);
 
949
#endif
 
950
              phposa[phlines] = i;
 
951
              if (i < 0)
 
952
                phsdir[phlines] = 1; /* left half */
 
953
              else
 
954
                phsdir[phlines] = 0; /* right half */
 
955
            } else {
 
956
              i = phsbacc / nphpts;
 
957
#if (DEBUG & DBG_SYN)
 
958
              fprintf(stderr, "sync line %d: B=%d\n", phlines, i);
 
959
#endif
 
960
              phposb[phlines] = i;
 
961
              if (i < 0)
 
962
                phsdir[phlines] = 2; /* right half */
 
963
              else
 
964
                phsdir[phlines] = 3; /* left half */
 
965
            }
 
966
            if (phstate == 0) { /* first sync line */
 
967
              phstate = 1;
 
968
            } else if (phstate == 1) { /* any sync line */
 
969
            }
 
970
            phlines++;
 
971
          } else { /* phlines >= 24 */
 
972
            /* ignore any further sync-lines... */
 
973
          }
 
974
        } else {
 
975
          /* no sync line, we are still waiting for one or they have passed */
 
976
          if (phstate == 0) {
 
977
            /* no sync line yet - just wait ?! */
 
978
          } else if (phstate == 1) {
 
979
            /* now begin to compute the ultimate sync-position */
 
980
            j = 0;
 
981
            /* count the lines in the left half */
 
982
            for (i=0; i<phlines; i++) {
 
983
              if (phsdir[i] & 1) j++;
 
984
            }
 
985
            phaseavg = 0;
 
986
            if (j > (phlines >> 1)) { /* more points in the left half */
 
987
#if (DEBUG & DBG_SYN)
 
988
              fprintf(stderr, "calculating for left half...\n");
 
989
#endif
 
990
              for (i=0; i<phlines; i++)
 
991
                if (phsdir[i] & 2)
 
992
                  phaseavg += phposb[i] - hsmpl_line;
 
993
                else
 
994
                  phaseavg += phposa[i];
 
995
            } else { /* more points in the right half */
 
996
#if (DEBUG & DBG_SYN)
 
997
              fprintf(stderr, "calculating for right half...\n");
 
998
#endif
 
999
              for (i=0; i<phlines; i++)
 
1000
                if (phsdir[i] & 2)
 
1001
                  phaseavg += phposb[i] + hsmpl_line;
 
1002
                else
 
1003
                  phaseavg += phposa[i];
 
1004
            }
 
1005
            phaseavg /= phlines;
 
1006
            phaseavg += hsmpl_line;
 
1007
#if (DEBUG & DBG_SYN)
 
1008
            fprintf(stderr, "phase average = %d\n", phaseavg);
 
1009
#endif
 
1010
            /* now prepare the core_start pointer for reception */
 
1011
            /* calculate difference from sync-pos to end of line */
 
1012
            j = (smpl_line >> 16);
 
1013
            i = demod_cnt - pcnt + phaseavg;
 
1014
            if (i > j)
 
1015
              i -= j;
 
1016
            /* start decoding at the beginning of the core */
 
1017
            core_wptr = core_dta;
 
1018
            core_start = core_dta + i;
 
1019
            /* now enter the real reception mode. When returning into the
 
1020
                fax_rx_backgnd, fax_state is set to FAX_RX so that the data
 
1021
                we just processed can also be used for the picture. */
 
1022
            fax_rx_start(1);
 
1023
            /* no more data to process */
 
1024
            return;
 
1025
          }
 
1026
        } /* if (sync_line_detected) */
 
1027
        /* re-initialize the both accumulators and sample-point counters */
 
1028
        phsaacc = 0;
 
1029
        phsbacc = 0;
 
1030
        npoints = 0;
 
1031
        nphpts = 0;
 
1032
        done = 0;
 
1033
      } /* if (done) */
 
1034
  } /* while (pcnt > 0) */
 
1035
}
 
1036
 
 
1037
/*
 
1038
 * calculate the APT frequency by counting low->high->low transitions.
 
1039
 * not very nice, but it works :-S . This funcion always computes the
 
1040
 * APT for 0.5 seconds, independant from demod_cnt, which can be very
 
1041
 * high on systems that use a large block-size for the audio-devide.
 
1042
 * After each calculation, apt_notify() is called with the frequency as
 
1043
 * argument.
 
1044
 */
 
1045
void decode_apt(int dummy)
 
1046
{
 
1047
  /* how many transitions (half-waves) we have counted */
 
1048
  static int apthws = 0;
 
1049
  /* how many consecutive points were on one side of the comparator-value */ 
 
1050
  static int aptncact = 0;
 
1051
  /* the phase (black or white) we processed last time */
 
1052
  static int phs = 0;
 
1053
  static int npoints = 0;
 
1054
  char *dtaptr;
 
1055
  int pcnt;
 
1056
 
 
1057
  dtaptr = demod_ptr;
 
1058
  pcnt = demod_cnt;
 
1059
  /* If we have to start with the "black" phase, do it before the main-loop
 
1060
     starts. This prevents us from ugly goto's (shudder) */
 
1061
  if (phs) {
 
1062
    while (pcnt) {
 
1063
      pcnt--;
 
1064
      if (++npoints >= hsmpl_sec) {
 
1065
        apt_notify(apthws);
 
1066
        apthws = 0;
 
1067
        npoints = 0;
 
1068
      }
 
1069
      if (*(unsigned char *)dtaptr++ <= compval) {
 
1070
        if (aptncact > aptncmax)
 
1071
          apthws = 0;
 
1072
        else
 
1073
          apthws++;
 
1074
        break;
 
1075
      }
 
1076
      aptncact++;
 
1077
    }
 
1078
  }
 
1079
  while (pcnt > 0) {
 
1080
    aptncact = 0;
 
1081
    while (pcnt) {
 
1082
      pcnt--;
 
1083
      if (++npoints >= hsmpl_sec) {
 
1084
#if (DEBUG & DBG_APT)
 
1085
        fprintf(stderr,"APT freq. pos = %d\n", apthws);
 
1086
#endif
 
1087
        apt_notify(apthws);
 
1088
        apthws = 0;
 
1089
        npoints = 0;
 
1090
      }
 
1091
      if (*(unsigned char *)dtaptr++ > compval) {
 
1092
        if (aptncact > aptncmax)
 
1093
          apthws = 0;
 
1094
        else
 
1095
          apthws++;
 
1096
        break;
 
1097
      }
 
1098
      aptncact++;
 
1099
    }
 
1100
    aptncact = 0;
 
1101
    while (pcnt) {
 
1102
      pcnt--;
 
1103
      if (++npoints >= hsmpl_sec) {
 
1104
#if (DEBUG & DBG_APT)
 
1105
        fprintf(stderr,"APT freq. neg = %d\n", apthws);
 
1106
#endif
 
1107
        apt_notify(apthws);
 
1108
        apthws = 0;
 
1109
        npoints = 0;
 
1110
      }
 
1111
      if (*(unsigned char *)dtaptr++ <= compval) {
 
1112
        if (aptncact > aptncmax)
 
1113
          apthws = 0;
 
1114
        else
 
1115
          apthws++;
 
1116
        break;
 
1117
      }
 
1118
      aptncact++;
 
1119
    }
 
1120
  }
 
1121
  /* now mark the phase for the next call... */
 
1122
  if (*(unsigned char *)(dtaptr-1) <= compval)
 
1123
    phs = 0;
 
1124
  else
 
1125
    phs = 1;
 
1126
}
 
1127
 
 
1128
void apt_control(int aptfrq)
 
1129
{
 
1130
  static int cnt;
 
1131
/*
 
1132
  fprintf(stderr, "apt_control: %d\n", aptfrq);
 
1133
*/
 
1134
  switch (fax_state) {
 
1135
    /* wait for one of the valid APT frequencies */
 
1136
    case FAX_APT:
 
1137
        if (abs(aptfrq - aptstart) < 2) {
 
1138
          if (++cnt >= 2) fax_rx_phase(1);
 
1139
        } else {
 
1140
          cnt = 0;
 
1141
        }
 
1142
        break;
 
1143
    /* here, a new start or a stop (interrupt) may occur */
 
1144
    case FAX_PHAS:
 
1145
    case FAX_RX:
 
1146
        if (abs(aptfrq - aptstop) < 2) {
 
1147
          if (++cnt >= 2) fax_rx_stop(1);
 
1148
        } else {
 
1149
          cnt = 0;
 
1150
        }
 
1151
        break;
 
1152
  }
 
1153
}
 
1154
 
 
1155
void fax_rx_start(int internal)
 
1156
{
 
1157
  fprintf(stderr,"starting fax reception\n");
 
1158
  /* if we come from phasing, initialize disp_func */
 
1159
  if (fax_state == FAX_PHAS)
 
1160
    disp_func(D_CPINIT | D_WDINIT | D_LDINIT);
 
1161
  fax_state = FAX_RX;
 
1162
  if (internal)
 
1163
    mode_notify(fax_state);
 
1164
}
 
1165
 
 
1166
void fax_rx_phase(int internal)
 
1167
{
 
1168
  fprintf(stderr,"entering phase-in mode\n");
 
1169
  sync_phase(1);
 
1170
  fax_state = FAX_PHAS;
 
1171
  if (internal)
 
1172
    mode_notify(fax_state);
 
1173
}
 
1174
 
 
1175
void fax_rx_stop(int internal)
 
1176
{
 
1177
  fprintf(stderr,"stopping fax reception\n");
 
1178
  fax_state = FAX_APT;
 
1179
  /* flush rest of image (in horimag/verimag) */
 
1180
  disp_func(D_FLUSHIMG);
 
1181
  /* get current image-parameters for saving */
 
1182
  save_func(F_GETDIM, 0);
 
1183
  save_func(F_DOSAVE, 0);
 
1184
  save_func(F_CLOSE, 0);
 
1185
  if (internal)
 
1186
    mode_notify(fax_state);
 
1187
}
 
1188
 
 
1189
/*
 
1190
 * this function is called by the callback-function of the Canvas-widget
 
1191
 * to move the picture in writing-direction, when phasing in has failed
 
1192
 * or was missed. px and py contain the coordinates of the button-press.
 
1193
 */
 
1194
void shift_fax_coords(unsigned px, unsigned py)
 
1195
{
 
1196
  void (*old_func)();
 
1197
  unsigned tmp_pos;
 
1198
 
 
1199
  fprintf(stderr, "coords = %d, %d\n", px, py);
 
1200
  old_func = disp_func;
 
1201
  disp_func = NULL;
 
1202
  if (vertical) {
 
1203
    if (bot2top)
 
1204
        tmp_pos = smpl_line / canhei * (canhei - py);
 
1205
    else
 
1206
        tmp_pos = smpl_line / canhei * py;
 
1207
  } else {
 
1208
    if (right2left)
 
1209
        tmp_pos = smpl_line / canwid * (canwid - px);
 
1210
    else
 
1211
        tmp_pos = smpl_line / canwid * px;
 
1212
  }
 
1213
  core_start += (tmp_pos >> 16);
 
1214
  tmp_pos = (smpl_line >> 16);
 
1215
  if (core_start - core_dta > tmp_pos)
 
1216
    core_start -= tmp_pos;
 
1217
  old_func (D_CPINIT | D_WDINIT | D_LDINIT);
 
1218
  old_func (D_ALLOWX);
 
1219
  disp_func = old_func;
 
1220
}
 
1221
 
 
1222
/*
 
1223
 * this function is called by the callback-function of the Canvas-widget
 
1224
 * to re-adjust the sampling frequency to correct the line-shifting
 
1225
 * caused by slightly deadjusted samling frequency.
 
1226
 */
 
1227
void correct_fax_azimut(int dx, int dy)
 
1228
{
 
1229
  void (*old_func)();
 
1230
  int flip;
 
1231
  int df;
 
1232
 
 
1233
  fprintf(stderr, "coords = %d, %d\n", dx, dy);
 
1234
  flip = 0;
 
1235
  if (right2left) flip ^= 1;
 
1236
  if (bot2top) flip ^= 1;
 
1237
  if (vertical) {
 
1238
    df = (smplf * (double)dy) / (dx * PI * ixoc);
 
1239
  } else {
 
1240
    df = (smplf * (double)dx) / (dy * PI * ixoc);
 
1241
  }
 
1242
  if (flip) df = -df;
 
1243
  smplf += df;
 
1244
  fprintf(stderr, "delta freq.=%2.3f smplf=%4.3f\n",
 
1245
        (double)df / 65536.0, (double)smplf / 65536.0);
 
1246
  tune_frequency(smplf);
 
1247
 
 
1248
  old_func = disp_func;
 
1249
  disp_func = NULL;
 
1250
  old_func (D_CPINIT | D_WDINIT | D_LDINIT);
 
1251
  old_func (D_ALLOWX);
 
1252
  disp_func = old_func;
 
1253
}
 
1254
 
 
1255
/*----------------------- FAX transmission --------------------------*/
 
1256
 
 
1257
void fax_tx_stop(int internal)
 
1258
{
 
1259
  fprintf(stderr,"stopping FAX-transmission\n");
 
1260
  if (internal)
 
1261
    mode_notify(fax_state);
 
1262
}
 
1263
 
 
1264
void fax_tx_start(int internal)
 
1265
{
 
1266
  fprintf(stderr,"transmitting image\n");
 
1267
  fax_state = FATX_TX;
 
1268
  fax_tx_func(D_WDINIT | D_LDINIT);
 
1269
  if (internal)
 
1270
    mode_notify(fax_state);
 
1271
}
 
1272
 
 
1273
void fax_tx_apta(int internal)
 
1274
{
 
1275
  fprintf(stderr,"transmitting APT-start\n");
 
1276
  transmit_apt(APTX_ISTART);
 
1277
  fax_state = FATX_APTA;
 
1278
  if (internal)
 
1279
    mode_notify(fax_state);
 
1280
}
 
1281
 
 
1282
void fax_tx_aptb(int internal)
 
1283
{
 
1284
  fprintf(stderr,"transmitting APT-stop\n");
 
1285
  transmit_apt(APTX_ISTOP);
 
1286
  fax_state = FATX_APTB;
 
1287
  if (internal)
 
1288
    mode_notify(fax_state);
 
1289
}
 
1290
 
 
1291
void fax_tx_phase(int internal)
 
1292
{
 
1293
  fprintf(stderr,"entering TX-phase-in mode\n");
 
1294
  transmit_phase(1);
 
1295
  fax_state = FATX_PHAS;
 
1296
  if (internal)
 
1297
    mode_notify(fax_state);
 
1298
}
 
1299
 
 
1300
int load_txfile(char *name)
 
1301
{
 
1302
  char line[80];
 
1303
  char lctab[256];
 
1304
  char *pline, *sp;
 
1305
  int ncols;
 
1306
  int color;
 
1307
  char *cp;
 
1308
  int i,j;
 
1309
 
 
1310
  if (timg_ptr)
 
1311
    free(timg_ptr);
 
1312
  if ((ftfile = fopen(name, "rb")) == NULL) {
 
1313
    perror("open_txfile");
 
1314
    return -1;
 
1315
  }
 
1316
  if (fgets(line, 79, ftfile) == NULL) {
 
1317
    perror("read_format");
 
1318
    return -1;
 
1319
  }
 
1320
  if (!strcmp(line, "P5\n"))
 
1321
    color = 0;
 
1322
  else if (!strcmp(line, "P6\n"))
 
1323
    color = 1;
 
1324
  else
 
1325
    return -2; /* unrecognized format */
 
1326
  if (color)
 
1327
    return -3; /* not yet supported */
 
1328
  do {
 
1329
    if (fgets(line, 79, ftfile) == NULL) {
 
1330
      perror("read_header");
 
1331
      return -1;
 
1332
    }
 
1333
  } while (*line == '#');
 
1334
  twidth = atoi(line);
 
1335
  if (fgets(line, 79, ftfile) == NULL) {
 
1336
    perror("read_header");
 
1337
    return -1;
 
1338
  }
 
1339
  theight = atoi(line);
 
1340
  if (fgets(line, 79, ftfile) == NULL) {
 
1341
    perror("read_header");
 
1342
    return -1;
 
1343
  }
 
1344
  timg_ptr = malloc(twidth*theight);
 
1345
  pline = malloc(twidth);
 
1346
  if (!(timg_ptr) || !(pline)) {
 
1347
    if (timg_ptr) free(timg_ptr);
 
1348
    if (pline) free(pline);
 
1349
    perror("alloc_txmem");
 
1350
    return -4;
 
1351
  }
 
1352
  ncols = atoi(line) + 1;
 
1353
  if (ncols > 256)
 
1354
    return -3;
 
1355
  for (i=0; i<ncols; i++)
 
1356
    lctab[i] = (64 * i) / ncols;
 
1357
  cp = timg_ptr;
 
1358
  for (i=0; i<theight; i++) {
 
1359
    if (fread(pline, twidth, 1, ftfile) != 1) {
 
1360
      perror("read_pixmap");
 
1361
      free(timg_ptr);
 
1362
      free(pline);
 
1363
      return -5;
 
1364
    }
 
1365
    sp = pline;
 
1366
    for (j=0; j<twidth; j++)
 
1367
      *cp++ = lctab[*(unsigned char *)sp++];
 
1368
  }
 
1369
  free(pline);
 
1370
  fclose(ftfile);
 
1371
  return 0;
 
1372
}
 
1373
 
 
1374
/*
 
1375
 * Fax-transmission background-routine :
 
1376
 * This works a little different from the receiving-routine.
 
1377
 * Transmission-data is not stored in a core-space, it is
 
1378
 * transmitted directly out of the image-memory. Every function
 
1379
 * called here must keep track of the pointer in the decptr-space
 
1380
 * and give back control if the task is done or the pointer has reached
 
1381
 * the end of the buffer.
 
1382
 */
 
1383
#ifdef DSP_SELECT
 
1384
void fax_tx_backgnd(XtPointer client_data, int *source, XtInputId *xid)
 
1385
#else
 
1386
void fax_tx_backgnd(XtPointer client_data, XtIntervalId *xid)
 
1387
#endif
 
1388
{
 
1389
  int space;
 
1390
 
 
1391
  /* if we are in the phasing state, compute the phase-position */
 
1392
  if (fax_state == FATX_APTA)
 
1393
    transmit_apt(0);
 
1394
 
 
1395
  if (fax_state == FATX_PHAS)
 
1396
    transmit_phase(0);
 
1397
 
 
1398
  if (fax_state == FATX_TX)
 
1399
    fax_tx_func(0);
 
1400
 
 
1401
  if (fax_state == FATX_APTB)
 
1402
    transmit_apt(0);
 
1403
 
 
1404
#ifdef DSP_SELECT
 
1405
#else
 
1406
  /* add a new timeout to call this function again */
 
1407
/*
 
1408
  printf("adding new timeout\n");
 
1409
*/
 
1410
  chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
 
1411
#endif
 
1412
 
 
1413
  /* if disp_func is set, call that function (e.g. main FAX decoder loop) */
 
1414
  if ((disp_func) && !(disp_locked)) {
 
1415
/*
 
1416
    fprintf(stderr, "calling disp_func\n");
 
1417
*/
 
1418
    fax_tx_func(0);
 
1419
  }
 
1420
/*
 
1421
  fprintf(stderr, "transmitting data\n");
 
1422
*/
 
1423
  do_transmit();
 
1424
}
 
1425
 
 
1426
void transmit_fax_gray(int init)
 
1427
{
 
1428
  /* pointer to sample-point for current pixel and current start-of-line */
 
1429
  static char *timg_line, *timg_pix;
 
1430
  /* sample-values per line or per pixel-value, 16bit int, 16bit frac */
 
1431
  static unsigned inc_pix, inc_line, inc_p0;
 
1432
  /* current index to pixel or line in sample-array, 16bit int, 16bit frac */
 
1433
  static unsigned idx_pix, idx_line, idx_p0;
 
1434
  /* increment between actual and previous pixel/line position */
 
1435
  static unsigned ipix, iline;
 
1436
  /* pixel-in-line-position start/increment/end */
 
1437
  static int pixinit, pixinc, pixend;
 
1438
  /* line-in-image-position start/increment/end, max. line of XImage */
 
1439
  static int lineinit, lineinc, lineend, imgmax;
 
1440
  static int (*put_pix)(struct _XImage *, int, int, unsigned long);
 
1441
  /* bytes per line or per pixel, depends on direction (hor, vert, r2l, b2t) */
 
1442
  static int bytes_per_line, bytes_per_pixel;
 
1443
 
 
1444
  if (init & D_INITS) {
 
1445
    /* smpl_line is the number of core_dta points per line << 16 */
 
1446
    smpl_line = 60.0 / lpm * smplf;
 
1447
    if (vertical) {
 
1448
      inc_pix = smpl_line / theight;
 
1449
      inc_line = (int)(ixoc * PI * 65536.0 / theight); 
 
1450
      imgmax = DEFWIDTH;
 
1451
      put_pix = verimag->f.put_pixel;
 
1452
      bytes_per_pixel = twidth;
 
1453
      bytes_per_line = 1;
 
1454
    } else {
 
1455
      inc_pix = smpl_line / twidth;
 
1456
      inc_line = (int)(ixoc * PI * 65536.0 / twidth); 
 
1457
      imgmax = DEFHEIGHT;
 
1458
      put_pix = horimag->f.put_pixel;
 
1459
      bytes_per_pixel = 1;
 
1460
      bytes_per_line = twidth;
 
1461
    }
 
1462
    if (!(vertical) && (right2left)) {
 
1463
      pixinit = twidth - 1;
 
1464
      pixinc = -1;
 
1465
      pixend = -1;
 
1466
      bytes_per_pixel = -bytes_per_pixel;
 
1467
    } else
 
1468
    if ((vertical) && (bot2top)) {
 
1469
      pixinit = theight - 1;
 
1470
      pixinc = -1;
 
1471
      pixend = -1;
 
1472
      bytes_per_pixel = -bytes_per_pixel;
 
1473
    } else {
 
1474
      pixinit = 0;
 
1475
      pixinc = 1;
 
1476
      pixend = (vertical) ? theight : twidth;
 
1477
    }
 
1478
    /* initialize the line-advance variables and pointers */
 
1479
    if (!(vertical) && (bot2top)) {
 
1480
        lineinit = theight - 1;
 
1481
        lineinc = -1;
 
1482
        lineend = -1;
 
1483
        bytes_per_line = -bytes_per_line;
 
1484
    } else
 
1485
    if ((vertical) && (right2left)) {
 
1486
        lineinit = twidth - 1;
 
1487
        lineinc = -1;
 
1488
        lineend = -1;
 
1489
        bytes_per_line = -bytes_per_line;
 
1490
    } else {
 
1491
        lineinit = 0;
 
1492
        lineinc = 1;
 
1493
        lineend = (vertical) ? twidth : theight;
 
1494
    }
 
1495
  }
 
1496
 
 
1497
 
 
1498
  if (init) {
 
1499
    timg_line = timg_ptr;
 
1500
    /* twidth, theight, timg_ptr */
 
1501
    if (vertical) {
 
1502
      inc_pix = 65536.0 * theight * lpm / ((60.0/65536.0) * smplf);
 
1503
      inc_line = 65536.0 * theight / (PI * ixoc);
 
1504
    } else {
 
1505
      inc_pix = 65536.0 * twidth * lpm / ((60.0/65536.0) * smplf);
 
1506
      inc_line = 65536.0 * twidth / (PI * ixoc);
 
1507
    }
 
1508
      if (right2left) {
 
1509
        pixinc = -1;
 
1510
        timg_line += (twidth - 1);
 
1511
      } else {
 
1512
        pixinc = 1;
 
1513
      }
 
1514
      if (bot2top) {
 
1515
        pixinc = -twidth;
 
1516
        timg_line += (theight - 1) * twidth;
 
1517
      } else {
 
1518
        pixinc = twidth;
 
1519
      }
 
1520
      timg_pix = timg_line;
 
1521
    inc_p0 = 0;
 
1522
    return;
 
1523
  }
 
1524
  while (mod_ptr < mod_end) {
 
1525
    *mod_ptr++ = *timg_pix;
 
1526
 
 
1527
    pixpos += pixinc;
 
1528
    if (pixpos == pixend) {
 
1529
      pixpos = pixinit;
 
1530
      linepos += lineinc;
 
1531
      if (linepos == lineend) {
 
1532
        /* we have transmitted the entire picture ! */
 
1533
        break;
 
1534
      }
 
1535
      idx_line += inc_line;
 
1536
      iline = (idx_line >> 16) & 0xffff;
 
1537
      idx_line &= 0xffff;
 
1538
      timg_pix += bytes_per_pixel;
 
1539
      timg_pix += iline * twidth; /* twidth == bytes_per_line */
 
1540
      continue; /* jump over stuff below */
 
1541
    }
 
1542
    idx_pix += inc_pix;
 
1543
    ipix = (idx_pix >> 16) & 0xffff;
 
1544
    idx_pix &= 0xffff;
 
1545
    timg_pix += ipix * bytes_per_pixel;
 
1546
  }
 
1547
  fax_tx_aptb(1);
 
1548
}
 
1549
 
 
1550
/*
 
1551
 * transmit an APT-tone. This function returns if either the pointer to
 
1552
 * decptr reaches the end of the buffer or the duration is reached.
 
1553
 * init can have the following values :
 
1554
 * APTX_ISTART: initialize for aptstart-frequency
 
1555
 * APTX_ISTOP:  initialize for apt stop-frequency
 
1556
 * 0:           start/continue transmission
 
1557
 */
 
1558
void transmit_apt(int init)
 
1559
{
 
1560
  XtInputMask msk;
 
1561
  static int acc = 0;
 
1562
  static int ap_inc;
 
1563
  static int dur;
 
1564
 
 
1565
  if (init == APTX_ISTART) {
 
1566
    ap_inc = 4.294967296e6 * aptstart / (double) smplf;
 
1567
    dur = (smplf >> 16) * aptdur / 1000;
 
1568
    return;
 
1569
  } else if (init == APTX_ISTOP) {
 
1570
    ap_inc = 4.294967296e6 * aptstop / (double) smplf;
 
1571
    dur = (smplf >> 16) * aptdur / 1000;
 
1572
    return;
 
1573
  }
 
1574
  while ((dur > 0) && (mod_ptr < mod_end)) {
 
1575
      acc += ap_inc;
 
1576
      if (acc & 0x8000)
 
1577
        *mod_ptr = dmaxval;
 
1578
      else
 
1579
        *mod_ptr = 0;
 
1580
      mod_ptr++;
 
1581
      dur--;
 
1582
  }
 
1583
  if (mod_ptr >= mod_end)
 
1584
    mod_ptr = demod_ptr;
 
1585
  if (dur <= 0) {
 
1586
      if (fax_state == FATX_APTA)
 
1587
        fax_tx_phase(1);
 
1588
      else
 
1589
        fax_tx_stop(1);
 
1590
  }
 
1591
}
 
1592
 
 
1593
/*
 
1594
 * transmit the phase-in signal for the image, which consists of 95% black
 
1595
 * and 5% white (or inverted if invphase is set). These 5% have to appear
 
1596
 * as one half to both the left and right margin of the image. The phase
 
1597
 * where we start is not important, but where we stop and give control
 
1598
 * to the function transmitting the contents of the loaded image.
 
1599
 * tx_phlines determines the number of lines for phasing, after which
 
1600
 * a line with 100% white is intersected to start the receiver.
 
1601
 * if init is set, variables are initialized and the function returns.
 
1602
 */
 
1603
void transmit_phase(int init)
 
1604
{
 
1605
  static int inc_pix;
 
1606
  static int idx_pix;
 
1607
  static int idx_min, idx_max;
 
1608
  static int txlines;
 
1609
 
 
1610
  if (init) {
 
1611
    inc_pix = lpm * (double) smplf / 60;
 
1612
    idx_min = 1638;
 
1613
    idx_max = 63807;
 
1614
    idx_pix = 0x8000;
 
1615
    txlines = tx_phlines + 1;
 
1616
    return;
 
1617
  }
 
1618
  while ((txlines >= 0) && (mod_ptr < mod_end)) {
 
1619
    idx_pix += inc_pix;
 
1620
    if (idx_pix > 63807 || idx_pix < 1638)
 
1621
     *mod_ptr = (invphase ? 0 : dmaxval);
 
1622
    else
 
1623
     *mod_ptr = (invphase ? dmaxval : 0);
 
1624
    mod_ptr++;
 
1625
    if (idx_pix > 0xffff)
 
1626
      txlines--;
 
1627
    idx_pix &= 0xffff;
 
1628
  }
 
1629
  if (mod_ptr >= mod_end)
 
1630
    mod_ptr = demod_ptr;
 
1631
  if (txlines <= 0)
 
1632
    fax_tx_start(1);
 
1633
}