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.
2434 lines
70 KiB
2434 lines
70 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/>.
|
||
|
*/
|
||
|
const char *SVN_REV = "$Id: api.c 508 2011-06-12 23:22:34Z attie@attie.co.uk $";
|
||
|
char svn_rev[128] = "\0";
|
||
|
|
||
|
#include "api.h"
|
||
|
|
||
|
const char *xbee_svn_version(void) {
|
||
|
if (svn_rev[0] == '\0') {
|
||
|
char *t;
|
||
|
sprintf(svn_rev,"r%s",&SVN_REV[11]);
|
||
|
t = strrchr(svn_rev,' ');
|
||
|
if (t) {
|
||
|
t[0] = '\0';
|
||
|
}
|
||
|
}
|
||
|
return svn_rev;
|
||
|
}
|
||
|
|
||
|
const char *xbee_build_info(void) {
|
||
|
return "Built on " __DATE__ " @ " __TIME__ " for " HOST_OS;
|
||
|
}
|
||
|
|
||
|
/* ################################################################# */
|
||
|
/* ### Memory Handling ############################################# */
|
||
|
/* ################################################################# */
|
||
|
|
||
|
/* malloc wrapper function */
|
||
|
static void *Xmalloc2(xbee_hnd xbee, size_t size) {
|
||
|
void *t;
|
||
|
t = malloc(size);
|
||
|
if (!t) {
|
||
|
/* uhoh... thats pretty bad... */
|
||
|
xbee_perror("libxbee:malloc()");
|
||
|
exit(1);
|
||
|
}
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
/* calloc wrapper function */
|
||
|
static void *Xcalloc2(xbee_hnd xbee, size_t size) {
|
||
|
void *t;
|
||
|
t = calloc(1, size);
|
||
|
if (!t) {
|
||
|
/* uhoh... thats pretty bad... */
|
||
|
xbee_perror("libxbee:calloc()");
|
||
|
exit(1);
|
||
|
}
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
/* realloc wrapper function */
|
||
|
static void *Xrealloc2(xbee_hnd xbee, void *ptr, size_t size) {
|
||
|
void *t;
|
||
|
t = realloc(ptr,size);
|
||
|
if (!t) {
|
||
|
/* uhoh... thats pretty bad... */
|
||
|
fprintf(stderr,"libxbee:realloc(): Returned NULL\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
/* free wrapper function (uses the Xfree macro and sets the pointer to NULL after freeing it) */
|
||
|
static void Xfree2(void **ptr) {
|
||
|
if (!*ptr) return;
|
||
|
free(*ptr);
|
||
|
*ptr = NULL;
|
||
|
}
|
||
|
|
||
|
/* ################################################################# */
|
||
|
/* ### Helper Functions ############################################ */
|
||
|
/* ################################################################# */
|
||
|
|
||
|
/* #################################################################
|
||
|
returns 1 if the packet has data for the digital input else 0 */
|
||
|
int xbee_hasdigital(xbee_pkt *pkt, int sample, int input) {
|
||
|
int mask = 0x0001;
|
||
|
if (input < 0 || input > 7) return 0;
|
||
|
if (sample >= pkt->samples) return 0;
|
||
|
|
||
|
mask <<= input;
|
||
|
return !!(pkt->IOdata[sample].IOmask & mask);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
returns 1 if the digital input is high else 0 (or 0 if no digital data present) */
|
||
|
int xbee_getdigital(xbee_pkt *pkt, int sample, int input) {
|
||
|
int mask = 0x0001;
|
||
|
if (!xbee_hasdigital(pkt,sample,input)) return 0;
|
||
|
|
||
|
mask <<= input;
|
||
|
return !!(pkt->IOdata[sample].IOdigital & mask);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
returns 1 if the packet has data for the analog input else 0 */
|
||
|
int xbee_hasanalog(xbee_pkt *pkt, int sample, int input) {
|
||
|
int mask = 0x0200;
|
||
|
if (input < 0 || input > 5) return 0;
|
||
|
if (sample >= pkt->samples) return 0;
|
||
|
|
||
|
mask <<= input;
|
||
|
return !!(pkt->IOdata[sample].IOmask & mask);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
returns analog input as a voltage if vRef is non-zero, else raw value (or 0 if no analog data present) */
|
||
|
double xbee_getanalog(xbee_pkt *pkt, int sample, int input, double Vref) {
|
||
|
if (!xbee_hasanalog(pkt,sample,input)) return 0;
|
||
|
|
||
|
if (Vref) return (Vref / 1023) * pkt->IOdata[sample].IOanalog[input];
|
||
|
return pkt->IOdata[sample].IOanalog[input];
|
||
|
}
|
||
|
|
||
|
/* ################################################################# */
|
||
|
/* ### XBee Functions ############################################## */
|
||
|
/* ################################################################# */
|
||
|
|
||
|
static void xbee_logf(xbee_hnd xbee, const char *logformat, const char *file,
|
||
|
const int line, const char *function, char *format, ...) {
|
||
|
char buf[128];
|
||
|
va_list ap;
|
||
|
if (!xbee) return;
|
||
|
if (!xbee->log) return;
|
||
|
va_start(ap,format);
|
||
|
vsnprintf(buf,127,format,ap);
|
||
|
va_end(ap);
|
||
|
fprintf(xbee->log,logformat,file,line,function,buf);
|
||
|
}
|
||
|
void xbee_logitf(char *format, ...) {
|
||
|
char buf[128];
|
||
|
va_list ap;
|
||
|
va_start(ap,format);
|
||
|
vsnprintf(buf,127,format,ap);
|
||
|
va_end(ap);
|
||
|
xbee_logit(buf);
|
||
|
}
|
||
|
void _xbee_logitf(xbee_hnd xbee, char *format, ...) {
|
||
|
char buf[128];
|
||
|
va_list ap;
|
||
|
va_start(ap,format);
|
||
|
vsnprintf(buf,127,format,ap);
|
||
|
va_end(ap);
|
||
|
_xbee_logit(xbee, buf);
|
||
|
}
|
||
|
void xbee_logit(char *str) {
|
||
|
_xbee_logit(default_xbee, str);
|
||
|
}
|
||
|
void _xbee_logit(xbee_hnd xbee, char *str) {
|
||
|
if (!xbee) return;
|
||
|
if (!xbee->log) return;
|
||
|
xbee_mutex_lock(xbee->logmutex);
|
||
|
fprintf(xbee->log,LOG_FORMAT"\n",__FILE__,__LINE__,__FUNCTION__,str);
|
||
|
xbee_mutex_unlock(xbee->logmutex);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_sendAT - INTERNAL
|
||
|
allows for an at command to be send, and the reply to be captured */
|
||
|
static int xbee_sendAT(xbee_hnd xbee, char *command, char *retBuf, int retBuflen) {
|
||
|
return xbee_sendATdelay(xbee, 0, command, retBuf, retBuflen);
|
||
|
}
|
||
|
static int xbee_sendATdelay(xbee_hnd xbee, int guardTime, char *command, char *retBuf, int retBuflen) {
|
||
|
struct timeval to;
|
||
|
|
||
|
int ret;
|
||
|
int bufi = 0;
|
||
|
|
||
|
/* if there is a guardTime given, then use it and a bit more */
|
||
|
if (guardTime) usleep(guardTime * 1200);
|
||
|
|
||
|
/* get rid of any pre-command sludge... */
|
||
|
memset(&to, 0, sizeof(to));
|
||
|
ret = xbee_select(xbee,&to);
|
||
|
if (ret > 0) {
|
||
|
char t[128];
|
||
|
while (xbee_read(xbee,t,127));
|
||
|
}
|
||
|
|
||
|
/* send the requested command */
|
||
|
xbee_log("sendATdelay: Sending '%s'", command);
|
||
|
xbee_write(xbee,command, strlen(command));
|
||
|
|
||
|
/* if there is a guardTime, then use it */
|
||
|
if (guardTime) {
|
||
|
usleep(guardTime * 900);
|
||
|
|
||
|
/* get rid of any post-command sludge... */
|
||
|
memset(&to, 0, sizeof(to));
|
||
|
ret = xbee_select(xbee,&to);
|
||
|
if (ret > 0) {
|
||
|
char t[128];
|
||
|
while (xbee_read(xbee,t,127));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* retrieve the data */
|
||
|
memset(retBuf, 0, retBuflen);
|
||
|
memset(&to, 0, sizeof(to));
|
||
|
if (guardTime) {
|
||
|
/* select on the xbee fd... wait at most 0.2 the guardTime for the response */
|
||
|
to.tv_usec = guardTime * 200;
|
||
|
} else {
|
||
|
/* or 250ms */
|
||
|
to.tv_usec = 250000;
|
||
|
}
|
||
|
if ((ret = xbee_select(xbee,&to)) == -1) {
|
||
|
xbee_perror("libxbee:xbee_sendATdelay()");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
if (!ret) {
|
||
|
/* timed out, and there is nothing to be read */
|
||
|
xbee_log("sendATdelay: No Data to read - Timeout...");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* check for any dribble... */
|
||
|
do {
|
||
|
/* if there is actually no space in the retBuf then break out */
|
||
|
if (bufi >= retBuflen - 1) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* read as much data as is possible into retBuf */
|
||
|
if ((ret = xbee_read(xbee,&retBuf[bufi], retBuflen - bufi - 1)) == 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* advance the 'end of string' pointer */
|
||
|
bufi += ret;
|
||
|
|
||
|
/* wait at most 150ms for any more data */
|
||
|
memset(&to, 0, sizeof(to));
|
||
|
to.tv_usec = 150000;
|
||
|
if ((ret = xbee_select(xbee,&to)) == -1) {
|
||
|
xbee_perror("libxbee:xbee_sendATdelay()");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/* loop while data was read */
|
||
|
} while (ret);
|
||
|
|
||
|
if (!bufi) {
|
||
|
xbee_log("sendATdelay: No response...");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* terminate the string */
|
||
|
retBuf[bufi] = '\0';
|
||
|
|
||
|
xbee_log("sendATdelay: Recieved '%s'",retBuf);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_start
|
||
|
sets up the correct API mode for the xbee
|
||
|
cmdSeq = CC
|
||
|
cmdTime = GT */
|
||
|
static int xbee_startAPI(xbee_hnd xbee) {
|
||
|
char buf[256];
|
||
|
|
||
|
if (xbee->cmdSeq == 0 || xbee->cmdTime == 0) return 1;
|
||
|
|
||
|
/* setup the command sequence string */
|
||
|
memset(buf,xbee->cmdSeq,3);
|
||
|
buf[3] = '\0';
|
||
|
|
||
|
/* try the command sequence */
|
||
|
if (xbee_sendATdelay(xbee, xbee->cmdTime, buf, buf, sizeof(buf))) {
|
||
|
/* if it failed... try just entering 'AT' which should return OK */
|
||
|
if (xbee_sendAT(xbee, "AT\r", buf, 4) || strncmp(buf,"OK\r",3)) return 1;
|
||
|
} else if (strncmp(&buf[strlen(buf)-3],"OK\r",3)) {
|
||
|
/* if data was returned, but it wasn't OK... then something went wrong! */
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
/* get the current API mode */
|
||
|
if (xbee_sendAT(xbee, "ATAP\r", buf, 3)) return 1;
|
||
|
buf[1] = '\0';
|
||
|
xbee->oldAPI = atoi(buf);
|
||
|
|
||
|
if (xbee->oldAPI != 2) {
|
||
|
/* if it wasnt set to mode 2 already, then set it to mode 2 */
|
||
|
if (xbee_sendAT(xbee, "ATAP2\r", buf, 4) || strncmp(buf,"OK\r",3)) return 1;
|
||
|
}
|
||
|
|
||
|
/* quit from command mode, ready for some packets! :) */
|
||
|
if (xbee_sendAT(xbee, "ATCN\r", buf, 4) || strncmp(buf,"OK\r",3)) return 1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_end
|
||
|
resets the API mode to the saved value - you must have called xbee_setup[log]API */
|
||
|
int xbee_end(void) {
|
||
|
return _xbee_end(default_xbee);
|
||
|
}
|
||
|
int _xbee_end(xbee_hnd xbee) {
|
||
|
int ret = 1;
|
||
|
xbee_con *con, *ncon;
|
||
|
xbee_pkt *pkt, *npkt;
|
||
|
xbee_hnd xbeet;
|
||
|
|
||
|
ISREADYR(0);
|
||
|
xbee_log("Stopping libxbee instance...");
|
||
|
|
||
|
/* unlink the instance from list... */
|
||
|
xbee_log("Unlinking instance from list...");
|
||
|
xbee_mutex_lock(xbee_hnd_mutex);
|
||
|
if (xbee == default_xbee) {
|
||
|
default_xbee = default_xbee->next;
|
||
|
if (!default_xbee) {
|
||
|
xbee_mutex_destroy(xbee_hnd_mutex);
|
||
|
}
|
||
|
} else {
|
||
|
xbeet = default_xbee;
|
||
|
while (xbeet) {
|
||
|
if (xbeet->next == xbee) {
|
||
|
xbeet->next = xbee->next;
|
||
|
break;
|
||
|
}
|
||
|
xbeet = xbeet->next;
|
||
|
}
|
||
|
}
|
||
|
if (default_xbee) xbee_mutex_unlock(xbee_hnd_mutex);
|
||
|
|
||
|
/* if the api mode was not 2 to begin with then put it back */
|
||
|
if (xbee->oldAPI == 2) {
|
||
|
xbee_log("XBee was already in API mode 2, no need to reset");
|
||
|
ret = 0;
|
||
|
} else {
|
||
|
int to = 5;
|
||
|
|
||
|
con = _xbee_newcon(xbee,'I',xbee_localAT);
|
||
|
con->callback = NULL;
|
||
|
con->waitforACK = 1;
|
||
|
_xbee_senddata(xbee,con,"AP%c",xbee->oldAPI);
|
||
|
|
||
|
pkt = NULL;
|
||
|
|
||
|
while (!pkt && to--) {
|
||
|
pkt = _xbee_getpacketwait(xbee,con);
|
||
|
}
|
||
|
if (pkt) {
|
||
|
ret = pkt->status;
|
||
|
Xfree(pkt);
|
||
|
}
|
||
|
_xbee_endcon(xbee,con);
|
||
|
}
|
||
|
|
||
|
/* xbee_* functions may no longer run... */
|
||
|
xbee->xbee_ready = 0;
|
||
|
|
||
|
/* nullify everything */
|
||
|
|
||
|
/* stop listening for data... either after timeout or next char read which ever is first */
|
||
|
xbee->run = 0;
|
||
|
|
||
|
xbee_thread_cancel(xbee->listent,0);
|
||
|
xbee_thread_join(xbee->listent);
|
||
|
|
||
|
xbee_thread_cancel(xbee->threadt,0);
|
||
|
xbee_thread_join(xbee->threadt);
|
||
|
|
||
|
/* free all connections */
|
||
|
con = xbee->conlist;
|
||
|
xbee->conlist = NULL;
|
||
|
while (con) {
|
||
|
ncon = con->next;
|
||
|
Xfree(con);
|
||
|
con = ncon;
|
||
|
}
|
||
|
|
||
|
/* free all packets */
|
||
|
xbee->pktlast = NULL;
|
||
|
pkt = xbee->pktlist;
|
||
|
xbee->pktlist = NULL;
|
||
|
while (pkt) {
|
||
|
npkt = pkt->next;
|
||
|
Xfree(pkt);
|
||
|
pkt = npkt;
|
||
|
}
|
||
|
|
||
|
/* destroy mutexes */
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
xbee_mutex_destroy(xbee->pktmutex);
|
||
|
xbee_mutex_destroy(xbee->sendmutex);
|
||
|
|
||
|
/* close the serial port */
|
||
|
Xfree(xbee->path);
|
||
|
if (xbee->tty) xbee_close(xbee->tty);
|
||
|
|
||
|
/* close log and tty */
|
||
|
if (xbee->log) {
|
||
|
fflush(xbee->log);
|
||
|
xbee_close(xbee->log);
|
||
|
}
|
||
|
xbee_mutex_destroy(xbee->logmutex);
|
||
|
|
||
|
Xfree(xbee);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_setup
|
||
|
opens xbee serial port & creates xbee listen thread
|
||
|
the xbee must be configured for API mode 2
|
||
|
THIS MUST BE CALLED BEFORE ANY OTHER XBEE FUNCTION */
|
||
|
int xbee_setup(char *path, int baudrate) {
|
||
|
return xbee_setuplogAPI(path,baudrate,0,0,0);
|
||
|
}
|
||
|
xbee_hnd _xbee_setup(char *path, int baudrate) {
|
||
|
return _xbee_setuplogAPI(path,baudrate,0,0,0);
|
||
|
}
|
||
|
int xbee_setuplog(char *path, int baudrate, int logfd) {
|
||
|
return xbee_setuplogAPI(path,baudrate,logfd,0,0);
|
||
|
}
|
||
|
xbee_hnd _xbee_setuplog(char *path, int baudrate, int logfd) {
|
||
|
return _xbee_setuplogAPI(path,baudrate,logfd,0,0);
|
||
|
}
|
||
|
int xbee_setupAPI(char *path, int baudrate, char cmdSeq, int cmdTime) {
|
||
|
return xbee_setuplogAPI(path,baudrate,0,cmdSeq,cmdTime);
|
||
|
}
|
||
|
xbee_hnd _xbee_setupAPI(char *path, int baudrate, char cmdSeq, int cmdTime) {
|
||
|
return _xbee_setuplogAPI(path,baudrate,0,cmdSeq,cmdTime);
|
||
|
}
|
||
|
int xbee_setuplogAPI(char *path, int baudrate, int logfd, char cmdSeq, int cmdTime) {
|
||
|
if (default_xbee) return 0;
|
||
|
default_xbee = _xbee_setuplogAPI(path,baudrate,logfd,cmdSeq,cmdTime);
|
||
|
return (default_xbee?0:-1);
|
||
|
}
|
||
|
xbee_hnd _xbee_setuplogAPI(char *path, int baudrate, int logfd, char cmdSeq, int cmdTime) {
|
||
|
int ret;
|
||
|
xbee_hnd xbee = NULL;
|
||
|
|
||
|
/* create a new instance */
|
||
|
xbee = Xcalloc(sizeof(struct xbee_hnd));
|
||
|
xbee->next = NULL;
|
||
|
|
||
|
xbee_mutex_init(xbee->logmutex);
|
||
|
#ifdef DEBUG
|
||
|
if (!logfd) logfd = 2;
|
||
|
#endif
|
||
|
if (logfd) {
|
||
|
xbee->logfd = dup(logfd);
|
||
|
xbee->log = fdopen(xbee->logfd,"w");
|
||
|
if (!xbee->log) {
|
||
|
/* errno == 9 is bad file descriptor (probrably not provided) */
|
||
|
if (errno != 9) xbee_perror("xbee_setup(): Failed opening logfile");
|
||
|
xbee->logfd = 0;
|
||
|
} else {
|
||
|
#ifdef __GNUC__ /* ---- */
|
||
|
/* set to line buffer - ensure lines are written to file when complete */
|
||
|
setvbuf(xbee->log,NULL,_IOLBF,BUFSIZ);
|
||
|
#else /* -------------- */
|
||
|
/* Win32 is rubbish... so we have to completely disable buffering... */
|
||
|
setvbuf(xbee->log,NULL,_IONBF,BUFSIZ);
|
||
|
#endif /* ------------- */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
xbee_logS("---------------------------------------------------------------------");
|
||
|
xbee_logI("libxbee Starting...");
|
||
|
xbee_logI("SVN Info: %s",xbee_svn_version());
|
||
|
xbee_logI("Build Info: %s",xbee_build_info());
|
||
|
xbee_logE("---------------------------------------------------------------------");
|
||
|
|
||
|
/* setup the connection stuff */
|
||
|
xbee->conlist = NULL;
|
||
|
|
||
|
/* setup the packet stuff */
|
||
|
xbee->pktlist = NULL;
|
||
|
xbee->pktlast = NULL;
|
||
|
xbee->pktcount = 0;
|
||
|
xbee->run = 1;
|
||
|
|
||
|
/* setup the mutexes */
|
||
|
if (xbee_mutex_init(xbee->conmutex)) {
|
||
|
xbee_perror("xbee_setup():xbee_mutex_init(conmutex)");
|
||
|
if (xbee->log) xbee_close(xbee->log);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
if (xbee_mutex_init(xbee->pktmutex)) {
|
||
|
xbee_perror("xbee_setup():xbee_mutex_init(pktmutex)");
|
||
|
if (xbee->log) xbee_close(xbee->log);
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
if (xbee_mutex_init(xbee->sendmutex)) {
|
||
|
xbee_perror("xbee_setup():xbee_mutex_init(sendmutex)");
|
||
|
if (xbee->log) xbee_close(xbee->log);
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
xbee_mutex_destroy(xbee->pktmutex);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* take a copy of the XBee device path */
|
||
|
if ((xbee->path = Xmalloc(sizeof(char) * (strlen(path) + 1))) == NULL) {
|
||
|
xbee_perror("xbee_setup():Xmalloc(path)");
|
||
|
if (xbee->log) xbee_close(xbee->log);
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
xbee_mutex_destroy(xbee->pktmutex);
|
||
|
xbee_mutex_destroy(xbee->sendmutex);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
strcpy(xbee->path,path);
|
||
|
if (xbee->log) xbee_log("Opening serial port '%s'...",xbee->path);
|
||
|
|
||
|
/* call the relevant init function */
|
||
|
if ((ret = init_serial(xbee,baudrate)) != 0) {
|
||
|
xbee_log("Something failed while opening the serial port...");
|
||
|
if (xbee->log) xbee_close(xbee->log);
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
xbee_mutex_destroy(xbee->pktmutex);
|
||
|
xbee_mutex_destroy(xbee->sendmutex);
|
||
|
Xfree(xbee->path);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* when xbee_end() is called, if this is not 2 then ATAP will be set to this value */
|
||
|
xbee->oldAPI = 2;
|
||
|
xbee->cmdSeq = cmdSeq;
|
||
|
xbee->cmdTime = cmdTime;
|
||
|
if (xbee->cmdSeq && xbee->cmdTime) {
|
||
|
if (xbee_startAPI(xbee)) {
|
||
|
if (xbee->log) {
|
||
|
xbee_log("Couldn't communicate with XBee...");
|
||
|
xbee_close(xbee->log);
|
||
|
}
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
xbee_mutex_destroy(xbee->pktmutex);
|
||
|
xbee_mutex_destroy(xbee->sendmutex);
|
||
|
Xfree(xbee->path);
|
||
|
#ifdef __GNUC__ /* ---- */
|
||
|
close(xbee->ttyfd);
|
||
|
#endif /* ------------- */
|
||
|
xbee_close(xbee->tty);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* allow the listen thread to start */
|
||
|
xbee->xbee_ready = -1;
|
||
|
|
||
|
/* can start xbee_listen thread now */
|
||
|
if (xbee_thread_create(xbee->listent, xbee_listen_wrapper, xbee)) {
|
||
|
xbee_perror("xbee_setup():xbee_thread_create(listent)");
|
||
|
if (xbee->log) xbee_close(xbee->log);
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
xbee_mutex_destroy(xbee->pktmutex);
|
||
|
xbee_mutex_destroy(xbee->sendmutex);
|
||
|
Xfree(xbee->path);
|
||
|
#ifdef __GNUC__ /* ---- */
|
||
|
close(xbee->ttyfd);
|
||
|
#endif /* ------------- */
|
||
|
xbee_close(xbee->tty);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* can start xbee_thread_watch thread thread now */
|
||
|
if (xbee_thread_create(xbee->threadt, xbee_thread_watch, xbee)) {
|
||
|
xbee_perror("xbee_setup():xbee_thread_create(threadt)");
|
||
|
if (xbee->log) xbee_close(xbee->log);
|
||
|
xbee_mutex_destroy(xbee->conmutex);
|
||
|
xbee_mutex_destroy(xbee->pktmutex);
|
||
|
xbee_mutex_destroy(xbee->sendmutex);
|
||
|
Xfree(xbee->path);
|
||
|
#ifdef __GNUC__ /* ---- */
|
||
|
close(xbee->ttyfd);
|
||
|
#endif /* ------------- */
|
||
|
xbee_close(xbee->tty);
|
||
|
Xfree(xbee);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
usleep(500);
|
||
|
while (xbee->xbee_ready != -2) {
|
||
|
usleep(500);
|
||
|
xbee_log("Waiting for xbee_listen() to be ready...");
|
||
|
}
|
||
|
|
||
|
/* allow other functions to be used! */
|
||
|
xbee->xbee_ready = 1;
|
||
|
|
||
|
xbee_log("Linking xbee instance...");
|
||
|
if (!default_xbee) {
|
||
|
xbee_mutex_init(xbee_hnd_mutex);
|
||
|
xbee_mutex_lock(xbee_hnd_mutex);
|
||
|
default_xbee = xbee;
|
||
|
xbee_mutex_unlock(xbee_hnd_mutex);
|
||
|
} else {
|
||
|
xbee_hnd xbeet;
|
||
|
xbee_mutex_lock(xbee_hnd_mutex);
|
||
|
xbeet = default_xbee;
|
||
|
while (xbeet->next) {
|
||
|
xbeet = xbeet->next;
|
||
|
}
|
||
|
xbeet->next = xbee;
|
||
|
xbee_mutex_unlock(xbee_hnd_mutex);
|
||
|
}
|
||
|
|
||
|
xbee_log("libxbee: Started!");
|
||
|
|
||
|
return xbee;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_con
|
||
|
produces a connection to the specified device and frameID
|
||
|
if a connection had already been made, then this connection will be returned */
|
||
|
xbee_con *xbee_newcon(unsigned char frameID, xbee_types type, ...) {
|
||
|
xbee_con *ret;
|
||
|
va_list ap;
|
||
|
|
||
|
/* xbee_vnewcon() wants a va_list... */
|
||
|
va_start(ap, type);
|
||
|
/* hand it over :) */
|
||
|
ret = _xbee_vnewcon(default_xbee, frameID, type, ap);
|
||
|
va_end(ap);
|
||
|
return ret;
|
||
|
}
|
||
|
xbee_con *_xbee_newcon(xbee_hnd xbee, unsigned char frameID, xbee_types type, ...) {
|
||
|
xbee_con *ret;
|
||
|
va_list ap;
|
||
|
|
||
|
/* xbee_vnewcon() wants a va_list... */
|
||
|
va_start(ap, type);
|
||
|
/* hand it over :) */
|
||
|
ret = _xbee_vnewcon(xbee, frameID, type, ap);
|
||
|
va_end(ap);
|
||
|
return ret;
|
||
|
}
|
||
|
xbee_con *_xbee_vnewcon(xbee_hnd xbee, unsigned char frameID, xbee_types type, va_list ap) {
|
||
|
xbee_con *con, *ocon;
|
||
|
unsigned char tAddr[8];
|
||
|
int t;
|
||
|
int i;
|
||
|
|
||
|
ISREADYR(NULL);
|
||
|
|
||
|
if (!type || type == xbee_unknown) type = xbee_localAT; /* default to local AT */
|
||
|
else if (type == xbee_remoteAT) type = xbee_64bitRemoteAT; /* if remote AT, default to 64bit */
|
||
|
|
||
|
/* if: 64 bit address expected (2 ints) */
|
||
|
if ((type == xbee_64bitRemoteAT) ||
|
||
|
(type == xbee_64bitData) ||
|
||
|
(type == xbee_64bitIO) ||
|
||
|
(type == xbee2_data)) {
|
||
|
t = va_arg(ap, int);
|
||
|
tAddr[0] = (t >> 24) & 0xFF;
|
||
|
tAddr[1] = (t >> 16) & 0xFF;
|
||
|
tAddr[2] = (t >> 8) & 0xFF;
|
||
|
tAddr[3] = (t ) & 0xFF;
|
||
|
t = va_arg(ap, int);
|
||
|
tAddr[4] = (t >> 24) & 0xFF;
|
||
|
tAddr[5] = (t >> 16) & 0xFF;
|
||
|
tAddr[6] = (t >> 8) & 0xFF;
|
||
|
tAddr[7] = (t ) & 0xFF;
|
||
|
|
||
|
/* if: 16 bit address expected (1 int) */
|
||
|
} else if ((type == xbee_16bitRemoteAT) ||
|
||
|
(type == xbee_16bitData) ||
|
||
|
(type == xbee_16bitIO)) {
|
||
|
t = va_arg(ap, int);
|
||
|
tAddr[0] = (t >> 8) & 0xFF;
|
||
|
tAddr[1] = (t ) & 0xFF;
|
||
|
tAddr[2] = 0;
|
||
|
tAddr[3] = 0;
|
||
|
tAddr[4] = 0;
|
||
|
tAddr[5] = 0;
|
||
|
tAddr[6] = 0;
|
||
|
tAddr[7] = 0;
|
||
|
|
||
|
/* otherwise clear the address */
|
||
|
} else {
|
||
|
memset(tAddr,0,8);
|
||
|
}
|
||
|
|
||
|
/* lock the connection mutex */
|
||
|
xbee_mutex_lock(xbee->conmutex);
|
||
|
|
||
|
/* are there any connections? */
|
||
|
if (xbee->conlist) {
|
||
|
con = xbee->conlist;
|
||
|
while (con) {
|
||
|
/* if: looking for a modemStatus, and the types match! */
|
||
|
if ((type == xbee_modemStatus) &&
|
||
|
(con->type == type)) {
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
return con;
|
||
|
|
||
|
/* if: looking for a txStatus and frameIDs match! */
|
||
|
} else if ((type == xbee_txStatus) &&
|
||
|
(con->type == type) &&
|
||
|
(frameID == con->frameID)) {
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
return con;
|
||
|
|
||
|
/* if: looking for a localAT, and the frameIDs match! */
|
||
|
} else if ((type == xbee_localAT) &&
|
||
|
(con->type == type) &&
|
||
|
(frameID == con->frameID)) {
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
return con;
|
||
|
|
||
|
/* if: connection types match, the frameIDs match, and the addresses match! */
|
||
|
} else if ((type == con->type) &&
|
||
|
(frameID == con->frameID) &&
|
||
|
(!memcmp(tAddr,con->tAddr,8))) {
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
return con;
|
||
|
}
|
||
|
|
||
|
/* if there are more, move along, dont want to loose that last item! */
|
||
|
if (con->next == NULL) break;
|
||
|
con = con->next;
|
||
|
}
|
||
|
|
||
|
/* keep hold of the last connection... we will need to link it up later */
|
||
|
ocon = con;
|
||
|
}
|
||
|
|
||
|
/* unlock the connection mutex */
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
|
||
|
/* create a new connection and set its attributes */
|
||
|
con = Xcalloc(sizeof(xbee_con));
|
||
|
con->type = type;
|
||
|
/* is it a 64bit connection? */
|
||
|
if ((type == xbee_64bitRemoteAT) ||
|
||
|
(type == xbee_64bitData) ||
|
||
|
(type == xbee_64bitIO) ||
|
||
|
(type == xbee2_data)) {
|
||
|
con->tAddr64 = TRUE;
|
||
|
}
|
||
|
con->atQueue = 0; /* queue AT commands? */
|
||
|
con->txDisableACK = 0; /* disable ACKs? */
|
||
|
con->txBroadcastPAN = 0; /* broadcast? */
|
||
|
con->frameID = frameID;
|
||
|
con->waitforACK = 0;
|
||
|
memcpy(con->tAddr,tAddr,8); /* copy in the remote address */
|
||
|
xbee_mutex_init(con->callbackmutex);
|
||
|
xbee_mutex_init(con->callbackListmutex);
|
||
|
xbee_mutex_init(con->Txmutex);
|
||
|
xbee_sem_init(con->waitforACKsem);
|
||
|
|
||
|
if (xbee->log) {
|
||
|
switch(type) {
|
||
|
case xbee_localAT:
|
||
|
xbee_log("New local AT connection!");
|
||
|
break;
|
||
|
case xbee_16bitRemoteAT:
|
||
|
case xbee_64bitRemoteAT:
|
||
|
xbee_logc("New %d-bit remote AT connection! (to: ",(con->tAddr64?64:16));
|
||
|
for (i=0;i<(con->tAddr64?8:2);i++) {
|
||
|
fprintf(xbee->log,(i?":%02X":"%02X"),tAddr[i]);
|
||
|
}
|
||
|
fprintf(xbee->log,")");
|
||
|
xbee_logcf();
|
||
|
break;
|
||
|
case xbee_16bitData:
|
||
|
case xbee_64bitData:
|
||
|
xbee_logc("New %d-bit data connection! (to: ",(con->tAddr64?64:16));
|
||
|
for (i=0;i<(con->tAddr64?8:2);i++) {
|
||
|
fprintf(xbee->log,(i?":%02X":"%02X"),tAddr[i]);
|
||
|
}
|
||
|
fprintf(xbee->log,")");
|
||
|
xbee_logcf();
|
||
|
break;
|
||
|
case xbee_16bitIO:
|
||
|
case xbee_64bitIO:
|
||
|
xbee_logc("New %d-bit IO connection! (to: ",(con->tAddr64?64:16));
|
||
|
for (i=0;i<(con->tAddr64?8:2);i++) {
|
||
|
fprintf(xbee->log,(i?":%02X":"%02X"),tAddr[i]);
|
||
|
}
|
||
|
fprintf(xbee->log,")");
|
||
|
xbee_logcf();
|
||
|
break;
|
||
|
case xbee2_data:
|
||
|
xbee_logc("New Series 2 data connection! (to: ");
|
||
|
for (i=0;i<8;i++) {
|
||
|
fprintf(xbee->log,(i?":%02X":"%02X"),tAddr[i]);
|
||
|
}
|
||
|
fprintf(xbee->log,")");
|
||
|
xbee_logcf();
|
||
|
break;
|
||
|
case xbee_txStatus:
|
||
|
xbee_log("New Tx status connection!");
|
||
|
break;
|
||
|
case xbee_modemStatus:
|
||
|
xbee_log("New modem status connection!");
|
||
|
break;
|
||
|
case xbee_unknown:
|
||
|
default:
|
||
|
xbee_log("New unknown connection!");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* lock the connection mutex */
|
||
|
xbee_mutex_lock(xbee->conmutex);
|
||
|
|
||
|
/* make it the last in the list */
|
||
|
con->next = NULL;
|
||
|
/* add it to the list */
|
||
|
if (xbee->conlist) {
|
||
|
ocon->next = con;
|
||
|
} else {
|
||
|
xbee->conlist = con;
|
||
|
}
|
||
|
|
||
|
/* unlock the mutex */
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
return con;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_conflush
|
||
|
removes any packets that have been collected for the specified
|
||
|
connection */
|
||
|
void xbee_purgecon(xbee_con *con) {
|
||
|
_xbee_purgecon(default_xbee, con);
|
||
|
}
|
||
|
void _xbee_purgecon(xbee_hnd xbee, xbee_con *con) {
|
||
|
xbee_pkt *r, *p, *n;
|
||
|
|
||
|
ISREADYP();
|
||
|
|
||
|
/* lock the packet mutex */
|
||
|
xbee_mutex_lock(xbee->pktmutex);
|
||
|
|
||
|
/* if: there are packets */
|
||
|
if ((p = xbee->pktlist) != NULL) {
|
||
|
r = NULL;
|
||
|
/* get all packets for this connection */
|
||
|
do {
|
||
|
/* does the packet match the connection? */
|
||
|
if (xbee_matchpktcon(xbee,p,con)) {
|
||
|
/* if it was the first packet */
|
||
|
if (!r) {
|
||
|
/* move the chain along */
|
||
|
xbee->pktlist = p->next;
|
||
|
} else {
|
||
|
/* otherwise relink the list */
|
||
|
r->next = p->next;
|
||
|
}
|
||
|
xbee->pktcount--;
|
||
|
|
||
|
/* free this packet! */
|
||
|
n = p->next;
|
||
|
Xfree(p);
|
||
|
/* move on */
|
||
|
p = n;
|
||
|
} else {
|
||
|
/* move on */
|
||
|
r = p;
|
||
|
p = p->next;
|
||
|
}
|
||
|
} while (p);
|
||
|
xbee->pktlast = r;
|
||
|
}
|
||
|
|
||
|
/* unlock the packet mutex */
|
||
|
xbee_mutex_unlock(xbee->pktmutex);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_endcon
|
||
|
close the unwanted connection
|
||
|
free wrapper function (uses the Xfree macro and sets the pointer to NULL after freeing it) */
|
||
|
void xbee_endcon2(xbee_con **con, int alreadyUnlinked) {
|
||
|
_xbee_endcon2(default_xbee, con, alreadyUnlinked);
|
||
|
}
|
||
|
void _xbee_endcon2(xbee_hnd xbee, xbee_con **con, int alreadyUnlinked) {
|
||
|
xbee_con *t, *u;
|
||
|
|
||
|
ISREADYP();
|
||
|
|
||
|
/* lock the connection mutex */
|
||
|
xbee_mutex_lock(xbee->conmutex);
|
||
|
|
||
|
u = t = xbee->conlist;
|
||
|
while (t && t != *con) {
|
||
|
u = t;
|
||
|
t = t->next;
|
||
|
}
|
||
|
if (!t) {
|
||
|
/* this could be true if comming from the destroySelf signal... */
|
||
|
if (!alreadyUnlinked) {
|
||
|
/* invalid connection given... */
|
||
|
if (xbee->log) {
|
||
|
xbee_log("Attempted to close invalid connection...");
|
||
|
}
|
||
|
/* unlock the connection mutex */
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
/* extract this connection from the list */
|
||
|
if (t == xbee->conlist) {
|
||
|
xbee->conlist = t->next;
|
||
|
} else {
|
||
|
u->next = t->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* unlock the connection mutex */
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
|
||
|
/* check if a callback thread is running... */
|
||
|
if (t->callback && xbee_mutex_trylock(t->callbackmutex)) {
|
||
|
/* if it is running... tell it to destroy the connection on completion */
|
||
|
xbee_log("Attempted to close a connection with active callbacks... "
|
||
|
"Connection will be destroyed when callbacks have completeted...");
|
||
|
t->destroySelf = 1;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* remove all packets for this connection */
|
||
|
_xbee_purgecon(xbee,t);
|
||
|
|
||
|
/* destroy the callback mutex */
|
||
|
xbee_mutex_destroy(t->callbackmutex);
|
||
|
xbee_mutex_destroy(t->callbackListmutex);
|
||
|
xbee_mutex_destroy(t->Txmutex);
|
||
|
xbee_sem_destroy(t->waitforACKsem);
|
||
|
|
||
|
/* free the connection! */
|
||
|
Xfree(*con);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_senddata
|
||
|
send the specified data to the provided connection */
|
||
|
int xbee_senddata(xbee_con *con, char *format, ...) {
|
||
|
int ret;
|
||
|
va_list ap;
|
||
|
|
||
|
/* xbee_vsenddata() wants a va_list... */
|
||
|
va_start(ap, format);
|
||
|
/* hand it over :) */
|
||
|
ret = _xbee_vsenddata(default_xbee, con, format, ap);
|
||
|
va_end(ap);
|
||
|
return ret;
|
||
|
}
|
||
|
int _xbee_senddata(xbee_hnd xbee, xbee_con *con, char *format, ...) {
|
||
|
int ret;
|
||
|
va_list ap;
|
||
|
|
||
|
/* xbee_vsenddata() wants a va_list... */
|
||
|
va_start(ap, format);
|
||
|
/* hand it over :) */
|
||
|
ret = _xbee_vsenddata(xbee, con, format, ap);
|
||
|
va_end(ap);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int xbee_vsenddata(xbee_con *con, char *format, va_list ap) {
|
||
|
return _xbee_vsenddata(default_xbee, con, format, ap);
|
||
|
}
|
||
|
int _xbee_vsenddata(xbee_hnd xbee, xbee_con *con, char *format, va_list ap) {
|
||
|
unsigned char data[128]; /* max payload is 100 bytes... plus a bit of fluff... */
|
||
|
int length;
|
||
|
|
||
|
/* make up the data and keep the length, its possible there are nulls in there */
|
||
|
length = vsnprintf((char *)data, 128, format, ap);
|
||
|
|
||
|
/* hand it over :) */
|
||
|
return _xbee_nsenddata(xbee, con, (char *)data, length);
|
||
|
}
|
||
|
|
||
|
/* returns:
|
||
|
1 - if NAC was recieved
|
||
|
0 - if packet was successfully sent (or just sent if waitforACK is off)
|
||
|
-1 - if there was an error building the packet
|
||
|
-2 - if the connection type was unknown */
|
||
|
int xbee_nsenddata(xbee_con *con, char *data, int length) {
|
||
|
return _xbee_nsenddata(default_xbee, con, data, length);
|
||
|
}
|
||
|
int _xbee_nsenddata(xbee_hnd xbee, xbee_con *con, char *data, int length) {
|
||
|
t_data *pkt;
|
||
|
int i;
|
||
|
unsigned char buf[128]; /* max payload is 100 bytes... plus a bit for the headers etc... */
|
||
|
|
||
|
ISREADYR(-1);
|
||
|
|
||
|
if (!con) return -1;
|
||
|
if (con->type == xbee_unknown) return -1;
|
||
|
if (length > 127) return -1;
|
||
|
|
||
|
if (xbee->log) {
|
||
|
xbee_logS("--== TX Packet ============--");
|
||
|
xbee_logIc("Connection Type: ");
|
||
|
switch (con->type) {
|
||
|
case xbee_unknown: fprintf(xbee->log,"Unknown"); break;
|
||
|
case xbee_localAT: fprintf(xbee->log,"Local AT"); break;
|
||
|
case xbee_remoteAT: fprintf(xbee->log,"Remote AT"); break;
|
||
|
case xbee_16bitRemoteAT: fprintf(xbee->log,"Remote AT (16-bit)"); break;
|
||
|
case xbee_64bitRemoteAT: fprintf(xbee->log,"Remote AT (64-bit)"); break;
|
||
|
case xbee_16bitData: fprintf(xbee->log,"Data (16-bit)"); break;
|
||
|
case xbee_64bitData: fprintf(xbee->log,"Data (64-bit)"); break;
|
||
|
case xbee_16bitIO: fprintf(xbee->log,"IO (16-bit)"); break;
|
||
|
case xbee_64bitIO: fprintf(xbee->log,"IO (64-bit)"); break;
|
||
|
case xbee2_data: fprintf(xbee->log,"Series 2 Data"); break;
|
||
|
case xbee2_txStatus: fprintf(xbee->log,"Series 2 Tx Status"); break;
|
||
|
case xbee_txStatus: fprintf(xbee->log,"Tx Status"); break;
|
||
|
case xbee_modemStatus: fprintf(xbee->log,"Modem Status"); break;
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
switch (con->type) {
|
||
|
case xbee_localAT: case xbee_remoteAT: case xbee_txStatus: case xbee_modemStatus:
|
||
|
break;
|
||
|
default:
|
||
|
xbee_logIc("Destination: ");
|
||
|
for (i=0;i<(con->tAddr64?8:2);i++) {
|
||
|
fprintf(xbee->log,(i?":%02X":"%02X"),con->tAddr[i]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
xbee_logI("Length: %d",length);
|
||
|
for (i=0;i<length;i++) {
|
||
|
xbee_logIc("%3d | 0x%02X ",i,(unsigned char)data[i]);
|
||
|
if ((data[i] > 32) && (data[i] < 127)) {
|
||
|
fprintf(xbee->log,"'%c'",data[i]);
|
||
|
} else{
|
||
|
fprintf(xbee->log," _");
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
xbee_logEf();
|
||
|
}
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: local AT */
|
||
|
if (con->type == xbee_localAT) {
|
||
|
/* AT commands are 2 chars long (plus optional parameter) */
|
||
|
if (length < 2) return -1;
|
||
|
if (length > 32) return -1;
|
||
|
|
||
|
/* use the command? */
|
||
|
buf[0] = ((!con->atQueue)?XBEE_LOCAL_ATREQ:XBEE_LOCAL_ATQUE);
|
||
|
buf[1] = con->frameID;
|
||
|
|
||
|
/* copy in the data */
|
||
|
for (i=0;i<length;i++) {
|
||
|
buf[i+2] = data[i];
|
||
|
}
|
||
|
|
||
|
/* setup the packet */
|
||
|
pkt = xbee_make_pkt(xbee, buf, i+2);
|
||
|
/* send it on */
|
||
|
return _xbee_send_pkt(xbee, pkt, con);
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: remote AT */
|
||
|
} else if ((con->type == xbee_16bitRemoteAT) ||
|
||
|
(con->type == xbee_64bitRemoteAT)) {
|
||
|
if (length < 2) return -1; /* at commands are 2 chars long (plus optional parameter) */
|
||
|
if (length > 32) return -1;
|
||
|
buf[0] = XBEE_REMOTE_ATREQ;
|
||
|
buf[1] = con->frameID;
|
||
|
|
||
|
/* copy in the relevant address */
|
||
|
if (con->tAddr64) {
|
||
|
memcpy(&buf[2],con->tAddr,8);
|
||
|
buf[10] = 0xFF;
|
||
|
buf[11] = 0xFE;
|
||
|
} else {
|
||
|
memset(&buf[2],0,8);
|
||
|
memcpy(&buf[10],con->tAddr,2);
|
||
|
}
|
||
|
/* queue the command? */
|
||
|
buf[12] = ((!con->atQueue)?0x02:0x00);
|
||
|
|
||
|
/* copy in the data */
|
||
|
for (i=0;i<length;i++) {
|
||
|
buf[i+13] = data[i];
|
||
|
}
|
||
|
|
||
|
/* setup the packet */
|
||
|
pkt = xbee_make_pkt(xbee, buf, i+13);
|
||
|
/* send it on */
|
||
|
return _xbee_send_pkt(xbee, pkt, con);
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: 16 or 64bit Data */
|
||
|
} else if ((con->type == xbee_16bitData) ||
|
||
|
(con->type == xbee_64bitData)) {
|
||
|
int offset;
|
||
|
if (length > 100) return -1;
|
||
|
|
||
|
/* if: 16bit Data */
|
||
|
if (con->type == xbee_16bitData) {
|
||
|
buf[0] = XBEE_16BIT_DATATX;
|
||
|
offset = 5;
|
||
|
/* copy in the address */
|
||
|
memcpy(&buf[2],con->tAddr,2);
|
||
|
|
||
|
/* if: 64bit Data */
|
||
|
} else { /* 64bit Data */
|
||
|
buf[0] = XBEE_64BIT_DATATX;
|
||
|
offset = 11;
|
||
|
/* copy in the address */
|
||
|
memcpy(&buf[2],con->tAddr,8);
|
||
|
}
|
||
|
|
||
|
/* copy frameID */
|
||
|
buf[1] = con->frameID;
|
||
|
|
||
|
/* disable ack? broadcast? */
|
||
|
buf[offset-1] = ((con->txDisableACK)?0x01:0x00) | ((con->txBroadcastPAN)?0x04:0x00);
|
||
|
|
||
|
/* copy in the data */
|
||
|
for (i=0;i<length;i++) {
|
||
|
buf[i+offset] = data[i];
|
||
|
}
|
||
|
|
||
|
/* setup the packet */
|
||
|
pkt = xbee_make_pkt(xbee, buf, i+offset);
|
||
|
/* send it on */
|
||
|
return _xbee_send_pkt(xbee, pkt, con);
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: I/O */
|
||
|
} else if ((con->type == xbee_64bitIO) ||
|
||
|
(con->type == xbee_16bitIO)) {
|
||
|
/* not currently implemented... is it even allowed? */
|
||
|
if (xbee->log) {
|
||
|
xbee_log("******* TODO ********\n");
|
||
|
}
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: Series 2 Data */
|
||
|
} else if (con->type == xbee2_data) {
|
||
|
if (length > 72) return -1;
|
||
|
|
||
|
buf[0] = XBEE2_DATATX;
|
||
|
buf[1] = con->frameID;
|
||
|
|
||
|
/* copy in the relevant address */
|
||
|
memcpy(&buf[2],con->tAddr,8);
|
||
|
buf[10] = 0xFF;
|
||
|
buf[11] = 0xFE;
|
||
|
|
||
|
/* Maximum Radius/hops */
|
||
|
buf[12] = 0x00;
|
||
|
|
||
|
/* Options */
|
||
|
buf[13] = 0x00;
|
||
|
|
||
|
/* copy in the data */
|
||
|
for (i=0;i<length;i++) {
|
||
|
buf[i+14] = data[i];
|
||
|
}
|
||
|
|
||
|
/* setup the packet */
|
||
|
pkt = xbee_make_pkt(xbee, buf, i+14);
|
||
|
/* send it on */
|
||
|
return _xbee_send_pkt(xbee, pkt, con);
|
||
|
}
|
||
|
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_getpacket
|
||
|
retrieves the next packet destined for the given connection
|
||
|
once the packet has been retrieved, it is removed for the list! */
|
||
|
xbee_pkt *xbee_getpacketwait(xbee_con *con) {
|
||
|
return _xbee_getpacketwait(default_xbee, con);
|
||
|
}
|
||
|
xbee_pkt *_xbee_getpacketwait(xbee_hnd xbee, xbee_con *con) {
|
||
|
xbee_pkt *p = NULL;
|
||
|
int i = 20;
|
||
|
|
||
|
/* 50ms * 20 = 1 second */
|
||
|
for (; i; i--) {
|
||
|
p = _xbee_getpacket(xbee, con);
|
||
|
if (p) break;
|
||
|
usleep(50000); /* 50ms */
|
||
|
}
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
xbee_pkt *xbee_getpacket(xbee_con *con) {
|
||
|
return _xbee_getpacket(default_xbee, con);
|
||
|
}
|
||
|
xbee_pkt *_xbee_getpacket(xbee_hnd xbee, xbee_con *con) {
|
||
|
xbee_pkt *l, *p, *q;
|
||
|
|
||
|
ISREADYR(NULL);
|
||
|
|
||
|
/* lock the packet mutex */
|
||
|
xbee_mutex_lock(xbee->pktmutex);
|
||
|
|
||
|
/* if: there are no packets */
|
||
|
if ((p = xbee->pktlist) == NULL) {
|
||
|
xbee_mutex_unlock(xbee->pktmutex);
|
||
|
/*if (xbee->log) {
|
||
|
xbee_log("No packets avaliable...");
|
||
|
}*/
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
l = NULL;
|
||
|
q = NULL;
|
||
|
/* get the first avaliable packet for this connection */
|
||
|
do {
|
||
|
/* does the packet match the connection? */
|
||
|
if (xbee_matchpktcon(xbee, p, con)) {
|
||
|
q = p;
|
||
|
break;
|
||
|
}
|
||
|
/* move on */
|
||
|
l = p;
|
||
|
p = p->next;
|
||
|
} while (p);
|
||
|
|
||
|
/* if: no packet was found */
|
||
|
if (!q) {
|
||
|
xbee_mutex_unlock(xbee->pktmutex);
|
||
|
if (xbee->log) {
|
||
|
struct timeval tv;
|
||
|
xbee_logS("--== Get Packet ==========--");
|
||
|
gettimeofday(&tv,NULL);
|
||
|
xbee_logE("Didn't get a packet @ %ld.%06ld",tv.tv_sec,tv.tv_usec);
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* if it was the first packet */
|
||
|
if (l) {
|
||
|
/* relink the list */
|
||
|
l->next = p->next;
|
||
|
if (!l->next) xbee->pktlast = l;
|
||
|
} else {
|
||
|
/* move the chain along */
|
||
|
xbee->pktlist = p->next;
|
||
|
if (!xbee->pktlist) {
|
||
|
xbee->pktlast = NULL;
|
||
|
} else if (!xbee->pktlist->next) {
|
||
|
xbee->pktlast = xbee->pktlist;
|
||
|
}
|
||
|
}
|
||
|
xbee->pktcount--;
|
||
|
|
||
|
/* unlink this packet from the chain! */
|
||
|
q->next = NULL;
|
||
|
|
||
|
if (xbee->log) {
|
||
|
struct timeval tv;
|
||
|
xbee_logS("--== Get Packet ==========--");
|
||
|
gettimeofday(&tv,NULL);
|
||
|
xbee_logI("Got a packet @ %ld.%06ld",tv.tv_sec,tv.tv_usec);
|
||
|
xbee_logE("Packets left: %d",xbee->pktcount);
|
||
|
}
|
||
|
|
||
|
/* unlock the packet mutex */
|
||
|
xbee_mutex_unlock(xbee->pktmutex);
|
||
|
|
||
|
/* and return the packet (must be free'd by caller!) */
|
||
|
return q;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_matchpktcon - INTERNAL
|
||
|
checks if the packet matches the connection */
|
||
|
static int xbee_matchpktcon(xbee_hnd xbee, xbee_pkt *pkt, xbee_con *con) {
|
||
|
/* if: the connection type matches the packet type OR
|
||
|
the connection is 16/64bit remote AT, and the packet is a remote AT response */
|
||
|
if ((pkt->type == con->type) || /* -- */
|
||
|
((pkt->type == xbee_remoteAT) && /* -- */
|
||
|
((con->type == xbee_16bitRemoteAT) ||
|
||
|
(con->type == xbee_64bitRemoteAT)))) {
|
||
|
|
||
|
|
||
|
/* if: is a modem status (there can only be 1 modem status connection) */
|
||
|
if (pkt->type == xbee_modemStatus) return 1;
|
||
|
|
||
|
/* if: the packet is a txStatus or localAT and the frameIDs match */
|
||
|
if ((pkt->type == xbee_txStatus) ||
|
||
|
(pkt->type == xbee_localAT)) {
|
||
|
if (pkt->frameID == con->frameID) {
|
||
|
return 1;
|
||
|
}
|
||
|
/* if: the packet was sent as a 16bit remoteAT, and the 16bit addresss match */
|
||
|
} else if ((pkt->type == xbee_remoteAT) &&
|
||
|
(con->type == xbee_16bitRemoteAT) &&
|
||
|
!memcmp(pkt->Addr16,con->tAddr,2)) {
|
||
|
return 1;
|
||
|
/* if: the packet was sent as a 64bit remoteAT, and the 64bit addresss match */
|
||
|
} else if ((pkt->type == xbee_remoteAT) &&
|
||
|
(con->type == xbee_64bitRemoteAT) &&
|
||
|
!memcmp(pkt->Addr64,con->tAddr,8)) {
|
||
|
return 1;
|
||
|
/* if: the packet is 64bit addressed, and the addresses match */
|
||
|
} else if (pkt->sAddr64 && !memcmp(pkt->Addr64,con->tAddr,8)) {
|
||
|
return 1;
|
||
|
/* if: the packet is 16bit addressed, and the addresses match */
|
||
|
} else if (!pkt->sAddr64 && !memcmp(pkt->Addr16,con->tAddr,2)) {
|
||
|
return 1;
|
||
|
} else if (con->type == pkt->type &&
|
||
|
(con->type == xbee_16bitData || con->type == xbee_64bitData) &&
|
||
|
(pkt->isBroadcastADR || pkt->isBroadcastPAN)) {
|
||
|
unsigned char t[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||
|
if ((con->tAddr64 && !memcmp(con->tAddr,t,8)) ||
|
||
|
(!con->tAddr64 && !memcmp(con->tAddr,t,2))) {
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_parse_io - INTERNAL
|
||
|
parses the data given into the packet io information */
|
||
|
static int xbee_parse_io(xbee_hnd xbee, xbee_pkt *p, unsigned char *d,
|
||
|
int maskOffset, int sampleOffset, int sample) {
|
||
|
xbee_sample *s = &(p->IOdata[sample]);
|
||
|
|
||
|
/* copy in the I/O data mask */
|
||
|
s->IOmask = (((d[maskOffset]<<8) | d[maskOffset + 1]) & 0x7FFF);
|
||
|
|
||
|
/* copy in the digital I/O data */
|
||
|
s->IOdigital = (((d[sampleOffset]<<8) | d[sampleOffset+1]) & 0x01FF);
|
||
|
|
||
|
/* advance over the digital data, if its there */
|
||
|
sampleOffset += ((s->IOmask & 0x01FF)?2:0);
|
||
|
|
||
|
/* copy in the analog I/O data */
|
||
|
if (s->IOmask & 0x0200) {
|
||
|
s->IOanalog[0] = (((d[sampleOffset]<<8) | d[sampleOffset+1]) & 0x03FF);
|
||
|
sampleOffset+=2;
|
||
|
}
|
||
|
if (s->IOmask & 0x0400) {
|
||
|
s->IOanalog[1] = (((d[sampleOffset]<<8) | d[sampleOffset+1]) & 0x03FF);
|
||
|
sampleOffset+=2;
|
||
|
}
|
||
|
if (s->IOmask & 0x0800) {
|
||
|
s->IOanalog[2] = (((d[sampleOffset]<<8) | d[sampleOffset+1]) & 0x03FF);
|
||
|
sampleOffset+=2;
|
||
|
}
|
||
|
if (s->IOmask & 0x1000) {
|
||
|
s->IOanalog[3] = (((d[sampleOffset]<<8) | d[sampleOffset+1]) & 0x03FF);
|
||
|
sampleOffset+=2;
|
||
|
}
|
||
|
if (s->IOmask & 0x2000) {
|
||
|
s->IOanalog[4] = (((d[sampleOffset]<<8) | d[sampleOffset+1]) & 0x03FF);
|
||
|
sampleOffset+=2;
|
||
|
}
|
||
|
if (s->IOmask & 0x4000) {
|
||
|
s->IOanalog[5] = (((d[sampleOffset]<<8) | d[sampleOffset+1]) & 0x03FF);
|
||
|
sampleOffset+=2;
|
||
|
}
|
||
|
|
||
|
if (xbee->log) {
|
||
|
if (s->IOmask & 0x0001)
|
||
|
xbee_logI("Digital 0: %c",((s->IOdigital & 0x0001)?'1':'0'));
|
||
|
if (s->IOmask & 0x0002)
|
||
|
xbee_logI("Digital 1: %c",((s->IOdigital & 0x0002)?'1':'0'));
|
||
|
if (s->IOmask & 0x0004)
|
||
|
xbee_logI("Digital 2: %c",((s->IOdigital & 0x0004)?'1':'0'));
|
||
|
if (s->IOmask & 0x0008)
|
||
|
xbee_logI("Digital 3: %c",((s->IOdigital & 0x0008)?'1':'0'));
|
||
|
if (s->IOmask & 0x0010)
|
||
|
xbee_logI("Digital 4: %c",((s->IOdigital & 0x0010)?'1':'0'));
|
||
|
if (s->IOmask & 0x0020)
|
||
|
xbee_logI("Digital 5: %c",((s->IOdigital & 0x0020)?'1':'0'));
|
||
|
if (s->IOmask & 0x0040)
|
||
|
xbee_logI("Digital 6: %c",((s->IOdigital & 0x0040)?'1':'0'));
|
||
|
if (s->IOmask & 0x0080)
|
||
|
xbee_logI("Digital 7: %c",((s->IOdigital & 0x0080)?'1':'0'));
|
||
|
if (s->IOmask & 0x0100)
|
||
|
xbee_logI("Digital 8: %c",((s->IOdigital & 0x0100)?'1':'0'));
|
||
|
if (s->IOmask & 0x0200)
|
||
|
xbee_logI("Analog 0: %d (~%.2fv)",s->IOanalog[0],(3.3/1023)*s->IOanalog[0]);
|
||
|
if (s->IOmask & 0x0400)
|
||
|
xbee_logI("Analog 1: %d (~%.2fv)",s->IOanalog[1],(3.3/1023)*s->IOanalog[1]);
|
||
|
if (s->IOmask & 0x0800)
|
||
|
xbee_logI("Analog 2: %d (~%.2fv)",s->IOanalog[2],(3.3/1023)*s->IOanalog[2]);
|
||
|
if (s->IOmask & 0x1000)
|
||
|
xbee_logI("Analog 3: %d (~%.2fv)",s->IOanalog[3],(3.3/1023)*s->IOanalog[3]);
|
||
|
if (s->IOmask & 0x2000)
|
||
|
xbee_logI("Analog 4: %d (~%.2fv)",s->IOanalog[4],(3.3/1023)*s->IOanalog[4]);
|
||
|
if (s->IOmask & 0x4000)
|
||
|
xbee_logI("Analog 5: %d (~%.2fv)",s->IOanalog[5],(3.3/1023)*s->IOanalog[5]);
|
||
|
}
|
||
|
|
||
|
return sampleOffset;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_listen_stop
|
||
|
stops the listen thread after the current packet has been processed */
|
||
|
void xbee_listen_stop(xbee_hnd xbee) {
|
||
|
ISREADYP();
|
||
|
xbee->run = 0;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_listen_wrapper - INTERNAL
|
||
|
the xbee_listen wrapper. Prints an error when xbee_listen ends */
|
||
|
static void xbee_listen_wrapper(xbee_hnd xbee) {
|
||
|
int ret;
|
||
|
|
||
|
/* just falls out if the proper 'go-ahead' isn't given */
|
||
|
if (xbee->xbee_ready != -1) return;
|
||
|
/* now allow the parent to continue */
|
||
|
xbee->xbee_ready = -2;
|
||
|
|
||
|
#ifdef _WIN32 /* ---- */
|
||
|
/* win32 requires this delay... no idea why */
|
||
|
usleep(1000000);
|
||
|
#endif /* ----------- */
|
||
|
|
||
|
while (xbee->run) {
|
||
|
ret = xbee_listen(xbee);
|
||
|
if (!xbee->run) break;
|
||
|
xbee_log("xbee_listen() returned [%d]... Restarting in 25ms!",ret);
|
||
|
usleep(25000);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* xbee_listen - INTERNAL
|
||
|
the xbee xbee_listen thread
|
||
|
reads data from the xbee and puts it into a linked list to keep the xbee buffers free */
|
||
|
static int xbee_listen(xbee_hnd xbee) {
|
||
|
#define LISTEN_BUFLEN 1024
|
||
|
unsigned char c, t, d[LISTEN_BUFLEN];
|
||
|
unsigned int l, i, chksum, o;
|
||
|
int j;
|
||
|
xbee_pkt *p = NULL, *q;
|
||
|
xbee_con *con;
|
||
|
int hasCon;
|
||
|
|
||
|
/* do this forever :) */
|
||
|
while (xbee->run) {
|
||
|
/* clean up any undesired storage */
|
||
|
if (p) Xfree(p);
|
||
|
|
||
|
/* wait for a valid start byte */
|
||
|
if ((c = xbee_getrawbyte(xbee)) != 0x7E) {
|
||
|
if (xbee->log) xbee_log("***** Unexpected byte (0x%02X)... *****",c);
|
||
|
continue;
|
||
|
}
|
||
|
if (!xbee->run) return 0;
|
||
|
|
||
|
xbee_logSf();
|
||
|
if (xbee->log) {
|
||
|
struct timeval tv;
|
||
|
xbee_logI("--== RX Packet ===========--");
|
||
|
gettimeofday(&tv,NULL);
|
||
|
xbee_logI("Got a packet @ %ld.%06ld",tv.tv_sec,tv.tv_usec);
|
||
|
}
|
||
|
|
||
|
/* get the length */
|
||
|
l = xbee_getbyte(xbee) << 8;
|
||
|
l += xbee_getbyte(xbee);
|
||
|
|
||
|
/* check it is a valid length... */
|
||
|
if (!l) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Recived zero length packet!");
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
if (l > 100) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Recived oversized packet! Length: %d",l - 1);
|
||
|
}
|
||
|
}
|
||
|
if (l > LISTEN_BUFLEN) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Recived packet larger than buffer! Discarding...");
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Length: %d",l - 1);
|
||
|
}
|
||
|
|
||
|
/* get the packet type */
|
||
|
t = xbee_getbyte(xbee);
|
||
|
|
||
|
/* start the checksum */
|
||
|
chksum = t;
|
||
|
|
||
|
/* suck in all the data */
|
||
|
for (i = 0; l > 1 && i < LISTEN_BUFLEN; l--, i++) {
|
||
|
/* get an unescaped byte */
|
||
|
c = xbee_getbyte(xbee);
|
||
|
d[i] = c;
|
||
|
chksum += c;
|
||
|
if (xbee->log) {
|
||
|
xbee_logIc("%3d | 0x%02X | ",i,c);
|
||
|
if ((c > 32) && (c < 127)) fprintf(xbee->log,"'%c'",c); else fprintf(xbee->log," _ ");
|
||
|
|
||
|
if ((t == XBEE_LOCAL_AT && i == 4) ||
|
||
|
(t == XBEE_REMOTE_AT && i == 14) ||
|
||
|
(t == XBEE_64BIT_DATARX && i == 10) ||
|
||
|
(t == XBEE_16BIT_DATARX && i == 4) ||
|
||
|
(t == XBEE_64BIT_IO && i == 13) ||
|
||
|
(t == XBEE_16BIT_IO && i == 7)) {
|
||
|
/* mark the beginning of the 'data' bytes */
|
||
|
fprintf(xbee->log," <-- data starts");
|
||
|
} else if (t == XBEE_64BIT_IO) {
|
||
|
if (i == 10) fprintf(xbee->log," <-- sample count");
|
||
|
else if (i == 11) fprintf(xbee->log," <-- mask (msb)");
|
||
|
else if (i == 12) fprintf(xbee->log," <-- mask (lsb)");
|
||
|
} else if (t == XBEE_16BIT_IO) {
|
||
|
if (i == 4) fprintf(xbee->log," <-- sample count");
|
||
|
else if (i == 5) fprintf(xbee->log," <-- mask (msb)");
|
||
|
else if (i == 6) fprintf(xbee->log," <-- mask (lsb)");
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
}
|
||
|
i--; /* it went up too many times!... */
|
||
|
|
||
|
/* add the checksum */
|
||
|
chksum += xbee_getbyte(xbee);
|
||
|
|
||
|
/* check if the whole packet was recieved, or something else occured... unlikely... */
|
||
|
if (l>1) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logE("Didn't get whole packet... :(");
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* check the checksum */
|
||
|
if ((chksum & 0xFF) != 0xFF) {
|
||
|
if (xbee->log) {
|
||
|
chksum &= 0xFF;
|
||
|
xbee_logE("Invalid Checksum: 0x%02X",chksum);
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* make a new packet */
|
||
|
p = Xcalloc(sizeof(xbee_pkt));
|
||
|
q = NULL;
|
||
|
p->datalen = 0;
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: modem status */
|
||
|
if (t == XBEE_MODEM_STATUS) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: Modem Status (0x8A)");
|
||
|
xbee_logIc("Event: ");
|
||
|
switch (d[0]) {
|
||
|
case 0x00: fprintf(xbee->log,"Hardware reset"); break;
|
||
|
case 0x01: fprintf(xbee->log,"Watchdog timer reset"); break;
|
||
|
case 0x02: fprintf(xbee->log,"Associated"); break;
|
||
|
case 0x03: fprintf(xbee->log,"Disassociated"); break;
|
||
|
case 0x04: fprintf(xbee->log,"Synchronization lost"); break;
|
||
|
case 0x05: fprintf(xbee->log,"Coordinator realignment"); break;
|
||
|
case 0x06: fprintf(xbee->log,"Coordinator started"); break;
|
||
|
}
|
||
|
fprintf(xbee->log,"... (0x%02X)",d[0]);
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
p->type = xbee_modemStatus;
|
||
|
|
||
|
p->sAddr64 = FALSE;
|
||
|
p->dataPkt = FALSE;
|
||
|
p->txStatusPkt = FALSE;
|
||
|
p->modemStatusPkt = TRUE;
|
||
|
p->remoteATPkt = FALSE;
|
||
|
p->IOPkt = FALSE;
|
||
|
|
||
|
/* modem status can only ever give 1 'data' byte */
|
||
|
p->datalen = 1;
|
||
|
p->data[0] = d[0];
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: local AT response */
|
||
|
} else if (t == XBEE_LOCAL_AT) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: Local AT Response (0x88)");
|
||
|
xbee_logI("FrameID: 0x%02X",d[0]);
|
||
|
xbee_logI("AT Command: %c%c",d[1],d[2]);
|
||
|
xbee_logIc("Status: ");
|
||
|
if (d[3] == 0x00) fprintf(xbee->log,"OK");
|
||
|
else if (d[3] == 0x01) fprintf(xbee->log,"Error");
|
||
|
else if (d[3] == 0x02) fprintf(xbee->log,"Invalid Command");
|
||
|
else if (d[3] == 0x03) fprintf(xbee->log,"Invalid Parameter");
|
||
|
fprintf(xbee->log," (0x%02X)",d[3]);
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
p->type = xbee_localAT;
|
||
|
|
||
|
p->sAddr64 = FALSE;
|
||
|
p->dataPkt = FALSE;
|
||
|
p->txStatusPkt = FALSE;
|
||
|
p->modemStatusPkt = FALSE;
|
||
|
p->remoteATPkt = FALSE;
|
||
|
p->IOPkt = FALSE;
|
||
|
|
||
|
p->frameID = d[0];
|
||
|
p->atCmd[0] = d[1];
|
||
|
p->atCmd[1] = d[2];
|
||
|
|
||
|
p->status = d[3];
|
||
|
|
||
|
/* copy in the data */
|
||
|
p->datalen = i-3;
|
||
|
for (;i>3;i--) p->data[i-4] = d[i];
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: remote AT response */
|
||
|
} else if (t == XBEE_REMOTE_AT) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: Remote AT Response (0x97)");
|
||
|
xbee_logI("FrameID: 0x%02X",d[0]);
|
||
|
xbee_logIc("64-bit Address: ");
|
||
|
for (j=0;j<8;j++) {
|
||
|
fprintf(xbee->log,(j?":%02X":"%02X"),d[1+j]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
xbee_logIc("16-bit Address: ");
|
||
|
for (j=0;j<2;j++) {
|
||
|
fprintf(xbee->log,(j?":%02X":"%02X"),d[9+j]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
xbee_logI("AT Command: %c%c",d[11],d[12]);
|
||
|
xbee_logIc("Status: ");
|
||
|
if (d[13] == 0x00) fprintf(xbee->log,"OK");
|
||
|
else if (d[13] == 0x01) fprintf(xbee->log,"Error");
|
||
|
else if (d[13] == 0x02) fprintf(xbee->log,"Invalid Command");
|
||
|
else if (d[13] == 0x03) fprintf(xbee->log,"Invalid Parameter");
|
||
|
else if (d[13] == 0x04) fprintf(xbee->log,"No Response");
|
||
|
fprintf(xbee->log," (0x%02X)",d[13]);
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
p->type = xbee_remoteAT;
|
||
|
|
||
|
p->sAddr64 = FALSE;
|
||
|
p->dataPkt = FALSE;
|
||
|
p->txStatusPkt = FALSE;
|
||
|
p->modemStatusPkt = FALSE;
|
||
|
p->remoteATPkt = TRUE;
|
||
|
p->IOPkt = FALSE;
|
||
|
|
||
|
p->frameID = d[0];
|
||
|
|
||
|
p->Addr64[0] = d[1];
|
||
|
p->Addr64[1] = d[2];
|
||
|
p->Addr64[2] = d[3];
|
||
|
p->Addr64[3] = d[4];
|
||
|
p->Addr64[4] = d[5];
|
||
|
p->Addr64[5] = d[6];
|
||
|
p->Addr64[6] = d[7];
|
||
|
p->Addr64[7] = d[8];
|
||
|
|
||
|
p->Addr16[0] = d[9];
|
||
|
p->Addr16[1] = d[10];
|
||
|
|
||
|
p->atCmd[0] = d[11];
|
||
|
p->atCmd[1] = d[12];
|
||
|
|
||
|
p->status = d[13];
|
||
|
|
||
|
p->samples = 1;
|
||
|
|
||
|
if (p->status == 0x00 && p->atCmd[0] == 'I' && p->atCmd[1] == 'S') {
|
||
|
/* parse the io data */
|
||
|
xbee_logI("--- Sample -----------------");
|
||
|
xbee_parse_io(xbee, p, d, 15, 17, 0);
|
||
|
xbee_logI("----------------------------");
|
||
|
} else {
|
||
|
/* copy in the data */
|
||
|
p->datalen = i-13;
|
||
|
for (;i>13;i--) p->data[i-14] = d[i];
|
||
|
}
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: TX status */
|
||
|
} else if (t == XBEE_TX_STATUS) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: TX Status Report (0x89)");
|
||
|
xbee_logI("FrameID: 0x%02X",d[0]);
|
||
|
xbee_logIc("Status: ");
|
||
|
if (d[1] == 0x00) fprintf(xbee->log,"Success");
|
||
|
else if (d[1] == 0x01) fprintf(xbee->log,"No ACK");
|
||
|
else if (d[1] == 0x02) fprintf(xbee->log,"CCA Failure");
|
||
|
else if (d[1] == 0x03) fprintf(xbee->log,"Purged");
|
||
|
fprintf(xbee->log," (0x%02X)",d[1]);
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
p->type = xbee_txStatus;
|
||
|
|
||
|
p->sAddr64 = FALSE;
|
||
|
p->dataPkt = FALSE;
|
||
|
p->txStatusPkt = TRUE;
|
||
|
p->modemStatusPkt = FALSE;
|
||
|
p->remoteATPkt = FALSE;
|
||
|
p->IOPkt = FALSE;
|
||
|
|
||
|
p->frameID = d[0];
|
||
|
|
||
|
p->status = d[1];
|
||
|
|
||
|
/* never returns data */
|
||
|
p->datalen = 0;
|
||
|
|
||
|
/* check for any connections waiting for a status update */
|
||
|
/* lock the connection mutex */
|
||
|
xbee_mutex_lock(xbee->conmutex);
|
||
|
xbee_logI("Looking for a connection that wants a status update...");
|
||
|
con = xbee->conlist;
|
||
|
while (con) {
|
||
|
if ((con->frameID == p->frameID) &&
|
||
|
(con->ACKstatus == 0xFF)) {
|
||
|
xbee_logI("Found @ 0x%08X!",con);
|
||
|
con->ACKstatus = p->status;
|
||
|
xbee_sem_post(con->waitforACKsem);
|
||
|
}
|
||
|
con = con->next;
|
||
|
}
|
||
|
|
||
|
/* unlock the connection mutex */
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: 16 / 64bit data recieve */
|
||
|
} else if ((t == XBEE_64BIT_DATARX) ||
|
||
|
(t == XBEE_16BIT_DATARX)) {
|
||
|
int offset;
|
||
|
if (t == XBEE_64BIT_DATARX) { /* 64bit */
|
||
|
offset = 8;
|
||
|
} else { /* 16bit */
|
||
|
offset = 2;
|
||
|
}
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: %d-bit RX Data (0x%02X)",((t == XBEE_64BIT_DATARX)?64:16),t);
|
||
|
xbee_logIc("%d-bit Address: ",((t == XBEE_64BIT_DATARX)?64:16));
|
||
|
for (j=0;j<offset;j++) {
|
||
|
fprintf(xbee->log,(j?":%02X":"%02X"),d[j]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
xbee_logI("RSSI: -%ddB",d[offset]);
|
||
|
if (d[offset + 1] & 0x02) xbee_logI("Options: Address Broadcast");
|
||
|
if (d[offset + 1] & 0x04) xbee_logI("Options: PAN Broadcast");
|
||
|
}
|
||
|
p->isBroadcastADR = !!(d[offset+1] & 0x02);
|
||
|
p->isBroadcastPAN = !!(d[offset+1] & 0x04);
|
||
|
p->dataPkt = TRUE;
|
||
|
p->txStatusPkt = FALSE;
|
||
|
p->modemStatusPkt = FALSE;
|
||
|
p->remoteATPkt = FALSE;
|
||
|
p->IOPkt = FALSE;
|
||
|
|
||
|
if (t == XBEE_64BIT_DATARX) { /* 64bit */
|
||
|
p->type = xbee_64bitData;
|
||
|
|
||
|
p->sAddr64 = TRUE;
|
||
|
|
||
|
p->Addr64[0] = d[0];
|
||
|
p->Addr64[1] = d[1];
|
||
|
p->Addr64[2] = d[2];
|
||
|
p->Addr64[3] = d[3];
|
||
|
p->Addr64[4] = d[4];
|
||
|
p->Addr64[5] = d[5];
|
||
|
p->Addr64[6] = d[6];
|
||
|
p->Addr64[7] = d[7];
|
||
|
} else { /* 16bit */
|
||
|
p->type = xbee_16bitData;
|
||
|
|
||
|
p->sAddr64 = FALSE;
|
||
|
|
||
|
p->Addr16[0] = d[0];
|
||
|
p->Addr16[1] = d[1];
|
||
|
}
|
||
|
|
||
|
/* save the RSSI / signal strength
|
||
|
this can be used with printf as:
|
||
|
printf("-%ddB\n",p->RSSI); */
|
||
|
p->RSSI = d[offset];
|
||
|
|
||
|
p->status = d[offset + 1];
|
||
|
|
||
|
/* copy in the data */
|
||
|
p->datalen = i-(offset + 1);
|
||
|
for (;i>offset + 1;i--) p->data[i-(offset + 2)] = d[i];
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: 16 / 64bit I/O recieve */
|
||
|
} else if ((t == XBEE_64BIT_IO) ||
|
||
|
(t == XBEE_16BIT_IO)) {
|
||
|
int offset,i2;
|
||
|
if (t == XBEE_64BIT_IO) { /* 64bit */
|
||
|
p->type = xbee_64bitIO;
|
||
|
|
||
|
p->sAddr64 = TRUE;
|
||
|
|
||
|
p->Addr64[0] = d[0];
|
||
|
p->Addr64[1] = d[1];
|
||
|
p->Addr64[2] = d[2];
|
||
|
p->Addr64[3] = d[3];
|
||
|
p->Addr64[4] = d[4];
|
||
|
p->Addr64[5] = d[5];
|
||
|
p->Addr64[6] = d[6];
|
||
|
p->Addr64[7] = d[7];
|
||
|
|
||
|
offset = 8;
|
||
|
p->samples = d[10];
|
||
|
} else { /* 16bit */
|
||
|
p->type = xbee_16bitIO;
|
||
|
|
||
|
p->sAddr64 = FALSE;
|
||
|
|
||
|
p->Addr16[0] = d[0];
|
||
|
p->Addr16[1] = d[1];
|
||
|
|
||
|
offset = 2;
|
||
|
p->samples = d[4];
|
||
|
}
|
||
|
if (p->samples > 1) {
|
||
|
p = Xrealloc(p, sizeof(xbee_pkt) + (sizeof(xbee_sample) * (p->samples - 1)));
|
||
|
}
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: %d-bit RX I/O Data (0x%02X)",((t == XBEE_64BIT_IO)?64:16),t);
|
||
|
xbee_logIc("%d-bit Address: ",((t == XBEE_64BIT_IO)?64:16));
|
||
|
for (j = 0; j < offset; j++) {
|
||
|
fprintf(xbee->log,(j?":%02X":"%02X"),d[j]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
xbee_logI("RSSI: -%ddB",d[offset]);
|
||
|
xbee_logI("Samples: %d",d[offset + 2]);
|
||
|
}
|
||
|
i2 = offset + 5;
|
||
|
|
||
|
/* never returns data */
|
||
|
p->datalen = 0;
|
||
|
|
||
|
p->dataPkt = FALSE;
|
||
|
p->txStatusPkt = FALSE;
|
||
|
p->modemStatusPkt = FALSE;
|
||
|
p->remoteATPkt = FALSE;
|
||
|
p->IOPkt = TRUE;
|
||
|
|
||
|
/* save the RSSI / signal strength
|
||
|
this can be used with printf as:
|
||
|
printf("-%ddB\n",p->RSSI); */
|
||
|
p->RSSI = d[offset];
|
||
|
|
||
|
p->status = d[offset + 1];
|
||
|
|
||
|
/* each sample is split into its own packet here, for simplicity */
|
||
|
for (o = 0; o < p->samples; o++) {
|
||
|
if (i2 >= i) {
|
||
|
xbee_logI("Invalid I/O data! Actually contained %d samples...",o);
|
||
|
p = Xrealloc(p, sizeof(xbee_pkt) + (sizeof(xbee_sample) * ((o>1)?o:1)));
|
||
|
p->samples = o;
|
||
|
break;
|
||
|
}
|
||
|
xbee_logI("--- Sample %3d -------------", o);
|
||
|
|
||
|
/* parse the io data */
|
||
|
i2 = xbee_parse_io(xbee, p, d, offset + 3, i2, o);
|
||
|
}
|
||
|
xbee_logI("----------------------------");
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: Series 2 Transmit status */
|
||
|
} else if (t == XBEE2_TX_STATUS) {
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: Series 2 Transmit Status (0x%02X)", t);
|
||
|
xbee_logI("FrameID: 0x%02X",d[0]);
|
||
|
xbee_logI("16-bit Delivery Address: %02X:%02X",d[1],d[2]);
|
||
|
xbee_logI("Transmit Retry Count: %02X",d[3]);
|
||
|
xbee_logIc("Delivery Status: ");
|
||
|
if (d[4] == 0x00) fprintf(xbee->log,"Success");
|
||
|
else if (d[4] == 0x02) fprintf(xbee->log,"CCA Failure");
|
||
|
else if (d[4] == 0x15) fprintf(xbee->log,"Invalid Destination");
|
||
|
else if (d[4] == 0x21) fprintf(xbee->log,"Network ACK Failure");
|
||
|
else if (d[4] == 0x22) fprintf(xbee->log,"Not Joined to Network");
|
||
|
else if (d[4] == 0x23) fprintf(xbee->log,"Self-Addressed");
|
||
|
else if (d[4] == 0x24) fprintf(xbee->log,"Address Not Found");
|
||
|
else if (d[4] == 0x25) fprintf(xbee->log,"Route Not Found");
|
||
|
else if (d[4] == 0x74) fprintf(xbee->log,"Data Payload Too Large"); /* ??? */
|
||
|
fprintf(xbee->log," (0x%02X)",d[4]);
|
||
|
xbee_logIcf();
|
||
|
|
||
|
xbee_logIc("Discovery Status: ");
|
||
|
if (d[5] == 0x00) fprintf(xbee->log,"No Discovery Overhead");
|
||
|
else if (d[5] == 0x01) fprintf(xbee->log,"Address Discovery");
|
||
|
else if (d[5] == 0x02) fprintf(xbee->log,"Route Discovery");
|
||
|
else if (d[5] == 0x03) fprintf(xbee->log,"Address & Route Discovery");
|
||
|
fprintf(xbee->log," (0x%02X)",d[5]);
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
|
||
|
p->type = xbee2_txStatus;
|
||
|
|
||
|
p->sAddr64 = FALSE;
|
||
|
p->dataPkt = FALSE;
|
||
|
p->txStatusPkt = TRUE;
|
||
|
p->modemStatusPkt = FALSE;
|
||
|
p->remoteATPkt = FALSE;
|
||
|
p->IOPkt = FALSE;
|
||
|
|
||
|
p->frameID = d[0];
|
||
|
|
||
|
p->status = d[4];
|
||
|
|
||
|
/* never returns data */
|
||
|
p->datalen = 0;
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: Series 2 data recieve */
|
||
|
} else if (t == XBEE2_DATARX) {
|
||
|
int offset;
|
||
|
offset = 10;
|
||
|
if (xbee->log) {
|
||
|
xbee_logI("Packet type: Series 2 Data Rx (0x%02X)", t);
|
||
|
|
||
|
xbee_logIc("64-bit Address: ");
|
||
|
for (j=0;j<8;j++) {
|
||
|
fprintf(xbee->log,(j?":%02X":"%02X"),d[j]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
|
||
|
xbee_logIc("16-bit Address: ");
|
||
|
for (j=0;j<2;j++) {
|
||
|
fprintf(xbee->log,(j?":%02X":"%02X"),d[j+8]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
|
||
|
if (d[offset] & 0x01) xbee_logI("Options: Packet Acknowledged");
|
||
|
if (d[offset] & 0x02) xbee_logI("Options: Packet was a broadcast packet");
|
||
|
if (d[offset] & 0x20) xbee_logI("Options: Packet Encrypted"); /* ??? */
|
||
|
if (d[offset] & 0x40) xbee_logI("Options: Packet from end device"); /* ??? */
|
||
|
}
|
||
|
p->dataPkt = TRUE;
|
||
|
p->txStatusPkt = FALSE;
|
||
|
p->modemStatusPkt = FALSE;
|
||
|
p->remoteATPkt = FALSE;
|
||
|
p->IOPkt = FALSE;
|
||
|
p->type = xbee2_data;
|
||
|
p->sAddr64 = TRUE;
|
||
|
|
||
|
p->Addr64[0] = d[0];
|
||
|
p->Addr64[1] = d[1];
|
||
|
p->Addr64[2] = d[2];
|
||
|
p->Addr64[3] = d[3];
|
||
|
p->Addr64[4] = d[4];
|
||
|
p->Addr64[5] = d[5];
|
||
|
p->Addr64[6] = d[6];
|
||
|
p->Addr64[7] = d[7];
|
||
|
|
||
|
p->Addr16[0] = d[8];
|
||
|
p->Addr16[1] = d[9];
|
||
|
|
||
|
p->status = d[offset];
|
||
|
|
||
|
/* copy in the data */
|
||
|
p->datalen = i - (offset + 1);
|
||
|
for (;i>offset;i--) {
|
||
|
p->data[i-(offset + 1)] = d[i];
|
||
|
}
|
||
|
|
||
|
/* ########################################## */
|
||
|
/* if: Unknown */
|
||
|
} else {
|
||
|
xbee_logE("Packet type: Unknown (0x%02X)",t);
|
||
|
continue;
|
||
|
}
|
||
|
p->next = NULL;
|
||
|
|
||
|
/* lock the connection mutex */
|
||
|
xbee_mutex_lock(xbee->conmutex);
|
||
|
|
||
|
hasCon = 0;
|
||
|
if (p->isBroadcastADR || p->isBroadcastPAN) {
|
||
|
unsigned char t[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||
|
/* if the packet was broadcast, search for a broadcast accepting connection */
|
||
|
con = xbee->conlist;
|
||
|
while (con) {
|
||
|
if (con->type == p->type &&
|
||
|
(con->type == xbee_16bitData || con->type == xbee_64bitData) &&
|
||
|
((con->tAddr64 && !memcmp(con->tAddr,t,8)) ||
|
||
|
(!con->tAddr64 && !memcmp(con->tAddr,t,2)))) {
|
||
|
hasCon = 1;
|
||
|
xbee_logI("Found broadcasting connection @ 0x%08X",con);
|
||
|
break;
|
||
|
}
|
||
|
con = con->next;
|
||
|
}
|
||
|
}
|
||
|
if (!hasCon || !con) {
|
||
|
con = xbee->conlist;
|
||
|
while (con) {
|
||
|
if (xbee_matchpktcon(xbee, p, con)) {
|
||
|
hasCon = 1;
|
||
|
break;
|
||
|
}
|
||
|
con = con->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* unlock the connection mutex */
|
||
|
xbee_mutex_unlock(xbee->conmutex);
|
||
|
|
||
|
/* if the packet doesn't have a connection, don't add it! */
|
||
|
if (!hasCon) {
|
||
|
xbee_logE("Connectionless packet... discarding!");
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* if the connection has a callback function then it is passed the packet
|
||
|
and the packet is not added to the list */
|
||
|
if (con && con->callback) {
|
||
|
t_callback_list *l, *q;
|
||
|
|
||
|
xbee_mutex_lock(con->callbackListmutex);
|
||
|
l = con->callbackList;
|
||
|
q = NULL;
|
||
|
while (l) {
|
||
|
q = l;
|
||
|
l = l->next;
|
||
|
}
|
||
|
l = Xcalloc(sizeof(t_callback_list));
|
||
|
l->pkt = p;
|
||
|
if (!con->callbackList || q == NULL) {
|
||
|
con->callbackList = l;
|
||
|
} else {
|
||
|
q->next = l;
|
||
|
}
|
||
|
xbee_mutex_unlock(con->callbackListmutex);
|
||
|
|
||
|
xbee_logI("Using callback function!");
|
||
|
xbee_logI(" info block @ 0x%08X",l);
|
||
|
xbee_logI(" function @ 0x%08X",con->callback);
|
||
|
xbee_logI(" connection @ 0x%08X",con);
|
||
|
xbee_logE(" packet @ 0x%08X",p);
|
||
|
|
||
|
/* if the callback thread not still running, then start a new one! */
|
||
|
if (!xbee_mutex_trylock(con->callbackmutex)) {
|
||
|
xbee_thread_t t;
|
||
|
int ret;
|
||
|
t_threadList *p, *q;
|
||
|
t_CBinfo info;
|
||
|
info.xbee = xbee;
|
||
|
info.con = con;
|
||
|
xbee_log("Starting new callback thread!");
|
||
|
if ((ret = xbee_thread_create(t,xbee_callbackWrapper,&info)) != 0) {
|
||
|
xbee_mutex_unlock(con->callbackmutex);
|
||
|
/* this MAY help with future attempts... */
|
||
|
xbee_sem_post(xbee->threadsem);
|
||
|
xbee_logS("An error occured while starting thread (%d)... Out of resources?", ret);
|
||
|
xbee_logE("This packet has been lost!");
|
||
|
continue;
|
||
|
}
|
||
|
xbee_log("Started thread 0x%08X!", t);
|
||
|
xbee_mutex_lock(xbee->threadmutex);
|
||
|
p = xbee->threadList;
|
||
|
q = NULL;
|
||
|
while (p) {
|
||
|
q = p;
|
||
|
p = p->next;
|
||
|
}
|
||
|
p = Xcalloc(sizeof(t_threadList));
|
||
|
if (q == NULL) {
|
||
|
xbee->threadList = p;
|
||
|
} else {
|
||
|
q->next = p;
|
||
|
}
|
||
|
p->thread = t;
|
||
|
p->next = NULL;
|
||
|
xbee_mutex_unlock(xbee->threadmutex);
|
||
|
} else {
|
||
|
xbee_logE("Using existing callback thread... callback has been scheduled.");
|
||
|
}
|
||
|
/* prevent the packet from being free'd */
|
||
|
p = NULL;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/* lock the packet mutex, so we can safely add the packet to the list */
|
||
|
xbee_mutex_lock(xbee->pktmutex);
|
||
|
|
||
|
/* if: the list is empty */
|
||
|
if (!xbee->pktlist) {
|
||
|
/* start the list! */
|
||
|
xbee->pktlist = p;
|
||
|
} else if (xbee->pktlast) {
|
||
|
/* add the packet to the end */
|
||
|
xbee->pktlast->next = p;
|
||
|
} else {
|
||
|
/* pktlast wasnt set... look for the end and then set it */
|
||
|
i = 0;
|
||
|
q = xbee->pktlist;
|
||
|
while (q->next) {
|
||
|
q = q->next;
|
||
|
i++;
|
||
|
}
|
||
|
q->next = p;
|
||
|
xbee->pktcount = i;
|
||
|
}
|
||
|
xbee->pktlast = p;
|
||
|
xbee->pktcount++;
|
||
|
|
||
|
/* unlock the packet mutex */
|
||
|
xbee_mutex_unlock(xbee->pktmutex);
|
||
|
|
||
|
xbee_logI("--========================--");
|
||
|
xbee_logE("Packets: %d",xbee->pktcount);
|
||
|
|
||
|
p = q = NULL;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void xbee_callbackWrapper(t_CBinfo *info) {
|
||
|
xbee_hnd xbee;
|
||
|
xbee_con *con;
|
||
|
xbee_pkt *pkt;
|
||
|
t_callback_list *temp;
|
||
|
xbee = info->xbee;
|
||
|
con = info->con;
|
||
|
/* dont forget! the callback mutex is already locked... by the parent thread :) */
|
||
|
xbee_mutex_lock(con->callbackListmutex);
|
||
|
while (con->callbackList) {
|
||
|
/* shift the list along 1 */
|
||
|
temp = con->callbackList;
|
||
|
con->callbackList = temp->next;
|
||
|
xbee_mutex_unlock(con->callbackListmutex);
|
||
|
/* get the packet */
|
||
|
pkt = temp->pkt;
|
||
|
|
||
|
xbee_logS("Starting callback function...");
|
||
|
xbee_logI(" info block @ 0x%08X",temp);
|
||
|
xbee_logI(" function @ 0x%08X",con->callback);
|
||
|
xbee_logI(" connection @ 0x%08X",con);
|
||
|
xbee_logE(" packet @ 0x%08X",pkt);
|
||
|
Xfree(temp);
|
||
|
if (con->callback) {
|
||
|
con->callback(con,pkt);
|
||
|
xbee_log("Callback complete!");
|
||
|
if (!con->noFreeAfterCB) Xfree(pkt);
|
||
|
} else {
|
||
|
xbee_pkt *q;
|
||
|
int i;
|
||
|
xbee_log("Callback function was removed! Appending packet to main list...");
|
||
|
/* lock the packet mutex, so we can safely add the packet to the list */
|
||
|
xbee_mutex_lock(xbee->pktmutex);
|
||
|
|
||
|
/* if: the list is empty */
|
||
|
if (!xbee->pktlist) {
|
||
|
/* start the list! */
|
||
|
xbee->pktlist = pkt;
|
||
|
} else if (xbee->pktlast) {
|
||
|
/* add the packet to the end */
|
||
|
xbee->pktlast->next = pkt;
|
||
|
} else {
|
||
|
/* pktlast wasnt set... look for the end and then set it */
|
||
|
i = 0;
|
||
|
q = xbee->pktlist;
|
||
|
while (q->next) {
|
||
|
q = q->next;
|
||
|
i++;
|
||
|
}
|
||
|
q->next = pkt;
|
||
|
xbee->pktcount = i;
|
||
|
}
|
||
|
xbee->pktlast = pkt;
|
||
|
xbee->pktcount++;
|
||
|
|
||
|
/* unlock the packet mutex */
|
||
|
xbee_mutex_unlock(xbee->pktmutex);
|
||
|
}
|
||
|
|
||
|
xbee_mutex_lock(con->callbackListmutex);
|
||
|
}
|
||
|
xbee_mutex_unlock(con->callbackListmutex);
|
||
|
|
||
|
xbee_log("Callback thread ending...");
|
||
|
/* releasing the thread mutex is the last thing we do! */
|
||
|
xbee_mutex_unlock(con->callbackmutex);
|
||
|
|
||
|
if (con->destroySelf) {
|
||
|
_xbee_endcon2(xbee,&con,1);
|
||
|
}
|
||
|
xbee_sem_post(xbee->threadsem);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_thread_watch - INTERNAL
|
||
|
watches for dead threads and tidies up */
|
||
|
static void xbee_thread_watch(xbee_hnd xbee) {
|
||
|
|
||
|
#ifdef _WIN32 /* ---- */
|
||
|
/* win32 requires this delay... no idea why */
|
||
|
usleep(1000000);
|
||
|
#endif /* ----------- */
|
||
|
|
||
|
xbee_mutex_init(xbee->threadmutex);
|
||
|
xbee_sem_init(xbee->threadsem);
|
||
|
|
||
|
while (xbee->run) {
|
||
|
t_threadList *p, *q, *t;
|
||
|
xbee_mutex_lock(xbee->threadmutex);
|
||
|
p = xbee->threadList;
|
||
|
q = NULL;
|
||
|
|
||
|
while (p) {
|
||
|
t = p;
|
||
|
p = p->next;
|
||
|
if (!(xbee_thread_tryjoin(t->thread))) {
|
||
|
xbee_log("Joined with thread 0x%08X...",t->thread);
|
||
|
if (t == xbee->threadList) {
|
||
|
xbee->threadList = t->next;
|
||
|
} else if (q) {
|
||
|
q->next = t->next;
|
||
|
}
|
||
|
free(t);
|
||
|
} else {
|
||
|
q = t;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
xbee_mutex_unlock(xbee->threadmutex);
|
||
|
xbee_sem_wait(xbee->threadsem);
|
||
|
usleep(100000); /* 100ms to allow the thread to end before we try to join */
|
||
|
}
|
||
|
|
||
|
xbee_mutex_destroy(xbee->threadmutex);
|
||
|
xbee_sem_destroy(xbee->threadsem);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_getbyte - INTERNAL
|
||
|
waits for an escaped byte of data */
|
||
|
static unsigned char xbee_getbyte(xbee_hnd xbee) {
|
||
|
unsigned char c;
|
||
|
|
||
|
/* take a byte */
|
||
|
c = xbee_getrawbyte(xbee);
|
||
|
/* if its escaped, take another and un-escape */
|
||
|
if (c == 0x7D) c = xbee_getrawbyte(xbee) ^ 0x20;
|
||
|
|
||
|
return (c & 0xFF);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_getrawbyte - INTERNAL
|
||
|
waits for a raw byte of data */
|
||
|
static unsigned char xbee_getrawbyte(xbee_hnd xbee) {
|
||
|
int ret;
|
||
|
unsigned char c = 0x00;
|
||
|
|
||
|
/* the loop is just incase there actually isnt a byte there to be read... */
|
||
|
do {
|
||
|
/* wait for a read to be possible */
|
||
|
if ((ret = xbee_select(xbee,NULL)) == -1) {
|
||
|
xbee_perror("libxbee:xbee_getrawbyte()");
|
||
|
exit(1);
|
||
|
}
|
||
|
if (!xbee->run) break;
|
||
|
if (ret == 0) continue;
|
||
|
|
||
|
/* read 1 character */
|
||
|
if (xbee_read(xbee,&c,1) == 0) {
|
||
|
/* for some reason no characters were read... */
|
||
|
if (xbee_ferror(xbee) || xbee_feof(xbee)) {
|
||
|
xbee_log("Error or EOF detected");
|
||
|
fprintf(stderr,"libxbee:xbee_read(): Error or EOF detected\n");
|
||
|
exit(1); /* this should have something nicer... */
|
||
|
}
|
||
|
/* no error... try again */
|
||
|
usleep(10);
|
||
|
continue;
|
||
|
}
|
||
|
} while (0);
|
||
|
|
||
|
return (c & 0xFF);
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
_xbee_send_pkt - INTERNAL
|
||
|
sends a complete packet of data */
|
||
|
static int _xbee_send_pkt(xbee_hnd xbee, t_data *pkt, xbee_con *con) {
|
||
|
int retval = 0;
|
||
|
|
||
|
/* lock connection mutex */
|
||
|
xbee_mutex_lock(con->Txmutex);
|
||
|
/* lock the send mutex */
|
||
|
xbee_mutex_lock(xbee->sendmutex);
|
||
|
|
||
|
/* write and flush the data */
|
||
|
xbee_write(xbee,pkt->data,pkt->length);
|
||
|
|
||
|
/* unlock the mutex */
|
||
|
xbee_mutex_unlock(xbee->sendmutex);
|
||
|
|
||
|
xbee_logSf();
|
||
|
if (xbee->log) {
|
||
|
int i,x,y;
|
||
|
/* prints packet in hex byte-by-byte */
|
||
|
xbee_logIc("TX Packet:");
|
||
|
for (i=0,x=0,y=0;i<pkt->length;i++,x--) {
|
||
|
if (x == 0) {
|
||
|
fprintf(xbee->log,"\n 0x%04X | ",y);
|
||
|
x = 0x8;
|
||
|
y += x;
|
||
|
}
|
||
|
if (x == 4) {
|
||
|
fprintf(xbee->log," ");
|
||
|
}
|
||
|
fprintf(xbee->log,"0x%02X ",pkt->data[i]);
|
||
|
}
|
||
|
xbee_logIcf();
|
||
|
}
|
||
|
xbee_logEf();
|
||
|
|
||
|
if (con->waitforACK &&
|
||
|
((con->type == xbee_16bitData) ||
|
||
|
(con->type == xbee_64bitData))) {
|
||
|
con->ACKstatus = 0xFF; /* waiting */
|
||
|
xbee_log("Waiting for ACK/NAK response...");
|
||
|
xbee_sem_wait1sec(con->waitforACKsem);
|
||
|
switch (con->ACKstatus) {
|
||
|
case 0: xbee_log("ACK recieved!"); break;
|
||
|
case 1: xbee_log("NAK recieved..."); break;
|
||
|
case 2: xbee_log("CCA failure..."); break;
|
||
|
case 3: xbee_log("Purged..."); break;
|
||
|
case 255: default: xbee_log("Timeout...");
|
||
|
}
|
||
|
if (con->ACKstatus) retval = 1; /* error */
|
||
|
}
|
||
|
|
||
|
/* unlock connection mutex */
|
||
|
xbee_mutex_unlock(con->Txmutex);
|
||
|
|
||
|
/* free the packet */
|
||
|
Xfree(pkt);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
/* #################################################################
|
||
|
xbee_make_pkt - INTERNAL
|
||
|
adds delimiter field
|
||
|
calculates length and checksum
|
||
|
escapes bytes */
|
||
|
static t_data *xbee_make_pkt(xbee_hnd xbee, unsigned char *data, int length) {
|
||
|
t_data *pkt;
|
||
|
unsigned int l, i, o, t, x, m;
|
||
|
char d = 0;
|
||
|
|
||
|
/* check the data given isnt too long
|
||
|
100 bytes maximum payload + 12 bytes header information */
|
||
|
if (length > 100 + 12) return NULL;
|
||
|
|
||
|
/* calculate the length of the whole packet
|
||
|
start, length (MSB), length (LSB), DATA, checksum */
|
||
|
l = 3 + length + 1;
|
||
|
|
||
|
/* prepare memory */
|
||
|
pkt = Xcalloc(sizeof(t_data));
|
||
|
|
||
|
/* put start byte on */
|
||
|
pkt->data[0] = 0x7E;
|
||
|
|
||
|
/* copy data into packet */
|
||
|
for (t = 0, i = 0, o = 1, m = 1; i <= length; o++, m++) {
|
||
|
/* if: its time for the checksum */
|
||
|
if (i == length) d = M8((0xFF - M8(t)));
|
||
|
/* if: its time for the high length byte */
|
||
|
else if (m == 1) d = M8(length >> 8);
|
||
|
/* if: its time for the low length byte */
|
||
|
else if (m == 2) d = M8(length);
|
||
|
/* if: its time for the normal data */
|
||
|
else if (m > 2) d = data[i];
|
||
|
|
||
|
x = 0;
|
||
|
/* check for any escapes needed */
|
||
|
if ((d == 0x11) || /* XON */
|
||
|
(d == 0x13) || /* XOFF */
|
||
|
(d == 0x7D) || /* Escape */
|
||
|
(d == 0x7E)) { /* Frame Delimiter */
|
||
|
l++;
|
||
|
pkt->data[o++] = 0x7D;
|
||
|
x = 1;
|
||
|
}
|
||
|
|
||
|
/* move data in */
|
||
|
pkt->data[o] = ((!x)?d:d^0x20);
|
||
|
if (m > 2) {
|
||
|
i++;
|
||
|
t += d;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* remember the length */
|
||
|
pkt->length = l;
|
||
|
|
||
|
return pkt;
|
||
|
}
|