/******************************************************************************
** Copyright 2015 MBARI - Monterey Bay Aquarium Research Institute
*******************************************************************************
*******************************************************************************
** Summary  : ISUS and DuraFET Controller Code for the ARGO Profiling Float (APF).
** Filename : msc_main.c
** Author   : Luke Coletti
** Project  :
** Version  : 1.0
** Compiler : MetroWerks Code Warrior v8.3
** Created  : 12/15/14
** Archived :
*******************************************************************************
** Modification History:
** 01/02/15 : CF2 Port, LJC
*******************************************************************************/
#include        <cfxpico.h>             // Persistor PicoDOS Definitions

#include        <assert.h>
#include        <ctype.h>
#include        <errno.h>
#include        <float.h>
#include        <limits.h>
#include        <locale.h>
#include        <math.h>
#include        <setjmp.h>
#include        <signal.h>
#include        <stdarg.h>
#include        <stddef.h>
#include        <stdio.h>
#include        <stdlib.h>
#include        <string.h>
#include        <time.h>
#include		<mc68332.h>

#include        <dirent.h>              // PicoDOS POSIX-like Directory Access Defines
#include        <dosdrive.h>    		// PicoDOS DOS Drive and Directory Definitions
#include        <fcntl.h>               // PicoDOS POSIX-like File Access Definitions
#include        <stat.h>                // PicoDOS POSIX-like File Status Definitions
#include        <termios.h>             // PicoDOS POSIX-like Terminal I/O Definitions
#include        <unistd.h>              // PicoDOS POSIX-like UNIX Function Definitions

#include        <apf_main.h>

// CRC32 macro
#include "icrctab.c"

/* Local Defines */
#define ACKBUFSIZE      32
#define CMDBUFSIZE      64
#define DATBUFSIZE      2048

/* Application Build Info */
char bfile[20] = __FILE__;
char bdate[20] = __DATE__;
char btime[20] = __TIME__;

/******************************************************************************\
**	main - include all global variables
\******************************************************************************/
#include        "apf_var_sys.c"
#include        "apf_var_isus.c"
#include        "apf_var_dura.c"

