/**
 * \file
 *
 * \brief FreeRTOS Peripheral Control API For the TWI
 *
 * Copyright (c) 2012 Atmel Corporation. All rights reserved.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 *    Atmel microcontroller product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \asf_license_stop
 *
 */

/* Standard includes. */
#include <string.h>

/* ASF includes. */
#include "twi_master.h"
#include "freertos_twi_master.h"
#include "freertos_peripheral_control_private.h"

/* Every bit in the interrupt mask. */
#define MASK_ALL_INTERRUPTS     (0xffffffffUL)

/* Interrupts that are enabled to catch error conditions on the bus. */
#define SR_ERROR_INTERRUPTS     (TWI_SR_NACK | TWI_SR_ARBLST | TWI_SR_OVRE)
#define IER_ERROR_INTERRUPTS    (TWI_IER_NACK | TWI_IER_ARBLST | TWI_IER_OVRE)

/* Work out how many TWI ports with PDC supported are present. */
#if defined(PDC_TWI4)
	#define MAX_TWIS                                (5)
#elif defined(PDC_TWI3)
	#define MAX_TWIS                                (4)
#elif defined(PDC_TWI2)
	#define MAX_TWIS                                (3)
#elif defined(PDC_TWI1)
	#define MAX_TWIS                                (2)
#elif defined(PDC_TWI0)
	#define MAX_TWIS                                (1)
#elif defined(PDC_TWI)
	#define MAX_TWIS                                (1)
#else
	#error No TWI peripherals with PDC support defined
#endif

/* A common interrupt handler definition used by all the TWI peripherals. */
static void local_twi_handler(const portBASE_TYPE twi_index);

/* Structures to manage the DMA control for both Rx and Tx transactions. */
static freertos_dma_event_control_t tx_dma_control[MAX_TWIS];
static freertos_dma_event_control_t rx_dma_control[MAX_TWIS];

/* Used to detect the init function being called after any part of the DMA
control structure has already been initialilsed - indicating an error
condition as init should only be called once per port. */
static const freertos_dma_event_control_t null_dma_control = {NULL, NULL};

/* Create an array that holds the information required about each defined TWI
 * peripheral. */
static const freertos_pdc_peripheral_parameters_t all_twi_definitions[MAX_TWIS] = {
	/* Chips with a single TWI port might define TWI only.  Chips with multiple
	TWI	ports defined the first TWI peripheral as TWI0. */
#if defined(TWI)
	{TWI, PDC_TWI, ID_TWI, TWI_IRQn},
#else
	{TWI0, PDC_TWI0, ID_TWI0, TWI0_IRQn},
#endif

#if MAX_TWIS > 1
	{TWI1, PDC_TWI1, ID_TWI1, TWI1_IRQn},
#endif
#if MAX_TWIS > 2
	{TWI2, PDC_TWI2, ID_TWI2, TWI2_IRQn},
#endif
#if MAX_TWIS > 3
	{TWI3, PDC_TWI3, ID_TWI3, TWI3_IRQn},
#endif
#if MAX_TWIS > 4
	{TWI4, PDC_TWI4, ID_TWI4, TWI4_IRQn},
#endif
};

/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initializes the FreeRTOS ASF TWI (I2C) master driver for the specified
 * TWI port.
 *
 * freertos_twi_master_init() is an ASF specific FreeRTOS driver function.  It
 * must be called before any other ASF specific FreeRTOS driver functions
 * attempt to access the same TWI port.
 *
 * If freertos_driver_parameters->operation_mode equals TWI_I2C_MASTER then
 * freertos_twi_master_init() will configure the TWI port for master mode
 * operation and enable the peripheral.  If
 * freertos_driver_parameters->operation_mode equals any other value then
 * freertos_twi_master_init() will not take any action.
 *
 * Other ASF TWI functions can be called after freertos_twi_master_init() has
 * completed successfully.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * This driver is provided with an application note, and an example project that
 * demonstrates the use of this function.
 *
 * \param p_twi    The twi peripheral being initialized.
 * \param freertos_driver_parameters    Defines the driver behavior.  See the
 *    freertos_peripheral_options_t documentation, and the application note that
 *    accompanies the ASF specific FreeRTOS functions.
 *
 * \return If the initialization completes successfully then a handle that can
 *     be used with FreeRTOS TWI read and write functions is returned.  If
 *     the initialisation fails then NULL is returned.
 */
