Esempio n. 1
0
/* get a packet from a connection
   if no packet is avaliable or an error occurs, then NULL is returned */
EXPORT struct xbee_pkt *xbee_conRx(struct xbee *xbee, struct xbee_con *con) {
	struct xbee_pkt *pkt;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return NULL;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return NULL;
	if (!con) return NULL;
	
	/* check the provided connection */
	if (_xbee_conValidate(xbee, con, NULL)) return NULL;
	
	/* you aren't allowed at the packets this way if a callback is enabled... */
	if (con->callback) {
		xbee_log(1,"Cannot retrieve a packet while callback is enabled for connection @ %p", con);
		return NULL;
	}
	
	/* try to get a packet */
	if ((pkt = (struct xbee_pkt*)ll_ext_head(&(con->rxList))) == NULL) {
		/* if there isnt one, then log a message */
		xbee_log(10,"No packets for connection @ %p", con);
		return NULL;
	}
	/* if there is one, then log its details and return it */
	xbee_log(2,"Gave a packet @ %p to the user from connection @ %p, %d remain...", pkt, con, ll_count_items(&(con->rxList)));
	return pkt;
}
Esempio n. 2
0
/* put a connection to sleep
   if wakeOnRx is TRUE, then the connection will be woken up when data is received, and if a callback is assigned it will be called */
