#include "SimpleSerialAnalyzer.h"
#include "SimpleSerialAnalyzerSettings.h"
#include <AnalyzerChannelData.h>

SimpleSerialAnalyzer::SimpleSerialAnalyzer() :

#ifdef NEW_SDK
	Analyzer2(),
#else
	Analyzer(),
#endif

	mSettings( new SimpleSerialAnalyzerSettings() ),
	mSimulationInitilized( false ),
	mBytes( NULL ),
	mNumBytes( 0 ),
	mNumBytesCapacity( 0 )
{
	SetAnalyzerSettings( mSettings.get() );
}

SimpleSerialAnalyzer::~SimpleSerialAnalyzer()
{
	KillThread();
}

void SimpleSerialAnalyzer::RxWaitBothHigh(void)
{
	while(1) {
		if (mPin1->GetBitState() == BIT_LOW ) {
			mPin1->AdvanceToNextEdge();
			mPin5->AdvanceToAbsPosition(mPin1->GetSampleNumber());
			continue;
		}
		if (mPin5->GetBitState() == BIT_LOW ) {
			mPin5->AdvanceToNextEdge();
			mPin1->AdvanceToAbsPosition(mPin5->GetSampleNumber());
			continue;
		}
		break;
	}
}

bool SimpleSerialAnalyzer::RxNextBit(char *phaseP)
{
	U64 when, when1, when5;
	BitState cur1, cur5, prev, val;
	char phase;


	do {
		cur1 = mPin1->GetBitState();
		cur5 = mPin5->GetBitState();

		when1 = mPin1->GetSampleOfNextEdge();
		when5 = mPin5->GetSampleOfNextEdge();

		//advance to edge
		if (when1 < when5) {
			phase = 1;
			when = when1;
			prev = cur1;
			val = cur5;
		}
		else {
			phase = 2;
			when = when5;
			prev = cur5;
			val = cur1;
		}

		if (when1 == when5)		//not normally a good thing
			phase = 0;
		
		mPin1->AdvanceToAbsPosition(when);
		mPin5->AdvanceToAbsPosition(when);

		//see if it was a down (else we can try again)
	} while (prev == BIT_LOW);

	*phaseP = phase;
	return val == BIT_HIGH;
}

void SimpleSerialAnalyzer::bytesAdd(U16 val, U64 first, U64 last)
{
	if (mNumBytesCapacity <= mNumBytes) {
		U32 nsz = mNumBytesCapacity * 5 / 4 + 1;	//grow by 25% and at least one
		struct SingleByte *no = (struct SingleByte*)realloc(mBytes, sizeof(struct SingleByte) * nsz);

		if (!no)
			return;	//fail

		mNumBytesCapacity = nsz;
		mBytes = no;
	}

	mBytes[mNumBytes].val = val;
	mBytes[mNumBytes].firstSample = first;
	mBytes[mNumBytes].lastSample = last;

	mNumBytes++;
}

void SimpleSerialAnalyzer::sendFrame(Frame &f)
{
	mResults->AddFrame( f );
	mResults->CommitResults();
	ReportProgress( f.mEndingSampleInclusive );
}

