Exemplo n.º 1
0
xbee_err xbee_rx(struct xbee *xbee, int *restart, void *arg) {
	xbee_err ret;
	struct xbee_rxInfo *info;
	struct xbee_tbuf *buf;
	
	info = arg;
	if (!info->bufList || !info->ioFunc) {
		*restart = 0;
		return XBEE_EINVAL;
	}
	
	while (!xbee->die) {
		buf = NULL;
		if ((ret = info->ioFunc(xbee, info->ioArg, &buf)) != XBEE_ENONE) {
			if (ret == XBEE_EEOF) {
				*restart = 0;
				if (info->eofCallback) info->eofCallback(xbee, info);
				return XBEE_EEOF;
			} else if (ret == XBEE_ESHUTDOWN && xbee->die) {
				break;
			}
			xbee_log(1, "rx() returned %d (%s)... retrying in 10 ms", ret, xbee_errorToStr(ret));
			usleep(10000); /* 10 ms */
			continue;
		}

#ifndef XBEE_DISABLE_LOGGING
#ifndef XBEE_LOG_NO_RX
		if (xbee->log->enable_rx) {
			/* format: tx[0x0000000000000000] */
			char label[42]; /* enough space for a 64-bit pointer and ANSI color codes */
#ifndef XBEE_LOG_NO_COLOR
			if (xbee->log->use_color) {
				snprintf(label, sizeof(label), "Rx[%c[%dm%p%c[0m]", 27, 30 + info->logColor, info,  27);
			} else {
#endif /* !XBEE_LOG_NO_COLOR */
				snprintf(label, sizeof(label), "Rx[%p]", info);
#ifndef XBEE_LOG_NO_COLOR
			}
#endif /* !XBEE_LOG_NO_COLOR */
			xbee_logData(25, label, buf->data, buf->len);
		}
#endif /* !XBEE_LOG_NO_RX */
#endif /* !XBEE_DISABLE_LOGGING */
		
		if (xbee_ll_add_tail(info->bufList, buf) != XBEE_ENONE) return XBEE_ELINKEDLIST;
		buf = NULL;
		if (xsys_sem_post(&info->sem) != 0) return XBEE_ESEMAPHORE;
	}
	
	return XBEE_ESHUTDOWN;
}
Exemplo n.º 2
0
xbee_err xbee_free(struct xbee *xbee) {
	int i;

	xbee_ll_ext_item(xbeeList, xbee);
	xbee->die = 1;
	
	if (xbee->iface.rx) {
		xsys_sem_post(&xbee->iface.rx->sem);
	}
	if (xbee->iface.tx) {
		xsys_sem_post(&xbee->iface.tx->sem);
	}
	
	/* sleep for 4 seconds because:
	     the rx thread should timeout every 2-ish econds
	     the rxHandler thread will need to run round one more time to clean up
	     the tx thread will need to run round one more time to clean up */
	for (i = 0; i < 4; i++) usleep(1000000);
	
	xbee_threadDestroyMine(xbee);
	
	if (xbee->netInfo) xbee_netStop(xbee);
	
	if (xbee->mode && xbee->mode->shutdown) xbee->mode->shutdown(xbee);
	
	xbee_modeCleanup(xbee->iface.conTypes);
	xbee_rxFree(xbee->iface.rx);
	xbee_txFree(xbee->iface.tx);
#ifndef XBEE_DISABLE_LOGGING
	xbee_logFree(xbee->log);
#endif /* !XBEE_DISABLE_LOGGING */
	xbee_frameBlockFree(xbee->fBlock);
	
	free(xbee);
	
	return XBEE_ENONE;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
xbee_err xbee_framePost(struct xbee_frameBlock *fBlock, unsigned char frameId, unsigned char retVal) {
	xbee_err ret;
	struct xbee_frame *frame;
	int i;
	
	if (!fBlock) return XBEE_EMISSINGPARAM;
	if (frameId == 0) return XBEE_ENONE;
	
	xbee_mutex_lock(&fBlock->mutex);

	frame = NULL;
	for (i = 0; i < fBlock->numFrames; i++) {
		if (fBlock->frame[i].id != frameId) continue;

		if (fBlock->frame[i].status != 0) {
			frame = &fBlock->frame[i];
		}
		
		break;
	}

	if (!frame) {
		ret = XBEE_EINVAL;
	} else if (frame->con && (frame->status & XBEE_FRAME_STATUS_WAITING)) {
		ret = XBEE_ENONE;
		frame->status |= XBEE_FRAME_STATUS_COMPLETE;
		frame->retVal = retVal;
		xsys_sem_post(&frame->sem);
	} else {
		if (!(frame->status & XBEE_FRAME_STATUS_ABANDONED)) {
			ret = XBEE_ETIMEOUT;
		}
		if (frame->con) {
			frame->con->frameId = 0;
			frame->con = NULL;
		}
		frame->status = 0;
	}

	xbee_mutex_unlock(&fBlock->mutex);
	
	return ret;
}
Exemplo n.º 5
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);
}
Exemplo n.º 6
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;
}