EXPORT int xbee_conSleep(struct xbee *xbee, struct xbee_con *con, int wakeOnRx) {
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!con) return XBEE_EMISSINGPARAM;

	/* check the connection */
	if (_xbee_conValidate(xbee, con, NULL)) return XBEE_EINVAL;

	/* this mapping is implemented as an extension, therefore it is entirely optional! */
	if (xbee->f->conSleep) {
		/* do the external stuff first, and then the internal if we have success */
		int ret;
		if ((ret = xbee->f->conSleep(xbee, con, wakeOnRx)) != 0) {
			/* ret should be either 0 / XBEE_ESTALE */;
			return ret;
		}
	}
	
	/* setup the sleep (i wish it was this easy for me to sleep!) */
	con->sleeping = 1;
	con->wakeOnRx = !!wakeOnRx;

	return XBEE_ENONE;
}
Esempio n. 3
0
/* get/set options for the connection */
EXPORT int xbee_conOptions(struct xbee *xbee, struct xbee_con *con, struct xbee_conOptions *getOptions, struct xbee_conOptions *setOptions) {
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!con) return XBEE_EMISSINGPARAM;
	
	/* check the connection */
	if (_xbee_conValidate(xbee, con, NULL)) return XBEE_EINVAL;

	/* this mapping is implemented as an extension, therefore it is entirely optional! */
	if (xbee->f->conOptions) {
		/* do the external stuff first, and then the internal if we have success */
		int ret;
		if ((ret = xbee->f->conOptions(xbee, con, getOptions, setOptions)) != 0) {
			/* ret should be either 0 / XBEE_ESTALE */;
			return ret;
		}
	}

	/* send the current options back to the caller */
	if (getOptions) memcpy(getOptions, &con->options, sizeof(struct xbee_conOptions));
	/* pull the new options in from the caller */
	if (setOptions) memcpy(&con->options, setOptions, sizeof(struct xbee_conOptions));

	return XBEE_ENONE;
}
Esempio n. 4
0
EXPORT xbee_err xbee_modeGet(struct xbee *xbee, const char **mode) {
	if (!xbee || !mode) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	*mode = xbee->mode->name;
	return XBEE_ENONE;
}
Esempio n. 5
0
xbee_err _xbee_logWrite(struct xbee_log *log, const char *file, int line, const char *function, struct xbee *xbee, int minLevel, char *preStr, char *format, va_list ap) {
	char tBuf[XBEE_LOG_MAXLEN];
	int len;
	const char * const truncStr = XBEE_LOG_TRUNC_STR;
	static int truncLen = 0;
	
	if (!log || !file || !function || !xbee || !preStr || !format) return XBEE_EMISSINGPARAM;
	if (!log->f) return XBEE_EINVAL;
	
	len = vsnprintf(tBuf, XBEE_LOG_MAXLEN, format, ap);
	
	if (len >= XBEE_LOG_MAXLEN) {
		if (truncLen == 0) {
			truncLen = strlen(truncStr);
		}
		strcpy(&(tBuf[XBEE_LOG_MAXLEN - (truncLen + 1)]), truncStr);
	}
	
	xbee_mutex_lock(&log->mutex);
	
#ifndef XBEE_LOG_NO_COLOR
	if (!xbee) {
		fprintf(log->f, "%s%c[36m%3d%c[90m#[%c[32m%s:%d%c[90m]%c[33m %s()%c[90m:%c[0m %s\n",
			preStr, 27, minLevel, 27, 27, file, line, 27, 27, function, 27, 27,                   tBuf);
	} else if (xbee_validate(xbee) == XBEE_ENONE) {
		fprintf(log->f, "%s%c[36m%3d%c[90m#[%c[32m%s:%d%c[90m]%c[33m %s()%c[0m %c[35m%p%c[90m:%c[0m %s\n",
			preStr, 27, minLevel, 27, 27, file, line, 27, 27, function, 27, 27, xbee, 27, 27,     tBuf);
	} else {
		fprintf(log->f, "%s%c[36m%3d%c[90m#[%c[32m%s:%d%c[90m]%c[33m %s()%c[31m !%c[35m%p%c[31m!%c[90m:%c[0m %s\n",
			preStr, 27, minLevel, 27, 27, file, line, 27, 27, function, 27, 27, xbee, 27, 27, 27, tBuf);
	}
#else
	if (!xbee) {
		fprintf(log->f, "%s%3d#[%s:%d] %s(): %s\n",      preStr, minLevel, file, line, function,       tBuf);
	} else if (xbee_validate(xbee) == XBEE_ENONE) {
		fprintf(log->f, "%s%3d#[%s:%d] %s() %p: %s\n",   preStr, minLevel, file, line, function, xbee, tBuf);
	} else {
		fprintf(log->f, "%s%3d#[%s:%d] %s() !%p!: %s\n", preStr, minLevel, file, line, function, xbee, tBuf);
	}
#endif
	fflush(log->f);
	
	xbee_mutex_unlock(&log->mutex);
	
	return XBEE_ENONE;
}
Esempio n. 6
0
EXPORT xbee_err xbee_dataGet(struct xbee *xbee, void **curData) {
	if (!xbee || !curData) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	*curData = xbee->userData;
	return XBEE_ENONE;
}
Esempio n. 7
0
EXPORT xbee_err xbee_dataSet(struct xbee *xbee, void *newData, void **oldData) {
	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	if (oldData) *oldData = xbee->userData;
	xbee->userData = newData;
	return XBEE_ENONE;
}
Esempio n. 8
0
EXPORT xbee_err xbee_attachEOFCallback(struct xbee *xbee, xbee_t_eofCallback eofCallback) {
      if (!xbee || !eofCallback) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
      if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
      if (xbee->iface.rx->eofCallback) return XBEE_EINUSE;
      xbee->iface.rx->eofCallback = eofCallback;
      return XBEE_ENONE;
}
Esempio n. 9
0
EXPORT xbee_err xbee_logLevelGet(struct xbee *xbee, int *level) {
	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	if (!xbee->log) return XBEE_ENOTIMPLEMENTED;
	
	*level = xbee->log->logLevel;
	
	return XBEE_ENONE;
}
Esempio n. 10
0
EXPORT xbee_err xbee_logTargetGet(struct xbee *xbee, FILE **f) {
	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	if (!xbee->log) return XBEE_ENOTIMPLEMENTED;
	
	*f = xbee->log->f;
	
	return XBEE_ENONE;
}
Esempio n. 11
0
EXPORT xbee_err xbee_shutdown(struct xbee *xbee) {
	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */

	/* pluck out the instance - from now on it is invalid */
	xbee_ll_ext_item(xbeeList, xbee);
	/* start a detached thread */
	xbee_threadStart(xbee, NULL, -1, 1, xbee_shutdownThread, (void*)(xsys_thread_self()));
	
	return XBEE_ENONE;
}
Esempio n. 12
0
EXPORT xbee_err xbee_logTargetSet(struct xbee *xbee, FILE *f) {
	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	if (!xbee->log) return XBEE_ENOTIMPLEMENTED;
	
	xbee_mutex_lock(&xbee->log->mutex);
	xbee->log->f = f;
	xbee_mutex_unlock(&xbee->log->mutex);
	
	return XBEE_ENONE;
}
Esempio n. 13
0
EXPORT xbee_err xbee_logLevelSet(struct xbee *xbee, int level) {
	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	if (!xbee->log) return XBEE_ENOTIMPLEMENTED;
	
	xbee_mutex_lock(&xbee->log->mutex);
	xbee->log->logLevel = level;
	xbee_mutex_unlock(&xbee->log->mutex);
	xbee_log(xbee->log->logLevel, "Set log level to: %d", level);
	
	return XBEE_ENONE;
}
Esempio n. 14
0
/* retrieve the userData assigned to a connection */
EXPORT void *xbee_conGetData(struct xbee *xbee, struct xbee_con *con) {
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return NULL;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return NULL;
	if (!con) return NULL;
	
	/* check the connection */
	if (_xbee_conValidate(xbee, con, NULL)) return NULL;
	
	/* return the data */
	return con->userData;
}
Esempio n. 15
0
/* start a monitored thread. If it dies, it will be restarted
   the thread identification information will be stored in the thread parameter */
