/* 
 * 2012 Visual Micro Debug Services
 * 
 * Some elements based on various examples found on the internet, 
 * can be freely copied, modified and re-distributed
 *
 * Firmata elements and general licences of note ...
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * See file LICENSE for further informations on licensing terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */


#define VM_DEBUG_ENABLE 1
//#define VM_DEBUG_START_PRE_DELAY 2000
#include "VM_DBG.h"

#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_NET_CONSOLE
#include <Bridge.h>
#endif

#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_SOFTWARESERIAL
#include <SoftwareSerial.h>
#endif

#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_COSA
	#include "Cosa/IOStream/Driver/UART.hh"
	#include "Cosa/Types.h"
	#include "Cosa/Bits.h"
	#include "Cosa/RTC.hh"
#endif

#if VM_DEBUG_MEM_CHECK == VM_DEBUG_ENABLE
 //#include "VM_mem_check.h"
#endif

	//added for cosa
#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_COSA
	unsigned long VisualMicroDebug::DBG_Millis()
	{
		return RTC::millis();
	}
#else
	unsigned long VisualMicroDebug::DBG_Millis()
	{
		return millis();
	}
#endif

VisualMicroDebug::VisualMicroDebug() {
	//ensure x millis between each debug packet
	//wait if we have to
	//try to prevent new users from overloading bandwidth and filling windows buffer
	//can be overriden via preferences
	//defaults to 50ms; needs to allow time for windows to recover if it pauses, so we need to be slower than the extensions and debugger can process + a bit
}


void VisualMicroDebug::outPacketStart()
{
	outPacketStart(false);
}


void VisualMicroDebug::outPacketStart(bool noWait)
{

#if defined(VM_DEBUG_BANDWIDTH_THROTTLE_MS)
	if (!noWait)
	{
		//1501 - for cosa
		//while  (millis()-lastPacketMS<VM_DEBUG_BANDWIDTH_THROTTLE_MS)
		while  (DBG_Millis()-lastPacketMS<VM_DEBUG_BANDWIDTH_THROTTLE_MS)
		{
			delay(3);
		}
	}
	//XXX: this should really be after packet end!
	//1501 for cosa - lastPacketMS=millis();
	lastPacketMS=DBG_Millis();
	
#endif


}

/*
void VisualMicroDebug::missedBreakpoint(uint8_t breakpoint_index)
{
	missed_breakpoints[missed_breakpoints_counter]=breakpoint_index;
}
void VisualMicroDebug::missedBreakpointsFlush()
{
	uint8_t i;
	for(i=0;i<missed_breakpoints_counter;i++)
	{
		//missed_breakpoints[missed_breakpoints_counter]=breakpoint_index;
		transport->print("VMDPM_");
		transport->print(i);
		transport->println("_VMDPM");
		delay(5);
	}
}
*/

#if defined(VM_DEBUG_USE_PRINT_F)
void VisualMicroDebug::p(char *fmt, ... ){
		char tmp[128]; // resulting string limited to 128 chars
		va_list args;
		va_start (args, fmt );
		vsnprintf(tmp, 128, fmt, args);
		va_end (args);
		transport->print(tmp);
}
#endif

/*
#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_UART
void VisualMicroDebug::begin(UARTClass *theSerial)
{
	transport = theSerial;
	while(!*theSerial)
	{;}
}

void VisualMicroDebug::begin(UARTClass *theSerial, long baud)
{
	//delay(500);

	transport = theSerial;
	while(!*theSerial)
	{;}

	//transport->begin(baud);
	//wait for laonardo port to connect. hack! we know it can only be main serial!
	//while(!*theSerial)
	//{;}
}
#endif
#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_USART
void VisualMicroDebug::begin(USARTClass *theSerial)
{
	transport = theSerial;
	while(!*theSerial)
	{;}
}

void VisualMicroDebug::begin(USARTClass *theSerial, long baud)
{
	//delay(500);

	transport = theSerial;
	while(!*theSerial)
	{;}

	//transport->begin(baud);
	//wait for laonardo port to connect. hack! we know it can only be main serial!
	//while(!*theSerial)
	//{;}
}
#endif
*/


