/*
 ************************************************************************
 *	      Convert the .IMP file to a set of MatLab .M file
 *
 * Call the routine
 *	imp2m imp_file_name name1 {name2 ...}
 *	name1, name2, ... are the names of the MatLab files to be
 *	created. Extension .M is to be assigned to them.
 *	The no. of names specified should be equal to the no. of channels
 *	that impulse activity was recorded on in the .IMP file
 *
 * IMP file is created by the Impulse Acquisition system and contains
 * the information on inter-impulses interval recorded on one or more
 * channels. It is a binary file with default extension .IMP
 * It contains a header
 *	1 word			Polling frequency (in microsec)
 *	1 word			No of channels to poll
 *	n+2 bytes		Comment for the 1. channel
 *	....
 *	n+2 bytes		Comment for the last channel polled
 * followed by data items (1 word). Two high bits of the data item word
 * specifies the channel while the other bits stand for the interval
 * from the previous to the current impulse on the channel.
 * All strings are written in the standard format as the two-byte length
 * field followed by the bytes of the string (the null byte included)
 *
 * Every M-file created by the present program contains data that refers
 * only to one channel. It is a text file with the extension .M and
 * it is intended to be read by the MatLab system. The file contains
 *  - comment string that says about the channel no.,
 *    the date the .IMP file has been created.
 *  - title = 'the comment that user assigned to the channel while running Impulses.exe'
 *  - name = [ intervals between first 4001 impulses on the channel ];
 *    the data are arranged in one column, name is the name of the M-file
 *  - name_1 = [ intervals between next 4001 impulses ];
 *  - name_2 = [ intervals between next 4001 impulses ];
 *    and so on. Thus all the data on interimpulse intervals are breaked
 *    into pieces of 4000 values (or less) and every piece is assigned
 *    to the matlab array. Therefore, every MatLab array has length
 *    not exceeding 4000 (that meets all the memory requirements)
 *
 ************************************************************************
 */

#include <alloc.h>
#include <io.h>
#include <string.h>
#include "stdio.h"
#include "assert.h"


/*
 *-----------------------------------------------------------------------
 * 			    Global parameters
 */

int  No_channels;
unsigned int Polling_period;

char * Imp_file_name;
FILE * Imp_file;
char Datetime [20];                     /* Date and time the IMP file	*/
					/* was created in the form     	*/
					/* 23/03/1991 10:05\0   	*/

typedef struct {			/* Format for data written into	*/
	interval	: 14;		/* the IMP file			*/
	channel_no	: 2;
	       }
DATA_ITEM;

struct M_FILE {			/* Describe a M-file and its curr status*/
	char * name;			/* File name			*/
	FILE * fp;			/* File stream pointer		*/
	int    counter_per_array;	/* Data items for one array	*/
	int    array_no;		/* No of array for a piece of data*/
	long int total_counter;
	      }
*M_files;



/*
 *========================================================================
 *     				Process an M-file
 */

#define M_file_extension ".M"
#define Max_no_elements_per_M_array	4000

				/* Initialize corresponding slot of the	*/
				/* M_files structure and open the file	*/
static void open_m_file(const int no, const char * fname)
{
  struct M_FILE * mp = &M_files[no];
  char * cp;

  mp->name = strcpy(calloc(strlen(fname)+1,sizeof(char)),fname);
  cp       = strcpy(calloc(strlen(fname)+1+sizeof(M_file_extension),
			   sizeof(char)),
		    fname);
  if( strchr(cp,'.') == (char *)0 )	/* No extension was specified	*/
    strcat(cp,M_file_extension);	/* Apply default one		*/
  else
    _error("Please, don't specify extension for M-file like '%s'",fname);

  mp->fp = fopenc(cp,"w");
  mp->counter_per_array = 0;
  mp->array_no          = 0;
  mp->total_counter     = 0;
}

static void write_m_file_header(const int no, const char * comment)
{
  struct M_FILE * mp = &M_files[no];
  fprintf(mp->fp,"%% Inter-impulse intervals. Channel no %d\n",no+1);
  fprintf(mp->fp,"%%   of the IMP file '%s' created %s\n",
	  Imp_file_name,Datetime);
  fprintf(mp->fp,"%% Polling period     %u microsec\n",Polling_period);
  fprintf(mp->fp,"title = '%s'\n",comment);
}

				/* Append an element to the M-array	*/