int _xbee_threadStartMonitored(struct xbee *xbee, xsys_thread *thread, void*(*start_routine)(void*), void *arg, char *funcName) {
	struct threadInfo *tinfo;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	
	if (!xbee_validate(xbee)) return XBEE_EINVAL;
	if (!thread)              return XBEE_EMISSINGPARAM;
	if (!start_routine)       return XBEE_EMISSINGPARAM;
	if (!arg)                 return XBEE_EMISSINGPARAM;
	if (!funcName)            return XBEE_EMISSINGPARAM;
	
	/* find out if we are already monitoring that function, and with the same argument */
	for (tinfo = NULL; (tinfo = ll_get_next(&xbee->threadList, tinfo)) != NULL;) {
		/* is that handle already being used? */
		if (tinfo->thread == thread) return XBEE_EINUSE;
		
		/* is that exact func/arg combo already being used? that would be a bit silly... */
		if (tinfo->start_routine == start_routine &&
				tinfo->arg == arg) {
			return XBEE_EEXISTS;
		}
	}
	
	/* create a new block */
	if ((tinfo = calloc(1, sizeof(struct threadInfo))) == NULL) {
		return XBEE_ENOMEM;
	}
	
	/* setup all the details */
	tinfo->funcName = funcName;
	tinfo->start_routine = start_routine;
	tinfo->arg = arg;
	tinfo->thread = thread;
	
	/* add it to the threadList */
	if (ll_add_tail(&xbee->threadList, tinfo)) {
		return XBEE_ELINKEDLIST;
	}
	
	/* and prod the monitor thread (who will start the thread for us! */
	xsys_sem_post(&xbee->semMonitor);
	
	return XBEE_ENONE;
}
Esempio n. 16
0
/* update the userData assigned to a connection */
EXPORT int xbee_conSetData(struct xbee *xbee, struct xbee_con *con, void *data) {
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!con) return XBEE_EMISSINGPARAM;
	
	/* check the connection */
	if (_xbee_conValidate(xbee, con, NULL)) return XBEE_EINVAL;
	
	/* update the userData */
	con->userData = data;
	return XBEE_ENONE;
}
Esempio n. 17
0
EXPORT xbee_err _xbee_logDev(const char *file, int line, const char *function, struct xbee *xbee, int minLevel, char *format, ...) {
	va_list ap;
	xbee_err ret;

	if (!xbee) return XBEE_EMISSINGPARAM;
#ifndef XBEE_DISABLE_STRICT_OBJECTS
	if (xbee_validate(xbee) != XBEE_ENONE) return XBEE_EINVAL;
#endif /* XBEE_DISABLE_STRICT_OBJECTS */
	if (!xbee->log) return XBEE_ENOTIMPLEMENTED;
	if (xbee_logTest(xbee->log->logLevel, minLevel)) return XBEE_ENONE;
	
	va_start(ap, format);
	ret = _xbee_logWrite(xbee->log, file, line, function, xbee, minLevel, "DEV:", format, ap);
	va_end(ap);
	
	return ret;
}
Esempio n. 18
0
/* get the current callback assigned to the connection */
EXPORT int xbee_conGetCallback(struct xbee *xbee, struct xbee_con *con, void **callback) {
	struct xbee_conType *conType;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!con) return XBEE_EMISSINGPARAM;
	if (!callback) return XBEE_EMISSINGPARAM;
	
	/* check the connection */
	if (_xbee_conValidate(xbee, con, &conType)) return XBEE_EINVAL;
	
	/* give the callback */
	*callback = con->callback;
	
	return XBEE_ENONE;
}
Esempio n. 19
0
/* get a list of connection types (ASCII strings)
   **retList is a single block of memory
     starting with an array of char*
     followed by a NULL
     followed by the '\0' terminated strings
   the length of the memory is returned so that the memory can later be realloc()ed or transmitted */
