Christian
Published © LGPL

Fix Your Arduino UNO R4 UART Issues

Having UART communication issues? Serial Monitor now working? This fix is for you!

BeginnerFull instructions provided661
Fix Your Arduino UNO R4 UART Issues

Things used in this project

Hardware components

UNO R4 Minima
Arduino UNO R4 Minima
×1
UNO R4 WiFi
Arduino UNO R4 WiFi
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

serial.h

C/C++
Download and replace the following files in the Arduino15\packages\arduino\hardware\renesas_uno\1.2.0\Cores\Arduino folder.

Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
  Serial.h - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 28 September 2010 by Mark Sproul
  Modified 14 August 2012 by Alarus
  Modified 3 December 2013 by Matthijs Kooijman
*/

/*
  Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
  
  1. Ring Buffer not thread safe.
  2. Added Tx buffer.
  3. Removed TEIE.
  4. Both Hardware UARTS can be used at the same time.
  
  Modified 1 November 2024 by Christian Huygen
  www.zevendevelopment.com  
*/


#define _TIMEVAL_DEFINED
#define _SYS_SELECT_H

#include "Arduino.h"
#include "api/HardwareSerial.h"

#ifdef __cplusplus

#ifndef __ARDUINO_UART_IMPLEMENTATION__
#define __ARDUINO_UART_IMPLEMENTATION__

#include "r_sci_uart.h"
#include "r_uart_api.h"

#include "SafeRingBuffer.h"

#undef SERIAL_BUFFER_SIZE
//#define SERIAL_BUFFER_SIZE 512
// Need to add one because the SerialRingBuffer no longer uses _numItems
// This will make the Serial Ring Buffer Interrupt Safe.
// _numElems gets updated when a character is received in the Interrupt and also when you UART::read() *** CORRUPTION OF SafeRingBufferN ***
// The SerialRingBuffer updates the _head when a character is received in the Interrupt, but updates the _tail when you UART::read().
#define SERIAL_BUFFER_SIZE 64+1

#define MAX_UARTS    10

typedef enum {
  TX_STARTED,
  TX_STOPPED
} TxStatus_t;

namespace arduino {
	
template <int N>
class SerialRingBuffer   
{
  public:
    SerialRingBuffer() { clear(); }
	inline void clear() { _head = _tail = 0; }
	inline bool isEmpty() { return (_head == _tail); }
	inline bool isFull() 
	{
		int i = (_head + 1) % N;
		return (i == _tail);
	}
  bool store_char(uint8_t c)
  {
      int i = (_head + 1) % N;
      if (i == _tail) return false;
        
      _buffer[_head] = c;
      _head = i;
        
      return true;
  }
  int read_char()
	{
		if (isEmpty()) return -1;
		
		uint8_t c = _buffer[_tail];
		_tail = (_tail + 1) % N;
		
		return c;
	}
	int available() { return (N + _head - _tail) % N; }
	int peek()
	{
		if (isEmpty()) return -1;
		return _buffer[_tail];
	}
	
  private:
    volatile int _head, _tail;
	uint8_t _buffer[N];
};

}

class UART : public arduino::HardwareSerial {
  public:
    static UART *g_uarts[MAX_UARTS]; 
    static void WrapperCallback(uart_callback_args_t *p_args);

    UART(int _pin_tx, int _pin_rx, int pin_rts = -1, int pin_cts = -1);
    void begin(unsigned long);
    void begin(unsigned long, uint16_t config);
    void end();
    int available(void);
    int peek(void);
    int read(void);
    void flush(void);
    size_t write(uint8_t c);
    size_t write(uint8_t* c, size_t len);
    size_t write_raw(uint8_t* c, size_t len);
	void address(uint8_t c); 
	using Print::write; 
    operator bool(); // { return true; }

  private:          
    int                       tx_pin;
    int                       rx_pin;
    int                       rts_pin = -1;
    int                       cts_pin = -1;
    bool                      cfg_pins(int max_index);

    int                       channel;
    //arduino::SafeRingBufferN<SERIAL_BUFFER_SIZE> rxBuffer;
    //arduino::SafeRingBufferN<SERIAL_BUFFER_SIZE> txBuffer;
	arduino::SerialRingBuffer<SERIAL_BUFFER_SIZE> rxBuffer;
	arduino::SerialRingBuffer<SERIAL_BUFFER_SIZE> txBuffer;

    //volatile bool tx_done;

    sci_uart_instance_ctrl_t  uart_ctrl;
    uart_cfg_t                uart_cfg;
    baud_setting_t            uart_baud;
    sci_uart_extended_cfg_t   uart_cfg_extend;

    uart_ctrl_t*              get_ctrl() { return &uart_ctrl; }
    
    bool                      setUpUartIrqs(uart_cfg_t &cfg);

  protected:
    bool                      init_ok;
};

   
    
    
    


extern UART _UART1_;
extern UART _UART2_;
extern UART _UART3_;
extern UART _UART4_;
extern UART _UART5_;

#endif
#endif

serial.cpp

C/C++
Download and replace the following files in the Arduino15\packages\arduino\hardware\renesas_uno\1.2.0\Cores\Arduino folder.

Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
  Serial.cpp - wrapper over mbed RawSerial
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2018-2019 Arduino SA

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

/*
  Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
  
  1. Transmit is Blocking.
  2. Transmit Ring Buffer not Used.
  3. Ring Buffer is not Interrupt Safe.
  4. Both Hardware UARTS can be used at the same time.
  5. 9-bit Support.
  
  Modified 6 July 2024 by Christian Huygen
  www.zevendevelopment.com  
*/

#include "Arduino.h"
#include "Serial.h"
#include "IRQManager.h"


#ifdef Serial
#undef Serial
#endif

UART * UART::g_uarts[MAX_UARTS] = {nullptr};

void uart_callback(uart_callback_args_t __attribute((unused)) *p_args)
{
    /* This callback function is not used but it is referenced into 
       FSP configuration so that (for the moment it is necessary to keep it) */
}

/* -------------------------------------------------------------------------- */
void UART::WrapperCallback(uart_callback_args_t *p_args) {
/* -------------------------------------------------------------------------- */  

  uint32_t channel = p_args->channel;
  
  UART *uart_ptr = UART::g_uarts[channel];

  if(uart_ptr == nullptr) {
    return;
  }
  
  switch (p_args->event){
      case UART_EVENT_ERR_PARITY:
      case UART_EVENT_ERR_FRAMING:
      case UART_EVENT_ERR_OVERFLOW:
      case UART_EVENT_RX_COMPLETE: // This is called when all the "expected" data are received
      {
          break;
      }
      case UART_EVENT_TX_COMPLETE:
      {
          break;
      }
      case UART_EVENT_TX_DATA_EMPTY:
      {
        //uint8_t to_enqueue = uart_ptr->txBuffer.available() < uart_ptr->uart_ctrl.fifo_depth ? uart_ptr->txBuffer.available() : uart_ptr->uart_ctrl.fifo_depth;
        //while (to_enqueue) {
        //uart_ptr->tx_done = true;
        if (!uart_ptr->txBuffer.isEmpty()) 
            uart_ptr->uart_ctrl.p_reg->TDR = uart_ptr->txBuffer.read_char();
        uart_ptr->uart_ctrl.p_reg->SCR_b.TIE = 1;
        // Disable TEIE
        // DTC and DMAC activation is not possible with TEIE enabled.
        // See Table 28.25 of RA4M1 documentation
        // Left alone for possible I2C communications requirements
        //uart_ptr->uart_ctrl.p_reg->SCR_b.TEIE = 0;
        break;
      }
      case UART_EVENT_RX_CHAR:
      {
        //if (uart_ptr->rxBuffer.availableForStore()) {
        if (!uart_ptr->rxBuffer.isFull()) {
            uart_ptr->rxBuffer.store_char(p_args->data);
        }
        break;
      }
      case UART_EVENT_BREAK_DETECT:
      {
          break;
      }
  }
}


