/*
 * hal_entory.c
 *
 * A simple bootloader with only a few commands.
 * This is basically a rehashed bootloader that has been used extensively elsewhere.
 * There are only three main functions.
 * 1. Receives a binary file via XMODEM protocol through SCI and writes it to flash.
 * 2. Execution of the program written to the flash.
 * 3. Erase the flash.
 *
 * Note that the program that can be executed must have its boot address offset to 0x00010000.
 *
 *  Created on: 2023/09/23
 *      Author: T.Uemitsu

 */

#include "hal_data.h"

#include <stdbool.h>
#include "us.h"

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

#define _BAUDRATE                 (1000000)
#define _ACKDELAYUS               (100)

#define USER_FLASH_END_ADDRESS    (0x0005FFFF)
#define IAP_HEAD_ADDRESS          (0x00010000)
#define IAP_FOOT_ADDRESS          (0x0005FFFF)

#define USER_FLASH_START_BLOCK    (8)
#define FLASH_BLOCK_SIZE_BYTE     (32768)
#define USER_FLASH_START_ADDRESS  ((USER_FLASH_START_BLOCK - 8) * FLASH_BLOCK_SIZE_BYTE + IAP_HEAD_ADDRESS)

#define _LED  BSP_IO_PORT_01_PIN_01

static uint8_t txb[1000], rxb[2000];

#ifdef _LED
int duty = 100;
#endif

static void ackdel (void) {
    R_BSP_SoftwareDelay(_ACKDELAYUS, BSP_DELAY_UNITS_MICROSECONDS);
}

static bool wait (int32_t ms, bool rx) {
    volatile int i;
    for (; ms; --ms) {
        for (i = 0; i < 100; i++) {
            if (rx && us_rx_buff ()) return true;
            R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MICROSECONDS);
        }
    }
    return false;
}

static int64_t H2I (char *s) {
    int64_t i, n = 0;

    if (!*s) return -1;
    for (i = 0; *s; i++, s++) {
        if ('0' <= *s && *s <= '9') {
            n <<= 4;
            n |= *s - '0';
        } else if ('a' <= *s && *s <= 'f') {
            n <<= 4;
            n |= *s - ('a' - 10);
        } else if ('A' <= *s && *s <= 'F') {
            n <<= 4;
            n |= *s - ('A' - 10);
        }
    }
    return n;
}

/*****************************************************************************
 * Flash functions
 ****************************************************************************/
#if 1

#define DBG(...)            us_printf(__VA_ARGS__)
#define WAITFOR_TXCMP()     while (us_tx_buff ()) __WFI();
#else

#define DBG(...)
#define WAITFOR_TXCMP()

#endif

static bool FLASH_Write (uint32_t addr, uint8_t *buf, uint32_t size) {
    bool result = false;
    __disable_irq();
    result = R_FLASH_HP_Write(&g_flash0_ctrl, (uint32_t)buf, addr, size) == FSP_SUCCESS;
    __enable_irq();
    return result;
}

static bool FLASH_EraseAll (void) {
    bool result = false;
    __disable_irq();
    result = R_FLASH_HP_Erase(&g_flash0_ctrl, IAP_HEAD_ADDRESS, 10) == FSP_SUCCESS;
    __enable_irq();
    return result;
}

/*****************************************************************************
 * XMODEM Protocol functions
 ****************************************************************************/
#define _SOH  (0x01)
#define _STX  (0x02)
#define _EOT  (0x04)
#define _ACK  (0x06)
#define _NAK  (0x15)
#define _CAN  (0x18)
#define _XYN  (_NAK)
#define _XYC  ('C')
#define _XYG  ('G')

#if 0
#define _XMODEM_PACKET_SIZE (128)
#else
#define _XMODEM_PACKET_SIZE (1024)
#endif
/*-----XMODEMのパケット処理-------*
  受信側              送信側
         --- NAK -->
         <-- SOH --- (128byte時のブロック開始)
         <--  01 --- (ブロック番号)
         <--  FE --- (ブロック番号を反転させたもの)
         <--  .. --- (実際のデータ 128 bytes)
              ..
         <-- sum --- (checksum)

         --- ACK -->
 *--------------------------------*/