void main( void )
{
	short result = 0;       // no errors so far
	char   *dbuf;
	char   *ebuf;
	char abuf[ACKBUFSIZE];
	char cbuf[CMDBUFSIZE];
	char   *srchptr, *endptr;
	ushort Rx_chars, Rx_loop;
	int i, ret, CMD_char;
	int gotVal, gotSample, missedSleeps;
	int lambda_beg, lambda_end;
	ulong input_var;
	time_t CTD_Time;
	long Erecs;
	fpos_t Efpos;
	float acquire_time, CTD_Temp, CTD_Salinity, CTD_Depth;
	WhatWokeSuspend suspret;


	InitMSC();

	if( (dbuf = calloc((size_t)DATBUFSIZE, sizeof(char))) == NULL ) {
		printf("main() Can't allocate DAT BUF!\n");
		IOPwrDown();
		BIOSResetToPicoDOS();
	}
	if( (ebuf = calloc((size_t)ERRBUFSIZE, sizeof(char))) == NULL ) {
		printf("main() Can't allocate ERR BUF!\n");
		IOPwrDown();
		BIOSResetToPicoDOS();
	}

	if( (Erecs = CalcRecsPending((uchar)ERRORLOG_FILE)) > 0 )
		printf("\n  There are %ld records in the error file!\n", Erecs);

	printf("\n\n  MBARI Sensor Controller (ISUS/DURA) Initialized\n");
	printf("\n  Auto Shutdown in %hu hours at: %s", sys_apf_tmout, ctime(&alarm_time) );
	printf("  Entering Suspend Mode, Serial Input (/WAKE) will wake me, send M for Menu Mode \n");

	gotSample = FALSE;
	missedSleeps  = 0;


/******************************************************************************\
**	start suspend mode
\******************************************************************************/

nightynite:

	IOPwrDown();
	SCIRxFlush();
	suspret = PWRSuspendUntil( alarm_time, true, WakeTmtOrWAKEFall );
	if( (RegIO_RdWord() & SYS_POR_MON) == 0 ) {             //was power removed during a suspend cycle?
		PWRSuspendTicks(1, true, WakeOnTimeout);        	//quickly clear the SRAM keys
		printf("\n!!!Power Failure during Suspend!!!\n");
		sprintf(ebuf, "Power Failure during Suspend");
		LogErrorMsg(ebuf, (int)POWER_FAIL_SUSPEND, sys_message_enable);
		BIOSReset();     									//reboot the application
	}
	wake_time = RTCGetTime( NULL, NULL );
	IOPwrUp();
	SCIRxFlush();


	if( suspret == WokeFromTimeout ) {

		if( gotSample == FALSE )
			sprintf(ebuf, "Alarm Time Expired with no sample - Entering back into Suspend");
		else
			sprintf(ebuf, "Alarm Time Expired with a sample - Entering back into Suspend");
		LogErrorMsg(ebuf, (int)ALARM_TIME_TIMEOUT, sys_message_enable);

		alarm_time = wake_time + (ulong)(sys_apf_tmout * 3600);

		goto nightynite;

	} //end WokeFromTimeout


	if( suspret == WokeNeverSuspending ) {

		++missedSleeps;

		if( missedSleeps > 1000 ) {
			if( gotSample == FALSE )
				sprintf(ebuf, "Max Alarm misses reached with no sample - Powering Down");
			else
				sprintf(ebuf, "Max Alarm misses reached with a sample - Powering Down");
			LogErrorMsg(ebuf, (int)MAX_SLEEP_TIME_MISSED, sys_message_enable);

			SysShutDown();
		}
		else{
			alarm_time = wake_time + (ulong)(sys_apf_tmout * 3600);
			tp = localtime(&alarm_time);
			sprintf(ebuf, "System Alarm set to a time of future past - New Alarm Time is %02d/%02d/%02d %02d:%02d:%02d", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec);
			LogErrorMsg(ebuf, (int)SLEEP_TIME_MISSED, sys_message_enable);
		}

		goto nightynite;

	} //end WokeNeverSuspending


/******************************************************************************\
**	end suspend mode
\******************************************************************************/


/******************************************************************************\
**	start command mode
\******************************************************************************/

	if( suspret == WokeTmtOrWAKEFall ) {

		//clear the Sensor Mode on each entry
		sys_sensor_mode = 0;

		//clear the data buffer on each entry
		gotSample = FALSE;
		memset(dbuf, '\0', sizeof(dbuf));

		//clear the CTD values on each entry
		CTD_Time = 0;
		acquire_time = CTD_Temp = CTD_Salinity = CTD_Depth = -1.0;

		//clear the file position values on each entry
		Efpos    = 0L;

		//clear the timeout and byte counter on each entry
		Rx_loop  = 0;
		Rx_chars = 0;

		//loop timeout in 15secs
		while( Rx_loop <= 150 ) {

#include "apf_cmds.c"

		} // end Rx_loop while

		if(Rx_chars == 0) {
			sprintf(ebuf, "Comms wakeup but NO chars received");
			LogErrorMsg(ebuf, (int)COMMAND_MODE_EMPTY, sys_message_enable);
		}

		current_time = RTCGetTime( NULL, NULL );
		if( current_time >= alarm_time ) {
			sprintf(ebuf, "Alarm behind due to comms wakeup - Resync will now occur");
			LogErrorMsg(ebuf, (int)ALARM_TIME_STALE, sys_message_enable);
		}

		goto nightynite;

	} //end WokeTmtOrWAKEFall


/******************************************************************************\
**	end command mode
\******************************************************************************/

	sprintf(ebuf, "MYSTERY WAKEUP! Suspend ret = %d", suspret);
	LogErrorMsg(ebuf, (int)MYSTERY_WAKEUP, sys_message_enable);

	current_time = RTCGetTime( NULL, NULL );
	if( current_time >= alarm_time ) {
		sprintf(ebuf, "Alarm behind due to mystery wakeup - Resync will now occur");
		LogErrorMsg(ebuf, (int)ALARM_TIME_STALE, sys_message_enable);
	}

	goto nightynite; // DON'T ASK, it's a mystery!


} // end main


/******************************************************************************\
**	data acquisition functions
\******************************************************************************/

