/* ----------------------------------------------------------------------------------------------- */
/* FILE :		avr32_uart.c																		*/
/*																									*/
/* CONTENTS :																						*/
/*				Driver for the avr32 family of chips from Atmel (Microchip)							*/
/*																									*/
/*																									*/
/* Copyright (c) 2017, Code-Time Technologies Inc. All rights reserved.								*/
/*																									*/
/* 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.										*/
/*																									*/
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND					*/
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED					*/
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE							*/
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 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.										*/
/*																									*/
/*																									*/
/*	$Revision: 1.6 $																				*/
/*	$Date: 2016/07/17 17:03:49 $																	*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

#if defined(_UABASSI_)							 	/* It is the same include file in all cases.	*/
  #include "Abassi.h"								/* There is a substitution during the release 	*/
#elif defined (OS_N_CORE)							/* This file is the same for Abassi, mAbassi,	*/
  #include "Abassi.h"								/* and uAbassi, so Code Time uses these checks	*/
#else												/* to not have to keep 3 quasi identical		*/
  #include "Abassi.h"								/* copies of this file							*/
#endif

#include "avr32_uart.h"


#ifdef __SAL_H__									/* When used in standalone, some build options	*/
  #undef UART_SINGLE_MUTEX							/* cannot be set, so they are forced to their	*/
  #undef UART_SLEEP									/* default values								*/
#endif

#ifndef UART_CIRC_BUF_RX							/* If the RX direction uses a circular buffer	*/
  #define UART_CIRC_BUF_RX		0					/* for accumulation.  if >0, is the size of		*/
#endif												/* the circular buffer							*/

#ifndef UART_CIRC_BUF_TX							/* If the TX direction uses a circular buffer	*/
  #define UART_CIRC_BUF_TX		0					/* for accumulation.  if >0, is the size of		*/
#endif												/* the circular buffer							*/

#ifndef UART_SLEEP									/* When polling, if the task can go into sleep	*/
  #define UART_SLEEP			0					/* Be aware the FIFOs are 128 deep and baud at	*/
#endif												/* 115200 will fill the RX FIFO in ~11 ms		*/

#ifndef UART_FULL_PROTECT							/* To use ISR on/off + spinlock to protect		*/
  #define UART_FULL_PROTECT		0					/* access instead of mutexes					*/
#endif

#if ((UART_FULL_PROTECT) != 0)						/* When full access protection done with ISRs	*/
  #undef  UART_SINGLE_MUTEX							/* on/off + spinlock, mutexes are redundant		*/
  #define UART_SINGLE_MUTEX		-1
#endif

#ifndef UART_SINGLE_MUTEX							/* If single mutex used for all devices or each	*/
  #define UART_SINGLE_MUTEX		-1					/* device has its own mutex						*/
#endif												/* ==0: individual / >0: single /-ve: none		*/
													/* Set to none as "C" lib should protect		*/
#ifndef UART_ARG_CHECK
  #define UART_ARG_CHECK		1					/* If checking validity of function arguments	*/
#endif

#ifndef UART_TOUT
  #define UART_TOUT		(10*(OS_TICK_PER_SEC))		/* Safety to not remain block forever			*/
#endif

/* ------------------------------------------------------------------------------------------------ */
/* Base addresses of the HW UART modules and other platform specific information					*/

#if (((OS_PLATFORM) & 0x00FFF000) == 0x00AEA000)	/* Atmel AV32A									*/
  #include "board.h"
  #include "gpio.h"
  #include "power_clocks_lib.h"

  static volatile uint32_t * const g_HWaddr[4] = { (volatile uint32_t *)0xFFFF1400,
                                                   (volatile uint32_t *)0xFFFF1800,
                                                   (volatile uint32_t *)0xFFFF1C00,
                                                   (volatile uint32_t *)0xFFFF2000
                                                 };

 #ifndef UART_CLK
  #define UART_CLK				12000000
 #endif

#endif

#define REG_IS_RD_MOD_WR		0					/* If the TX/RX enable-disable is Rd-mod-wrt	*/

/* ------------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------------ */
/* UART driver is special: can be a stub when used with System Call Layer where stdio is not used	*/

#if ((UART_LIST_DEVICE) == 0U) 
int uart_recv(int Dev, char *Buff, int Len)
{
	return(0);
}
int uart_send(int Dev, const char *Buff, int Len)
{
	return(0);
}
int uart_init(int Dev, int Baud, int Nbits, int Parity, int Stop, int RXsize, int TXsize, int Filter)
{
	return(0);
}
#else

/* ------------------------------------------------------------------------------------------------ */
/* This section uses a lots of macros but it's to reduce the size of the data requirements by only	*/
/* creating descriptor / mutexes etc for the devices in use ("1" in UART_LIST_DEVICE)				*/

#ifndef UART_MAX_DEVICES
 #if   (((UART_LIST_DEVICE) & 0x200) != 0U)
  #define UART_MAX_DEVICES	10
 #elif (((UART_LIST_DEVICE) & 0x100) != 0U)
  #define UART_MAX_DEVICES	9
 #elif (((UART_LIST_DEVICE) & 0x080) != 0U)
  #define UART_MAX_DEVICES	8
 #elif (((UART_LIST_DEVICE) & 0x040) != 0U)
  #define UART_MAX_DEVICES	7
 #elif (((UART_LIST_DEVICE) & 0x020) != 0U)
  #define UART_MAX_DEVICES	6
 #elif (((UART_LIST_DEVICE) & 0x010) != 0U)
  #define UART_MAX_DEVICES	5
 #elif (((UART_LIST_DEVICE) & 0x008) != 0U)
  #define UART_MAX_DEVICES	4
 #elif (((UART_LIST_DEVICE) & 0x004) != 0U)
  #define UART_MAX_DEVICES	3
 #elif (((UART_LIST_DEVICE) & 0x002) != 0U)
  #define UART_MAX_DEVICES	2
 #elif (((UART_LIST_DEVICE) & 0x001) != 0U)
  #define UART_MAX_DEVICES	1
 #endif
#endif

/* ------------------------------------------------------------------------------------------------ */
/* This section figures out how to remap the individual devices specified by UART_LIST_DEVICE		*/
/* e.g. if UART_LIST_DEVICE == 0x12, the only descriptors/mutexes for 2 devices are required and	*/
/*      device#1 is remapped to [0] and device #4 is remapped to [1]								*/

#if (((UART_LIST_DEVICE) & 0x001) != 0)
  #define UART_CNT_0	0
  #define UART_IDX_0	0
#else
  #define UART_CNT_0	(-1)
  #define UART_IDX_0	(-1)
#endif
#if (((UART_LIST_DEVICE) & 0x002) != 0)
  #define UART_CNT_1	((UART_CNT_0) + 1)
  #define UART_IDX_1	((UART_CNT_0) + 1)
#else
  #define UART_CNT_1	(UART_CNT_0)
  #define UART_IDX_1	-1
#endif
#if (((UART_LIST_DEVICE) & 0x004) != 0)
  #define UART_CNT_2	((UART_CNT_1) + 1)
  #define UART_IDX_2	((UART_CNT_1) + 1)
#else
  #define UART_CNT_2	(UART_CNT_1)
  #define UART_IDX_2	-1
#endif
#if (((UART_LIST_DEVICE) & 0x008) != 0)
  #define UART_CNT_3	((UART_CNT_2) + 1)
  #define UART_IDX_3	((UART_CNT_2) + 1)
#else
  #define UART_CNT_3	(UART_CNT_2)
  #define UART_IDX_3	-1
#endif
#if (((UART_LIST_DEVICE) & 0x010) != 0)
  #define UART_CNT_4	((UART_CNT_3) + 1)
  #define UART_IDX_4	((UART_CNT_3) + 1)
#else
  #define UART_CNT_4	(UART_CNT_3)
  #define UART_IDX_4	-1
#endif
#if (((UART_LIST_DEVICE) & 0x020) != 0)
  #define UART_CNT_5	((UART_CNT_4) + 1)
  #define UART_IDX_5	((UART_CNT_4) + 1)
#else
  #define UART_CNT_5	(UART_CNT_4)
  #define UART_IDX_5	-1
#endif
#if (((UART_LIST_DEVICE) & 0x040) != 0)
  #define UART_CNT_6	((UART_CNT_5) + 1)
  #define UART_IDX_6	((UART_CNT_5) + 1)
#else
  #define UART_CNT_6	(UART_CNT_5)
  #define UART_IDX_6	-1
#endif
#if (((UART_LIST_DEVICE) & 0x080) != 0)
  #define UART_CNT_7	((UART_CNT_6) + 1)
  #define UART_IDX_7	((UART_CNT_6) + 1)
#else
  #define UART_CNT_7	(UART_CNT_6)
  #define UART_IDX_7	-1
#endif
#if (((UART_LIST_DEVICE) & 0x100) != 0)
  #define UART_CNT_8	((UART_CNT_7) + 1)
  #define UART_IDX_8	((UART_CNT_7) + 1)