int _xbee_conGetTypeList(struct xbee *xbee, char ***retList, int *retLength) {
	int i;
	char **retL;
	char *d;
	int datalen;
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!xbee->mode) return XBEE_ENOMODE;
	
	/* calculate the size of the data, each conType requires one char*, and strlen + 1 bytes */
	datalen = 0;
	/* add up all of the string lengths (including '\0' termination) */
	for (i = 0; xbee->mode->conTypes[i].name; i++) {
		datalen += sizeof(char) * (strlen(xbee->mode->conTypes[i].name) + 1);
	}
	/* add a char* for each conType, and another for the NULL */
	datalen += sizeof(char *) * (i + 1);
	
	/* allocate the memory */
	if ((retL = calloc(1, datalen)) == NULL) return XBEE_ENOMEM;
	d = (char *)&(retL[i+1]);
	
	/* populate the memory */
	for (i = 0; xbee->mode->conTypes[i].name; i++) {
		strcpy(d, xbee->mode->conTypes[i].name);
		retL[i] = d;
		d = &(d[strlen(xbee->mode->conTypes[i].name) + 1]);
	}
	/* NULL terminate the array at the front */
	retL[i] = NULL;
	
	/* return the information */
	*retList = retL;
	if (retLength) *retLength = datalen;
	
	return 0;
}
Esempio n. 20
0
/* end a connection
   the userData parameter can be used to retrieve the data stored with the connection */
EXPORT int xbee_conEnd(struct xbee *xbee, struct xbee_con *con, void **userData) {
	struct xbee_conType *conType;
	struct xbee_pkt *pkt;
	int i;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!con) return XBEE_EMISSINGPARAM;
	
	/* check the connection */
	if (_xbee_conValidate(xbee, con, &conType)) return XBEE_EINVAL;
	
	/* remove the connection from the list */
	if (ll_ext_item(&(conType->conList), con)) return XBEE_EINVAL;
	
	/* chop up any queued packets */
	for (i = 0; (pkt = ll_ext_head(&(con->rxList))) != NULL; i++) {
		xbee_pktFree(pkt);
	}
	xbee_log(2,"Ended '%s' connection @ %p (destroyed %d packet%s)", conType->name, con, i, (i!=1)?"s":"");

	/* if the userData parameter is provided, then give the con's userData back to the caller */
	if (userData) *userData = con->userData;

	/* if there is a callback thread running, then kill it off */
	if (con->callbackRunning) {
		con->destroySelf = 1;
		xsys_sem_post(&con->callbackSem);
		
		/* inform the caller that we are waiting for the callback to complete */
		return XBEE_ECALLBACK;
	}

	/* it is only safe to call _xbee_conEnd2() once the callback thread has completed, this will finish tidying up the connection */
	return _xbee_conEnd2(xbee, con);
}
Esempio n. 21
0
/* convert a name into a connection ID
   this internal funtion can ignore the 'initialized' flag for connection types */
int _xbee_conTypeIdFromName(struct xbee *xbee, char *name, unsigned char *id, int ignoreInitialized) {
	int i;
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!xbee->mode) return XBEE_ENOMODE;
	if (!name) return XBEE_EMISSINGPARAM;
	
	/* find the connection type by name, case in-sensetive */
	for (i = 0; xbee->mode->conTypes[i].name; i++) {
		if (!ignoreInitialized && !xbee->mode->conTypes[i].initialized) continue;
		if (!strcasecmp(name, xbee->mode->conTypes[i].name)) {
			/* return the type ID */
			if (id) *id = i;
			return XBEE_ENONE;
		}
	}
	return XBEE_EUNKNOWN;
}
Esempio n. 22
0
/* validate that the given connection exists in the xbee instance
   can return the conType, or ignore of **conType = NULL */