freertos_twi_if freertos_twi_master_init(Twi *p_twi,
		const freertos_peripheral_options_t *const freertos_driver_parameters)
{
	portBASE_TYPE twi_index;
	bool is_valid_operating_mode;
	freertos_twi_if return_value;
	const enum peripheral_operation_mode valid_operating_modes[] = {TWI_I2C_MASTER};

	/* Find the index into the all_twi_definitions array that holds details of
	the p_twi peripheral. */
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) p_twi);

	/* Check the requested operating mode is valid for the peripheral. */
	is_valid_operating_mode = check_requested_operating_mode(
			freertos_driver_parameters->operation_mode,
			valid_operating_modes,
			sizeof(valid_operating_modes) /
			sizeof(enum peripheral_operation_mode));

	/* Don't do anything unless a valid p_twi pointer was used, and a valid
	operating mode was requested. */
	if ((twi_index < MAX_TWIS) && (is_valid_operating_mode == true)) {
		/* This function must be called exactly once per supported twi.  Check
		it has not been called	before. */
		configASSERT(memcmp((void *)&(tx_dma_control[twi_index]),
				&null_dma_control,
				sizeof(null_dma_control)) == 0);
		configASSERT(memcmp((void *)&(rx_dma_control[twi_index]),
				&null_dma_control,
				sizeof(null_dma_control)) == 0);

		/* Enable the peripheral's clock. */
		pmc_enable_periph_clk(
				all_twi_definitions[twi_index].peripheral_id);

		/* Ensure everything is disabled before configuration. */
		pdc_disable_transfer(
				all_twi_definitions[twi_index].pdc_base_address,
				(PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS));
		twi_disable_interrupt(
				all_twi_definitions[twi_index].peripheral_base_address,
				MASK_ALL_INTERRUPTS);
		twi_reset(
				all_twi_definitions[twi_index].peripheral_base_address);

		switch (freertos_driver_parameters->operation_mode) {
		case TWI_I2C_MASTER:
			/* Call the standard ASF init function. */
			twi_enable_master_mode(
					all_twi_definitions[twi_index].peripheral_base_address);
			break;

		default:
			/* No other modes are currently supported. */
			break;
		}

		/* Create any required peripheral access mutexes and transaction complete
		semaphores.  This peripheral is half duplex so only a single access
		mutex is required. */
		create_peripheral_control_semaphores(
				freertos_driver_parameters->options_flags,
				&(tx_dma_control[twi_index]),
				&(rx_dma_control[twi_index]));

		/* Error interrupts are always enabled. */
		twi_enable_interrupt(
				all_twi_definitions[twi_index].peripheral_base_address,
				IER_ERROR_INTERRUPTS);

		/* Configure and enable the TWI interrupt in the interrupt controller. */
		configure_interrupt_controller(
				all_twi_definitions[twi_index].peripheral_irq,
				freertos_driver_parameters->interrupt_priority);

		return_value = (freertos_twi_if) p_twi;
	} else {
		return_value = NULL;
	}

	return return_value;
}