#else
  #define UART_CNT_8	(UART_CNT_7)
  #define UART_IDX_8	-1
#endif
#if (((UART_LIST_DEVICE) & 0x200) != 0)
  #define UART_CNT_9	((UART_CNT_8) + 1)
  #define UART_IDX_9	((UART_CNT_8) + 1)
#else
  #define UART_CNT_9	(UART_CNT_8)
  #define UART_IDX_9	-1
#endif

#define UART_NMB_DEVICES	((UART_CNT_9)+1)

/* ------------------------------------------------------------------------------------------------ */

static const int g_DevReMap[] = { UART_IDX_0
                               #if ((UART_MAX_DEVICES) > 1)
                                 ,UART_IDX_1
                               #endif 
                               #if ((UART_MAX_DEVICES) > 2)
                                 ,UART_IDX_2
                               #endif 
                               #if ((UART_MAX_DEVICES) > 3)
                                 ,UART_IDX_3
                               #endif 
                               #if ((UART_MAX_DEVICES) > 4)
                                 ,UART_IDX_4
                               #endif 
                               #if ((UART_MAX_DEVICES) > 5)
                                 ,UART_IDX_5
                               #endif 
                               #if ((UART_MAX_DEVICES) > 6)
                                 ,UART_IDX_6
                               #endif 
                               #if ((UART_MAX_DEVICES) > 7)
                                 ,UART_IDX_7
                               #endif 
                               #if ((UART_MAX_DEVICES) > 8)
                                 ,UART_IDX_8
                               #endif 
                               #if ((UART_MAX_DEVICES) > 9)
                                 ,UART_IDX_9
                               #endif
                               };

/* ------------------------------------------------------------------------------------------------ */

#if (((OS_PLATFORM) & 0x00FFF000) == 0x00AEA000)	/* Atmel AV32A									*/
  #if (((UART_NMB_DEVICES) > 4)  || ((UART_MAX_DEVICES) > 4))
	#error "Too many USART devices for Arria V / Cyclone V:"
    #error "      Set UART_MAX_DEVICES <= 4 and/or UART_LIST_DEVICE <= 0xF"
  #endif
#else
  	#error "Unsupported platform specified by OS_PLATFORM"
#endif

#if ((UART_CIRC_BUF_RX) != 0)
  #define UART_MAILBOX_RX	0
#else
  #define UART_MAILBOX_RX	(OX_MAILBOX)
#endif

#if ((UART_CIRC_BUF_TX) != 0)
  #define UART_MAILBOX_TX	0
#else
  #define UART_MAILBOX_TX	(OX_MAILBOX)
#endif

#if ((OX_MAILBOX) != 0)								/* Abassi must be set-up to have MBXput report	*/
  #if ((OX_MBXPUT_ISR) == 0)						/* valid return value (full or write OK)		*/
	#error "When using mailboxes with dw_uart, OS_MBXPUT_ISR MUST be set to non-zero"
  #endif
#endif

#if ((UART_CIRC_BUF_RX) < 0)
  #error "UART_CIRC_BUF_RX must be set >= 0"
#endif

#if ((UART_CIRC_BUF_TX) < 0)
  #error "UART_CIRC_BUF_TX must be set >= 0"
#endif

/* ------------------------------------------------------------------------------------------------ */
/* UART register index definitions (are accessed as uint32_t)										*/

#define UART_CR_REG				(0x00/4)
#define UART_MR_REG				(0x04/4)
#define UART_IER_REG			(0x08/4)
#define UART_IDR_REG			(0x0C/4)
#define UART_IMR_REG			(0x10/4)
#define UART_CSR_REG			(0x14/4)
#define UART_RHR_REG			(0x18/4)
#define UART_THR_REG			(0x1C/4)
#define UART_BRGR_REG			(0x20/4)
#define UART_RTOR_REG			(0x24/4)
#define UART_TTGR_REG			(0x28/4)
#define UART_LINMR_REG			(0x54/4)
#define UART_LINIR_REG			(0x58/4)
#define UART_WPMR_REG			(0xE4/4)
#define UART_WPSR_REG			(0xEB/4)
#define UART_VERSION_REG		(0xFC/4)

/* ------------------------------------------------------------------------------------------------ */

#define UART_FILT_IN_CR_MASK   ((UART_FILT_IN_CR_CRLF)|(UART_FILT_IN_CR_LF)|(UART_FILT_IN_CR_DROP))
#define UART_FILT_IN_LF_MASK   ((UART_FILT_IN_LF_CRLF)|(UART_FILT_IN_LF_CR)|(UART_FILT_IN_LF_DROP))
#define UART_FILT_OUT_CR_MASK  ((UART_FILT_OUT_CR_CRLF)|(UART_FILT_OUT_CR_LF)|(UART_FILT_OUT_CR_DROP))
#define UART_FILT_OUT_LF_MASK  ((UART_FILT_OUT_LF_CRLF)|(UART_FILT_OUT_LF_CR)|(UART_FILT_OUT_LF_DROP))

/* ------------------------------------------------------------------------------------------------ */
/* When protection mutex(es) are requested															*/

#if ((UART_SINGLE_MUTEX) == 0)
  #define UART_MTX_LOCK(Cfg)	MTXlock((Cfg)->Mutex, -1)
  #define UART_MTX_UNLOCK(Cfg)	MTXunlock((Cfg)->Mutex)

#elif ((UART_SINGLE_MUTEX) > 0)
  #define UART_MTX_LOCK(Cfg)	MTXlock(g_MyMutex, -1)
  #define UART_MTX_UNLOCK(Cfg)	MTXunlock(g_MyMutex)

  static MTX_t *g_MyMutex = (MTX_t *)NULL;
#endif

/* ------------------------------------------------------------------------------------------------ */
/* Access protection for back-ground vs ISR.  The ISR handler is sometimes called from the			*/
/* background so mutexes cannot be used to provide exclusive access: mutexes cannot be locked in	*/
/* an ISR.																							*/

#if ((OX_N_CORE) == 1)								/* UART's register exclusive access control		*/
  #define UART_GET_EXCL(Cfg, x)		do {x=OSintOff();} while(0)
  #define UART_RLS_EXCL(Cfg, x)		(OSintBack(x))

#else												/* Multi-core also requires to use a spinlock	*/
  #define UART_GET_EXCL(Cfg, x)		do {x=OSintOff();												\
									    CORElock(UART_SPINLOCK, &(Cfg)->Lock, 0, COREgetID()+1);	\
									} while(0)
  #define UART_RLS_EXCL(Cfg, x)		do {COREunlock(UART_SPINLOCK, &(Cfg)->Lock, 0);					\
									    OSintBack(x);												\
									} while(0)
#endif

/* ------------------------------------------------------------------------------------------------ */
/* The following ???_F_EXCL are used to replace mutexes in the background to provide exclusive		*/
/* access the UART descriptor																		*/

#if ((UART_FULL_PROTECT) == 0)						/* Not requested to perform local full protect	*/
  #define UART_GET_F_EXCL(Dv, x)	OX_DO_NOTHING()
  #define UART_RLS_F_EXCL(Dv, x)	OX_DO_NOTHING()
#else												/* Requested to perform full local protection	*/
  #define UART_GET_F_EXCL(Dv, x)	UART_GET_EXCL(Dv, x)
  #define UART_RLS_F_EXCL(Dv, x)	UART_RLS_EXCL(Dv, x)
#endif

/* ------------------------------------------------------------------------------------------------ */
/* Register access protection when enabling / disabling RX or TX interrupts							*/
/* If the register(s) is read-modify-write, it requires protection, if not, then no protections		*/

#if ((REG_IS_RD_MOD_WR) == 0)
  #define UART_GET_R_EXCL(Dv, x)	OX_DO_NOTHING()
  #define UART_RLS_R_EXCL(Dv, x)	OX_DO_NOTHING()
#else
  #define UART_GET_R_EXCL(Dv, x)	UART_GET_EXCL(Dv, x)
  #define UART_RLS_R_EXCL(Dv, x)	UART_RLS_EXCL(Dv, x)
#endif

/* ------------------------------------------------------------------------------------------------ */
/* Other than configuration, these are all the UART access operations that have to be performed		*/

#define UART_RX_EMPTY(Cfg)			(0 == ((Cfg)->HW[UART_CSR_REG] & 0x1U))
#define UART_TX_FULL(Cfg)			(0 == ((Cfg)->HW[UART_CSR_REG] & 0x2U))
#define UART_DATA_RX(Cfg)			((Cfg)->HW[UART_RHR_REG])
#define UART_DATA_TX(Cfg)			((Cfg)->HW[UART_THR_REG])

#define UART_RX_DISABLE(Cfg)		do {(Cfg)->HW[UART_IDR_REG] = 1U;} while(0)
#define UART_RX_ENABLE(Cfg)			do {(Cfg)->HW[UART_IER_REG] = 1U;} while(0)
#define UART_TX_DISABLE(Cfg)		do {(Cfg)->HW[UART_IDR_REG] = 2U;} while(0)
#define UART_TX_ENABLE(Cfg)			do {(Cfg)->HW[UART_IER_REG] = 2U;} while(0)

