/*
 * bbdump.c - Tool to pretty print the contents of the Black Box from 
 *            HLC firmware memory.
 *
 * $Id: bbdump.c,v 1.2 1999/03/22 16:24:07 rick Exp $
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>

#include "feptypes.h"
#include "triglbl.h"
#include "dxbglbl.h"
#include "fepglbl.h"
#include "hou2mmap.h"
#define DENSE 1
#include "events.h"			/* From ../../libcsc/csc/include */
#include "status.h"			/* From ../../libcsc/csc/include */
typedef int int32;
#include "blackbox.h"
#include "evtbl.h"			/* From ../vocal/ */
#include "bbevents.h" 


void usage(void);
int chunkcompare(const void *, const void *);
char *ev2str(unsigned long event);
char *vocal_ev2str(unsigned long event);
char *digi_ev2str(unsigned long event);


int main(int argc, char *argv[])
{
	int info=0, count=0, numevents=0;
	char *vaddr;
	ulong gco;
	GLOBAL_FEP_DATA *gfd;
	BLACKBOX_CTRL *bb;
	BLACKBOX_DATA *bbdata, *bbdataend, *bbdatain, *bbdatabeg;
	int devicefd, c;
	long rc, memsize=0;
	char junkbuf[4096];

	while((c=getopt(argc, argv, "ci")) != EOF) {
		switch(c) {
			case 'c':
				count = 1;
				break;
			case 'i':
				info = 1;
				break;
			default:
				usage();
		}
	}

	if(argc-optind != 1) {
		usage();
	}

	if((devicefd=open(argv[optind], O_RDONLY)) < 0) {
		fprintf(stderr, "Can't open '%s': %s\n", argv[optind], strerror(errno));
		exit(1);
	}

	/*
	 * Determine size of RAM device file.  Okay, okay, so this is a really
	 * corny way of determing RAM size.  I thought it was the most portable
	 * way without having to first mmap() the device file in or requiring the
	 * driver to implement the lseek() hook for the RAM minor devices.
	 */
	while((rc=read(devicefd, junkbuf, 4096)) > 0) {
		memsize += rc;
	}

	vaddr = (uchar *) mmap((caddr_t) 0, memsize, PROT_READ, 
										MAP_SHARED, devicefd, 0x00000000);

	if(vaddr == (void *)-1) {
		fprintf(stderr, "Can't mmap '%s': %s\n", argv[optind], strerror(errno));
		exit(1);
	}

	/*
	 *	Get pointer to global common area
	 */
	gco = * (ulong *) (vaddr + GLOBAL_DATA_OFFSET);

	if(gco == 0) {
		fprintf(stderr, "Error: Invalid Global Data Offset value!\n");
		exit(1);
	}

	gfd = (GLOBAL_FEP_DATA *) (vaddr + gco);

	if(gfd->common.magic != MAGIC_FEP) {
		fprintf(stderr, "Error: Global FEP Data Magic incorrect!\n");
		exit(1);
	}

	bb = (BLACKBOX_CTRL *) (vaddr + gfd->blackbox);


	if(info) {
		printf("   buf = 0x%x\n"
		       "bufend = 0x%x\n"
		       "    in = 0x%x\n", bb->buf, bb->bufend, bb->in);
	}


	bbdatain  = (BLACKBOX_DATA *) (vaddr + ((unsigned int)bb->in - 0x80000000));
	bbdataend = (BLACKBOX_DATA *) 
			(vaddr + ((unsigned int)bb->bufend - 0x80000000));
	bbdatabeg = (BLACKBOX_DATA *) 
			(vaddr + ((unsigned int)bb->buf - 0x80000000));

	bbdata = bbdatain - 1;	/* We want to start with the most recent event */

	while(bbdata >= bbdatabeg && bbdata->event) {
		if(!info && !count)
			printf("0x%08x %-45s 0x%08x 0x%08x\n", bbdata->timestamp, 
				ev2str(bbdata->event), bbdata->data[0], bbdata->data[1]);
		++numevents;
		--bbdata;
	}

	for(bbdata=bbdataend-1; bbdata >= bbdatain && bbdata->event; --bbdata) {
		if(!info && !count)
			printf("0x%08x %-45s 0x%08x 0x%08x\n", bbdata->timestamp, 
				ev2str(bbdata->event), bbdata->data[0], bbdata->data[1]);
		++numevents;
	}

	if(count || info) 
		printf("%d total events in Black Box.\n", numevents);

	close(devicefd);

	exit(0);
}


char *ev2str(unsigned long event)
{
	if(event & BB_DIGI_EVENT) 
		return(digi_ev2str(event));
	else
		return(vocal_ev2str(event));
}


char *digi_ev2str(unsigned long event)
{
	static char retstr[16];
	EVMAP *eptr;
	int i=0;

	while(i < sizeof(DigiEvMap)/sizeof(EVMAP)) {
		eptr = &DigiEvMap[i];

		if(eptr->num == event)
			return(eptr->name);

		++i;
	}		

	sprintf(retstr, "(0x%x)", event);
	return(retstr);
}

char *vocal_ev2str(unsigned long event)
{
	static char retstr[16];
	EVMAP *eptr;
	int i=0;

	while(i < sizeof(EvMap)/sizeof(EVMAP)) {
		eptr = &EvMap[i];

		if(eptr->num == event)
			return(eptr->name);

		++i;
	}		

	sprintf(retstr, "(0x%x)", event);
	return(retstr);
}


void usage(void)
{
	fprintf(stderr, "usage: bbdump [-i] [-c] <ram-device|corefile>\n"
					"         No options: Print events\n"
					"         -i prints Black Box info\n"
					"         -c returns number of events in Black Box\n");
	exit(1);
}
