/*

**  Projekt:				SCCD (Simple City-Call Decoder)

**  Modul:      			pocsac.c

**  Abhaengige module:  	none

**  Copyright:  			gone

**  Version:                kappa 1.3E-15 (standallone COM1)

**  Lastmodification:	 	15.11.92 19:38

**  History:

**

**

** f1 = 465.970 MHz 	512 Bits/sec

** f2 = 466.075 MHz     1200 Bits/sec

** f3 = 466.230 MHz     1200 Bits/sec

**

*/





/* compact memory model */

/* keine flotingpoint emu */

/* nested comments */



/*

**

** Includes fuer dieses Modul

**

*/

#include <stdio.h>

#include <io.h>

#include <dos.h>

#include <fcntl.h>

#include <alloc.h>

#include <stdlib.h>

#include <string.h>

#include <conio.h>

#include <time.h>





/*

**

** Defines die die arbeitsweise beeinflussen

**

*/

#define BITWRONG                /* fallback wenn paritaet nicht stimmt */

#define LOGFILE					/* Wir schreiben eine Logfile fuer

								   spaetere Datenbankauswertungen */





/*

**

** Defines fuer dieses Modul

**

*/

#define TIMER0CLOCK 1193182L	/* Grundfreqenz des Timerbausteins */

								/* divisor f r timer 0 : sample

								   time=30/CLOCK_FREQ = 25.1 uSec */

#define TIMER0B512  2330  		/* Teilerrate fuer 512 Baud */

#define TIMER0B1200 994			/* Teilerrate fuer 1200 Baud */



#define MAXARRAY 60000		    /* groesse des bitpuffers */



#define SYNCRON  0x7cd215d8L	/* Frame fuer das Syncronwort */

#define SYNCINFO 0x7cd21436L	/* Frame fuer das InforufSyncronwort */

#define IDLE     0x7a89c197L	/* Frame fuer das Idlewort */



#define COMPORT	0x3f8           /* alles fuer COM1 */

#define TXBYTE  0

#define RXBYTE  0

#define DIFLLB  0

#define DIFLHB  1

#define IER     1

#define IIR		2

#define LCR		3

#define MCR		4

#define LSR		5

#define MSR		6





#define GETSYNCR 	1			/* Auf erstes Syncronwort warten */

#define GETFRAME	2			/* Frames einladen */





/*

**

** Variablen / Speicher der von diesem Modul benutzt wird

**

*/

		 char *roh_daten_feld;				/* zeiger auf pufferfeld */

volatile unsigned int  roh_daten_anfang; 	/* momentaner Anfang des

											   Ringpuffers */

volatile unsigned int  roh_daten_ende;		/* momentanes Ende des

											   Ringpuffers */

volatile unsigned int  roh_daten_laenge; 	/* momentane Ringpufferlaenge

											   (anzahl der Daten) */



unsigned int tics;				/* soviel Teilerschritte treten pro Bit

								   auf */

unsigned int tics_2;			/* die Haelfte der Schritte */



void interrupt (*old_vec)();	/* Adresse der alten Timerseviceroutine */

void interrupt (*time_int)();	/* Adresse der alten Timer0 Routine */

void interrupt time_i();		/* prototyp der Timer0 Routine */

void interrupt lauf_er();		/* prototyp der bitholroutine */

volatile int abbruch = 0;		/* wir sollen das Programm verlassen */

volatile int eine_sek_weg = 0;	/* es ist eine Sekunde vergangen */



#ifdef LOGFILE

FILE *logfile = NULL;			/* logfile fuer die daten */

volatile int last_sync;			/* Sekunden zaehlen wann das letzte

								   mal ein Sync emfangen wurde */

#endif



char asc_time[40] = "Keine Zeit angegeben";



static char numerik[] = {       /* Decodierrung von Numerikpagern */

'0',

'8',

'4',

' ',

'2',

'=',

'6',

']',

'1',

'9',

'5',

'_',

'3',

'U',

'7',

'['

};





/*

**

** Routinen dieses Moduls

**

*/





char *

strip_cr(char *cptr)					/* CR+LF rausscheissen */