/* ------------------------------------------------------------------------------------------------ */
/* Local variables																					*/

typedef struct {									/* Per device: configuration					*/
	volatile uint32_t *HW;							/* Base address of the UART peripheral			*/
	SEM_t *SemRX;									/* When using semaphore instead of timeout		*/
	SEM_t *SemTX;									/* When using semaphore instead of timeout		*/
	int    RXsize;									/* Size of the RX mailbox (0 when polling)		*/
	int    TXsize;									/* Size of the TX mailbox (0 when polling)		*/
	int    PendRX;									/* Pending char to read							*/
	int    PendTX;									/* Pending char to transmit						*/
	int    IsInit;									/* If the device has been initialized			*/
	unsigned int Filter;							/* Operations about ECHO, CR & LF to perform	*/
  #if ((OX_N_CORE) >= 2)							/* Doing Read-Modify-Write of UART registers	*/
	int    Lock;									/* Need also a spinlock in extra of ISR disable	*/
  #endif											/* when multi-core								*/
  #if ((UART_SINGLE_MUTEX) == 0)
	MTX_t *Mutex;									/* When 1 mutex per device						*/
  #endif
  #if ((UART_MAILBOX_RX) != 0)
	MBX_t *MboxRX;									/* RX mailbox									*/
    int    PendINT;									/* Safety used in UART RX interrupt handler		*/
  #endif
  #if ((UART_MAILBOX_TX) != 0)
	MBX_t *MboxTX;									/* TX mailbox									*/
  #endif
  #if ((UART_CIRC_BUF_RX) != 0)
	char CBufRX[(UART_CIRC_BUF_RX)+1];
	volatile int RXrdIdx;
	volatile int RXwrtIdx;
  #endif
  #if ((UART_CIRC_BUF_TX) != 0)
	char CBufTX[(UART_CIRC_BUF_TX)+1];
	volatile int TXrdIdx;
	volatile int TXwrtIdx;
  #endif
} UARTcfg_t;

static UARTcfg_t g_UARTcfg[UART_NMB_DEVICES];		/* Device configuration							*/
static int       g_CfgIsInit = 0;					/* To track first time an init occurs			*/

/* ------------------------------------------------------------------------------------------------ */
/* Local functions prototypes																		*/

static void UARTintRX(UARTcfg_t *Cfg);				/* UART interrupt handler for RX direction		*/
static void UARTintTX(UARTcfg_t *Cfg);				/* UART interrupt handler for TX direction		*/

/* ------------------------------------------------------------------------------------------------ */
/* FUNCTION: uart_recv																				*/
/*																									*/
/* uart_recv - receive data from a UART device														*/
/*																									*/
/* SYNOPSIS:																						*/
/*		int uart_recv(int Dev, char *Buff, int Len)													*/
/*																									*/
/* ARGUMENTS:																						*/
/*		Dev  : UART device number (on Arria V/10 & Cyclone V : 0->1)								*/
/*		Buff : pointer to a buffer to hold the data received										*/
/*		Len  : number or max number of bytes (filtered) to read from the UART						*/
/*																									*/
/* RETURN VALUE:																					*/
/*		int : number of characters in Buff															*/
/*            may be different from the number received due to filtering							*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

int uart_recv(int Dev, char *Buff, int Len)
{
char ccc;											/* Character being handled						*/
int  Drop;											/* If filtering drops the received character	*/
int  Idx;											/* Index writing in Buff[]						*/
int  ii;											/* General purpose								*/
int  NoLock;										/* Boolean if can block or lock the mutex		*/
int  OSnotRdy;										/* Boolean if the OS is running or not			*/
int  PollSem;										/* Boolean if doing polling						*/
int  ReMap;											/* Remapped "Dev" to index in g_UARTcfg[]		*/
int  Wait;											/* Wait time (0 or -1:forever)					*/
#if ((UART_MAILBOX_RX) != 0)
  intptr_t Data;									/* To grab the character from the ISR mailbox	*/
  int      Ret;										/* Return value grabbing data from the mailbox	*/
#endif
#if ((UART_CIRC_BUF_RX) != 0)
  int RdIdx;										/* I'm the only one touching this one			*/
#endif

UARTcfg_t *MyCfg;									/* De-reference array for faster access			*/