/*-----XMODEM1kのパケット処理-------*
  受信側              送信側
         --- 'C' -->
         <-- STX --- (1024byte時のブロック開始)
         <--  01 --- (ブロック番号)
         <--  FE --- (ブロック番号を反転させたもの)
         <--  .. --- (実際のデータ 1024 bytes)
              ..
         <-- sumH --- (CRC)
         <-- sumL --- (CRC)

         --- ACK -->
 *--------------------------------*/
#define _CNTOVER  (5)

static bool XmodemRX (void) {

    bool my_put_ack (void) {
        int8_t i = 0;
        for (i = 0; i < _CNTOVER; i++) {
            ackdel ();
            us_putc (_ACK);  // OK
            if (wait (100, true)) return true;
        }
        return false;
    }

    bool my_get_char (uint8_t *ch, bool f) {
        int8_t cntover = 0;

        if (wait (50, true)) {
            *ch = (uint8_t)us_getc ();
            return true;
        } else {
            if (f) {
                wait (100, false);
                us_rx_purge ();
                do {
                    ackdel ();
                    us_putc (_NAK);
                    wait (100, true);
                    if (cntover++ > _CNTOVER) break;
                } while (!us_rx_buff ());
            }
            return false;
        }
    }

    static uint8_t xbuff[_XMODEM_PACKET_SIZE];
    uint8_t head, sum0 = 0, sum1, h0 = 1, h1, h2;
    uint16_t sum2;
    int  i = 0;
    uint32_t size = 0, adr = 0, fladdr = USER_FLASH_START_ADDRESS;
    bool f;

    while (!us_rx_buff ()) {
        ackdel ();
#if _XMODEM_PACKET_SIZE == 128
        us_putc (_NAK);
#else
        us_putc (_XYC);
#endif
        if (wait (100, true)) break;
        if (i++ > 240) return false;
    }
    for (;;) {
        if (my_get_char (&head, true)) {
            switch (head) {
#if _XMODEM_PACKET_SIZE == 128
                case _SOH:
#else
                case _STX:
#endif
                    if (my_get_char (&h1, false)) {
                        if (my_get_char (&h2, false)) {
                            if (h1 != ((~h2) & 0xff)) {
                                wait (50, false);
                                us_rx_purge ();
                                ackdel ();
                                us_putc (_NAK);
                            } else {
                                if (h1 == h0) {
                                    sum2 = 0;
                                    f = false;
                                    for (i = 0; i < _XMODEM_PACKET_SIZE; i++) {
                                        if ((f = my_get_char (&xbuff[adr + i], false))) {
#if _XMODEM_PACKET_SIZE == 128
                                            sum2 = (sum2 + xbuff[adr + i]) & 0xff;
#else
                                            sum2 = sum2 ^ xbuff[adr + i] << 8;
                                            int  j;
                                            for (j = 0; j < 8; ++j) {
                                                if (sum2 & 0x8000) sum2 = sum2 << 1 ^ 0x1021;
                                                else               sum2 = sum2 << 1;
                                            }
#endif
                                        } else break;
                                    }
                                    if (f) {
#if _XMODEM_PACKET_SIZE == 128
                                        if (my_get_char (&sum1, false))
#else
                                            if (my_get_char (&sum0, false) && my_get_char (&sum1, false))
#endif
                                            {
                                                if (((sum0 << 8) | sum1) == sum2) {
                                                    adr += _XMODEM_PACKET_SIZE;
                                                    h0++;
                                                    if ((adr % sizeof (xbuff)) == 0) {
                                                        if (FLASH_Write (fladdr, (void *)xbuff, sizeof (xbuff))) {
                                                            fladdr += sizeof (xbuff);
                                                            adr = 0;
                                                        } else {
                                                            ackdel ();
                                                            us_putc (_CAN);
                                                            wait (200, false);
                                                            us_rx_purge ();
                                                            return false;
                                                        }
                                                    }
                                                    size += _XMODEM_PACKET_SIZE;
                                                    if (!my_put_ack ()) { // OK
                                                        ackdel ();
                                                        us_putc (_CAN);
                                                        wait (200, false);
                                                        us_rx_purge ();
                                                        return false;
                                                        break;
                                                    }
                                                } else {
                                                    wait (50, false);
                                                    us_rx_purge ();
                                                    ackdel ();
                                                    us_putc (_NAK);
                                                }
                                            }
                                    } else {
                                        wait (50, false);
                                        us_rx_purge ();
                                        ackdel ();
                                        us_putc (_NAK);
                                    }
                                }
                            }
                        }
                    }
                    break;
                case _EOT:
                    if (adr) {
                        if (!(FLASH_Write (fladdr, (void *)xbuff, adr) == 0)) {
                            ackdel ();
                            us_putc (_CAN);
                            wait (200, false);
                            us_rx_purge ();
                            return false;
                        }
                    }
                    us_rx_purge ();
                    ackdel ();
                    us_putc (_ACK);
                    wait (200, false);
                    return true;
                    break;
                case _CAN:
                    wait (200, false);
                    us_rx_purge ();
                    return false;
                    break;
                default:
                    wait (50, false);
                    us_rx_purge ();
                    ackdel ();
                    us_putc (_NAK);
                    break;
            }
        }
    }
    return false;
}

