//-------------------------------
// File:			xon_xoff.cpp
// Function:		XON/XOFF protocol implementation
// Supported Toolchain(s):
//		- Microsoft Visual C++
// Date created:	23-May-2006
// Created by:		JJo
//-------------------------------

//-------------------------------
// Includes

#include "XonXoff.h"

//-------------------------------
// Class

/**
 * Name:		XonXoff
 * Purpose:		Constructor for the XonXoff class
 */
XonXoff::XonXoff(Media * media): Communication(media) {}

/**
 * Name:		~XonXoff
 * Purpose:		Destructor for the XonXoff class
 */
XonXoff::~XonXoff() {}

/**
 * Name:		Send
 * Purpose:		Sends a firmware to the target device
 * Input(s):
 *	- Data buffer to transmit
 *	- Size of the buffer
 *	- Pointer to a ProgressDialog instance
 *	- Rate of progress update
 * Output:		Number of bytes transmitted
 */
unsigned long XonXoff::Send(void * data,
							unsigned long size,
							ProgressDialog * pProgressDialog,
							unsigned long rate) {

	// Local variables
	unsigned long bytes;
	unsigned char control;
	unsigned long progress;
	unsigned long bytesToSend;
	unsigned long timeout;
	bool stop;

	// Send data
	bytes = 0;
	progress = 0;
	stop = false;

	while (bytes != size) {

		// Wait for transfer to resume
		timeout = 0;

		while (stop) {

			if (pProgressDialog != NULL) {

				if (pProgressDialog->ThreadShouldClose()) {
					
					return bytes;
				}
			}
			this->m_media->Read(&control, 1);

			if (control == XON) {

				stop = false;
			}
		}

		// Send data if there is no control character
		if (this->m_media->Poll() == 0) {

			if ((size - bytes) < XONXOFF_PACKETSIZE) {

				bytesToSend = size - bytes;
			}
			else {

				bytesToSend = XONXOFF_PACKETSIZE;
			}

			if (pProgressDialog != NULL) {

				if (pProgressDialog->ThreadShouldClose()) {
					
					return bytes;
				}
			}
			this->m_media->Write((void *)((unsigned long) data + bytes), bytesToSend);
			bytes += bytesToSend;
			
			if (pProgressDialog != NULL) {

				// Update progress
				progress += bytesToSend;

				while (progress >= rate) {
						
					pProgressDialog->StepIt();
					progress -= rate;
				}
			}
		}
		else {

			// Stop transfer on XOFF
			if (pProgressDialog != NULL) {

				if (pProgressDialog->ThreadShouldClose()) {
					
					return bytes;
				}
			}
			this->m_media->Read(&control, 1);

			if (control == XOFF) {

				stop = true;
			}
		}
	}

	if (pProgressDialog != NULL) {

		pProgressDialog->Finish();
	}

	return bytes;
}