int TakeDuraSample(char *dbuf, float *atime, ulong CTD_Time, float CTD_Temp, float CTD_Salinity, float CTD_Depth)
{
	char   *tbuf;
	char   *ebuf;
	char   *tmbuf;
	ushort crc;
	float sd, StdDevVrs, StdDevVk;
	float VrsExt, backupVoltage, Vk, Ik, Ib;
	float pH;
	ldiv_t sdiv;
	RTCTimer ElpTm;

	*atime = -1.0;

	RTCElapsedTimerSetup( &ElpTm );

	HIH6130_ReadTempHumidity(&sysTemperature, &sysHumidity);

	if( AtodPowerOn() == TRUE ){
		if( AtodEnable() != TRUE )
			if( AtodReset() != TRUE )
				return( ERROR );
	}
	else
		return( ERROR );

	AtodReadValue(DURAFET_BATT, dura_atod_delay, 1, &backupVoltage, &sd);

	// Must set PGA scaling factors in DuraAcquireData(), AtodProcessValue(), and AtodSelectValue() too!
	//AtodReadValue(DURAFET_IB_32, dura_atod_delay, 1, &Ib, &sd);
	AtodReadValue(DURAFET_IB_4, dura_atod_delay, 1, &Ib, &sd);

	AtodReadValue(DURAFET_IK_32, dura_atod_delay, 1, &Ik, &sd);
	
	AtodReadValue(DURAFET_VK, dura_atod_delay, 5, &Vk, &StdDevVk);

	AtodReadValue(DURAFET_VRS_EXT, dura_atod_delay, dura_atod_readings, &VrsExt, &StdDevVrs);

	INA219_ReadVoltageCurrent(&sysVoltage, &sysCurrent);

	AtodPowerOff();

	dura_sample_time = RTCGetTime( NULL, NULL );
	tp = localtime(&dura_sample_time);

	pH = 7.1234;

	if( (tbuf = calloc((size_t)DATBUFSIZE, sizeof(char))) == NULL ) {
		if( (ebuf = calloc((size_t)ERRBUFSIZE, sizeof(char))) == NULL )
			return( ERROR );
		sprintf(ebuf, "CAN'T allocate TakeSample() tbuf memory");
		LogErrorMsg(ebuf, (int)MALLOC_FAILURE, sys_message_enable);
		free(ebuf);
		return( ERROR );
	}
	//pH Vbat Vrs SD Vk  SD Ik    Ib
	sprintf(tbuf, "pH,%02d/%02d/%02d %02d:%02d:%02d,%lu,%.2f,%.4f,%.4f,%lu,%lu,%lu,%.2f,%.2f,%.3f,%.3e,%.4f,%.3f,%+f,%f,%+f,%f,%+.3e,%+.3e",
	        tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec,
	        CTD_Time, CTD_Depth, CTD_Temp, CTD_Salinity,
	        dura_sample_ctr, sys_por_ctr, dura_error_ctr,
	        sysTemperature, sysHumidity, sysVoltage, sysCurrent,
	        pH, backupVoltage, VrsExt, StdDevVrs, Vk, StdDevVk, Ik, Ib);

	dat_file = OpenApfLogFile( DURA_DATA_FILE );
	if( dat_file != FNULL ) {
		if( dura_reset_flag == TRUE ) {
			OutputDuraHeader(dat_file);
			dura_reset_flag = FALSE;
		}
		fprintf(dat_file, "%s\n", tbuf);
		fclose(dat_file);
	}

	crc = fCrc16Bit((const unsigned char *)tbuf);
	sprintf(dbuf,"0x%04X,%s", crc, tbuf);
	free(tbuf);

	++dura_sample_ctr;
	DS3234_WrSRAM(DURA_SAMPLECTR_PTR, sizeof(ulong), (ulong*)&dura_sample_ctr);
	DS3234_WrSRAM(DURA_LASTSAMPTIME_PTR, sizeof(ulong), (ulong*)&dura_sample_time);

	sdiv = ldiv(RTCElapsedTime( &ElpTm ), 1000000L);
	if( (tmbuf = calloc((size_t)40, sizeof(char))) != NULL ) {
		sprintf(tmbuf, "%ld.%.6ld", sdiv.quot, sdiv.rem);
		*atime = atof(tmbuf);
		free(tmbuf);
	}

	return( OK );

}

