Serial Communications Header

Posted By: EvilSOB

Serial Communications Header - 07/22/09 20:32

Hi again.
Due to inspiration by The_Mehmaster, Ive decided to write a Serial Communications Suite.
It enables 3DGS to communicate via the SERIAL port (COMx) of the computer, like port_in & port_out does with the parallel port.
But Serial devices are easier to design (in my mind), much more common on "specialised" hardware than parallel, and more flexible.
Also, my code contains buffering of data on both READ and WRITE data-flow, so it needs less effort by your code than port_in/port_out.

Another thing to remember, this being a work in progress and all, THEORETICALLY, my code can be utilised to use many types of ports
at the same time, with the same code, the only difference being the parameters you call the port_open_xxxx with.
I am still investigating this, but theoretically, my code will be able to handle TCP ports, parallel ports, serial ports and possibly more.
But this investigation is on hold till this code is "finished" exclusivly for Serial-Ports.


Its still under development, but Im brain-fried for the night. So I'm putting this work-in-progress up for everyones scrutiny.

All the serial READing functions are fully functional, as are the WRITEing functions. (I'll be starting the the bi-directional port handling tomorrow)
[EDIT] The bi-directional communications appears to be working but still needs quality testing. (Ive updated the code-block below)

But both all three types are in need of further testing. Im hoping for you guys to help.
Im also looking for suggestions as to improvements/additions to make this header a more complete communications suite.
I know this tool is a bit of a "niche" product, but Im hoping it will get some interest.
The usage is modeled on 3DGS's way of handling files. There is plenty of included documentation so there shouldnt be a problem
for you to get it going. If the documentation is lacking, please let me know.

[EDIT]Thanks to the newbie "druid" spotting it, but there was a bug when trying to access serial ports with a number higher than 9.
This has now been fixed and the code in this post has been corrected.
No changes in usage are required, and only the "port_open_???" functions have been changed.


[EDIT] ALSO, if you have any code/implementation problems, let me know here, so all can see what is going on.
BUT, If you are connecting to external hardware (that ISNT a PC), please let me know of any Success/Fail/Wish stories via PM. Im VERY interested to hear about it.


Port_IO.H
Code:
#ifndef	port_io_h
#define	port_io_h
////
//
//////////////////////////////////////////////////////////////////////////////////////////
//																						//
//	File :	Port_IO.h																	//
//	Author:	EvilSOB 																	//
//	Date:	23/July/2009																//
//	Updated:23/May /2010	(Failing Com ports > 9 bug fixed)							//
//																						//
//	Requirements:	None	(except acknex.h or litec.h of course)						//
//																						//
//																						//
//======================================================================================//
//	USAGE Descriptions																	//
//======================================================================================//
//																						//
//	var port_open_read(char* portname, char* config);									//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Opens a communications port for reading.										//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	portname = The windows name for the port. eg COM1. 	  (see NOTES#1)	//
//			char*	config	 = The serial port settings. eg "9600,n,8,1"  (see NOTES#2)	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:																		//
//					NULL = Port could not be opened.									//
//					else = A VAR handle for the open port.								//
//																						//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_open_write(char* portname, char* config);									//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Opens a communications port for writing.										//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	portname = The windows name for the port. eg COM1. 	  (see NOTES#1)	//
//			char*	config	 = The serial port settings. eg "9600,n,8,1"  (see NOTES#2)	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:																		//
//					NULL = Port could not be opened.									//
//					else = A VAR handle for the open port.								//
//																						//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_open_readwrite(char* portname, char* config);								//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Opens a communications port for both reading and writing.						//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	portname = The windows name for the port. eg COM1. 	  (see NOTES#1)	//
//			char*	config	 = The serial port settings. eg "9600,n,8,1"  (see NOTES#2)	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:																		//
//					NULL = Port could not be opened.									//
//					else = A VAR handle for the open port.								//
//																						//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	void port_close(var port);															//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Closes a communications port that was previously opened for reading or writing.	//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	NONE																//
//																						//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_read_status(var port);														//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Checks the "IDLE" status of an open communications port.						//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	TRUE   = Port is IDLE. Ready for read/write. (writing untested)		//
//					FALSE  = Port is BUSY. Waiting to Send, or Still Receiving.			//
//																						//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_read_buffer_size(var port);												//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Checks how full the READ buffer is in bytes.									//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	-1   = Port was opened for WRITE-ONLY.								//
//					else = Number of bytes in use.										//
//																						//
//																						//
//																						//
//																						//
//======================================================================================//
//	PORT READING FUNCTIONS																//
//======================================================================================//
//																						//
//	var port_read_bytes(var port, void* outdata, long bytes);							//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Reads a "block" of data into a buffer, to a maximum length of 'bytes'.			//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	outdata = A pointer to an output-buffer to store the data in.		//
//			long	bytes	= The maximum length of the output-buffer.					//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	-1   = The port handle was invalid or the Port is WRITE-ONLY.		//
//					 0	 = There was NO data in the READ-buffer to retrieve.			//
//					else = The number of bytes retieved from the READ-buffer.			//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_read_string(var port, STRING* outdata);									//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Reads a null-terminated string and overwrites the contents of 'outdata'.		//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	outdata = A pointer to valid STRING object to store the data in.	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	-1   = The port handle was invalid or the Port is WRITE-ONLY.		//
//					 0	 = There was NO data in the READ-buffer to retrieve.			//
//					else = The length of the retrieved string.							//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_read_number(var port, DWORD* outdata);										//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Reads a 4-byte number (long,int,DWORD,var,float) and stores it at 'outdata'.	//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	outdata = A pointer to valid numeric object to store the data in.	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	-1   = The port handle was invalid or the Port is WRITE-ONLY.		//
//					 0	 = There was NO data in the READ-buffer to retrieve.			//
//					 4   = The length in bytes of the retrieved number.					//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_read_double(var port, double* outdata);									//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Reads an 8-byte number (double)	and stores it at 'outdata'.						//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	outdata = A pointer to valid numeric object to store the data in.	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	-1   = The port handle was invalid or the Port is WRITE-ONLY.		//
//					 0	 = There was NO data in the READ-buffer to retrieve.			//
//					 8   = The length in bytes of the retrieved number.					//
//																						//
//																						//
//																						//
//======================================================================================//
//	PORT WRITING FUNCTIONS																//
//======================================================================================//
//																						//
//	var port_write_bytes(var port, void* data, long bytes, long ms_wait);				//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Writes a "block" of data from a buffer, for a length of 'bytes'.				//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	data 	= A pointer to an output-buffer to send the data in.		//
//			long	bytes	= The length in bytes of the output-buffer.					//
//			long	ms_wait	= The TIMEOUT period in milliseconds after which to abort.	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	 0   = The port handle was invalid or the Port is READ-ONLY.		//
//					 0	 = There 'data' buffer pointer is NULL.							//
//					< MAX_READ_BUFFER = The number of bytes INSTANTLY sent.				//
//					else = A spurious huge number because the send has been delayed.	//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_write_string(var port, STRING* data, long ms_wait);						//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Writes a null-terminated string from the supplied STRING object.				//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	data 	= A pointer to valid STRING object to send the data from.	//
//			long	ms_wait	= The TIMEOUT period in milliseconds after which to abort.	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	 0   = The port handle was invalid or the Port is READ-ONLY.		//
//					 0	 = There 'data' buffer pointer is NULL.							//
//					< MAX_READ_BUFFER = The number of bytes INSTANTLY sent.				//
//					else = A spurious huge number because the send has been delayed.	//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_write_number(var port, DWORD* data, long ms_wait);							//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Writes a 4-byte number (long,int,DWORD,var,float) pointed to by 'outdata'.		//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	data 	= A pointer to valid numeric object to send the data from.	//
//			long	ms_wait	= The TIMEOUT period in milliseconds after which to abort.	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	 0   = The port handle was invalid or the Port is READ-ONLY.		//
//					 0	 = There 'data' buffer pointer is NULL.							//
//					< MAX_READ_BUFFER = The number of bytes INSTANLT sent.				//
//					else = A spurious huge number because the send has been delayed.	//
//																						//
//																						//
//																						//
//======================================================================================//
//																						//
//	var port_write_double(var port, double* data, long ms_wait);						//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Writes an 8-byte number (double) pointed to by 'outdata'.						//
//																						//
//--------------------------------------------------------------------------------------//
//																						//
//		Parameters:																		//
//			char*	port 	= The VAR handle of a previously opened communications port.//
//			void*	data 	= A pointer to valid numeric object to send the data from.	//
//			long	ms_wait	= The TIMEOUT period in milliseconds after which to abort.	//
//																						//
//--------------------------------------------------------------------------------------//
//		Returns:	 0   = The port handle was invalid or the Port is READ-ONLY.		//
//					 0	 = There 'data' buffer pointer is NULL.							//
//					< MAX_READ_BUFFER = The number of bytes INSTANLT sent.				//
//					else = A spurious huge number because the send has been delayed.	//
//																						//
//																						//
//																						//
//======================================================================================//
//======================================================================================//
//																						//
//																						//
//======================================================================================//
//======================================================================================//
//																						//
//	NOTES#1	::	PORT Naming Convention	(from known and tested ports)					//
//		"COM1", "com1", "COM1:", "com1:"												//
//		"COM2", "com2", "COM2:", "com2:"												//
//		"COM3", "com3", "COM3:", "com3:"												//
//		"COM4", "com4", "COM4:", "com4:"												//
//																						//
//======================================================================================//
//======================================================================================//
//																						//
//	NOTES#2	::	SERIAL PORT SETTINGS - "WWWWW,X,Y,Z [,A]"	(eg "9600,n,8,1" )			//
//																						//
//	WWWWWW	= Baud Rate (110, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200)	//
//	X		= Parity ( 'n' = None, 'o' = Odd, 'e' = Even, 'm' = Mark, 's' = Space )		//
//	Y		= Data Bits ( 5, 6, 7, 8 )													//
//	Z		= Stop Bits ( 1, 1.5, 2 )													//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//
//	A		= [ OPTIONAL ] Hardware Flow Control										//
//					no entry	= NONE	(default)		(eg "9600,n,8,1" )				//
//					,x			= Xon/Xoff				(eg "9600,n,8,1,x" )			//
//					,p			= Hardware				(eg "9600,n,8,1,p" )			//
//																						//
//	NOTE:: Option 'A' being other than default has not HARDWARE tested					//
//																						//
//======================================================================================//
//======================================================================================//
//																						//
//	NOTES#3 :: TWEAKABLES																//
//																						//
#define	MAX_PORTS		20		//Maximum number of open IO-Ports						//
#define	MAX_READ_BUFFER	10240	//Size (in bytes) in READ buffer/s	(10240 = 10kb)		//
//																						//
//																						//
//======================================================================================//
//======================================================================================//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//	ANY CHANGES MADE FROM HERE ON IN ARE AT YOUR OWN RISK !  PROCEED WITH CAUTION !		//
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//	API linkages																		//
//////////////////////////////////////////////////////////////////////////////////////////
//																						//
long __stdcall _GetLastError();															//
#define PRAGMA_API _GetLastError;kernel32!GetLastError									//
//																						//
#ifndef windows_h																		//
//	long __stdcall GetCommState(long hFile, long lpDCB);								//
//	#define PRAGMA_API GetCommState;kernel32!GetCommState								//
	long __stdcall BuildCommDCB(char* lpDef, long lpDCB);								//
	#define PRAGMA_API BuildCommDCB;kernel32!BuildCommDCBA								//
	long __stdcall SetCommState(long hFile, long lpDCB);								//
	#define PRAGMA_API SetCommState;kernel32!SetCommState								//
	long __stdcall CreateFile(char*,long,long,long,long,long,long);						//
	#define PRAGMA_API CreateFile;kernel32!CreateFileA									//
	long __stdcall ReadFile(long,long,long,long,long);									//
	#define PRAGMA_API ReadFile;kernel32!ReadFile										//
	long __stdcall WriteFile(long,long,long,long,long);									//
	#define PRAGMA_API WriteFile;kernel32!WriteFile										//
	long __stdcall CreateEvent(long,long,long,char*);									//
	#define PRAGMA_API CreateEvent;kernel32!CreateEventA								//
	long __stdcall WaitForSingleObject(long,long);										//
	#define PRAGMA_API WaitForSingleObject;kernel32!WaitForSingleObject					//
	long __stdcall GetOverlappedResult(long,long,long,long);							//
	#define PRAGMA_API GetOverlappedResult;kernel32!GetOverlappedResult					//
	long __stdcall CloseHandle(long);													//
	#define PRAGMA_API CloseHandle;kernel32!CloseHandle									//
	long __stdcall FormatMessage(long,long,long,long,char,long,long);					//
	#define PRAGMA_API FormatMessage;kernel32!FormatMessageA							//
#endif	//windows_h																		//
//																						//
//																						//
//======================================================================================//
//======================================================================================//
//	Port Access WORKSPACE																//
//======================================================================================//
//																						//
long open_port[MAX_PORTS][3];															//
void open_port_startup()  {  var i;  for(i=0;i<MAX_PORTS;i++)  open_port[i][0]=0;  }	//
void port_read_worker(var);	//function prototype for PORT-READing worker 'thread'		//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//																						//
//	PORT ACCESS FUNCTIONS																//
//																						//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_open_read(char* portname, char* config)
{	if((!portname)||(!config))	return(0);	//invalid (EMPTY) data pointer/s
	STRING* dev_name = str_create("\\\\.\\");	str_cat(dev_name, _str(portname));
	long *ols  = malloc(sizeof(long)*6);		memset(ols,0,sizeof(long)*6);
	long *dcb  = malloc(sizeof(long)*8);		memset(dcb,0,sizeof(long)*8);
	long *buff = malloc(MAX_READ_BUFFER);		memset(buff,0,MAX_READ_BUFFER);
	long port;		var s=0, i;	
	port = CreateFile(dev_name.chars, 0x80000000, 0,0, 0x3, 0x40000000, 0);
	str_remove(dev_name);
	if(port!=-1)
	{	if(BuildCommDCB( config, dcb))	//decode supplied port-config
		{	if(SetCommState(port, dcb))		//configure port to new config
			{	if(ols[4]=CreateEvent(NULL,true,false,NULL))
				{	for(i=1;i<MAX_PORTS;i++)  if(!open_port[i][0])  break;	
					if(i<MAX_PORTS)
					{	open_port[i][0] = port;
						open_port[i][1] = ols;
						open_port[i][2] = buff;
						ols[5]          = 0;
						port_read_worker(i);
						return(i);				//SUCCESS, return port-handle
		}	}	}	}
		CloseHandle(port);
	}
	free(dcb);				free(ols);
	return(s);	//file has NOT been opened.
}
//
void port_read_worker(var port)
{	if(!open_port[port][0])		return;		//ABORT - invalid handle
	long  rport = open_port[port][0];	
	long* ols   = (long*)open_port[port][1];	ols[5] = 0; //filled-to pos
	void* data  = (void*)open_port[port][2];
	long fWaitingonread=false;
	while(open_port[port][0])
	{	if(!fWaitingonread)
		{	if(!ReadFile(rport, (long)data+ols[5], MAX_READ_BUFFER-ols[5], NULL, ols))
			{	if(_GetLastError()==997)	fWaitingonread = true;	 }
			else	
			{	fWaitingonread = false;   ols[5] += ols[1];   }	//INSTANT-read succeeded
		}
		else
			if(!WaitForSingleObject(ols[4],0))
			{	fWaitingonread = false;   ols[5] += ols[1];   }	//DELAYED-read succeeded
		wait(1);
}	}
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_read_status(var port)
{	if(!open_port[port][0])		return(0);	//invalid handle
	long* ols 	= (long*)open_port[port][1];	
	if(WaitForSingleObject(ols[4],1)==0x00000102)	return(1);		//port idle
	return(0);		//port busy
}
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_read_buffer_size(var port)
{	if(!open_port[port][0])		return(0);	//invalid handle
	long* ols 	= (long*)open_port[port][1];	
	return(ols[5]);
}
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_open_write(char* portname, char* config)
{	if((!portname)||(!config))	return(0);	//invalid (EMPTY) data pointer/s
	STRING* dev_name = str_create("\\\\.\\");	str_cat(dev_name, _str(portname));
	long *ols = malloc(sizeof(long)*5);		memset(ols,0,sizeof(long)*5);
	byte *dcb = malloc(sizeof(long)*8);		memset(dcb,0,sizeof(long)*8);
	long port;		var s=0, i;	
	port = CreateFile(dev_name.chars, 0x40000000, 0,0, 0x3, 0x40000000, 0);
	str_remove(dev_name);
	if(port!=-1)
	{	if(BuildCommDCB( config, dcb))	//decode supplied port-config
		{	if(SetCommState(port, dcb))		//configure port to new config
			{	if(ols[4]=CreateEvent(NULL,true,false,NULL))
				{	for(i=1;i<MAX_PORTS;i++)  if(!open_port[i][0])  break;	
					if(i<MAX_PORTS)
					{	open_port[i][0] = port;
						open_port[i][1] = ols;
						open_port[i][2] = NULL;
						ols[5]          = -1;
						return(i);			//SUCCESS, return port-handle
		}	}	}	}
		CloseHandle(port);
	}
	free(dcb);				free(ols);
	return(s);	//file has NOT been opened.
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_open_readwrite(char* portname, char* config)
{	if((!portname)||(!config))	return(0);	//invalid (EMPTY) data pointer/s
	STRING* dev_name = str_create("\\\\.\\");	str_cat(dev_name, _str(portname));
	long *ols  = malloc(sizeof(long)*5);	memset(ols,0,sizeof(long)*5);
	byte *dcb  = malloc(sizeof(long)*8);	memset(dcb,0,sizeof(long)*8);
	long *buff = malloc(MAX_READ_BUFFER);	memset(buff,0,MAX_READ_BUFFER);
	long port;		var s=0, i;	
	port = CreateFile(dev_name.chars, 0xC0000000, 0,0, 0x3, 0x40000000, 0);
	str_remove(dev_name);
	if(port!=-1)
	{	if(BuildCommDCB( config, dcb))	//decode supplied port-config
		{	if(SetCommState(port, dcb))		//configure port to new config
			{	if(ols[4]=CreateEvent(NULL,true,false,NULL))
				{	for(i=1;i<MAX_PORTS;i++)  if(!open_port[i][0])  break;	
					if(i<MAX_PORTS)
					{	open_port[i][0] = port;
						open_port[i][1] = ols;
						open_port[i][2] = buff;
						ols[5]          = 0;
						port_read_worker(i);
						return(i);			//SUCCESS, return port-handle
		}	}	}	}
		CloseHandle(port);
	}
	free(dcb);				free(ols);
	return(s);	//file has NOT been opened.
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
void port_close(var port)
{	if(open_port[port][0])
	{	//only close ports if it is still open.
		long* ols = (long*)open_port[port][1];
		proc_mode = PROC_LATE;		wait(1);
		while(ols[1]<=0)	wait(1);	//wait till idle
		CloseHandle(open_port[port][1]);		//close event
		CloseHandle(open_port[port][0]);		//close port
		free(open_port[port][0]);
	}
	if(open_port[port][2])	free(open_port[port][2]);
	open_port[port][0] = open_port[port][1] = open_port[port][2] = NULL;
}
//
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//	Start Port READING Functions														//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_read_bytes(var port, void* outdata, long bytes)
{	if(!open_port[port][0])		return(-1);	//invalid handle
	if(!outdata)				return(-1);	//invalid pointer to buffer
	long* ols   = (long*)open_port[port][1];
	if(!ols[5])					return(0);	//No data to retrieve, buffer EMPTY
	if(bytes>ols[5])			bytes = ols[5];
	byte* data  = (byte*)open_port[port][2];
	long i;   for(i=0;i<bytes;i++)	if(i<MAX_READ_BUFFER)   ((byte*)outdata)[i]=data[i];
	for(i=0; i<(ols[5]-bytes); i++)		data[i] = data[i+bytes];		ols[5] -= bytes;
	for(i=ols[5]; i<MAX_READ_BUFFER; i++)		data[i] = 0;
	return(bytes);
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_read_string(var port, STRING* outdata)
{	if(!open_port[port][0])		return(-1);	//invalid handle
	if(!outdata)				return(-1);	//invalid pointer to buffer
	long* ols   = (long*)open_port[port][1];	
	if(!ols[5])					return(0);	//No data to retrieve, buffer EMPTY
	char* data  = (char*)open_port[port][2];			str_cpy(outdata, data);	
	long bytes;   for(bytes=0;bytes<ols[5];bytes++)		if(data[bytes])		break;
	long i;   for(i=0;i<bytes;i++)	if(i<MAX_READ_BUFFER)   ((byte*)outdata)[i]=data[i];
	for(i=0; i<(ols[5]-bytes); i++)		data[i] = data[i+bytes];		ols[5] -= bytes;
	for(i=ols[5]; i<MAX_READ_BUFFER; i++)		data[i] = 0;
	return(bytes-1);
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_read_number(var port, DWORD* outdata)
{	if(!open_port[port][0])		return(-1);	//invalid handle
	if(!outdata)				return(-1);	//invalid pointer to buffer
	long* ols   = (long*)open_port[port][1];	
	if(ols[5]<4)				return(0);	//Not enough data to retrieve a 4-byte number
	byte* data  = (byte*)open_port[port][2];	*outdata = ((DWORD*)data)[0];	
	long i;	for(i=0; i<(ols[5]-4); i++)		data[i] = data[i+4];		ols[5] -= 4;
	for(i=ols[5]; i<MAX_READ_BUFFER; i++)		data[i] = 0;
	return(4);
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_read_double(var port, double* outdata)
{	if(!open_port[port][0])		return(-1);	//invalid handle
	if(!outdata)				return(-1);	//invalid pointer to buffer
	long* ols   = (long*)open_port[port][1];	
	if(ols[5]<8)				return(0);	//Not enough data to retrieve a 8-byte number
	byte* data  = (byte*)open_port[port][2];	*outdata = ((double*)data)[0];	
	long i;	for(i=0; i<(ols[5]-8); i++)		data[i] = data[i+8];		ols[5] -= 8;
	for(i=ols[5]; i<MAX_READ_BUFFER; i++)		data[i] = 0;
	return(8);
}
//
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//	Start Port WRITING Functions														//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_write_bytes(var port, void* data, long bytes, long ms_wait)
{	if(!open_port[port][0])		return(0);	//invalid handle
	long* ols = (long*)open_port[port][1];	
	while((proc_status(port_write_bytes))&&(ols[1]==-1))	wait(1);
	if(WriteFile(open_port[port][0], data, bytes, NULL, ols)!=-1)
	{	if(_GetLastError()==997)
		{	ols[1] = -1;	proc_mode = PROC_LATE;
			float timr=0;	while(timr<ms_wait)
			{	if(!WaitForSingleObject(ols[4],0))	break;
				timr += time_frame*64;				wait(1);
}	}	}	}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_write_string(var port, STRING* data, long ms_wait)
{	if(!open_port[port][0])		return(0);	//invalid handle
	return(port_write_bytes(port, data.chars, data.length, ms_wait));
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_write_number(var port, DWORD* data, long ms_wait)
{	if(!open_port[port][0])		return(0);	//invalid handle
	return(port_write_bytes(port, data, 4, ms_wait));
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
var port_write_double(var port, double* data, long ms_wait)
{	if(!open_port[port][0])		return(0);	//invalid handle
	return(port_write_bytes(port, data, 8, ms_wait));
}
//
//
//////////////////////////////////////////////////////////////////////////////////////////
//
////
#endif	//port_io_h





Posted By: the_mehmaster

Re: Serial Communications Header - 07/23/09 05:28

Wonderful contribution evilSOB!
I'll be sure to test it out.smile

I think you should 'ask the developers' to implement this into the engine.
Posted By: Felixsg

Re: Serial Communications Header - 07/23/09 07:56

if I renember wheel is already implement
Posted By: Joozey

Re: Serial Communications Header - 07/23/09 08:48

Can you explain what this exactly is/does?

Thanks,
Joozey
Posted By: Joozey

Re: Serial Communications Header - 07/23/09 08:59

Can you explain what this exactly is/does?

Thanks,
Joozey
Posted By: the_mehmaster

Re: Serial Communications Header - 07/23/09 09:13

What it does:
This header enables lite-c to interface to the (9 pin) serial communication ports.
The existing port io header only works with (25 pin) parallel ports.

Why it is needed:
Serial communication is a quick, simple way to interface to slave devices such as:

-Microcontrollers
-Sensors (accelerometer, GPS)
-External LCDs

Using these devices you could make a lightgun or something like that.
Posted By: Joozey

Re: Serial Communications Header - 07/23/09 09:26

Nice contribution indeed smile
Thanks!
Posted By: EvilSOB

Re: Serial Communications Header - 07/23/09 12:06

Bump!

Lead-Post updated a bit to clarify what it actually does! And its plans for the future.
Sorry Joozey, I was at the end of a 12hr night-shift, and the brain was a bit blurry.

Ive updated the header again, as the "bi-directional" code is now included and looks good.
But I feel like doing something else tonight, but I will still respond if anyone posts any problems/suggestions.
Posted By: the_mehmaster

Re: Serial Communications Header - 07/23/09 22:17

I'm assuming you have tested this..
Could you post your test-script please?

Just for simple port reading.
Posted By: EvilSOB

Re: Serial Communications Header - 07/24/09 10:30

It was tested, but only lightly.
I have since discovered there was a TYPO in it which meant it only worked if you included windows.h, which I was doing accidently.

To fix, replace all the #define's with what is in it now. (Ive fixed the header-post code).
Or find the line long __stdcall BuildCommDCB(char lpDef, long lpDCB); and replace it with long __stdcall BuildCommDCB(char* lpDef, long lpDCB);
(just one missing asterix...)

I have been doing my testing using a null-model cable connecting twp PC's and using the windows program "HyperTerminal" on the 'other' PC.
(The code was tested using a "factory" null-modem cable with both real serial ports and ONE type of USB->Serial adapter, that fakes a serial port very well)

NOTE: I think I MAY have found a minor bug that is preventing the port from being configured correctly.
This USED to work, so it shouldnt be too hard to fix. Im looking at it now.
NO FAULT FOUND

the_mehmaster :: here is a test "main" for you to try. All it does is display the last byte recieved.
If you need something more 'specific' than this, let me know what you are doing...
MAIN.C
Code:
#include <acknex.h>
#include <default.c>
#include "Port_IO.h"

TEXT* debug = {  pos_x=20;  pos_y=20;  size_y=400; font="Arial#20b";  strings=20;  flags=SHOW + WWRAP;  }

function main()
{
	wait(1);	level_load(NULL);	wait(1);	diag("\n\n\n");
	on_esc = NULL;
	//
	//
	byte last_recieved = 0;
	var hPort = port_open_read("COM1", "9600,n,8,1");
	//	
	while(1)
	{
		if(port_read_bytes(hPort,&last_recieved,1))
		{
			str_cpy((debug.pstring)[0], "Last Byte Recieved = ");
			str_cat((debug.pstring)[0], _chr(str_for_int(NULL,(long)last_recieved)));
		}
		if(key_esc)	break;
		wait(1);
	}
	port_close(hPort);
	//
	//
	sys_exit("");	
}


Posted By: the_mehmaster

Re: Serial Communications Header - 07/24/09 10:55

That should work finesmile. I'm testing PIC communication.

[EDIT] Setup, if you need it:

Test 1:
PIC(TX)->Serial2UsbCable(COM3)->Computer(RX)

Test 2:
PIC(TX)->SerialCable(COM1)->Computer(RX)

The PIC (16F84A at 20mhz) is programmed to transmit 'A' (ASCII 65) every second.

I'll post the results when I'm done.
Posted By: EvilSOB

Re: Serial Communications Header - 07/24/09 12:41

Try changing the loop to something like this then. It will make your 'input' more noticable.

The sample I gave before will only show the arrival of the first, unless you re-code the pic to transmit "changing" numbers.

Code:
while(1)
{
	str_cpy((debug.pstring)[0], "Last Byte Recieved = ");
	if(port_read_bytes(hPort,&last_recieved,1))
		str_cat((debug.pstring)[0], _chr(str_for_int(NULL,(long)last_recieved)));
	if(key_esc)	break;
	wait(-0.25);
}


Posted By: EvilSOB

Re: Serial Communications Header - 07/30/09 00:00

BUMP...

Does anyone have any further comments on this?
I haven found any further bugs, but has anyone had any successes/failures with it?
And any suggestions for improvement / enhancements?
Posted By: seecah

Re: Serial Communications Header - 07/30/09 08:12

Wow meh, I wish I have time doing that thing also... I'm really interested in PIC and some interfacing programming.. :-)

By the way how much is the cost of 16F84A in your country recently? During my college years, it costs about 3-5 US dollar - converted to piso..

It's really nice to hear about this stuff...
Posted By: EvilSOB

Re: Serial Communications Header - 07/30/09 08:36

Ive still go 20+ in stock, and I bought those a couple of years back.
But I just checked my local stores website and they are Aus$ 6.50 each.($4.50 bulk 10+)
[EDIT] Thats about 2 loaves of bread...

Posted By: the_mehmaster

Re: Serial Communications Header - 07/30/09 08:44

@EvilSOB:
My programmer broke(no joke, this isn't a lame excuse)
I guess i'll have to buy a proper one. (The one i used I built myself..).
Computer-to-computer communication works fine though on my end.

@Seecah:
The 'Wow' should go to EvilSOB, who was the one who made this!smile
Prices in $AU, from a local electronics shop:
- PIC16F88.....$12
- PIC10F**.....$6
- dsPIC30F**...$20
- PIC16F877A...$13
- PIC16F84A....$7

@Everyone reading this thread:
If anyone owns a programmer or similar, could they carry out some simple tests?
Posted By: seecah

Re: Serial Communications Header - 07/30/09 09:50

Actually I have a circuit for PIC programmer.. hahahahhaa.. I still have to find it.. You can program your PIC just in the breadboard.. so what did you use? MPLab? and load the hex file?
Posted By: the_mehmaster

Re: Serial Communications Header - 07/30/09 10:31

I use GCbasic which is a free BASIC compiler. It makes the .asm and .hex
WinPic is what i use to load the hex file onto the chip
Posted By: EvilSOB

Re: Serial Communications Header - 07/30/09 11:51

Quote:
@Everyone reading this thread:
If anyone owns a programmer or similar, could they carry out some simple tests?
I've three or four in a drawer somewhere gathering dust, both purchased and self-designed.
One is even a parallel-port one, but my main PC doesnt even have one of them anymore...

What do you need to know? (I'll need a day to find and re-connect one of them)

[EDIT]Ha! Found the software, PicPro v3.63 January 2000.....GOD, has it been that long?
Posted By: the_mehmaster

Re: Serial Communications Header - 07/30/09 12:00

Quote:
What do you need to know?


The main thing i would like to know is if lite-c will successfully read bytes sent from a PIC through a USB-serial(rs232) cable.

Those are the tests i was going to do but my programmer broke. frown

thankyousmile
Posted By: EvilSOB

Re: Serial Communications Header - 07/30/09 12:20

I dont see why not, assuming the pic uses a decent serial routine,
and you connect via a max232 line driver for a guarantee, unreliable otherwise.

I dunno if I can just "throw" together even something that simple,
looking at my archives, I haven done any actual MP-Lab PIC coding since October 2003 !
Ive got the parts, but the skills may be a little weak. And Im on day-shift which limits my "play" time.

But I'll give it a try... Gimma a couple of days...
Posted By: the_mehmaster

Re: Serial Communications Header - 07/30/09 21:08

My programmer was also my testbed (LEDs, SerialPort with max232, switches, lcd).
And it cost quite a bit too. I think I'll try and fix it before i buy a new one.

I'd like to see how you'll go though..smile
Posted By: EvilSOB

Re: Serial Communications Header - 07/30/09 22:11

Definately fix first... PM me on this and I may be able to help fault-find.
Posted By: the_mehmaster

Re: Serial Communications Header - 08/09/09 01:21

In response to 27 fault-finding PMs:
Originally Posted By: me
Yes!.. YEs!.. YES! It Works now!

All i did was resolder the ICSP header, And it works!

I've never missed a programmer so much.. I guess you can easily take things for granted smile

Couldn't have done it without you, evilSOB.. Thanks!

Now all i have to do is learn hitech C cool ..

Posted By: kasimir

Re: Serial Communications Header - 08/16/09 16:44

very interessting!

Does anyone test this code with USB?
Is it f.e. possible to check my mouse-input?
Posted By: EvilSOB

Re: Serial Communications Header - 08/16/09 22:44

I'd give you a hand if I could figure out the device name of the mouse.
According to the API documentation it SHOULD be able to.
Ive not played with and true USB devices yet.
I tested this code with a USB-to-Serial adapter, but windows recognised it as a
serial port, so it doesnt really count as a USB test like you are requesting.

I'll do a bit of digging and see what I can come up with though.
Posted By: kasimir

Re: Serial Communications Header - 08/19/09 19:23

thx,

if found following three commands, but i am not able to get them running:

Code:
usbhandle = CreateFile( ...USB PORT GUID...,
                    GENERIC_WRITE,
                    FILE_SHARE_WRITE,
                    NULL,
                    OPEN_EXISTING,
                    0,
                    0 );


-> here i get an error - GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_EXISTING do not exist... ???

Code:
DeviceIoControl( usbhandle, 0x04, pIn, sizeof(szIn), pOut,
                        sizeof(szOut), lpByte, NULL );



0x04
pIn
szIn
pOut
szOut

...are specific port-functions/ bites to read...

and
Code:
CloseHandle( usbhandle );


Posted By: EvilSOB

Re: Serial Communications Header - 08/20/09 04:21

I dont follow what you are actually asking for questions 2 and 3.

But or question 1, here are all the "contants" I ever used.
I ended up hard-coding the values into the functions to reduce
the source-file complexity-of-reading.
Code:
#define GENERIC_READ	0x80000000
#define GENERIC_WRITE	0x40000000

#define FILE_SHARE_READ	0x1
#define FILE_SHARE_WRITE	0x2

#define CREATE_NEW 		0x1
#define CREATE_ALWAYS		0x2
#define OPEN_EXISTING		0x3
#define OPEN_ALWAYS		0x4
#define TRUNCATE_EXISTING		0x5

#define FILE_FLAG_OVERLAPPED	0x40000000

#define OF_READ	0x0
#define OF_WRITE	0x1



The problem with convrting my code to be USB friendly is
finding/retrieving the "...USB PORT GUID...".
I just cant figure out how...
Posted By: kasimir

Re: Serial Communications Header - 08/20/09 18:31

did you get this working (USB PORT GUID)???
i tried out some different desriptions, but nothing worked...
Posted By: EvilSOB

Re: Serial Communications Header - 08/21/09 03:22

I couldnt get enything to go.
But Im still VERY unsure if I was using the correct GUID.
Posted By: Nicholas

Re: Serial Communications Header - 11/22/09 22:27

I am very interested in getting this to work, but the engine gives me problems with the "str_for_int" it says undeclared identifier. There isn't anything in the manual.
The "SHOW" and "WWRAP" flags apparently don't work also (when I commented out the str line. I changed show to visible and it worked, but I don't know what to do with the wwrap so commenting it out seemed to work. (using a7)
Any ideas?
Posted By: EvilSOB

Re: Serial Communications Header - 11/22/09 22:50

You need to be using at least A7-7.50.
And if your using lite-c free, I dont know what its version is.

SHOW requires 7.66, if you are using an older version, replace it with VISIBLE.

'str_for_int' requires 7.50, if you are using an older version, replacing it with 'str_for_num' SHOULD work.

WWRAP requires 7.60, if you are using an older version, just delete the WWRAP flag.
But note that and text added to that TEXT panel will now only bo on the first line,
and will no longer auto-wrap to the next line when 'this' line is full.


Does anyone out there know what engine-version lite-c(FREE) is ATM ??
Posted By: Nicholas

Re: Serial Communications Header - 11/23/09 00:03

Awesome, thanks man. This will really help me a lot.
I've apparently been neglecting my updates since I've put some of my projects on hold for a while.

:-)
Posted By: Nicholas

Re: Serial Communications Header - 11/26/09 07:59

Ok, at first I was going nuts thinking it wasn't working with the exact same setup and code I was using, but I apparently found an issue. (I am using an FTDI usb serial chip making COM8 a virtual com port through my usb, works fine though)
I put in the code and test it with the arduino software and test that I am getting serial data on the right com port.
I open A7 and it works fine.
Here's the tricky part:
if I unplug my USB serial cable and plug it back in, A7 will not recognize it... I know the code is working because I see my rx light up at the proper interval. A7 won't connect until I connect and disconnect with another software (I use my arduino "serial monitor" for this. I connect, disconnect a few seconds later then run my code in A7 then it works again)
Any ideas on how to fix this problem?
Can anyone else verify this on their machine?
Posted By: EvilSOB

Re: Serial Communications Header - 11/26/09 09:11

Im not clear, but are you leaving A7 running DURING the unplug-replug process?

Also, try testing it using non-arduino software. (Say Hyperterminal on XP and below.)
It may be re-connecting on a different com port and the arduino software prolly doesnt care.

I did all my testing with hyperterminal <-> A7, a real serial port at the hyperterminal 'end'
and a generic usb stub that run with just windows built-in drivers at the A7 end.
Sometimes swapped over to ensure it worked the same way in both directions.

Another possible issue may be if the drivers are still initiallising when
A7 is started, it may not see that serial port yet.

I'll be listening...
Posted By: Nicholas

Re: Serial Communications Header - 11/26/09 09:29

I am hitting esc to close the port and program properly before unplugging.

Arduino software is setup to look at the same port number every time. I also checked through my device manager and it has "serial com port (COM8)" listed before I run A7.

The ftdi drivers seem to be working OK, I don't have an xp machine I can test on at the moment.
I thought it could just be taking a while for the drivers to load, so I gave it a decent amount of time before running my code. Also, if it's shown up in device manager, it should be loaded already. It is trying to look at the com port, I see my LEDs on my board light up as if it's talking to the PC the same way it does when I'm establishing a new connection, it just doesn't show any code coming in from the board.
Maybe I should test it for outgoing code to the board, send a number and if received light up an LED on a pin. Can I send using this code too?
If you can't reproduce the effect the same way, maybe it's a Win7 thing, I'll try setting up an older machine and test it the same way there.

edit: to test the output method I would assume I use port_write_bytes while checking to make sure port_read_status is true. does anyone have a sample of this for me to check, I have this so far used in the while loop
Quote:
if(port_read_status(hPort)==1) //TRUE = Port is IDLE. Ready for read/write. (writing untested)
{
var testz=77;
port_write_bytes(hPort, testz, 1, 500); // hPort, send 77, 1 byte, 500ms timeout?
}


Still not sure about if Win7 is the problem though
Posted By: EvilSOB

Re: Serial Communications Header - 11/26/09 10:32

The best my memory can supply this is ALMOST correct.

All that looks wrong to me is the buffer needs to be a null-pointer.
So the port_write_bytes should be port_write_bytes(hPort, &testz, 1, 500);

Otherwise the logic and syntax looks fine to me.

As for it being a windows7 issue, Ive not had access to anything higher than XP-sp3.
I think someone tested it OK in Vista, but I think your the first Win7 person.
But seeing as it works happily bufore the plug-unplug thing, I would say its a
Win7 'quirk', and I cant do anything about it myself till I get around to
building a Win7 test-box.

But I'll keep me eye here in case anyone comes up with anything I can tweak without win7.
Posted By: Nicholas

Re: Serial Communications Header - 11/26/09 19:45

I'm actually running Win7 beta, I just got the ultimate disk, so I'll be installing that soon. It has an xp compatible mode built in, just in case it is the problem.

I noticed the syntax on reading the var, I guess I didn't think to put it in the write (&testz), thanks. I'll be testing both issues soon and post back my findings.
Posted By: evilfantasy

Re: Serial Communications Header - 11/27/09 06:33

I wanted to come here for some fun ! Who can give? Thank you !

wubinuu@gmail.com
Posted By: qoolelee

Re: Serial Communications Header - 01/11/10 15:38

This is a great contribution to the GS community, thanks.

After tested it with your previous example code on my vista machine. I met two minor problems,

First, when port_open_read/write/readwrite my existing com port, it only suceeded once, after my exiting the script and re-run it again, the port_open_xxxx command seems not to work anymore. But when I close the SED then reopen the SED, load the script, run it. It works again. (and Yes, the first script run only)

Listed bellow is my modified script from your example,

Code:
#include <acknex.h>
#include <default.c>
#include "Port_IO.h"

TEXT* debug = {  pos_x=20;  pos_y=20;  size_y=400; font="Arial#20b";  strings=20;  flags=SHOW + WWRAP;  }

var hPort;

function main()
{
	wait(1);	level_load(NULL);	wait(1);	diag("\n\n\n");
	on_esc = NULL;
	//
	//

	hPort = port_open_readwrite("COM9", "2400,n,8,1");
	
	wait(-1);
	//	
	while(1)
	{
		str_cpy((debug.pstring)[0], "Port Handle = ");
		str_cat((debug.pstring)[0], _chr(str_for_int(NULL,hPort)));
		if(key_esc)	break;
		wait(1); 
		
	}
	port_close(hPort);
	//
	//
	sys_exit("");	
}



Maybe the port_close needs more time to finish its operation before A7 closing ?

Second, the port_open_xxxx command seems not to be able to open the port number larger the 9 (e.g. 10, 11, 12 ....). Is there a way to get around this problem? since I use a virtual com port through a usb converter, it is very easy to get a virtual com port number larger than 9.

I apologize for my bad english, your kindly response will be much appreciated.

Again, thank you for your wonderful contribution. I really think conitec should include your work in next update.
Posted By: EvilSOB

Re: Serial Communications Header - 01/12/10 12:10

port_close waits for the port to be idle before it closes,
and I think thats the problem...

Try changing the port_close step to this...
Code:
...
    }
    port_close(hPort);
    while(proc_status(port_close))   wait(1);	
    //
    //
    sys_exit("");
}

Let me know how it goes... any changes in behaviour.
Then if its fixed I'll explain what was happening...
Posted By: qoolelee

Re: Serial Communications Header - 01/13/10 03:35

Thank you for your response.

The situation is the same, the second re-run of the script is still not able to successfully open the port in SED. After changing my device to com1 instead the usb virtual com9 port, still the same problem happened.

I've got a mcu device designed for my other project for stationary bike control, if it got the order control command "0xFD", it will return "0xFD R", where R stands for a single byte indicates the rpm of the bike. So I change the script to

Code:
#include <acknex.h>
#include <default.c>
#include "Port_IO.h"

TEXT* debug = {  pos_x=20;  pos_y=20;  size_y=400; font="Arial#20b";  strings=20;  flags=SHOW + WWRAP;  }

var hPort;
var temp;
var temp2;
byte sent_data = 0xFD;
byte received_data[2] = { 0x00, 0x00};

function main()
{
	wait(1);	level_load(NULL);	wait(1);	diag("\n\n\n");
	on_esc = NULL;
	//
	//

	hPort = port_open_readwrite("COM1", "2400,n,8,1");
	
	wait(-1);
	
	if(port_read_status(hPort))
	{
		temp = port_write_bytes(hPort, &sent_data, 1, 500);	// write to com1 1 byte 500ms time out
	}
	else
	{
		str_cpy((debug.pstring)[0], "Port is Busy");
	   port_close(hPort);
	   while(proc_status(port_close))   wait(1);
	   //
	   //
	   while(!key_any){wait(1);	}
	   sys_exit("");		
	}
	
	wait(-1);
	
	if(port_read_status(hPort))
	{
		port_read_bytes(hPort, received_data, 2);	// read data from com1 per 1 byte
	}
	
	//	
	while(1)
	{
		str_cpy((debug.pstring)[0], "Port Handle = ");
		str_cat((debug.pstring)[0], _chr(str_for_int(NULL,hPort)));
		str_cpy((debug.pstring)[1], "Data Sent = ");
		str_cat((debug.pstring)[1], _chr(str_for_int(NULL,temp)));	
		str_cpy((debug.pstring)[2], "Data Read [0]= ");
		str_cat((debug.pstring)[2], _chr(str_for_int(NULL,(long)received_data[0])));
		str_cpy((debug.pstring)[3], "Data Read [1]= ");
		str_cat((debug.pstring)[3], _chr(str_for_int(NULL,(long)received_data[1])));				
		if(key_esc)	break;
		wait(1); 
		
	}
	port_close(hPort);
	while(proc_status(port_close))   wait(1);
	//
	//
	sys_exit("");	
}



The result became more confusing,

1. the port sometimes is opened successfully, sometimes don't.
2. when press ecs key to end, sometimes the script crashes, sometimes don't.

result 1
result 2

Any advise will be much appreciated. laugh


Posted By: qoolelee

Re: Serial Communications Header - 01/13/10 05:37

Another test with my little mcu device, if send "0xFF T1 T2" 3 byte command, the device will return "0xFF T1 T2" immediantly.

Though the "Data send =" item on PC end still show the huge number but the LED digits on the mcu device show me it received the command and the T1 T2 bytes and number correctly. But on pc end it seems there's no return from it for me to show it on the computer window.

If I comment out the newly added "while(proc_status(port_close)) wait(1);" line it stop crashed.

Code:
#include <acknex.h>
#include <default.c>
#include "Port_IO.h"

TEXT* debug = {  pos_x=20;  pos_y=20;  size_y=400; font="Arial#20b";  strings=20;  flags=SHOW + WWRAP;  }

var hPort;
var temp;
var temp2;
byte sent_data[3] = {0xFF, 0x10, 0x00};
byte received_data[3] = {0x00, 0x00, 0x00};

function main()
{
	wait(1);	level_load(NULL);	wait(1);	diag("\n\n\n");
	on_esc = NULL;
	//
	//

	hPort = port_open_readwrite("COM1", "2400,n,8,1");
	
	wait(-1);
	
	
	if(port_read_status(hPort))
	{
		temp = port_write_bytes(hPort, sent_data, 3, 500);	// write to com1 1 byte 500ms time out
	}
	else
	{
		str_cpy((debug.pstring)[0], "Port is Busy");
	   port_close(hPort);
	   while(proc_status(port_close))   wait(1);
	   //
	   //
	   while(!key_any){wait(1);	}
	   sys_exit("");		
	}
	
	wait(-1);
	
	while(!port_read_status(hPort)){	wait(1);}
	
	if(port_read_status(hPort))
	{
		port_read_bytes(hPort, received_data, 3);	// read data from com1 3 byte
	}
	
	//	
	while(1)
	{
		str_cpy((debug.pstring)[0], "Port Handle = ");
		str_cat((debug.pstring)[0], _chr(str_for_int(NULL,hPort)));
		str_cpy((debug.pstring)[1], "Data Sent = ");
		str_cat((debug.pstring)[1], _chr(str_for_int(NULL,temp)));	
		str_cpy((debug.pstring)[2], "Data Read [0]= ");
		str_cat((debug.pstring)[2], _chr(str_for_int(NULL,(long)received_data[0])));
		str_cpy((debug.pstring)[3], "Data Read [1]= ");
		str_cat((debug.pstring)[3], _chr(str_for_int(NULL,(long)received_data[1])));
		str_cpy((debug.pstring)[4], "Data Read [2]= ");
		str_cat((debug.pstring)[4], _chr(str_for_int(NULL,(long)received_data[2])));				
		if(key_esc)	break;
		wait(1); 
		
	}
	port_close(hPort);
//	while(proc_status(port_close))   wait(1);
	//
	//
	sys_exit("");	
}



For your reference. Thanks.
Posted By: EvilSOB

Re: Serial Communications Header - 01/13/10 06:15

OK, Im having a think on this, but I need to refresh myself with
how my code works first, so give me time... maybe a couple of days...

Firstly, to try and remove the random "crash on exit issue",
try putting "on_esc=NULL;" at the beginning of main,
and re-enable my while(proc_status... line.
default.c has an on_esc function that almost-instant-closes.
I think it is making the code skip some (if not all) of the
port_close stages, thereby leaving the port open and crashing.


From memory, I have not (intentionally) limited the COM port numbers to 8,
but if I find something during my memory-refreshing process, I'll take it
out and let you know...
Posted By: qoolelee

Re: Serial Communications Header - 01/13/10 07:20

Really appreciate your quick response.

I must apologize to you, it's my fault, after checking my rusty mcu device. I found some glitch in my firmware.

After re-write and upload to the chip, it works in both reading and writing with your header. Except that on the PC end the port_write_bytes still returns a huge number.

Thank you for your great contribution and your continuous attention on this thread, I think I own you a beer. laugh

Wish you a best day.
Posted By: EvilSOB

Re: Serial Communications Header - 01/14/10 05:05

Hehe... been there, done that, myself.
Pulling the wrong MCU from the shelf sucks,
thats why I toss or erase all out-of-date mcu's now.

I'll have a look at the port-write-bytes again because
I can vaguely remember that being a bug I had for a while.
I thought I had fixed it but I may be wrong...
I dont remember if I tested it with an MCU, only with hyperterminal.
Posted By: charrua

Re: Serial Communications Header - 01/17/10 15:22

nice to see that i were not the only one interested in serial communications, my first post was on this subject about 2 years, in that time i posted code to do serial communications with liteC but on these days seems that few people were working on this topic (seen by many but only few posts). is good to see that serial communications are still alive!

i mantain my offer so if some needs some help, here i'm.
(edit: sorry, i should say: i'm back, i been disconected from this forum for a while, best regards)
(sorry my bad english)

Juan



Posted By: druid

Re: Serial Communications Header - 05/21/10 10:27

i have test the wonderful work and Thanks!

but i have a problem i didn't know whether it is my mistake or bug.

i have tried COM1~COM9 and it works fine,but COM10 and above is not connect correctly.

have anyone get similar problem?
Posted By: EvilSOB

Re: Serial Communications Header - 05/21/10 14:40

Ive just done a bit of research, and it SHOULD work for COM1 right through to COM256

The core API functions should allow this, according to several on-line sources.

But I dont have a USB device that will let me 'set' it above COM8 to test with ATM.
Im gonna try and beg/borrow/steal one in the next few days and I'll post my results...


FYI :: be certain you are trying to access the ports with COM in capital letters, and be sure there is no trailling "."
ie "COM25" is correct, but NOT "com25" or "COM25."
Posted By: EvilSOB

Re: Serial Communications Header - 05/23/10 03:13

Bug Found and fixed. Thanks for that druid.
The top post of this thread has been corrected.
Read the dark-green [EDIT] up there for explaination.

[WARNING :: TECHNICAL CONTENT]
Serial ports COM1 -> COM9 'appear' to be dos-legacy names,
whereas COM10 -> COM256 are not.
So when accessing the COM10 and above you NEED to lead the port name
with the 'root-path' accessor "\\.\" (eg \\.\COM25 ),
but when accessing ports 1->9 it is assumed by the OS.
My code now adds this accessor automatically, so you dont
NEED to know this, Im just giving this infomation out for the curious...

Posted By: druid

Re: Serial Communications Header - 07/23/10 20:32

i have a new question about using the " Serial Communications Header" on reading a number from serial,please help me.

i was using the "port_read_number(portSerial,tmp);" and tmp is a var. how can i get the right number from serial? i have only got 789516.xxxx things. i have tried print DEC,BIN,BYTE,String from the serial device.i have tried &tmp and float tmp or int tmp or long tmp and didn't get the right number.

if i use other serial tool,i can get the wanted number (0-9).what should i do?

thank u~~~
Posted By: EvilSOB

Re: Serial Communications Header - 07/24/10 00:18

What is the number being sent by the other device?
Is it a single byte, or a 4-byte long-integer, or what?

If you are trying to read a single BYTE, then use
Code:
// var tmp;   //assumed...
   BYTE tmp_byte=0;
   port_read_bytes(portSerial, &tmp_byte, 1);
   tmp = tmp_byte;



If you are trying to read a long-integer (ie "9, 0, 0, 0" )
Code:
// var tmp;   //assumed...
   long tmp_long=0;
   port_read_number(portSerial,&tmp_long);
   tmp = tmp_long;


Posted By: druid

Re: Serial Communications Header - 07/24/10 05:08

thank u EvilSOB
i follow ur advice and do these things:
the device send variable by "Serial.print(1000+speedCount);" 10 times a second.(speedCount is an int form 0 to 9.)

and i was trying to read a long-integer :
var tmp;
...//open Serial and other code.
long tmp_long=0;
port_read_number(portSerial,&tmp_long);
tmp = tmp_long;
and i got tmp=-1036239 .is there anything i mis-understanding?

or i have to send serial 4-byte long-integer in the format "1,0,0,0"-"1,0,0,9"?
Posted By: EvilSOB

Re: Serial Communications Header - 07/24/10 07:01

What language / hardware / platform is the "serial.print" being executed by?

I need to know is the serial.pring sending a 4-byte integer or something else...

If you can tell me what hardware/software is doing the talking I can look it up myself.
Posted By: druid

Re: Serial Communications Header - 07/24/10 14:15

EvilSOB, u r so kind hearted~~~
i am using arduino.
Posted By: druid

Re: Serial Communications Header - 07/24/10 14:17

here is the reference link

http://arduino.cc/en/Serial/Print
Posted By: EvilSOB

Re: Serial Communications Header - 07/25/10 00:12

I thought it might be. Arduino seems to be the only hardware around
that has a "serial.print" function. Ugly little thing that it is.

Now, is the +1000 'needed' for the finished product, or is it only for testing?
And are you able to change the arduino code?
Because if you can change the code, and the +1000 is un-necessary, you can use the following.
Code:
//arduino
   Serial.print(speedCount, BYTE);
or
   Serial.write(speedCount);  //does the same thing

//lite-c
   byte tmp_byte=0;
   port_read_bytes(portSerial, &tmp_byte, 1);
   tmp = tmp_byte;


This will let you send a value of speedCount of 0 -> 255

I cant test this of course, as I dont have any arduinos to test with.

Does this get you up and running? Do you NEED to send numbers larger than 255?
If it doesnt do exactly what you NEED, let me know.
Posted By: druid

Re: Serial Communications Header - 07/25/10 08:29

ok,that works. the +1000 is not for testing.
i have change both arduino and lite-c as u said and it works.
thank u ,Evilsob

last night,before getting ur reply,i tried this in lite-c:
Code:
byte last_recieved[2] = {0,0};
		if(port_read_bytes(hPort, last_recieved, 2)){
			
			str_cpy((debug.pstring)[0]," ");
			str_for_asc((debug.pstring)[0],(long)last_recieved[0]);
			str_for_asc(inNumber,(long)last_recieved[1]);
			str_cat((debug.pstring)[0],inNumber);
			debugDr=str_to_num((debug.pstring)[0]);
		}


it works too.

but i still don't understand the difference.
how to use port_read_number()? i found that u always use port_read_bytes().
it seems port_read_string() don't clear the Read-buffer,but port_read_bytes() did clear the buffer. am i mis-understanding?

is 4 byte integer means 4 byte binary data?
Posted By: EvilSOB

Re: Serial Communications Header - 07/25/10 14:17

"port_read_number" and "port_read_string" were really only meant for,
and only tested with, a lite-c application at BOTH ends.

The reason that I tend to use port-read_bytes all the time is because, at its lowest level,
that is what the port is 'physically' doing. So I keep thinking that way to avoid confusion.

In your arduino code, Im going to assume that speedCount is an arduino-int.(appears the same as a liteC-short)
Due to you saying so, and the fact you get two bytes back with your above code.
So try these code-combinations. If you dont mind...
Code:
//arduino
   Serial.write(1000+speedCount); 

//lite-c
   short tmp_number = 0;
   port_read_bytes(portSerial, &tmp_number, 2);
   tmp = tmp_number;

and let me know how it goes...

And try this one too...
Code:
//arduino
   Serial.write(1000L + speedCount); 

//lite-c
   long tmp_number = 0;
   port_read_number(portSerial, &tmp_number);
   tmp = tmp_number;

//if this fails, leave lite-c as is, but change the arduino code to
   long tmp_num = 1000 + speedCount;
   Serial.write(tmp_num);

Im curious on this one too...
Posted By: EvilSOB

Re: Serial Communications Header - 07/25/10 14:21

As for the buffer clearing, its old code so I cant remember well.
But it may be buggy, but more likely that because the arduino doesnt
put a null on the end of its Serial.print strings,
then my code doesnt know the string is finished.

[EDIT]
Quote:
is 4 byte integer means 4 byte binary data?
Yes, as in a datatype of "long". Both arduino and liteC appear to have this onein common.
See my second test for you above...



Posted By: Germanunkol

Re: Serial Communications Header - 12/04/10 19:23

Hi EvilSOB!
Thanks for this library. We've been using it for a couple of days to try and communicate with a Micro Controller.

We got the communication to work now, except for one problem:
If the connection is not constantly busy (constantly meaning sending stuff about once a second from MC to the COM port, it seems to "time out"). We're using a USB-Adapter, and here is the code:

Code:
void collectInput(var hPort)
{
	(inputText.pstring)[0] = inputStr;
	inputText.pos_y = screen_size.y - 25;
	while(1)
	{
		result = inkey(inputStr);
		//		while(inkey_active == ON) wait(1);
		if(result == 13)
		{
			port_write_bytes(hPort,_chr(inputStr), str_len(inputStr)+1,1);
			appendLine(sendTxt, inputStr);
		}
		str_cpy(inputStr, "               ");
		wait(1);
	}
}


byte singleByte = -1;
byte inputBytes[10] = {0,0,0,0,0,0,0,0,0,0};
double inputDouble = -1;
var resetCharArray()
{
	var count = 0;
	while(count < 10)
	{
		inputBytes[count] = 0;
		count += 1;
	}
}


void receiveData(var hPort)
{
	STRING* inputStr = str_create("");
	var count = 0;
	while(1)
	{
		if(key_esc)	break;
		
		result = port_read_bytes(hPort,singleByte,1);
		
		if(result > 0)
		{
			if(singleByte == 0 || count == 9)
			{
				count = 0;
				appendLine(receiveTxt, _str(inputBytes));
				resetCharArray();
			}
			else
			{
				inputBytes[count] = singleByte;
				count += 1;
			}
		}		
		wait(1);
	}
}


function main()
{
	wait(1);
	appendLine(sendTxt, "Started.");
	
	
	on_close = exit_safely;
	initLevel();
	on_esc = NULL;
	byte last_recieved = 0;
	hPort = port_open_readwrite("COM2", "9600,n,8,1");
	if(hPort)
	{
		collectInput(hPort);
		receiveData(hPort);
		wait_for(receiveData);
		port_close(hPort);
	}
	else
	{
		error("Error connecting to Port");
		while(key_esc == OFF) wait(1);
	}
	sys_exit("");	
}



We can't figure this one out.
If we don't send a "NULL" from the MC to the PC every second, then nothing seems to be received any more at all.
Posted By: EvilSOB

Re: Serial Communications Header - 12/06/10 06:14

OK, I'll take a look in the next day or so.

Im going to have to refresh my memory of this library,
AND dig up some external hardware to test with if I cant see any
obvious code-bugs in my or your coding...
(I have had un-resolved intermittant problems in the past with port_read_bytes
losing sync with its buffer at times so it may be something there)

FYI:: 90% of my testing was done through a USB-serial adaptor, so its
unlikely to have anything to do with that...

I'll let you know back here...
Posted By: Germanunkol

Re: Serial Communications Header - 12/06/10 19:35

Thank you a lot!

I've spent quite a few hours now with your code. Apart from initial problems where I didn't understand how it worked and then a few troubles with strings, it's been working great.
We're building a prototype 3d-scanner with 2 motors and a distancescanner which displays its data in acknex, plotted using draw_line3d. It's a really fun project, and even though it's very simple and non-professional, we've already had some neat tests that we did.

Just to let you know what your code made possible laugh
Posted By: IngoS.

Re: Serial Communications Header - 01/11/11 20:42

Bei mir funktioniert das Lesen des COM Ports nur wenn ich zuvor einmal HyperTerminal gestartet und wieder beendet hatte.

Ohne dies, also nach dem Hochfahren des PC, kann ich nichts vom COM Port lesen. Senden funktioniert immer. Hat jemand eine Idee wora es liegt?

I.S.

read worked only if Hyperterminal executed once before and ended again?
Sending always works.
Is the computer started newly, read not working.
Does anybody have an idea?
Posted By: eaglelab

Re: Serial Communications Header - 07/12/11 09:35

I using Port_IO.h no problem when each time a byte is sent&#12290;
but when sending multiple consecutive bytes, are sent the wrong data.
code:
function func_write()
{

byte last_test[8] ={ 0x01, 0x02,0x03, 0x04,0x05, 0x06,0x07, 0x08};

port_write_bytes(hPortwrite, &last_test,8,50);
}
Posted By: EvilSOB

Re: Serial Communications Header - 09/25/11 01:47

Hiya guys, long time no see. Its been 6 months since Ive
even touched Gamestudio, so Im a bit rusty...
But Im trying to get back into it again, just to validate the
money I just spent upgrading to A8...

So I will be looking at all your problems, once Ive re-familiarised myself
with gamestudio in general, and POINTERS in particular, because
port_io.h was evil with them...
Posted By: ed_h

Re: Serial Communications Header - 01/12/12 20:38

Hi EvilSOB,

Thank you for posting the serial communications header. It's a very useful utility and a great way to start learning about API calls using Lite C.

Sending characters works flawlessly for me. There seems to be something odd happening in trying to receive them though. This has happened on 2 different computers using both hardware and USB adapter serial ports.

The first character received comes in fine. After that, when receiving individual characters, nothing happens. Receiving a continuous stream of characters does work though. This is consistent with Germanunkol's post. I'm receiving one byte at a time using the approach you recommended in another post:

"If you are trying to read a single BYTE, then use
Code:

// var tmp; //assumed...
BYTE tmp_byte=0;
port_read_bytes(portSerial, &tmp_byte, 1);
tmp = tmp_byte;"

I think what's happening is when a receive buffer is initially empty, the first character in the buffer is received fine. Once the buffer has received that initial character though, it's actually the second character that gets retrieved from then on. So, if you send a single character and the buffer never fills beyond that one character, you always retrieve a null character (the second character in the buffer). If characters come in faster than you retrieve them and the buffer fills a little, you do read valid data because the second buffer position then has something in it. The following test code demonstrates the effect:

#include <acknex.h> // Include header file required by the acknex engine.
#include <default.c> // Include default engine keys and functions.
#include <serial_io.h> // Include header file containing the serial routines.

TEXT* debug = { pos_x=20; pos_y=20; size_y=400; font="Arial#20b"; strings=20; flags=SHOW + WWRAP; }

var port_status;
var port_handle;
var char_counter = 0;

var temp;
byte tmp_byte;

function main()
{
wait(1); level_load(NULL); wait(1); diag("\n\n\n");
on_esc = NULL;

port_handle = port_open_readwrite("COM1", "9600,n,8,1");

wait(-1);

str_cpy((debug.pstring)[0], "Port Handle = ");
str_cat((debug.pstring)[0], _chr(str_for_int(NULL,port_handle)));

while(1)
{
if(port_read_buffer_size(port_handle) != 0)
{
++char_counter;

tmp_byte=0;
port_status = port_read_bytes(port_handle, &tmp_byte, 1);
temp = tmp_byte;
str_cpy((debug.pstring)[0], "Byte received char code = ");
str_cat((debug.pstring)[0], _chr(str_for_int(NULL,temp)));
str_cat((debug.pstring)[0], " Total characters = ");
str_cat((debug.pstring)[0], _chr(str_for_int(NULL,char_counter)));
}
else
{
str_cpy((debug.pstring)[0], "No byte received.");
str_cat((debug.pstring)[0], " Total characters = ");
str_cat((debug.pstring)[0], _chr(str_for_int(NULL,char_counter)));
}

if(key_esc) break;

wait(-1);
}

// data_byte[0] = 't';
// port_status = port_write_bytes(port_handle, &data_byte[0], 1, 500);

wait(-0.5);

port_close(port_handle);

sys_exit("");
}

With this program doing the receiving, when you transmit an initial character from another computer, its character code number will display fine. If you then send just a single character again, character code "0" will get displayed. You can send as many single characters as you like with the same resulting character code, as long as you wait until "No byte received." is displayed again. If you send two characters in quick succession though, you'll get a "0" code displayed for the first character received but a correct character code for the second character.

It seems to be something to do with buffer pointers that I'd really like to solve, but unfortunately, I don't have enough API programming or Lite C experience to figure out. In the mean time, I've hard coded a workaround in the header to only receive one byte at a time. It misses the initial character received when the program is first started but otherwise, it's good enough for now. A general solution would sure be great though and hopefully you might be able to find time to look at this.

Thanks again!
© 2024 lite-C Forums