int _xbee_conValidate(struct xbee *xbee, struct xbee_con *con, struct xbee_conType **conType) {
	int i;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!xbee->mode) return XBEE_ENOMODE;
	if (!con) return XBEE_EMISSINGPARAM;
	
	/* try to find the provided connection in any of the xbee's conTypes */
	for (i = 0; xbee->mode->conTypes[i].name; i++) {
		/* look for, and break if we find it */
		if (ll_get_item(&(xbee->mode->conTypes[i].conList), con)) break;
	}
	if (!xbee->mode->conTypes[i].name) {
		/* no connection was found */
		if (conType) *conType = NULL;
		return XBEE_EFAILED;
	}
	
	/* provide the conType to the caller */
	if (conType) *conType = &(xbee->mode->conTypes[i]);
	
	/* this mapping is implemented as an extension, therefore it is entirely optional! */
	if (xbee->f->conValidate) {
		int ret;
		/* call the conValidate extension */
		if ((ret = xbee->f->conValidate(xbee, con, conType)) != 0) {
			/* ret should be either 0 / XBEE_ESTALE */;
			return ret;
		}
	}
	
	return XBEE_ENONE;
}
Esempio n. 23
0
/* set the callback for a connection
   this function can provide the previously set callback, as well as assign a new one */
EXPORT int xbee_conAttachCallback(struct xbee *xbee, struct xbee_con *con, void(*callback)(struct xbee *xbee, struct xbee_con *con, struct xbee_pkt **pkt, void **userData), void **prevCallback) {
	struct xbee_conType *conType;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!con) return XBEE_EMISSINGPARAM;
	
	/* check the connection */
	if (_xbee_conValidate(xbee, con, &conType)) return XBEE_EINVAL;
	
	/* give the currently assigned callback */
	if (prevCallback) *prevCallback = con->callback;
	
	/* we don't need to kill the existing callback, because it is refreshed each time the callback function returns */
	
	/* assign the new callback */
	con->callback = callback;
	
	/* and if a callback was assigned, kick it off */
	if (callback) {
		xbee_log(5,"Attached callback to connection @ %p", con);
		/* but only kick it off if there are packets in the queue */
		if (ll_count_items(&con->rxList)) {
			xbee_log(5,"... and triggering callback due to packets in queue");
			xbee_triggerCallback(xbee, con);
		}
	} else {
		/* otherwise log that we disabled callbacks for this connection */
		xbee_log(5,"Detached callback from connection @ %p", con);
	}
	
	return XBEE_ENONE;
}
Esempio n. 24
0
/* retrieve a matching connection from the address information provided */
struct xbee_con *xbee_conFromAddress(struct xbee *xbee, struct xbee_conType *conType, struct xbee_conAddress *address) {
	struct xbee_con *con, *scon;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return NULL;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return NULL;
	if (!address) return NULL;
	if (!conType || !conType->initialized) return NULL;
	
	/* get the first connection, and return if there isn't one! */
	con = ll_get_head(&conType->conList);
	if (!con) return NULL;
	
	/* if both addresses are completely blank, just return the first connection (probably a local AT connection) */
	if ((!address->addr64_enabled && !address->addr16_enabled) &&
	    (!con->address.addr64_enabled && !con->address.addr16_enabled)) {
		return con;
	}
	
	scon = NULL;
	do {
		/* if both addresses have no 16 or 64-bit addressing information, match! */
		if ((!address->addr16_enabled && !con->address.addr16_enabled) &&
		    (!address->addr64_enabled && !con->address.addr64_enabled)) {
			goto got1;
		}

		/* check 64-bit addressing */
		if (address->addr64_enabled && con->address.addr64_enabled) {
			xbee_log(10,"Testing 64-bit address: 0x%02X%02X%02X%02X 0x%02X%02X%02X%02X", con->address.addr64[0],
			                                                                             con->address.addr64[1],
			                                                                             con->address.addr64[2],
			                                                                             con->address.addr64[3],
			                                                                             con->address.addr64[4],
			                                                                             con->address.addr64[5],
			                                                                             con->address.addr64[6],
			                                                                             con->address.addr64[7]);

			/* if 64-bit address matches, accept, else decline (don't even accept matching 16-bit address */
			if (!memcmp(address->addr64, con->address.addr64, 8)) {
				xbee_log(10,"    Success!");
				goto got1;
			}
		}

		/* check 16-bit addressing */
		if (address->addr16_enabled && con->address.addr16_enabled) {
			xbee_log(10,"Testing 16-bit address: 0x%02X%02X",  con->address.addr16[0], con->address.addr16[1]);
			/* if 16-bit address matches accept */
			if (!memcmp(address->addr16, con->address.addr16, 2)) {
				xbee_log(10,"    Success!");
				goto got1;
			}
		}

		/* nothing caused an 'accept', so try the next connection */
		continue; /* ############################################ */
		/* ###################################################### */

got1:
		/* if both connections have endpoints disabled, match! */
		if (!address->endpoints_enabled && !con->address.endpoints_enabled) goto got2;
		/* if both local endpoints match, match! */
		if (address->local_endpoint == con->address.local_endpoint) goto got2;

		/* nothing caused an 'accept', so try the next connection */
		continue; /* ############################################ */
		/* ###################################################### */

got2:
		/* if the connection is not sleeping, then we have our target!, otherwise continue the search */
		if (!con->sleeping) break;
		/* hold on to the last sleeping connection, just incase */
		scon = con;
	} while ((con = ll_get_next(&conType->conList, con)) != NULL);
	
