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.
280 lines
9.0 KiB
280 lines
9.0 KiB
14 years ago
|
/*
|
||
|
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;
|
||
|
}
|