{

	char *oldcptr;



	oldcptr = cptr;

	while (*cptr != '\0') {

		if (*cptr == '\r' ||  *cptr == '\n')   *cptr = '\0';

		cptr++;

	}

	return(oldcptr);

}





#define ADRESS 0                /* Wir haben eine Adresse */

#define DATEN  1				/* Wir haben Daten */



void

decode_frame(int framepos, unsigned long frame)	/* Ein emfangenes Frame

												   entschluesseln */

{

static unsigned long lastadress = 0L;	/* letzte emfaenger adresse */

static int lastadrfunktion = 0;			/* letzte funktion der adresse */

static char lastchar = '\0';

static int lastbitpos = 0;				/* letzte Frameposition */

static int lastget = ADRESS;			/* was fuer einen Typ hatte das

										   letzte Frame ? */



	int i;

	unsigned long l;





	if ((frame&0x80000000) != 0L)   i = 1;  	/* nachricht */

	else   i = 0;								/* adresse (nur Ton) */

	if (i == 0) {								/* es ist ein adress

												   frame */



		if (lastget == ADRESS  &&  lastadrfunktion > 0  && \

			lastadress != 0) {	/* der letzte war eine adresse also

								   war er nurton */



			printf("\nA:%07ld | %s | T | BEEP", lastadress, asc_time);

			printf("%d", lastadrfunktion);

#ifdef LOGFILE

			fprintf(logfile, "\nA:%07ld | %s | T | BEEP", lastadress, \

				asc_time);

			fprintf(logfile, "%d", lastadrfunktion);

#endif

		}



		if (frame == SYNCRON) {         /* das ist nur ein eingeschobenes

										   Syncronwort */

			lastget = DATEN;			/* wird nicht als adresse

										   gewertet */

		} else if (frame == IDLE) {	    /* das ist nur ein Fuellwort */

			lastadress = 0L;

			lastadrfunktion = 0;		/* alles zurueckstellen */

			lastbitpos = 0;

			lastget = ADRESS;			/* ende einer Nachricht */

		} else {      					/* adressse + funktion merken */

			lastadress = ((frame>>10)&0x001FFFF8L)+(framepos/2);

			lastadrfunktion = ((frame >> 11)&0x00000003L)+1;

			lastbitpos = 0;

			lastget = ADRESS;			/* dies war eine Adresse */

		}

	} else {							/* es ist ein Daten frame */



		if (lastbitpos == 0) {			/* wir sind am anfang eines

										   Datenwortes */

			if (lastadrfunktion == 1) {	/* numerikpager */

				printf("\nA:%07ld | %s | N | ", lastadress, asc_time);

#ifdef LOGFILE

				fprintf(logfile, "\nA:%07ld | %s | N | ", lastadress, \

					asc_time);

#endif

			} else if (lastadrfunktion == 4) {	/* alphaPager */

				printf("\nA:%07ld | %s | A | ", lastadress, asc_time);

#ifdef LOGFILE

				fprintf(logfile, "\nA:%07ld | %s | A | ", lastadress, \

					asc_time);

#endif

				lastchar = '\0';

			}

		}







		/* Daten analysiern und ausgeben */

		frame <<= 1;					/* das erste bit wurde schon

										   interpretiert und wird jetzt

										   ignoriert */

		i = 0;

		if (lastadrfunktion == 1) {		/* numerik Pager decodieren */

			for (i = 0; i <= 4; i++) {

				l = frame&0xf0000000L;	/* ich brauch nur die

										   hoechsten vier bits */

				l >>= 28;				/* bitte als char */

				printf("%c", numerik[(char)l]);	/* so einer sind wir */

#ifdef LOGFILE

				fprintf(logfile, "%c", numerik[(char)l]);

#endif

				frame <<= 4;

				lastbitpos += 4;

			}

		}

		if (lastadrfunktion == 4) {		/* alpha Pager decodieren */

			for (i = 0; i <= 19; i++) {	/* alle 20 Bits nacheinader

										   durchmachen */

				lastchar >>= 1;

				if ((frame&0x80000000L) != 0L)   lastchar |= 0x40; /* bit in ein Char schieben */

				frame <<= 1;

				lastbitpos++;

				if ((lastbitpos%7) == 0) {		/* ein neues Datenwort

												   ist voll */

					printf("%c", lastchar);

#ifdef LOGFILE

					fprintf(logfile, "%c", lastchar);

#endif

					lastchar = '\0';

				}

			}

		}

		lastget = DATEN;

	}

}