UART::UART(int _pin_tx, int _pin_rx, int _pin_rts, int _pin_cts):
  tx_pin(_pin_tx),
  rx_pin(_pin_rx),
  rts_pin(_pin_rts),
  cts_pin(_pin_cts),
  init_ok(false) {
/* -------------------------------------------------------------------------- */    
  uart_cfg.txi_irq = FSP_INVALID_VECTOR;
  uart_cfg.tei_irq = FSP_INVALID_VECTOR;
  uart_cfg.rxi_irq = FSP_INVALID_VECTOR;
  uart_cfg.eri_irq = FSP_INVALID_VECTOR;
}

/* -------------------------------------------------------------------------- */
bool UART::setUpUartIrqs(uart_cfg_t &cfg) {
/* -------------------------------------------------------------------------- */  
  bool rv = false;

  rv = IRQManager::getInstance().addPeripheral(IRQ_SCI_UART,&cfg);
  
  return rv;
} 

/* -------------------------------------------------------------------------- */
size_t UART::write(uint8_t c) {
/* -------------------------------------------------------------------------- */  
  if(init_ok) {
    // Interrupts are disabled because a Transmit Interrupt could have occured with one 
    // char in the buffer, and it is removed before we can store it, resulting in a missed
    // TDR and there will be no more TIE interrupts.
    noInterrupts();
    if (txBuffer.isEmpty() && uart_ctrl.p_reg->SSR_b.TDRE == 1) {
        interrupts();
        uart_ctrl.p_reg->SCR_b.TIE = 1;
        if (uart_cfg.data_bits == UART_DATA_BITS_9) uart_ctrl.p_reg->TDRHL = c;
        else uart_ctrl.p_reg->TDR = c;
        return 1;
    }
    
    if (txBuffer.isFull()) {
        interrupts();
        while(txBuffer.isFull());
    }
    txBuffer.store_char(c);
    interrupts();
/*  
    tx_done = false;
    R_SCI_UART_Write(&uart_ctrl, &c, 1);
    while (!tx_done) {} */
    return 1;
  }
  else {
    return 0;
  }
}

size_t  UART::write(uint8_t* c, size_t len) {
  size_t i = 0;

  if(init_ok) {
    while (i < len) {
      write(*(c+i));
      i++;
    }
/*  tx_done = false;
    R_SCI_UART_Write(&uart_ctrl, c, len);
    while (!tx_done) {} */
    return len; 
  }
  else {
    return 0;
  }
}

/* -------------------------------------------------------------------------- */
UART::operator bool() {
/* -------------------------------------------------------------------------- */  
    return true;
}

/* -------------------------------------------------------------------------- */
bool  UART::cfg_pins(int max_index) {
/* -------------------------------------------------------------------------- */  
  /* verify index are good */
  if(tx_pin < 0 || rx_pin < 0 || tx_pin >= max_index || rx_pin >= max_index) {
    return false;
  }
  /* getting configuration from table */
  auto cfgs_tx = getPinCfgs(tx_pin, PIN_CFG_REQ_UART_TX);
  auto cfgs_rx = getPinCfgs(rx_pin, PIN_CFG_REQ_UART_RX);

  uint16_t cfg_tx = 0;
  uint16_t cfg_rx = 0;

  /* Find the best combination */
  for (size_t i = 0; i < cfgs_tx.size(); i++) {
    for (size_t j = 0; j < cfgs_rx.size(); j++) {
      if (cfgs_tx[i] && cfgs_rx[i] && GET_CHANNEL(cfgs_tx[i]) == GET_CHANNEL(cfgs_rx[j])) {
        cfg_tx = cfgs_tx[i];
        cfg_rx = cfgs_rx[j];
        channel = GET_CHANNEL(cfg_tx);
        goto done;
      }
    }
  }

done:
  /* verify configuration are good */
  if(cfg_tx == 0 || cfg_rx == 0 ) {
    return false;
  }

  /* verify channel does not exceed max possible uart channels */
  if(channel >= MAX_UARTS) {
    return false;
  }
  /* setting channel */
  channel = GET_CHANNEL(cfg_tx);
  
  /* actually configuring PIN function */
  ioport_peripheral_t ioport_tx = USE_SCI_EVEN_CFG(cfg_tx) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9;
  ioport_peripheral_t ioport_rx = USE_SCI_EVEN_CFG(cfg_rx) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9;

  R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[tx_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_tx));
  R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[rx_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_rx));
  if (rts_pin != -1 && cts_pin != -1) {
    // hopefully people using flow control have read the datasheet so let's avoid the double check
    R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[rts_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_rx));
    R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[cts_pin].pin, (uint32_t) (IOPORT_CFG_PERIPHERAL_PIN | ioport_rx));
  }

  return true;
}

/* -------------------------------------------------------------------------- */
void UART::begin(unsigned long baudrate, uint16_t config) {
/* -------------------------------------------------------------------------- */  
  int max_index = PINS_COUNT;

  init_ok = cfg_pins(max_index);
  
  if(init_ok) {
    UART::g_uarts[channel]        = this;

    uart_baud.semr_baudrate_bits_b.abcse          = 0;
    uart_baud.semr_baudrate_bits_b.abcs           = 0;
    uart_baud.semr_baudrate_bits_b.bgdm           = 1;
    uart_baud.cks                                 = 0;
    uart_baud.brr                                 = 25;
    uart_baud.mddr                                = (uint8_t) 256;
    uart_baud.semr_baudrate_bits_b.brme           = false;

    uart_cfg_extend.clock                         = SCI_UART_CLOCK_INT;
    uart_cfg_extend.rx_edge_start                 = SCI_UART_START_BIT_FALLING_EDGE;
    uart_cfg_extend.noise_cancel                  = SCI_UART_NOISE_CANCELLATION_DISABLE;
    uart_cfg_extend.rx_fifo_trigger               = SCI_UART_RX_FIFO_TRIGGER_MAX;
    uart_cfg_extend.p_baud_setting                = &uart_baud;
    uart_cfg_extend.flow_control                  = SCI_UART_FLOW_CONTROL_RTS;
    uart_cfg_extend.flow_control_pin              = (bsp_io_port_pin_t) UINT16_MAX;
    if (rts_pin != -1 && cts_pin != -1) {
      uart_cfg_extend.flow_control                  = SCI_UART_FLOW_CONTROL_HARDWARE_CTSRTS;
    }
    uart_cfg_extend.rs485_setting.enable          = SCI_UART_RS485_DISABLE;
    uart_cfg_extend.rs485_setting.polarity        = SCI_UART_RS485_DE_POLARITY_HIGH;
    uart_cfg_extend.rs485_setting.de_control_pin  = (bsp_io_port_pin_t) UINT16_MAX;
    
    uart_cfg.channel                              = channel; 
    uart_cfg.p_context                            = NULL;
    uart_cfg.p_extend                             = &uart_cfg_extend;
    uart_cfg.p_transfer_tx                        = NULL;
    uart_cfg.p_transfer_rx                        = NULL;
  
    switch(config){
      case SERIAL_8N1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8N2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_8E1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8E2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_8O1:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_8O2:
          uart_cfg.data_bits = UART_DATA_BITS_8;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      // add 7 bit support
      case SERIAL_7N1:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_7N2:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_7E1:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_7E2:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_EVEN;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;
      case SERIAL_7O1:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
      case SERIAL_7O2:
          uart_cfg.data_bits = UART_DATA_BITS_7;
          uart_cfg.parity = UART_PARITY_ODD;
          uart_cfg.stop_bits = UART_STOP_BITS_2;
          break;          
       // add 9 bit support 9N1
      case SERIAL_9N1:
          uart_cfg.data_bits = UART_DATA_BITS_9;
          uart_cfg.parity = UART_PARITY_OFF;
          uart_cfg.stop_bits = UART_STOP_BITS_1;
          break;
    }
    
    uart_cfg.p_callback = UART::WrapperCallback;
  }
  else {
    return;
  }

  init_ok &= setUpUartIrqs(uart_cfg);
  
  fsp_err_t err;
  const bool bit_mod = true;
  const uint32_t err_rate = 3000; //means 3%

  err = R_SCI_UART_BaudCalculate(baudrate, bit_mod, err_rate, &uart_baud);
  if (uart_baud.mddr == 0) {
    err = R_SCI_UART_BaudCalculate(baudrate, false, err_rate, &uart_baud);
  }
  err = R_SCI_UART_Open (&uart_ctrl, &uart_cfg);
  if(err != FSP_SUCCESS) while(1);
  err = R_SCI_UART_BaudSet(&uart_ctrl, (void *) &uart_baud);
  if(err != FSP_SUCCESS) while(1);

  rxBuffer.clear();
  txBuffer.clear();
}