#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_Uart
void VisualMicroDebug::begin(Uart *theSerial)
{
	transport = theSerial;
	int n=0;
	while(!*theSerial)
	{
		if (n>25)
		break;
		n++;
		delay(200);
	}
}

void VisualMicroDebug::begin(Uart *theSerial, unsigned long baud)
{
	transport = theSerial;
	int n=0;
	while(!*theSerial)
	{
		if (n>25)
		break;
		n++;
		delay(200);
	}
}
#endif

#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_TEENSY
	void VisualMicroDebug::begin(usb_serial_class *theSerial)
	{
		transport = theSerial;
		int n=0;
		while(!*theSerial)
		{
			if (n>25)
				break;
			n++;
			delay(200);
		}
		//delay(VM_DEBUG_START_PRE_DELAY);
	}

	void VisualMicroDebug::begin(usb_serial_class *theSerial, unsigned long baud)
	{
		//delay(500);

		transport = theSerial;
		int n=0;
		while(!*theSerial)
		{
			if (n>25)
				break;
			n++;
			delay(200);
		}
		//delay(VM_DEBUG_START_PRE_DELAY);
		//transport->begin(baud);
		//wait for laonardo port to connect. hack! we know it can only be main serial!
		//while(!*theSerial)
		//{;}
	}
#endif


#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_USB
	void VisualMicroDebug::begin(Serial_ *theSerial)
	{
		transport = theSerial;

		//wait for leonardo port to connect. hack! we know it can only be main serial!
		//exit wait after 5 seconds assume user has disconnected board from pc but left debug running?
		int n=0;
		while(!*theSerial)
		{
			if (n>25)
				break;
			n++;
			delay(200);
		}
		//delay(VM_DEBUG_START_PRE_DELAY);
	}
	void VisualMicroDebug::begin(Serial_ *theSerial, unsigned long baud)
	{
		transport = theSerial;
		transport->begin(baud);
		//wait for leonardo port to connect. hack! we know it can only be main serial!
		//exit wait after 5 seconds assume user has disconnected board from pc but left debug running?
		int n=0;
		while(!*theSerial)
		{
			if (n>25)
				break;
			n++;
			delay(200);
		}
		//delay(VM_DEBUG_START_PRE_DELAY);
	}
#endif


#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_NET_CONSOLE

	void VisualMicroDebug::begin(ConsoleClass *theSerial, unsigned long baud)
	{
		transport = theSerial;
		//hack
		//console crashes if bridge not started
		Bridge.begin();
		Console.begin();
		//transport->begin();
		//delay(VM_DEBUG_START_PRE_DELAY);
	}
#endif

#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_TTYUART

	void VisualMicroDebug::begin(TTYUARTClass *theSerial, unsigned long baud)
	{
		transport = theSerial;
		transport->begin(baud);
		//delay(VM_DEBUG_START_PRE_DELAY);
	}
#endif


#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_USBSERIAL

	void VisualMicroDebug::begin(USBSerial *theSerial, unsigned long baud)
	{
		transport = theSerial;
		transport->begin(baud);
		//delay(VM_DEBUG_START_PRE_DELAY);
	}
#endif


#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_COSA
	void VisualMicroDebug::begin(UART *theSerial, unsigned long int baud)
	{
		RTC::begin();

		// Create an instance of the iostream and bind to the uart
		IOStream dbgSerial(theSerial);
		transport = &dbgSerial;
		
		reader = theSerial;
		reader->begin(baud);
		

	}
#endif

#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_UART

	void VisualMicroDebug::begin(UARTClass *theSerial, unsigned long baud)
	{
		transport = theSerial;
		transport->begin(baud);
		//delay(VM_DEBUG_START_PRE_DELAY);
	}
#endif