void

mach_hin(int baud)				/* wir gehen auf emfang */

{

	int i, j, k, anz, paritaet, timercl, timertic;

	unsigned long l;

	int getmodus;

	char old_0x21, old_pio_b;

	char c;

	time_t zeit;

	struct tm *zeit2;



#ifdef LOGFILE

	logfile = fopen("logfile.txt", "a");

	if (logfile == NULL)   return;

#endif





	disable();					/* alle interrupts abschalten */



	roh_daten_anfang = roh_daten_ende = roh_daten_laenge = 0;

	getmodus = GETSYNCR;

	anz = k = 0;

	if (baud == 1200) {

		printf("1200 Baud\n");

		tics = TIMER0B1200;

	} else {

		printf("512 Baud\n");

		tics = TIMER0B512;

	}

	tics_2 = tics/2;



	old_vec = getvect(12);		/* alte Timerserviceroutine retten */

	setvect(12, lauf_er);		/* timerserviceroutine setzen */



	time_int = getvect(0x1c);	/* timer0 interrupt setzen */

	setvect(0x1c, time_i);



	outportb(COMPORT+MCR, 0x09);/* Leitungen setzen */

	outportb(COMPORT+IER, 0x08);/* MODEMzustandswechsel */



	old_0x21 = inportb(0x21);	/* interrupt maske holen */

	outportb(0x21, old_0x21&(char)(~((char)0x10)));		/* Timer 2

														   einschalten */



	outportb(0x43, 0xB0);		/* Zaehler auf hoechsten wert stellen */

	outportb(0x42, 0xff);

	outportb(0x42, 0xff);

	old_pio_b = inportb(0x61);			/* pio-b einlesen */

	outportb(0x61, old_pio_b|0x01);		/* Zaehler einschalten */



	enable();					/* jetzt gehts los  */







	do {

		if (abbruch)   break;





		if (eine_sek_weg) {				/* uhr nachstellen */

			eine_sek_weg = 0;



			if (kbhit() != 0) {			/* ein Zeichen von der Tastatur

										   liegt an also abbrechen */

				break;

			}



			time(&zeit);

			zeit2 = localtime(&zeit);

			strcpy(asc_time, strip_cr(asctime(zeit2)));	/* neue uhrzeit */



#ifdef LOGFILE

			if (last_sync >= 0)   last_sync++;

			if (last_sync > 20) {	/* 20 Sekunden lang kein Sync mehr

									   gekommen */

				disable();

				if (logfile != NULL)   fclose(logfile);

				logfile = fopen("logfile.txt", "a");

				if (logfile == NULL) {

					printf("Logfile laesst sich nicht oeffnen\n");

					abbruch = 1;

				}

				enable();

				last_sync = -1;

			}

#endif

		}





		if (roh_daten_laenge > 0) {		/* timerinterrupt hat ein oder

										   mehr neue Zeichen eingelesen */



			/* felddaten holen */

			i = roh_daten_feld[roh_daten_anfang++];

			if (roh_daten_anfang > MAXARRAY)   roh_daten_anfang = 0;

			roh_daten_laenge--;

/*

			printf("%c", i+'0');

			fflush(stdout);

*/

			/* felddaten auswerten */



			if (getmodus == GETSYNCR) {		/* Erstes Syncronframe

											   erwarten */

				l <<= 1;

				if (i == 1)   l |= 0x00000001L;			/* bit setzen */

				if (l == SYNCRON  ||  l == SYNCINFO) {	/* wert stimmt

														mit Syncronwort

														ueberein */

/*					printf("\nSyncronwort");

					fflush(stdout);   					*/

					last_sync = 0;

					getmodus = GETFRAME;

					anz = k = paritaet = 0;

					l = 0L;

					decode_frame(0, IDLE);

				}

			} else if (getmodus == GETFRAME) {	/* GETFRAME Daten als

												   Frame einlesen */

				anz++;

				l <<= 1;

				if (i == 1) {

					l |= 0x00000001L; 			/* bit setzen */

					if (paritaet == 0)   paritaet = 1;

					else   paritaet = 0;

				}

				if (anz >= 32) {				/* neues Frame ist

												   vollstaendig */

					if (paritaet == 1) {

						printf("%c", 247);		/* paritaetsfehler */

						fflush(stdout);

#ifdef BITWRONG

						l = 1L;					/* fallback machen */

						getmodus = GETSYNCR;

						decode_frame(0, IDLE);

						anz = k = paritaet = 0;

#endif

					}

					if (k >= 16  ||  l == SYNCRON  ||  l == SYNCINFO) {

						/* egal was dies MUSS ein Syncronwort seien */

						decode_frame(0, SYNCRON);

						last_sync = 0;

						k = 0;

					} else if (l == IDLE) {     /* nur idle keine

												   relevanten daten */

						decode_frame(k, l);

/*						printf("IDLE\n"); */

						k++;

					} else {					/* endlich ein

												   normales Frame */

						decode_frame(k, l);

						k++;

					}

					anz = paritaet = 0;

					l = 0L;

				}

			}

		}





	} while(42);				/* endlos */







	/* destall interrupts */

	disable();

	setvect(12, old_vec);		/* timerserviceroutine zuruecksetzen */

	setvect(0x1c, time_int);	/* alter Timer2 interrupt */

	outportb(0x21, old_0x21);	/* alte Timer einschalten */

	outportb(0x61, old_pio_b);	/* Zaehler Ursprung */

	enable();

#ifdef LOGFILE

	if (logfile != NULL)   		fclose(logfile);

#endif

	return;

}





