#include "SimpleSerialSimulationDataGenerator.h"
#include "SimpleSerialAnalyzerSettings.h"

#include <AnalyzerHelpers.h>

//target is 0x51 (light gun & controller), source is 0x40
static const U32 mSampleData1[] = {
									//request device info
									0x01514000,
};

static const U32 mSampleData2[] = {
									//reply device info
									0x0540511C,
									0x00000081,															//functions: light gun & controller
									0x00000000,															//info for light gun fucntion
									0xFE000000,															//info for controller function
									0x00000000,															//no third function
									0x00000000 + (((int)'D') << 8) + 'm',								//no area, no direction, name
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'s') << 24) + (((int)' ') << 16) + (((int)'T') << 8) + 'e',	
									(((int)'s') << 24) + (((int)'t') << 16) + (((int)' ') << 8) + 'C',	
									(((int)'o') << 24) + (((int)'n') << 16) + (((int)'t') << 8) + 'r',	
									(((int)'o') << 24) + (((int)'l') << 16) + (((int)'l') << 8) + 'e',	
									(((int)'r') << 24) + (((int)' ') << 16) + (((int)'V') << 8) + ' ',	
									(((int)'1') << 24) + (((int)'.') << 16) + (((int)'0') << 8) + ' ',

									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	//license
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	
									(((int)'i') << 24) + (((int)'t') << 16) + (((int)'r') << 8) + 'y',	

									0x32009600,					//standby power: 50, active power: 150
						};

static const U32 mSampleData3[] = {
									//block read from memry card function (which we do not have)
									0x0B514002, 0x00000002, 0x00012345,	//part 0, ph 1, block 0x2345
						};

static const U32 mSampleData4[] = {
									//block read reply
									0x08405182, 0x00000002, 0x00012345,	//params copied from request

									//data (128 words)
									0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 
									0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, 0x0000000F, 
									0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 
									0x00000018, 0x00000019, 0x0000001A, 0x0000001B, 0x0000001C, 0x0000001D, 0x0000001E, 0x0000001F, 
									0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 
									0x00000028, 0x00000029, 0x0000002A, 0x0000002B, 0x0000002C, 0x0000002D, 0x0000002E, 0x0000002F, 
									0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 
									0x00000038, 0x00000039, 0x0000003A, 0x0000003B, 0x0000003C, 0x0000003D, 0x0000003E, 0x0000003F, 
									0x00000040, 0x00000041, 0x00000042, 0x00000043, 0x00000044, 0x00000045, 0x00000046, 0x00000047, 
									0x00000048, 0x00000049, 0x0000004A, 0x0000004B, 0x0000004C, 0x0000004D, 0x0000004E, 0x0000004F, 
									0x00000050, 0x00000051, 0x00000052, 0x00000053, 0x00000054, 0x00000055, 0x00000056, 0x00000057, 
									0x00000058, 0x00000059, 0x0000005A, 0x0000005B, 0x0000005C, 0x0000005D, 0x0000005E, 0x0000005F, 
									0x00000060, 0x00000061, 0x00000062, 0x00000063, 0x00000064, 0x00000065, 0x00000066, 0x00000067, 
									0x00000068, 0x00000069, 0x0000006A, 0x0000006B, 0x0000006C, 0x0000006D, 0x0000006E, 0x0000006F, 
									0x00000070, 0x00000071, 0x00000072, 0x00000073, 0x00000074, 0x00000075, 0x00000076, 0x00000077, 
									0x00000078, 0x00000079, 0x0000007A, 0x0000007B, 0x0000007C, 0x0000007D, 0x0000007E, 0x0000007F, 
						};




SimpleSerialSimulationDataGenerator::SimpleSerialSimulationDataGenerator()
{
}

SimpleSerialSimulationDataGenerator::~SimpleSerialSimulationDataGenerator()
{
}

void SimpleSerialSimulationDataGenerator::Initialize( U32 simulation_sample_rate, SimpleSerialAnalyzerSettings* settings )
{
	mSimulationSampleRateHz = simulation_sample_rate;
	mSettings = settings;

	mChan1SimData = mChannels.Add(mSettings->mChannelPin1, mSimulationSampleRateHz, BIT_HIGH);
	mChan5SimData = mChannels.Add(mSettings->mChannelPin5, mSimulationSampleRateHz, BIT_HIGH);
}

