You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
9.0 KiB
279 lines
9.0 KiB
/* |
|
libxbee - a C library to aid the use of Digi's Series 1 XBee modules |
|
running in API mode (AP=2). |
|
|
|
Copyright (C) 2009 Attie Grande (attie@attie.co.uk) |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
*/ |
|
|
|
/* ################################################################# */ |
|
/* ### Win32 Code ################################################## */ |
|
/* ################################################################# */ |
|
|
|
/* this file contains code that is used by Win32 ONLY */ |
|
#ifndef _WIN32 |
|
#error "This file should only be used on a Win32 system" |
|
#endif |
|
|
|
#include "win32.h" |
|
#include "win32.dll.c" |
|
|
|
static int init_serial(xbee_hnd xbee, int baudrate) { |
|
int chosenbaud; |
|
DCB tc; |
|
int evtMask; |
|
COMMTIMEOUTS timeouts; |
|
|
|
/* open the serial port */ |
|
xbee->tty = CreateFile(TEXT(xbee->path), |
|
GENERIC_READ | GENERIC_WRITE, |
|
0, /* exclusive access */ |
|
NULL, /* default security attributes */ |
|
OPEN_EXISTING, |
|
FILE_FLAG_OVERLAPPED, |
|
NULL); |
|
if (xbee->tty == INVALID_HANDLE_VALUE) { |
|
xbee_logS("Invalid file handle..."); |
|
xbee_logE("Is the XBee plugged in and avaliable on the correct port?"); |
|
xbee_mutex_destroy(xbee->conmutex); |
|
xbee_mutex_destroy(xbee->pktmutex); |
|
xbee_mutex_destroy(xbee->sendmutex); |
|
Xfree(xbee->path); |
|
return -1; |
|
} |
|
|
|
GetCommState(xbee->tty, &tc); |
|
tc.BaudRate = baudrate; |
|
tc.fBinary = TRUE; |
|
tc.fParity = FALSE; |
|
tc.fOutxCtsFlow = FALSE; |
|
tc.fOutxDsrFlow = FALSE; |
|
tc.fDtrControl = DTR_CONTROL_DISABLE; |
|
tc.fDsrSensitivity = FALSE; |
|
tc.fTXContinueOnXoff = FALSE; |
|
tc.fOutX = FALSE; |
|
tc.fInX = FALSE; |
|
tc.fErrorChar = FALSE; |
|
tc.fNull = FALSE; |
|
tc.fRtsControl = RTS_CONTROL_DISABLE; |
|
tc.fAbortOnError = FALSE; |
|
tc.ByteSize = 8; |
|
tc.Parity = NOPARITY; |
|
tc.StopBits = ONESTOPBIT; |
|
SetCommState(xbee->tty, &tc); |
|
|
|
timeouts.ReadIntervalTimeout = MAXDWORD; |
|
timeouts.ReadTotalTimeoutMultiplier = 0; |
|
timeouts.ReadTotalTimeoutConstant = 0; |
|
timeouts.WriteTotalTimeoutMultiplier = 0; |
|
timeouts.WriteTotalTimeoutConstant = 0; |
|
SetCommTimeouts(xbee->tty, &timeouts); |
|
|
|
SetCommMask(xbee->tty, EV_RXCHAR); |
|
|
|
return 0; |
|
} |
|
|
|
/* a replacement for the linux select() function... for a serial port */ |
|
static int xbee_select(xbee_hnd xbee, struct timeval *timeout) { |
|
int evtMask = 0; |
|
COMSTAT status; |
|
int ret; |
|
|
|
for (;;) { |
|
/* find out how many bytes are in the Rx buffer... */ |
|
if (ClearCommError(xbee->tty,NULL,&status) && (status.cbInQue > 0)) { |
|
/* if there is data... return! */ |
|
return 1; /*status.cbInQue;*/ |
|
} else if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { |
|
/* if the timeout was 0 (return immediately) then return! */ |
|
return 0; |
|
} |
|
|
|
/* otherwise wait for an Rx event... */ |
|
memset(&(xbee->ttyovrs),0,sizeof(OVERLAPPED)); |
|
xbee->ttyovrs.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); |
|
if (!WaitCommEvent(xbee->tty,&evtMask,&(xbee->ttyovrs))) { |
|
if (GetLastError() == ERROR_IO_PENDING) { |
|
DWORD timeoutval; |
|
if (!timeout) { |
|
/* behave like the linux function... if the timeout pointer was NULL |
|
then wait indefinately */ |
|
timeoutval = INFINITE; |
|
} else { |
|
/* Win32 doesn't give the luxury of microseconds and seconds... just miliseconds! */ |
|
timeoutval = (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000); |
|
} |
|
ret = WaitForSingleObject(xbee->ttyovrs.hEvent,timeoutval); |
|
if (ret == WAIT_TIMEOUT) { |
|
/* cause the WaitCommEvent() call to stop */ |
|
SetCommMask(xbee->tty, EV_RXCHAR); |
|
/* if a timeout occured, then return 0 */ |
|
CloseHandle(xbee->ttyovrs.hEvent); |
|
return 0; |
|
} |
|
} else { |
|
return -1; |
|
} |
|
} |
|
CloseHandle(xbee->ttyovrs.hEvent); |
|
} |
|
|
|
/* always return -1 (error) for now... */ |
|
return -1; |
|
} |
|
|
|
/* this offers the same behavior as non-blocking I/O under linux */ |
|
int xbee_write(xbee_hnd xbee, const void *ptr, size_t size) { |
|
xbee->ttyeof = FALSE; |
|
if (!WriteFile(xbee->tty, ptr, size, NULL, &(xbee->ttyovrw)) && |
|
(GetLastError() != ERROR_IO_PENDING)) return 0; |
|
if (!GetOverlappedResult(xbee->tty, &(xbee->ttyovrw), &(xbee->ttyw), TRUE)) { |
|
if (GetLastError() == ERROR_HANDLE_EOF) xbee->ttyeof = TRUE; |
|
return 0; |
|
} |
|
return xbee->ttyw; |
|
} |
|
|
|
/* this offers the same behavior as non-blocking I/O under linux */ |
|
int xbee_read(xbee_hnd xbee, void *ptr, size_t size) { |
|
xbee->ttyeof = FALSE; |
|
if (!ReadFile(xbee->tty, ptr, size, NULL, &(xbee->ttyovrr)) && |
|
(GetLastError() != ERROR_IO_PENDING)) return 0; |
|
if (!GetOverlappedResult(xbee->tty, &(xbee->ttyovrr), &(xbee->ttyr), TRUE)) { |
|
if (GetLastError() == ERROR_HANDLE_EOF) xbee->ttyeof = TRUE; |
|
return 0; |
|
} |
|
return xbee->ttyr; |
|
} |
|
|
|
/* this is because Win32 has some weird memory management rules... |
|
- the thread that allocated the memory, MUST free it... */ |
|
void xbee_free(void *ptr) { |
|
if (!ptr) return; |
|
free(ptr); |
|
} |
|
|
|
/* win32 equivalent of unix gettimeofday() */ |
|
int gettimeofday(struct timeval *tv, struct timezone *tz) { |
|
if (tv) { |
|
struct _timeb timeb; |
|
_ftime(&timeb); |
|
tv->tv_sec = timeb.time; |
|
tv->tv_usec = timeb.millitm * 1000; |
|
} |
|
/* ignore tz for now */ |
|
return 0; |
|
} |
|
|
|
/* ################################################################# */ |
|
/* ### Helper Functions (Mainly for VB6 use) ####################### */ |
|
/* ################################################################# */ |
|
|
|
/* enable the debug output to a custom file or fallback to stderr */ |
|
int xbee_setupDebugAPI(char *path, int baudrate, char *logfile, char cmdSeq, int cmdTime) { |
|
xbee_hnd xbee = NULL; |
|
int fd, ret; |
|
if ((fd = _open(logfile,_O_WRONLY | _O_CREAT | _O_TRUNC)) == -1) { |
|
fd = 2; |
|
} |
|
ret = xbee_setuplogAPI(path,baudrate,fd,cmdSeq,cmdTime); |
|
if (fd > 2) { /* close fd, as libxbee dup'ed it */ |
|
//_close(fd); |
|
} |
|
if (!ret) { /* libxbee started correctly */ |
|
xbee = default_xbee; |
|
if (fd == -1) { |
|
xbee_log("Error opening logfile '%s' (errno=%d)... using stderr instead!",logfile,errno); |
|
} |
|
} |
|
return ret; |
|
} |
|
int xbee_setupDebug(char *path, int baudrate, char *logfile) { |
|
return xbee_setupDebugAPI(path,baudrate,logfile,0,0); |
|
} |
|
|
|
/* These silly little functions are required for VB6 |
|
- it freaks out when you call a function that uses va_args... */ |
|
xbee_con *xbee_newcon_simple(unsigned char frameID, xbee_types type) { |
|
return xbee_newcon(frameID, type); |
|
} |
|
xbee_con *xbee_newcon_16bit(unsigned char frameID, xbee_types type, int addr) { |
|
return xbee_newcon(frameID, type, addr); |
|
} |
|
xbee_con *xbee_newcon_64bit(unsigned char frameID, xbee_types type, int addrL, int addrH) { |
|
return xbee_newcon(frameID, type, addrL, addrH); |
|
} |
|
|
|
void xbee_enableACKwait(xbee_con *con) { |
|
con->waitforACK = 1; |
|
} |
|
void xbee_disableACKwait(xbee_con *con) { |
|
con->waitforACK = 0; |
|
} |
|
|
|
void xbee_enableDestroySelf(xbee_con *con) { |
|
con->destroySelf = 1; |
|
} |
|
|
|
/* for vb6... it will send a message to the given hWnd which can in turn check for a packet */ |
|
void xbee_callback(xbee_con *con, xbee_pkt *pkt) { |
|
xbee_hnd xbee = default_xbee; |
|
|
|
if (!win32_hWnd) { |
|
xbee_log("*** Cannot do callback! No hWnd set... ***"); |
|
return; |
|
} |
|
if (!win32_MessageID) { |
|
xbee_log("*** Cannot do callback! No MessageID set... ***"); |
|
return; |
|
} |
|
|
|
xbee_log("Callback message sent!"); |
|
SendMessage(win32_hWnd, win32_MessageID, (int)con, (int)pkt); |
|
} |
|
|
|
/* very simple C function to provide more functionality to VB6 */ |
|
int xbee_runCallback(int(*func)(xbee_con*,xbee_pkt*), xbee_con *con, xbee_pkt *pkt) { |
|
return func(con,pkt); |
|
} |
|
|
|
void xbee_enableCallbacks(HWND hWnd, UINT uMsg) { |
|
xbee_hnd xbee = default_xbee; |
|
if (!win32_MessageID || win32_MessageID != uMsg) { |
|
xbee_log("Configuring libxbee to use MessageID = 0x%08X", uMsg); |
|
win32_MessageID = uMsg; |
|
} |
|
if (!win32_hWnd || win32_hWnd != hWnd) { |
|
xbee_log("Configuring libxbee to use hWnd = 0x%08X", hWnd); |
|
win32_hWnd = hWnd; |
|
} |
|
} |
|
|
|
void xbee_attachCallback(xbee_con *con) { |
|
xbee_hnd xbee = default_xbee; |
|
|
|
/* setup the callback function */ |
|
xbee_log("Setting callback for connection @ 0x%08X",con); |
|
con->callback = xbee_callback; |
|
} |
|
|
|
void xbee_detachCallback(xbee_con *con) { |
|
xbee_hnd xbee = default_xbee; |
|
|
|
/* un-setup the callback function */ |
|
xbee_log("Unsetting callback for connection @ 0x%08X",con); |
|
con->callback = NULL; |
|
}
|
|
|