/*******************************************************************

		LINEMOD

********************************************************************

Program models a uniform transmission line using ABCD parameters
and calculates the input impedance, voltage transfer function,
impulse response, and other quantities of interest

Sections of transmission line can be cascaded, with series
and shunt resistances and bridge taps

Other twoports can easily be added to the line by user-defined functions

Bridge taps can themselves be cascades of transmission lines
and have their own bridge taps

A filter transfer function can be specified, and that filter
will be cascaded with the transfer function of the line

Programmer: D.G.Messerschmitt
Date: Aug. 4, 1982
Last modification: Oct. 19, 1982
*/

#include <stdio.h>
#include "type.h"

#define MAXLINE 81

/* declare variables used by the other routines, but read from
   the input file */

int mexp,	/* 2**mexp = number of bit times pulse calc over */
    nexp;	/* 2**nexp = number of samples per bit time */

double T;	/* bit time in seconds */

/* declare file pointers for various outputs */

FILE *fin,*fdata,*ffreq,*fimped,*ftime;

/*****************************************************************

			main()

******************************************************************

Routine inputs the file that the line parameter information
is contained in, and calls routines which extract that
information and develop the line model from it
*/

main(argc,argv)
int argc;
char *argv[];

{
	FILE *fopen();
	TWOPORT *first;  /* points to the first twoport in line */
	TWOPORT *read_file();
	char file_name[15];
	int i;
	char line[MAXLINE], *newline;
	char *remblank();
	PFM funct_list();

/* determine the input file containing the line parameter information */

	if(argc == 2) {

		if((fin=fopen(argv[1],"r")) == NULL) {

			fprintf(stderr,"File %s could not be opened\n",argv[1]);
			exit(1);
			}
		}

	else {
		fprintf(stderr,"Usage: linemod filein\n");
		exit(1);
		}

/* open up the output files */

	strcpy(file_name,argv[1]);
	i = strlen(argv[1]);

	/* data file */
	strcpy(file_name+i,".data");
	if((fdata = fopen(file_name,"w")) == NULL) {
		fprintf(stderr,"File %s could not be opened\n",file_name);
		exit(1);
		}

	/* freq file */
	strcpy(file_name+i,".freq");
	if((ffreq = fopen(file_name,"w")) == NULL) {
		fprintf(stderr,"File %s could not be opened\n",file_name);
		exit(1);
		}

	/* imped file */
	strcpy(file_name+i,".imped");
	if((fimped = fopen(file_name,"w")) == NULL) {
		fprintf(stderr,"File %s could not be opened\n",file_name);
		exit(1);
		}

	/* time file */
	strcpy(file_name+i,".time");
	if((ftime = fopen(file_name,"w")) == NULL) {
		fprintf(stderr,"File %s could not be opened\n",file_name);
		exit(1);
		}

/* first read from the input file m,n, and T */

	/* read input lines until it is encountered */
	newline = NULL;
	while(newline == NULL) {
		if(fgets(line,MAXLINE,fin) == NULL) {
			fprintf(stderr,"EOF encountered prematurely\n");
			exit(1);
			}

		/* remove blanks and tabs from beginning of line --
		   returns NULL if line is empty or a comment */
		newline = remblank(line);
		}

	if(sscanf(newline,"%d%d%lf\n",&mexp,&nexp,&T) != 3) {

		/* line not properly read */ 
		fprintf(stderr,"First line of file error\n");
		exit(2);
		}

/* print parameters to the data file */

	fprintf(fdata,"m = %d, n = %d, T = %g\n",mexp,nexp,T);

/* now read the rest of the input file, returning pointer to the data
 structure of the first twoport in the line, NULL if error occurs */

	if((first=read_file(fin,fdata)) == NULL) {

		fprintf(stderr,"Error in reading file\n");
		exit(2);
		}

/* find the abcd matrix characterization for the line at each
	frequency */

	abcd(first);

/* find the input impedance of the line */

	imped();

/* find the impulse response of the line */

	ir();
}