/* -------------------------------------------------------------------------- */
void UART::begin(unsigned long baudrate) {
/* -------------------------------------------------------------------------- */  
  begin(baudrate, SERIAL_8N1);
}

/* -------------------------------------------------------------------------- */
void UART::end() {
/* -------------------------------------------------------------------------- */  
  rxBuffer.clear();
  txBuffer.clear();
  R_SCI_UART_Close (&uart_ctrl);
}

/* -------------------------------------------------------------------------- */
int UART::available() {
/* -------------------------------------------------------------------------- */  
  return rxBuffer.available();
}

/* -------------------------------------------------------------------------- */
int UART::peek() {
/* -------------------------------------------------------------------------- */  
  return rxBuffer.peek();
}

/* -------------------------------------------------------------------------- */
int UART::read() {
/* -------------------------------------------------------------------------- */  
  return  rxBuffer.read_char();
}

/* -------------------------------------------------------------------------- */
void UART::flush() {
/* -------------------------------------------------------------------------- */  
  //while(txBuffer.available());
  // Wait for queue to empty and TDR to be sent to RSR
  while (!txBuffer.isEmpty() && uart_ctrl.p_reg->SSR_b.TDRE == 0);
}

/* -------------------------------------------------------------------------- */
size_t UART::write_raw(uint8_t* c, size_t len) {
/* -------------------------------------------------------------------------- */
  size_t i = 0;
  while (i < len) {
    uart_ctrl.p_reg->TDR = *(c+i);
    while (uart_ctrl.p_reg->SSR_b.TEND == 0) {}
    i++;
  }
  return len;
}

/* -------------------------------------------------------------------------- */
void UART::address(uint8_t c) {
/* -------------------------------------------------------------------------- */
  // 9-bit set for address
  flush();
  uart_ctrl.p_reg->TDRHL = 0x100 + c;
  // Wait for address to be sent so next write will clear out the address bit
  while (uart_ctrl.p_reg->SSR_b.TDRE == 0);
}

IRQManager.cpp

C/C++
Download and replace the following files in the Arduino15\packages\arduino\hardware\renesas_uno\1.2.0\Cores\Arduino folder.

Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
  Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
  
  1. Ring Buffer not thread safe.
  2. Added Tx buffer.
  3. Removed TEIE.
  4. Both Hardware UARTS can be used at the same time.
  
  Modified 6 July 2024 by Christian Huygen
  www.zevendevelopment.com  
*/

#include "IRQManager.h"
#include "bsp_api.h"

#define FIXED_IRQ_NUM   16


#define PROG_IRQ_NUM    BSP_ICU_VECTOR_MAX_ENTRIES //32

#define ETHERNET_PRIORITY          12
#define SDCARD_ACCESS_PRIORITY     10
#define SDCARD_DMA_REQ_PRIORITY    10
#define SDCARD_CARD_PRIORITY       12
#define EXTERNAL_PIN_PRIORITY      12
// UART Priority needs to be lower than USB so you can run both Serial and Serial1 at the same time
#define UART_SCI_PRIORITY          10 // 12
#define USB_PRIORITY               12
#define AGT_PRIORITY               14
#define RTC_PRIORITY               12
#define I2C_MASTER_PRIORITY        12
#define I2C_SLAVE_PRIORITY         12
#define SPI_MASTER_PRIORITY        6
#define DMA_PRIORITY               12
#define TIMER_PRIORITY             8
#define ADC_PRIORITY               12
#define CAN_PRIORITY               12
#define CANFD_PRIORITY             12
#define I2S_PRIORITY               12
#define FIRST_INT_SLOT_FREE         0

IRQManager::IRQManager() : last_interrupt_index{0} {

}

IRQManager::~IRQManager() {

}

IRQManager& IRQManager::getInstance() {
    static IRQManager    instance;
    return instance;
}