static int getc2 (int w) {
    wait (w, true);
    if (us_rx_buff ()) return us_getc ();
    return -1;
}

static int XmodemTX (uint8_t *src, int srcsz) {
    uint16_t sum2;
    static uint8_t xbuff[_XMODEM_PACKET_SIZE + 30];
    uint8_t packetno = 1;
    int packetsize = 0, i, j, c, len = 0, retry = 0;
    bool crc = false;

    while (!us_rx_buff ()) {
        if (wait (100, true)) {
            switch (c = us_getc ()) {
                case _XYC:  // 1kbyte
                    crc = true;
                    packetsize = 1024;
                    break;
                case _NAK:  // 128byte
                    crc = false;
                    packetsize = 128;
                    break;
                case _CAN:  // canceled by remote
                    wait (50, false);
                    us_rx_purge ();
                    ackdel ();
                    us_putc (_ACK);
                    return -1;
                    break;
                default:    // cancel
                    wait (50, false);
                    us_rx_purge ();
                    ackdel ();
                    us_putc (_CAN);
                    return -1;
                    break;
            }
            break;
        }
        if (retry++ > _CNTOVER * 10) return -1;
    }

    for (;;) {
        xbuff[0] = crc ? _STX : _SOH;
        xbuff[1] = packetno;
        xbuff[2] = ~packetno;
        if ((c = srcsz - len) > packetsize) c = packetsize;
        if (c > 0) {
            memset (&xbuff[3], 0xff, packetsize);
            sum2 = 0;
            for (i = 0; i < packetsize; i++) {
                xbuff[3 + i] = src[len + i];
                if (crc) {
                    sum2 = sum2 ^ xbuff[3 + i] << 8;
                    for (j = 0; j < 8; ++j) {
                        if (sum2 & 0x8000) sum2 = sum2 << 1 ^ 0x1021;
                        else               sum2 = sum2 << 1;
                    }
                } else sum2 = (sum2 + xbuff[3 + i]) & 0xff;
            }
            if (crc) {
                xbuff[packetsize + 3] = (sum2 >> 8) & 0xFF;
                xbuff[packetsize + 4] = sum2 & 0xFF;
            } else xbuff[packetsize + 3] = sum2;
            for (retry = 0; retry < _CNTOVER; ++retry) {
                us_putsb ((char *)xbuff, packetsize + 4 + (crc ? 1 : 0));
                if ((c = getc2 (200)) >= 0) {
                    switch (c) {
                        case _ACK:  // ok
                            packetno++;
                            len += packetsize;
                            retry = _CNTOVER;
                            break;
                        case _CAN:  // canceled by remote
                            wait (50, false);
                            us_rx_purge ();
                            ackdel ();
                            us_putc (_ACK);
                            return -1;
                            break;
                        case _NAK:  // retry
                        default:
                            wait (50, false);
                            us_rx_purge ();
                            break;
                    }
                }
            }
            if (c != _ACK) {
                wait (50, false);
                us_rx_purge ();
                ackdel ();
                us_putc (_CAN);
                return -1;
            }
        } else {
            for (retry = 0; retry < _CNTOVER; retry++) {
                ackdel ();
                us_putc (_EOT);
                if ((c = getc2 (500)) == _ACK) break;
            }
            us_rx_purge ();
            return (c == _ACK) ? len : -5;
        }
    }
    return -1;
}