const static char BSecho[2] ={ ' ', '\b'};			/* BS echo with expansion, add " \b" after '\b'	*/

  #if ((UART_ARG_CHECK) == 0)
	ReMap = g_DevReMap[Dev];
	MyCfg = &g_UARTcfg[ReMap];

  #else
	if ((Dev <0)									/* Device # must be within range to be valid	*/
	||  (Dev >= UART_MAX_DEVICES)) {
		return(-1);
	}

	ReMap = g_DevReMap[Dev];						/* The device must have a valid remapping		*/
	if (ReMap < 0) {								/* This is set by UART_LIST_DEVICE				*/
		return(-2);
	}

	MyCfg = &g_UARTcfg[ReMap];						/* This is my device configuration				*/

    if ((Len == 0) 									/* Exit when no data to read					*/
	||  (g_CfgIsInit == 0)							/* or nothing configured yet					*/
	||  (MyCfg->IsInit == 0)) {						/* or this device hasn't been initialized yet	*/
        return(0);									/* Report nothing read							*/
    }
  #endif
													/* Can't block or use MBX/MTX/SEM if the OS 	*/
	OSnotRdy = (TSKmyID() == (TSK_t *)NULL);		/* is not yet started							*/

   #ifdef __ABASSI_H__								/* Single core internals != multi-core ones		*/
	NoLock = (int)G_OSstate[0]						/* Can't lock/block if within an ISR			*/
	       | (0 == OSisrInfo())						/* Can't lock/block if the ISRs are disabled	*/
	       | OSnotRdy;
   #else											/* mAbassi or uAbassi							*/
	ii = OSintOff();								/* Must disable as Core # can switch in middle	*/
	  NoLock = (int)G_OSisrState[0][COREgetID()];	/* Can't lock/block if within an ISR			*/
	OSintBack(ii);
	NoLock  |= (0 == OSisrInfo())					/* Can't lock/block if the ISRs are disabled	*/
	        |  OSnotRdy;							/* Can't lock/block if OS not started			*/
   #endif

	Wait = -1;										/* Assume wait (forever) for RX data available	*/
	if (Len < 0) {									/* No waiting requested when Len is negative	*/
		Wait = 0;
		Len  = -Len;								/* Positive value is the max # of char to read	*/
	}

  #if ((UART_CIRC_BUF_RX) == 0)
	PollSem = (MyCfg->RXsize <= 0)					/* If has to do polling / use semaphore			*/
	        | OSnotRdy;								/* Must do polling if the OS not yet started	*/
  #else
	PollSem = OSnotRdy;								/* When circular buffer is used, waiting on the	*/
  #endif											/* will happen if MyCfg->RXsize <= 0			*/

  #if ((UART_SINGLE_MUTEX) >= 0)					/* When mutexes are used for protection			*/
	if (NoLock == 0) {								/* Lock the mutex only if it can be done		*/
		UART_MTX_LOCK(MyCfg);
	}
  #endif

	Idx = 0;										/* Index writing into Buff[]					*/
	do {
		Drop = 0;									/* Assume we are keeping this character			*/
		UART_GET_F_EXCL(MyCfg, ii);					/* When requested to do local full protection	*/
		if (MyCfg->PendRX >= 0) {					/* If there is a pending RX char, grab it		*/
			ccc = (char)MyCfg->PendRX;				/* instead of reading the UART or the mailbox	*/
			MyCfg->PendRX = -1;						/* Indicate no more pending RX char				*/
			UART_RLS_F_EXCL(MyCfg, ii);
		}											/* Pending chars exist because of filtering		*/
		else {										/* No pending char to grab, get a new one		*/
			UART_RLS_F_EXCL(MyCfg, ii);
			if (PollSem != 0) {						/* Set-up for polling or semaphore				*/
				if (Wait == 0) {					/* Request to not wait for avail char			*/
					UART_GET_F_EXCL(MyCfg, ii);		/* When requested to do local full protection	*/
					if (UART_RX_EMPTY(MyCfg)) {		/* No char available							*/
						UART_RLS_F_EXCL(MyCfg, ii);
						break;						/* Abort the processing and exit				*/
					}
					else {
						ccc = (char)UART_DATA_RX(MyCfg);
						UART_RLS_F_EXCL(MyCfg, ii);
					}
				}

				else {								/* Must wait until a char is available			*/
					UART_GET_F_EXCL(MyCfg, ii);		/* When requested to do local full protection	*/
					while (UART_RX_EMPTY(MyCfg)) {	/* Loop as long as RX FIFO empty				*/
						UART_RLS_F_EXCL(MyCfg, ii);
						if (NoLock == 0) { 			/* If can block, block on semaphore or sleep	*/
							if (MyCfg->RXsize < 0) {/* Wait on the RX semaphore						*/
								UART_GET_R_EXCL(MyCfg, ii);
								UART_RX_ENABLE(MyCfg);	/* FIFO is empty, make sure ISRs are enable	*/
								UART_RLS_R_EXCL(MyCfg,ii);
								SEMwaitBin(MyCfg->SemRX, UART_TOUT);/* Posted: FIFO not empty		*/
							}						/* RX ISR disable in ISR when FIFO not empty	*/
						  #if (((UART_SLEEP) > 0) && ((OX_TIMER_US) && ((OX_TIMEOUT) > 0)))
							else {					/* Can only sleep if timeouts are available		*/
								TSKsleep(UART_SLEEP);	/* And authorized by the build option		*/
							}
						  #endif
						}
						UART_GET_F_EXCL(MyCfg, ii);	/* When requested to do local full protection	*/
					}
					ccc = (char)UART_DATA_RX(MyCfg);
					UART_RLS_F_EXCL(MyCfg, ii);
				}
			}
		  #if ((UART_CIRC_BUF_RX) != 0)				/* Circular buffer used							*/
			else {
				if (Wait == 0) {					/* Not waiting for char to be received			*/
					RdIdx = MyCfg->RXrdIdx;			/* Volatile: read once							*/
					if (RdIdx == MyCfg->RXwrtIdx) {	/* Nothing in the circ buffer but	*/
						UART_GET_EXCL(MyCfg, ii);	/* manual call as ISR may be turned off			*/
						UARTintRX(MyCfg);
						UART_RLS_EXCL(MyCfg, ii);
					}
					if (RdIdx == MyCfg->RXwrtIdx) {	/* If still nothing								*/
						break;						/* Request to not wait, skip the processing		*/
					}
				}

				RdIdx = MyCfg->RXrdIdx;				/* Volatile: read once							*/
				while (RdIdx == MyCfg->RXwrtIdx) {	/* Wait for something in circ buffer			*/
					if ((MyCfg->RXsize != 0)		/* When ISRs are used							*/
					&&  (NoLock == 0)) { 			/* If can block, block on semaphore or sleep	*/
						UART_GET_R_EXCL(MyCfg, ii);	/* Make sure ISRs are enable					*/
						UART_RX_ENABLE(MyCfg);		/* Circbuff is empty, make sure ISRs are enable	*/
						UART_RLS_R_EXCL(MyCfg,ii);
						SEMwaitBin(MyCfg->SemRX, UART_TOUT);
					}				
					else {							/* Can't block, call the ISR handler manually	*/
					  #if (((UART_SLEEP) > 0) && ((OX_TIMER_US) && ((OX_TIMEOUT) > 0)))
						if (NoLock == 0) {			/* If can bloxk									*/
							TSKsleep(UART_SLEEP);	/* Can only sleep if timeouts are available		*/
						}							/* And authorized by the build option			*/
					  #endif
						UART_GET_EXCL(MyCfg, ii);	/* No ISRs: manual call to the ISR handler		*/
						UARTintRX(MyCfg);
						UART_RLS_EXCL(MyCfg, ii);
					}
				}

				ccc = MyCfg->CBufRX[MyCfg->RXrdIdx];
				if (--MyCfg->RXrdIdx < 0) {
					MyCfg->RXrdIdx = UART_CIRC_BUF_RX;
				}
			}
		  #elif ((UART_MAILBOX_RX) != 0)			/* This code only used when mailbox included	*/
			else {									/* Not polling, therefore use Mailboxes & ISRs	*/
				Ret = MBXget(MyCfg->MboxRX, (intptr_t *)&Data, 0);	/* Quick try first				*/
				if ((Ret != 0)						/* When nothing in mailbox, a char may be held	*/
				&&  (MyCfg->PendINT >= 0)) { 		/* in ->PendINT (the safety mechanism)			*/
					UART_GET_EXCL(MyCfg, ii);		/* To get the char in PendINT, need to get the	*/
					UARTintRX(MyCfg);				/* RX interrupt handler to run: do it manually	*/
					UART_RLS_EXCL(MyCfg, ii);
					Ret = MBXget(MyCfg->MboxRX, (intptr_t *)&Data, 0);
				}

				if (Ret != 0) {						/* Mailbox & PendINT are empty, wait for char	*/
					if (NoLock != 0) {				/* If can't block, then poll the mailbox		*/
						if (Wait == 0) {			/* Request to not wait, skip the processing		*/
							break;
						}
						do {						/* Either ISRs disabled or inside an interrupt	*/
							UART_GET_EXCL(MyCfg, ii);	/* So call the RX interrupt handler manually*/
							UARTintRX(MyCfg);		/* This will also pull PendINT if it holds char	*/
							UART_RLS_EXCL(MyCfg, ii);
							Ret = MBXget(MyCfg->MboxRX, (intptr_t *)&Data, 0);
						} while (Ret != 0);			/* If mailbox still empty, try again			*/
					}
					else {							/* We can block, so normal processing			*/
						UART_GET_R_EXCL(MyCfg, ii);	/* Make sure the ISRs are enable as will be		*/
						UART_RX_ENABLE(MyCfg);		/* blocking on RX char received					*/
						UART_RLS_R_EXCL(MyCfg, ii);	/* RX processing (That's another core)			*/
						Ret = MBXget(MyCfg->MboxRX, (intptr_t *)&Data, Wait);
						if (Ret != 0) {				/* Non-zero result is only when timeout = 0		*/
							break;					/* which is when no-wait requested				*/
						}							/* Abort the rest of the processing				*/
					}
				}

				UART_GET_R_EXCL(MyCfg, ii);
				UART_RX_ENABLE(MyCfg);				/* Make sure the RX ISRs are enable as we have	*/
				UART_RLS_R_EXCL(MyCfg, ii);			/* read the mailbox, so there is room for one	*/
				ccc = (char)Data;					/* char in it now for sure						*/
			}						
		  #endif
		}

		if ((ccc == '\r')							/* Input CR filtering							*/
		&&  (0U != (MyCfg->Filter & UART_FILT_IN_CR_MASK))) {
			if (0 != (MyCfg->Filter & UART_FILT_IN_CR_CRLF)) {
				UART_GET_F_EXCL(MyCfg, ii);			/* When requested to do local full protection	*/
				MyCfg->PendRX = 0xFF & (int)'\n';
				UART_RLS_F_EXCL(MyCfg, ii);
			}
			else if (0 != (MyCfg->Filter & UART_FILT_IN_CR_LF)) {
				ccc = '\n';
			}
			else if (0 != (MyCfg->Filter & UART_FILT_IN_CR_DROP)) {
				Drop = 1;
			}
		}
		else if ((ccc == '\n')						/* Input LF filtering							*/
		&&       (0U != (MyCfg->Filter & UART_FILT_IN_LF_MASK))) {
			if (0 != (MyCfg->Filter & UART_FILT_IN_LF_CRLF)) {
				UART_GET_F_EXCL(MyCfg, ii);			/* When requested to do local full protection	*/
				MyCfg->PendRX = 0xFF & (int)'\n';
				UART_RLS_F_EXCL(MyCfg, ii);
			}
			else if (0 != (MyCfg->Filter & UART_FILT_IN_LF_CR)) {
				ccc = '\r';
			}
			else if (0 != (MyCfg->Filter & UART_FILT_IN_LF_DROP)) {
				Drop = 1;
			}
		}

		if (Drop == 0) {							/* We do use this character						*/
			if (0U != (MyCfg->Filter & UART_ECHO)) {/* If set to echo on output, do it				*/
				uart_send(Dev, (const char *)&ccc, 1);
				if ((ccc == '\b')					/* If filtering expand BACKSPACE to output		*/
				&&  (0U != (MyCfg->Filter & UART_ECHO_BS_EXPAND))) {
					uart_send(Dev, (const char *)&BSecho[0], 2);
				}
			}
			Buff[Idx++] = ccc;						/* Memo the newly received/filtered character	*/
		}											/* Process as long a room in buffer or 			*/
	} while (Idx < Len);							/* aborted when no-wait requested				*/

  #if ((UART_SINGLE_MUTEX) >= 0)					/* When mutexes are used for protection			*/
	if (NoLock == 0) {								/* Remove lock if was obtained					*/
		UART_MTX_UNLOCK(MyCfg);
	}
  #endif

	return(Idx);
}