	/* if we couldn't find a connection, return a sleeping connection (if any) */
	if (!con) return scon;
	return con;
}
Esempio n. 25
0
/* create a new connection based on the address information provided
   if a connection already exists with a matching address, *retCon points to it, and XBEE_EEXISTS is returned
   the userData provided is assigned to the connection immediately */
EXPORT int xbee_conNew(struct xbee *xbee, struct xbee_con **retCon, unsigned char id, struct xbee_conAddress *address, void *userData) {
	int ret;
	struct xbee_con *con;
	struct xbee_conType *conType;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!xbee->mode) return XBEE_ENOMODE;
	if (!retCon) return XBEE_EMISSINGPARAM;
	if (!address) return XBEE_EMISSINGPARAM;
	
	/* get the conType that is being requested */
	if (id >= xbee->mode->conTypeCount) return XBEE_EINVAL;
	conType = &(xbee->mode->conTypes[id]);
	
	/* check the addressing information */
	switch (conType->needsAddress) {
		/* don't care */
		case 0:
			break;
		
		/* need either */
		case 1:
			if (!address->addr16_enabled && !address->addr64_enabled) return XBEE_EINVAL;
			break;
		
		/* need 16-bit */
		case 2:
			if (!address->addr16_enabled) return XBEE_EINVAL;
			break;
		
		/* need 64-bit */
		case 3:
			if (!address->addr64_enabled) return XBEE_EINVAL;
			break;
		
		/* need both */
		case 4:
			if (!address->addr16_enabled || !address->addr64_enabled) return XBEE_EINVAL;
			break;
		
		/* not supported */
		default:
			xbee_log(1,"addressing mode %d is not supported", conType->needsAddress);
			return XBEE_EINVAL;
	}
	
	/* retrieve a connection if one aready exists, ignoring sleeping connections */
	if ((con = xbee_conFromAddress(xbee, conType, address)) != NULL && !con->sleeping) {
		*retCon = con;
		ret = XBEE_EEXISTS;
		goto done;
	}
	
	ret = XBEE_ENONE;
	/* allocate the memory */
	if ((con = calloc(1, sizeof(struct xbee_con))) == NULL) {
		ret = XBEE_ENOMEM;
		goto die1;
	}
	
	/* setup the connection info */
	con->conType = conType;
	memcpy(&con->address, address, sizeof(struct xbee_conAddress));
	con->userData = userData;
	ll_init(&con->rxList);
	xsys_sem_init(&con->callbackSem);
	xsys_mutex_init(&con->txMutex);

	/* this mapping is implemented as an extension, therefore it is entirely optional! */
	if (xbee->f->conNew) {
		int ret;
		if ((ret = xbee->f->conNew(xbee, retCon, id, address, userData)) != 0) {
			/* ret should be either 0 / XBEE_ESTALE */;
			return ret;
		}
	}
	
	/* once everything has been done, add it to the list (enable it) */
	ll_add_tail(&(con->conType->conList), con);
	*retCon = con;
	
	/* log the details */
	xbee_log(2,"Created new '%s' connection @ %p", conType->name, con);
	
	xbee_conLogAddress(xbee, address);

	goto done;
die1:
done:
	return ret;
}
Esempio n. 26
0
/* transmit a message on the provided connection
   this function takes the raw data and its length */