void

interrupt lauf_er()				/* interrupt wenn wechsel an CTS

								   verstrichene Zeit und Zustand

								   feststellen, anzahl von 0/1 in

								   puffer schreiben */

{

	char bytein, c;

	unsigned int i;

	unsigned int j;





	bytein = inportb(COMPORT+MSR);

	if ((bytein&0x01) == 0x01) {	/* CTS zustands wechselaufgetreten */

		c = ((bytein&0x10) != 0) ? (char)0 : (char)1; /* hab ich ne 0

														 oder ne 1 */

		outportb(0x43, 0x80);		/* Zaehlerstand auslesen */

		i = inportb(0x42);

		i += (256 * inportb(0x42));

		outportb(0x43, 0xB0);		/* Zaehler auf hoechsten wert neustellen */

		outportb(0x42, 0xff);

		outportb(0x42, 0xff);



		i = 0xffff-i;				/* wieviele Zaehlerschritte sind

									   vergangen */

		j = i/tics;                 /* wieviele Bits waehren das ? */

		if (i%tics > tics_2)  j++;  /* ist vieleicht die Zeit

									   unterlaufen worden? */

/*	if (j <= 0)  j = 1; */



		for (i = 1; i <= j; i++) {	/* anzahl der bits die decodiert

									   wurden speichern */

			if (roh_daten_laenge < MAXARRAY) {

				roh_daten_feld[roh_daten_ende++] = c;

				if (roh_daten_ende > MAXARRAY)   roh_daten_ende = 0;

				roh_daten_laenge++;

			} else   printf("\nPufferueberlauf\n");

		}

	}

	outportb(0x20,0x20);            /* end of interrupt klarmachen */

}





void interrupt time_i()				/* wird 18.2/Sekunde aufgerufen */

{

static int t = 0;



	t++;

	if (t >= 19) {	/* genuegend zeit vergangen ? */

		t = 0;

		eine_sek_weg = 1;

	}

/*	time_int();	*/	/* alte zeitroutine weiter machen */

}







int

main(int argc, char *argv[])

{

	roh_daten_feld = (char *)malloc(MAXARRAY+300);

	if (roh_daten_feld == NULL)   exit(0);

	printf("\nPOCSAC Decoder fuer COM1\n");

	printf("Als Argumente bitte die Baudrate eingeben (512/1200)\n");

	if (argc != 2) {

		printf("keine Baudrate\n");

		return(0);

	}



	mach_hin(atoi(argv[1]));



	free(roh_daten_feld);

}