/* ------------------------------------------------------------------------------------------------ */
/* FUNCTION: uart_send																				*/
/*																									*/
/* uart_send - send data to the UART device															*/
/*																									*/
/* SYNOPSIS:																						*/
/*		int uart_send(int Dev, const char *Buff, int Len)											*/
/*																									*/
/* ARGUMENTS:																						*/
/*		Dev  : UART device number (on Arria V & Cyclone V : 0 -> 1)									*/
/*		Buff : pointer to a buffer that holds the data to send										*/
/*		Len  : number of bytes to send to the slave device											*/
/*																									*/
/* RETURN VALUE:																					*/
/*		int  : number of character used from Buff													*/
/*             may be different from the number transmitted due to filtering						*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

int uart_send(int Dev, const char *Buff, int Len)
{
char ccc;											/* Character being handled						*/
int  Drop;											/* If filtering drops the received character	*/
int  Idx;											/* Index reading from Buff[]					*/
int  ii;											/* General purpose								*/
int  InKrnl;										/* If called from the kernel					*/
int  NoLock;										/* Boolean if can block or lock the mutex		*/
int  OSnotRdy;										/* Boolean if the OS is running or not			*/
int  PendTX;										/* Original contents of UARTcfg_t.PendTX		*/
int  PollSem;										/* Boolean if doing polling						*/
int  ReMap;											/* Remapped "Dev" to index in g_UARTcfg[]		*/
int  Wait;											/* Wait time (0 or -1:forever)					*/
int  WasAbort;										/* Boolean if the writing was aborted (no wait)	*/
#if ((UART_MAILBOX_TX) != 0)
  int  Ret;											/* Result of writing in mailbox					*/
#endif
#if ((UART_CIRC_BUF_TX) != 0)
  int NextWrt;
#endif
UARTcfg_t *MyCfg;									/* De-reference array for faster access			*/

  #if ((UART_ARG_CHECK) == 0)
	ReMap = g_DevReMap[Dev];
	MyCfg = &g_UARTcfg[ReMap];

  #else
	if ((Dev <0)									/* Device # must be within range to be valid	*/
	||  (Dev >= UART_MAX_DEVICES)) {
		return(-1);
	}

	ReMap = g_DevReMap[Dev];						/* The device must have a valid remapping		*/
	if (ReMap < 0) {								/* This is set by UART_LIST_DEVICE				*/
		return(-2);
	}

	MyCfg = &g_UARTcfg[ReMap];						/* This is my device configuration				*/

	if ((Len == 0) 									/* No data to send, exit						*/
	||  (g_CfgIsInit == 0)							/* Nothing configured yet						*/
	||  (MyCfg->IsInit == 0)) {						/* This device hasn't been initialized yet		*/
		return(0);									/* Report nothing written						*/
	}
  #endif
													/* Can't block or use MBOX/MTX/SEM if the OS 	*/
	OSnotRdy = (TSKmyID() == (TSK_t *)NULL);		/* is not yet started							*/
	InKrnl   = 0;									/* Assume is not called from the kernel			*/
  #ifdef __ABASSI_H__								/* Single core internals != multi-core ones		*/
   #if ((OX_LOGGING_TYPE) == 1)						/* Only type 1 makes kernel to do direct print	*/
	InKrnl = (int)G_OSstate[2];						/* G_OSstate[2] == Boolean if in the kernel		*/
   #endif
	NoLock   = (int)G_OSstate[0]					/* Can't lock/block if within an ISR			*/
	         | InKrnl								/* can't lock/block if in the kernel			*/
	         | (0 == OSisrInfo())					/* Can't lock/block if the ISRs are disabled	*/
	         | OSnotRdy;
  #else
	ii = OSintOff();								/* Must disable as Core # can switch in middle	*/
	{
	 int CoreID;
	 CoreID = COREgetID();
	 NoLock = (int)G_OSisrState[0][CoreID];			/* Can't lock/block if within an ISR			*/
   #if ((OX_LOGGING_TYPE) == 1)						/* Only type 1 makes kernel to do direct print	*/
	 InKrnl = (G_OSisrState[3][CoreID] == (CoreID+1));/* Memo if called from the kernel				*/
   #endif
	}
	OSintBack(ii);
	NoLock  |= InKrnl								/* Can't lock/block if in the kernel			*/
            |  (0 == OSisrInfo())					/* Can't lock/block if the ISRs are disabled	*/
	        |  OSnotRdy;							/* Can't lock/block if OS not started			*/
  #endif

	Wait = -1;										/* Assume wait (forever) for roam in TX FIFO	*/
	if (Len < 0) {									/* No waiting requested when Len is negative	*/
		Wait = 0;
		Len  = -Len;								/* Positive value is the # of char to read		*/
	}

  #if ((UART_CIRC_BUF_TX) == 0)
	PollSem = (MyCfg->TXsize <= 0)					/* If has to do polling / wait on semaphore		*/
	        | InKrnl								/* Polling must be used when called from kernel	*/
	        | OSnotRdy;								/* MBX use would re-enter the kernel: very bad	*/
  #else
	PollSem = InKrnl								/* Polling must be used when called from kernel	*/
	        | OSnotRdy;								/* When circular buffer is used, waiting on the	*/
  #endif											/* will happen if MyCfg->TXsize <= 0			*/

  #if ((UART_SINGLE_MUTEX) >= 0)					/* When mutexes are used for protection			*/
	if (NoLock == 0) {								/* Lock the mutex only if it can be done		*/
		UART_MTX_LOCK(MyCfg);
	}
  #endif

	for (Idx=0 ; (Idx<Len) || (MyCfg->PendTX >= 0) ; ) {
		Drop   = 0;									/* Assume we transmit the processed character	*/

		UART_GET_F_EXCL(MyCfg, ii);					/* When requested to do local full protection	*/
		PendTX = MyCfg->PendTX;						/* Memo original in case no wait and out full	*/
		if (PendTX >= 0) {							/* If there is a pending TX char, send it		*/
			ccc           = MyCfg->PendTX;			/* instead of reading the supplied buffer		*/
			MyCfg->PendTX = -1;						/* Tag these is no more pending TX char			*/
			UART_RLS_F_EXCL(MyCfg, ii);
		}											/* Pending chars exist because of filtering		*/
		else {										/* No pending TX char, use next from buffer		*/
			UART_RLS_F_EXCL(MyCfg, ii);
			ccc = Buff[Idx++];
			if ((ccc == '\r')						/* Output CR filtering							*/
			&&  (0U != (MyCfg->Filter & UART_FILT_OUT_CR_MASK))) {
				if (0 != (MyCfg->Filter & UART_FILT_OUT_CR_CRLF)) {
					UART_GET_F_EXCL(MyCfg, ii);		/* When requested to do local full protection	*/
					MyCfg->PendTX = 0xFF & (int)'\n';
					UART_RLS_F_EXCL(MyCfg, ii);
				}
				else if (0 != (MyCfg->Filter & UART_FILT_OUT_CR_LF)) {
					ccc = '\n';
				}
				else if (0 != (MyCfg->Filter & UART_FILT_OUT_CR_DROP)) {
					Drop = 1;
				}
			}
			else if ((ccc == '\n')					/* Output LF filtering							*/
			&&       (0U != (MyCfg->Filter & UART_FILT_OUT_LF_MASK))) {
				if (0 != (MyCfg->Filter & UART_FILT_OUT_LF_CRLF)) {
					UART_GET_F_EXCL(MyCfg, ii);		/* When requested to do local full protection	*/
					MyCfg->PendTX = 0xFF & (int)'\n';
					UART_RLS_F_EXCL(MyCfg, ii);
					ccc = '\r';
				}
				else if (0 != (MyCfg->Filter & UART_FILT_OUT_LF_CR)) {
					ccc = '\r';
				}
				else if (0 != (MyCfg->Filter & UART_FILT_OUT_LF_DROP)) {
					Drop = 1;
				}
			}
		}

		if (Drop == 0) {							/* Not dropping the character, queue/transmit 	*/
			WasAbort = 0;
			if (PollSem != 0) {						/* Polling/Sema: check for room in the TX FIFO	*/
				UART_GET_F_EXCL(MyCfg, ii);			/* When requested to do local full protection	*/
				while (UART_TX_FULL(MyCfg)) {
					UART_RLS_F_EXCL(MyCfg, ii);
					if (Wait == 0) {				/* No room in the TX FIFO and requested to not	*/
						WasAbort = 1;				/* wait, so abort								*/
						break;
					}
					if (NoLock == 0) { 				/* If can block, semaphore or sleep				*/
						if (MyCfg->TXsize < 0) {	/* Wait on the TX semaphore						*/
							UART_GET_R_EXCL(MyCfg, ii);	/* Get exclusive access (ISR disables TX	*/
							UART_TX_ENABLE(MyCfg);	/* As FIFO is full, make sure ISRs are enable	*/
							UART_RLS_R_EXCL(MyCfg, ii);	/* Release the exclusive access				*/
							SEMwaitBin(MyCfg->SemTX, UART_TOUT);	/* Posted when FIFO <= 1/2		*/
						}							/* The int handler will disable the TX ISRs		*/
					  #if (((UART_SLEEP) > 0) && ((OX_TIMER_US) && ((OX_TIMEOUT) > 0)))
						else {						/* Can only sleep if timeouts are available		*/
							TSKsleep(UART_SLEEP);	/* And authorized by the build option			*/
						}
					  #endif
					}
					UART_GET_F_EXCL(MyCfg, ii);		/* When requested to do local full protection	*/
				}									/* When while is done, may room in TX FIFO		*/
				if (WasAbort == 0) {				/* or may be there was an abort					*/
					UART_DATA_TX(MyCfg) = (uint32_t)ccc;
				}									/* If not access protected, may lose this write	*/
				UART_RLS_F_EXCL(MyCfg, ii);
			}										/* If not mutex protected, may drop, too bad	*/
		  #if ((UART_CIRC_BUF_TX) != 0)
			else {
				NextWrt = MyCfg->TXwrtIdx;			/* Need to check if next write location clashes	*/
				if (--NextWrt < 0) {				/* with reading as this is a buffer overflow	*/
					NextWrt = UART_CIRC_BUF_TX;
				}

				if (Wait == 0) {
					if (NextWrt == MyCfg->TXrdIdx) {/* No room in the circular buffer and requested	*/
						UART_GET_EXCL(MyCfg, ii);	/* Manual xfer in case ISR are turned off		*/
						UARTintTX(MyCfg);
						UART_RLS_EXCL(MyCfg, ii);
					}
					if (NextWrt == MyCfg->TXrdIdx) {/* If still no room, can't do nore				*/
						WasAbort = 1;
						break;
					}
				}
				while (NextWrt == MyCfg->TXrdIdx) {	/* Wait for room in the circular buffer			*/
					if ((MyCfg->TXsize != 0)		/* When ISRs are used							*/
					&&  (NoLock == 0)) { 			/* If can block, block on semaphore or sleep	*/
						UART_GET_R_EXCL(MyCfg, ii);	/* Get exclusive access (ISR disables TX		*/
						UART_TX_ENABLE(MyCfg);		/* As FIFO is full, make sure ISRs are enable	*/
						UART_RLS_R_EXCL(MyCfg, ii);	/* Release the exclusive access					*/
						SEMwaitBin(MyCfg->SemTX, UART_TOUT);
					}
					else {							/* Can't block, call the ISR handler manually	*/
					  #if (((UART_SLEEP) > 0) && ((OX_TIMER_US) && ((OX_TIMEOUT) > 0)))
						if (NoLock == 0) {			/* If can bloxk									*/
							TSKsleep(UART_SLEEP);	/* And authorized by the build option			*/
						}
					  #endif
						UART_GET_EXCL(MyCfg, ii);	/* No ISRs: manual call to the ISR handler		*/
						UARTintTX(MyCfg);
						UART_RLS_EXCL(MyCfg, ii);
					}
				}

				MyCfg->CBufTX[MyCfg->TXwrtIdx] = ccc;
				MyCfg->TXwrtIdx = NextWrt;

				if (MyCfg->TXsize == 0) {			/* ISRs are not used, must wait for all char	*/
					while(MyCfg->TXrdIdx != NextWrt) {/* to be out. Done manually					*/
						UART_GET_EXCL(MyCfg, ii);
						UARTintTX(MyCfg);
						UART_RLS_EXCL(MyCfg, ii);
					}
				}
			}
		  #elif ((UART_MAILBOX_TX) != 0)			/* This code only used when mailbox included	*/
			else {									/* Mailbox & ISRs								*/
				if (0 != MBXput(MyCfg->MboxTX, (intptr_t)ccc, 0)) {	/* Trying to fill the mailbox	*/
					UART_GET_R_EXCL(MyCfg, ii);		/* We'll fill until full, then will block		*/
					UART_TX_ENABLE(MyCfg);			/* Make sure TX ISRs are enabled				*/
					UART_RLS_R_EXCL(MyCfg, ii);		/* The ISR will empty the mailbox				*/
					if (0 != MBXput(MyCfg->MboxTX, (intptr_t)ccc, (NoLock != 0) ? 0 : Wait)) {
						if (Wait == 0) {			/* No room in the mailbox and requested to not	*/
							WasAbort = 1;			/* wait, so abort								*/
						}
						else {						/* Either ISRs disable or inside an interrupt	*/
							do {					/* the TX direction as we are doing it from here*/
								UART_GET_EXCL(MyCfg, ii);/* Get exclusive access (handler not reent)*/
								UARTintTX(MyCfg);	/* Direct call to the handler					*/
								Ret = MBXput(MyCfg->MboxTX, (intptr_t)ccc, 0);
								UART_RLS_EXCL(MyCfg, ii);	/* Release the exclusive access			*/
							} while (Ret != 0);		/* If mailbox still full, try again				*/
						}
					}
				}
			}
		  #endif

			if (WasAbort != 0) {					/* If there was an abort, rewind back before	*/
				UART_GET_F_EXCL(MyCfg, ii);			/* When requested to do local full protection	*/
				MyCfg->PendTX = PendTX;				/* filtering									*/
				UART_RLS_F_EXCL(MyCfg, ii);
				if (PendTX < 0) {
					Idx--;
				}
				break;								/* Exit the outer for() loop					*/
			}
			else if (MyCfg->TXsize != 0) {			/* Was able to put a character in mailbox		*/
				UART_GET_R_EXCL(MyCfg, ii);			/* so that means the TX ISR can pull it			*/
				UART_TX_ENABLE(MyCfg);				/* Exclusive access as ISR disable TX ISRs		*/
				UART_RLS_R_EXCL(MyCfg, ii);
			}
		}
	}

  #if ((UART_SINGLE_MUTEX) >= 0)					/* When mutexes are used for protection			*/
	if (NoLock == 0) {								/* Remove lock if was obtained					*/
		UART_MTX_UNLOCK(MyCfg);
	}
  #endif

	return(Idx);
}