#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_USART

	void VisualMicroDebug::begin(USARTClass *theSerial, unsigned long baud)
	{
		transport = theSerial;
		transport->begin(baud);
		//delay(VM_DEBUG_START_PRE_DELAY);
	}
#endif


#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_HARDWARESERIAL
void VisualMicroDebug::begin(HardwareSerial *theSerial)
	{
		transport = theSerial;
	}
	void VisualMicroDebug::begin(HardwareSerial *theSerial, unsigned long baud)
	{
		transport = theSerial;
		transport->begin(baud);

		//delay(VM_DEBUG_START_PRE_DELAY);
	}
#endif


#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_SOFTWARESERIAL
	void VisualMicroDebug::begin(SoftwareSerial *theSerial)
	{
		transport = theSerial;
		transport->listen();
		//delay(VM_DEBUG_START_PRE_DELAY); //try to stop initial rubbish in debug console
//#if VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_SOFTWARESERIAL
		
//#endif
	}
	void VisualMicroDebug::begin(SoftwareSerial *theSerial, unsigned long baud)
	{
		transport = theSerial;
		transport->begin(baud);
		transport->listen();
		//delay(VM_DEBUG_START_PRE_DELAY); //try to stop initial rubbish in debug console
		
	} 
#endif


void VisualMicroDebug::start(bool waitForKeyToStart, bool _alwaysBreak)
{	
	#if defined (VM_DEBUG_BREAKPAUSE)
	if (waitForKeyToStart)
	{
		alwaysBreak = true;
			
		//server should know we are waiting sendMessage("Press any key to continue");
		breakWait(0);
	}
	alwaysBreak = _alwaysBreak;
	#endif

}


/*
*
*
*/
#if defined (VM_DEBUG_BREAKPAUSE)

