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