int TakeIsusSample(char *dbuf, float *atime, ulong CTD_Time, float CTD_Temp, float CTD_Salinity, float CTD_Depth)
{
	char   *tbuf;
	char   *ebuf;
	char   *tmbuf;
	ushort crc;
	int i, ret;
	double ref_ch_mean, ref_ch_sd, dc_mean, dc_sd, sw_dc_mean;
	double isus_no3, isus_sal, isus_hs, isus_err;
	ldiv_t sdiv;
	RTCTimer ElpTm;

	*atime = -1.0;

	RTCElapsedTimerSetup( &ElpTm );

	dat_file = OpenApfLogFile( ISUS_DATA_FILE );
	if( dat_file != FNULL ) {
		if( isus_reset_flag == TRUE ) {
			OutputIsusHeader(dat_file);
			isus_reset_flag = FALSE;
		}
	}

	if( SpecPwrOn( &SpecPort ) != TRUE ) {
		if( dat_file != FNULL )
			fclose(dat_file);
		return( ERROR );
	}

	DelayMilliSecs( 500 );

    if( ScanSpectra( SpecPort, dat_file, 1, DarkData, DARKCURRENT_SCAN ) != TRUE ){
		if( dat_file != FNULL )
		  fclose(dat_file);
		LampPwrOff();
	    SpecPwrOff( SpecPort );
		return( ERROR );
	}			
	dc_mean = DataMean;         //value set in ScanSpectra()
	dc_sd   = DataStdDev;       //value set in ScanSpectra()

	LampPwrOnUsingSpec( SpecPort, SpecData, FALSE );
	ref_ch_mean = DataMean;		//value set in LampPwrOnUsingSpec() = MaxPixelInten
	ref_ch_sd   = DataStdDev;	//value set in LampPwrOnUsingSpec() = MinPixelInten
		
    if( ScanSpectra( SpecPort, dat_file, 1, SpecData, INTENSITY_SCAN ) != TRUE ){
		if( dat_file != FNULL )
		  fclose(dat_file);
		LampPwrOff();
	    SpecPwrOff( SpecPort );
		return( ERROR );
	}			

	if( dat_file != FNULL )
		fclose(dat_file);

	INA219_ReadVoltageCurrent( &sysVoltage, &sysCurrent );

	LampPwrOff();
	SpecPwrOff( SpecPort );

	isus_sal       = -1.0;      //initialize prior to fit
	isus_no3       = -1.0;
	isus_hs        = -1.0;
	isus_err       = -1.0;

	if( Ecoefs == 256 ) {
		if( isus_tcomp_mode == TRUE ) {
			if( CTD_Time != 0 ) //time will be zero if CTD values are not passed
				XformSwEcoefs(EcoefFile, EcoefData, LambdaData, TcompCoefs, SwCalTemp, CTD_Temp);
			else
				CopySwEcoefs(EcoefFile, EcoefData);

			FitData[SALINITY]=0.0; //force salinity term to get FIT, see linfit.c

			if( (isus_salfit_mode == FIX) && (CTD_Time != 0) )
				FitData[SALINITY]=CTD_Salinity;
		} //end tcomp if
		else{
			CopySwEcoefs(EcoefFile, EcoefData); //always start fresh
			FitData[SALINITY]=0.0; //always fit salinity if Br Tcomp isn't enabled
		}

		//CalcAbs() expects the ScanData to begin at 0 and the ZeroData and AbsData to begin at 1, confused, read on...
		CalcAbs(&ZeroData[isus_pixel_beg-1], &SpecData[isus_pixel_beg-1], &AbsData[0], dc_mean, isus_fit_pixels);

		//LinFit() expects array data to begin at 1, therefore passed data values (Ecoef, Lambda and Abs) should point one back, Absorbance Data should start at AbsData[1], see CalcAbs(), above.
		ret = LinFit(&EcoefData[isus_pixel_beg-1], &LambdaData[isus_pixel_beg-1], &AbsData[0], &AbsFitData[0], &ResidualsData[0], &FitData[0], isus_fit_pixels, isus_fit_concs, isus_bsl_model);

		if( ret != TRUE ) {
			if( (ebuf = calloc((size_t)ERRBUFSIZE, sizeof(char))) == NULL )
				return( ERROR );
			sprintf(ebuf, "Spectra Fitting Error LinFit() ret = %d", ret);
			LogErrorMsg(ebuf, (int)NRC_FIT_FAILURE, sys_message_enable);
			free(ebuf);
		}
		else{
			isus_sal = FitData[SALINITY];
			isus_no3 = FitData[NITRATE];
			isus_hs  = FitData[BISULFIDE];
			isus_err = FitData[FIT_ERROR];
		}
	}

	tp = localtime(&isus_sample_time);

	if( (tbuf = calloc((size_t)DATBUFSIZE, sizeof(char))) == NULL ) {
		if( (ebuf = calloc((size_t)ERRBUFSIZE, sizeof(char))) == NULL )
			return( ERROR );
		sprintf(ebuf, "CAN'T allocate TakeSample() tbuf memory");
		LogErrorMsg(ebuf, (int)MALLOC_FAILURE, sys_message_enable);
		free(ebuf);
		return( ERROR );
	}

	sprintf(tbuf, "A,%02d/%02d/%02d %02d:%02d:%02d,%lu,%.2f,%.4f,%.4f,%lu,%lu,%lu,%lu,%.2f,%.2f,%.3f,%.3e,%.2lf,%.2lf,%.2lf,%.2lf,%.2lf,%.2lf,%.3le,%d,%d,",
	        tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec,
	        CTD_Time, CTD_Depth, CTD_Temp, CTD_Salinity,
	        isus_sample_ctr, sys_por_ctr, isus_error_ctr, sys_error_ctr,
	        sysTemperature, sysHumidity, sysVoltage, sysCurrent,
	        ref_ch_mean, ref_ch_sd, dc_mean, dc_sd,
	        isus_sal, isus_no3, isus_err, isus_datpixel_beg, isus_datpixel_end);

	if( (isus_datpixel_beg > 0) && (isus_datpixel_end <= 256) ) {
		for( i = isus_datpixel_beg; i <= isus_datpixel_end; i++ ) {
			sprintf(tbuf+strlen(tbuf), "%04X", SpecData[i-1]);
		}
	}

	sw_dc_mean = 0.0;
	for( i = 0; i < 5; i++ )
		sw_dc_mean += (double)SpecData[i];
	sw_dc_mean = sw_dc_mean/5.0;
	sprintf(tbuf+strlen(tbuf), ",%.1lf", sw_dc_mean);

	crc = fCrc16Bit((const unsigned char *)tbuf);

	sprintf(dbuf,"0x%04X,%s", crc, tbuf);

	free(tbuf);

	++isus_sample_ctr;
	DS3234_WrSRAM(ISUS_SAMPLECTR_PTR, sizeof(ulong), (ulong*)&isus_sample_ctr);
	DS3234_WrSRAM(ISUS_LASTSAMPTIME_PTR, sizeof(ulong), (ulong*)&isus_sample_time);

	sdiv = ldiv(RTCElapsedTime( &ElpTm ), 1000000L);
	if( (tmbuf = calloc((size_t)40, sizeof(char))) != NULL ) {
		sprintf(tmbuf, "%ld.%.6ld", sdiv.quot, sdiv.rem);
		*atime = atof(tmbuf);
		free(tmbuf);
	}

	return( OK );

}