/* ------------------------------------------------------------------------------------------------ */
/* FUNCTION: uart_init																				*/
/*																									*/
/* uart_init - initialize a UART controller															*/
/*																									*/
/* SYNOPSIS:																						*/
/*		int uart_init(int Dev int Baud, int Nbits, int Parity, int Stop, int RXsize,				*/
/*		              int TXsize, int Filter);														*/
/*																									*/
/* ARGUMENTS:																						*/
/*		Dev     : UART device number (on Arria V/10 & Cyclone V : 0->1)								*/
/*		Baud    : BaudRate to set																	*/
/*		Nbits   : Number of data bits (5->8)														*/
/*		Parity  : Parity																			*/
/*		          == 0 : none																		*/
/*		          +ve value: even parity bit														*/
/*		          -ve value:  odd parity bit														*/
/*		Stop    : Stop bit																			*/
/*		          == 10 : 1   stop bit																*/
/*		          == 15 : 1.5 stop bit																*/
/*		RXsize  : RX operating mode: Polling / Semaphore with ISRs / OS queue with ISRs				*/
/*				  -ve  : Blocking on a semaphore, uses ISRs											*/
/*		          == 0 : polling with sleep (when timeout available)								*/
/*		          +ve  : OS queue size, uses ISRs													*/
/*		TXsize  : TX operating mode: Polling / Semaphore with ISRs / OS queue with ISRs				*/
/*				  -ve  : Blocking on a semaphore, uses ISRs											*/
/*		          == 0 : polling with sleep (when timeout available)								*/
/*		          +ve  : OS queue size, uses ISRs													*/
/*		Filter  : Handling of \r, \n and \b (Is a set of bits OR any of the control masks)			*/
/*		          == 0 : do nothing																	*/
/*		          See #define of input & output character filtering control masks in "dw_uart.h"	*/
/*																									*/
/* RETURN VALUE:																					*/
/*		 0 : success																				*/
/*      -1 : error																					*/
/*																									*/
/* DESCRIPTION:																						*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */
#define TARGET_PBACLK_FREQ_HZ	FOSC0
#define USART					(&AVR32_USART1)
#define USART_RX_PIN			AVR32_USART1_RXD_0_0_PIN
#define USART_RX_FUNCTION		AVR32_USART1_RXD_0_0_FUNCTION
#define USART_TX_PIN			AVR32_USART1_TXD_0_0_PIN
#define USART_TX_FUNCTION		AVR32_USART1_TXD_0_0_FUNCTION