U32 SimpleSerialSimulationDataGenerator::GenerateSimulationData( U64 largest_sample_requested, U32 sample_rate, SimulationChannelDescriptor** simulation_channels )
{
	U64 adjusted_largest_sample_requested = AnalyzerHelpers::AdjustSimulationTargetSample( largest_sample_requested, sample_rate, mSimulationSampleRateHz );

	CreateSampleTransaction(mSampleData1, sizeof(mSampleData1) / sizeof(*mSampleData1));
	CreateSampleTransaction(mSampleData2, sizeof(mSampleData2) / sizeof(*mSampleData2));
	CreateSampleTransaction(mSampleData3, sizeof(mSampleData3) / sizeof(*mSampleData3));
	CreateSampleTransaction(mSampleData4, sizeof(mSampleData4) / sizeof(*mSampleData4));

	//fill with crap after that
	while (mChan1SimData->GetCurrentSampleNumber() <= adjusted_largest_sample_requested) {
		U64 now = adjusted_largest_sample_requested + 1 - mChan1SimData->GetCurrentSampleNumber();

		if (now > 0x40000000)
			now = 0x40000000;

		mChan1SimData->Advance((U32)now);
		mChan5SimData->Advance((U32)now);
	}

	*simulation_channels = mChannels.GetArray();

	return mChannels.GetCount();
}

void SimpleSerialSimulationDataGenerator::TransitionNone(void)
{
	U32 samples_per_half_bit = mSimulationSampleRateHz / 2000000;	//usually signals are 1MHz (thus we need 2mhz sampling rate to see them)

	if (!samples_per_half_bit)
		samples_per_half_bit = 1;


	mChan1SimData->Advance(samples_per_half_bit);
	mChan5SimData->Advance(samples_per_half_bit);
}

void SimpleSerialSimulationDataGenerator::Transition1(void)
{
	mChan1SimData->Transition();
	TransitionNone();
}

void SimpleSerialSimulationDataGenerator::Transition5(void)
{
	mChan5SimData->Transition();
	TransitionNone();
}

void SimpleSerialSimulationDataGenerator::Prologue(void)
{
	int i;
	
	Transition1();

	for (i = 0; i < 8; i++)
		Transition5();

	Transition1();
}

void SimpleSerialSimulationDataGenerator::Epilogue(void)
{
	int i;

	for (i = 0; i < 2; i++)
		Transition5();

	for (i = 0; i < 4; i++)
		Transition1();

	Transition5();
}

void SimpleSerialSimulationDataGenerator::Byte(U8 val)
{
	int i;

	for (i = 0; i < 8; i += 2, val <<= 2) {
		
		mChan5SimData->TransitionIfNeeded((val & 0x80) ? BIT_HIGH : BIT_LOW);
		TransitionNone();
		mChan1SimData->TransitionIfNeeded(BIT_LOW);
		TransitionNone();
		mChan5SimData->TransitionIfNeeded(BIT_HIGH);
		TransitionNone();

		mChan1SimData->TransitionIfNeeded((val & 0x40) ? BIT_HIGH : BIT_LOW);
		TransitionNone();
		mChan5SimData->TransitionIfNeeded(BIT_LOW);
		TransitionNone();
		mChan1SimData->TransitionIfNeeded(BIT_HIGH);
		TransitionNone();
	}
}

void SimpleSerialSimulationDataGenerator::CreateSampleTransaction(const U32 *data, size_t numWords)
{
	U8 checksum = 0;
	int i;

	//advance at start a litte
	mChan1SimData->Advance(mSimulationSampleRateHz / 100);
	mChan5SimData->Advance(mSimulationSampleRateHz / 100);

	//send sync
	Prologue();

	//send words
	while (numWords--) {
		U32 word = *data++;

		for (i = 0; i < 4; i++, word >>= 8) {	//send LE
			U8 byte = word;
			
			checksum ^= byte;
			Byte(byte);
		}
	}

	//send checksum
	Byte(checksum);

	//send epilogue
	Epilogue();
}