/*****************************************************************************
 * Init/Deinit
 ****************************************************************************/
static void Init (void) {
    SysTick->CTRL = 0;
    SysTick_Config (100000000 / 10000);

    us_init (_BAUDRATE, USIP_8N1, txb, sizeof (txb), rxb, sizeof (rxb));

    // Init GPIO
    R_IOPORT_Open(&g_ioport_ctrl, &g_bsp_pin_cfg);
    R_IOPORT_PinWrite(&g_ioport_ctrl, _LED, BSP_IO_LEVEL_HIGH);

    // Init UART
    R_SCI_UART_Open (&g_uart4_ctrl, &g_uart4_cfg);

    R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);
}

static void DeInit (void) {
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    R_IOPORT_Close(&g_ioport_ctrl);

    R_SCI_UART_Close (&g_uart4_ctrl);
    R_FLASH_HP_Close (&g_flash0_ctrl);
}

/*****************************************************************************
 * Dump
 ****************************************************************************/
typedef enum {
    mode_str,
    mode_hex,
    mode_dec,
} TCharMode;

static char *getstr (char *s, int len, TCharMode m) {
    int i = 0;
    char c;

    while (1) {
        c = us_getc ();
        if (c == '\n' || c == '\r') {
            s[i++] = '\0';
            break;
        } else if ((i > 0) && (c == '\b')) {
            ackdel ();
            us_puts ("\b \b");
            i--;
        } else if ((i < len) && (i >= 0) && (c >= ' ') && (c <= '~')) {
            ackdel ();
            switch (m) {
                case mode_dec:
                    if ((c >= '0') && (c <= '9')) {
                        s[i++] = (char)c;
                        us_putc (c);
                    }
                    break;
                case mode_hex:
                    if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'))) {
                        s[i++] = c;
                        us_putc (c);
                    }
                    break;
                default:
                    s[i++] = (char)c;
                    us_putc (c);
                    break;
            }
        } else {
            ackdel ();
            us_putc ('\a');
        }
    }
    return s;
}

/*****************************************************************************
 * mem dump
 ****************************************************************************/
static void dump (uint32_t addr) {
    uint32_t i, j;
    uint8_t *dat = (uint8_t *)addr;
    char c;
    while (1) {
        for (i = 0; i < 16; i++) {
            us_printf("%08X:", dat + (i << 4));
            for (j = 0; j < 16; j++) {
                us_printf("%02X ", dat[(i << 4) + j]);
            }
            us_putc (' ');
            for (j = 0; j < 16; j++) {
                c = (char)dat[(i << 4) + j];
                us_putc (((0x20 <= c) && (c < 0x7f)) ? c : '.');
            }
            us_puts("\r\n");
        }
        us_puts ("---([u]up [d]down [ESC]exit)---\r\n");
        switch (us_getc ()) {
            case 0x1b:
            case 'q':
            case 'Q':
                return;
                break;
            case ' ':
            case 'u':
            case 'U':
            case '\r':
                dat += 256;
                break;
            case 'd':
            case 'D':
                dat -= 256;
                break;
        }
#ifdef _LED
        duty = 100;
#endif
    }
}