/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte write operation on a TWI
 * peripheral.
 *
 * freertos_twi_write_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to transmit data on the
 * TWI port, then returns.  freertos_twi_write_packet_async() does not wait for
 * the transmission to complete before returning.
 *
 * The FreeRTOS TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_write_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_TX_COMPLETE bit clear.
 *
 * freertos_twi_write_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_write_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_twi    The handle to the TWI peripheral returned by the
 *     freertos_twi_master_init() call used to initialise the peripheral.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the source data location, and the number
 *     of bytes to transmit.  twi_packet_t is a standard ASF type (it is not
 *     FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_TX_ACCESS_MUTEX bit
 *     set, then the driver will only write to the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the write operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the transmit
 *     function exits the transmit function as soon as the transmission starts.
 *     The data being transmitted by the PDC must not be modified until after
 *     the transmission has completed.  The PDC interrupt (handled internally by
 *     the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has finished accessing the data.
 *     The calling task can call standard FreeRTOS functions to block on the
 *     semaphore until the PDC interrupt occurs.  Other RTOS tasks will execute
 *     while the the calling task is in the Blocked state.  The semaphore must
 *     be created using the FreeRTOS vSemaphoreCreateBinary() API function
 *     before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI write operation.
 */
status_code_t freertos_twi_write_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->addr_length > 0)) {
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Set write mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			internal_address = p_packet->addr[0];
			if (p_packet->addr_length > 1) {
				internal_address <<= 8;
				internal_address |= p_packet->addr[1];
			}

			if (p_packet->addr_length > 2) {
				internal_address <<= 8;
				internal_address |= p_packet->addr[2];
			}

			twi_base->TWI_IADR = internal_address;

			freertos_start_pdc_tx(&(tx_dma_control[twi_index]),
					p_packet->buffer, p_packet->length,
					all_twi_definitions[twi_index].pdc_base_address,
					notification_semaphore);

			/* Catch the end of transmission so the access mutex can be
			returned, and the task notified (if it supplied a notification
			semaphore).  The interrupt can be enabled here because the ENDTX
			signal from the PDC to the peripheral will have been de-asserted when
			the next transfer was configured. */
			twi_enable_interrupt(twi_base, TWI_IER_ENDTX);

			return_value = freertos_optionally_wait_transfer_completion(
					&(tx_dma_control[twi_index]),
					notification_semaphore,
					block_time_ticks);
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}

/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte read operation on an TWI
 * peripheral.
 *
 * freertos_twi_read_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to read data from the
 * TWI port, then returns.  freertos_twi_read_packet_async() does not wait for
 * the reception to complete before returning.
 *
 * The FreeRTOS ASF TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_read_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_RX_COMPLETE bit clear.
 *
 * freertos_twi_read_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_read_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_twi    The handle to the TWI port returned by the
 *     freertos_twi_master_init() call used to initialise the port.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the destination for the data being read,
 *     and the number of bytes to read.  twi_packet_t is a standard ASF type (it
 *     is not FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_RX_ACCESS_MUTEX bit
 *     set, then the driver will only read from the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the read operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the receive
 *     function exits the receive function as soon as the reception starts.
 *     The data being received by the PDC cannot normally be processed until
 *     after the reception has completed.  The PDC interrupt (handled internally
 *     by the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has read the requested number of
 *     bytes.  The calling task can call standard FreeRTOS functions to block on
 *     the semaphore until the PDC interrupt occurs.  Other RTOS tasks will
 *     execute while the the calling task is in the Blocked state.  The
 *     semaphore must be created using the FreeRTOS vSemaphoreCreateBinary() API
 *     function before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI read operation.
 */
status_code_t freertos_twi_read_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->addr_length > 0)) {
		/* Because the peripheral is half duplex, there is only one access mutex
		and the rx uses the tx mutex. */
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Ensure Rx is already empty. */
			twi_read_byte(twi_base);

			/* Set read mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(
					p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			internal_address = p_packet->addr [0];
			if (p_packet->addr_length > 1) {
				internal_address <<= 8;
				internal_address |= p_packet->addr[1];
			}

			if (p_packet->addr_length > 2) {
				internal_address <<= 8;
				internal_address |= p_packet->addr[2];
			}

			twi_base->TWI_IADR = internal_address;

			/* Start the PDC reception. */
			freertos_start_pdc_rx(&(rx_dma_control[twi_index]),
					p_packet->buffer, p_packet->length,
					all_twi_definitions[twi_index].pdc_base_address,
					notification_semaphore);

			/* Start the transfer. */
			twi_base->TWI_CR = TWI_CR_START;

			/* Catch the end of reception so the access mutex can be returned,
			and the task notified (if it supplied a notification semaphore).
			The interrupt can be enabled here because the ENDRX	signal from the
			PDC to the peripheral will have been de-asserted when the next
			transfer was configured. */
			twi_enable_interrupt(twi_base, TWI_IER_ENDRX);

			return_value = freertos_optionally_wait_transfer_completion(
					&(rx_dma_control[twi_index]),
					notification_semaphore,
					block_time_ticks);
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}

