Esempio n. 1
0
/**
 * When a frame is received, cast it to a csp_packet
 * and send it directly to the CSP new packet function.
 * Context: ISR only
 * @param frame
 */
void csp_i2c_rx(i2c_frame_t * frame, void * pxTaskWoken) {

	static csp_packet_t * packet;

	/* Validate input */
	if (frame == NULL)
		return;

	if ((frame->len < 4) || (frame->len > I2C_MTU)) {
		csp_if_i2c.frame++;
		csp_buffer_free_isr(frame);
		return;
	}

	/* Strip the CSP header off the length field before converting to CSP packet */
	frame->len -= sizeof(csp_id_t);

	/* Convert the packet from network to host order */
	packet = (csp_packet_t *) frame;
	packet->id.ext = csp_ntoh32(packet->id.ext);

	/* Receive the packet in CSP */
	csp_new_packet(packet, &csp_if_i2c, pxTaskWoken);

}
Esempio n. 2
0
void csp_new_packet(csp_packet_t * packet, csp_iface_t * interface, CSP_BASE_TYPE * pxTaskWoken) {

    int result, fifo;

    if (packet == NULL) {
        csp_log_warn("csp_new packet called with NULL packet\r\n");
        return;
    } else if (interface == NULL) {
        csp_log_warn("csp_new packet called with NULL interface\r\n");
        if (pxTaskWoken == NULL)
            csp_buffer_free(packet);
        else
            csp_buffer_free_isr(packet);
        return;
    }

    csp_route_queue_t queue_element;
    queue_element.interface = interface;
    queue_element.packet = packet;

    fifo = csp_route_get_fifo(packet->id.pri);
    result = csp_route_enqueue(router_input_fifo[fifo], &queue_element, 0, pxTaskWoken);

    if (result != CSP_ERR_NONE) {
        csp_log_warn("ERROR: Routing input FIFO is FULL. Dropping packet.\r\n");
        interface->drop++;
        if (pxTaskWoken == NULL)
            csp_buffer_free(packet);
        else
            csp_buffer_free_isr(packet);
    } else {
        interface->rx++;
        interface->rxbytes += packet->length;
    }

}
Esempio n. 3
0
/** pbuf_free
 * Free buffer element and associated CSP packet buffer element.
 * @param buf Buffer element to free
 * @return 0 on success, -1 on error.
 */
static int pbuf_free(pbuf_element_t *buf, CSP_BASE_TYPE *task_woken) {
	int32_t refcount;

	/* Lock packet buffer */
	if (task_woken == NULL)
		CSP_ENTER_CRITICAL(pbuf_sem);

	/* Free CSP packet */
	if (buf->packet != NULL) {

		/* first check to see if the buffer was already free. This could happen
           if the top level timeout occurred already. If so, no need to free it
           again */
		refcount = csp_buffer_get_refcount(buf->packet);
		if (refcount > 0) {

			if (task_woken == NULL) {
				csp_buffer_free(buf->packet);
			} else {
				csp_buffer_free_isr(buf->packet);
			}

		}
		buf->packet = NULL;
	}

	/* Mark buffer element free */
	buf->state = BUF_FREE;
	buf->rx_count = 0;
	buf->tx_count = 0;
	buf->cfpid = 0;
	buf->last_used = 0;
	buf->remain = 0;

	/* Unlock packet buffer */
	if (task_woken == NULL)
		CSP_EXIT_CRITICAL(pbuf_sem);

	return CSP_ERR_NONE;

}
Esempio n. 4
0
/** pbuf_free_locked
 * Free buffer element and associated CSP packet buffer element with pbuf list locked.
 * @param buf Buffer element to free
 * @param free_packet true if the associated packet should be freed as well
 * @return 0 on success, -1 on error.
 */