void SimpleSerialAnalyzer::showBytes(void)
{
	struct SingleByte *b = mBytes, *stop = NULL;
	Frame f;
	U64 lastSampleSeen, firstSampleOfCrc = 0, byteStarts[4], byteEnds[4];
	U32 i, wordVal = 0, transWordCtr, transWordsExpected;
	bool errOnEnd = false;
	U8 crc, wordBytes, transCmdVal;
	
	if (!mNumBytes)
		return;

	//we get here either with a stop as last entry or without. let's see which and remove it from the queue (so last byte is really last BYTE and not the stop)
	if (mBytes[mNumBytes - 1].val == VAL_STOP) {
		stop = &mBytes[mNumBytes - 1];
		mNumBytes--;
	}

	for (i = 0; i < mNumBytes; i++, b++) {

		lastSampleSeen = b->lastSample;

		if (b->val == VAL_START) {
			
			f.mStartingSampleInclusive = b->firstSample;
			f.mEndingSampleInclusive = b->lastSample;
			f.mType = FRAME_TYPE_START;
			f.mFlags = 0;
			sendFrame(f);

			crc = 0;
			wordBytes = 0;
			wordVal;
			transWordCtr = 0;
		}
		else if (b->val == VAL_PHASE_ERROR) {

			mResults->AddMarker(b->firstSample, AnalyzerResults::ErrorX, mSettings->mChannelPin1);
			mResults->AddMarker(b->firstSample, AnalyzerResults::ErrorX, mSettings->mChannelPin5);
		}
		else if (b->val <= 0xFF) {	//actual byte
			
			//crc byte always handled as such
			if (i == mNumBytes - 1) {
				f.mStartingSampleInclusive = b->firstSample;
				f.mEndingSampleInclusive = b->lastSample;
				f.mType = FRAME_TYPE_CRC;
				f.mData1 = b->val;						//value on wire
				f.mData2 = crc;
				f.mFlags = b->val == crc ? 0 : DISPLAY_AS_ERROR_FLAG;
				sendFrame(f);

				firstSampleOfCrc = b->firstSample;

				continue;
			}

			crc ^= b->val;		//update crc

			if (mSettings->mDisplayMode == DISPLAY_MODE_BYTES) {		//just show byte
				
				f.mStartingSampleInclusive = b->firstSample;
				f.mEndingSampleInclusive = b->lastSample;
				f.mType = FRAME_TYPE_BYTE;
				f.mData1 = b->val;
				f.mFlags = 0;
				sendFrame(f);
				continue;
			}

			//in other cases we want words
			wordVal <<= 8;
			wordVal += b->val;

			//record where each byte starts and ends
			byteStarts[wordBytes] = b->firstSample;
			byteEnds[wordBytes] = b->lastSample;

			if (++wordBytes != 4)	//if not yet full word, do nothing
				continue;
			wordBytes = 0;

			//swap32 since but swaps bytes
			wordVal = (wordVal >> 24) | (wordVal << 24) | ((wordVal & 0xFF00) << 8) | ((wordVal >> 8 ) & 0xFF00);

			//we have a word now
			if (mSettings->mDisplayMode == DISPLAY_MODE_WORDS) {		//if in word mode just show word
				
				f.mStartingSampleInclusive = byteStarts[wordBytes];
				f.mEndingSampleInclusive = b->lastSample;
				f.mType = FRAME_TYPE_WORD;
				f.mData1 = wordVal;
				f.mFlags = 0;
				sendFrame(f);
				continue;
			}
			
			if (mSettings->mDisplayMode == DISPLAY_MODE_TRANSACTIONS) {		//if we're in transaction mode - do more
				
				//first word is always header
				if (transWordCtr == 0) {		//header

					transWordsExpected = (wordVal & 0xFF) + 1;	//to account for header itself
					transCmdVal = wordVal >> 24;

					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_HEADER;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//function word maybe?
				else if (transWordCtr == 1 && (transCmdVal == CMD_GET_COND || transCmdVal == CMD_GET_MEM_NFO || transCmdVal == CMD_BLK_RD || transCmdVal == CMD_BLK_WR || transCmdVal == CMD_FLSH_ICON_OFF || transCmdVal == CMD_SET_COND)) {
					
					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_FUNC;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//function ORR word  in dev info rsp
				else if (transWordCtr == 1 && (transCmdVal == RSP_DEV_NFO || transCmdVal == RSP_EXTD_NFO)) {

					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_FUNCS_ORRED;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//area code, conn dir, first 2 chars of product code in dev info rsp
				else if (transWordCtr == 5 && (transCmdVal == RSP_DEV_NFO || transCmdVal == RSP_EXTD_NFO)) {

					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_2b_AND_2c;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//other chars in dev info rsp
				else if (transWordCtr >=6 && transWordCtr <= 27 && (transCmdVal == RSP_DEV_NFO || transCmdVal == RSP_EXTD_NFO)) {

					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_4c;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//power vals in dev info rsp
				else if (transWordCtr == 28 && (transCmdVal == RSP_DEV_NFO || transCmdVal == RSP_EXTD_NFO)) {

					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_2_LE_s;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//more string in extended dev info rsp (arbitrary length)
				else if (transWordCtr >= 29 && transCmdVal == RSP_EXTD_NFO) {

					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_4c;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//pt, phase, block
				else if (transWordCtr == 2 && (transCmdVal == CMD_GET_MEM_NFO || transCmdVal == CMD_BLK_RD || transCmdVal == CMD_BLK_WR)) {
					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_PT_PH_BLK;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);
				}

				//if in doubt, treat as a word
				else {	//normal word

					f.mStartingSampleInclusive = byteStarts[wordBytes];
					f.mEndingSampleInclusive = b->lastSample;
					f.mType = FRAME_TYPE_WORD;
					f.mData1 = wordVal;
					f.mFlags = 0;
					sendFrame(f);

					//check if we have too many words
					if (transWordCtr >= transWordsExpected)
						f.mFlags |= DISPLAY_AS_ERROR_FLAG;
				}

				transWordCtr++;
			}
		}
	}

	//leftover bytes not part of a word are an error
	if ((mSettings->mDisplayMode == DISPLAY_MODE_TRANSACTIONS || mSettings->mDisplayMode == DISPLAY_MODE_WORDS) && wordBytes) {	//bytes left over from words?

		//swap still (moves the bytes we care about to top)
		wordVal = (wordVal >> 24) | (wordVal << 24) | ((wordVal & 0xFF00) << 8) | ((wordVal >> 8 ) & 0xFF00);
		//move them down and remove possible crap at once
		wordVal >>= 8 * (4 - wordBytes);

		f.mStartingSampleInclusive = byteStarts[wordBytes];
		f.mEndingSampleInclusive = firstSampleOfCrc ? firstSampleOfCrc : lastSampleSeen++;
		f.mType = FRAME_TYPE_INCOMPL_WORD;
		f.mData1 = wordVal;
		f.mData2 = wordBytes;
		f.mFlags = DISPLAY_AS_ERROR_FLAG;
		sendFrame(f);
	}

	//wrong number of words is an error
	if (mSettings->mDisplayMode == DISPLAY_MODE_TRANSACTIONS && transWordsExpected != transWordCtr)		//wrong number of transaction words
		errOnEnd = true;

	//if we have no stop, that is an error
	if (!stop)
		errOnEnd = true;

	//if we have errors, see what timestamp to show them at (before stop or one byte after last thing shown if no stop) and show them
	if (errOnEnd) {
		U64 when = lastSampleSeen++;

		mResults->AddMarker(when, AnalyzerResults::ErrorX, mSettings->mChannelPin1);
		mResults->AddMarker(when, AnalyzerResults::ErrorX, mSettings->mChannelPin5);
	}

	//if we have a stop, show it
	if (stop) {
		if (stop->firstSample < lastSampleSeen)	//make space
			stop->firstSample = lastSampleSeen;

		f.mStartingSampleInclusive = stop->firstSample;
		f.mEndingSampleInclusive = stop->lastSample;
		f.mType = FRAME_TYPE_STOP;
		f.mFlags = 0;
		sendFrame(f);
	}

	//done
	mResults->CommitPacketAndStartNewPacket();
	mNumBytes = 0;
}

#ifdef NEW_SDK
	void SimpleSerialAnalyzer::SetupResults() {

		mResults.reset( new SimpleSerialAnalyzerResults( this, mSettings.get() ) );
		SetAnalyzerResults( mResults.get() );
		mResults->AddChannelBubblesWillAppearOn( mSettings->mChannelPin1 );
	}
#endif

void SimpleSerialAnalyzer::WorkerThread()
{
	
	#ifndef NEW_SDK
		mResults.reset( new SimpleSerialAnalyzerResults( this, mSettings.get() ) );
		SetAnalyzerResults( mResults.get() );
		mResults->AddChannelBubblesWillAppearOn( mSettings->mChannelPin1 );
	#endif

	mSampleRateHz = GetSampleRate();

	mPin1 = GetAnalyzerChannelData( mSettings->mChannelPin1 );
	mPin5 = GetAnalyzerChannelData( mSettings->mChannelPin5 );


	if (mSettings->mDisplayMode == DISPLAY_MODE_RAW_BITS) {	//an entirely different and simpler thing

		Frame frame;
		char phase;
		
		while (1) {
			frame.mStartingSampleInclusive = mPin1->GetSampleNumber();
			frame.mData1 = RxNextBit(&phase) ? 1 : 0;
			frame.mEndingSampleInclusive = mPin1->GetSampleNumber();
			frame.mData2 = phase;
			frame.mFlags = 0;
			frame.mType = FRAME_TYPE_RAW_BIT;

			sendFrame(frame);
		}
	}

	while(1) {

		U64 when, startSample;
		Frame frame;
		char phase;
		bool val;
		int i;
		
		//see if we got here from a previous packet. If so, show it
		showBytes();

		////just in case, cancel packet
		//mResults->CancelPacketAndStartNewPacket();

		//starting state must be both pins high!
		RxWaitBothHigh();

		//wait for preamble
		//we know currently both pins are high!
		if (!RxNextBit(&phase) || phase != 1)	//"1" in phase 1
			continue;
		startSample = mPin1->GetSampleNumber() - 1;
		for (i = 0; i < 4; i++) {									//4x "0" in phase 2
			if (RxNextBit(&phase) || phase != 2)	//"0" in phase 2
				break;
		}
		if (i != 4)
			continue;

		//both pins are low. 5 must go up first
		if (mPin5->GetSampleOfNextEdge() >= mPin1->GetSampleOfNextEdge())
			continue;
		mPin5->AdvanceToNextEdge();
		mPin1->AdvanceToAbsPosition(mPin5->GetSampleNumber());

		//now pin 5 is up and 1 is down. 1 must go up for this to be a valid start
		if (mPin1->GetSampleOfNextEdge() >= mPin5->GetSampleOfNextEdge())
			continue;
		mPin1->AdvanceToNextEdge();
		mPin5->AdvanceToAbsPosition(mPin1->GetSampleNumber());

		//NOW the weird part. Both lines are currently high. If 5 goes low now, it is not a clock and we must ignore it. If next low is 1, it is a clock.
		when = mPin5->GetSampleOfNextEdge();
		if (mPin1->GetSampleOfNextEdge() > when) {
			mPin1->AdvanceToAbsPosition(when);
			mPin5->AdvanceToAbsPosition(when);
		}

		bytesAdd(VAL_START, startSample, mPin1->GetSampleNumber());


		//now get bits (or stop)
		while(true) {
			startSample = mPin1->GetSampleNumber();
			val = RxNextBit(&phase);

			if (val && phase == 2) {	//probably beginning of a stop else invalid

				//2x phase-1 "0"
				for (i = 0; i < 2; i++) {
					if (RxNextBit(&phase) || phase != 1) {
						bytesAdd(VAL_PHASE_ERROR, mPin1->GetSampleNumber() - 1, mPin1->GetSampleNumber());
						break;
					}
				}
				if (i != 2)
					break;

				//now wait both go high
				RxWaitBothHigh();

				//record the stop
				bytesAdd(VAL_STOP, startSample, mPin1->GetSampleNumber());
				break;
			}
			else if (phase != 1) {		//error

				//phase error
				bytesAdd(VAL_PHASE_ERROR, mPin1->GetSampleNumber() - 1, mPin1->GetSampleNumber());
				break;
			}
			else {						//RX a byte
				U8 byte = val ? 0x80 : 0x00;
				U8 mask = 0x40;
				char expectedPhase = 2;

				for (i = 1; i < 8; i++, mask >>= 1, expectedPhase = 3 - expectedPhase) {
					if (RxNextBit(&phase))
						byte |= mask;
				//	if (phase != expectedPhase) {
				//		bytesAdd(VAL_PHASE_ERROR, mPin1->GetSampleNumber() - 1, mPin1->GetSampleNumber());
				//		break;
				//	}
				}

				if (i != 8)
					break;

				bytesAdd(byte, startSample, mPin1->GetSampleNumber());
			}
		}
	}
}

bool SimpleSerialAnalyzer::NeedsRerun()
{
	return false;
}

U32 SimpleSerialAnalyzer::GenerateSimulationData( U64 minimum_sample_index, U32 device_sample_rate, SimulationChannelDescriptor** simulation_channels )
{
	if( mSimulationInitilized == false )
	{
		mSimulationDataGenerator.Initialize( GetSimulationSampleRate(), mSettings.get() );
		mSimulationInitilized = true;
	}

	return mSimulationDataGenerator.GenerateSimulationData( minimum_sample_index, device_sample_rate, simulation_channels );
}

U32 SimpleSerialAnalyzer::GetMinimumSampleRateHz()
{
	return 25000;
}

const char* SimpleSerialAnalyzer::GetAnalyzerName() const
{
	return "MAPLE bus";
}

const char* GetAnalyzerName()
{
	return "MAPLE bus";
}

Analyzer* CreateAnalyzer()
{
	return new SimpleSerialAnalyzer();
}

void DestroyAnalyzer( Analyzer* analyzer )
{
	delete analyzer;
}