#if defined(VM_DEBUGGER_TYPE) //&& ( VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_HARDWARESERIAL || VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_FASTSERIAL)
//TODO: implement sturcture serial com!
//we never get called if break was not set during compliation
//return _vm_cmd so that we can setVariable if required (caller needs to know result)
int VisualMicroDebug::breakWait(uint8_t breakPointId)
{
	if (!alwaysBreak)
	{
		//if dedicated debug port then we can perform a quick check on serial
		//for vm command to switch back on breaks
		return 'c';
	}


	int b;


#if defined(VMDGB_HAS_READER)
	while(reader->available()==0)
		{
			//delay(10);
			//detect incoming byte as quickly as possible
		}

#else
	while(transport->available()==0)
		{
			//delay(10);
			//detect incoming byte as quickly as possible
		}

#endif
		
		//delay(10); //wait for rest

		//note: work in progress!!
		//todo: implement decent command header	instead of this. 
		//		cows have 7 stomachs and chickens have 12 eggs inside them most of the time
		//doh!  better if we have any key to continue so users data doesn't get lost so much. 
		//NOTE. pause/breakpoints are best used with dedicated port!
		//while(true)
		//{

#if defined(VMDGB_HAS_READER)
		while(reader->available()>0)
		{

			b = reader->getchar();
#else
		while(transport->available()>0)
		{
			b = transport->read();
#endif
				//debug break commands
				switch (b)
				{
				
					case 'c':
						sendContinuedACK(breakPointId);
						return 'c'; //if we get here we are continuing!


					case 'v': //setVariableValue
						return b; //caller will come back again after setting variable value
						//break;

					//continue
					//case 'c':
					//	sendContinuedACK(breakPointId);
					//	return;
			
					//switch off break until re-start. for dev/testing
					case 'X':
						alwaysBreak=false;
						break;
				}
			}
		//}
		//while(printer->available()>0)
		//printer->read();
		//sendContinuedACK(breakPointId);
		//return 'c'; //if we get here we are continuing!

		//	return '?'; //software serial rubbish detected?

			return 'c';
}
#endif


/*
#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_SOFTWARESERIAL

//TODO: implement sturcture serial com!
//we never get called if break was not set during compliation
void VisualMicroDebug::breakWait(uint8_t breakPointId)
{
	if (!alwaysBreak)
	{
		//if dedicated debug port then we can perform a quick check on serial
		//for vm command to switch back on breaks
		return;
	}
	transport->listen();

	while(!transport->available())
		{
			//delay(10);
			//detect incoming byte as quickly as possible
		}
		
		//delay(10); //wait for rest
		byte b;

		//note: work in progress!!
		//todo: implement decent command header	instead of this. 
		//		cows have 7 stomachs and chickens have 12 eggs inside them most of the time
		//doh!  better if we have any key to continue so users data doesn't get lost so much. 
		//NOTE. pause/breakpoints are best used with dedicated port!
		//while(true)
		//{
			//while(printer->available()>0)
			//{
				b = transport->read();
				//debug break commands
				switch (b)
				{
					//continue
					//case 'c':
					//	sendContinuedACK(breakPointId);
					//	return;
			
					//switch off break until re-start. for dev/testing
					case 'X':
						alwaysBreak=false;
						break;
				}
			//}
		//}
		//while(printer->available()>0)
		//printer->read();
		sendContinuedACK(breakPointId);
}
#endif
*/


//this method is only called once during mcu startup
void VisualMicroDebug::sendContinuedACK(uint8_t breakPointId)
{
		transport->print("VMDPC_");
		//todo: arduino early versions prior to 1.0 will not convert this number in the same way
		transport->print(breakPointId);

		//1501 - split into two because cosa doesn't support println(str)
		transport->print("_VMDPC\r\n");		
		//transport->println();


		//nb: 2560 looses some chars of 2nd and third print statements after startup. todo: look into this!
		//the following delay seems to sort it out sometimes!
		delay(50);
}

#endif //_VM_DEBUG_BREAKPAUSE


void VisualMicroDebug::sendMessage(const char debugger_message[])
{
	//1501 - split this into two calls because cosa doesn;t support println(str)
	transport->print(debugger_message);
	transport->println();
}


#if defined(VM_DEBUG_AUTO_REPORTING)

	#define TOTAL_DIGITAL_PINS TOTAL_PINS-TOTAL_ANALOG_PINS

	//reporting
	#if VM_DEBUG_READ_DIGITAL_PORTS == VM_DEBUG_ENABLE 

		void VisualMicroDebug::printPortsDigital()
		{
			uint32_t i;
			unsigned char pByte=0;
			unsigned char bitCounter=0;
			uint32_t v=0;
			bool state;
			for (i=0;i<TOTAL_DIGITAL_PINS;i++)
			{
				state = false;
				//don't bother with hardware serial
				if (i>1)
				{
				v=digitalRead(i);
				if (v>0)
					state = true;
				else state = false;
				}

				pByte |= (state << bitCounter);
								
				bitCounter++;
				//NEXT BYTE
				if (bitCounter==8 || i==TOTAL_DIGITAL_PINS-1)
				{
					//transport->print("D");
					transport->print(pByte);
					transport->print(":");		
					bitCounter=0;
					pByte=0;
				}
			
				
				delay(1); //avoid unclean next reading. is this required?
			}
		}
		#endif

		//uint8_t VM_DBG_LAST_PORT_VALUES[TOTAL_PORTS];
		//uint8_t VM_DBG_TEMP_UNINT8_T=0;
		/*
		void VisualMicroDebug::printPortsDigital()
		{

			byte i;
			for (i=0; i<TOTAL_PORTS; i++) 
			{

			#if defined(_VM_DEBUG_USE_PRINT_F)
				p("%*d=%*d:",i,readPort(i,255));
			#else
				transport->print(i);
				transport->print("=");
				transport->print(readPort(i,255));
				transport->print(":");				
			#endif

			}

		}

		*/
		/*

		void VisualMicroDebug::printPortsDigital()
		{
			tmp_found = false;

			byte i;
			for (i=0; i<TOTAL_PORTS; i++) 
			{
				VM_DBG_TEMP_UNINT8_T = readPort(i,255);
				if (VM_DBG_LAST_PORT_VALUES[i]!=VM_DBG_TEMP_UNINT8_T)
				{
					if (!tmp_found)
					{
						tmp_found=true;
						//MicroDebug.transport->print("PORTS");
					}
			
					VM_DBG_LAST_PORT_VALUES[i] = VM_DBG_TEMP_UNINT8_T;

					#if defined(_VM_DEBUG_USE_PRINT_F)
						p("%*d:%*d",i,VM_DBG_TEMP_UNINT8_T);
					#else
						transport->print(":");
						transport->print(i);
						transport->print("=");
						transport->print(VM_DBG_TEMP_UNINT8_T);
					#endif
				}
			}

			//if (tmp_found)
				//MicroDebug.transport->println("PORTS");
		}

		*/
	


	#if VM_DEBUG_MEM_CHECK == VM_DEBUG_ENABLE
		void VisualMicroDebug::printFreeMemory()
		{
			transport->print(_VM_freeMemory());
		}
		/*unsigned long VisualMicroDebug::getFreeMemory()
		{
			return _VM_freeMemory();
		}*/

#endif



	#if VM_DEBUG_READ_ANALOG_PINS == VM_DEBUG_ENABLE
		void VisualMicroDebug::printPinsAnalog()
		{
		
			int analogPin = 0; // counter for reading analog pins
			int analogData; // storage variable for data from analogRead()

			for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) 
			{
			//if( analogPinsToReport & (1 << analogPin) ) {
				//delay(4);
				analogData = analogRead(analogPin);
				//transport->print(analogPin);
				// These two bytes converted back into the 10-bit value on host
				//transport->print("=");
				transport->print(analogData);
				//transport->print(analogData % 128);
				//transport->print(analogData >> 7); 
				transport->print(":");
			}	
			//transport->println(":ANALOGS");
		}
		#endif



