Ejemplo n.º 1
0
/* recv_fsm
 *
 * Attempt to process some data from the buffer located at 'data'.
 *
 * If a command is succcessfully read, then this returns the number of bytes
 * consumed from the buffer. If a partial command is present in the buffer,
 * but not enough to process yet, then this will return 0; the invoking
 * function should call it later when more data is available. If an error
 * occurs such that no further data can be handled from the connection, then
 * this will call close_conn on the connection and return -1.
 */
static int recv_fsm(struct tcp_pcb *pcb, uint8_t * data, int len) {
	uint8_t cmd = *data;
	int npoints;

	switch (ps_state) {
	case MAIN:
		switch (cmd) {
		case 'p':
			/* Prepare stream. */
			if (dac_prepare() < 0) {
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);
			} else {
				return send_resp(pcb, RESP_ACK, cmd, 1);
			}

		case 'b':
			/* Make sure we have all of this packet... */
			if (len < sizeof(struct begin_command))
				return 0;

			struct begin_command *bc = (struct begin_command *)data;

			if (bc->point_rate > DAC_MAX_POINT_RATE)
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);

// XXX			set_low_water_mark(bc->low_water_mark);
			dac_set_rate(bc->point_rate);
			dac_start();

			return send_resp(pcb, RESP_ACK, cmd,
					 sizeof(struct begin_command));

		case 'u':
			/* Update and Begin use the same packet format */
			if (len < sizeof(struct begin_command))
				return 0;

			struct begin_command *uc = (struct begin_command *)data;

			if (uc->point_rate > DAC_MAX_POINT_RATE)
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);

			dac_set_rate(uc->point_rate);
// XXX			set_low_water_mark(uc->low_water_mark);

			return send_resp(pcb, RESP_ACK, cmd, 
					 sizeof(struct begin_command));

		case 'q':
			if (len < sizeof(struct queue_command))
				return 0;

			struct queue_command *qc = (struct queue_command *)data;

			if (qc->point_rate > DAC_MAX_POINT_RATE)
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);

			dac_rate_queue(qc->point_rate);

			return send_resp(pcb, RESP_ACK, cmd, 
					 sizeof(struct queue_command));

		case 'd':
			/* Data: switch into the DATA state to start reading
			 * points into the buffer. */
			if (len < sizeof(struct data_command))
				return 0;

			struct data_command *h = (struct data_command *) data;

			if (h->npoints) {
				ps_state = DATA;
				ps_pointsleft = h->npoints;

				/* We'll send a response once we've read all
				 * of the data. */
				return sizeof(struct data_command);
			} else {
				/* 0-length data packets are legit. */
				return send_resp(pcb, RESP_ACK, cmd,
					sizeof(struct data_command));
			}

		case 's':
			/* Stop */
			if (dac_get_state() == DAC_IDLE) {
				return send_resp(pcb, RESP_NAK_INVL, cmd, 1);
			} else {
				dac_stop(0);
				return send_resp(pcb, RESP_ACK, cmd, 1);
			}

		case 0:
		case 0xFF:
			/* Emergency-stop. */
			le_estop(ESTOP_PACKET);
			return send_resp(pcb, RESP_ACK, cmd, 1);

		case 'c':
			/* Clear e-stop. */
			le_estop_clear(ESTOP_CLEAR_ALL);
			if (le_get_state() == LIGHTENGINE_READY)
				return send_resp(pcb, RESP_ACK, cmd, 1);
			else
				return send_resp(pcb, RESP_NAK_ESTOP, cmd, 1);

		case '?':
			/* Ping */
			return send_resp(pcb, RESP_ACK, cmd, 1);

		default:
			outputf("unknown cmd 0x%02x", cmd);
			return close_conn(pcb, CONNCLOSED_UNKNOWNCMD, -1);
		}

		return -1;

	case DATA:
		ASSERT_NOT_EQUAL(ps_pointsleft, 0);

		/* We can only write a complete point at a time. */
		if (len < sizeof(struct dac_point))
			return 0;

		/* How many bytes of data is it our business to write? */
		npoints = len / sizeof(struct dac_point);
		if (npoints > ps_pointsleft)
			npoints = ps_pointsleft;

		/* How much do we have room for now? Note that dac_prepare
		 * is a ring buffer, so it's OK if it returns less than the
		 * number of points we have ready for it. We'll just have
		 * the FSM invoke us again. */
		int nready = dac_request();
		packed_point_t *addr = dac_request_addr();

		/* On the other hand, if the DAC isn't ready for *any* data,
		 * then ignore the rest of this write command and NAK when
		 * it's over. The FSM will take care of us... */
		if (nready <= 0) {
			if (nready == 0) {
				outputf("overflow: wanted to write %d", npoints);
			} else {
				outputf("underflow: pl %d np %d r %d", ps_pointsleft, npoints, nready);
			}
			ps_state = DATA_ABORTING;

			/* Danger: goto. This could probably be structured
			 * better... */
			goto handle_aborted_data;
		}

		if (npoints > nready)
			npoints = nready;

		dac_point_t *pdata = (dac_point_t *)data;

		int i;
		for (i = 0; i < npoints; i++) {
			dac_pack_point(addr + i, pdata + i);
		}

		/* Let the DAC know we've given it more data */
		dac_advance(npoints);

		ps_pointsleft -= npoints;

		if (!ps_pointsleft) {
			ps_state = MAIN;
			return send_resp(pcb, RESP_ACK, 'd',
					 npoints * sizeof(struct dac_point));
		} else {
			return (npoints * sizeof(struct dac_point));
		}

	case DATA_ABORTING:
		ASSERT_NOT_EQUAL(ps_pointsleft, 0);

		/* We can only consume a complete point at a time. */
		if (len < sizeof(struct dac_point))
			return 0;

		/* How many points do we have? */
		npoints = len / sizeof(struct dac_point);
		if (npoints > ps_pointsleft)
			npoints = ps_pointsleft;