bool IRQManager::addGenericInterrupt(GenericIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/){
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = false;
    
    if((cfg.irq == FSP_INVALID_VECTOR) && (last_interrupt_index < PROG_IRQ_NUM)) {
    	if(fnc != nullptr){
    		R_ICU->IELSR[last_interrupt_index] = cfg.event;
    		*(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
    		R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
    		R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
    		NVIC_SetPriority((IRQn_Type)last_interrupt_index, cfg.ipl);
    		R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
    		cfg.irq = (IRQn_Type)last_interrupt_index;
    		last_interrupt_index++;
    		rv = true;
    	}
    }
	return rv;
}

bool IRQManager::addADCScanEnd(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    if (last_interrupt_index >= PROG_IRQ_NUM){
        rv = false;
    }
    else if (adc->cfg.scan_end_irq == FSP_INVALID_VECTOR) {
        if(set_adc_end_link_event(last_interrupt_index, adc->cfg.unit)) {
            adc->cfg.scan_end_ipl = TIMER_PRIORITY;
            adc->cfg.scan_end_irq = (IRQn_Type)last_interrupt_index;
            
            if(fnc == nullptr) {
                *(irq_ptr + last_interrupt_index) = (uint32_t)adc_scan_end_isr;
            }
            else {
                *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
            }
            last_interrupt_index++;
        }
    }
    else {
        if(adc->cfg.scan_end_irq == FSP_INVALID_VECTOR) {
            rv = false;
        }
        else {
            rv = true;
        }
    }
    return rv;
}



bool IRQManager::addADCScanEndB(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    if (last_interrupt_index >= PROG_IRQ_NUM){
        rv = false;
    }
    else if (adc->cfg.scan_end_b_irq == FSP_INVALID_VECTOR) {
        if(set_adc_end_b_link_event(last_interrupt_index, adc->cfg.unit)) {
            adc->cfg.scan_end_b_ipl = TIMER_PRIORITY;
            adc->cfg.scan_end_b_irq = (IRQn_Type)last_interrupt_index;
            
            if(fnc == nullptr) {
                *(irq_ptr + last_interrupt_index) = (uint32_t)adc_scan_end_b_isr;
            }
            else {
                *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
            }
            last_interrupt_index++;
        }
    }
    return rv;
}

bool IRQManager::addADCWinCmpA(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    if (last_interrupt_index >= PROG_IRQ_NUM){
        rv = false;
    }
    else if( ((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_a_irq == FSP_INVALID_VECTOR) {
        if(set_adc_win_a_link_event(last_interrupt_index, adc->cfg.unit)) {
            ((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_a_ipl = TIMER_PRIORITY;
            ((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_a_irq = (IRQn_Type)last_interrupt_index;
            
            if(fnc == nullptr) {
                *(irq_ptr + last_interrupt_index) = (uint32_t)adc_window_compare_isr;
            }
            else {
                *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
            }
            last_interrupt_index++;
        }
    }
    return rv;

}

bool IRQManager::addADCWinCmpB(ADC_Container *adc, Irq_f fnc /*= nullptr*/) {
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    if (last_interrupt_index >= PROG_IRQ_NUM){
        rv = false;
    }
    else if (((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_b_irq == FSP_INVALID_VECTOR) {
        if(set_adc_win_b_link_event(last_interrupt_index, adc->cfg.unit)) {
            ((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_b_ipl = TIMER_PRIORITY;
            ((adc_extended_cfg_t *)(adc->cfg.p_extend))->window_b_irq = (IRQn_Type)last_interrupt_index;
            
            if(fnc == nullptr) {
                *(irq_ptr + last_interrupt_index) = (uint32_t)adc_window_compare_isr;
            }
            else {
                *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
            }
            last_interrupt_index++;
        }
    }
    return rv;

}

/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerOverflow(TimerIrqCfg_t &cfg, Irq_f fnc /* = nullptr */) {
/* -------------------------------------------------------------------------- */    
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    if (last_interrupt_index >= PROG_IRQ_NUM){
        rv = false;
    }
    else if (cfg.base_cfg->cycle_end_irq == FSP_INVALID_VECTOR) {
        if(cfg.gpt_ext_cfg != nullptr) {
            if(set_gpt_over_link_event(last_interrupt_index, cfg.base_cfg->channel)) {
                cfg.base_cfg->cycle_end_ipl = TIMER_PRIORITY;
                cfg.base_cfg->cycle_end_irq = (IRQn_Type)last_interrupt_index;
                /* that is a GPT timer */
                if(fnc == nullptr) {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)gpt_counter_overflow_isr;
                }
                else {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
                }
                last_interrupt_index++;
            }
        }
        else if(cfg.agt_ext_cfg != nullptr) {
            /* DOUBT: is EVENT_AGT0_INT Overflow?? */
            if(set_agt_link_event(last_interrupt_index, cfg.base_cfg->channel)) {
                cfg.base_cfg->cycle_end_ipl = TIMER_PRIORITY;
                cfg.base_cfg->cycle_end_irq = (IRQn_Type)last_interrupt_index;
                /* that is a AGT timer */
                if(fnc == nullptr) {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)agt_int_isr;
                }
                else {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
                }
                last_interrupt_index++;
            }
        }
        else {
            rv = false;
        }
    }
    return rv;
}

/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerUnderflow(TimerIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/) {
/* -------------------------------------------------------------------------- */ 
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    
    if((cfg.agt_ext_cfg != nullptr) || (last_interrupt_index >= PROG_IRQ_NUM)) {
        /* not supported for AGT  */
        rv = false;
    }
    else if(cfg.gpt_ext_cfg != nullptr && cfg.gpt_ext_cfg->p_pwm_cfg != nullptr) {
        if (cfg.gpt_ext_cfg->p_pwm_cfg->trough_irq == FSP_INVALID_VECTOR) {
            if(set_gpt_under_link_event(last_interrupt_index, cfg.base_cfg->channel)){
                ((gpt_extended_pwm_cfg_t *)(cfg.gpt_ext_cfg->p_pwm_cfg))->trough_ipl = TIMER_PRIORITY;
                ((gpt_extended_pwm_cfg_t *)(cfg.gpt_ext_cfg->p_pwm_cfg))->trough_irq = (IRQn_Type)last_interrupt_index;
                if(fnc == nullptr) {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)gpt_counter_underflow_isr;
                }
                else {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
                }
                last_interrupt_index++;
            }
        }
    }
    else {
        rv = false;
    }
    return rv;   
}

/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerCompareCaptureA(TimerIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/) {
/* -------------------------------------------------------------------------- */    
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    
    if((cfg.agt_ext_cfg != nullptr) || (last_interrupt_index >= PROG_IRQ_NUM)) {
        /* not supported for AGT  */
        rv = false;
    }
    else if(cfg.gpt_ext_cfg != nullptr ) {
        if (cfg.gpt_ext_cfg->capture_a_irq == FSP_INVALID_VECTOR) {
            if(set_gpt_compare_capture_A_link_event(last_interrupt_index, cfg.base_cfg->channel)){
                cfg.gpt_ext_cfg->capture_a_ipl = TIMER_PRIORITY;
                cfg.gpt_ext_cfg->capture_a_irq = (IRQn_Type)last_interrupt_index;
                if(fnc == nullptr) {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)gpt_capture_a_isr;
                }
                else {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
                }
                last_interrupt_index++;
            }
        }
    }
    else {
        rv = false;
    }
    return rv;   
}

/* -------------------------------------------------------------------------- */
bool IRQManager::addTimerCompareCaptureB(TimerIrqCfg_t &cfg, Irq_f fnc /*= nullptr*/) {
/* -------------------------------------------------------------------------- */
   /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    
    if((cfg.agt_ext_cfg != nullptr) || (last_interrupt_index >= PROG_IRQ_NUM)) {
        /* not supported for AGT  */
        rv = false;
    }
    else if(cfg.gpt_ext_cfg != nullptr ) {
        if (cfg.gpt_ext_cfg->capture_b_irq == FSP_INVALID_VECTOR) {
            if(set_gpt_compare_capture_B_link_event(last_interrupt_index, cfg.base_cfg->channel)){
                cfg.gpt_ext_cfg->capture_b_ipl = TIMER_PRIORITY;
                cfg.gpt_ext_cfg->capture_b_irq = (IRQn_Type)last_interrupt_index;
                if(fnc == nullptr) {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)gpt_capture_b_isr;
                }
                else {
                    *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
                }
                last_interrupt_index++;
            }
        }
    }
    else {
        rv = false;
    }
    return rv;   
}

#ifdef HAS_DMAC
/* -------------------------------------------------------------------------- */
bool IRQManager::addDMA(dmac_extended_cfg_t &cfg, Irq_f fnc /* = nullptr */) {
/* -------------------------------------------------------------------------- */    
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;
    if (last_interrupt_index >= PROG_IRQ_NUM){
        rv = false;
    }
    else if (cfg.irq == FSP_INVALID_VECTOR) {
        /* to check correctness of the channel */
        if(set_dma_link_event(last_interrupt_index, cfg.channel)) {
            cfg.ipl = DMA_PRIORITY;
            cfg.irq = (IRQn_Type)last_interrupt_index;
            if(fnc == nullptr) {
                *(irq_ptr + last_interrupt_index) = (uint32_t)dmac_int_isr;
            }
            else {
                *(irq_ptr + last_interrupt_index) = (uint32_t)fnc;
            }
            last_interrupt_index++;
        }
        else {
            rv = false;
        }
    }
    return rv;
}
#endif

/* -------------------------------------------------------------------------- */
bool IRQManager::addPeripheral(Peripheral_t p, void *cfg) {
/* -------------------------------------------------------------------------- */    
    /* getting the address of the current location of the irq vector table */
    volatile uint32_t *irq_ptr = (volatile uint32_t *)SCB->VTOR;
    /* set the displacement to the "programmable" part of the table */
    irq_ptr += FIXED_IRQ_NUM;
    bool rv = true;

    if(last_interrupt_index >= PROG_IRQ_NUM){
        rv = false;
        goto end_config;
    }

    __disable_irq();
    /* **********************************************************************
                                      USB
       ********************************************************************** */
    if(p == IRQ_USB && cfg != NULL) {
        USBIrqCfg_t *irqcfg = (USBIrqCfg_t *)cfg;

        if (irqcfg->first_irq_number != FSP_INVALID_VECTOR) {
            // already configured, return
            goto end_config;
        }

        /* configuring USB interrupts */
        /* in case of USB which does not use any FSP API the cfg contains the 
           only interrupt handler function used */
        if( (last_interrupt_index +  irqcfg->num_of_irqs_required ) < PROG_IRQ_NUM ) {

            #ifdef ELC_EVENT_USBFS_INT
            /* USBFS INT (USBFS interrupt) */
            *(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_INT);
            R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
            R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
            NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
            R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
            irqcfg->first_irq_number = last_interrupt_index;
            last_interrupt_index++;
            #endif

            #ifdef ELC_EVENT_USBFS_RESUME
            /* USBFS RESUME (USBFS resume interrupt) */
            *(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_RESUME);
            R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
            R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
            NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
            R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
            last_interrupt_index++;
            #endif

            #ifdef ELC_EVENT_USBFS_FIFO_0
            /* USBFS FIFO 0 (DMA transfer request 0) */
            *(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_FIFO_0);
            R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
            R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
            NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
            R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
            last_interrupt_index++;
            #endif

            #ifdef ELC_EVENT_USBFS_FIFO_1
            /* USBFS FIFO 1 (DMA transfer request 1) */
            *(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBFS_FIFO_1);
            R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
            R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
            NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
            R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
            last_interrupt_index++;
            #endif
        }
        else {
            rv = false;
        }
    }

    else if(p == IRQ_USB_HS && cfg != NULL) {
        USBIrqCfg_t *irqcfg = (USBIrqCfg_t *)cfg;

        if (irqcfg->first_irq_number != FSP_INVALID_VECTOR) {
            // already configured, return
            goto end_config;
        }

        /* configuring USB interrupts */
        /* in case of USB which does not use any FSP API the cfg contains the 
           only interrupt handler function used */
        if( (last_interrupt_index +  irqcfg->num_of_irqs_required ) < PROG_IRQ_NUM ) {

            #ifdef ELC_EVENT_USBHS_USB_INT_RESUME
            /* USBHS INT (USBFS interrupt) */
            *(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBHS_USB_INT_RESUME);
            R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
            R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
            NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
            R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
            irqcfg->first_irq_number = last_interrupt_index;
            last_interrupt_index++;
            #endif

            #ifdef ELC_EVENT_USBHS_FIFO_0
            /* USBFS FIFO 0 (DMA transfer request 0) */
            *(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBHS_FIFO_0);
            R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
            R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
            NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
            R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
            last_interrupt_index++;
            #endif

            #ifdef ELC_EVENT_USBHS_FIFO_1
            /* USBFS FIFO 1 (DMA transfer request 1) */
            *(irq_ptr + last_interrupt_index) = (uint32_t)irqcfg->address_of_handler;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_USBHS_FIFO_1);
            R_BSP_IrqDisable((IRQn_Type)last_interrupt_index);
            R_BSP_IrqStatusClear((IRQn_Type)last_interrupt_index);
            NVIC_SetPriority((IRQn_Type)last_interrupt_index, USB_PRIORITY);
            R_BSP_IrqEnable ((IRQn_Type)last_interrupt_index);
            last_interrupt_index++;
            #endif
        } else {
            rv = false;
        }
    }

    /* **********************************************************************
                                      AGT
       ********************************************************************** */
    else if(p == IRQ_AGT && cfg != NULL) {
        timer_cfg_t *p_cfg = (timer_cfg_t *)cfg;
        if (p_cfg->cycle_end_irq == FSP_INVALID_VECTOR) {
            p_cfg->cycle_end_ipl = AGT_PRIORITY;
            p_cfg->cycle_end_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)agt_int_isr;
            set_agt_link_event(last_interrupt_index, p_cfg->channel);
            last_interrupt_index++;
        }
    }
    /* **********************************************************************
                                      UART
       ********************************************************************** */
    else if(p == IRQ_SCI_UART && cfg != NULL) {
        uart_cfg_t *p_cfg = (uart_cfg_t *)cfg;
        
        if (p_cfg->txi_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + UART_INTERRUPT_COUNT > PROG_IRQ_NUM){
                rv = false;
                goto end_config;
            }
            /* TX interrupt */
            p_cfg->txi_ipl = UART_SCI_PRIORITY;
            p_cfg->txi_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_txi_isr;
            set_sci_tx_link_event(last_interrupt_index, p_cfg->channel);
            last_interrupt_index++;

            /* TX-ERROR interrupt */
            p_cfg->tei_ipl = UART_SCI_PRIORITY;
            p_cfg->tei_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_tei_isr;
            set_sci_tei_link_event(last_interrupt_index, p_cfg->channel);
            last_interrupt_index++;

            /* RX interrupt */
            p_cfg->rxi_ipl = UART_SCI_PRIORITY;
            p_cfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_rxi_isr;
            set_sci_rx_link_event(last_interrupt_index, p_cfg->channel);
            last_interrupt_index++;

            /* RX-ERROR interrupt */
            p_cfg->eri_ipl = UART_SCI_PRIORITY;
            p_cfg->eri_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_uart_eri_isr;
            set_sci_eri_link_event(last_interrupt_index, p_cfg->channel);
            last_interrupt_index++;
        }
        R_BSP_IrqEnable (p_cfg->txi_irq);
        R_BSP_IrqEnable (p_cfg->tei_irq);
        R_BSP_IrqEnable (p_cfg->rxi_irq);
        R_BSP_IrqEnable (p_cfg->eri_irq);
    }
    /* **********************************************************************
                                      RTC
       ********************************************************************** */
#if RTC_HOWMANY > 0
    else if(p == IRQ_RTC && cfg != NULL) {
        RTCIrqCfg_t *p_cfg = (RTCIrqCfg_t *)cfg;

        /* rtc interrupts are added once a time and not all three together */

        if(p_cfg->req == RTC_ALARM) {
            if (p_cfg->cfg->alarm_irq == FSP_INVALID_VECTOR) {
                p_cfg->cfg->alarm_ipl = RTC_PRIORITY;
                p_cfg->cfg->alarm_irq = (IRQn_Type)last_interrupt_index;
                *(irq_ptr + last_interrupt_index) = (uint32_t)rtc_alarm_periodic_isr;
                R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_RTC_ALARM);
                R_BSP_IrqCfg(p_cfg->cfg->alarm_irq, p_cfg->cfg->alarm_ipl, p_cfg->ctrl);
                last_interrupt_index++;
            }
            R_BSP_IrqEnable (p_cfg->cfg->alarm_irq);

        }
        else if(p_cfg->req == RTC_PERIODIC) {
            if (p_cfg->cfg->periodic_irq == FSP_INVALID_VECTOR) {
                p_cfg->cfg->periodic_ipl = RTC_PRIORITY;
                p_cfg->cfg->periodic_irq = (IRQn_Type)last_interrupt_index;
                *(irq_ptr + last_interrupt_index) = (uint32_t)rtc_alarm_periodic_isr;
                R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_RTC_PERIOD);
                R_BSP_IrqCfg(p_cfg->cfg->periodic_irq, p_cfg->cfg->periodic_ipl, p_cfg->ctrl);
                last_interrupt_index++;
            }
            R_BSP_IrqEnable (p_cfg->cfg->periodic_irq);

        }
        else if(p_cfg->req == RTC_CARRY) {
            if (p_cfg->cfg->carry_irq == FSP_INVALID_VECTOR) {
                p_cfg->cfg->carry_ipl = RTC_PRIORITY;
                p_cfg->cfg->carry_irq = (IRQn_Type)last_interrupt_index;
                *(irq_ptr + last_interrupt_index) = (uint32_t)rtc_carry_isr;
                R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_RTC_CARRY);
                R_BSP_IrqCfg(p_cfg->cfg->carry_irq, p_cfg->cfg->carry_ipl, p_cfg->ctrl);
                last_interrupt_index++;
            }
            R_BSP_IrqEnable (p_cfg->cfg->carry_irq);
        }
        else {
            rv = false;
        }
    }
#endif

#if WIRE_HOWMANY > 0
    /* I2C true NOT SCI */
    else if(p == IRQ_I2C_MASTER && cfg != NULL) {       

        I2CIrqReq_t *p_cfg = (I2CIrqReq_t *)cfg;
        i2c_master_cfg_t *mcfg = (i2c_master_cfg_t *)p_cfg->mcfg;
        i2c_slave_cfg_t *scfg = (i2c_slave_cfg_t *)p_cfg->scfg;
        mcfg->ipl = I2C_MASTER_PRIORITY;
        
        if (mcfg->txi_irq  == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + WIRE_MASTER_INTERRUPT_COUNT > PROG_IRQ_NUM){
                rv = false;
                goto end_config;
            } 
            /* TX interrupt */
            mcfg->txi_irq = (IRQn_Type)last_interrupt_index;
            scfg->txi_irq = (IRQn_Type)last_interrupt_index;
            set_iic_tx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;

            /* RX interrupt */
            mcfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            scfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            set_iic_rx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;

            /* TX ERROR interrupt */
            mcfg->tei_irq = (IRQn_Type)last_interrupt_index;
            scfg->tei_irq = (IRQn_Type)last_interrupt_index;
            set_iic_tei_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;

            /* RX ERROR interrupt */
            mcfg->eri_irq = (IRQn_Type)last_interrupt_index;
            scfg->eri_irq = (IRQn_Type)last_interrupt_index;
            set_iic_eri_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;
        }
        
        *(irq_ptr + mcfg->txi_irq) = (uint32_t)iic_master_txi_isr;
        *(irq_ptr + mcfg->rxi_irq) = (uint32_t)iic_master_rxi_isr;
        *(irq_ptr + mcfg->tei_irq) = (uint32_t)iic_master_tei_isr;
        *(irq_ptr + mcfg->eri_irq) = (uint32_t)iic_master_eri_isr;

        R_BSP_IrqEnable (mcfg->txi_irq);
        R_BSP_IrqEnable (mcfg->rxi_irq);
        R_BSP_IrqEnable (mcfg->tei_irq);
        R_BSP_IrqEnable (mcfg->eri_irq);
    }
    /* I2C SCI MASTER (only) */
    else if(p == IRQ_SCI_I2C_MASTER && cfg != NULL) {      
        I2CIrqReq_t *p_cfg = (I2CIrqReq_t *)cfg;
        i2c_master_cfg_t *mcfg = (i2c_master_cfg_t *)p_cfg->mcfg;
        mcfg->ipl = I2C_MASTER_PRIORITY;
        if (mcfg->txi_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + WIRE_SCI_MASTER_INTERRUPT_COUNT > PROG_IRQ_NUM) {
                rv = false;
                goto end_config;
            }
            /* TX interrupt */
            mcfg->txi_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_txi_isr;
            set_sci_tx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;

            /* RX interrupt */
            mcfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_rxi_isr;
            set_sci_rx_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;

            /* TX ERROR interrupt */
            mcfg->tei_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_tei_isr;
            set_sci_tei_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;

            /* RX ERROR interrupt */
            #if 0
            mcfg->eri_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_i2c_eri_isr;
            set_sci_eri_link_event(last_interrupt_index, p_cfg->mcfg->channel);
            R_BSP_IrqCfg((IRQn_Type)last_interrupt_index, I2C_MASTER_PRIORITY, mcfg);
            last_interrupt_index++;
            #endif
        }
        R_BSP_IrqEnable (mcfg->txi_irq);
        R_BSP_IrqEnable (mcfg->rxi_irq);
        R_BSP_IrqEnable (mcfg->tei_irq);
        #if 0
        R_BSP_IrqEnable (mcfg->eri_irq);
        #endif
    }
    else if(p == IRQ_I2C_SLAVE && cfg != NULL) {
        I2CIrqReq_t *p_cfg = (I2CIrqReq_t *)cfg;
        i2c_master_cfg_t *mcfg = (i2c_master_cfg_t *)p_cfg->mcfg;
        i2c_slave_cfg_t *scfg = (i2c_slave_cfg_t *)p_cfg->scfg;
        scfg->ipl = I2C_SLAVE_PRIORITY;
        scfg->eri_ipl = I2C_SLAVE_PRIORITY;

        if (scfg->txi_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + WIRE_SLAVE_INTERRUPT_COUNT > PROG_IRQ_NUM) {
                rv = false;
                goto end_config;
            }
            /* TX interrupt */
            mcfg->txi_irq = (IRQn_Type)last_interrupt_index;
            scfg->txi_irq = (IRQn_Type)last_interrupt_index;
            set_iic_tx_link_event(last_interrupt_index, scfg->channel);
            last_interrupt_index++;

            /* RX interrupt */
            scfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            mcfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            set_iic_rx_link_event(last_interrupt_index, scfg->channel);
            last_interrupt_index++;

            /* TEI interrupt */
            scfg->tei_irq = (IRQn_Type)last_interrupt_index;
            mcfg->tei_irq = (IRQn_Type)last_interrupt_index;
            set_iic_tei_link_event(last_interrupt_index, scfg->channel);
            last_interrupt_index++;

            /* ERI interrupt */
            scfg->eri_irq = (IRQn_Type)last_interrupt_index;
            mcfg->eri_irq = (IRQn_Type)last_interrupt_index;
            set_iic_eri_link_event(last_interrupt_index, scfg->channel);
            last_interrupt_index++;
        }
        *(irq_ptr + scfg->txi_irq) = (uint32_t)iic_slave_txi_isr;
        *(irq_ptr + scfg->rxi_irq) = (uint32_t)iic_slave_rxi_isr;
        *(irq_ptr + scfg->tei_irq) = (uint32_t)iic_slave_tei_isr;
        *(irq_ptr + scfg->eri_irq) = (uint32_t)iic_slave_eri_isr;
        R_BSP_IrqEnable (scfg->txi_irq);
        R_BSP_IrqEnable (scfg->rxi_irq);
        R_BSP_IrqEnable (scfg->tei_irq);
        R_BSP_IrqEnable (scfg->eri_irq);

    }