typedef void (*fp)(void);

/*****************************************************************************
 * for user programs
 ****************************************************************************/
static uint32_t FlashIsNotEmpty (void) {
    uint32_t *FWBOOT = (uint32_t *)(USER_FLASH_START_ADDRESS + 4);
    if ((USER_FLASH_START_ADDRESS <= *FWBOOT) && (*FWBOOT <= USER_FLASH_END_ADDRESS)) return *FWBOOT;
    else return 0;
}


__attribute__((always_inline)) __STATIC_INLINE void __set_PC(uint32_t ProgramCounter) {
    __ASM volatile ("MOV pc, %0" : : "r" (ProgramCounter) : );
}

#define EnablePrivilegedMode() __asm("SVC #0")

static bool JumpToUserProgram (void) {
    uint32_t jump_address = FlashIsNotEmpty ();
    if (jump_address != 0) {
        DeInit ();

#if 0
        __disable_irq();

        if (CONTROL_nPRIV_Msk & __get_CONTROL()) EnablePrivilegedMode( ) ;

        NVIC->ICER[ 0 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 1 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 2 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 3 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 4 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 5 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 6 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 7 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 8 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 9 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 10 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 11 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 12 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 13 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 14 ] = 0xFFFFFFFF ;
        NVIC->ICER[ 15 ] = 0xFFFFFFFF ;


        NVIC->ICPR[ 0 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 1 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 2 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 3 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 4 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 5 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 6 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 7 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 8 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 9 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 10 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 11 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 12 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 13 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 14 ] = 0xFFFFFFFF ;
        NVIC->ICPR[ 15 ] = 0xFFFFFFFF ;


        SysTick->CTRL = 0 ;
        SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;

        SCB->SHCSR &= ~(SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk | SCB_SHCSR_MEMFAULTENA_Msk);

        __set_PSPLIM(0);
        __set_MSPLIM(0);
        R_MPU_SPMON->SP[0].CTL = 0;

        if (CONTROL_SPSEL_Msk & __get_CONTROL( )) {
          __set_MSP (__get_PSP( )) ;
          __set_CONTROL (__get_CONTROL( ) & ~CONTROL_SPSEL_Msk) ;
        }
        SCB->VTOR = ( uint32_t )jump_address & 0x1FFFFF80;

        void (*UserProgram)(void) = (fp)*(uint32_t*)(jump_address + 4);
        __set_MSP (*(uint32_t*)jump_address);
        UserProgram ();

        __NOP ();
        __NOP ();
        __NOP ();
#else
        __disable_irq();

        //disable Main Stack Pointer monitoring
        R_MPU_SPMON->SP[0].CTL = 0;

        // Set the Vector Table Offset Register
        SCB->VTOR = USER_FLASH_START_ADDRESS & 0xffffff80;//jump_address & 0xffffff80;

        __DSB();

        // Ensure that when we jump we're using the Main Stack Pointer
        __set_CONTROL(0);

        __ISB();

        __set_PSPLIM(0);
        __set_MSPLIM(0);

//        __set_MSP(*(uint32_t *)jump_address);
        __set_MSP(*(uint32_t *)USER_FLASH_START_ADDRESS);

        __enable_irq();
        __ASM volatile ("bx %0"::"r"(jump_address));
//        __set_PC(*(uint32_t *)(jump_address + 4));

        __NOP();
        __NOP();
        __NOP();

        // Shouldn't get here
        while(1);
#endif
    }
    return false;
}

/*****************************************************************************
 * etc
 ****************************************************************************/
static bool AreYouSure (void) {
    char c;
    us_puts ("(y/n)");
    c = us_getc ();
    ackdel ();
    us_putc (c);
    return (c == 'y');
}

#if 0
void HardFault_Handler(void) {
    BSP_CFG_HANDLE_UNRECOVERABLE_ERROR(0);
}
#endif

void SysTick_Handler(void);