#if defined(VM_DEBUG_I2C)
	#include <Wire.h>

	extern "C" { 
		#include <utility/twi.h>  // from Wire library, so we can do bus scanning
	}

	void VisualMicroDebug::initI2C()
	{
		Wire.begin();	
	}

	#if VM_DEBUG_READ_I2C_DEVICES == VM_DEBUG_ENABLE

		void VisualMicroDebug::printI2CDeviceList()
		{
			if (devicesFound)
				return;

			//tmp_found=false;
			uint8_t from_addr = 8;
			uint8_t to_addr = 118; //#119 seems erratic
			uint8_t rc;
			uint8_t data = 0; // not used, just an address to feed to twi_writeTo()
			for( byte addr = from_addr; addr <= to_addr; addr++ ) 
			{
				rc = twi_writeTo(addr, &data, 0, 1,1);
				if (rc==0)
				{
			//		if (!tmp_found)
			//		{
			//			tmp_found=true;
			//			transport->print("VMDPI_");
			//		}	
					
					transport->print(addr);			
					transport->print(":");
					devicesFound = true;
				} 
			
			}
	
			//if (tmp_found)
			//	transport->println("_VMDPI");

		}

	#endif //i2c scan
 #endif //i2c
#endif

/*
#if defined(VM_DEBUG_WRITEVARS_SIMPLE)
		
	void VisualMicroDebug::setVariable(long &i, int j) 
	{
		delay(5); //make sure we get the whole data packet. needs a check sum or something!
		uint8_t dtype = readVariableTextDataType();
		uint8_t len = readVariableTextLength();

		char readString[17];

		for(uint16_t r=0; r<len; r++) {
			readString[r]=transport->read();
		}
		readString[len] = '\0';

		i = atol(readString);

#if defined(VM_DEBUG_WRITEVAR_CONFIRM)
		transport->print("l_Variable value received: Len=");
		transport->print(len);
		transport->print(" text data type=");
		transport->print(dtype);
		transport->print(" value=");
		transport->println(i);
#endif
	}

	void VisualMicroDebug::setVariable(unsigned long &i, int j) 
	{
		delay(5); //make sure we get the whole data packet. needs a check sum or something!
		uint8_t dtype = readVariableTextDataType();
		uint8_t len = readVariableTextLength();

		char readString[17];

		for(uint16_t r=0; r<len; r++) {
			readString[r]=transport->read();
		}
		readString[len] = '\0';

		i = atol(readString);

		
		transport->print("l_Variable value received: Len=");
		transport->print(len);
		transport->print(" text data type=");
		transport->print(dtype);
		transport->print(" value=");
		transport->println(i);
		
	}
	
	void VisualMicroDebug::setVariable(float &i, int j) {
		delay(5); //make sure we get the whole data packet. needs a check sum or something!
		uint8_t dtype = readVariableTextDataType();
		uint8_t len = readVariableTextLength();

		char readString[20];
		for(uint16_t r=0; r<len; r++) {
			readString[r]=transport->read();
		}
		readString[len] = '\0';
		i = atof(readString);

		transport->print("f_Variable value received: Len=");
		transport->print(len);
		transport->print(" text data type=");
		transport->print(dtype);
		transport->print(" value=");
		transport->println(i);
		
	}


	void VisualMicroDebug::setVariable( unsigned int &i, int j ) 
	{ 
		delay(5); //make sure we get the whole data packet. needs a check sum or something!
		uint8_t dtype = readVariableTextDataType();
		uint8_t len = readVariableTextLength();
		
		char readString[5];
		for(uint16_t r=0; r<len; r++) {
			readString[r]=transport->read();
		}
		readString[len] = '\0';
		i = atoi(readString);
	
		
		transport->print("Variable value received: Len=");
		transport->print(len);
		transport->print(" text data type=");
		transport->print(dtype);
		transport->print(" value=");
		transport->println(i);
		
	}
	void VisualMicroDebug::setVariable( int &i, int j ) 
	{ 
		delay(5); //make sure we get the whole data packet. needs a check sum or something!
		uint8_t dtype = readVariableTextDataType();
		uint8_t len = readVariableTextLength();

		char readString[5];
		for(uint16_t r=0; r<len; r++) {
			readString[r]=transport->read();
		}
		readString[len] = '\0';
		i = atoi(readString);
		
		transport->print("Variable value received: Len=");
		transport->print(len);
		transport->print(" text data type=");
		transport->print(dtype);
		transport->print(" value=");
		transport->println(i);
	}
#endif
*/