#endif

#if EXT_INTERRUPTS_HOWMANY > 0
    /* **********************************************************************
                             PIN EXTERNAL INTERRUPT
       ********************************************************************** */
    else if(p == IRQ_EXTERNAL_PIN && cfg != NULL) {
        external_irq_cfg_t *p_cfg = (external_irq_cfg_t *)cfg;
        if (p_cfg->irq == FSP_INVALID_VECTOR) {
            p_cfg->ipl = EXTERNAL_PIN_PRIORITY;
            p_cfg->irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)r_icu_isr;
            set_ext_link_event(last_interrupt_index, p_cfg->channel);
            last_interrupt_index++;
        }
    }
#endif

#if SPI_HOWMANY > 0
    /* **********************************************************************
                                      SPI MASTER
       ********************************************************************** */
    else if(p == IRQ_SPI_MASTER && cfg != NULL) {      
        spi_instance_ctrl_t * p_ctrl = reinterpret_cast<SpiMasterIrqReq_t *>(cfg)->ctrl;
        spi_cfg_t  * p_cfg  = reinterpret_cast<SpiMasterIrqReq_t *>(cfg)->cfg;
        uint8_t const hw_channel = reinterpret_cast<SpiMasterIrqReq_t *>(cfg)->hw_channel;

        if (p_cfg->txi_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + SPI_INTERRUPT_COUNT > PROG_IRQ_NUM) {
                rv = false;
                goto end_config;
            } 
            /* TX interrupt */
            p_cfg->txi_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->txi_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)spi_txi_isr;
            set_spi_tx_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->txi_irq, p_cfg->txi_ipl, p_ctrl);
            last_interrupt_index++;

            /* RX interrupt */
            p_cfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->rxi_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)spi_rxi_isr;
            set_spi_rx_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->rxi_irq, p_cfg->rxi_ipl, p_ctrl);
            last_interrupt_index++;

            /* Error interrupt */
            p_cfg->eri_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->eri_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)spi_eri_isr;
            set_spi_eri_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->eri_irq, p_cfg->eri_ipl, p_ctrl);
            last_interrupt_index++;

            /* TX register empty interrupt */
            p_cfg->tei_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->tei_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)spi_tei_isr;
            set_spi_tei_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->tei_irq, p_cfg->tei_ipl, p_ctrl);
            last_interrupt_index++;
        }
        R_BSP_IrqEnable (p_cfg->txi_irq);
        R_BSP_IrqEnable (p_cfg->rxi_irq);
        R_BSP_IrqEnable (p_cfg->eri_irq);
        /* Note tei_irq is not enabled until the last data frame is transfered. */
        // R_BSP_IrqEnable (p_cfg->tei_irq);
    }

    /* **********************************************************************
                                    SCI SPI MASTER
       ********************************************************************** */
    else if(p == IRQ_SCI_SPI_MASTER && cfg != NULL) {  
        sci_spi_instance_ctrl_t * p_ctrl = reinterpret_cast<SciSpiMasterIrqReq_t *>(cfg)->ctrl;
        spi_cfg_t  * p_cfg  = reinterpret_cast<SciSpiMasterIrqReq_t *>(cfg)->cfg;
        uint8_t const hw_channel = reinterpret_cast<SciSpiMasterIrqReq_t *>(cfg)->hw_channel;

        if (p_cfg->txi_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + SPI_INTERRUPT_COUNT > PROG_IRQ_NUM) {
                rv = false;
                goto end_config;
            } 
            /* TX interrupt */
            p_cfg->txi_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->txi_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_txi_isr;
            set_sci_tx_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->txi_irq, p_cfg->txi_ipl, p_ctrl);
            last_interrupt_index++;

            /* RX interrupt */
            p_cfg->rxi_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->rxi_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_rxi_isr;
            set_sci_rx_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->rxi_irq, p_cfg->rxi_ipl, p_ctrl);
            last_interrupt_index++;

            /* Error interrupt */
            p_cfg->eri_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->eri_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_eri_isr;
            set_sci_eri_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->eri_irq, p_cfg->eri_ipl, p_ctrl);
            last_interrupt_index++;

            /* TX register empty interrupt */
            p_cfg->tei_irq = (IRQn_Type)last_interrupt_index;
            p_cfg->tei_ipl = SPI_MASTER_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sci_spi_tei_isr;
            set_sci_tei_link_event(last_interrupt_index, hw_channel);
            R_BSP_IrqCfg(p_cfg->tei_irq, p_cfg->tei_ipl, p_ctrl);
            last_interrupt_index++;
        }
        R_BSP_IrqEnable (p_cfg->txi_irq);
        R_BSP_IrqEnable (p_cfg->rxi_irq);
        R_BSP_IrqEnable (p_cfg->eri_irq);
        R_BSP_IrqEnable (p_cfg->tei_irq);
    }
