In order to communicate with the serial port, you can use this solution. It works on Win32 so far.
Create a new file, paste this contents into it and add it to your project:
// --------------------------------- //
// Project: SerialPort
// Start: Wednesday, March 12, 2008
// IDE Version: 5.199
TYPE TComTimeouts
ReadIntervalTimeout%
ReadTotalTimeoutMultiplier%
ReadTotalTimeoutConstant%
WriteTotalTimeoutMultiplier%
WriteTotalTimeoutConstant%
ENDTYPE
INLINE
} // namespace
#ifdef WIN32 // ### WINDOWS ###
#define DWORD unsigned long
#define WINAPI __stdcall
#define __in
#define __inout
#define __in_opt
#define BOOL int
typedef HANDLE HLOCAL;
#define INVALID_HANDLE ((HANDLE)-1)
HANDLE g_hSerialFile[8]={INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE, INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE};
#define GENERIC_READ (0x80000000L)
#define GENERIC_WRITE (0x40000000L)
#define CREATE_NEW 1
#define CREATE_ALWAYS 2
#define OPEN_EXISTING 3
#define OPEN_ALWAYS 4
typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultiplier;
DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS,
*LPCOMMTIMEOUTS;
typedef struct _DCB {
DWORD DCBlength;
DWORD BaudRate;
DWORD fBinary;
DWORD fParity;
DWORD fOutxCtsFlow;
DWORD fOutxDsrFlow;
DWORD fDtrControl;
DWORD fDsrSensitivity;
DWORD fTXContinueOnXoff;
DWORD fOutX;
DWORD fInX;
DWORD fErrorChar;
DWORD fNull;
DWORD fRtsControl;
DWORD fAbortOnError;
DWORD fDummy2;
WORD wReserved;
WORD XonLim;
WORD XoffLim;
BYTE ByteSize;
BYTE Parity;
BYTE StopBits;
char XonChar;
char XoffChar;
char ErrorChar;
char EofChar;
char EvtChar;
WORD wReserved1;
} DCB,
*LPDCB;
extern "C"
{
#ifdef UNICODE
HANDLE __stdcall CreateFileW (const wchar_t*,DWORD,DWORD,void*,DWORD,DWORD,HANDLE);
#else
HANDLE __stdcall CreateFileA (const char*,DWORD,DWORD,void*,DWORD,DWORD,HANDLE);
#endif
BOOL __stdcall GetCommState(HANDLE, LPDCB);
BOOL __stdcall SetCommState(HANDLE, LPDCB);
BOOL __stdcall GetCommTimeouts(HANDLE, COMMTIMEOUTS*);
BOOL __stdcall SetCommTimeouts(HANDLE, COMMTIMEOUTS*);
BOOL __stdcall WriteFile(HANDLE, const void*, DWORD numwrite, DWORD* nwritten, const void* overlapped);
BOOL __stdcall ReadFile(HANDLE, void*, DWORD numread, DWORD* nread, const void* overlapped);
BOOL __stdcall CloseHandle(HANDLE);
DWORD __stdcall GetLastError(void);
#ifdef UNICODE
DWORD __stdcall FormatMessageW(DWORD dwFlags, void* lpSource, DWORD dwMessageId, DWORD dwLanguageId, wchar_t* lpBuffer, DWORD nSize, void *Arguments);
#else
DWORD __stdcall FormatMessageA(DWORD dwFlags, void* lpSource, DWORD dwMessageId, DWORD dwLanguageId, char* lpBuffer, DWORD nSize, void *Arguments);
#endif
int __stdcall MessageBoxW(HWND hWnd, const wchar_t* lpText, const wchar_t* lpCaption, unsigned int uType);
}
#if 0
#ifdef WINCE
#define SERDLL "corelib.dll"
#else
#define SERDLL "kernel32.dll"
#endif
#ifdef UNICODE
DECLARE(CreateFileW, SERDLL, (const wchar_t*,DWORD,DWORD,void*,DWORD,DWORD,HANDLE),HANDLE);
#else
DECLARE(CreateFileA, SERDLL, (const char*,DWORD,DWORD,void*,DWORD,DWORD,HANDLE),HANDLE);
#endif
DECLARE(GetCommState, SERDLL, (HANDLE, LPDCB), BOOL);
DECLARE(SetCommState, SERDLL, (HANDLE, LPDCB), BOOL);
DECLARE(GetCommTimeouts, SERDLL, (HANDLE, COMMTIMEOUTS*), BOOL);
DECLARE(SetCommTimeouts, SERDLL, (HANDLE, COMMTIMEOUTS*), BOOL);
DECLARE(WriteFile, SERDLL, (HANDLE, const void*, DWORD numwrite, DWORD* nwritten, const void* overlapped), BOOL);
DECLARE(ReadFile, SERDLL, (HANDLE, void*, DWORD numread, DWORD* nread, const void* overlapped), BOOL);
DECLARE(CloseHandle, SERDLL, (HANDLE), BOOL);
// error handling
DECLARE(GetLastError, SERDLL, (void), DWORD);
#ifdef UNICODE
DECLARE(FormatMessageW, SERDLL, (DWORD dwFlags, void* lpSource, DWORD dwMessageId, DWORD dwLanguageId, wchar_t* lpBuffer, DWORD nSize, void *Arguments), DWORD);
#else
DECLARE(FormatMessageA, SERDLL, (DWORD dwFlags, void* lpSource, DWORD dwMessageId, DWORD dwLanguageId, char* lpBuffer, DWORD nSize, void *Arguments), DWORD);
#endif
#endif
#else // ### NOT WINDOWS ###
// Prototypes for Linux
extern "C"
{
typedef long off_t;
typedef int speed_t;
#define ssize_t int
typedef unsigned int size_t;
typedef int mode_t;
#define O_NOCTTY 0x8000
#define O_RDWR 2
#define O_NONBLOCK 0x0004
#define O_NDELAY O_NONBLOCK
#define TCIFLUSH 0
#define TCSANOW 0
#define EAGAIN 11
/* c_cflag bit meaning */
#define CBAUD 0000017
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define CPARENB 0000400
#define CPARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
#define CIBAUD 03600000 /* input baud rate (not used) */
#define CRTSCTS 020000000000 /* flow control */
#define NCCS 17
struct termios {
unsigned long c_iflag; /* input mode flags */
unsigned long c_oflag; /* output mode flags */
unsigned long c_cflag; /* control mode flags */
unsigned long c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCCS]; /* control characters */
};
int open(const char *pathname, mode_t mode);
int errno;
char *strerror(int errnum);
int tcgetattr(int fildes, struct termios *termios_p);
int tcsetattr(int fildes, int optional_actions, struct termios *termios_p);
int tcflush(int fildes, int queue_selector);
int cfsetospeed(struct termios *termios_p, speed_t speed);
int ioctl(int fildes, int request, ... /* arg */);
int open(const char *pathname, int flags);
ssize_t read(int fd, void *buf, size_t count);
int write(int fildes, const char * buf, off_t count);
int close(int fildes);
int printf(char*, ...);
}
#define INVALID_HANDLE 0
static int g_hSerialFile[8] = {INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE, INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE,INVALID_HANDLE};
// closes the serial port
void CloseAdrPort(int iSlot)
{
// you may want to restore the saved port attributes
if (g_hSerialFile[iSlot] != INVALID_HANDLE)
{
close(g_hSerialFile[iSlot]);
} // end if
g_hSerialFile[iSlot] = INVALID_HANDLE;
} // end CloseAdrPort
// opens the serial port
// return code:
// > 0 = fd for the port
// -1 = open failed
int OpenAdrPort(int iSlot, int iRS232Port)
{
DGStr sPortName = "/dev/ttyS"+iRS232Port;
// make sure port is closed
CloseAdrPort();
g_hSerialFile[iSlot] = open(sPortName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0)
{
STDERR (CGStr("open error ")+DGNat(errno)+CGStr(" ")+CGStr(strerror(errno))+CGStr("\n"));
}
return g_hSerialFile[iSlot];
}
// 0 OK
// <0 failed
int SetAdrPortMode(int iSlot, int baud)
{
if(g_hSerialFile[iSlot] != INVALID_HANDLE)
{
struct termios my_termios;
tcgetattr(g_hSerialFile[iSlot], &my_termios);
/*
printf("fd is %d\n", g_hSerialFile[iSlot]);
// NOTE: you may want to save the port attributes
// here so that you can restore them later
printf("old cflag=%08x\n", my_termios.c_cflag);
printf("old oflag=%08x\n", my_termios.c_oflag);
printf("old iflag=%08x\n", my_termios.c_iflag);
printf("old lflag=%08x\n", my_termios.c_lflag);
printf("old line=%02x\n", my_termios.c_line);
*/
tcflush(g_hSerialFile[iSlot], TCIFLUSH);
my_termios.c_cflag = 0;
switch(baud)
{
#define MKB(a) case a: my_termios.c_cflag |= B ## a; break;
MKB(0);
MKB(50);
MKB(75);
MKB(110);
MKB(150);
MKB(200);
MKB(300);
MKB(600);
MKB(1200);
MKB(1800);
MKB(2400);
MKB(4800);
MKB(9600);
MKB(19200);
MKB(38400);
default:
return -1;
}
my_termios.c_cflag |= (CS8 |CREAD | CLOCAL | HUPCL);
cfsetospeed(&my_termios, B9600);
tcsetattr(g_hSerialFile[iSlot], TCSANOW, &my_termios);
printf("new cflag=%08x\n", my_termios.c_cflag);
printf("new oflag=%08x\n", my_termios.c_oflag);
printf("new iflag=%08x\n", my_termios.c_iflag);
printf("new lflag=%08x\n", my_termios.c_lflag);
printf("new line=%02x\n", my_termios.c_line);
} // end if
return 0;
}
// writes zero terminated string to the serial port
// return code:
// >= 0 = number of characters written
// -1 = write failed
int WriteAdrPort(int iSlot, const char* psOutput, int outlen)
{
return write(g_hSerialFile[iSlot], psOutput, outlen);
}
// read string from the serial port
// return code:
// >= 0 = number of characters read
// -1 = read failed
int ReadAdrPort(int iSlot, char* psResponse, int iMax)
{
int iIn;
iIn = read(g_hSerialFile[iSlot], psResponse, iMax-1);
if (iIn < 0)
{
if (errno == EAGAIN)
{
return 0; // assume that command generated no response
}
}
return iIn;
}
#endif // ### WIN / LINUX ###
namespace __GLBASIC__ {
ENDINLINE
FUNCTION DebugLastError:
INLINE
#ifdef WIN32
DWORD err = ::GetLastError();
// DGStr serr = DGStr("Error number: ") + (DGNat)err;
// MessageBoxW((HWND)GLBASIC_HWND(), serr.w_str(), L"Debug:", 1);
#ifdef UNICODE
wchar_t lpMsgBuf[1024];
FormatMessageW(0x00001000 | 0x00000200, NULL, err, 1<<10, lpMsgBuf, 1024, NULL);
// MessageBoxW((HWND)GLBASIC_HWND(), lpMsgBuf, L"Debug:", 1);
#else
char lpMsgBuf[1024];
FormatMessageA(0x00001000 | 0x00000200, NULL, err, 1<<10, lpMsgBuf, 1024, NULL);
#endif
DEBUG(DGStr(lpMsgBuf));
DEBUG(DGStr("\n"));
#else
DEBUG(CGStr(strerror(errno)) + CGStr("\n"));
#endif
ENDINLINE
ENDFUNCTION
FUNCTION COM_Open: iSlot%, port%, bRead, bWrite
INLINE
#ifdef WIN32
DGStr port_Str = CGStr("COM") + port + CGStr(":");
#ifdef UNICODE
g_hSerialFile[iSlot] = ::CreateFileW(port_Str.w_str(), (bRead?GENERIC_READ:0)|(bWrite?GENERIC_WRITE:0),0,0,OPEN_EXISTING, 0,0);
#else
g_hSerialFile[iSlot] = ::CreateFileA(port_Str.c_str(), (bRead?GENERIC_READ:0)|(bWrite?GENERIC_WRITE:0),0,0,OPEN_EXISTING, 0,0);
#endif
if(g_hSerialFile[iSlot] == INVALID_HANDLE)
{
port_Str = CGStr("Error opening port: ")+port_Str;
DebugLastError();
}
return (g_hSerialFile[iSlot]!=INVALID_HANDLE) ? TRUE:FALSE;
#else
return (OpenAdrPort(iSlot, port) < 0) ? FALSE:TRUE;
#endif
ENDINLINE
ENDFUNCTION
FUNCTION COM_Close: iSlot%
INLINE
#ifdef WIN32
if(g_hSerialFile[iSlot] != INVALID_HANDLE)
{
::CloseHandle(g_hSerialFile[iSlot]);
g_hSerialFile[iSlot]=INVALID_HANDLE;
}
#else
CloseAdrPort(iSlot);
#endif
ENDINLINE
ENDFUNCTION
// parity: 0 = none, 1=even, 2=mark, 3=space
FUNCTION COM_SetComState: iSlot%, baud, parity, databits, stopbits
INLINE
#ifdef WIN32
DCB MyDCB;
for(int i=0; i<sizeof(DCB); ++i)
{
((char*)&MyDCB)[i] = 0;
}
MyDCB.DCBlength = sizeof(DCB);
if( GetCommState(g_hSerialFile[iSlot], &MyDCB))
{
MyDCB.BaudRate=(int)baud;
MyDCB.Parity = (int)parity;
MyDCB.ByteSize = (int)databits;
MyDCB.StopBits = (int)stopbits;
return SetCommState(g_hSerialFile[iSlot], &MyDCB);
}
return FALSE;
#else
SetAdrPortMode(iSlot, baud);
// #NEED parity and shit
#endif
ENDINLINE
ENDFUNCTION
FUNCTION COM_SetCommTimeouts%: iSlot%, tout AS TComTimeouts
INLINE
#ifdef WIN32
COMMTIMEOUTS co;
co.ReadIntervalTimeout =tout.ReadIntervalTimeout;
co.ReadTotalTimeoutMultiplier =tout.ReadTotalTimeoutMultiplier;
co.ReadTotalTimeoutConstant =tout.ReadTotalTimeoutConstant;
co.WriteTotalTimeoutMultiplier=tout.WriteTotalTimeoutMultiplier;
co.WriteTotalTimeoutConstant =tout.WriteTotalTimeoutConstant;
::SetCommTimeouts(g_hSerialFile[iSlot], &co);
#else
// ???
#endif
ENDINLINE
ENDFUNCTION
FUNCTION COM_Read$: iSlot%, nbytes% = 1024
INLINE
DGStr buf;
#ifdef WIN32
DWORD nread =0;
ReadFile(g_hSerialFile[iSlot], buf.getbuffer(nbytes+1), nbytes, &nread, NULL);
#else
int nread = ReadAdrPort(iSlot, buf.getbuffer(nbytes+1), nbytes);
#endif
if(nread > 0)
{
buf[(int)nread] = '\0';
buf.setlength(nread);
return buf;
}
return DGStr("");
ENDINLINE
ENDFUNCTION
FUNCTION COM_Write%: iSlot%, text$
INLINE
#ifdef WIN32
DWORD nwrite =0;
if( WriteFile(g_hSerialFile[iSlot], text_Str.c_str(), (DWORD)LEN(text_Str), &nwrite, NULL))
return nwrite;
return 0;
#else
return WriteAdrPort(iSlot, text_Str.c_str(), LEN(text_Str));
#endif
ENDINLINE
ENDFUNCTION
Here's a test program for the library:
// --------------------------------- //
// Project: SerialPort
// Start: Wednesday, March 12, 2008
// IDE Version: 5.199
port% = 1 // COM1 / /dev/ttyS1
baud = 19200 // baud rate
parity = 0 // 0=none, 1=odd, 2=even, 3=mark, 4=space
datab = 8 // data bits
stop = 0 // stop bits: 0=1 (ONE) stop bit, 1=1.5 bits, 2=2 bits
// Open COM port for writing
IF COM_Open(0, port, FALSE, TRUE) = FALSE THEN Error("open COM2 failed")
// Set Baud rate and handshake
IF COM_SetComState(0, baud, parity, datab, stop) = FALSE THEN Error("Failed to set com state")
// optionally set com timeouts
// LOCAL tout AS TComTimeouts
// tout.ReadIntervalTimeout = 0xffffffff
// tout.ReadTotalTimeoutMultiplier = 0
// tout.ReadTotalTimeoutConstant = 0
// tout.WriteTotalTimeoutMultiplier= 0
// tout.WriteTotalTimeoutConstant = 0
// COM_SetCommTimeouts(0, tout)
// Write something
IF COM_Write(0, "ABC\n")=0 THEN Error("Failed to write data")
// Read something - make sure you COM_Open(..., TRUE, ...) before
// read$ = COM_Read$()
// close COM port
COM_Close(0)
MOUSEWAIT
END
FUNCTION Error: txt$
PRINT txt$, 0,0
SHOWSCREEN
MOUSEWAIT
END
ENDFUNCTION
Hi Gernot,
I've found a two errors in code :
FUNCTION COM_SetComState: baud, parity, databits, stopbits
INLINE
DCB MyDCB;
for(int i=0; i
{
((char*)&MyDCB)[i] = 0;
}
First "For cycle" not complete
FUNCTION COM_Read: buffer[], nbytes
INLINE
char buf[1024];
DWORD nread =0;
if( ReadFile(g_hSerialFile, buf, nbytes, &nread, 0))
{
DIM(buffer, nread);
for(int i=0; i
buffer(i) = buf[i];
Second "For cycle" not complete
Bye,
Neurox
This forum is starting to make me angry. It just swallowed that text. Maybe FireFox was the problem.
Now it's ok,
thanks!
Neurox
Hi Gernot
This will work in WINCE ?
My idea is get GPS data from a serial port.
Please excuseme my very bad english.
Kind Regards.
Very good question. It seems that the functions are there. Though Windows CE builds unicode so there might be some tweaks required.
If you could build it and try, please? There's surely a way to fix it then.
If you make a project to read GPS from a serial device, please let us know about your progress. I think many will like the idea to get GPS data from any device, so you should seperate GPS handling from the input source. Reading NMEA strings seems the easiest and lowest common protocol.
I'm waiting for a wince gps device.
When I have one, i will try it.
Thanks. ;-)
This topic looks interesting, is there any updated version of it or is this it? :-)
yep yesterday kittie solved the last problems with reading com port on wince devices.
OK, updated in the first topic.
Ocean will be interested in this :)
Sorry for pushing this old thread but i can't get this to work with my bluetooth GPS receiver. Normally it takes some time (for example with putty) to open the comport (bluetooth needs some time to connect), but with this code I instantly get the error "Failed to set com state". The Comport Settings are correct. Here is my Code:
Running = TRUE
error$ = ""
port% = 10 // COM10
baud = 9600 // baud rate
parity = 0 // 0=none, 1=odd, 2=even, 3=mark, 4=space
datab = 8 // data bits
stop = 0 // stop bits: 0=1 (ONE) stop bit, 1=1.5 bits, 2=2 bits
// Open COM port for reading
IF COM_Open(0, port, TRUE, FALSE) = FALSE THEN error$="open COM10 failed"
// Set Baud rate and handshake
IF COM_SetComState(0, baud, parity, datab, stop) = FALSE THEN error$="Failed to set com state"
WHILE Running
IF KEY(01) = 1
Running = FALSE
ENDIF
IF error$ <> ""
PRINT error$,0,0
ELSE
read$ = COM_Read$(0,1)
PRINT read$, 0,0
ENDIF
SHOWSCREEN
WEND
COM_Close(0)
END
I am using Windows 7 X64 (don't know if thats relevant)
Try this function for a more detailed error, maybe?
FUNCTION DebugLastError:
Ok with the debug mode and "DebugLastError()" between "IF COM_SetComState [...]" and the main Loop I get
QuoteDie Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnung ist falsch.
Das Handle ist ungültig.
Which is strange because I know, that the settings are correct (as I said it works in other programs like putty or hterm). The first error accrues even before DebugLastError() is called.
//Edit: OK this is very strange.
I Changed the Devices Bluetooth Comport to COM3 and now its working.
Hi everyone,
I see the topic is very old, but i'm in great need to communicate with an Arduino via USB.
I tried to apply the code in post #1, but it gives an error. The output of the compiler:
_______________________________________
*** Configuration: WIN32 ***
precompiling:
GPC - GLBasic Precompiler V.10.053 SN:61acac25 - 3D, NET
Wordcount:25 commands
compiling:
C:\Users\OLUSUM~1\AppData\Local\Temp\glbasic\gpc_temp1.cpp: In function `__GLBASIC__::DGStr __GLBASIC__::COM_Read_Str(DGNat, DGNat)':
C:\Users\OLUSUM~1\AppData\Local\Temp\glbasic\gpc_temp1.cpp:1057: error: invalid token
C:\Users\OLUSUM~1\AppData\Local\Temp\glbasic\gpc_temp1.cpp:1057: error: non-lvalue in unary `&'
C:\Users\OLUSUM~1\AppData\Local\Temp\glbasic\gpc_temp1.cpp:1057: error: stray '\' in program
C:\Users\OLUSUM~1\AppData\Local\Temp\glbasic\gpc_temp1.cpp:1057: error: invalid token
*** FATAL ERROR - Please post this output in the forum
_______________________________________
*** Finished ***
Elapsed: 1.1 sec. Time: 15:11
Build: 0 succeeded.
*** 1 FAILED ***
I also downloaded an older version of glbasic (12.308) but it didn't work.
I guess the line:
buf[(int)nread] = '\0';
should be:
buf[(int)nread] = "\0";
or:
buf[(int)nread] = &'\0&';
Only KittyHello can tell...
Fixed. It should be '\0'.