int TakeIsusPseudoSample(char *dbuf, float *atime, ulong CTD_Time, float CTD_Temp, float CTD_Salinity, float CTD_Depth)
{
	char   *tbuf;
	char   *ebuf;
	char   *tmbuf;
	ushort crc;
	int i;
	double ref_ch_mean, ref_ch_sd, dc_mean, dc_sd, sw_dc_mean;
	double isus_no3, isus_sal, isus_hs, isus_err;
	ldiv_t sdiv;
	RTCTimer ElpTm;

	*atime = -1.0;

	RTCElapsedTimerSetup( &ElpTm );

	HIH6130_ReadTempHumidity( &sysTemperature, &sysHumidity );

	dat_file = OpenApfLogFile( ISUS_DATA_FILE );
	if( dat_file != FNULL ) {
		if( isus_reset_flag == TRUE ) {
			OutputIsusHeader(dat_file);
			isus_reset_flag = FALSE;
		}
	}

	if( SpecPwrOn( &SpecPort ) != TRUE ) {
		if( dat_file != FNULL )
			fclose(dat_file);
		return( ERROR );
	}

	DelayMilliSecs( 500 );

	isus_sample_time = RTCGetTime( NULL, NULL );
	tp = localtime(&isus_sample_time);
	DelayMilliSecs( isus_spec_period );

	dc_mean   = 435.23;
	dc_sd     = 4.31;
	if( dat_file != FNULL ) {
		fprintf(dat_file,"D,%02d/%02d/%02d %02d:%02d:%02d,%.2f,%.2f,%.2f,", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec, sysTemperature, dc_mean, dc_sd);
		for(i = 1; i <= 256; i++) {
			if(i != 256) {
				if( (Zcoefs > 0) || (Ecoefs == 256) )
					fprintf(dat_file, "%.1f,", LambdaData[i]);
				else
					fprintf(dat_file, "%05d,", i);
			}
			else{
				if( (Zcoefs > 0) || (Ecoefs == 256) )
					fprintf(dat_file, "%.1f\n", LambdaData[i]);
				else
					fprintf(dat_file, "%05d\n", i);
			}
		} //end i loop
	} //end FNULL if


	LampPwrOn();

	isus_sample_time = RTCGetTime( NULL, NULL );
	tp = localtime(&isus_sample_time);
	DelayMilliSecs( isus_spec_period );

	ref_ch_mean = 1022.16;
	ref_ch_sd   = 1.67;
	if( dat_file != FNULL ) {
		fprintf(dat_file,"S,%02d/%02d/%02d %02d:%02d:%02d,%.2f,%.2f,%.2f,", tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec,sysTemperature, ref_ch_mean, ref_ch_sd);
		for(i = 1; i <= 256; i++) {
			if(i != 256) {
				if( (Zcoefs > 0) || (Ecoefs == 256) )
					fprintf(dat_file, "%.1f,", LambdaData[i]);
				else
					fprintf(dat_file, "%05d,", i);
			}
			else{
				if( (Zcoefs > 0) || (Ecoefs == 256) )
					fprintf(dat_file, "%.1f\n", LambdaData[i]);
				else
					fprintf(dat_file, "%05d\n", i);
			}
		} //end i loop

		fclose(dat_file);
	} //end FNULL if

	INA219_ReadVoltageCurrent( &sysVoltage, &sysCurrent );

	LampPwrOff();
	SpecPwrOff( SpecPort );

	isus_sal       = 32.57;
	isus_no3       = 12.35;
	isus_hs        = -1.0;
	isus_err       = 0.0001245;

	if( CTD_Time != 0 ) {           //time will be zero if CTD values are not passed
		if( (isus_salfit_mode == FIX) && (CTD_Time != 0) )
			isus_sal=CTD_Salinity;
	}

	if( (tbuf = calloc((size_t)DATBUFSIZE, sizeof(char))) == NULL ) {
		if( (ebuf = calloc((size_t)ERRBUFSIZE, sizeof(char))) == NULL )
			return( ERROR );
		sprintf(ebuf, "CAN'T allocate TakeSample() tbuf memory");
		LogErrorMsg(ebuf, (int)MALLOC_FAILURE, sys_message_enable);
		free(ebuf);
		return( ERROR );
	}

	sprintf(tbuf, "A,%02d/%02d/%02d %02d:%02d:%02d,%lu,%.2f,%.4f,%.4f,%lu,%lu,%lu,%lu,%.2f,%.2f,%.3f,%.3e,%.2lf,%.2lf,%.2lf,%.2lf,%.2lf,%.2lf,%.3le,%d,%d,",
	        tp->tm_mon+1, tp->tm_mday, tp->tm_year+1900, tp->tm_hour, tp->tm_min, tp->tm_sec,
	        CTD_Time, CTD_Depth, CTD_Temp, CTD_Salinity,
	        isus_sample_ctr, sys_por_ctr, isus_error_ctr, sys_error_ctr,
	        sysTemperature, sysHumidity, sysVoltage, sysCurrent,
	        ref_ch_mean, ref_ch_sd, dc_mean, dc_sd,
	        isus_sal, isus_no3, isus_err, isus_datpixel_beg, isus_datpixel_end);

	for( i = isus_datpixel_beg; i <= isus_datpixel_end; i++ ) {
		sprintf(tbuf+strlen(tbuf), "%04X", i);
	}

	sw_dc_mean = 411.35;
	sprintf(tbuf+strlen(tbuf), ",%.1lf", sw_dc_mean);

	crc = fCrc16Bit((const unsigned char *)tbuf);

	sprintf(dbuf,"0x%04X,%s", crc, tbuf);

	free(tbuf);

	++isus_sample_ctr;
	DS3234_WrSRAM(ISUS_SAMPLECTR_PTR, sizeof(ulong), (ulong*)&isus_sample_ctr);
	DS3234_WrSRAM(ISUS_LASTSAMPTIME_PTR, sizeof(ulong), (ulong*)&isus_sample_time);

	sdiv = ldiv(RTCElapsedTime( &ElpTm ), 1000000L);
	if( (tmbuf = calloc((size_t)40, sizeof(char))) != NULL ) {
		sprintf(tmbuf, "%ld.%.6ld", sdiv.quot, sdiv.rem);
		*atime = atof(tmbuf);
		free(tmbuf);
	}

	return( OK );

}


//*****************************************************************************
// It's all one big fat nasty "compilation unit"
//*****************************************************************************
#include "apf_init.c"
#include "apf_util.c"
#include "apf_menu.c"
