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

DISPLAY_ERRORLOG.C

Z-World, 2001

Program to display the contents of the error log buffer.  Errors are
logged if ENABLE_ERROR_LOGGING in RabbitBios.c is #defined to 1.

This or other programs in this directory can be used to generate run
time errors or watchdog timeouts.  If run in debug mode, this
program's current error log will not be displayed until after this
program is recompiled and rerun on the target.  (In debug mode, the
flash copy of the previous program's error log is displayed.)

When a Dynamic C cold boot takes place, the error log header in RAM
is zeroed out to initialize it, but first it's contents are copied to
an address in the BIOS code before the BIOS in RAM is copied to
flash.  This means that on the second cold boot, the data structure
in flash will be zeroed out.  The configuration of the log buffer may
still be read, and the log buffer entries are not affected.

Because the fatal exception mechanism resets the processor by causing
a watchdog time out, the number of watchdog time outs reported is the
number of actual WDTOs plus the number of fatal exceptions.

The meaning of the bit-coded status byte is as follows:
bit 0   - An error has occurred since deployment.
bit 1   - The count of SW resets has rolled over.
bit 2   - The count of HW resets has rolled over.
bit 3   - The count of WDTOs has rolled over.
bit 4   - The count of exceptions has rolled over.
bit 5-6 - Not used.
bit 7   - The error log has been initialized.

The index of the last exception is the index from the start of the
error log entries.  If this index does not equal the total exception
count minus one, the error log entries have wrapped around the log
buffer.  The index of the last exception is reported as -1 when none
has occurred.

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

#class auto

// Add these lines to redirect printf output at 57600 baud to serial port A.
#define	STDIO_DEBUG_SERIAL	SADR
#define	STDIO_DEBUG_BAUD		57600

// Add this line to add carriage returns ('\r') to each newline char ('\n')
//  when sending printf output to a serial port.
#define	STDIO_DEBUG_ADDCR

#define	AINBUFSIZE	31
#define	AOUTBUFSIZE	31

// function prototypes
char *ErrCodeText(int errCode);

main()
{
	char mystr[10], *whichstr;
	int *ip, j;
	unsigned k, n;
	float f;

	printf("\n\n\n\n%s\n", errlogGetHeaderInfo());
	// the default is to display only valid entries
	n = (errLogInfo.ExceptionIndex > (unsigned) ERRLOG_NUM_ENTRIES)
	    ? (unsigned) ERRLOG_NUM_ENTRIES : errLogInfo.ExceptionIndex;

	printf("Type a digit to display a selection of error log entries.\n\n");
	whichstr = ((OPMODE & 0x08) == 0x08) ? " previous " : " ";
	printf("0:  no error log entries\n");
	printf("1:  the %u valid%serror log entries only\n", n, whichstr);
	printf("2:  all %u%serror log entries\n", ERRLOG_NUM_ENTRIES, whichstr);
	switch ((int) getchar()) {
	case (int) '0':
		// have chosen to display no entries instead
		n = 0;
	case (int) '1':
	default:
		// have chosen to keep the default display entries
		break;
	case (int) '2':
		// have chosen to display all entries instead
		n = ERRLOG_NUM_ENTRIES;
		break;
	}
	printf("\n\n\n\n");

	// initial displayed entry is the nth one before the current exception index
	k = (errLogInfo.ExceptionIndexMod + ERRLOG_NUM_ENTRIES - n)
	    % ERRLOG_NUM_ENTRIES;

	for (j = 0; j < n; ++j, ++k) {
		k %= (unsigned) ERRLOG_NUM_ENTRIES;
		if (!errlogGetNthEntry(k)) {
			printf("Entry %d (%s):\n", k, ErrCodeText((int) errLogEntry.errType));
			printf("%s\n", errlogFormatEntry());
			printf("%s\n", errlogFormatStackDump());
			printf("%s\n", errlogFormatRegDump());
		} else {
			printf("Checksum Error\n");
		}
	}

	// Explain why, if in debug mode and if the following offer to generate a
	//  run time error is taken up, such generated run time errors will not be
	//  correctly displayed until this program is recompiled and rerun on the
	//  target, so that the error log is copied into flash.
	if ((OPMODE & 0x08) == 0x08) {
		// display information about flash copy of error log only in debug mode!
		printf("\n\n\n\nNB:  In debug mode, this program's displayed error log ");
		printf("header\n     information is taken from the flash copy of the pr");
		printf("evious\n     program's error log.  Thus, even though the curren");
		printf("t error log\n     is updated in RAM, the displayed error log he");
		printf("ader information\n     will not change until this program is re");
		printf("compiled and rerun.\n");
	}

	printf("\n\nType a digit to generate a run time error or reset,\n");
	printf("or press the Enter key to bypass all run time errors.\n\n");
	printf("0:  bad pointer (228)\n");
	printf("1:  bad array index (229)\n");
	printf("2:  domain (234)\n");
	printf("3:  range (235)\n");
	printf("4:  integer divide by zero (240)\n");
	printf("5:  unexpected interrupt (241))\n");
	printf("6:  virtual watchdog time out (244)\n");
	printf("7:  bad xalloc (245)\n");
	if ((OPMODE & 0x08) == 0x00) {
		// these items are available only in run mode!
		printf("8:  software reset (no error logged)\n");
		printf("9:  watchdog time out (no error logged)\n");
	}
	switch ((int) getchar()) {
	case (int) '0':	// bad pointer (228)
		ip = (int *) 0x0000;
		*ip = 4;
		break;
	case (int) '1':	// bad array index (229)
		j = sizeof(mystr);
		mystr[j] = 'Q';
		break;
	case (int) '2':	// domain (234)
		f = acos(2);
		break;
	case (int) '3':	// range (235)
		f = fmod(1, 0);
		break;
	case (int) '4':	// integer divide by zero (240)
		j = 0;
		1 / j;
		break;
	case (int) '5':	// unexpected interrupt (241)
		asm   rst   10h
		break;
	case (int) '6':	// virtual watchdog time out (244)
		j = VdGetFreeWd(3);
		while(1);
		break;
	case (int) '7':	// bad xalloc (245)
		xalloc(0xFFFFFFFFL);
		break;
	case (int) '8':	// software reset (no error logged)
		if ((OPMODE & 0x08) == 0x00) {
			// this item is available only in run mode!
			//  (it would confuse the debug kernel)
			forceSoftReset();
		}
		break;
	case (int) '9':	// watchdog time out (no error logged)
		if ((OPMODE & 0x08) == 0x00) {
			// this item is available only in run mode!
			//  (it would cause loss of target communication)
			asm   ipset 3
			while(1);
		}
	default:				// no error or reset
		break;
	}
}

const struct {
	char *errText;
	int errCode;
} ErrDesc[] = {
	{ "ERR_LZINPUTBUFFERS", 226 },
	{ "ERR_LZOUTPUTBUFFERS", 227 },
	{ "ERR_BADPOINTER", 228 },
	{ "ERR_BADARRAYINDEX", 229 },
	{ "ERR_STACKCORRUPTED", 230 },	// (not currently used)
	{ "ERR_STACKOVERFLOW", 231 },		// (not currently used)
	{ "ERR_AUXSTACKOVERFLOW", 232 },	// (not currently used)
	{ "ERR_DOMAIN", 234 },
	{ "ERR_RANGE", 235 },
	{ "ERR_FLOATOVERFLOW", 236 },
	{ "ERR_LONGDIVBYZERO", 237 },
	{ "ERR_LONGZEROMODULUS", 238 },
	{ "ERR_BADPARAMETER", 239 },
	{ "ERR_INTDIVBYZERO", 240 },
	{ "ERR_UNEXPECTEDINTRPT", 241 },
	{ "ERR_CORRUPTEDCODATA", 243 },
	{ "ERR_VIRTWDOGTIMEOUT", 244 },
	{ "ERR_BADXALLOC", 245 },
	{ "ERR_BADSTACKALLOC", 246 },
	{ "ERR_BADSTACKDEALLOC", 247 },
	{ "ERR_BADXALLOCINIT", 249 },
	{ "ERR_NOVIRTWDOGAVAIL", 250 },
	{ "ERR_INVALIDMACADDR", 251 },
	{ "ERR_INVALIDCOFUNC", 252 },
	{ "ERR_TCPSOCKETISAUTO", 253 },
	{ "Unknown exception code!", 0 }	// last entry must have error code 0
};

char *ErrCodeText(int findCode)
{
	int i;

	i = 0;
	while (ErrDesc[i].errCode && (ErrDesc[i].errCode != findCode)) ++i;
	return ErrDesc[i].errText;
}