int uart_init(int Dev, int Baud, int Nbits, int Parity, int Stop, int RXsize, int TXsize, int Filter)
{
int        Error;
int        Error1;
UARTcfg_t *MyCfg;									/* De-reference array for faster access			*/
int        OSnotRdy;								/* If the OS is running or not					*/
int        ReMap;									/* Remapped "Dev" to index in g_UARTcfg[]		*/
int32_t    Temp;
int32_t    Temp1;


static const gpio_map_t USART_GPIO_MAP =       { {USART_RX_PIN, USART_RX_FUNCTION},
                                                 {USART_TX_PIN, USART_TX_FUNCTION}
                                               };

  #if ((UART_ARG_CHECK) == 0)
	ReMap = g_DevReMap[Dev];

  #else
	if ((Dev <0)									/* Device # must be within range to be valid	*/
	||  (Dev >= UART_MAX_DEVICES)) {
		return(-1);
	}

	ReMap = g_DevReMap[Dev];						/* The device must have a valid remapping		*/
	if (ReMap < 0) {								/* This is set by UART_LIST_DEVICE				*/
		return(-2);
	}

	if (g_CfgIsInit == 0) {							/* First time an init occurs, init globals		*/
		memset(&g_UARTcfg[0], 0, sizeof(g_UARTcfg));
		g_CfgIsInit = 1;							/* Globals are now OK							*/
	}
  #endif

	MyCfg    = &g_UARTcfg[ReMap];					/* This is this device configuration			*/
	OSnotRdy = (TSKmyID() == (TSK_t *)NULL);		/* Can't block or use MBOX if OS not started	*/

  #if ((UART_SINGLE_MUTEX) >= 0)
	if (OSnotRdy == 0) {							/* If mutexes are used, open once				*/
	  #if ((UART_SINGLE_MUTEX) > 0)					/* But make sure the OS is up and running		*/
		if (g_MyMutex == (MTX_t *)NULL) {
			g_MyMutex = MTXopen(NULL);
		}
	  #else
		if (MyCfg->Mutex == (MTX_t *)NULL) {
			MyCfg->Mutex = MTXopen(NULL);
		}
	  #endif
	}
  #endif

	if (OSnotRdy != 0) {							/* OS not yet running, can't create mailboxes	*/
		RXsize = 0;									/* or semaphores. Overload size parameters		*/
		TXsize = 0;
	}

  #if ((UART_MAILBOX_RX) != 0)						/* Deal with mailbox only if available			*/
	if (RXsize > 0) {								/* Create them only once in case re-init		*/
		if (MyCfg->MboxRX == (MBX_t *)NULL) {
			MyCfg->MboxRX = MBXopen(NULL, RXsize);
			MBXputInISR(MyCfg->MboxRX);				/* UART RX mailboxes need full/non-full in ISR	*/
		}
	}
  #else												/* Mailboxes not available, back to polling		*/
	if (RXsize > 0) {								/* If mailbox was requested, use polling or 	*/
		RXsize = -1;								/* circular buffers with semaphore				*/
	}
  #endif

  #if ((UART_MAILBOX_TX) != 0)
	if (TXsize > 0) {
		if (MyCfg->MboxTX == (MBX_t *)NULL) {
			MyCfg->MboxTX = MBXopen(NULL, TXsize);
		}
	}
  #else												/* Mailboxes not available, back to polling		*/
	if (TXsize > 0) {								/* If mailbox was requested, use polling or 	*/
		TXsize = -1;								/* circular buffer with semaphore				*/
	}
  #endif

  #if ((UART_CIRC_BUF_RX) != 0)
	MyCfg->RXrdIdx  = 0;
	MyCfg->RXwrtIdx = 0;
  #endif

  #if ((UART_CIRC_BUF_TX) != 0)
	MyCfg->TXrdIdx  = 0;
	MyCfg->TXwrtIdx = 0;
  #endif

	if (RXsize < 0) {								/* Request to use a semaphore for RX			*/
		if (MyCfg->SemRX == (SEM_t *)NULL) {
			MyCfg->SemRX = SEMopen(NULL);
		}
	}
	if (TXsize < 0) {								/* Request to use a semaphore for TX			*/
		if (MyCfg->SemTX == (SEM_t *)NULL) {
			MyCfg->SemTX = SEMopen(NULL);
		}
	}

	MyCfg->RXsize  = RXsize;						/* Memo sizes to know if using mailbox or not	*/
	MyCfg->TXsize  = TXsize;						/* The size of the mailboxes is not use per se	*/


  #if ((UART_MAILBOX_RX) != 0)
	MyCfg->PendINT = -1;							/* No pending char to deal with in the ISR		*/
  #endif
	MyCfg->Filter  = (unsigned int)Filter;			/* Memo the In/Out filtering operations			*/
	MyCfg->PendRX  = -1;							/* No In/Out pending characters					*/
	MyCfg->PendTX  = -1;

	MyCfg->HW = g_HWaddr[Dev];

	pcl_switch_to_osc(PCL_OSC0, FOSC0, OSC0_STARTUP);
  
	gpio_enable_module(USART_GPIO_MAP, sizeof(USART_GPIO_MAP)/sizeof(USART_GPIO_MAP[0]));

	MyCfg->HW[UART_MR_REG]   = 0;
	MyCfg->HW[UART_RTOR_REG] = 0; 
	MyCfg->HW[UART_TTGR_REG] = 0;
	MyCfg->HW[UART_CR_REG]   = (1U << 2)			/* Reset RX										*/
	                         | (1U << 3)			/* Reset TX										*/
	                         | (1U << 5)			/* Disable RX									*/
	                         | (1U << 7)			/* Disable TX									*/
	                         | (1U << 8);			/* Reset status bits							*/


	Temp  = (UART_CLK + (Baud/2))					/* Check using Over == 1						*/
	      / (Baud);									/* Temp is 8*CD + FP							*/
	Error = Baud									/* Error between desired & resulting clock		*/
	      - (UART_CLK / Temp);
	if (Error < 0) {
		Error = - Error;
	}
	if ((Temp < 8)									/* CD is bounded between 1 & 65535				*/
	||  (Temp > 8*65535)) {
		Error = 0x7FFFFFFF;
	}

	Temp1  = (UART_CLK + Baud)						/* Check with Over == 0							*/
	       / (2*Baud);								/* Temps is 8*CD + FP							*/
	Error1 = Baud									/* Error between desired & resulting clock		*/
	       - (UART_CLK / (2*Temp1));
	if (Error1 < 0) {
		Error1 = - Error1;
	}
	if ((Temp1 < 8)									/* CD is bounded between 1 & 65535				*/
	||  (Temp1 > 8*65535)) {
		Error1 = 0x7FFFFFFF;
	}

	if (Error < Error1) {							/* Select the Over that provides lowest error	*/
		MyCfg->HW[UART_BRGR_REG] =  (Temp >> 3)
		                         | ((Temp & 0x7) << 16);
		Temp = 1<< 19;								/* Over is 16 times over sampling				*/
	}
	else {
		MyCfg->HW[UART_BRGR_REG] =  (Temp1 >> 3)
		                         | ((Temp1 & 0x7) << 16);
		Temp = 0;									/* Over is 8 times oversampling					*/
	}

	Temp = 0;										/* Mode is normal								*/
	if (Nbits < 5) {
		Nbits = 5;
	}
	if (Nbits > 8) {
		Nbits = 8;
	}
	Temp |= (Nbits-5) << 6;

	if (Parity == 0) {								/* No parity									*/
		Temp |= 4 << 9;
	}
	else if (Parity < 0) {							/* Odd parity									*/
		Temp |= 1 << 9;
	}												/* Even parity is (0<<9), so nothing to do		*/

	if (Stop > 17) {								/* 2 stop bits									*/
		Temp |= 2 << 12;
	}
	else if (Stop > 12) {							/* 1.5 stop bit									*/
		Temp |= 1 << 12;
	}												/* 1 stop nbi tis 0, nothing to do				*/

	MyCfg->HW[UART_MR_REG] = Temp;
	MyCfg->HW[UART_CR_REG] = (1U << 4)				/* Enable RX									*/
	                       | (1U << 6);				/* Enable TX									*/
	
	MyCfg->IsInit = 1;								/* Is now initialized							*/

	if (RXsize != 0) {								/* Semaphore is in use							*/
		UART_GET_R_EXCL(MyCfg, ReMap);				/* Re-use ReMap for that						*/
		UART_RX_ENABLE(MyCfg);						/* Enable the RX interrupts for mailbox only	*/
		UART_RLS_R_EXCL(MyCfg, ReMap);				/* TX will be enable when using uart_send()		*/
	}

	return(0);
}

/* ------------------------------------------------------------------------------------------------ */
/* Interrupt handlers for the UART transfers														*/
/*																									*/
/* A common function is used for all the device, the device to handle is specified by the argument	*/
/* Quite straightforward processing, refer to the side comments										*/
/* The interrupt ID field is  not used as simply checking the RS & TX FIFO and put mailbox			*/
/* states is simpler and more efficient as it can deal with both interrupts raised at the same time	*/
/* The interrupt handler is split into RX & TX individual functions as the driver can also call		*/
/* a single direction handler. When the driver call one direction, the interrupts are disable in	*/
/* that direction, so that's why the state of the ISR (enable/disable) is checked when the handler	*/
/* is called from an interrupt to not go into conflict with the driver call							*/
/* ------------------------------------------------------------------------------------------------ */

  #define UART_INT_HNDL(Device)																		\
	void UARTintHndl_##Device(void)																	\
	{																								\
	  int ii;																						\
	  int ReMap;																					\
	  UARTcfg_t *MyCfg;																				\
		ReMap =  g_DevReMap[Device];																\
		MyCfg = &g_UARTcfg[ReMap];																	\
		UART_GET_EXCL(MyCfg, ii);																	\
		UARTintRX(MyCfg);							/* Driver will not call the handler directly*/	\
		UARTintTX(MyCfg);							/* So it's safe to call both directions		*/	\
		UART_RLS_EXCL(MyCfg, ii);																	\
		return;																						\
	}

/* ----------------------------------------------------------------------------------------------- */ 