EXPORT int xbee_connTx(struct xbee *xbee, struct xbee_con *con, char *data, int length) {
	int ret = XBEE_ENONE;
	struct bufData *buf;
	struct xbee_conType *conType;
	int waitForAckEnabled;
	
	/* check parameters */
	if (!xbee) {
		if (!xbee_default) return XBEE_ENOXBEE;
		xbee = xbee_default;
	}
	if (!xbee_validate(xbee)) return XBEE_ENOXBEE;
	if (!con) return XBEE_EMISSINGPARAM;
	
	/* check the provided connection */
	if (_xbee_conValidate(xbee, con, &conType)) return XBEE_EINVAL;
	
	/* check that we are able to send the message,
	   if there is no xbee->f->connTx mapping, then we need a conType->txHandler */
	if (!conType->txHandler && !xbee->f->connTx) return XBEE_ECANTTX;
	
	/* allocate a buffer, 1 byte is already held within the bufData struct, and we don't send the trailing '\0' */
	if ((buf = calloc(1, sizeof(struct bufData) + (sizeof(unsigned char) * (length - 1)))) == NULL) {
		ret = XBEE_ENOMEM;
		goto die1;
	}
	
	/* populate the buffer */
	buf->len = length;
	memcpy(buf->buf, data, length);
	
	/* cache the value of waitForAck, because it may change halfway through! */
	waitForAckEnabled = con->options.waitForAck;
	
	/* if the connection has 'waitForAck' enabled, then we need to get a free FrameID that can be used */
	if (waitForAckEnabled) {
		/* if we are configured to wait for an Ack, then we need to lock down the connection */
		xbee_log(4,"Locking txMutex for con @ %p", con);
		xsys_mutex_lock(&con->txMutex);
		if ((con->frameID = xbee_frameIdGet(xbee, con)) == 0) {
			/* currently we don't inform the user (BAD), but this is unlikely unless you are communicating with >256 remote nodes */
			xbee_log(1,"No avaliable frame IDs... we can't validate delivery");
			xbee_log(4,"Unlocking txMutex for con @ %p (failed to get FrameID)", con);
			xsys_mutex_unlock(&con->txMutex);
		} else {
			/* mark the FrameID as present */
			con->frameID_enabled = 1;
		}
	}
	
	/* if there is a custom mapping for connTx, then the handlers are skipped (but can be called from within the mapping!) */
	if (!xbee->f->connTx) {
		struct bufData *oBuf;
		oBuf = buf;
		
		/* execute the conType handler, this should take the data provided, and convert it into an XBee formatted block of data
		   this is given, and returned via the 'buf' argument */
		xbee_log(6,"Executing handler (%s)...", conType->txHandler->handlerName);
		if ((ret = conType->txHandler->handler(xbee, conType->txHandler, 0, &buf, con, NULL)) != XBEE_ENONE) goto die2;
		
		/* a bit of sanity checking... */
		if (!buf || buf == oBuf) {
			ret = XBEE_EUNKNOWN;
			goto die2;
		}
		free(oBuf);
	}
	
	if (!xbee->f->connTx) {
		/* if there is no connTx mapped, then add the packet to libxbee's txlist, and prod the tx thread */
		ll_add_tail(&xbee->txList, buf);
		xsys_sem_post(&xbee->txSem);
	} else {
		/* same as before, if a mapping is registered, then the packet isn't queued for Tx, at least not here
		   instead we execute the mapped function */
		if ((ret = xbee->f->connTx(xbee, con, buf)) != XBEE_ENONE) goto die2;
	}
	
	/* if we should be waiting for an Ack, we now need to wait */
	if (waitForAckEnabled && con->frameID) {
		xbee_log(4,"Waiting for txSem for con @ %p", con);
		/* the wait occurs inside xbee_frameIdGetACK() */
		ret = xbee_frameIdGetACK(xbee, con, con->frameID);
		if (ret) xbee_log(4,"--- xbee_frameIdGetACK() returned: %d",ret);
		/* unlock the connection so that other transmitters may follow on */
		xbee_log(4,"Unlocking txMutex for con @ %p", con);
		xsys_mutex_unlock(&con->txMutex);
	}
	/* disable the frameID */
	con->frameID_enabled = 0;
	
	goto done;
die2:
	free(buf);
die1:
done:
	return ret;
}