/*********************************************************************

			remblank()

***********************************************************************

Function removes blanks and tabs from the beginning of a line
and returns a pointer to the resulting new line
*/

char *remblank(line)

char line[];

{
	char *newline;

	newline = line;
	while(newline[0] == ' ' || newline[0] == '\t') ++ newline;

	/* blanks and tabs have now been removed */
	if(newline[0] == '\n' || newline[0] == '#') return(NULL);
	else return(newline);
}

/***********************************************************************

			read_file()

***********************************************************************

Function reads the specified input file and stores the data in the
data structure, and prints out the input data into the output file

It reads the file for a single transmission line, the data for which
is terminated by a line containing "end"

If a line contains "bridge" it is assumed the following lines
specify a bridge tap until the next "end" is encountered, in which
case it calls itself recursively

The function returns a pointer to the first twoport in the data
structure for the transmission line
*/

TWOPORT *read_file(fin,fdata)
FILE *fin,*fdata;

{
	POINTER calloc();	/* storage allocator */

	TWOPORT *first = NULL;  /* points to first twoport in line */
	TWOPORT *current;       /* points to twoport currently being read */
	TWOPORT *tp;		/* temporary storage */

	char line[MAXLINE];	/* stores one line of input file */
	char *newline;
	char control[MAXLINE];	/* stores control word for input line */
	char *remblank();

	for(;;) {	/* for each line in the input file */

/* input one line from the input file; error if EOF since the
   file should terminate with "end" line */

	if(fgets(line,MAXLINE,fin) == NULL) {
		fprintf(stderr,"File terminates before end stmt\n");
		return(NULL);
		}

/* remove blanks and tabs from the line -- goto next line if line
   is empty or contains just a comment */

	if((newline = remblank(line)) == NULL) continue;

/* read the function name from the beginning of the line */

	if(sscanf(newline,"%s",control) != 1) return(NULL);

/* when we encounter a line "end", we return the pointer first */

	if(strcmp(control,"end") == 0) {
		fprintf(fdata,"\n");
		return(first);
		}

/* presume otherwise that the line is a valid control line --
   first allocate memory for the twoport data structure which
   will be filled from the input line */

	if((tp = (TWOPORT *) calloc(1,sizeof(TWOPORT))) == NULL)
		error_alloc();

/* assume that twoport is not a bridge tap by setting tap = NULL */

	tp->tap = NULL;

/* if this is the first storage allocation, first and current are
   both pointers to storage just allocated */

	if(first == NULL) {
		first = current = tp;
		current->right = NULL;
		}

/* otherwise add twoport to the end of the linked list */

	else {
		current->right = tp;
		current = tp;
		current->right = NULL;
		}

/* if line is "bridge", call read_file() recursively to
   fill in the linked list on the bridge tap */

	if(strcmp(control,"bridge") == 0) {

		fprintf(fdata,"\nBridge Tap consisting of:\n");

		if((current->tap = read_file(fin,fdata)) == NULL)

			/* error in reading bridge tap info */
			return(NULL);

		continue;  /* read next line */
		}

/* the remaining types of lines are handled by individual functions --
   we call the function with the same name as control and have
   it read its own parameters from the line */

/* first find function pointer from table look-up routine funct_list() */
	
	if((current->function=funct_list(control))==NULL) {

		fprintf(stderr,"Function %s not defined in funct_list()\n",
			control);
		return(NULL);
		}

/* we signal to the function that this is just an
   initialization call by passing a pointer to line */

	current->line = newline;

	(*(current->function))(current);

/* subsequent calls will pass NULL */

	current->line = NULL;
	}
}

/**********************************************************************

			error_alloc()

***********************************************************************

Function prints error message and exits when allocation of storage
cannot be performed
*/

error_alloc()

{
	fprintf(stderr,"OS unable to allocate storage\n");
	exit(1);
}