/*
 * For internal use only.
 * A common SPI interrupt handler that is called for all SPI peripherals.
 */
static void local_twi_handler(const portBASE_TYPE twi_index)
{
	portBASE_TYPE higher_priority_task_woken = pdFALSE;
	uint32_t twi_status;
	Twi *twi_port;

	twi_port = all_twi_definitions[twi_index].peripheral_base_address;

	twi_status = twi_get_interrupt_status(twi_port);
	twi_status &= twi_get_interrupt_mask(twi_port);

	/* Has the PDC completed a transmission? */
	if ((twi_status & TWI_SR_ENDTX) != 0UL) {
		/* Complete the transfer. */
		twi_port->TWI_CR = TWI_CR_STOP;

		twi_disable_interrupt(twi_port, TWI_IDR_ENDTX);

		/* If the driver is supporting multi-threading, then return the access
		mutex. */
		if (tx_dma_control[twi_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[twi_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}

		/* if the sending task supplied a notification semaphore, then
		notify the task that the transmission has completed. */
		if (tx_dma_control[twi_index]. transaction_complete_notification_semaphore != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[twi_index].transaction_complete_notification_semaphore,
					&higher_priority_task_woken);
		}
	}

	/* Has the PDC completed a reception? */
	if ((twi_status & TWI_SR_ENDRX) != 0UL) {
		/* Complete the transfer. */
		twi_port->TWI_CR = TWI_CR_STOP;

		twi_disable_interrupt(twi_port, TWI_IDR_ENDRX);

		/* If the driver is supporting multi-threading, then return the access
		mutex.  NOTE: As the peripheral is half duplex there is only one
		access mutex, and the reception uses the tx access muted. */
		if (tx_dma_control[twi_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[twi_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}

		/* if the receiving task supplied a notification semaphore, then
		notify the task that the transmission has completed. */
		if (rx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
			xSemaphoreGiveFromISR(
					rx_dma_control[twi_index].transaction_complete_notification_semaphore,
					&higher_priority_task_woken);
		}
	}

	if ((twi_status & SR_ERROR_INTERRUPTS) != 0) {
		/* An error occurred in either a transmission or reception.  Abort.
		Stop the transmission, disable interrupts used by the peripheral, and
		ensure the peripheral access mutex is made available to tasks.  As this
		peripheral is half duplex, only the Tx peripheral access mutex exits.*/
		twi_port->TWI_CR = TWI_CR_STOP;
		twi_disable_interrupt(twi_port, TWI_IDR_ENDTX);
		twi_disable_interrupt(twi_port, TWI_IDR_ENDRX);

		if (tx_dma_control[twi_index].peripheral_access_mutex != NULL) {
			xSemaphoreGiveFromISR(
					tx_dma_control[twi_index].peripheral_access_mutex,
					&higher_priority_task_woken);
		}
	}

	/* If giving a semaphore caused a task to unblock, and the unblocked task
	has a priority equal to or higher than the currently running task (the task
	this ISR interrupted), then higher_priority_task_woken will have
	automatically been set to pdTRUE within the semaphore function.
	portEND_SWITCHING_ISR() will then ensure that this ISR returns directly to
	the higher priority unblocked task. */
	portEND_SWITCHING_ISR(higher_priority_task_woken);
}

/*
 * Individual interrupt handlers follow from here.  Each individual interrupt
 * handler calls the common interrupt handler.
 */
#ifdef TWI

void TWI_Handler(void)
{
	local_twi_handler(0);
}

#endif /* TWI */

#ifdef TWI0

void TWI0_Handler(void)
{
	local_twi_handler(0);
}

#endif /* TWI0 */

#ifdef TWI1

void TWI1_Handler(void)
{
	local_twi_handler(1);
}

#endif /* TWI1 */

#ifdef TWI2

void TWI2_Handler(void)
{
	local_twi_handler(2);
}

#endif /* TWI2 */

#ifdef TWI3

void TWI3_Handler(void)
{
	local_twi_handler(3);
}

#endif /* TWI3 */

#ifdef TWI4

void TWI4_Handler(void)
{
	local_twi_handler(4);
}

#endif /* TWI4 */
