/*******************************************************************************
 *	HexFile.cpp	Hex File Access
 *			T.Barnaby,	Beam Ltd,	2008-02-29
 *******************************************************************************
 *
 * Version:	1.0.0
 */
#include <HexFile.h>

static void hd8(void* data, int n){
	uint8_t* d = (uint8_t*)data;
	int	i;
	
	for(i = 0; i < n; i++){
		printf("%2.2x ", *d++);
		if((i & 0xF) == 0xF)
			printf("\n");
	}
	printf("\n");
}


HexFile::HexFile(){
	memset(oprogram, 0xFF, sizeof(oprogram));
	memset(odata, 0xFF, sizeof(odata));
	memset(oconfig, 0xFF, sizeof(oconfig));
	ocpuStartAddress = 0x0000;
	ocpuEndAddress = 0x0000;
	oprogramLowAddress = 0xFFFF;
	oprogramHighAddress = 0x0000;
}

void HexFile::setAddressRange(uint32_t startAddress, uint32_t endAddress){
	ocpuStartAddress = startAddress;
	ocpuEndAddress = endAddress;
}


uint32_t HexFile::programLowAddress(){
	return oprogramLowAddress;
}

uint32_t HexFile::programSize(){
	return oprogramHighAddress - oprogramLowAddress;
}

BError HexFile::readProgramData(uint32_t address, void* data, uint32_t len){
	BError	err;
	
	if(address >= oprogramHighAddress)
		return err.set(1, "Out of memory space");
	memcpy(data, &oprogram[address], len);
	return err;
}

BError HexFile::writeProgramData(uint32_t address, void* data, uint32_t len){
	BError	err;
	
	if(address >= oprogramHighAddress)
		return err.set(1, "Out of memory space");
	memcpy(&oprogram[address], data, len);
	return err;
}

uint8_t HexFile::hexChar(BString s, int offset){
	uint8_t	v;
	uint8_t	d;
	
	d = s[offset] - '0';
	if(d > 9)
		d -= 7;
	v = d << 4;

	d = s[offset + 1] - '0';
	if(d > 9)
		d -= 7;
	return v | d;
}

void HexFile::printInfo(){
	printf("Program: %4.4x -> %4.4x\n", oprogramLowAddress, oprogramHighAddress);
}

BError HexFile::read(BString fileName){
	BError		err;
	BString		line;
	int		recType;
	int		recLen;
	uint16_t	addressHigh = 0;
	uint16_t	addressLow = 0;
	uint32_t	address = 0;
	int		i;
	uint8_t		buffer[8192];

	if(err = ofile.open(fileName, "r"))
		return err;
	
	while(ofile.readString(line)){
		if(sscanf(line, ":%2x%4x%2x", &recLen, &addressLow, &recType) != 3)
			return err.set(1, "Hex File syntax error");

		address = (addressHigh << 16) | addressLow;

//		printf("Type: %x Len: %x Address: %x\n", recType, recLen, addressLow);
		
		if((recType == 1) || (recLen == 0))
			break;

		if((recType != 0) && (recType != 4))
			return err.set(1, "Unknown record type");
		
		if(recLen > sizeof(buffer))
			return err.set(1, "Hex file line to long");
		
		line = line.subString(9, 8192);
		if(recType == 4){
			sscanf(line, "%4x", &addressHigh);
		}
		else {
			for(i = 0; i < recLen; i++){
				buffer[i] = hexChar(line, i*2);
			}
//			printf("%8.8x: ", address);
//			hd8(buffer, recLen);
			
			if(address == 0x00300000)
				memcpy(oconfig, buffer, recLen);
			else if(address <= ocpuEndAddress){
				memcpy(&oprogram[addressLow], buffer, recLen);
				if(address < ocpuStartAddress)
					printf("Igoring writes below 0x%x\n", ocpuStartAddress);
				else if(address < oprogramLowAddress)
					oprogramLowAddress = address;
				if((address + recLen) > oprogramHighAddress)
					oprogramHighAddress = address + recLen;
			}
			else {
				return err.set(1, BString("Out of range address: ") + address);
			}
		}
	}
	return err;
}