handle_aborted_data:
		ps_pointsleft -= npoints;

		if (!ps_pointsleft) {
			ps_state = MAIN;
			return send_resp(pcb, RESP_NAK_INVL, 'd',
					 npoints * sizeof(struct dac_point));
		} else {
			return (npoints * sizeof(struct dac_point));
		}

	default:
		break;
	}

	panic("invalid state in recv_dfa");
	return -1;
}
Ejemplo n.º 2
0
void playback_refill() {
	dac_point_t *ptr = 0;
	int i;

	int dlen = dac_request(&ptr);

	/* Have we underflowed? */
	if (dlen < 0) {
		if (le_get_state() != LIGHTENGINE_READY)
			return;

		outputf("*U*");
		dac_prepare();
		return;
	}

	/* If we don't have any more room... */
	if (dlen == 0) {
		if (dac_get_state() == DAC_PREPARED)
			dac_start();
		return;
	}

	switch (playback_src) {
	case SRC_ILDAPLAYER:
		if (!(playback_source_flags & ILDA_PLAYER_PLAYING))
			break;

		outputf("%d", dlen);

		i = ilda_read_points(dlen, ptr);

		if (i < 0) {
			outputf("err: %d", i);
			playback_source_flags &= ~ILDA_PLAYER_PLAYING;
		} else if (i == 0) {
			ilda_reset_file();

			if (playback_source_flags & ILDA_PLAYER_REPEAT) {
				outputf("rep");
			} else {
				outputf("done");

				/* If the whole file didn't fit in the
				 * buffer, we may have to start it now. */
				dlen = 0;

				playback_source_flags &= ~ILDA_PLAYER_PLAYING;
			}
		} else {
			dac_advance(i);
		}

		break;
	default:
		panic("bad playback source");
	}

	/* If the buffer is nearly full, start it up */
	if (dlen < 100 && dac_get_state() == DAC_PREPARED)
		dac_start();
}