#endif

#if CAN_HOWMANY > 0
    /* **********************************************************************
                                      CAN
       ********************************************************************** */
    else if(p == IRQ_CAN && cfg != NULL) {  
        can_instance_ctrl_t * p_ctrl = reinterpret_cast<CanIrqReq_t *>(cfg)->ctrl;
        can_cfg_t * p_cfg  = reinterpret_cast<CanIrqReq_t *>(cfg)->cfg;
        p_cfg->ipl = CAN_PRIORITY; /* All interrupts share the same priority. */

        if (p_cfg->error_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + CAN_INTERRUPT_COUNT > PROG_IRQ_NUM) {
                rv = false;
                goto end_config;
            } 
            /* Error interrupt */
            p_cfg->error_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)can_error_isr;
            set_can_error_link_event(last_interrupt_index, p_cfg->channel);
            R_BSP_IrqCfg(p_cfg->error_irq, p_cfg->ipl, p_ctrl);
            last_interrupt_index++;

            /* Receive interrupt */
            p_cfg->rx_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)can_rx_isr;
            set_can_rx_link_event(last_interrupt_index, p_cfg->channel);
            R_BSP_IrqCfg(p_cfg->rx_irq, p_cfg->ipl, p_ctrl);
            last_interrupt_index++;

            /* Transmit interrupt */
            p_cfg->tx_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)can_tx_isr;
            set_can_tx_link_event(last_interrupt_index, p_cfg->channel);
            R_BSP_IrqCfg(p_cfg->tx_irq, p_cfg->ipl, p_ctrl);
            last_interrupt_index++;
        }
        R_BSP_IrqEnable (p_cfg->error_irq);
        R_BSP_IrqEnable (p_cfg->rx_irq);
        R_BSP_IrqEnable (p_cfg->tx_irq);
    }