static int pbuf_free_locked(pbuf_element_t *buf, CSP_BASE_TYPE *task_woken, bool free_packet) {

	/* Free CSP packet */
	if (buf->packet != NULL && free_packet) {
		if (task_woken == NULL) {
			csp_buffer_free(buf->packet);
		} else {
			csp_buffer_free_isr(buf->packet);
		}
	}

	/* Mark buffer element free */
	buf->packet = NULL;
	buf->state = BUF_FREE;
	buf->rx_count = 0;
	buf->tx_count = 0;
	buf->cfpid = 0;
	buf->last_used = 0;
	buf->remain = 0;

	return CSP_ERR_NONE;

}
Esempio n. 5
0
File: pca9665.c Progetto: lirihe/arm
/**
 * Interrupt service routine
 * Basically handles the entire protocol
 */
void __attribute__((noinline)) pca9665_dsr(portBASE_TYPE * task_woken) {

	static int handle, len;
	static uint8_t state;
	static uint8_t dest;

	/* Loop through number of devices */
	for (handle = 0; handle < pca9665_device_count; handle++) {

		/* Check for interrupt flag in device status register */
		if (!(pca9665_read_reg(handle, I2CCON) & CON_SI))
			continue;

		/* We have an interrupt, read the status register */
		state = pca9665_read_reg(handle, I2CSTA);

		/* The I2C driver is one _big_ state-machine */
		driver_debug(DEBUG_I2C, "I2C ISR %u %x\n\r", handle, state);
		switch (state) {

		/**
		 * MASTER IRQ's
		 */

		/* START: is the first ISR that appears for outgoing frames */
		case STA_M_REPEATED_START_SENDT:
		case STA_M_START_SENDT:

			/* Mark as busy, so start flag is not sent from task context while transmission is active */
			device[handle].is_busy = 1;

			/* If this is the beginning of a new frame, dequeue */
			if (device[handle].tx.frame == NULL && device[handle].rx.frame == NULL) {

				/* Try do dequeue element, if it fails, stop transmission */
				xQueueReceiveFromISR(device[handle].tx.queue, &device[handle].tx.frame, task_woken);
				if (device[handle].tx.frame == NULL) {
					pca9665_try_tx_from_isr(handle, task_woken);
					break;
				}

				/* If TX len > 0, go for master transmit */
				if (device[handle].tx.frame->len) {
					device[handle].mode = DEVICE_MODE_M_T;
					device[handle].tx.next_byte = 0;

				/* If TX len == 0 and RX len > 0, go for master receive */
				} else if (device[handle].tx.frame->len_rx) {
					device[handle].mode = DEVICE_MODE_M_R;
					device[handle].rx.frame = device[handle].tx.frame;
					device[handle].tx.frame = NULL;
					device[handle].rx.frame->len = device[handle].rx.frame->len_rx;
					device[handle].rx.next_byte = 0;

				/* Well, this should not happen */
				} else {
					csp_buffer_free_isr(device[handle].tx.frame);
					device[handle].tx.frame = NULL;
					pca9665_try_tx_from_isr(handle, task_woken);
					break;
				}

			}

			/* If mode is master receiver then set the read-bit in the address field */
			if (device[handle].mode == DEVICE_MODE_M_R) {

				dest = (device[handle].rx.frame->dest << 1) | 0x01;
				device[handle].rx.next_byte = 0;

				/* Do first part of frame here */
				if (device[handle].rx.frame->len > PCA9665_MAX_BUF) {
					pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
				} else {
					pca9665_write_reg(handle, I2CCOUNT, device[handle].rx.frame->len | 0x80);
				}

				pca9665_write_data(handle, &dest, 1);

			} else {

				dest = device[handle].tx.frame->dest << 1;
				device[handle].tx.next_byte = 0;

				/* Do first part of frame here */
				if (device[handle].tx.frame->len + 1 > PCA9665_MAX_BUF) {
					pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
					pca9665_write_data(handle, &dest, 1);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	PCA9665_MAX_BUF - 1);
					device[handle].tx.next_byte += PCA9665_MAX_BUF - 1;
				} else {
					pca9665_write_reg(handle, I2CCOUNT, device[handle].tx.frame->len + 1);
					pca9665_write_data(handle, &dest, 1);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	device[handle].tx.frame->len);
					device[handle].tx.next_byte += device[handle].tx.frame->len;
				}
			}

			/* Let the hardware continue */
			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
			break;

		/* WRITE ACK: A node is ready to be written to */
		case STA_M_SLAW_SENDT_ACKED:
		case STA_M_DATA_SENDT_ACKED:

			/* Safety first */
			if (device[handle].tx.frame == NULL)
				goto isr_error;

			/* Calculate remaining length */
			len = device[handle].tx.frame->len - device[handle].tx.next_byte;

			/* Transmit next chunk */
			if (len > 0) {

				if (len > PCA9665_MAX_BUF) {
					pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	PCA9665_MAX_BUF);
					device[handle].tx.next_byte += PCA9665_MAX_BUF;
				} else {
					pca9665_write_reg(handle, I2CCOUNT, len);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	len);
					device[handle].tx.next_byte += len;
				}

				pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
				break;

			/* Or, Change from master transmit, to master read if wanted */
			} else if (device[handle].tx.frame->len_rx) {

				device[handle].mode = DEVICE_MODE_M_R;
				device[handle].rx.frame = device[handle].tx.frame;
				device[handle].tx.frame = NULL;
				device[handle].rx.frame->len = device[handle].rx.frame->len_rx;

				/* We need to send a repeated start now! */
				pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA | CON_STA);
				break;

			/* Or, We are done */
			} else {
				csp_buffer_free_isr(device[handle].tx.frame);
				device[handle].tx.frame = NULL;
				pca9665_try_tx_from_isr(handle, task_woken);
			}

			break;

		/* WRITE ERROR: A write has failed */
		case STA_M_SLAW_SENDT_NACKED:
		case STA_M_DATA_SENDT_LAST_NACKED:

			if (device[handle].tx.frame != NULL) {
				driver_debug(DEBUG_I2C, "I2C SLA+W NACK: 0x%02"PRIx8"\n\r", device[handle].tx.frame->dest);
				csp_buffer_free_isr(device[handle].tx.frame);
				device[handle].tx.frame = NULL;
			}

			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/* ARBITRATION LOST: Start condition failed */
		case STA_M_ARBITRATION_LOST:

			/* Restart transmission by resetting next_byte and preserving tx_frame pointer */
			device[handle].tx.next_byte = 0;
			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/* READ ACK: A node is ready to be read from */
		case STA_M_SLAR_SENT_ACKED:
		case STA_M_DATA_RECEIVED_ACKED:
		case STA_M_DATA_RECEIVED_NACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			if (device[handle].rx.queue == NULL)
				goto isr_error;

			pca9665_read_data_to_buffer(handle);
			int remaining = device[handle].rx.frame->len - device[handle].rx.next_byte;
			driver_debug(DEBUG_I2C, "RX: Remaining %u\r\n", remaining);

			/* If no more to receive */
			if (remaining == 0) {
				if (xQueueSendToBackFromISR(device[handle].rx.queue, &device[handle].rx.frame, task_woken)	== pdFALSE) {
					driver_debug(DEBUG_I2C, "I2C rx queue full - freeing\n\r");
					csp_buffer_free_isr(device[handle].rx.frame);
				}
				device[handle].rx.frame = NULL;
				pca9665_try_tx_from_isr(handle, task_woken);
				break;
			}

			/* If more than a full PCA9665 buffer remains */
			if (remaining > PCA9665_MAX_BUF) {
				pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);

			/* Otherwise, this is the last bit, set NACK on final slave read */
			} else {
				pca9665_write_reg(handle, I2CCOUNT, remaining | 0x80);
			}

			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
			break;

		/* READ ERROR: A read has failed */
		case STA_M_SLAR_SENT_NACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			driver_debug(DEBUG_I2C, "I2C SLA+R nacked\n\r");
			csp_buffer_free_isr(device[handle].rx.frame);
			device[handle].rx.frame = NULL;

			/* Start up again */
			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/**
		 * SLAVE RECEIVER BUFFERED MODE
		 */

		/* START: Lost the arbitration and is addressed as a slave receiver */
		case STA_S_ARB_LOST_SLAW_RECEIVED:
		case STA_S_ARB_LOST_GC_RECEIVED:

			/* Preserve TX frame active, so the START flag will be re-set when the
			 * reception is completed
			 */

			/* Deliberate Fallthrough */

		/* START: Addressed as a slave receiver */
		case STA_S_SLAW_RECEIVED_ACKED:
		case STA_S_GC_RECEIVED:

			/* Check if RX frame was started */
			if (device[handle].rx.frame != NULL)
				goto isr_error;

			/* Allocate new frame */
			device[handle].rx.frame = csp_buffer_get_isr(I2C_MTU);
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			device[handle].is_busy = 1;
			device[handle].rx.next_byte = 0;
			device[handle].rx.frame->len = 0;
			device[handle].rx.frame->dest = device[handle].slave_addr;
			pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
			break;

		/* READ: Data received. */
		case STA_S_DATA_RECEIVED_SLA_ACKED:
		case STA_S_DATA_RECEIVED_GC_ACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			/* Receive data, if any */
			pca9665_read_data_to_buffer(handle);

			/* Limit incoming bytes */
			pca9665_write_reg(handle, I2CCOUNT, (device[handle].rx.next_byte + PCA9665_MAX_BUF > I2C_MTU) ? (I2C_MTU - device[handle].rx.next_byte) | 0x80 : PCA9665_MAX_BUF);
			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);

			break;

		/* STOP or NACK: No more data to receive */
		case STA_S_STOP_REP_RECEIVED:
		case STA_S_DATA_RECEIVED_SLA_NACKED:
		case STA_S_DATA_RECEIVED_GC_NACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			/* Receive data, if any */
			pca9665_read_data_to_buffer(handle);

			/* Queue up frame */
			device[handle].rx.frame->len = device[handle].rx.next_byte;
			if (device[handle].rx.queue != NULL) {
				if (xQueueSendToBackFromISR(device[handle].rx.queue, &device[handle].rx.frame, task_woken)	== pdFALSE) {
					driver_debug(DEBUG_I2C, "I2C RX queue full\n\r");
					csp_buffer_free_isr(device[handle].rx.frame);
				}
			} else if (device[handle].callback != NULL) {
				device[handle].callback(device[handle].rx.frame, task_woken);
			} else {
				csp_buffer_free_isr(device[handle].rx.frame);
			}

			/* The frame has been freed now */
			device[handle].rx.frame = NULL;

			/* Set back to master mode */
			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/**
		 * Other IRQ's, typically indicates a hardware or protcol error
		 * The IDLE status is considered an error if asserted at the same time as the Serial Interrupt flag
		 */
		case STA_IDLE:
		default:

isr_error:
			/* Soft reset the device */
			driver_debug(DEBUG_I2C, "I2C ERR 0x%02X\n\r", state);
			pca9665_init_registers(handle);

			/* Clean up RX */
			if (device[handle].rx.frame != NULL) {
				csp_buffer_free_isr(device[handle].rx.frame);
				device[handle].rx.frame = NULL;
			}

			/* Clean up TX */
			if (device[handle].tx.frame != NULL) {
				csp_buffer_free_isr(device[handle].tx.frame);
				device[handle].tx.frame = NULL;
			}

			/* Start up again */
			pca9665_try_tx_from_isr(handle, task_woken);

			break;
		}

	} /**< END Switch/Case */

}