static void write_m_file_data(const int no, const unsigned data)
{
  struct M_FILE * mp = &M_files[no];

  if( mp->counter_per_array == 0 )	/* Create a new array		*/
    if( mp->array_no == 0 )		/* first array has the name without suffuxes	*/
      fprintf(mp->fp,"\n%s = [%u",mp->name,data);
    else				/* The next arrays has a numerical suffix	*/
      fprintf(mp->fp,"\n%s_%d = [%u",mp->name,mp->array_no,data);
  else
      fprintf(mp->fp,"\n%u",data);	/* Append to the existed array	*/

  mp->total_counter ++;
  if( ++(mp->counter_per_array) > Max_no_elements_per_M_array )
  {                 			/* Complete the array		*/
    fprintf(mp->fp," ];\n");
    mp->counter_per_array = 0;
    mp->array_no ++;
  }
}

static void close_m_file(const int no)
{
  struct M_FILE * mp = &M_files[no];

  if( mp->counter_per_array != 0 )	/* The array was being filled	*/
  {                 			/* Complete the array		*/
    fprintf(mp->fp," ];\n");
    mp->array_no ++;
  }
  fclose(mp->fp);

  printf("\nChannel %d",no);
  printf("\nTotal %ld data on intervals has been arranged",mp->total_counter);
  printf("\ninto %d M-arrays with the root name %s\n",mp->array_no,mp->name);
}

/*
 *=======================================================================
 * 		   	Process the IMP file
 */
				/* Obtain the date and time the		*/
				/* file specified has been created	*/
				/* and put this info into Datetime str	*/
static void get_date_and_time(const FILE * fp)
{
  struct ftime ft;
  getftime(fileno(fp), &ft);
  sprintf(Datetime,"%u/%u/%u %u:%u",
	  ft.ft_day,  ft.ft_month, ft.ft_year+1980,
	  ft.ft_hour, ft.ft_min);
}

				/* Open IMP file, read its header	*/
				/* and set up the global parameters	*/
static void preprocess_imp_file(const char * fname)
{
  Imp_file_name = strcpy(calloc(strlen(fname)+1,sizeof(char)),fname);
  Imp_file = fopenc(fname,"rb");
  get_date_and_time(Imp_file);
  Polling_period = getw(Imp_file);
  No_channels    = getw(Imp_file);
  assure( !ferror(Imp_file),"Error reading the IMP file");

  printf("\nIMP file named '%s' was created %s\n",Imp_file_name,Datetime);
  printf("\nNo channels polled %d",No_channels);
  printf("\nPolling period     %u microsec\n",Polling_period);
}


static void process_imp_file_comments()
{
  register int i;

  for(i=0; i<No_channels; i++)
  {
    int len;
    char * sp;
    len = getw(Imp_file);
    assure( !ferror(Imp_file), "Error reading comments from the IMP file");
    assert( (sp = malloc(len)) != (void *)0 );
    assure( fread(sp,1,len,Imp_file) == len,
	   "Error reading comments from the IMP file");
    write_m_file_header(i,sp);
    free(sp);
  }
}

static void process_imp_file()
{
  DATA_ITEM item;

  while( !feof(Imp_file) )
  {
    if( fread(&item,sizeof(item),1,Imp_file) != 1 )
      break;
    if( item.channel_no >= No_channels )
      continue;				/* Artefact			*/
    write_m_file_data(item.channel_no,item.interval);
  }
}

/*
 *========================================================================
 *			Initialization routines
 */

static void help(const char * mess)		/* Output help message  */
{
  message("\n%s\n",mess);
  message("\n\n\timp2m imp_file_name name1 name2 ...");
  message("\n\nwhere name1, name2,... stand for the names of the M files");
  message("\nto be created. Extension .M is assigned by default");
  exit();
}

/*
 *-----------------------------------------------------------------------
 *				Root module
 *	Parse the command string and call appr. routine to convert
 */

void main(argc,argv)
int argc;				/* No. of arguments being passed*/
char *argv[];				/* Vector of pointers to args 	*/
{
  register int i;

  message("\n\nConvert the IMP file recorded by the Impulse Acquisition system");
  message("\n\t\tto a set of MatLab M-files\n");

  if(argc <= 1)				/* No additional arguments      */
    help("");				/* except the pgm name was spec */

  preprocess_imp_file(argv[1]);

  if( argc-2 != No_channels )
    help("No. of m-file names You specify doesn't correspond to the no. of channels");

  assure( (M_files = calloc(No_channels,sizeof(struct M_FILE))) != (void *)0,
	  "No memory to allocate M_file structure" );

  for(i=0; i<No_channels; i++)
     open_m_file(i,argv[2+i]);

  process_imp_file_comments();
  process_imp_file();

  for(i=0; i<No_channels; i++)
     close_m_file(i);
  fclose(Imp_file);
}