void SysTick_Handler (void) {
#ifdef _LED
    static int freq = 0;

    if (duty > 0) {
        if (++freq > 100) {
            freq = 0;
            duty -= 3;
        }
        if (duty > 0) {
            R_IOPORT_PinWrite(&g_ioport_ctrl, _LED, (duty <= freq) ? BSP_IO_LEVEL_LOW: BSP_IO_LEVEL_HIGH);
        } else {
            R_IOPORT_PinWrite(&g_ioport_ctrl, _LED, BSP_IO_LEVEL_LOW);
            freq = 0;
        }
    }
#endif
}

/*****************************************************************************
 * Main
 ****************************************************************************/
void hal_entry (void) {
    const char *mess[] = {
        "\nRA4M2 BL1.2",
        "\n>","\nOK","\nNG",
        "\nw:write r:read e:erase d:dump g:go",
    };

    int64_t i, j;
    char c = 3, s[20];

    Init ();
#if 1
    if (1 != R_SYSTEM->RSTSR1_b.SWRF) {
        while (1) {
            if (getc2 (50) == '!')
                if (getc2 (50) == '!')
                    if (getc2 (50) == '!') break;
            if (--c <= 0) if (!JumpToUserProgram ()) break;
        }
    }
#endif
    us_puts (mess[0]);
    us_puts (mess[1]);

    for (;;) {
        if (us_rx_buff ()) {
            duty = 100;
            c = us_getc ();
            ackdel ();
            us_putc (c);
            switch (c) {
                case 'w':
                    if (AreYouSure ()) us_puts (XmodemRX () ? mess[2] : mess[3]);
                    break;
                case 'g':
                    if (!JumpToUserProgram ()) us_puts (mess[3]);
                    break;
                case 'r':
                    us_puts ("\n START ADDRESS:$");
                    if ((i = H2I (getstr (s, 8, mode_hex))) < 0) i = USER_FLASH_START_ADDRESS;
                    ackdel ();
                    us_printf ("\33[%cD%08X",strlen(s)+'0',i);
                    us_puts ("\n SiZE:$");
                    if ((j = H2I (getstr (s, 8, mode_hex))) < 0) j = USER_FLASH_END_ADDRESS - IAP_HEAD_ADDRESS + 1;
                    ackdel ();
                    us_printf ("\33[%cD%08X\n START DOWNLOAD...",strlen(s)+'0',j);
                    if (AreYouSure ()) {
                        ackdel ();
                        us_puts (XmodemTX ((uint8_t *)(uint32_t)i, j) > 0 ? "\n <SUCCESS>" : "\n <ERROR>");
                    }
                    break;
                case 'e':
                    if (AreYouSure ()) {
                        ackdel ();
                        us_puts (FLASH_EraseAll () ? mess[2] : mess[3]);
                    }
                    break;
                case 'd':
                    us_puts ("\n START ADDRESS:$");
                    if ((i = H2I (getstr (s, 8, mode_hex))) < 0) i = USER_FLASH_START_ADDRESS;
                    ackdel ();
                    us_printf ("\33[%cD%08X\r\n",strlen(s)+'0',i);
                    dump (i);
                    break;
                default:
                    us_puts ((char *)mess[0]);
                    us_puts ((char *)mess[4]);
                    break;
            }
            us_puts ((char *)mess[1]);
            __WFI ();
        }
    }
}

/*******************************************************************************************************************//**
 * This function is called at various points during the startup process.  This implementation uses the event that is
 * called right before main() to set up the pins.
 *
 * @param[in]  event    Where at in the start up process the code is currently at
 **********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_RESET == event)
    {
#if BSP_FEATURE_FLASH_LP_VERSION != 0

        /* Enable reading from data flash. */
        R_FACI_LP->DFLCTL = 1U;

        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
    }

    if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment and system clocks are setup. */

        /* Configure pins. */
        R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
    }
}

#if BSP_TZ_SECURE_BUILD

BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();

/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{

}
#endif