#if defined(VM_DEBUG_WRITEVARS_SIMPLE) || defined(VM_DEBUG_WRITEVARS_ADVANCED)

#if defined(VMDGB_HAS_READER)
	uint8_t VisualMicroDebug::readVariableTextDataType() 
	{
		return reader->read();
	}
	
	uint8_t VisualMicroDebug::readVariableTextLength() 
	{
		return reader->read();
	}
#else
	uint8_t VisualMicroDebug::readVariableTextDataType() 
	{
		return transport->read();
	}
	
	uint8_t VisualMicroDebug::readVariableTextLength() 
	{
		return transport->read();
	}
#endif

#endif


#if defined(VM_DEBUG_WRITEVARS_ADVANCED)


void no_lvalue_err()
{
#if defined(VM_DEBUG_WRITEVAR_CONFIRM)
	MicroDebug.transport->print("Error: Attempt to set a read-only variable or data type not supported\r\n");
#endif

	// you can put any code here that will be executed if the user tries to set a variable that isn't any (that is no lvalue)
}


long VisualMicroDebug::vmstrtol(char *rs, byte format)
{
	byte base = DEC;

#if DEC == 10 && HEX == 16 && OCT == 8 && BIN == 2
	if( format != 0 )
		base = format;	// that#s how it is currently defined in print.h
#else
	switch( format )
	{
	case HEX:	base = 16; break;
	case OCT:	base =  8; break;
	case BIN:	base =  2; break;
	}
#endif

	return strtol( rs, NULL, base );
}

