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