Codesnippets > Code Snippets

Serial port (COM interface) programming

(1/4) > >>

Kitty Hello:
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:

--- Code: (glbasic) ---
// --------------------------------- //
// 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




--- End code ---

Here's a test program for the library:


--- Code: (glbasic) ---// --------------------------------- //
// 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


--- End code ---

Neurox:
Hi Gernot,
I've found a two errors in code :


--- Code: (glbasic) ---FUNCTION COM_SetComState: baud, parity, databits, stopbits
INLINE
    DCB MyDCB;
    for(int i=0; i
    {
        ((char*)&MyDCB)[i] = 0;
    }

--- End code ---
First "For cycle" not complete


--- Code: (glbasic) ---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];

--- End code ---
Second "For cycle" not complete

Bye,
Neurox

Kitty Hello:
This forum is starting to make me angry. It just swallowed that text. Maybe FireFox was the problem.

Neurox:
Now it's ok,
thanks!

Neurox

javiero:
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.

Navigation

[0] Message Index

[#] Next page

Go to full version