2
ACfax - Fax reception with X11-interface for amateur radio
3
Copyright (C) 1995-1998 Andreas Czechanowski, DL4SDC
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.
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.
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.
19
andreas.czechanowski@ins.uni-stuttgart.de
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.
34
#include <X11/Intrinsic.h>
36
#include "mod_demod.h"
38
#include "fax_funcs.h"
40
/* some variables that are allowed to be global */
41
int lpm; /* lines per minute */
42
int ixoc; /* number of pixels of one scan-line / PI */
43
int devi; /* deviation in Hz (+/- of middle) */
44
int mod_mode; /* can be MOD_FM or MOD_AM */
45
int aptstart; /* possible APT start values */
46
int aptstop; /* possible APT stop values */
47
int aptdur; /* apt duration in millisecs (for transmitting) */
48
int vertical; /* vertical or horizontal line direction */
49
int right2left; /* boolean indicating reverse line writing direction */
50
int bot2top; /* boolean indicating reverse line stacking direction */
51
int invphase; /* polarity of phase-in-signal to use */
52
int invimage; /* inverse colormap usage */
53
/* and the private variables */
54
int fax_inited = 0; /* if fax_init was called */
55
unsigned canwid; /* width of the Pixmap to draw in */
56
unsigned canhei; /* height of the Pixmap */
57
int sxpos, sypos; /* current coordinates of received/xmitted data */
58
int pixpos, linepos; /* current coordinates of received/xmitted data */
59
int imline; /* currently processed line of XImage */
60
void (*update_area)(XImage *, int, int, int, int, unsigned, unsigned);
61
/* called to copy XImage to Pixmap and update the window-area required */
62
void (*mode_notify)(int); /* notifies main program of changes of fax_state */
63
int mcolor; /* color-mode selected */
64
int dmaxval; /* number of usable grayscale-values - 1 */
65
int compval; /* comparator value for APT-counter */
66
int flip; /* flipping of green and blue parts of the colormap */
67
int rotate; /* rotation of the colormap */
68
int fax_state; /* one of FAX_APT, FAX_PHAS or FAX_RX */
69
char *core_dta; /* storage for raw demodulated data (accumulating) */
70
char *core_start; /* start of core for image-processing */
71
char *core_wptr; /* pointer to next written element in core_dta */
72
char *core_maxptr; /* pointer beyond the last element in core_dta */
73
void (*disp_func)(int); /* pointer to function displaying the data-stream */
74
int (*save_func)(int, int);
75
/* pointer to function saving image to file */
76
void (*fax_tx_func)(int); /* pointer to function transmitting image */
77
int disp_locked; /* flag indicating that disp_func should not be called
78
from fax_rx_backgnd */
79
int save_locked; /* same as above for save_func */
80
void (*apt_notify)(int); /* pointer to function evaluating APT frequency */
81
unsigned smplf; /* number of samples per second << 16 */
82
unsigned smpl_line; /* number of samples per line << 16 */
83
unsigned hsmpl_sec; /* half the number of samples per second */
84
int aptncmax; /* maximum "empty" points in an APT-line */
85
int phstate = 0; /* state (0=waiting, 1=active) of phase-finder */
86
int phlines; /* number of recognized phase-lines */
87
unsigned hsmpl_line; /* half the number of samples per line */
88
int phposa[24]; /* phase position A (middle of line) */
89
int phposb[24]; /* phase position B (edges of line) */
90
int phsdir[24]; /* phase direction (beginning or end of line) */
91
int phaseavg; /* average phase position calculated */
92
char *demod_ptr; /* pointer to raw demodulated data */
93
int demod_cnt; /* number of decoded points per call */
94
char *mod_ptr; /* pointer to raw data being modulated */
95
char *mod_end; /* pointer to first byte behind end of modulator-space */
96
FILE *fsfile; /* file pointer of current save-file */
97
char faxsavename[256]; /* current name of save-file */
98
char *saveline; /* storage for 1 image-line in save_func */
99
XtAppContext mainapp; /* main app.context (needed for interv.timer) */
100
XtIntervalId chstime; /* for the repetitive called background function */
101
XtInputId dspxid = 0; /* for the background function when using select() */
102
XEvent event; /* event needed to form the XtAppMainLoop */
103
unsigned twidth; /* width of transmitted image */
104
unsigned theight; /* height of transmitted image */
105
int tx_phlines; /* number of phase-in lines to be transmitted */
106
char *timg_ptr; /* array holding image to be transmitted (pixel oriented) */
107
FILE *ftfile; /* pointer to file-struct for transmission */
110
* init_fax initializes the "core"-space where the raw decoded data resides.
111
* This practice is not very nice to memory-limited systems, but has the
112
* advantage of being able to back up from nearly any setup-error (including
113
* wrong lpm, IOC, direction and color-mode but excluding tuning-errors)
117
if (fax_inited) return;
118
fprintf(stderr, "initializing FAX procedures and alloc'ing core-space\n");
122
mod_mode = MOD_FM | FIL_MIDL;
124
compval = dmaxval >> 1;
125
core_dta = malloc(CORESIZE);
126
core_start = core_dta;
127
core_wptr = core_dta;
128
core_maxptr = core_dta + COREMAX;
129
interface_init(&demod_ptr, &demod_cnt);
130
setup_mode(mod_mode, dmaxval, devi, &smplf);
131
hsmpl_sec = smplf >> 17;
132
aptncmax = hsmpl_sec / 25;
133
mod_end = demod_ptr + demod_cnt;
135
fprintf(stderr, "smplf = %08x (16.16), demod_cnt = %d\n", smplf, demod_cnt);
136
disp_func = decode_fax_gray;
137
fax_tx_func = transmit_fax_gray;
138
save_func = save_fax_gray;
141
apt_notify = apt_control;
142
chstime = (XtIntervalId) 0;
150
/* exit_fax frees the core_dta space, so that other program-parts may
151
allocate memory without having a dead-space overhead.
155
if (!fax_inited) return;
161
* setup_fax sets up all the variables for FAX-reception and transmission.
162
* s_lpm : lines per minute (no change if set to 0)
163
* s_ixoc: IOC to use (pixels per line = PI * IOC) (no change if set to 0)
164
* mode : fax-specific mode setings such as writing direction and order,
165
* phase-in polarity and grayscale or color-mode
166
* s_devi: deviation to use for FM (no change if set to 0)
167
* s_modem : (de-)modulator-specific settings as filter to use, AM or FM
169
void setup_fax(int s_lpm, int s_ixoc, unsigned mode,
170
Widget toplevel, unsigned width, unsigned height,
171
int s_devi, unsigned s_modem)
174
unsigned filter, mmode;
175
void (*old_func)(int);
177
/* be sure initialisation is done */
180
mainapp = XtWidgetToApplicationContext(toplevel);
181
/* if size is given or has changed, re-create X-images */
182
if ((width) || (height)) {
187
create_images(toplevel, canwid, canhei);
189
/* check if the (de-)modulator needs readjustment */
190
filter = s_modem & FIL_MASK;
191
mmode = s_modem & MOD_BITS;
192
if ((filter) || (mmode) || (s_devi)) {
193
fprintf(stderr, "setting filter & mmode = 0x%04x\n", (filter | mmode));
195
if (s_devi < 100) s_devi = 100;
196
if (s_devi > 1200) s_devi = 1200;
199
setup_mode((filter | mmode), dmaxval, s_devi, &smplf);
200
hsmpl_sec = smplf >> 17;
201
aptncmax = hsmpl_sec / 25;
204
mod_mode = (~FIL_MASK & mod_mode) | filter;
208
mod_mode = (~MOD_BITS & mod_mode) | mmode;
213
if (s_lpm < 60) s_lpm = 60;
214
if (s_lpm > 500) s_lpm = 500;
216
fprintf(stderr, "changing lpm to %d\n", lpm);
219
if (s_ixoc < 60) s_ixoc = 60;
220
if (s_ixoc > 600) s_ixoc = 600;
222
fprintf(stderr, "changing ioc to %d\n", ixoc);
224
if ((id = mode & FAX_POL)) {
225
if (id == FAX_CNOR) {
230
fprintf(stderr, "setting invimage mode to %d\n", invimage);
232
if ((id = mode & FAX_CFLS)) {
233
if (id == FAX_CUNFL) {
238
fprintf(stderr, "setting color-flip to %d\n", flip);
240
if ((id = mode & FAX_CROTS)) {
252
fprintf(stderr, "setting color-rotation to %d\n", rotate);
254
if ((id = mode & FAX_DIR)) {
255
if (id & FAX_TOP2BOT)
257
else if (id & FAX_BOT2TOP)
260
if (id & FAX_LEF2RIG)
262
else if (id & FAX_RIG2LEF)
265
fprintf(stderr, "changing direction to h=%d, v=%d\n", right2left, bot2top);
267
if ((id = mode & FAX_ROT)) {
273
fprintf(stderr, "selecting %s direction\n",
274
(vertical) ? "vertical" : "horizontal");
276
if ((id = mode & FAX_PHS)) {
277
if (id == FAX_PWHT) {
282
fprintf(stderr, "phase inversion mode = %d\n", invphase);
284
if ((id = mode & FAX_CMODE)) {
293
fprintf(stderr, "receive mode is %s\n", (mcolor) ? "color" : "grayscale");
295
/* now, all modifications to variables are done.
296
some recomputations are to be done dependant on what has changed... */
297
if (mode & FAX_CMODS)
299
fill_cmap_col(invimage, flip, rotate);
301
fill_cmap_gray(invimage);
303
if ((mode & (FAX_DIR | FAX_ROT | FAX_CMODE | FAX_CMODS))
304
|| (s_ixoc) || (s_lpm) || (width) || (height)
305
|| (s_modem & MOD_BITS)) {
307
disp_func = decode_fax_gray;
308
save_func = save_fax_gray;
310
disp_func = decode_fax_gray;
311
save_func = save_fax_gray;
313
/* recomputations are done in disp_func() */
314
fprintf(stderr, "initializing disp_func\n");
315
disp_func(D_CPINIT | D_WDINIT | D_LDINIT);
316
/* now call function to re-create picture */
317
#if stillneeded /* the disp_func should lock itself */
318
old_func = disp_func;
320
fprintf(stderr, "calling disp_func to re-display image\n");
322
disp_func = old_func;
324
fprintf(stderr, "calling disp_func to re-display image\n");
328
if ((mmode) && (dspxid != 0))
330
/* re-initiate data reception, because changing the modulation mode
331
* (and thus changing the sample rate) requires the data stream to
332
* stop. [Later, this should be RX or TX depending on what we do] */
333
fax_rx_backgnd((XtPointer) NULL, &dspfd, (XtInputId *) NULL);
337
/* enable FAX reception: set auto-initializing background function */
338
void receive_on(void)
341
if (chstime != (XtIntervalId) 0) return;
344
mode_notify(fax_state);
346
dspxid = XtAppAddInput(mainapp, dspfd, (XtPointer) XtInputReadMask,
347
fax_rx_backgnd, (XtPointer) NULL);
348
fprintf(stderr, "dspxid from XtAppAddInput is %ld\n", dspxid);
349
/* initiate the reading of data. Once started, it is called by
350
* XtAppMainLoop() which uses select() to listen on dspfd. */
351
fax_rx_backgnd((XtPointer) NULL, &dspfd, &dspxid);
353
chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
357
void receive_off(void)
360
XtRemoveInput(dspxid);
361
dspxid = (XtInputId) 0;
363
XtRemoveTimeOut(chstime);
366
chstime = (XtIntervalId) 0;
370
/* this is the reception routine triggered upon input from DSP device */
371
void fax_rx_backgnd(XtPointer client_data, int *source, XtInputId *xid)
373
/* this is the reception routine which calls itself after 250ms */
374
void fax_rx_backgnd(XtPointer client_data, XtIntervalId *xid)
382
core_wptr = core_dta;
386
fprintf(stderr, "receiving data\n");
388
/* get the input samples and demodulate the input data stream */
391
/* update the signal-level scrollbar display */
392
set_sigdisplay((double)rx_level / 255.0);
394
/* always watch for APT frequencies */
396
fprintf(stderr, "decoding APT\n");
400
/* if we are in the phasing state, compute the phase-position */
401
if (fax_state == FAX_PHAS)
404
/* copy the data into the core_dta array and advance the write-pointer */
405
if (fax_state == FAX_RX) {
406
space = core_maxptr - core_wptr;
407
if (space > demod_cnt)
409
memcpy(core_wptr, demod_ptr, space);
414
/* we don't need to retrigger ourself - do nothing */
416
/* add a new timeout to call this function again */
418
printf("adding new timeout\n");
420
chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
423
/* if disp_func is set, call that function (e.g. main FAX decoder loop) */
424
if ((disp_func) && !(disp_locked)) {
426
fprintf(stderr, "calling disp_func\n");
430
/* if save_func is set (saving of received image enabled), call function */
431
if ((save_func) && !(save_locked)) {
433
fprintf(stderr, "calling save_func\n");
435
save_func(F_DOSAVE, 0);
440
* grayscale FAX decoding main routine.
441
* init is used to control the behavior and initialize some internal
442
* variables. It is bit-wise coded as follows :
443
* D_CPINIT : initialize read-pointer to start of core-buffer
444
* D_WDINIT : initialize x-position to the start-value
445
* D_LDINIT : initialize y-position to the start-value
446
* D_ALLOWX : periodically call XtAppProcessEvent during processing
447
* (requires that this function is NOT called from fax_rx_backgnd !)
449
void decode_fax_gray(int init)
455
static char *imptinit;
459
/* pointer to sample-point for current pixel and current start-of-line */
460
static char *core_line, *core_pix;
461
/* sample-values per line or per pixel-value, 16bit int, 16bit frac */
462
static unsigned inc_pix, inc_line;
463
/* current index to pixel or line in sample-array, 16bit int, 16bit frac */
464
static unsigned idx_pix, idx_line, idx_p0;
465
/* increment between actual and previous pixel/line position */
466
static unsigned ipix, iline;
467
/* pixel-in-line-position start/increment/end */
468
static int pixinit, pixinc, pixend;
469
/* line-in-image-position start/increment/end, max. line of XImage */
470
static int lineinit, lineinc, lineend, imgmax;
471
static int (*put_pix)(struct _XImage *, int, int, unsigned long);
473
if (init & D_INITS) {
474
/* smpl_line is the number of core_dta points per line << 16 */
475
smpl_line = 60.0 / lpm * smplf;
477
inc_pix = smpl_line / canhei;
478
inc_line = (int)(ixoc * PI * 65536.0 / canhei);
480
put_pix = verimag->f.put_pixel;
482
inc_pix = smpl_line / canwid;
483
inc_line = (int)(ixoc * PI * 65536.0 / canwid);
485
put_pix = horimag->f.put_pixel;
487
if (!(vertical) && (right2left)) {
488
pixinit = canwid - 1;
492
imptinit = horimag->data + canwid - 1;
496
if ((vertical) && (bot2top)) {
497
pixinit = canhei - 1;
501
imptinit = verimag->data + (canhei - 1) * verimag->bytes_per_line;
502
impinc = -verimag->bytes_per_line;
507
pixend = (vertical) ? canhei : canwid;
509
imptinit = (vertical) ? verimag->data : horimag->data;
510
impinc = (vertical) ? verimag->bytes_per_line : 1;
513
/* initialize the line-advance variables and pointers */
514
if (!(vertical) && (bot2top)) {
515
lineinit = canhei - DEFHEIGHT;
519
if ((vertical) && (right2left)) {
520
lineinit = canwid - DEFWIDTH;
526
lineend = (vertical) ? canwid : canhei;
529
if (init & D_WDINIT) {
533
if (init & D_LDINIT) {
535
if ((!(vertical) && (bot2top)) || ((vertical) && (right2left)))
541
if ((init & D_LDINIT) || (init & D_WDINIT)) {
542
imptr = imptinit + impinc * pixpos;
546
imptr += horimag->bytes_per_line * imline;
550
if (init & D_CPINIT) {
551
/* initialize the fractional index pointers */
552
idx_pix = idx_line = idx_p0 = 0;
553
core_pix = core_line = core_start;
556
fprintf(stderr,"initialisation done :\n"
557
"pixinit = %d, pixinc = %d, pixend = %d\n"
558
"lineinit = %d, lineinc = %d, lineend = %d\n"
559
"imline = %d, imgmax = %d\n",
560
pixinit, pixinc, pixend,
561
lineinit, lineinc, lineend,
567
if (init & D_ALLOWX) {
568
printf("redrawing from %d, %d, corepos = %d\n", pixpos, linepos, core_pix - core_dta);
572
/* if it is better to wait for more data, cancel function and wait
573
until it is called next time */
574
if (core_pix >= core_wptr)
577
/* enter a new brightness-value (0..63) into core_dta */
580
*imptr = coltab[*(unsigned char *)core_pix];
584
put_pix(verimag, imline, pixpos, coltab[*(unsigned char *)core_pix]);
586
put_pix(horimag, pixpos, imline, coltab[*(unsigned char *)core_pix]);
589
/* shift the x-position, and if we have reached the end... */
591
if (pixpos == pixend) {
592
/* re-start from left border */
594
/* now we have one more complete line, copy it from core_dta to the
595
horimag (an Ximage). Use fast methode by advancing pointers */
597
/* check if we wave filled up all lines of horimag, or if we just
598
have got as many lines that we can complete the picture. */
600
if ((imline == imgmax) || (imline < 0) || (linepos + imline == lineend)) {
601
while ((init & D_ALLOWX) && ((msk = XtAppPending(mainapp)))) {
602
XtAppProcessEvent(mainapp, msk);
606
update_area(verimag, 0, 0, linepos, 0, (DEFWIDTH-1) - imline, canhei);
608
update_area(verimag, 0, 0, linepos, 0, imline, canhei);
612
update_area(horimag, 0, 0, 0, linepos, canwid, (DEFHEIGHT-1) - imline);
614
update_area(horimag, 0, 0, 0, linepos, canwid, imline);
616
if (((vertical) && (right2left)) || (!(vertical) && (bot2top))) {
624
if (linepos >= lineend)
631
imptr = imptinit + imline;
633
imptr = imptinit + horimag->bytes_per_line * imline;
636
idx_line += inc_line;
637
iline = (idx_line >> 16) & 0xffff;
639
core_line += iline * ((smpl_line >> 16) & 0xffff);
641
/* we must also initialize the pixel-counters here ! */
642
idx_p0 += iline * (smpl_line & 0xffff);
643
core_line += (idx_p0 >> 16) & 0xffff;
644
core_pix = core_line;
649
/* jump over the stuff below... */
652
/* shift the sample-point (16 bits integer, 16 bits fractional part) */
654
ipix = (idx_pix >> 16) & 0xffff;
658
if (init & D_FLUSHIMG) {
661
update_area(verimag, 0, 0, linepos, 0, (DEFWIDTH-1) - imline, canhei);
663
update_area(verimag, 0, 0, linepos, 0, imline, canhei);
667
update_area(horimag, 0, 0, 0, linepos, canwid, (DEFHEIGHT-1) - imline);
669
update_area(horimag, 0, 0, 0, linepos, canwid, imline);
676
* this function should be used by the main program to initiate saving
677
* of an image. If name is not given, it is constructed of date and time.
679
int save_faxfile(char *name, int width)
682
char date[16]; /* string to build date for automatic savefile-name */
684
/* check if save-file is already open */
687
/* if no name is given, generate autosave-filename from date and time */
689
strcpy(faxsavename, name);
692
strftime(date, 14, "%m.%d-%H:%M", localtime(&tp));
693
sprintf(faxsavename, "%s/faxsave_%s.pgm", FAX_SAVEDIR, date);
695
return save_func(F_OPEN, width);
698
/* properly close the save-file */
699
void close_faxsave(void)
703
save_func(F_GETDIM, 0);
704
save_func(F_DOSAVE, 0);
705
save_func(F_CLOSE, 0);
709
* fax-image saving function, writes grayscale ppm-images (pgm).
710
* The image cannot be rotated, only flipped in writing-direction.
711
* init defines the action to be done :
712
* F_DOSAVE : save image if file is opened, close when completed
713
* F_OPEN : open file, faxsavename contains the name and width the width
714
* of the image. If width is not given, the best resolution is taken
716
* F_CLOSE : close file and adjust data in header to actual values
717
* F_GETDIM : get dimensions and parameters of image into internal variables
718
* the filename must previously be put into faxsavename.
720
int save_fax_gray(int init, int width)
723
/* width and height of saved image */
724
static unsigned swidth, sheight;
725
static char *ldptr, *ldpinit, *ldpend;
727
/* end of picture in core-space */
728
static char *save_wptr = NULL;
729
/* pointer to sample-point for current pixel and current start-of-line */
730
static char *core_line, *core_pix;
731
/* sample-values per line or per pixel-value, 16bit int, 16bit frac */
732
static unsigned inc_pix, inc_line;
733
/* current index to pixel or line in sample-array, 16bit int, 16bit frac */
734
static unsigned idx_pix, idx_line, idx_p0;
735
/* increment between actual and previous pixel/line position */
736
static unsigned ipix, iline;
737
/* pixel-in-line-position start/increment/end */
739
static int pixinit, pixinc, pixend;
741
/* line-in-image-position start/increment/end, max. line of XImage */
743
static int lineinit, lineinc, lineend, imgmax;
745
/* whether the writing-direction must be reversed */
749
if (init == F_OPEN) {
750
/* close "old" file first */
752
save_fax_gray(F_CLOSE, 0);
756
swidth = (ixoc * PI) + 0.5;
757
fsfile = fopen(faxsavename, "wb");
761
fprintf(stderr, "save file \"%s\", %d pix/line\n", faxsavename, swidth);
762
fputs("P5\nxxxxx\nyyyyy\n63\n", fsfile);
763
/* allocate space for the one line */
764
saveline = malloc(swidth + 4);
765
/* do not initialize too much here, the user may change parameters
766
of the picture while receiving... */
769
} else if (init == F_CLOSE) {
771
return SAVE_OK; /* no save-file open, doesn't matter */
772
fprintf(stderr,"closing savefile\n");
776
fprintf(fsfile, "P5\n%05u\n%05u\n", swidth, sheight);
777
fseek(fsfile, pos, SEEK_SET);
784
} else if (init == F_GETDIM) {
786
return SAVE_NFILE; /* no save-file open, can't get dimensions */
787
/* now initialize all the variables... */
788
fprintf(stderr, "getting image settings...");
789
inc_pix = smpl_line / swidth;
790
inc_line = (int)(ixoc * PI * 65536.0 / swidth);
791
idx_pix = idx_line = idx_p0 = 0;
792
core_pix = core_line = core_start;
793
save_wptr = core_wptr;
795
flip = (vertical) ? 1 : 0;
796
if (bot2top) flip ^= 1;
797
if (right2left) flip ^= 1;
799
ldpinit = saveline + (swidth - 1);
801
ldpend = saveline - 1;
805
ldpend = saveline + swidth;
812
/* no open save-file, or variables not initialized, so return */
813
if (!(fsfile) || !(save_wptr)) return SAVE_NFILE;
815
fprintf(stderr,"saving image...");
816
while (core_pix < save_wptr) {
818
*ldptr = dmaxval - *(unsigned char *)core_pix;
820
*ldptr = *(unsigned char *)core_pix;
822
if (ldptr == ldpend) {
825
fwrite(saveline, swidth, 1, fsfile);
827
while ((msk = XtAppPending(mainapp))) {
828
XtAppProcessEvent(mainapp, msk);
830
idx_line += inc_line;
831
iline = (idx_line >> 16) & 0xffff;
833
core_line += iline * ((smpl_line >> 16) & 0xffff);
835
/* we must also initialize the pixel-counters here ! */
836
idx_p0 += iline * (smpl_line & 0xffff);
837
core_line += (idx_p0 >> 16) & 0xffff;
838
core_pix = core_line;
843
/* jump over the stuff below... */
847
ipix = (idx_pix >> 16) & 0xffff;
851
fprintf(stderr,"done.\n");
856
/* called when save-function has terminated writing */
857
void faxsave_complete(int init)
859
/* this makes save_func call itself recursively, but should not hurt */
860
save_func(F_CLOSE, 0);
864
* wait for a phasing signal, keep track of the phase-pulses, and preset
865
* core_start on end of the phase_signal. This is done by correlating the
866
* digitized gray-values (reduced to 1 or 0) with two sawtooth-signals,
867
* each with a periode of one scan line, and one of them shifted by a
868
* half scan-line against the other. This lets us find the position of
869
* the phase-pulse relative to our scan-line. Lines are recognized as
870
* phase-in-lines when they contain at most 3/32 and at least 1/32 of values
871
* that are above (or below for inverse phase) the middle of the gray-scale.
873
void sync_phase(int init)
875
/* run counters, count pixels per line (16bit int, 16bit frac) */
876
static int phsarc, phsbrc;
877
/* accumulators for the integration */
878
static int phsaacc = 0, phsbacc = 0;
879
/* these are counted up until limit to form the sawtooth-signal */
880
static int phsainc, phsbinc;
881
/* number of sample-points processed */
882
static int npoints = 0;
883
/* number of points having the right level (black) for a sync pulse */
884
static int nphpts = 0;
885
/* minimum/maximum number of black points per line that must be present */
886
static int minphpts, maxphpts;
887
static char done = 0;
896
hsmpl_line = smpl_line >> 17;
897
phsaacc = phsbacc = 0;
899
phsbrc = smpl_line >> 1;
900
phsainc = - hsmpl_line;
902
minphpts = (smpl_line >> 16) >> 5;
903
maxphpts = minphpts * 3;
907
core_wptr = core_dta;
908
core_start = core_dta;
909
fprintf(stderr, "initialized sync-phase-detector\n");
914
if ((!(invphase) && *dtaptr > compval) ||
915
((invphase) && *dtaptr < compval)) {
927
done = 1; /* this indicates the end-of-line */
929
phsainc = - hsmpl_line;
934
phsbinc = - hsmpl_line;
937
#if (DEBUG & DBG_SYN)
938
fprintf(stderr, "got line with %d of %d points phase-value\n",
941
/* check if it was probably a phase-in line */
942
if (nphpts < maxphpts && nphpts > minphpts) {
944
/* use the accumulator with the lower absolute-value */
945
if (abs(phsaacc) < abs(phsbacc)) {
946
i = phsaacc / nphpts;
947
#if (DEBUG & DBG_SYN)
948
fprintf(stderr, "sync line %d: A=%d\n", phlines, i);
952
phsdir[phlines] = 1; /* left half */
954
phsdir[phlines] = 0; /* right half */
956
i = phsbacc / nphpts;
957
#if (DEBUG & DBG_SYN)
958
fprintf(stderr, "sync line %d: B=%d\n", phlines, i);
962
phsdir[phlines] = 2; /* right half */
964
phsdir[phlines] = 3; /* left half */
966
if (phstate == 0) { /* first sync line */
968
} else if (phstate == 1) { /* any sync line */
971
} else { /* phlines >= 24 */
972
/* ignore any further sync-lines... */
975
/* no sync line, we are still waiting for one or they have passed */
977
/* no sync line yet - just wait ?! */
978
} else if (phstate == 1) {
979
/* now begin to compute the ultimate sync-position */
981
/* count the lines in the left half */
982
for (i=0; i<phlines; i++) {
983
if (phsdir[i] & 1) j++;
986
if (j > (phlines >> 1)) { /* more points in the left half */
987
#if (DEBUG & DBG_SYN)
988
fprintf(stderr, "calculating for left half...\n");
990
for (i=0; i<phlines; i++)
992
phaseavg += phposb[i] - hsmpl_line;
994
phaseavg += phposa[i];
995
} else { /* more points in the right half */
996
#if (DEBUG & DBG_SYN)
997
fprintf(stderr, "calculating for right half...\n");
999
for (i=0; i<phlines; i++)
1001
phaseavg += phposb[i] + hsmpl_line;
1003
phaseavg += phposa[i];
1005
phaseavg /= phlines;
1006
phaseavg += hsmpl_line;
1007
#if (DEBUG & DBG_SYN)
1008
fprintf(stderr, "phase average = %d\n", phaseavg);
1010
/* now prepare the core_start pointer for reception */
1011
/* calculate difference from sync-pos to end of line */
1012
j = (smpl_line >> 16);
1013
i = demod_cnt - pcnt + phaseavg;
1016
/* start decoding at the beginning of the core */
1017
core_wptr = core_dta;
1018
core_start = core_dta + i;
1019
/* now enter the real reception mode. When returning into the
1020
fax_rx_backgnd, fax_state is set to FAX_RX so that the data
1021
we just processed can also be used for the picture. */
1023
/* no more data to process */
1026
} /* if (sync_line_detected) */
1027
/* re-initialize the both accumulators and sample-point counters */
1034
} /* while (pcnt > 0) */
1038
* calculate the APT frequency by counting low->high->low transitions.
1039
* not very nice, but it works :-S . This funcion always computes the
1040
* APT for 0.5 seconds, independant from demod_cnt, which can be very
1041
* high on systems that use a large block-size for the audio-devide.
1042
* After each calculation, apt_notify() is called with the frequency as
1045
void decode_apt(int dummy)
1047
/* how many transitions (half-waves) we have counted */
1048
static int apthws = 0;
1049
/* how many consecutive points were on one side of the comparator-value */
1050
static int aptncact = 0;
1051
/* the phase (black or white) we processed last time */
1053
static int npoints = 0;
1059
/* If we have to start with the "black" phase, do it before the main-loop
1060
starts. This prevents us from ugly goto's (shudder) */
1064
if (++npoints >= hsmpl_sec) {
1069
if (*(unsigned char *)dtaptr++ <= compval) {
1070
if (aptncact > aptncmax)
1083
if (++npoints >= hsmpl_sec) {
1084
#if (DEBUG & DBG_APT)
1085
fprintf(stderr,"APT freq. pos = %d\n", apthws);
1091
if (*(unsigned char *)dtaptr++ > compval) {
1092
if (aptncact > aptncmax)
1103
if (++npoints >= hsmpl_sec) {
1104
#if (DEBUG & DBG_APT)
1105
fprintf(stderr,"APT freq. neg = %d\n", apthws);
1111
if (*(unsigned char *)dtaptr++ <= compval) {
1112
if (aptncact > aptncmax)
1121
/* now mark the phase for the next call... */
1122
if (*(unsigned char *)(dtaptr-1) <= compval)
1128
void apt_control(int aptfrq)
1132
fprintf(stderr, "apt_control: %d\n", aptfrq);
1134
switch (fax_state) {
1135
/* wait for one of the valid APT frequencies */
1137
if (abs(aptfrq - aptstart) < 2) {
1138
if (++cnt >= 2) fax_rx_phase(1);
1143
/* here, a new start or a stop (interrupt) may occur */
1146
if (abs(aptfrq - aptstop) < 2) {
1147
if (++cnt >= 2) fax_rx_stop(1);
1155
void fax_rx_start(int internal)
1157
fprintf(stderr,"starting fax reception\n");
1158
/* if we come from phasing, initialize disp_func */
1159
if (fax_state == FAX_PHAS)
1160
disp_func(D_CPINIT | D_WDINIT | D_LDINIT);
1163
mode_notify(fax_state);
1166
void fax_rx_phase(int internal)
1168
fprintf(stderr,"entering phase-in mode\n");
1170
fax_state = FAX_PHAS;
1172
mode_notify(fax_state);
1175
void fax_rx_stop(int internal)
1177
fprintf(stderr,"stopping fax reception\n");
1178
fax_state = FAX_APT;
1179
/* flush rest of image (in horimag/verimag) */
1180
disp_func(D_FLUSHIMG);
1181
/* get current image-parameters for saving */
1182
save_func(F_GETDIM, 0);
1183
save_func(F_DOSAVE, 0);
1184
save_func(F_CLOSE, 0);
1186
mode_notify(fax_state);
1190
* this function is called by the callback-function of the Canvas-widget
1191
* to move the picture in writing-direction, when phasing in has failed
1192
* or was missed. px and py contain the coordinates of the button-press.
1194
void shift_fax_coords(unsigned px, unsigned py)
1199
fprintf(stderr, "coords = %d, %d\n", px, py);
1200
old_func = disp_func;
1204
tmp_pos = smpl_line / canhei * (canhei - py);
1206
tmp_pos = smpl_line / canhei * py;
1209
tmp_pos = smpl_line / canwid * (canwid - px);
1211
tmp_pos = smpl_line / canwid * px;
1213
core_start += (tmp_pos >> 16);
1214
tmp_pos = (smpl_line >> 16);
1215
if (core_start - core_dta > tmp_pos)
1216
core_start -= tmp_pos;
1217
old_func (D_CPINIT | D_WDINIT | D_LDINIT);
1218
old_func (D_ALLOWX);
1219
disp_func = old_func;
1223
* this function is called by the callback-function of the Canvas-widget
1224
* to re-adjust the sampling frequency to correct the line-shifting
1225
* caused by slightly deadjusted samling frequency.
1227
void correct_fax_azimut(int dx, int dy)
1233
fprintf(stderr, "coords = %d, %d\n", dx, dy);
1235
if (right2left) flip ^= 1;
1236
if (bot2top) flip ^= 1;
1238
df = (smplf * (double)dy) / (dx * PI * ixoc);
1240
df = (smplf * (double)dx) / (dy * PI * ixoc);
1244
fprintf(stderr, "delta freq.=%2.3f smplf=%4.3f\n",
1245
(double)df / 65536.0, (double)smplf / 65536.0);
1246
tune_frequency(smplf);
1248
old_func = disp_func;
1250
old_func (D_CPINIT | D_WDINIT | D_LDINIT);
1251
old_func (D_ALLOWX);
1252
disp_func = old_func;
1255
/*----------------------- FAX transmission --------------------------*/
1257
void fax_tx_stop(int internal)
1259
fprintf(stderr,"stopping FAX-transmission\n");
1261
mode_notify(fax_state);
1264
void fax_tx_start(int internal)
1266
fprintf(stderr,"transmitting image\n");
1267
fax_state = FATX_TX;
1268
fax_tx_func(D_WDINIT | D_LDINIT);
1270
mode_notify(fax_state);
1273
void fax_tx_apta(int internal)
1275
fprintf(stderr,"transmitting APT-start\n");
1276
transmit_apt(APTX_ISTART);
1277
fax_state = FATX_APTA;
1279
mode_notify(fax_state);
1282
void fax_tx_aptb(int internal)
1284
fprintf(stderr,"transmitting APT-stop\n");
1285
transmit_apt(APTX_ISTOP);
1286
fax_state = FATX_APTB;
1288
mode_notify(fax_state);
1291
void fax_tx_phase(int internal)
1293
fprintf(stderr,"entering TX-phase-in mode\n");
1295
fax_state = FATX_PHAS;
1297
mode_notify(fax_state);
1300
int load_txfile(char *name)
1312
if ((ftfile = fopen(name, "rb")) == NULL) {
1313
perror("open_txfile");
1316
if (fgets(line, 79, ftfile) == NULL) {
1317
perror("read_format");
1320
if (!strcmp(line, "P5\n"))
1322
else if (!strcmp(line, "P6\n"))
1325
return -2; /* unrecognized format */
1327
return -3; /* not yet supported */
1329
if (fgets(line, 79, ftfile) == NULL) {
1330
perror("read_header");
1333
} while (*line == '#');
1334
twidth = atoi(line);
1335
if (fgets(line, 79, ftfile) == NULL) {
1336
perror("read_header");
1339
theight = atoi(line);
1340
if (fgets(line, 79, ftfile) == NULL) {
1341
perror("read_header");
1344
timg_ptr = malloc(twidth*theight);
1345
pline = malloc(twidth);
1346
if (!(timg_ptr) || !(pline)) {
1347
if (timg_ptr) free(timg_ptr);
1348
if (pline) free(pline);
1349
perror("alloc_txmem");
1352
ncols = atoi(line) + 1;
1355
for (i=0; i<ncols; i++)
1356
lctab[i] = (64 * i) / ncols;
1358
for (i=0; i<theight; i++) {
1359
if (fread(pline, twidth, 1, ftfile) != 1) {
1360
perror("read_pixmap");
1366
for (j=0; j<twidth; j++)
1367
*cp++ = lctab[*(unsigned char *)sp++];
1375
* Fax-transmission background-routine :
1376
* This works a little different from the receiving-routine.
1377
* Transmission-data is not stored in a core-space, it is
1378
* transmitted directly out of the image-memory. Every function
1379
* called here must keep track of the pointer in the decptr-space
1380
* and give back control if the task is done or the pointer has reached
1381
* the end of the buffer.
1384
void fax_tx_backgnd(XtPointer client_data, int *source, XtInputId *xid)
1386
void fax_tx_backgnd(XtPointer client_data, XtIntervalId *xid)
1391
/* if we are in the phasing state, compute the phase-position */
1392
if (fax_state == FATX_APTA)
1395
if (fax_state == FATX_PHAS)
1398
if (fax_state == FATX_TX)
1401
if (fax_state == FATX_APTB)
1406
/* add a new timeout to call this function again */
1408
printf("adding new timeout\n");
1410
chstime = XtAppAddTimeOut(mainapp, 250, fax_rx_backgnd, (XtPointer) NULL);
1413
/* if disp_func is set, call that function (e.g. main FAX decoder loop) */
1414
if ((disp_func) && !(disp_locked)) {
1416
fprintf(stderr, "calling disp_func\n");
1421
fprintf(stderr, "transmitting data\n");
1426
void transmit_fax_gray(int init)
1428
/* pointer to sample-point for current pixel and current start-of-line */
1429
static char *timg_line, *timg_pix;
1430
/* sample-values per line or per pixel-value, 16bit int, 16bit frac */
1431
static unsigned inc_pix, inc_line, inc_p0;
1432
/* current index to pixel or line in sample-array, 16bit int, 16bit frac */
1433
static unsigned idx_pix, idx_line, idx_p0;
1434
/* increment between actual and previous pixel/line position */
1435
static unsigned ipix, iline;
1436
/* pixel-in-line-position start/increment/end */
1437
static int pixinit, pixinc, pixend;
1438
/* line-in-image-position start/increment/end, max. line of XImage */
1439
static int lineinit, lineinc, lineend, imgmax;
1440
static int (*put_pix)(struct _XImage *, int, int, unsigned long);
1441
/* bytes per line or per pixel, depends on direction (hor, vert, r2l, b2t) */
1442
static int bytes_per_line, bytes_per_pixel;
1444
if (init & D_INITS) {
1445
/* smpl_line is the number of core_dta points per line << 16 */
1446
smpl_line = 60.0 / lpm * smplf;
1448
inc_pix = smpl_line / theight;
1449
inc_line = (int)(ixoc * PI * 65536.0 / theight);
1451
put_pix = verimag->f.put_pixel;
1452
bytes_per_pixel = twidth;
1455
inc_pix = smpl_line / twidth;
1456
inc_line = (int)(ixoc * PI * 65536.0 / twidth);
1458
put_pix = horimag->f.put_pixel;
1459
bytes_per_pixel = 1;
1460
bytes_per_line = twidth;
1462
if (!(vertical) && (right2left)) {
1463
pixinit = twidth - 1;
1466
bytes_per_pixel = -bytes_per_pixel;
1468
if ((vertical) && (bot2top)) {
1469
pixinit = theight - 1;
1472
bytes_per_pixel = -bytes_per_pixel;
1476
pixend = (vertical) ? theight : twidth;
1478
/* initialize the line-advance variables and pointers */
1479
if (!(vertical) && (bot2top)) {
1480
lineinit = theight - 1;
1483
bytes_per_line = -bytes_per_line;
1485
if ((vertical) && (right2left)) {
1486
lineinit = twidth - 1;
1489
bytes_per_line = -bytes_per_line;
1493
lineend = (vertical) ? twidth : theight;
1499
timg_line = timg_ptr;
1500
/* twidth, theight, timg_ptr */
1502
inc_pix = 65536.0 * theight * lpm / ((60.0/65536.0) * smplf);
1503
inc_line = 65536.0 * theight / (PI * ixoc);
1505
inc_pix = 65536.0 * twidth * lpm / ((60.0/65536.0) * smplf);
1506
inc_line = 65536.0 * twidth / (PI * ixoc);
1510
timg_line += (twidth - 1);
1516
timg_line += (theight - 1) * twidth;
1520
timg_pix = timg_line;
1524
while (mod_ptr < mod_end) {
1525
*mod_ptr++ = *timg_pix;
1528
if (pixpos == pixend) {
1531
if (linepos == lineend) {
1532
/* we have transmitted the entire picture ! */
1535
idx_line += inc_line;
1536
iline = (idx_line >> 16) & 0xffff;
1538
timg_pix += bytes_per_pixel;
1539
timg_pix += iline * twidth; /* twidth == bytes_per_line */
1540
continue; /* jump over stuff below */
1543
ipix = (idx_pix >> 16) & 0xffff;
1545
timg_pix += ipix * bytes_per_pixel;
1551
* transmit an APT-tone. This function returns if either the pointer to
1552
* decptr reaches the end of the buffer or the duration is reached.
1553
* init can have the following values :
1554
* APTX_ISTART: initialize for aptstart-frequency
1555
* APTX_ISTOP: initialize for apt stop-frequency
1556
* 0: start/continue transmission
1558
void transmit_apt(int init)
1565
if (init == APTX_ISTART) {
1566
ap_inc = 4.294967296e6 * aptstart / (double) smplf;
1567
dur = (smplf >> 16) * aptdur / 1000;
1569
} else if (init == APTX_ISTOP) {
1570
ap_inc = 4.294967296e6 * aptstop / (double) smplf;
1571
dur = (smplf >> 16) * aptdur / 1000;
1574
while ((dur > 0) && (mod_ptr < mod_end)) {
1583
if (mod_ptr >= mod_end)
1584
mod_ptr = demod_ptr;
1586
if (fax_state == FATX_APTA)
1594
* transmit the phase-in signal for the image, which consists of 95% black
1595
* and 5% white (or inverted if invphase is set). These 5% have to appear
1596
* as one half to both the left and right margin of the image. The phase
1597
* where we start is not important, but where we stop and give control
1598
* to the function transmitting the contents of the loaded image.
1599
* tx_phlines determines the number of lines for phasing, after which
1600
* a line with 100% white is intersected to start the receiver.
1601
* if init is set, variables are initialized and the function returns.
1603
void transmit_phase(int init)
1607
static int idx_min, idx_max;
1611
inc_pix = lpm * (double) smplf / 60;
1615
txlines = tx_phlines + 1;
1618
while ((txlines >= 0) && (mod_ptr < mod_end)) {
1620
if (idx_pix > 63807 || idx_pix < 1638)
1621
*mod_ptr = (invphase ? 0 : dmaxval);
1623
*mod_ptr = (invphase ? dmaxval : 0);
1625
if (idx_pix > 0xffff)
1629
if (mod_ptr >= mod_end)
1630
mod_ptr = demod_ptr;