unsigned long VisualMicroDebug::vmstroul(char *rs, byte format)
{
	byte base = DEC;

#if DEC == 10 && HEX == 16 && OCT == 8 && BIN == 2
	if( format != 0 )
		base = format;	// that#s how it is currently defined in print.h
#else
	switch( format )
	{
	case HEX:	base = 16; break;
	case OCT:	base =  8; break;
	case BIN:	base =  2; break;
	}
#endif

	return strtoul( rs, NULL, base );
}

//void VisualMicroDebug::fetchVarData( char *buf )
#if defined(VM_DEBUGGER_TYPE) && VM_DEBUGGER_TYPE == VM_DEBUGGER_TYPE_COSA
void VisualMicroDebug::fetchVarData()
{
	//dummy not impemented
}
#else
void VisualMicroDebug::fetchVarData()
{
//#if defined(VM_DEBUG_WRITEVAR_CONFIRM)
//	transport->println("Variable Value: ");
//#endif

	delay(10); //make sure we get the whole data packet. needs a check sum or something!

	//uint8_t dtype = 
	readVariableTextDataType();

	uint8_t len = readVariableTextLength();

//#if defined(VM_DEBUG_WRITEVAR_CONFIRM)
//	transport->print(len);
//#endif

	for(byte r=0; r<len; r++) {
		//buf[r]=transport->read();
		MicroDebug.readString[r]=transport->read();
	}
	//buf[len] = '\0';
	MicroDebug.readString[len] = '\0';

//#if defined(VM_DEBUG_WRITEVAR_CONFIRM)
//	transport->print("Variable Value: ");
//	transport->print(len);
//	transport->print(" text data type=");
//	transport->print(dtype);
//#endif
}
#endif

void VisualMicroDebug::vmsetvar(char *rs, byte format, char *v ) { strcpy( v, rs ); }
void VisualMicroDebug::vmsetvar(char *rs, byte format, int16_t &v ) { v = (int16_t) vmstrtol(rs, format); }
void VisualMicroDebug::vmsetvar(char *rs, byte format, uint16_t &v ) { v = (uint16_t) vmstroul(rs, format); };
#if __SIZEOF_INT__ == __SIZEOF_LONG__
// for 32 Bit CPUs
void VisualMicroDebug::vmsetvar(char *rs, byte format, int &v ) { v = vmstrtol(rs, format); };
void VisualMicroDebug::vmsetvar(char *rs, byte format, unsigned int &v ) { v = vmstroul(rs, format); };
#endif
void VisualMicroDebug::vmsetvar(char *rs, byte format, long &v ) { v = vmstrtol(rs, format); };
void VisualMicroDebug::vmsetvar(char *rs, byte format, unsigned long &v ) { v = vmstroul(rs, format); };

#if !defined(VM_DEBUG_EXCLUDE_TYPE_FLOAT)
	void VisualMicroDebug::vmsetvar(char *rs, byte format, float &v ) { v = (float) atof(rs); };
	void VisualMicroDebug::vmsetvar(char *rs, byte format, double &v ) { v = atof(rs); };
#endif

void VisualMicroDebug::vmsetvar(char *rs, byte format, char &v )
{
	vmsetvar( rs, format, (int8_t &) v );
}

void VisualMicroDebug::vmsetvar(char *rs, byte format, int8_t &v )
{
/* removed 27.01.2015 HK as a bugfix
	if( format == 0 )	// treat as character, not as value
		v = *rs;
	else */
	v = (int8_t) vmstrtol(rs, format);
};
void VisualMicroDebug::vmsetvar(char *rs, byte format, uint8_t &v )
{
	int8_t c;
	vmsetvar( rs, format, c );
	v = (uint8_t) c;
}
void VisualMicroDebug::vmsetvar(char *rs, byte format, volatile uint8_t &v )
{
	int8_t c;
	vmsetvar( rs, format, c );
	v = (uint8_t) c;
}



#endif


//initialize debug object
VisualMicroDebug MicroDebug;