static void UARTintRX(UARTcfg_t *IntCfg)
{
#if ((UART_CIRC_BUF_RX) != 0)
char Data;											/* Interim needed due to volatile warning		*/
int  NextWrt;										/* Next write index								*/
int  RdOri;											/* Read index unpon entry						*/
int  ToPost;										/* If has to post the semaphore					*/
int  WrtOri;										/* Write index upon entry						*/

	RdOri   = IntCfg->RXrdIdx;
	WrtOri  = IntCfg->RXwrtIdx;

	NextWrt = WrtOri-1;
	if (NextWrt < 0) {
		NextWrt = UART_CIRC_BUF_RX;
	}

	ToPost = 0;										/* Assume no semaphore posting					*/
	while ((IntCfg->RXrdIdx != NextWrt)				/* Make sure to not overflow circular buffer	*/
	&&     (!UART_RX_EMPTY(IntCfg))) {				/* Grab the RX data as long as FIFO not empty	*/
		Data = (char)UART_DATA_RX(IntCfg);
		IntCfg->CBufRX[IntCfg->RXwrtIdx] = Data;
		IntCfg->RXwrtIdx = NextWrt;					/* Keep updating for BG to be in-sync			*/
		if (--NextWrt < 0) {
			NextWrt = UART_CIRC_BUF_RX;
		}
		ToPost = 1;									/* One char put in buffer, may have to post		*/
	}

	if ((WrtOri == RdOri)							/* If the circ buffer was empty upon entry, the	*/
	&&  (ToPost != 0)								/* background may be waitng for semaphore now	*/
	&&  (IntCfg->RXsize != 0)) {					/* When RXsize == 0, semaphore not used			*/
		SEMpost(IntCfg->SemRX);
	}

	if (IntCfg->RXrdIdx == NextWrt) {				/* The circular buffer is full, disable the		*/
		UART_RX_DISABLE(IntCfg);					/* ISRs, they will be re-enable in uart_recv()	*/
	}

#else
 #if ((UART_MAILBOX_RX) != 0)						/* Mailboxes are available						*/
 intptr_t Data;										/* To read a mailbox with the proper data type	*/
 int      RetVal;									/* When sending to mailbox, result				*/
													/* Make sure we are using the RX mailboxes		*/
	if (IntCfg->RXsize > 0) {						/* First make sure there is room in the mailbox	*/
		RetVal = (IntCfg->MboxRX->Size <= IntCfg->MboxRX->Count);
		if (IntCfg->PendINT >= 0) {					/* Check if previous data read but not put in	*/
			Data   = (intptr_t)IntCfg->PendINT;		/* the mailbox (this is a safety mechanism)		*/
			RetVal = MBXput(IntCfg->MboxRX, Data, 0);	/* Try to put it in the mailbox				*/
			if (RetVal == 0) {						/* If was able to put in mailbox				*/
				IntCfg->PendINT = -1;				/* No more pending on hold						*/
			}
		}
		if (RetVal == 0) {							/* Pending mailbox write may have failed (0:OK)	*/
			while (! UART_RX_EMPTY(IntCfg)) {		/* Process as long as data in RX FIFO			*/
				Data   = (intptr_t)UART_DATA_RX(IntCfg);
				RetVal = MBXput(IntCfg->MboxRX, Data, 0);	/* Put in the mailbox. If could			*/
				if (RetVal != 0) {					/* not do it, keep char for next time			*/
					IntCfg->PendINT = (int)Data;	
					break;							/* If mailbox is full, we are done				*/
				}
			}
		}
		if (RetVal != 0) {							/* The mailbox is full, can't get anymore ISRs	*/
			UART_RX_DISABLE(IntCfg);				/* So disable the RX interrupts otherwise will	*/
		}											/* will be constantly interrupted				*/
	}												/* They will be re-enable in uart_recv()		*/
	else
#endif

	if (! UART_RX_EMPTY(IntCfg)) {					/* If data in RX FIFO, report to upper level	*/
		if (IntCfg->RXsize < 0) {					/* Using semaphore for RX direction				*/
			SEMpost(IntCfg->SemRX);
		}
		if (IntCfg->RXsize <= 0) {					/* When semaphore, disable RX interrupts		*/
			UART_RX_DISABLE(IntCfg);				/* Otherwise will be continuously interrupted	*/
		}											/* Also done for polling as polling should		*/
	}												/* never enable the interrupts					*/
#endif												/* uart_recv will re-enable when FIFO is empty	*/
	return;											/* uart_recv will re-enable when FIFO is empty	*/
}

/* ------------------------------------------------------------------------------------------------ */

static void UARTintTX(UARTcfg_t *IntCfg)
{
#if ((UART_CIRC_BUF_TX) != 0)
int NextWrt;										/* Next write index								*/
int RdNow;											/* Index where the next character to send is	*/
int RdOri;											/* Read index upon entry						*/
int ToPost;											/* If has to post the semaphore					*/
int WrtOri;

	RdNow  = IntCfg->TXrdIdx;
	RdOri  = RdNow;
	WrtOri = IntCfg->TXwrtIdx;

	ToPost = 0;
	while ((RdNow != WrtOri)						/* Send as long as data in the circular buffer	*/
	&&     (!UART_TX_FULL(IntCfg))){				/* and room in the UART TX FIFO					*/
		UART_DATA_TX(IntCfg) = (uint32_t)IntCfg->CBufTX[RdNow];
		if (--RdNow < 0) {
			RdNow = UART_CIRC_BUF_TX;
		}
		IntCfg->TXrdIdx = RdNow;					/* Keep updating to keep BG in-sync				*/
		ToPost = 1;									/* One char took from buffer, may have to post	*/
	}

	NextWrt = WrtOri;								/* Check if circular buffer wass full upon entry*/
	if (--NextWrt < 0) {
		NextWrt = UART_CIRC_BUF_TX;
	}

	if ((NextWrt == RdOri)							/* The circular buffer was full, post the		*/
	&&  (ToPost != 0)								/* semaphore only if room now in circ buffer	*/
	&&  (IntCfg->TXsize != 0)) {					/* When TXsize == 0, semaphore not used			*/
		SEMpost(IntCfg->SemTX);		
	}

	if (IntCfg->TXrdIdx == WrtOri) {				/* If circular buffer is empty, done with the	*/
		UART_TX_DISABLE(IntCfg);					/* ISRs, they will be re-enable in uart_send()	*/
	}

#else
 #if ((UART_MAILBOX_RX) != 0)						/* Mailboxes available							*/
intptr_t Data;										/* To read a mailbox with the proper data type	*/

	if (IntCfg->TXsize > 0) {						/* Make sure we are using the TX mailboxes		*/
		while (!UART_TX_FULL(IntCfg)) {				/* Process as long as room in the TX FIFO		*/
			if (0 == MBXget(IntCfg->MboxTX, &Data, 0)) {	/* Got something, send to UART			*/
				UART_DATA_TX(IntCfg) = (uint32_t)Data;
			}
			else {									/* If mailbox is empty: done. Disable TX ISRs	*/
				UART_TX_DISABLE(IntCfg);			/* They will be re-enable in uart_send()		*/
				break;								/* Break out of the loop: nothing more to send	*/
			}
		}
	}
	else
 #endif

	if (!UART_TX_FULL(IntCfg)) {					/* If room in TX FIFO, report to upper level	*/
		if (IntCfg->TXsize < 0) {					/* Using semaphore for TX direction				*/
			SEMpost(IntCfg->SemTX);
		}
		if (IntCfg->TXsize <= 0) {					/* When semaphore, disable TX interrupts		*/
			UART_TX_DISABLE(IntCfg);				/* Otherwise will be continuously interrupted	*/
		}											/* Also done for polling as polling should		*/
	}												/* never enable the interrupts					*/
#endif

	return;
}

/* ------------------------------------------------------------------------------------------------ */

#if (((UART_LIST_DEVICE) & 0x001) != 0U)
  UART_INT_HNDL(0)
#endif
#if (((UART_LIST_DEVICE) & 0x002) != 0U)
  UART_INT_HNDL(1)
#endif
#if (((UART_LIST_DEVICE) & 0x004) != 0U)
  UART_INT_HNDL(2)
#endif
#if (((UART_LIST_DEVICE) & 0x008) != 0U)
  UART_INT_HNDL(3)
#endif
#if (((UART_LIST_DEVICE) & 0x010) != 0U)
  UART_INT_HNDL(4)
#endif
#if (((UART_LIST_DEVICE) & 0x020) != 0U)
  UART_INT_HNDL(5)
#endif
#if (((UART_LIST_DEVICE) & 0x040) != 0U)
  UART_INT_HNDL(6)
#endif
#if (((UART_LIST_DEVICE) & 0x080) != 0U)
  UART_INT_HNDL(7)
#endif
#if (((UART_LIST_DEVICE) & 0x100) != 0U)
  UART_INT_HNDL(8)
#endif
#if (((UART_LIST_DEVICE) & 0x200) != 0U)
  UART_INT_HNDL(9)
#endif

#endif												/* ENDIF of UART_LIST_DEVICE == 0				*/

/* EOF */