#endif /* CAN_HOWMANY > 0 */


#if ETHERNET_HOWMANY > 0
    /* **********************************************************************
                                    ETHERNET
       ********************************************************************** */
    else if(p == IRQ_ETHERNET && cfg != NULL) {
        ether_cfg_t *eth = (ether_cfg_t *)cfg;
        if (eth->irq == FSP_INVALID_VECTOR) {
            eth->irq = (IRQn_Type)last_interrupt_index;
            eth->interrupt_priority = ETHERNET_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)ether_eint_isr;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_EDMAC0_EINT);
            last_interrupt_index++;
        }
    }
#endif

#if CANFD_HOWMANY > 0
    /* **********************************************************************
                                      CANFD
       ********************************************************************** */
    else if(p == IRQ_CANFD && cfg != NULL) {
        canfd_instance_ctrl_t * p_ctrl = reinterpret_cast<CanFdIrqReq_t *>(cfg)->ctrl;
        can_cfg_t * p_cfg  = reinterpret_cast<CanFdIrqReq_t *>(cfg)->cfg;
        p_cfg->ipl = CAN_PRIORITY; /* All interrupts share the same priority. */

        if (p_cfg->error_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + CANFD_INTERRUPT_COUNT > PROG_IRQ_NUM) {
                rv = false;
                goto end_config;
            }   
            /* Error interrupt */
            p_cfg->error_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)canfd_error_isr;
            set_canfd_error_link_event(last_interrupt_index, p_cfg->channel);
            R_BSP_IrqCfg(p_cfg->error_irq, p_cfg->ipl, p_ctrl);
            last_interrupt_index++;

            /* Receive interrupt */
            p_cfg->rx_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)canfd_rx_fifo_isr;
            set_canfd_rx_link_event(last_interrupt_index, p_cfg->channel);
            R_BSP_IrqCfg(p_cfg->rx_irq, p_cfg->ipl, p_ctrl);
            last_interrupt_index++;

            /* Transmit interrupt */
            p_cfg->tx_irq = (IRQn_Type)last_interrupt_index;
            *(irq_ptr + last_interrupt_index) = (uint32_t)canfd_channel_tx_isr;
            set_canfd_tx_link_event(last_interrupt_index, p_cfg->channel);
            R_BSP_IrqCfg(p_cfg->tx_irq, p_cfg->ipl, p_ctrl);
            last_interrupt_index++;
        }
        R_BSP_IrqEnable (p_cfg->error_irq);
        R_BSP_IrqEnable (p_cfg->rx_irq);
        R_BSP_IrqEnable (p_cfg->tx_irq);
    }
