/****************************************************************************//*																			*//*									KIR.h									*//*																			*//****************************************************************************//****************************************************************************//* This is a C language header file that defines the following routine for	*//* reading KIR format data files into memory. The KIR format is a data		*//* format used at Kiruna magnetic observatory for storing magnetometer data.*//* A KIR file is a binary file containing data for only one station.		*//*																			*//*	-------------------  Read data from a KIR-format file	--------------	*//*																			*//* long ReadKIR(char *FileName,NetworkPtr Network,char *StartTimeStr,		*//*				 char *EndTimeStr,char *StationList,Time_sec SampleStep)	*//*		FileName		Name of the KIR-file containing the data.			*//*						Contrary to other format reading routines ReadKIR	*//*						cannot read data from stdin. Therefore FileName		*//*						must not be nil nor zero length.					*//*		Network			Structure into which the data is read.				*//*						Network_struct is defined in file MagnData.h.		*//*		StartTimeStr	String defining the first time to be read from  	*//*						the data file (String delimited with '\0').			*//*						String format : YYMMDDHH. If HH is missing then		*//*						00 is assumed. If StartTimeStr is nil or zero		*//*						length then start of file is assumed.				*//*		EndTimeStr		String defining the time not to be read anymore.	*//*						Format as before YYMMDDHH. If nil or zero length	*//*						then data is read until end of file.				*//*		StationList		List of stations included in the data. This is 		*//*						for compatibility reasons only as the KIR format	*//*						allows only one station in one data file.			*//*						Furthermore, as there is no information about the	*//*						station in the datafile itself (e.g. station name)	*//*						The StationList must contain exactly one station.	*//*		SampleStep		Sample step used in the data file. If missing then	*//*						sample step is read from the start of data file.	*//*																			*//*		The function result indicates how successfull the file reading was:	*//*				0: OK			: File read successfully					*//*				1: FileError	: Failed to read the given file				*//*				2: OutOfMemory	: Memory allocation failed during reading	*//*				3: FormatError	: File to be read is not a KIR file			*//*																			*//****************************************************************************//****************************************************************************//*							  Lasse Hakkinen								*//*					  Finnish Meteorological Institute						*//*						  Department of Geophysics							*//*								P.O.Box 503									*//*						FIN-00101, Helsinki, Finland						*//*						e-mail: Lasse.Hakkinen@fmi.fi						*//*						phone : (+358)-9-19294634							*//*						fax   : (+358)-9-19294603							*//*																			*//*						version 1.03 		19.10.1999						*//****************************************************************************//****************************************************************************//*	Version history:														*//*																			*//*	1.03 19.10 1999 Modified GetLong-routine so that it works correctly 	*//*					in Little-endian processors.							*//*	1.02 04.05 1999 Re-fixed a bug in handling data lines where the			*//*					difference in times is not the fixed TimeStep.			*//*	1.01 02.02.1999	Fixed a timing bug where the times of the data blocks	*//*					were not at fixed intervals.							*//*	1.0  29.09.1997	First official release									*//****************************************************************************/#include <stdio.h>#include <string.h>#include <stdlib.h>#define MissingKIR 0x7FFFFFFF/*--------------------------------------------------------------------------*//* Function prototypes														*//*--------------------------------------------------------------------------*/static Time_sec GetKIRTime(char *p);static int ReadKIRLine(FILE *KIRfile,char *p);static long Get_long(char *p);static void SetStationParamsKIR(StationPtr Station,Time_sec T,char *StatList);static void GetKIRData(StationPtr Station, char *Buff, Time_sec Time);long ReadKIR(char *FileName,NetworkPtr Network,char *StartTimeStr,			  char *EndTimeStr,char *StationList,Time_sec SampleStep);/*==========================================================================*//*				Routines for reading KIR-format files						*//*==========================================================================*//*--------------------------------------------------------------------------*//*	Get a four byte longint (big endian) from memory. This routine is		*//*	designed so that it should work both in little endian and big endian	*//*	processors.																*//*--------------------------------------------------------------------------*/static long Get_long(char *p){	long i;	long value;	char *q = p+3;	/* This code is for big endian longints 	value = *p++;	for (i=0;i<3;i++) value = ((value << 8) | ((0x000000FF) & (*p++)));*//* This code is for low endian longints */	value = (0x000000FF) & (*q--);	for (i=0;i<3;i++) value = ((value << 8) | ((0x000000FF) & (*q--)));		return (value);}/*--------------------------------------------------------------------------*//*	Get the time of the current data point (in seconds). The date in a KIR	*//*  file is in seconds since Jan 1st 1970 00:00:00 and is stored as a long	*//*	(4 bytes)																*//*--------------------------------------------------------------------------*/static Time_sec GetKIRTime(char *p){	Time_sec T0,T1;		T0 = StrToSecs("700101",0);	T1 = Get_long(p);	return (T0+T1);}/*--------------------------------------------------------------------------*//* Read one data point (=time+X+Y+Z) from the KIR-format file into Buffer.	*//* The routine will return 1 if the line was read succesfully , otherwise	*//* 0 is returned.															*//*--------------------------------------------------------------------------*/int ReadKIRLine(FILE *KIRfile,char *p){		return(fread(p,16,1,KIRfile));}/*--------------------------------------------------------------------------*//*	Fill some fields in the Station_struct by copying them from the			*//*	StatonInfo structure defined in the StatInfo.h file.					*//*--------------------------------------------------------------------------*/static void SetStationParamsKIR(StationPtr Station,Time_sec T,char *StatList){	StationInfoPtr StationInfo;	/* Set the station ID */	strncpy(Station->StationID,StatList,3);	Station->StationID[3] = '\0';		StationInfo = FindStationInfo(StatList);		/* Set the location of the station */	Station->Latitude  = StationInfo->Latitude;	Station->Longitude = StationInfo->Longitude;	/* Set the component markers */	strcpy(Station->Components,"XYZ");	/* Set the start time. End time is updated by GetKIRData routine */	Station->StartTime = T;}/*--------------------------------------------------------------------------*//* Round field values from pT into 0.1 nT (= factor 100). And also check for*//* missing data value.														*//*--------------------------------------------------------------------------*/static long Round100(long value){	if (value == MissingKIR) return MissingValue;	if (value > 0)		return ((value+50)/100);	else		return -((-value+50)/100);}/*--------------------------------------------------------------------------*//* Copy data from a single data line into proper OneDayBlock.				*//*--------------------------------------------------------------------------*/static void GetKIRData(StationPtr Station, char *Line,Time_sec Time){	OneDay_struct *p;	long *XPtr,*YPtr,*ZPtr,*TPtr;	long value;		/* Find the last OneDayBlock */	for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay);		/* Set the temperature value */	TPtr  = (p->T)+(p->TCount);	*TPtr = MissingValue;	p->TCount++;	/* Set the pointers within the OneDayBlock */	XPtr = (p->X)+(p->XCount);	YPtr = (p->Y)+(p->YCount);	ZPtr = (p->Z)+(p->ZCount);	/* Copy the data */		*XPtr = Round100(Get_long(Line+4));	*YPtr = Round100(Get_long(Line+8));	*ZPtr = Round100(Get_long(Line+12));		p->XCount++;	p->YCount++;	p->ZCount++;		/* Update the end time */	Station->EndTime = Time+Station->TimeStep;}/*--------------------------------------------------------------------------*//* Fill data points with missing value markers								*//*--------------------------------------------------------------------------*/static void AddMissingDataPoint(StationPtr Station){	OneDay_struct *p;	long *XPtr,*YPtr,*ZPtr,*TPtr;		/* Find the last OneDayBlock */	for (p = Station->FirstDay; p->NextDay != NULL; p = p->NextDay);		/* Set the temperature value */	TPtr  = (p->T)+(p->TCount);	*TPtr = MissingValue;	p->TCount++;	/* Set the pointers within the OneDayBlock */	XPtr = (p->X)+(p->XCount);	YPtr = (p->Y)+(p->YCount);	ZPtr = (p->Z)+(p->ZCount);	/* Copy the data */	*XPtr = MissingValue;	*YPtr = MissingValue;	*ZPtr = MissingValue;	p->XCount++;	p->YCount++;	p->ZCount++;		/* Update the end time */	Station->EndTime += Station->TimeStep;}/*--------------------------------------------------------------------------*//*	Here is the routine for reading KIR-format data file into memory.		*//*	The data is read into a Network structure (see MagnData.h for details).	*//*	See the comments at the beginning of this file for more details about	*//*	the parameters for this routine.										*//*																			*//*	The rounite works by reading one data line (40 bytes) at a time and 	*//*	adds that data into the stations data block. Because one doesn't know	*//*	a priori the amount of data in the data file first space for one day is	*//*	allocated. If there is more than one day then additional one day blocks	*//*	are allocated. At the end of the routine all one day blocks are			*//*	combined into a single data block.										*//*--------------------------------------------------------------------------*/long ReadKIR(char *FileName,NetworkPtr Network,char *StartTimeStr,			  char *EndTimeStr,char *StationList,Time_sec SampleStep){	FILE	*KIRfile;				/* The data file to be processed		*/	char	Buffer[16];				/* Buffer for one KIR data line			*/	Time_sec Time;					/* Time of the current data block   	*/	Time_sec PrevTime;				/* Time of the previous data block   	*/	Time_sec T;						/* Dummy time variable				   	*/	Time_sec StartTime;				/* Time of first record to be read		*/	Time_sec EndTime;				/* Time of record not read anymore		*/	Time_sec TimeStep;				/* Sampling rate in the KIR file		*/	StationPtr Station = NULL;		/* Pointer to the current station		*/	long	FirstLine = 1;			/* Flag for first valid data line		*/	InitNetwork(Network);			/* Initialize the fields of Network		*/	/* --- Set the start and end times --- */	if ((StartTimeStr == NULL) || (*StartTimeStr == '\0'))		StartTime = MIN_TIME;	else StartTime = StrToSecs(StartTimeStr,0);	if ((EndTimeStr == NULL) || (*EndTimeStr == '\0')) EndTime = MAX_TIME;	else EndTime = StrToSecs(EndTimeStr,0);	/* --- Try to open the file --- */	if ((KIRfile = fopen(FileName, "r")) == NULL) return FileError;	/* --- Find the sampling step in the data file --- */		if (SampleStep == 0) {		ReadKIRLine(KIRfile,Buffer);		Time = GetKIRTime(Buffer);		ReadKIRLine(KIRfile,Buffer);		TimeStep = GetKIRTime(Buffer) - Time;		rewind(KIRfile);	}	else		TimeStep = SampleStep;					/* --- Read the rest of the data into one day blocks ---*/ 	while (ReadKIRLine(KIRfile,Buffer))	{		if ((Time = GetKIRTime(Buffer)) >= EndTime) break;				Time = TimeStep*(Time/TimeStep);	/* Round to previous full 'TimeStep' second */		if (Time >= StartTime) {						if (FirstLine) {		/* First valid data line */				Station = AddNewStation(Network,TimeStep,TimeStep);				if (Station != NULL)					SetStationParamsKIR(Station,Time,StationList);				else		/* Unable to allocate memory for station data	*/					return(OutOfMemory);				FirstLine = 0;				PrevTime = Time-TimeStep;			}			if (PrevTime > Time) continue;		/* Neglect mysterious backward time jumps*/						if (Time == PrevTime) continue;		/* Neglect lines with same times */			for (T=PrevTime+TimeStep;T<Time;T += TimeStep) { /* Add missing data */				if (OneDayFull(Station,'Z')) {					if (AddOneDay(Station))						return(OutOfMemory); 	   /* Failed to allocate memory */				}				AddMissingDataPoint(Station);			}			if (OneDayFull(Station,'Z')) {				if (AddOneDay(Station))					return(OutOfMemory); 	   /* Failed to allocate memory */			}			GetKIRData(Station,Buffer,Time);			PrevTime = Time;		}	}	fclose(KIRfile);	/* --- Combine one day blocks into one large block ---*/	Station = Network->StationList;	while (Station != NULL) {		if (CombineData(Station) == OutOfMemory) return(OutOfMemory);		Station = Station->Next;	}	return OK;}