#endif /* CANFD_HOWMANY > 0 */

#if SDCARD_HOWMANY > 0
    /* **********************************************************************
                                    SDCARD
       ********************************************************************** */
    else if(p == IRQ_SDCARD && cfg != NULL) {
        sdmmc_cfg_t *sd_cfg = (sdmmc_cfg_t *)cfg;
        /* SDCARD_ACCESS */
        if(sd_cfg->access_irq == FSP_INVALID_VECTOR) {
            if (last_interrupt_index + SD_INTERRUPT_COUNT > PROG_IRQ_NUM){
                rv = false;
                goto end_config;
            }   
            sd_cfg->access_irq = (IRQn_Type)last_interrupt_index;
            sd_cfg->access_ipl = SDCARD_ACCESS_PRIORITY;
            *(irq_ptr + last_interrupt_index) = (uint32_t)sdhimmc_accs_isr;
            R_ICU->IELSR[last_interrupt_index] = BSP_PRV_IELS_ENUM(EVENT_SDHIMMC0_ACCS);
            last_interrupt_index++;
...

This file has been truncated, please download it to see its full contents.

api\HardwareSerial.h

C/C++
Download and replace the following files in the Arduino15\packages\arduino\hardware\renesas_uno\1.2.0\Cores\Arduino folder.

Windows: C:\Users\{username}\AppData\Local\Arduino15
macOS: /Users/{username}/Library/Arduino15
Linux: /home/{username}/.arduino15
/*
  Copyright (c) 2016 Arduino LLC.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*
  Modifications for v1.2.0 Arduino UNO R4 Board package to fix:
  
  1. Ring Buffer not interrupt safe.
  2. Added Tx buffer.
  3. Removed TEIE.
  4. Both Hardware UARTS can be used at the same time.
  
  Modified 6 July 2024 by Christian Huygen
  www.zevendevelopment.com  
*/

#pragma once

#include <inttypes.h>
#include "Stream.h"

namespace arduino {

// XXX: Those constants should be defined as const int / enums?
// XXX: shall we use namespaces too?
#define SERIAL_PARITY_EVEN   (0x1ul)
#define SERIAL_PARITY_ODD    (0x2ul)
#define SERIAL_PARITY_NONE   (0x3ul)
#define SERIAL_PARITY_MARK   (0x4ul)
#define SERIAL_PARITY_SPACE  (0x5ul)
#define SERIAL_PARITY_MASK   (0xFul)

#define SERIAL_STOP_BIT_1    (0x10ul)
#define SERIAL_STOP_BIT_1_5  (0x20ul)
#define SERIAL_STOP_BIT_2    (0x30ul)
#define SERIAL_STOP_BIT_MASK (0xF0ul)

#define SERIAL_DATA_5        (0x100ul)
#define SERIAL_DATA_6        (0x200ul)
#define SERIAL_DATA_7        (0x300ul)
#define SERIAL_DATA_8        (0x400ul)
#define SERIAL_DATA_9		 (0x500ul)
#define SERIAL_DATA_MASK     (0xF00ul)

#define SERIAL_5N1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE  | SERIAL_DATA_5)
#define SERIAL_6N1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE  | SERIAL_DATA_6)
#define SERIAL_7N1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE  | SERIAL_DATA_7)
#define SERIAL_8N1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE  | SERIAL_DATA_8)
#define SERIAL_5N2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE  | SERIAL_DATA_5)
#define SERIAL_6N2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE  | SERIAL_DATA_6)
#define SERIAL_7N2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE  | SERIAL_DATA_7)
#define SERIAL_8N2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_NONE  | SERIAL_DATA_8)
#define SERIAL_5E1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN  | SERIAL_DATA_5)
#define SERIAL_6E1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN  | SERIAL_DATA_6)
#define SERIAL_7E1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN  | SERIAL_DATA_7)
#define SERIAL_8E1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_EVEN  | SERIAL_DATA_8)
#define SERIAL_5E2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN  | SERIAL_DATA_5)
#define SERIAL_6E2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN  | SERIAL_DATA_6)
#define SERIAL_7E2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN  | SERIAL_DATA_7)
#define SERIAL_8E2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_EVEN  | SERIAL_DATA_8)
#define SERIAL_5O1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD   | SERIAL_DATA_5)
#define SERIAL_6O1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD   | SERIAL_DATA_6)
#define SERIAL_7O1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD   | SERIAL_DATA_7)
#define SERIAL_8O1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_ODD   | SERIAL_DATA_8)
#define SERIAL_5O2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD   | SERIAL_DATA_5)
#define SERIAL_6O2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD   | SERIAL_DATA_6)
#define SERIAL_7O2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD   | SERIAL_DATA_7)
#define SERIAL_8O2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_ODD   | SERIAL_DATA_8)
#define SERIAL_5M1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK  | SERIAL_DATA_5)
#define SERIAL_6M1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK  | SERIAL_DATA_6)
#define SERIAL_7M1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK  | SERIAL_DATA_7)
#define SERIAL_8M1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_MARK  | SERIAL_DATA_8)
#define SERIAL_5M2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK  | SERIAL_DATA_5)
#define SERIAL_6M2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK  | SERIAL_DATA_6)
#define SERIAL_7M2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK  | SERIAL_DATA_7)
#define SERIAL_8M2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_MARK  | SERIAL_DATA_8)
#define SERIAL_5S1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
#define SERIAL_6S1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
#define SERIAL_7S1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
#define SERIAL_8S1           (SERIAL_STOP_BIT_1 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
#define SERIAL_5S2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_5)
#define SERIAL_6S2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_6)
#define SERIAL_7S2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_7)
#define SERIAL_8S2           (SERIAL_STOP_BIT_2 | SERIAL_PARITY_SPACE | SERIAL_DATA_8)
#define SERIAL_9N1			 (SERIAL_STOP_BIT_1 | SERIAL_PARITY_NONE  | SERIAL_DATA_9)

class HardwareSerial : public Stream
{
  public:
    virtual void begin(unsigned long) = 0;
    virtual void begin(unsigned long baudrate, uint16_t config) = 0;
    virtual void end() = 0;
    virtual int available(void) = 0;
    virtual int peek(void) = 0;
    virtual int read(void) = 0;
    virtual void flush(void) = 0;
    virtual size_t write(uint8_t) = 0;
    using Print::write; // pull in write(str) and write(buf, size) from Print
    virtual operator bool() = 0;
};

// XXX: Are we keeping the serialEvent API?
extern void serialEventRun(void) __attribute__((weak));

}

Credits

Christian
24 projects • 135 followers
Senior Embedded Engineer
Contact

Comments

Please log in or sign up to comment.